PoW support code cleanup

Is now nicer and reports if OpenCL fails
This commit is contained in:
mailchuck 2015-11-26 02:38:55 +01:00 committed by Peter Surda
parent 9335f74c61
commit 399100e6d8
3 changed files with 76 additions and 39 deletions

View File

@ -21,6 +21,12 @@ import l10n
# This thread, of which there is only one, does the heavy lifting: # This thread, of which there is only one, does the heavy lifting:
# calculating POWs. # 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): class singleWorker(threading.Thread, StoppableThread):
@ -787,7 +793,7 @@ class singleWorker(threading.Thread, StoppableThread):
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.run(target, initialHash)
logger.info('(For msg message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) logger.info('(For msg message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce))
try: 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: except:
pass pass
@ -966,7 +972,7 @@ class singleWorker(threading.Thread, StoppableThread):
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.run(target, initialHash)
logger.info('(For ack message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) logger.info('(For ack message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce))
try: 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: except:
pass pass

View File

@ -5,35 +5,49 @@ import hashlib
import random import random
import os import os
from shared import codePath, safeConfigGetBoolean
from debug import logger
libAvailable = True
ctx = False ctx = False
queue = False queue = False
program = False program = False
gpus = []
hash_dt = None
try: try:
import numpy import numpy
import pyopencl as cl import pyopencl as cl
hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) except:
gpus = [] libAvailable = False
for platform in cl.get_platforms():
gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) def initCL():
if (len(gpus) > 0): global ctx, queue, program, gpus, hash_dt
ctx = cl.Context(devices=gpus) try:
queue = cl.CommandQueue(ctx) hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)])
full_path = os.path.dirname(os.path.realpath(__file__)) for platform in cl.get_platforms():
f = open(os.path.join(full_path, "bitmsghash", 'bitmsghash.cl'), 'r') gpus.extend(platform.get_devices(device_type=cl.device_type.GPU))
fstr = ''.join(f.readlines()) if (len(gpus) > 0):
program = cl.Program(ctx, fstr).build(options="") ctx = cl.Context(devices=gpus)
else: queue = cl.CommandQueue(ctx)
print "No OpenCL GPUs found" 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 ctx = False
except Exception as e:
print "opencl fail: " + str(e)
ctx = False
def has_opencl(): def has_opencl():
global ctx
return (ctx != False) return (ctx != False)
def do_opencl_pow(hash, target): def do_opencl_pow(hash, target):
global ctx, queue, program, gpus, hash_dt
output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)])
if (ctx == False): if (ctx == False):
return output[0][0] return output[0][0]
@ -62,11 +76,14 @@ def do_opencl_pow(hash, target):
queue.finish() queue.finish()
progress += globamt progress += globamt
sofar = time.time() - start 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 taken = time.time() - start
print progress, taken # logger.debug("Took %d tries.", progress)
return output[0][0] return output[0][0]
if libAvailable:
initCL()
if __name__ == "__main__": if __name__ == "__main__":
target = 54227212183L target = 54227212183L
initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex") initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex")

View File

@ -4,9 +4,10 @@
import hashlib import hashlib
from struct import unpack, pack from struct import unpack, pack
import sys import sys
from shared import config, frozen, codePath from debug import logger
import shared from shared import config, frozen, codePath, shutdown, safeConfigGetBoolean, UISignalQueue
import openclpow import openclpow
import tr
import os import os
import ctypes import ctypes
@ -17,12 +18,20 @@ if "win32" == sys.platform:
else: else:
bitmsglib = 'bitmsghash64.dll' bitmsglib = 'bitmsghash64.dll'
try: try:
# MSVS
bso = ctypes.WinDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) bso = ctypes.WinDLL(os.path.join(codePath(), "bitmsghash", bitmsglib))
logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib)
except: 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: else:
try: try:
bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib))
logger.info("Loaded C PoW DLL %s", bitmsglib)
except: except:
bso = None bso = None
if bso: if bso:
@ -58,16 +67,17 @@ def _pool_worker(nonce, initialHash, target, pool_size):
return [trialValue, nonce] return [trialValue, nonce]
def _doSafePoW(target, initialHash): def _doSafePoW(target, initialHash):
print "Safe POW\n" logger.debug("Safe PoW start")
nonce = 0 nonce = 0
trialValue = float('inf') trialValue = float('inf')
while trialValue > target: while trialValue > target:
nonce += 1 nonce += 1
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
logger.debug("Safe PoW done")
return [trialValue, nonce] return [trialValue, nonce]
def _doFastPoW(target, initialHash): def _doFastPoW(target, initialHash):
print "Fast POW\n" logger.debug("Fast PoW start")
import time import time
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
try: try:
@ -85,7 +95,7 @@ def _doFastPoW(target, initialHash):
for i in range(pool_size): for i in range(pool_size):
result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size)))
while True: while True:
if shared.shutdown >= 1: if shutdown >= 1:
pool.terminate() pool.terminate()
while True: while True:
time.sleep(10) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py 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() result = result[i].get()
pool.terminate() pool.terminate()
pool.join() #Wait for the workers to exit... pool.join() #Wait for the workers to exit...
logger.debug("Fast PoW done")
return result[0], result[1] return result[0], result[1]
time.sleep(0.2) time.sleep(0.2)
def _doCPoW(target, initialHash): def _doCPoW(target, initialHash):
h = initialHash h = initialHash
m = target m = target
out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64)) out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64))
out_m = ctypes.c_ulonglong(m) out_m = ctypes.c_ulonglong(m)
print "C PoW start" logger.debug("C PoW start")
nonce = bmpow(out_h, out_m) nonce = bmpow(out_h, out_m)
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) 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] return [trialValue, nonce]
def _doGPUPoW(target, initialHash): def _doGPUPoW(target, initialHash):
print "GPU PoW start" logger.debug("GPU PoW start")
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target) nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
#print "{} - value {} < {}".format(nonce, trialValue, target) #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] return [trialValue, nonce]
def run(target, initialHash): def run(target, initialHash):
target = int(target) 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) # trialvalue1, nonce1 = _doGPUPoW(target, initialHash)
# trialvalue, nonce = _doFastPoW(target, initialHash) # trialvalue, nonce = _doFastPoW(target, initialHash)
# print "GPU: %s, %s" % (trialvalue1, nonce1) # print "GPU: %s, %s" % (trialvalue1, nonce1)
@ -133,12 +151,8 @@ def run(target, initialHash):
return _doCPoW(target, initialHash) return _doCPoW(target, initialHash)
except: except:
pass # fallback pass # fallback
if frozen == "macosx_app" or not frozen: try:
# on my (Peter Surda) Windows 10, Windows Defender return _doFastPoW(target, initialHash)
# does not like this and fights with PyBitmessage except:
# over CPU, resulting in very slow PoW pass #fallback
try:
return _doFastPoW(target, initialHash)
except:
pass #fallback
return _doSafePoW(target, initialHash) return _doSafePoW(target, initialHash)