Added POW settings to settings window

This commit is contained in:
Biryuzovye Kleshni 2018-07-29 04:38:05 +00:00
parent 2c7d677ccf
commit 373157db45
7 changed files with 376 additions and 139 deletions

View File

@ -55,6 +55,7 @@ import sound
import re
import bitmessage_icons_rc # Loads icon resources
import workprover.utils
import singleworker
try:
@ -2616,9 +2617,34 @@ class MyForm(settingsmixin.SMainWindow):
BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float(
self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes)))
if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"):
BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText()))
queues.workerQueue.put(('resetPoW', ''))
if self.settingsDialogInstance.ui.radioButtonDumbSolver.isChecked():
BMConfigParser().set("bitmessagesettings", "powsolver", "dumb")
elif self.settingsDialogInstance.ui.radioButtonForkingSolver.isChecked():
BMConfigParser().set("bitmessagesettings", "powsolver", "forking")
BMConfigParser().set(
"bitmessagesettings",
"processes",
str(self.settingsDialogInstance.ui.spinBoxForkingSolverParallelism.value())
)
elif self.settingsDialogInstance.ui.radioButtonFastSolver.isChecked():
BMConfigParser().set("bitmessagesettings", "powsolver", "fast")
BMConfigParser().set(
"bitmessagesettings",
"threads",
str(self.settingsDialogInstance.ui.spinBoxFastSolverParallelism.value())
)
elif self.settingsDialogInstance.ui.radioButtonGPUSolver.isChecked():
BMConfigParser().set("bitmessagesettings", "powsolver", "gpu")
BMConfigParser().set(
"bitmessagesettings",
"opencl",
str(self.settingsDialogInstance.ui.comboBoxGPUVendor.currentText().toUtf8())
)
singleworker.setBestSolver()
acceptableDifficultyChanged = False
@ -4547,18 +4573,43 @@ class settingsDialog(QtGui.QDialog):
self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint(
'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes)))
# OpenCL
if openclpow.openclAvailable():
self.ui.comboBoxOpenCL.setEnabled(True)
else:
self.ui.comboBoxOpenCL.setEnabled(False)
self.ui.comboBoxOpenCL.clear()
self.ui.comboBoxOpenCL.addItem("None")
self.ui.comboBoxOpenCL.addItems(openclpow.vendors)
self.ui.comboBoxOpenCL.setCurrentIndex(0)
for i in range(self.ui.comboBoxOpenCL.count()):
if self.ui.comboBoxOpenCL.itemText(i) == BMConfigParser().safeGet('bitmessagesettings', 'opencl'):
self.ui.comboBoxOpenCL.setCurrentIndex(i)
if "forking" not in singleworker.workProver.availableSolvers:
self.ui.radioButtonForkingSolver.setEnabled(False)
if "fast" not in singleworker.workProver.availableSolvers:
self.ui.radioButtonFastSolver.setEnabled(False)
if "gpu" not in singleworker.workProver.availableSolvers:
self.ui.radioButtonGPUSolver.setEnabled(False)
solverName = BMConfigParser().safeGet("bitmessagesettings", "powsolver", "gpu")
forkingSolverParallelism = BMConfigParser().safeGetInt("bitmessagesettings", "processes")
fastSolverParallelism = BMConfigParser().safeGetInt("bitmessagesettings", "threads")
GPUVendor = BMConfigParser().safeGet("bitmessagesettings", "opencl")
if solverName == "dumb":
self.ui.radioButtonDumbSolver.setChecked(True)
elif solverName == "forking":
self.ui.radioButtonForkingSolver.setChecked(True)
elif solverName == "fast":
self.ui.radioButtonFastSolver.setChecked(True)
elif solverName == "gpu":
self.ui.radioButtonGPUSolver.setChecked(True)
self.ui.spinBoxForkingSolverParallelism.setValue(forkingSolverParallelism)
self.ui.spinBoxFastSolverParallelism.setValue(fastSolverParallelism)
vendors = set(singleworker.workProver.availableSolvers["gpu"].vendors)
if GPUVendor is not None:
vendors.add(GPUVendor)
self.ui.comboBoxGPUVendor.clear()
self.ui.comboBoxGPUVendor.addItems(list(vendors))
self.ui.comboBoxGPUVendor.setCurrentIndex(0)
for i in range(self.ui.comboBoxGPUVendor.count()):
if self.ui.comboBoxGPUVendor.itemText(i) == GPUVendor:
self.ui.comboBoxGPUVendor.setCurrentIndex(i)
break
# Namecoin integration tab

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>555</width>
<width>616</width>
<height>592</height>
</rect>
</property>
@ -14,16 +14,6 @@
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidgetSettings">
<property name="currentIndex">
@ -549,13 +539,13 @@
<string>Max acceptable difficulty</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_15">
<item row="2" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.</string>
<string>Maximum acceptable small message difficulty:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
@ -585,6 +575,32 @@
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="lineEditMaxAcceptableSmallMessageDifficulty">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="lineEditMaxAcceptableTotalDifficulty">
<property name="sizePolicy">
@ -614,33 +630,142 @@
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Maximum acceptable small message difficulty:</string>
<item row="3" column="0" colspan="3">
<widget class="QGroupBox" name="groupBoxSolvers">
<property name="title">
<string>Proof of work solver</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<layout class="QGridLayout" name="gridLayout_10">
<item row="0" column="0">
<widget class="QLabel" name="labelSolvers">
<property name="text">
<string>There are several worker modules to solve POW:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="lineEditMaxAcceptableSmallMessageDifficulty">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayoutForkingSolver">
<item>
<widget class="QRadioButton" name="radioButtonForkingSolver">
<property name="text">
<string>Forking solver using multiple processes:</string>
</property>
<property name="maximumSize">
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxForkingSolverParallelism">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>4096</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacerForkingSolver">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>70</width>
<height>16777215</height>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayoutFastSolver">
<item>
<widget class="QRadioButton" name="radioButtonFastSolver">
<property name="text">
<string>Fast solver in C with multiple threads:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item>
<widget class="QSpinBox" name="spinBoxFastSolverParallelism">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>4096</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacerFastSolver">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayoutDumbSolver">
<item>
<widget class="QRadioButton" name="radioButtonDumbSolver">
<property name="text">
<string>Dumb solver</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacerDumbSolver">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayoutGPUSolver">
<item>
<widget class="QRadioButton" name="radioButtonGPUSolver">
<property name="text">
<string>GPU solver:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxGPUVendor"/>
</item>
<item>
<spacer name="horizontalSpacerGPUSolver">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" colspan="3">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -653,16 +778,6 @@
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelOpenCL">
<property name="text">
<string>Hardware GPU acceleration (OpenCL):</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="comboBoxOpenCL"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNamecoin">
@ -981,6 +1096,16 @@
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
@ -998,6 +1123,7 @@
<tabstop>checkBoxSocksListen</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>

View File

@ -221,6 +221,66 @@ def disseminateObject(nonce, expiryTime, headlessPayload, objectType, stream, ta
return inventoryHash, payload
workProver = workprover.WorkProver(
os.path.join(paths.codePath(), "workprover"),
helper_random.randomBytes(32),
lambda status: queues.UISignalQueue.put(("updateWorkProverStatus", status)),
queues.workerQueue
)
debug.logger.info("Availabe solvers: %s", str(workProver.availableSolvers.keys()))
if "fast" not in workProver.availableSolvers:
queues.UISignalQueue.put(("updateStatusBar", (
tr._translate(
"proofofwork",
"C PoW module unavailable. Please build it."
), 1
)))
def setBestSolver():
solverName = bmconfigparser.BMConfigParser().safeGet("bitmessagesettings", "powsolver", "gpu")
forkingSolverParallelism = bmconfigparser.BMConfigParser().safeGetInt("bitmessagesettings", "processes")
fastSolverParallelism = bmconfigparser.BMConfigParser().safeGetInt("bitmessagesettings", "threads")
GPUVendor = bmconfigparser.BMConfigParser().safeGet("bitmessagesettings", "opencl")
if forkingSolverParallelism < 1:
forkingSolverParallelism = workProver.defaultParallelism
if fastSolverParallelism < 1:
fastSolverParallelism = workProver.defaultParallelism
maxcores = bmconfigparser.BMConfigParser().safeGetInt("bitmessagesettings", "maxcores", None)
if maxcores is not None:
forkingSolverParallelism = min(maxcores, forkingSolverParallelism)
fastSolverParallelism = min(maxcores, fastSolverParallelism)
if solverName == "gpu" and GPUVendor is None:
solverName = "fast"
while solverName not in workProver.availableSolvers:
if solverName == "gpu":
solverName = "fast"
elif solverName == "fast":
solverName = "forking"
elif solverName == "forking":
solverName = "dumb"
bmconfigparser.BMConfigParser().set("bitmessagesettings", "powsolver", solverName)
bmconfigparser.BMConfigParser().set("bitmessagesettings", "processes", str(forkingSolverParallelism))
bmconfigparser.BMConfigParser().set("bitmessagesettings", "threads", str(fastSolverParallelism))
bmconfigparser.BMConfigParser().save()
if solverName in ["dumb", "gpu"]:
workProver.commandsQueue.put(("setSolver", solverName, None))
elif solverName == "forking":
workProver.commandsQueue.put(("setSolver", "forking", forkingSolverParallelism))
elif solverName == "fast":
workProver.commandsQueue.put(("setSolver", "fast", fastSolverParallelism))
setBestSolver()
class singleWorker(threading.Thread, helper_threading.StoppableThread):
name = "singleWorker"
@ -235,41 +295,7 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
super(self.__class__, self).stopThread()
def run(self):
GPUVendor = bmconfigparser.BMConfigParser().safeGet("bitmessagesettings", "opencl")
self.workProver = workprover.WorkProver(
os.path.join(paths.codePath(), "workprover"),
GPUVendor,
helper_random.randomBytes(32),
lambda status: queues.UISignalQueue.put(("updateWorkProverStatus", status)),
queues.workerQueue
)
self.workProver.start()
parallelism = bmconfigparser.BMConfigParser().safeGetInt("bitmessagesettings", "maxcores")
if parallelism < 1:
parallelism = self.workProver.defaultParallelism
debug.logger.info("Availabe solvers: %s", str(self.workProver.availableSolvers.keys()))
if "gpu" in self.workProver.availableSolvers and GPUVendor is not None:
self.workProver.commandsQueue.put(("setSolver", "gpu", None))
elif "fast" in self.workProver.availableSolvers:
self.workProver.commandsQueue.put(("setSolver", "fast", parallelism))
elif "forking" in self.workProver.availableSolvers:
self.workProver.commandsQueue.put(("setSolver", "forking", parallelism))
else:
self.workProver.commandsQueue.put(("setSolver", "dumb", None))
if "fast" not in self.workProver.availableSolvers:
queues.UISignalQueue.put(("updateStatusBar", (
tr._translate(
"proofofwork",
"C PoW module unavailable. Please build it."
), 1
)))
workProver.start()
self.startedWorks = {}
@ -299,16 +325,34 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
self.requestPubkey(*arguments)
elif command == "resetPoW":
pass
elif command == "GPUError":
self.handleGPUError(*arguments)
elif command == "taskDone":
self.workDone(*arguments)
elif command == "stopThread":
self.workProver.commandsQueue.put(("shutdown", ))
self.workProver.join()
workProver.commandsQueue.put(("shutdown", ))
workProver.join()
break
debug.logger.info("Quitting...")
def handleGPUError(self):
bmconfigparser.BMConfigParser().set("bitmessagesettings", "powsolver", "dumb")
workProver.commandsQueue.put(("setSolver", "dumb", None))
debug.logger.error(
"Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers"
)
queues.UISignalQueue.put(("updateStatusBar", (
tr._translate(
"MainWindow",
"Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers."
), 1
)))
def startWork(self, ID, headlessPayload, TTL, expiryTime, byteDifficulty, lengthExtension, logPrefix, callback):
debug.logger.info(
"%s Starting work %s, payload length = %s, TTL = %s",
@ -317,7 +361,7 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
self.startedWorks[ID] = callback
self.workProver.commandsQueue.put((
workProver.commandsQueue.put((
"addTask", ID, headlessPayload, TTL, expiryTime,
byteDifficulty, lengthExtension
))
@ -588,7 +632,7 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
if ID in self.startedWorks:
del self.startedWorks[ID]
self.workProver.commandsQueue.put(("cancelTask", ID))
workProver.commandsQueue.put(("cancelTask", ID))
helper_sql.sqlExecute("""
UPDATE "sent" SET "status" = 'broadcastcanceled'
@ -906,14 +950,14 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
if ID in self.startedWorks:
del self.startedWorks[ID]
self.workProver.commandsQueue.put(("cancelTask", ID))
workProver.commandsQueue.put(("cancelTask", ID))
ID = "message", ackData
if ID in self.startedWorks:
del self.startedWorks[ID]
self.workProver.commandsQueue.put(("cancelTask", ID))
workProver.commandsQueue.put(("cancelTask", ID))
state.watchedAckData -= {ackData}
@ -933,7 +977,7 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
if ID in self.startedWorks:
del self.startedWorks[ID]
self.workProver.commandsQueue.put(("cancelTask", ID))
workProver.commandsQueue.put(("cancelTask", ID))
status, version, stream, ripe = addresses.decodeAddress(destination)

View File

@ -30,10 +30,12 @@ class Task(object):
Status = collections.namedtuple("Status", ["solverName", "solverStatus", "speed", "tasksCount", "difficulty"])
# Only one instance allowed
class WorkProver(threading.Thread):
# Seed must be 32 bytes
def __init__(self, codePath, GPUVendor, seed, statusUpdated, resultsQueue):
def __init__(self, codePath, seed, statusUpdated, resultsQueue):
super(self.__class__, self).__init__()
self.availableSolvers = {
@ -56,7 +58,7 @@ class WorkProver(threading.Thread):
pass
try:
self.availableSolvers["gpu"] = gpusolver.GPUSolver(codePath, GPUVendor)
self.availableSolvers["gpu"] = gpusolver.GPUSolver(codePath)
except gpusolver.GPUSolverError:
pass
@ -99,6 +101,7 @@ class WorkProver(threading.Thread):
self.statusUpdated(Status(self.solverName, status, self.speed, len(self.tasks), self.totalDifficulty))
def setSolver(self, name, configuration):
try:
if name is None and self.solverName is None:
pass
elif name == self.solverName:
@ -116,6 +119,11 @@ class WorkProver(threading.Thread):
self.solverName = name
self.solver = self.availableSolvers[name]
self.solver.setConfiguration(configuration)
except GPUSolverError:
self.solverName = None
self.solver = None
self.resultsQueue.put(("GPUError", ))
self.notifyStatus()
@ -229,8 +237,9 @@ class WorkProver(threading.Thread):
try:
nonce, iterationsCount = self.solver.search(initialHash, task.target, appendedSeed, timeout)
except gpusolver.GPUSolverError:
self.setSolver("dumb", 1)
self.availableSolvers.pop("gpu")
self.setSolver(None, None)
self.resultsQueue.put(("GPUError", ))
nonce, iterationsCount = None, 0

View File

@ -37,6 +37,8 @@ def loadFastSolver(codePath):
except:
raise FastSolverError()
# Only one instance allowed
class FastSolver(object):
def __init__(self, codePath):
self.libfastsolver = loadFastSolver(codePath)

View File

@ -11,7 +11,7 @@ class GPUSolverError(Exception):
pass
class GPUSolver(object):
def __init__(self, codePath, vendor = None):
def __init__(self, codePath):
global pyopencl
try:
@ -19,17 +19,15 @@ class GPUSolver(object):
except ImportError:
raise GPUSolverError()
for i in pyopencl.get_platforms():
if vendor is not None and i.vendor != vendor:
continue
self.vendors = {}
for i in pyopencl.get_platforms():
devices = i.get_devices(device_type = pyopencl.device_type.GPU)
if len(devices) != 0:
self.device = devices[0]
self.vendors[i.vendor] = devices[0]
break
else:
if len(self.vendors) == 0:
raise GPUSolverError()
with open(os.path.join(codePath, "gpusolver.cl")) as file:
@ -88,14 +86,21 @@ class GPUSolver(object):
import numpy
context = pyopencl.Context(devices = [self.device])
if configuration is None:
configuration = self.vendors.keys()[0]
computeUnitsCount = self.device.get_info(pyopencl.device_info.MAX_COMPUTE_UNITS)
workGroupSize = self.device.get_info(pyopencl.device_info.MAX_WORK_GROUP_SIZE)
if configuration not in self.vendors:
raise GPUSolverError()
device = self.vendors[configuration]
context = pyopencl.Context(devices = [device])
computeUnitsCount = device.get_info(pyopencl.device_info.MAX_COMPUTE_UNITS)
workGroupSize = device.get_info(pyopencl.device_info.MAX_WORK_GROUP_SIZE)
self.batchSize = workGroupSize * computeUnitsCount * 256
self.queue = pyopencl.CommandQueue(context, self.device)
self.queue = pyopencl.CommandQueue(context, device)
program = pyopencl.Program(context, self.source).build()

View File

@ -122,7 +122,7 @@ class TestGPUSolver(TestSolver):
class TestWorkProver(unittest.TestCase):
def setUp(self):
self.thread = __init__.WorkProver(codePath, None, seed, None, None)
self.thread = __init__.WorkProver(codePath, seed, None, None)
self.thread.start()
def checkTaskLinks(self):