From e69e38a764126af467e8bf1f82000e8d907caa86 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:38:55 +0100 Subject: [PATCH] PoW support code cleanup Is now nicer and reports if OpenCL fails --- src/class_singleWorker.py | 10 ++++++-- src/openclpow.py | 53 ++++++++++++++++++++++++++------------- src/proofofwork.py | 52 ++++++++++++++++++++++++-------------- 3 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 6a827ce2..6de8703c 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -21,6 +21,12 @@ import l10n # This thread, of which there is only one, does the heavy lifting: # calculating POWs. +def sizeof_fmt(num, suffix='h/s'): + for unit in ['','k','M','G','T','P','E','Z']: + if abs(num) < 1000.0: + return "%3.1f%s%s" % (num, unit, suffix) + num /= 1024.0 + return "%.1f%s%s" % (num, 'Yi', suffix) class singleWorker(threading.Thread, StoppableThread): @@ -787,7 +793,7 @@ class singleWorker(threading.Thread, StoppableThread): trialValue, nonce = proofofwork.run(target, initialHash) logger.info('(For msg message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) try: - logger.info('POW took ' + str(int(time.time() - powStartTime)) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) except: pass @@ -966,7 +972,7 @@ class singleWorker(threading.Thread, StoppableThread): trialValue, nonce = proofofwork.run(target, initialHash) logger.info('(For ack message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) try: - logger.info('POW took ' + str(time.time() - powStartTime) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) except: pass diff --git a/src/openclpow.py b/src/openclpow.py index a2cfb068..426913a4 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,35 +5,49 @@ import hashlib import random import os +from shared import codePath, safeConfigGetBoolean +from debug import logger + +libAvailable = True ctx = False queue = False program = False +gpus = [] +hash_dt = None try: import numpy import pyopencl as cl - hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) - gpus = [] - for platform in cl.get_platforms(): - gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if (len(gpus) > 0): - ctx = cl.Context(devices=gpus) - queue = cl.CommandQueue(ctx) - full_path = os.path.dirname(os.path.realpath(__file__)) - f = open(os.path.join(full_path, "bitmsghash", 'bitmsghash.cl'), 'r') - fstr = ''.join(f.readlines()) - program = cl.Program(ctx, fstr).build(options="") - else: - print "No OpenCL GPUs found" +except: + libAvailable = False + +def initCL(): + global ctx, queue, program, gpus, hash_dt + try: + hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) + for platform in cl.get_platforms(): + gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) + if (len(gpus) > 0): + ctx = cl.Context(devices=gpus) + queue = cl.CommandQueue(ctx) + f = open(os.path.join(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") + ctx = False + except Exception as e: + logger.error("OpenCL fail: ", exc_info=True) ctx = False -except Exception as e: - print "opencl fail: " + str(e) - ctx = False def has_opencl(): + global ctx return (ctx != False) def do_opencl_pow(hash, target): + global ctx, queue, program, gpus, hash_dt + output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) if (ctx == False): return output[0][0] @@ -62,11 +76,14 @@ def do_opencl_pow(hash, target): queue.finish() progress += globamt sofar = time.time() - start - print sofar, progress / sofar, "hashes/sec" +# logger.debug("Working for %.3fs, %.2f Mh/s", sofar, (progress / sofar) / 1000000) taken = time.time() - start - print progress, taken +# logger.debug("Took %d tries.", progress) return output[0][0] +if libAvailable: + initCL() + if __name__ == "__main__": target = 54227212183L initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex") diff --git a/src/proofofwork.py b/src/proofofwork.py index fc779467..8ab04820 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -4,9 +4,10 @@ import hashlib from struct import unpack, pack import sys -from shared import config, frozen, codePath -import shared +from debug import logger +from shared import config, frozen, codePath, shutdown, safeConfigGetBoolean, UISignalQueue import openclpow +import tr import os import ctypes @@ -17,12 +18,20 @@ if "win32" == sys.platform: else: bitmsglib = 'bitmsghash64.dll' try: + # MSVS bso = ctypes.WinDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) except: - bso = None + try: + # MinGW + bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) + except: + bso = None else: try: bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL %s", bitmsglib) except: bso = None if bso: @@ -58,16 +67,17 @@ def _pool_worker(nonce, initialHash, target, pool_size): return [trialValue, nonce] def _doSafePoW(target, initialHash): - print "Safe POW\n" + logger.debug("Safe PoW start") nonce = 0 trialValue = float('inf') while trialValue > target: nonce += 1 trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) + logger.debug("Safe PoW done") return [trialValue, nonce] def _doFastPoW(target, initialHash): - print "Fast POW\n" + logger.debug("Fast PoW start") import time from multiprocessing import Pool, cpu_count try: @@ -85,7 +95,7 @@ def _doFastPoW(target, initialHash): for i in range(pool_size): result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) while True: - if shared.shutdown >= 1: + if shutdown >= 1: pool.terminate() while True: time.sleep(10) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py @@ -95,30 +105,38 @@ def _doFastPoW(target, initialHash): result = result[i].get() pool.terminate() pool.join() #Wait for the workers to exit... + logger.debug("Fast PoW done") return result[0], result[1] time.sleep(0.2) + def _doCPoW(target, initialHash): h = initialHash m = target out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64)) out_m = ctypes.c_ulonglong(m) - print "C PoW start" + logger.debug("C PoW start") nonce = bmpow(out_h, out_m) trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - print "C PoW done" + logger.debug("C PoW done") return [trialValue, nonce] def _doGPUPoW(target, initialHash): - print "GPU PoW start" + logger.debug("GPU PoW start") nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target) trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) #print "{} - value {} < {}".format(nonce, trialValue, target) - print "GPU PoW done" + if trialValue > target: + deviceNames = ", ".join(gpu.name for gpu in openclpow.gpus) + UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'))) + logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames) + openclpow.ctx = False + raise Exception("GPU did not calculate correctly.") + logger.debug("GPU PoW done") return [trialValue, nonce] def run(target, initialHash): target = int(target) - if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): + if safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): # trialvalue1, nonce1 = _doGPUPoW(target, initialHash) # trialvalue, nonce = _doFastPoW(target, initialHash) # print "GPU: %s, %s" % (trialvalue1, nonce1) @@ -133,12 +151,8 @@ def run(target, initialHash): return _doCPoW(target, initialHash) except: pass # fallback - if frozen == "macosx_app" or not frozen: - # on my (Peter Surda) Windows 10, Windows Defender - # does not like this and fights with PyBitmessage - # over CPU, resulting in very slow PoW - try: - return _doFastPoW(target, initialHash) - except: - pass #fallback + try: + return _doFastPoW(target, initialHash) + except: + pass #fallback return _doSafePoW(target, initialHash)