burstcoin.jminer.core.checker.util.OCLChecker.java Source code

Java tutorial

Introduction

Here is the source code for burstcoin.jminer.core.checker.util.OCLChecker.java

Source

/*
 * 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();
    }
}