def add(self, device_id, device_class, pool, miner, algo, region, hashrate, gross_mbtc, net_mbtc, device_watts, total_watts): if not os.path.exists(self.log_file): with open(self.log_file, "w") as f: f.write( "timestamp,device_id,device_class,pool,miner,algorithm,region,hashrate,gross_mbtc,net_mbtc,device_watts,total_watts\n" ) with open(self.log_file, "a+") as f: if net_mbtc == 0: net_s = "" else: net_s = "%.2f" % (net_mbtc) if '_' in algo: hashrate_s = Units().hashrate_str(hashrate) else: hashrate_s = Units().hashrate_str(hashrate[0]) f.write("%s,%d,%s,%s,%s,%s,%s,%s,%.2f,%s,%.2f,%.2f\n" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), device_id, device_class, pool, miner, algo, region, hashrate_s, gross_mbtc, net_s, device_watts, total_watts)) if os.path.getsize(self.log_file) >= ( Config().get('stats.max_size_mb') * 1024 * 1024): self.rotate_logs(self.log_file)
def get_power_draw_average_time_periods(self): data = {} for seconds in Config().get('live_data.power_draw_averages'): data[seconds] = Units().seconds_to_string(seconds) return data
def get_miner_hashrate_for_algorithm_on_device(self, miner_name, algorithm, device_class): calibrated = self.get('%s.%s.%s' % (device_class, miner_name, algorithm)) if calibrated: return Units().hashrate_str(calibrated['hashrate']) return " "
def realnew(klass, h, M, L, K): self = object.__new__(klass) self.M = M self.L = L self.K = K self.h = h self.units = Units(h) self.U = self.units self.DH = self.units.C / self.units.H0 self.tH = 1.0 / self.units.H0 self._cosmology = _cosmology.Cosmology(self.M, self.K, self.L, self.h) return self
def check_hashrate(self): hashrates = Calibration().get_hashrates(self) if len(self.algos) == 0: return miner = self.algos[0]['miner'] algo = self.algos[0]['algo'] if not miner in hashrates.keys() or not algo in hashrates[miner].keys( ): self.log( 'warning', 'running uncalibrated algorithm %s with miner %s' % (algo, miner)) return if self.algos[0]['algo'] in Config().get('algorithms.single'): baseline = float(hashrates[miner][algo]['hashrate']) else: baseline = float(hashrates[miner][algo]['hashrate'][0]) threshold_pc_value = ( baseline / 100) * Config().get('hashrate_alert_threshold_percent') hr_s = Units().hashrate_str(self.algos[0]['hashrate'][0]) bl_s = Units().hashrate_str(baseline) if self.algos[0]['hashrate'][0] < baseline and ( baseline - self.algos[0]['hashrate'][0]) >= threshold_pc_value: self.log( 'warning', 'hashrate %d%% below calibrated rate [%s < %s]' % (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s)) if self.algos[0]['hashrate'][0] > baseline and ( self.algos[0]['hashrate'][0] - baseline) >= threshold_pc_value: self.log( 'warning', 'hashrate %d%% above calibrated rate [%s > %s]' % (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s))
args_cli = pytools.parse_args() var = args_cli.var #confs = [ "gam3.ini", ] confs = [ args_cli.conf_filename, ] for conf_filename in confs: conf = Configuration(conf_filename, do_print=True) # restructure path to point to this dir fdir = conf.outdir print(fdir) units = Units(conf) #-------------------------------------------------- # read data flds_Epar = [] flds_Eperp = [] flds_Bpar = [] flds_Bperp = [] flds_Jpar = [] flds_Jperp = [] flds_time = [] flds_tot = []
def hashrate_str(self): if self.algos[0]['algo'] in Config().get('algorithms.single'): return Units().hashrate_str(self.algos[0]['hashrate'][0]) return Units().hashrate_str(self.algos[0]['hashrate'])
def handle_device_update(self, device): if (datetime.datetime.now() - device.changed).seconds < (Config().get('calibration.update_calibration_data_after_mins') * 60): return for algo in device.algos: # Max update once a minute if algo['calibration_updated_at'] and \ (time.time() - algo['calibration_updated_at']) < 60: continue if len(algo['hashrate_readings']) >0: readings_a = [] readings_b = [] for reading in algo['hashrate_readings']: readings_a.append(reading[0]) readings_b.append(reading[1]) if '_' in algo['algo']: variance, n = self.get_variance(readings_a, readings_b) else: variance, n = self.get_variance(readings_a) if self.is_stable(variance, n): calibrated_data = self.get('%s.%s.%s' % (device.dclass, algo['miner'], algo['algo'])) if '_' in algo['algo']: nominal = [self.get_nominal_hashrate_from_range(readings_a), self.get_nominal_hashrate_from_range(readings_b)] else: nominal = self.get_nominal_hashrate_from_range(readings_a) if self.within_update_threshold(nominal, calibrated_data['hashrate']) and \ self.hashrate_is_visibly_different(nominal, calibrated_data['hashrate']): device.log('info', '%s[%s]: new calibrated rate: %s' % (algo['algo'], algo['miner'], Units().hashrate_str(nominal))) calibrated_data['hashrate'] = nominal self.update_calibration_data(device.dclass, algo['miner'], algo['algo'], nominal, calibrated_data['power_limit']) self.set("%s.%s.%s" % (device.dclass, algo['miner'], algo['algo']), calibrated_data) algo['calibration_updated_at'] = time.time()
def start(self, device, pool_name, miner, algorithm, region, quick=False, force=False): self.miner = miner self.device = device self.default_profile = Config().get('device_profiles.default') Miners().reload_config() device.pin = { 'pool_name': pool_name, 'miner_name': miner.name, 'algorithm': algorithm, 'region': region } if not Config().get('calibration'): Log().add('fatal', "calibration config missing from config file") for key in [ "hashrate_stabilisation_timeout_mins", "hashrate_stabilisation_tolerance", "hashrate_stabilisation_consecutive_readings_required", "algorithm_start_timeout" ]: if Config().get('calibration.%s' % (key)) == None: Log().add('fatal', "missing config option: calibration.%s" % (key)) if Config().get('calibration.power_tuning.enable'): for key in ["decrement_watts", "acceptable_loss_percent"]: if not Config().get('calibration.power_tuning.%s' % (key)): Log().add( 'fatal', "missing config option: calibration.power_tuning.%s" % (key)) Config().set('pools.%s.append_device_id_to_worker_name' % (pool_name), False) if pool_name == 'miningpoolhub': if Config().get('pools.miningpoolhub.hub_workers.%s' % (algorithm))[-5:] != 'CALIB': Config().set( 'pools.miningpoolhub.hub_workers.%s' % (algorithm), Config().get('pools.miningpoolhub.hub_workers.%s' % (algorithm)) + 'CALIB') else: if Config().get('pools.%s.worker_name' % (pool_name))[-5:] != 'CALIB': Config().set( 'pools.%s.worker_name' % (pool_name), Config().get('pools.%s.worker_name' % (pool_name)) + "CALIB") if quick: Config().set('calibration.power_tuning.enable', False) profile = Profiles().get_for_device_algo(device, algorithm) Log().add('info', ' device id: %d' % (device.id)) Log().add('info', ' pool: %s' % (pool_name)) Log().add('info', ' device class: %s' % (device.dclass)) Log().add('info', 'device profile: %s' % (profile.name)) Log().add('info', ' miner: %s' % (miner.name)) Log().add('info', ' algorithm: %s' % (algorithm)) Log().add('info', ' region: %s' % (region)) Miners().poll() Miners().get_device_state(device) if device.state != 'inactive': if device.state == 'calibrating': device.log( 'fatal', 'this device is already being used for calibration') if force: device.log('info', 'terminating existing worker') if not device.stop(True): device.log('fatal', 'failed to stop existing worker') else: device.log( 'fatal', 'unable to start calibration - device is in use (use --force to override)' ) self.set_pin(device.id) default_power_limit = device.default_power_limit_f min_power_limit = device.min_power_limit_f max_power_limit = device.max_power_limit_f if max_power_limit == 0: device.log('info', 'device does not support power monitoring') else: device.log('info', 'max power limit: %d W' % (max_power_limit)) device.log( 'info', 'stabilisation tolerance: %.2f%%' % (Config().get('calibration.hashrate_stabilisation_tolerance'))) if Config().get('debug'): device.log('debug', 'loading default profile') Nvidia().set_default_profile(device) if Config().get('debug'): device.log('debug', 'initialising pools') Pools() sample_timeout = Config().get( 'calibration.hashrate_stabilisation_timeout_mins') if default_power_limit != None and Config().get( 'calibration.power_tuning.enable'): device.log( 'info', 'starting initial run at max power limit [timeout=%dmins]' % (sample_timeout)) else: device.log( 'info', 'starting single run [timeout=%dmins]' % (sample_timeout)) Miners().poll() Miners().get_device_state(device) if device.state != 'calibrating': if not device.start(True): device.log('fatal', 'worker failed to start') if Config().get('calibration.power_tuning.enable'): if not device.power_supported(): device.log('info', 'device does not support power monitoring') else: device.set_power_limit(max_power_limit) initial_hashrate, initial_max_power_draw = self.get_max_hashrate_and_power_draw( miner, device, sample_timeout * 60) if initial_hashrate == None: device.log( 'info', 'skipping algorithm as we failed to get a stable reading') print "" return if initial_max_power_draw != None and initial_max_power_draw > max_power_limit: initial_max_power_draw = max_power_limit device.log( 'info', 'benchmark hashrate: %s' % (Units().hashrate_str(initial_hashrate))) if initial_max_power_draw != None: device.log('info', 'max power draw: %.2f' % (initial_max_power_draw)) initial_power_limit = int(math.ceil(initial_max_power_draw)) hashrate = initial_hashrate if initial_max_power_draw == None: power_limit = None elif Config().get('calibration.power_tuning.enable'): if max_power_limit == 0 or min_power_limit == 0 or default_power_limit == 0: device.log( 'error', 'device did not give us sane values for its min/max/default power limits' ) device.log( 'error', 'unable to proceed with power calibration - device may not support changing the power limit' ) power_limit = default_power_limit else: power_limit = initial_power_limit device.log('info', 'tuning power limit for optimum efficiency') hashrate, power_limit = self.do_power_calibration( device, power_limit, miner, hashrate, min_power_limit) else: power_limit = default_power_limit Nvidia().set_default_profile(device) self.unset_pin(device.id) device.log('info', 'storing calibration data') Calibration().update_calibration_data(device.dclass, miner.name, algorithm, hashrate, power_limit) if not device.stop(True): device.log('fatal', "failed to stop the miner process") print "" device.log( 'info', ' calibrated hashrate: %s' % (Units().hashrate_str(hashrate))) if power_limit != None: device.log('info', 'calibrated power limit: %.2f W' % (power_limit)) print ""
def do_power_calibration(self, device, power_limit, miner, initial_hashrate, min_power_limit): sample_timeout = Config().get( 'calibration.hashrate_stabilisation_timeout_mins') acceptable_loss_pc = Config().get( 'calibration.power_tuning.acceptable_loss_percent') dial_back = False dialed_back = False hashrate = initial_hashrate if "_" in device.algos[0]['algo']: initial_value = initial_hashrate[0] else: initial_value = initial_hashrate while True: if dial_back: power_limit += Config().get( 'calibration.power_tuning.decrement_watts') / 2 dialed_back = True else: power_limit -= Config().get( 'calibration.power_tuning.decrement_watts') if power_limit < min_power_limit: power_limit = min_power_limit device.log('info', 'setting power limit: %d W' % (power_limit)) device.set_power_limit(power_limit) new_hashrate, max_power_draw = self.get_max_hashrate_and_power_draw( miner, device, sample_timeout * 60) if new_hashrate == None: device.log( 'info', 'skipping algorithm as we failed to get a stable reading') print "" return if "_" in device.algos[0]['algo']: new_value = new_hashrate[0] else: new_value = new_hashrate device.log( 'info', 'nominal hashrate: %s' % (Units().hashrate_str(new_hashrate))) if new_value > initial_value: device.log('info', 'hashrate is higher than before, w00t!') hashrate = new_hashrate initial_value = new_value elif new_value >= (initial_value - (initial_value / 100) * acceptable_loss_pc): hashrate = new_hashrate if power_limit == min_power_limit or dial_back: device.log( 'info', 'hashrate loss is within acceptable %.2f%%' % (acceptable_loss_pc)) else: device.log( 'info', 'hashrate loss is within acceptable %.2f%%, continuing' % (acceptable_loss_pc)) else: if dial_back or Config().get( 'calibration.power_tuning.decrement_watts') == 1: device.log( 'info', 'hashrate still below our acceptable loss level of %.2f%%, stopping' % (acceptable_loss_pc)) if Config().get( 'calibration.power_tuning.decrement_watts') == 1: power_limit += 1 else: power_limit += Config().get( 'calibration.power_tuning.decrement_watts') / 2 break else: device.log( 'info', 'hashrate fell below our acceptable loss level of %.2f%%, dialling back %d W' % (acceptable_loss_pc, Config().get( 'calibration.power_tuning.decrement_watts') / 2)) dial_back = True if dialed_back: break if power_limit == min_power_limit and not dial_back: device.log('info', 'minimum power limit reached, stopping') break return [hashrate, power_limit]
def __init__(self, units_config): self.units_config = units_config self.units = Units(units_config["units"]) self.allies = Allies(units_config["allies"]) self.battalions = Battalions(units_config["battalions"]) self.all = [self.units, self.allies, self.battalions]
def get_local_data(self, minimal=False): data = [] devices = nvidia.Nvidia().get_nvidia_devices(1, True) Miners().poll() if not minimal and os.path.exists( self.power_file) and os.path.getsize(self.power_file) > 0: power_draw_readings = pickle.loads(open(self.power_file).read()) else: power_draw_readings = [] if not minimal and os.path.exists( self.profitability_file) and os.path.getsize( self.profitability_file) > 0: profitability_readings = pickle.loads( open(self.profitability_file).read()) else: profitability_readings = [] Calibration().load() total_mbtc = 0 total_power = 0 total_power_limit = 0 power_values = {} power_limit_values = {} for device in devices: device.algos = [] Miners().get_device_state(device) mbtc_per_day_values = [0] algos = device.algos if len(algos) == 0: algos = ['IDLE'] for algo_i in range(0, len(algos)): algo = algos[algo_i] if algo_i == 0: omit_fields = False else: omit_fields = True if algo == 'IDLE': algo = "IDLE" algo1 = "IDLE" rate_s = "-" mbtc_per_day = 0 miner = '-' region = '-' pool = '-' _time = '-' else: algo1 = algo['algo'] miner = algo['miner'] region = algo['region'] pool = algo['pool'] _pool = Pools().pools[pool] if os.path.exists("/tmp/.minotaur.%d" % (device.id)): _time = Units().to_timestr( int(time.time() - os.stat("/tmp/.minotaur.%d" % (device.id)).st_mtime)) else: _time = '-' rate_a, rate_b = algo['hashrate'] if algo['algo'] in Config().get('algorithms')['double']: rate_s = Units().hashrate_str(rate_a) rate_s2 = Units().hashrate_str(rate_b) benchmarks = {algo['algo']: [rate_a, rate_b]} algo1, algo2 = algo['algo'].split("_") mbtc_per_day_values = [ _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']][algo['algo']] ] else: rate_s = Units().hashrate_str(rate_a) benchmarks = {algo['algo']: rate_a} if algo['algo'] in _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']].keys(): mbtc_per_day_values = [ _pool.mbtc_per_day( benchmarks, 'cached')[algo['region']][algo['algo']] ] else: mbtc_per_day_values = [0] if pool != '-': pool = _pool.shortened(region) metrics = device.to_hash() metrics.pop('changed', None) metrics['miner'] = miner metrics['region'] = region metrics['pool'] = pool metrics['time'] = _time metrics['omit_fields'] = omit_fields if metrics['fan']: metrics['fan'] = str(metrics['fan']).rjust(3) + " %" if metrics['miner']: metrics['miner'] = metrics['miner'][0:5] else: metrics['miner'] = '-' if algo == "IDLE": if metrics['gpu_u_i'] and metrics['gpu_u_i'] >= 90: algo = ".pending." algo1 = ".pending." rate_s = ".." mbtc_per_day = mbtc_per_day_values[0] metrics['host'] = 'local' metrics['id'] = device.id metrics[" algo"] = algo1 metrics["rate"] = rate_s metrics[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5) if not metrics['region']: metrics['region'] = '-' total_mbtc += sum(mbtc_per_day_values) if metrics['power_f']: power_values[metrics['id']] = metrics['power_f'] margin = self.calculate_profit_margin_for_card( sum(mbtc_per_day_values), metrics['power_f']) net_mbtc = (mbtc_per_day / 100) * margin if margin < 0: margin = 0 margin_s = "%d%%" % (int(margin)) metrics[" mBTC/day"] += "/" metrics[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5) metrics[" mBTC/day"] += " %s" % (margin_s.rjust(4)) else: margin = 0 if margin > 0: metrics["margin"] = "%.1f%%" % (margin) else: metrics["margin"] = "-" if metrics['limit_f']: power_limit_values[metrics['id']] = metrics['limit_f'] if device.state == 'calibrating': metrics[' algo'] = '*' + metrics[' algo'] elif device.get_pin() and 'algorithm' in device.get_pin().keys( ) and device.get_pin()['algorithm'] == metrics[' algo']: metrics[' algo'] = '+' + metrics[' algo'] elif device.get_pin() and 'algorithm' in device.get_pin().keys( ) and '_' in device.get_pin()['algorithm'] and metrics[ ' algo'] in device.get_pin()['algorithm'].split('_'): metrics[' algo'] = '+' + metrics[' algo'] else: metrics[' algo'] = ' ' + metrics[' algo'] if metrics['gpu_f']: match = re.match("^([\d]+)", metrics['gpu_f']) if match: metrics['gpu_f'] = match.group(1) else: metrics['gpu_f'] = '-' else: metrics['gpu_f'] = '-' if metrics['mem_f']: match = re.match("^([\d]+)", metrics['mem_f']) if match: metrics['mem_f'] = match.group(1) else: metrics['mem_f'] = '-' else: metrics['mem_f'] = '-' metrics['ps clocks'] = "%s %s/%s MHz" % ( metrics['ps'], metrics['gpu_f'], metrics['mem_f']) power = re.match("^([\d]+)", metrics['power']) limit = re.match("^([\d]+)", metrics['limit']) if power and limit: metrics['power'] = "%s/%s W" % (power.group(1), limit.group(1)) else: metrics['power'] = '-' data.append(metrics) if algo not in [ 'IDLE', '.pending.' ] and algo['algo'] in Config().get('algorithms.double'): mbtc_per_day = mbtc_per_day_values[1] metrics2 = metrics.copy() metrics2[" algo"] = algo2 metrics2["rate"] = rate_s2 metrics2[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5) net_mbtc = (mbtc_per_day / 100) * margin metrics2[" mBTC/day"] += "/" metrics2[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5) metrics2[" mBTC/day"] += " %s" % (margin_s.rjust(4)) if device.state == 'calibrating': metrics2[" algo"] = '*' + metrics2[' algo'] elif device.get_pin() and '_' in device.get_pin( )['algorithm'] and metrics2[' algo'] in device.get_pin( )['algorithm'].split('_'): metrics2[" algo"] = '+' + metrics2[' algo'] else: metrics2[" algo"] = ' ' + metrics2[' algo'] data.append(metrics2) total_power = sum(power_values.values()) total_power_limit = sum(power_limit_values.values()) electric_cost_mbtc = self.get_electricity_cost( total_power + Config().get('system_draw_watts'), True, Config().get('electricity_per_kwh')) net_mbtc = total_mbtc - electric_cost_mbtc return [ data, total_mbtc, net_mbtc, total_power, total_power_limit, power_draw_readings, profitability_readings ]