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:
# 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

View File

@ -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")

View File

@ -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)