2019-10-22 16:23:23 +02:00
|
|
|
"""
|
|
|
|
Module for Proof of Work using OpenCL
|
|
|
|
"""
|
2021-02-06 20:51:47 +01:00
|
|
|
import logging
|
2017-08-15 12:24:43 +02:00
|
|
|
import os
|
2021-01-16 19:58:40 +01:00
|
|
|
from struct import pack
|
2017-08-15 12:24:43 +02:00
|
|
|
|
2021-07-30 15:14:36 +02:00
|
|
|
import paths
|
|
|
|
from bmconfigparser import BMConfigParser
|
|
|
|
from state import shutdown
|
2017-08-15 12:24:43 +02:00
|
|
|
|
2021-02-06 20:51:47 +01:00
|
|
|
try:
|
|
|
|
import numpy
|
|
|
|
import pyopencl as cl
|
|
|
|
libAvailable = True
|
|
|
|
except ImportError:
|
|
|
|
libAvailable = False
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger('default')
|
|
|
|
|
2017-08-15 12:24:43 +02:00
|
|
|
ctx = False
|
|
|
|
queue = False
|
|
|
|
program = False
|
|
|
|
gpus = []
|
|
|
|
enabledGpus = []
|
|
|
|
vendors = []
|
|
|
|
hash_dt = None
|
|
|
|
|
2018-06-21 12:03:17 +02:00
|
|
|
|
2017-08-15 12:24:43 +02:00
|
|
|
def initCL():
|
2019-10-22 16:23:23 +02:00
|
|
|
"""Initlialise OpenCL engine"""
|
2021-02-06 20:51:47 +01:00
|
|
|
global ctx, queue, program, hash_dt # pylint: disable=global-statement
|
2017-03-28 16:38:05 +02:00
|
|
|
if libAvailable is False:
|
|
|
|
return
|
2017-08-15 12:24:43 +02:00
|
|
|
del enabledGpus[:]
|
|
|
|
del vendors[:]
|
|
|
|
del gpus[:]
|
|
|
|
ctx = False
|
|
|
|
try:
|
|
|
|
hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)])
|
|
|
|
try:
|
|
|
|
for platform in cl.get_platforms():
|
|
|
|
gpus.extend(platform.get_devices(device_type=cl.device_type.GPU))
|
|
|
|
if BMConfigParser().safeGet("bitmessagesettings", "opencl") == platform.vendor:
|
2019-10-22 16:23:23 +02:00
|
|
|
enabledGpus.extend(platform.get_devices(
|
|
|
|
device_type=cl.device_type.GPU))
|
2017-08-15 12:24:43 +02:00
|
|
|
if platform.vendor not in vendors:
|
|
|
|
vendors.append(platform.vendor)
|
|
|
|
except:
|
|
|
|
pass
|
2019-10-22 16:23:23 +02:00
|
|
|
if enabledGpus:
|
2017-08-15 12:24:43 +02:00
|
|
|
ctx = cl.Context(devices=enabledGpus)
|
|
|
|
queue = cl.CommandQueue(ctx)
|
|
|
|
f = open(os.path.join(paths.codePath(), "bitmsghash", 'bitmsghash.cl'), 'r')
|
|
|
|
fstr = ''.join(f.readlines())
|
|
|
|
program = cl.Program(ctx, fstr).build(options="")
|
|
|
|
logger.info("Loaded OpenCL kernel")
|
|
|
|
else:
|
|
|
|
logger.info("No OpenCL GPUs found")
|
|
|
|
del enabledGpus[:]
|
2019-10-22 16:23:23 +02:00
|
|
|
except Exception:
|
2017-08-15 12:24:43 +02:00
|
|
|
logger.error("OpenCL fail: ", exc_info=True)
|
|
|
|
del enabledGpus[:]
|
|
|
|
|
2019-10-22 16:23:23 +02:00
|
|
|
|
2017-08-15 12:24:43 +02:00
|
|
|
def openclAvailable():
|
2019-10-22 16:23:23 +02:00
|
|
|
"""Are there any OpenCL GPUs available?"""
|
|
|
|
return bool(gpus)
|
|
|
|
|
2017-08-15 12:24:43 +02:00
|
|
|
|
|
|
|
def openclEnabled():
|
2019-10-22 16:23:23 +02:00
|
|
|
"""Is OpenCL enabled (and available)?"""
|
|
|
|
return bool(enabledGpus)
|
2017-08-15 12:24:43 +02:00
|
|
|
|
2019-10-22 16:23:23 +02:00
|
|
|
|
|
|
|
def do_opencl_pow(hash_, target):
|
|
|
|
"""Perform PoW using OpenCL"""
|
2017-08-15 12:24:43 +02:00
|
|
|
output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)])
|
2019-10-22 16:23:23 +02:00
|
|
|
if not enabledGpus:
|
2017-08-15 12:24:43 +02:00
|
|
|
return output[0][0]
|
|
|
|
|
|
|
|
data = numpy.zeros(1, dtype=hash_dt, order='C')
|
2019-10-22 16:23:23 +02:00
|
|
|
data[0]['v'] = ("0000000000000000" + hash_).decode("hex")
|
2017-08-15 12:24:43 +02:00
|
|
|
data[0]['target'] = target
|
|
|
|
|
|
|
|
hash_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=data)
|
|
|
|
dest_buf = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, output.nbytes)
|
|
|
|
|
|
|
|
kernel = program.kernel_sha512
|
|
|
|
worksize = kernel.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, enabledGpus[0])
|
|
|
|
|
|
|
|
kernel.set_arg(0, hash_buf)
|
|
|
|
kernel.set_arg(1, dest_buf)
|
|
|
|
|
|
|
|
progress = 0
|
2019-10-22 16:23:23 +02:00
|
|
|
globamt = worksize * 2000
|
2017-08-15 12:24:43 +02:00
|
|
|
|
|
|
|
while output[0][0] == 0 and shutdown == 0:
|
|
|
|
kernel.set_arg(2, pack("<Q", progress))
|
|
|
|
cl.enqueue_nd_range_kernel(queue, kernel, (globamt,), (worksize,))
|
2019-03-22 10:06:02 +01:00
|
|
|
try:
|
|
|
|
cl.enqueue_read_buffer(queue, dest_buf, output)
|
|
|
|
except AttributeError:
|
|
|
|
cl.enqueue_copy(queue, output, dest_buf)
|
2017-08-15 12:24:43 +02:00
|
|
|
queue.finish()
|
|
|
|
progress += globamt
|
|
|
|
if shutdown != 0:
|
2019-10-22 16:23:23 +02:00
|
|
|
raise Exception("Interrupted")
|
2017-08-15 12:24:43 +02:00
|
|
|
# logger.debug("Took %d tries.", progress)
|
|
|
|
return output[0][0]
|