Permalink
Browse files

further work on implementing multi miner support

  • Loading branch information...
1 parent f1ce310 commit 48a97874c2f7e01adc6d663187134b432d1ec51b @m0mchil committed Sep 26, 2012
Showing with 131 additions and 80 deletions.
  1. +33 −21 BitcoinMiner.py
  2. +9 −12 HttpTransport.py
  3. +16 −15 Servers.py
  4. +12 −14 StratumTransport.py
  5. +2 −2 Transport.py
  6. +8 −1 log.py
  7. +51 −15 poclbm.py
View
@@ -24,40 +24,49 @@
class BitcoinMiner():
- def __init__(self, device, options):
+ def __init__(self, device_index, options):
self.output_size = 0x100
self.options = options
- (self.defines, self.rate_divisor, self.hashspace) = if_else(self.options.vectors, ('-DVECTORS', 500, 0x7FFFFFFF), ('', 1000, 0xFFFFFFFF))
- self.defines += (' -DOUTPUT_SIZE=' + str(self.output_size))
- self.defines += (' -DOUTPUT_MASK=' + str(self.output_size - 1))
-
- self.device = device
- self.options.frames = max(self.options.frames, 3)
+ self.device_index = device_index
+ self.device = cl.get_platforms()[options.platform].get_devices()[device_index]
+ self.device_name = self.device.name.strip('\r\n \x00\t')
+ self.frames = 30
self.update_time_counter = 1
self.share_count = [0, 0]
self.work_queue = Queue()
self.update = True
+ self.worksize = self.frameSleep= self.rate = self.estimated_rate = 0
+ self.vectors = False
+
if ADL_PRESENT:
self.adapterIndex = self.get_adapter_info()[self.options.device].iAdapterIndex
+ def id(self):
+ return str(self.options.platform) + ':' + str(self.device_index) + ':' + self.device_name
+
def start(self):
self.should_stop = False
Thread(target=self.mining_thread).start()
+ say_line('started OpenCL miner on platform %d, device %d (%s)', (self.options.platform, self.device_index, self.device_name))
def stop(self, message = None):
if message: print '\n%s' % message
self.should_stop = True
def mining_thread(self):
+ (self.defines, rate_divisor, hashspace) = if_else(self.vectors, ('-DVECTORS', 500, 0x7FFFFFFF), ('', 1000, 0xFFFFFFFF))
+ self.defines += (' -DOUTPUT_SIZE=' + str(self.output_size))
+ self.defines += (' -DOUTPUT_MASK=' + str(self.output_size - 1))
+
self.load_kernel()
- frame = 1.0 / self.options.frames
- unit = self.options.worksize * 256
+ frame = 1.0 / max(self.frames, 3)
+ unit = self.worksize * 256
global_threads = unit * 10
-
+
queue = cl.CommandQueue(self.context)
start_time = last_rated_pace = last_rated = last_n_time = last_temperature = time()
@@ -69,21 +78,23 @@ def mining_thread(self):
work = None
temperature = 0
while True:
- sleep(self.options.frameSleep)
if self.should_stop: return
+
+ sleep(self.frameSleep)
+
if (not work) or (not self.work_queue.empty()):
try:
work = self.work_queue.get(True, 1)
except Empty: continue
else:
if not work: continue
- nonces_left = self.hashspace
+ nonces_left = hashspace
state = work.state
state2 = work.state2
f = work.f
if temperature < self.options.cutoff_temp:
- self.miner.search(queue, (global_threads,), (self.options.worksize,),
+ self.miner.search(queue, (global_threads,), (self.worksize,),
state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7],
state2[1], state2[2], state2[3], state2[5], state2[6], state2[7],
pack('I', base),
@@ -109,16 +120,17 @@ def mining_thread(self):
t = now - last_rated_pace
if t > 1:
- rate = (threads_run_pace / t) / self.rate_divisor
+ rate = (threads_run_pace / t) / rate_divisor
last_rated_pace = now; threads_run_pace = 0
r = last_hash_rate / rate
if r < 0.9 or r > 1.1:
- global_threads = max(unit * int((rate * frame * self.rate_divisor) / unit), unit)
+ global_threads = max(unit * int((rate * frame * rate_divisor) / unit), unit)
+ print self.id(), global_threads
last_hash_rate = rate
t = now - last_rated
if t > self.options.rate:
- self.rate = int((threads_run / t) / self.rate_divisor)
+ self.rate = int((threads_run / t) / rate_divisor)
self.rate = Decimal(self.rate) / 1000
if accept_hist:
LAH = accept_hist.pop()
@@ -174,7 +186,7 @@ def load_kernel(self):
self.context = cl.Context([self.device], None, None)
if (self.device.extensions.find('cl_amd_media_ops') != -1):
self.defines += ' -DBITALIGN'
- if self.device.name.strip('\r\n \x00\t') in ['Cedar',
+ if self.device_name in ['Cedar',
'Redwood',
'Juniper',
'Cypress',
@@ -210,13 +222,13 @@ def load_kernel(self):
finally:
if binary: binary.close()
- if (self.options.worksize == -1):
- self.options.worksize = self.miner.search.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, self.device)
+ if not self.worksize:
+ self.worksize = self.miner.search.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, self.device)
- def get_temperature(self):
+ def get_temperature(self):
temperature = ADLTemperature()
temperature.iSize = sizeof(temperature)
-
+
if ADL_Overdrive5_Temperature_Get(self.adapterIndex, 0, byref(temperature)) == ADL_OK:
return temperature.iTemperature/1000.0
return 0
View
@@ -10,7 +10,6 @@
import httplib
import socket
import socks
-import traceback
import urlparse
@@ -58,8 +57,7 @@ def loop(self):
self.servers.send(result, self.send_internal)
sleep(1)
except Exception:
- say_line("Unexpected error:")
- traceback.print_exc()
+ say_exception("Unexpected error:")
break
def ensure_connected(self, connection, proto, host):
@@ -69,12 +67,12 @@ def ensure_connected(self, connection, proto, host):
if proto == 'https': connector = httplib.HTTPSConnection
else: connector = httplib.HTTPConnection
- if not self.config.proxy:
+ if not self.options.proxy:
return connector(host, strict=True), True
host, port = host.split(':')
- proxy_proto, user, pwd, proxy_host, name = self.config.proxy
+ proxy_proto, user, pwd, proxy_host, name = self.options.proxy
proxy_port = 9050
proxy_host = proxy_host.split(':')
if len(proxy_host) > 1:
@@ -92,8 +90,8 @@ def ensure_connected(self, connection, proto, host):
connection.sock.setproxy(proxy_type, proxy_host, proxy_port, True, user, pwd)
try:
connection.sock.connect((host, int(port)))
- except socks.Socks5AuthError as e:
- say_line('Proxy error: %s', str(e))
+ except socks.Socks5AuthError:
+ say_exception('Proxy error:')
self.stop()
return connection, True
@@ -118,7 +116,7 @@ def request(self, connection, url, headers, data=None, timeout=0):
self.servers.update_time = bool(response.getheader('X-Roll-NTime', ''))
hostList = response.getheader('X-Host-List', '')
self.stratum_header = response.getheader('x-stratum', '')
- if (not self.config.nsf) and hostList: self.servers.add_servers(loads(hostList))
+ if (not self.options.nsf) and hostList: self.servers.add_servers(loads(hostList))
result = loads(response.read())
if result['error']:
say_line('server error: %s', result['error']['message'])
@@ -192,13 +190,12 @@ def long_poll_thread(self):
if response:
(self.lp_connection, result) = response
self.queue_work(result['result'])
- if self.config.verbose:
+ if self.options.verbose:
say_line('long poll: new block %s%s', (result['result']['data'][56:64], result['result']['data'][48:56]))
except Exception:
- traceback.print_exc()
+ say_exception()
except (IOError, httplib.HTTPException, ValueError, socks.ProxyError, NotAuthorized, RPCError):
- say_line('long poll: IO error')
- #traceback.print_exc()
+ say_exception('long poll IO error')
self.close_lp_connection()
sleep(.5)
View
@@ -7,13 +7,13 @@
import log
class Servers(object):
- def __init__(self, config):
+ def __init__(self, options):
self.lock = RLock()
self.miners = []
- self.config = config
+ self.options = options
self.last_work = 0
self.update_time = True
- self.max_update_time = config.max_update_time
+ self.max_update_time = options.max_update_time
self.backup_server_index = 1
self.errors = 0
@@ -23,23 +23,24 @@ def __init__(self, config):
self.save_server = None
self.server_map = {}
- self.user_agent = 'poclbm/' + config.version
+ self.user_agent = 'poclbm/' + options.version
self.difficulty = 0
self.true_target = None
self.last_block = ''
self.sent = {}
- if self.config.proxy:
- self.config.proxy = self.parse_server(self.config.proxy, False)
+ if self.options.proxy:
+ self.options.proxy = self.parse_server(self.options.proxy, False)
self.servers = []
- for server in self.config.servers:
+ for server in self.options.servers:
try:
self.servers.append(self.parse_server(server))
- except ValueError as e:
- say_line(str(e))
+ except ValueError:
+ if self.options.verbose:
+ say_exception()
say_line("Ignored invalid server entry: %s", server)
continue
@@ -111,9 +112,9 @@ def loop(self):
continue
self.errors += 1
- say_line('IO errors - %s, tolerance %s', (self.errors, self.config.tolerance))
+ say_line('IO errors - %s, tolerance %s', (self.errors, self.options.tolerance))
- if self.errors > self.config.tolerance:
+ if self.errors > self.options.tolerance:
self.errors = 0
if self.backup_server_index >= len(self.servers):
say_line("No more backup pools left. Using primary and starting over.")
@@ -176,7 +177,7 @@ def send(self, result, send_callback):
if result.nonce[i]:
h = hash(result.state, result.merkle_end, result.time, result.difficulty, result.nonce[i])
if h[7] != 0:
- say_line('Verification failed, check hardware!')
+ say_line('Verification failed, check hardware! (%s)', (result.miner.id()))
else:
self.diff1_found(bytereverse(h[6]), result.target[6])
if belowOrEquals(h[:7], result.target[:7]):
@@ -187,7 +188,7 @@ def send(self, result, send_callback):
return send_callback(result, result.nonce[i])
def diff1_found(self, hash, target):
- if self.config.verbose and target < 0xFFFF0000L:
+ if self.options.verbose and target < 0xFFFF0000L:
say_line('checking %s <= %s', (hash, target))
def status_updated(self):
@@ -202,8 +203,8 @@ def report(self, miner, nonce, accepted):
is_block, hash6, hash5 = self.sent[nonce]
miner.share_count[if_else(accepted, 1, 0)] += 1
hash = if_else(is_block, hash6 + hash5, hash6)
- if self.config.verbose or is_block:
- say_line('%s%s, %s', (if_else(is_block, 'block ', ''), hash, if_else(accepted, 'accepted', '_rejected_')))
+ if self.options.verbose or is_block:
+ say_line('%s %s%s, %s', (miner.id(), if_else(is_block, 'block ', ''), hash, if_else(accepted, 'accepted', '_rejected_')))
del self.sent[nonce]
def set_server_by_index(self, server_index):
View
@@ -11,7 +11,6 @@
import asyncore
import socket
import socks
-import traceback
#import ssl
@@ -58,13 +57,13 @@ def loop(self):
#socket = ssl.wrap_socket(socket)
host = self.server[3]
address, port = host.split(':', 1)
-
- if not self.config.proxy:
+
+ if not self.options.proxy:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((address, int(port)))
else:
- proxy_proto, user, pwd, proxy_host, name = self.config.proxy
+ proxy_proto, user, pwd, proxy_host, name = self.options.proxy
proxy_port = 9050
proxy_host = proxy_host.split(':')
if len(proxy_host) > 1:
@@ -81,8 +80,8 @@ def loop(self):
self.socket.setproxy(proxy_type, proxy_host, proxy_port, True, user, pwd)
try:
self.socket.connect((address, int(port)))
- except socks.Socks5AuthError as e:
- say_line('Proxy error: %s', str(e))
+ except socks.Socks5AuthError:
+ say_exception('Proxy error:')
self.stop()
self.handler = Handler(self.socket, self.channel_map, self)
@@ -96,8 +95,8 @@ def loop(self):
elif not self.authorize():
self.stop()
- except socket.error as e:
- say_line(str(e))
+ except socket.error:
+ say_exception()
self.stop()
continue
@@ -206,9 +205,9 @@ def handle_message(self, message):
self.subscribed = True
#check if this is submit confirmation (message id should be in submits dictionary)
- #cleanup if necessary
+ #cleanup if necessary
elif message['id'] in self.submits:
- miner, nonce, time = self.submits[message['id']]
+ miner, nonce, t = self.submits[message['id']]
accepted = message['result']
self.servers.report(miner, nonce, accepted)
del self.submits[message['id']]
@@ -269,10 +268,9 @@ def send_message(self, message):
return True
except AttributeError:
self.stop()
- except Exception as e:
- say_line(str(e))
+ except Exception:
+ say_exception()
self.stop()
-
def queue_work(self, work, miner=None):
target = ''.join(list(chunks('%064x' % self.pool_difficulty, 2))[::-1])
@@ -292,7 +290,7 @@ def handle_close(self):
def handle_error(self):
type, value, trace = sys.exc_info()
- say_line('%s', value)
+ say_exception()
self.parent.stop()
def collect_incoming_data(self, data):
View
@@ -9,13 +9,13 @@ def __init__(self, servers, server):
self.server = server
self.proto, self.user, self.pwd, self.host, self.name = server[:5]
self.result_queue = Queue()
- self.config = servers.config
+ self.options = servers.options
def loop(self):
self.should_stop = False
self.last_failback = time()
def check_failback(self):
- if self.servers.server_index != 0 and time() - self.last_failback > self.config.failback:
+ if self.servers.server_index != 0 and time() - self.last_failback > self.options.failback:
self.stop()
return True
Oops, something went wrong.

0 comments on commit 48a9787

Please sign in to comment.