Permalink
Fetching contributors…
Cannot retrieve contributors at this time
291 lines (253 sloc) 11.9 KB
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 by luxe - https://github.com/de-luxe - BURST-LUXE-RED2-G6JW-H4HG5
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package burstcoin.jminer.core.checker.util;
import burstcoin.jminer.core.CoreProperties;
import org.jocl.Pointer;
import org.jocl.Sizeof;
import org.jocl.cl_command_queue;
import org.jocl.cl_context;
import org.jocl.cl_context_properties;
import org.jocl.cl_device_id;
import org.jocl.cl_kernel;
import org.jocl.cl_mem;
import org.jocl.cl_platform_id;
import org.jocl.cl_program;
import org.jocl.utils.DeviceInfos;
import org.jocl.utils.Devices;
import org.jocl.utils.PlatformInfos;
import org.jocl.utils.Platforms;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.jocl.CL.*;
/**
* Org. OCLChecker code and the used openCL kernels are provided by 'burst dev'. Please donate: BURST-QHCJ-9HB5-PTGC-5Q8J9
*/
@Component
@Scope("singleton")
public class OCLChecker
{
private static final Logger LOG = LoggerFactory.getLogger(OCLChecker.class);
private static final int SIZE_DIVISOR = CoreProperties.isByteUnitDecimal() ? 1000 : 1024;
private static final String T_UNIT = CoreProperties.isByteUnitDecimal() ? "TB" : "TiB";
private static final String G_UNIT = CoreProperties.isByteUnitDecimal() ? "GB" : "GiB";
private static final String M_UNIT = CoreProperties.isByteUnitDecimal() ? "MB" : "MiB";
cl_context context;
cl_command_queue queue;
cl_program program;
cl_kernel kernel[] = new cl_kernel[3];
long workgroupSize[] = new long[3];
long computeUnits;
cl_mem gensigMem;
cl_mem bestMem;
@PostConstruct
protected void postConstruct()
{
initChecker(CoreProperties.getPlatformId(), CoreProperties.getDeviceId());
}
public void initChecker(int platformId, int deviceId)
{
check();
setExceptionsEnabled(true);
int numPlatforms[] = new int[1];
clGetPlatformIDs(0, null, numPlatforms);
if(platformId >= numPlatforms[0])
{
throw new ArrayIndexOutOfBoundsException("Invalid platform id");
}
cl_platform_id platforms[] = new cl_platform_id[numPlatforms[0]];
clGetPlatformIDs(platforms.length, platforms, null);
int[] numDevices = new int[1];
clGetDeviceIDs(platforms[platformId], CL_DEVICE_TYPE_ALL, 0, null, numDevices);
if(deviceId >= numDevices[0])
{
throw new ArrayIndexOutOfBoundsException("Invalid device id");
}
cl_device_id devices[] = new cl_device_id[numDevices[0]];
clGetDeviceIDs(platforms[platformId], CL_DEVICE_TYPE_ALL, devices.length, devices, null);
cl_context_properties contextProperties = new cl_context_properties();
contextProperties.addProperty(CL_CONTEXT_PLATFORM, platforms[platformId]);
context = clCreateContext(contextProperties, 1, new cl_device_id[]{devices[deviceId]}, null, null, null);
queue = clCreateCommandQueue(context, devices[deviceId], 0, null);
String kernelSource;
try
{
InputStream inputStream = OCLChecker.class.getResourceAsStream("calcdeadlines.cl");
kernelSource = readInputStreamAsString(inputStream);
inputStream.close();
}
catch(IOException e)
{
throw new RuntimeException("Failed to read calcdeadlines.cl file", e);
}
program = clCreateProgramWithSource(context, 1, new String[]{kernelSource}, null, null);
clBuildProgram(program, 0, null, "-I kernel", null, null);
kernel[0] = clCreateKernel(program, "calculate_deadlines", null);
kernel[1] = clCreateKernel(program, "reduce_best", null);
kernel[2] = clCreateKernel(program, "reduce_target", null);
long[] maxWorkGroupSize = new long[1];
for(int i = 0; i < 3; i++)
{
clGetKernelWorkGroupInfo(kernel[i], devices[deviceId], CL_KERNEL_WORK_GROUP_SIZE, 8, Pointer.to(maxWorkGroupSize), null);
workgroupSize[i] = maxWorkGroupSize[0];
}
long[] maxComputeUnits = new long[1];
clGetDeviceInfo(devices[deviceId], CL_DEVICE_MAX_COMPUTE_UNITS, 8, Pointer.to(maxComputeUnits), null);
computeUnits = maxComputeUnits[0];
gensigMem = clCreateBuffer(context, CL_MEM_READ_ONLY, 32, null, null);
bestMem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, 400, null, null); // org 400 // tested 5000
LOG.info("");
LOG.info("(*) openCL context successfully started! (platformId: "+platformId+", deviceId: "+deviceId+")");
LOG.info("-------------------------------------------------------");
}
private void check()
{
List<cl_platform_id> platforms = Platforms.getPlatforms();
LOG.info("-------------------------------------------------------");
LOG.info("List of system openCL platforms and devices (* = used for mining)");
LOG.info("");
for(cl_platform_id cl_platform_id : platforms)
{
int currentPlatformId = platforms.indexOf(cl_platform_id);
if(currentPlatformId == CoreProperties.getPlatformId())
{
String selector = " * ";
String selectionPrefix = currentPlatformId == CoreProperties.getPlatformId() ? selector : " ";
LOG.info(selectionPrefix + "PLATFORM-[" + currentPlatformId + "] " + PlatformInfos.getName(cl_platform_id) + " - "
+ "(" + PlatformInfos.getVersion(cl_platform_id) + ")");
List<cl_device_id> devices = Devices.getDevices(cl_platform_id);
for(cl_device_id cl_device_id : devices)
{
int currentDeviceId = devices.indexOf(cl_device_id);
selectionPrefix = currentDeviceId == CoreProperties.getDeviceId() ? selector : " ";
LOG.info(selectionPrefix + " DEVICE-[" + currentDeviceId + "] " + DeviceInfos.getName(cl_device_id) + " "
+ "(" + bytesAsGigabyte(DeviceInfos.getMaxMemAllocSize(cl_device_id)) + ")"
+ " - " + DeviceInfos.getVendor(cl_device_id) + " (" + DeviceInfos.getDeviceVersion(cl_device_id)
+ " | '" + DeviceInfos.getDriverVersion(cl_device_id) + "')");
LOG.info(selectionPrefix + " [" + currentDeviceId + "] "
+ "work group size: '" + DeviceInfos.getMaxWorkGroupSize(cl_device_id) + "', "
+ "computing units: '" + DeviceInfos.getMaxComputeUnits(cl_device_id) + "', "
+ "available '" + DeviceInfos.getAvailable(cl_device_id) + "'");
}
}
}
}
public void reset(int platformId, int deviceId)
{
clReleaseContext(context);
initChecker(platformId, deviceId);
}
private String bytesAsGigabyte(long bytes)
{
return bytes / SIZE_DIVISOR / SIZE_DIVISOR / SIZE_DIVISOR % SIZE_DIVISOR + "" + G_UNIT;
}
public int findLowest(byte[] gensig, byte[] data)
{
cl_mem dataMem;
cl_mem deadlineMem;
long numNonces = data.length / 64;
long calcWorkgroups = numNonces / workgroupSize[0];
// thx blago
if(numNonces % workgroupSize[0] != 0) // if(numNonces % 64 != 0) // org.
{
calcWorkgroups++;
}
clEnqueueWriteBuffer(queue, gensigMem, false, 0, 32, Pointer.to(gensig), 0, null, null);
dataMem = clCreateBuffer(context, CL_MEM_READ_ONLY, calcWorkgroups * workgroupSize[0] * 64, null, null);
clEnqueueWriteBuffer(queue, dataMem, false, 0, data.length, Pointer.to(data), 0, null, null);
deadlineMem = clCreateBuffer(context, CL_MEM_READ_WRITE, calcWorkgroups * workgroupSize[0] * 8, null, null);
clSetKernelArg(kernel[0], 0, Sizeof.cl_mem, Pointer.to(gensigMem));
clSetKernelArg(kernel[0], 1, Sizeof.cl_mem, Pointer.to(dataMem));
clSetKernelArg(kernel[0], 2, Sizeof.cl_mem, Pointer.to(deadlineMem));
clEnqueueNDRangeKernel(queue, kernel[0], 1, null, new long[]{calcWorkgroups * workgroupSize[0]}, new long[]{workgroupSize[0]}, 0, null, null);
clSetKernelArg(kernel[1], 0, Sizeof.cl_mem, Pointer.to(deadlineMem));
long len[] = {data.length / 64};
clSetKernelArg(kernel[1], 1, Sizeof.cl_uint, Pointer.to(len));
clSetKernelArg(kernel[1], 2, Sizeof.cl_uint * workgroupSize[1], null);
clSetKernelArg(kernel[1], 3, Sizeof.cl_ulong * workgroupSize[1], null);
clSetKernelArg(kernel[1], 4, Sizeof.cl_mem, Pointer.to(bestMem));
clEnqueueNDRangeKernel(queue, kernel[1], 1, null, new long[]{workgroupSize[1]}, new long[]{workgroupSize[1]}, 0, null, null);
int best[] = new int[1];
clEnqueueReadBuffer(queue, bestMem, true, 0, 4, Pointer.to(best), 0, null, null);
clReleaseMemObject(dataMem);
clReleaseMemObject(deadlineMem);
return best[0];
}
public int[] findTarget(byte[] gensig, byte[] data, long target)
{
long numNonces = data.length / 64;
long calcWorkgroups = numNonces / workgroupSize[0];
// thx blago
if(numNonces % workgroupSize[0] != 0) // org. if(numNonces % 64 != 0)
{
calcWorkgroups++;
}
clEnqueueWriteBuffer(queue, gensigMem, false, 0, 32, Pointer.to(gensig), 0, null, null);
cl_mem dataMem = clCreateBuffer(context, CL_MEM_READ_ONLY, calcWorkgroups * workgroupSize[0] * 64, null, null);
clEnqueueWriteBuffer(queue, dataMem, false, 0, data.length, Pointer.to(data), 0, null, null);
cl_mem deadlineMem = clCreateBuffer(context, CL_MEM_READ_WRITE, calcWorkgroups * workgroupSize[0] * 8, null, null);
clSetKernelArg(kernel[0], 0, Sizeof.cl_mem, Pointer.to(gensigMem));
clSetKernelArg(kernel[0], 1, Sizeof.cl_mem, Pointer.to(dataMem));
clSetKernelArg(kernel[0], 2, Sizeof.cl_mem, Pointer.to(deadlineMem));
clEnqueueNDRangeKernel(queue, kernel[0], 1, null, new long[]{calcWorkgroups * workgroupSize[0]}, new long[]{workgroupSize[0]}, 0, null, null);
int best[] = new int[]{0};
clEnqueueWriteBuffer(queue, bestMem, false, 0, 4, Pointer.to(best), 0, null, null);
clSetKernelArg(kernel[2], 0, Sizeof.cl_mem, Pointer.to(deadlineMem));
long len[] = {data.length / 64};
clSetKernelArg(kernel[2], 1, Sizeof.cl_uint, Pointer.to(len));
long targetPtr[] = new long[]{target};
clSetKernelArg(kernel[2], 2, Sizeof.cl_ulong, Pointer.to(targetPtr));
clSetKernelArg(kernel[2], 3, Sizeof.cl_mem, Pointer.to(bestMem));
clEnqueueNDRangeKernel(queue, kernel[2], 1, null, new long[]{workgroupSize[2]}, new long[]{workgroupSize[2]}, 0, null, null);
clEnqueueReadBuffer(queue, bestMem, true, 0, 4, Pointer.to(best), 0, null, null);
if(best[0] == 0)
{
return null;
}
int bestVals[] = new int[best[0]];
clEnqueueReadBuffer(queue, bestMem, true, 4, 4 * best[0], Pointer.to(bestVals), 0, null, null);
clReleaseMemObject(dataMem);
clReleaseMemObject(deadlineMem);
return bestVals;
}
public static String readInputStreamAsString(InputStream in)
throws IOException
{
BufferedInputStream bis = new BufferedInputStream(in);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while(result != -1)
{
byte b = (byte) result;
buf.write(b);
result = bis.read();
}
return buf.toString();
}
}