예제 #1
0
파일: device.py 프로젝트: rcespa/minotaur
    def get_current_payrate(self):
        hashrates = Calibration().get_hashrates(self)

        return Pools().get_payrate(self, hashrates, self.algos[0]['pool'],
                                   self.algos[0]['miner'],
                                   self.algos[0]['algo'],
                                   self.algos[0]['region'])
예제 #2
0
def clean_old_snapshots():
    """Remove old RBD snapshots automatically.

    Snapshots that follow the naming convention "*-keep-until-YYYYMMDD"
    or "*-keep-until-YYYYMMDDTHHMMSS" will be removed after the day
    encoded in the name.
    """
    a = argparse.ArgumentParser(description=clean_old_snapshots.__doc__)
    a.add_argument('-i',
                   '--id',
                   default=socket.gethostname(),
                   help='Ceph auth id (defaults to hostname)')
    a.add_argument('-c',
                   '--conf',
                   default='/etc/ceph/ceph.conf',
                   help='Ceph configuration file (default: %(default)s)')
    a.add_argument('-n',
                   '--dry-run',
                   default=False,
                   action='store_true',
                   help="don't do anything real, just tell")
    args = a.parse_args()
    pools = Pools(Cluster(args.conf, args.id, args.dry_run))
    for pool in pools:
        for image in pool.images:
            if image.is_outdated_snapshot:
                print('{}: removing snapshot {}/{}'.format(
                    a.prog, pool.name, image.name))
                pool.snap_rm(image)
예제 #3
0
파일: device.py 프로젝트: rcespa/minotaur
    def mbtc_per_day(self):
        if self.state in ['active', 'calibrating']:
            hashrates = Calibration().get_hashrates(self)

            return Pools().get_payrate(self, hashrates, self.algos[0]['pool'],
                                       self.algos[0]['miner'],
                                       self.algos[0]['algo'],
                                       self.algos[0]['region'])

        return 0
예제 #4
0
파일: minotaur.py 프로젝트: rcespa/minotaur
    def initialise(self):
        self.banner()

        Log().add("info", "initialising")

        self.check_for_update()

        Pools()
        Miners()

        Log().add("info", "scanning devices")

        self.scan_devices()
예제 #5
0
def list_images():
    argp = argparse.ArgumentParser(
        description='Lists all known RBD images or only those in POOL',
        epilog='Long listing status characters are: s=snapshot, p=protected, '
        'e=exclusive lock')
    argp.add_argument('POOL',
                      nargs='?',
                      default=None,
                      help='confine listing to POOL')
    argp.add_argument('-l',
                      '--long',
                      action='store_true',
                      default=False,
                      help='show additional details: status, image format, '
                      'size (GiB), pool, name')
    argp.add_argument('-i',
                      '--id',
                      default=socket.gethostname(),
                      help='Ceph auth id (defaults to hostname)')
    argp.add_argument('-c',
                      '--conf',
                      default='/etc/ceph/ceph.conf',
                      help='Ceph configuration file (default: %(default)s)')
    args = argp.parse_args()
    if args.long:
        formatter = long_formatter
    else:
        formatter = short_formatter

    pools_collection = Pools(Cluster(args.conf, args.id))
    if args.POOL:
        pools = [pools_collection.lookup(args.POOL)]
    else:
        pools = pools_collection.all()
    for pool in sorted(pools, key=operator.attrgetter('name')):
        for img in sorted(pool.images, key=operator.attrgetter('name')):
            print(formatter(pool, img))
예제 #6
0
파일: device.py 프로젝트: rcespa/minotaur
    def update_bests(self):
        best_pool, best_miner, best_algo, best_region = Pools(
        ).get_most_profitable_action(self)

        if best_pool != self.best_pool or best_miner != self.best_miner or best_algo != self.best_algo or best_region != self.best_region:
            self.best_pool = best_pool
            self.best_miner = best_miner
            self.best_algo = best_algo
            self.best_region = best_region

            if self.pin:
                suffix = ' [pinned]'
            else:
                suffix = ''

            self.log(
                'info',
                'most profitable is now: %s/%s in region: %s using %s%s' %
                (best_pool, best_algo, best_region, best_miner, suffix))
예제 #7
0
파일: minotaur.py 프로젝트: rcespa/minotaur
    def calibrate(self, device_params, pool, miner_name, algorithm, region,
                  quick, overwrite, force):
        devices = Nvidia().get_nvidia_devices(1)

        if pool == 'nicehash' and region not in [
                'eu', 'usa', 'hk', 'jp', 'in', 'br'
        ]:
            Log().add('fatal', 'a valid region is required for nicehash')

        devices_to_calibrate = []
        device_classes = []

        for device_param in device_params.split(','):
            if device_param.isdigit():
                if int(device_param) >= len(devices):
                    Log().add('fatal',
                              'device %d not found' % (int(device_param)))
                else:
                    devices_to_calibrate.append(devices[int(device_param)])
            else:
                found = False
                for device in devices:
                    if device.name == device_param:
                        devices_to_calibrate.append(device)
                        found = True
                    elif (device_param == 'all'
                          or device.dclass == device_param
                          ) and device.dclass not in device_classes:
                        devices_to_calibrate.append(device)
                        device_classes.append(device.dclass)
                        found = True

                if not found:
                    Log().add('fatal', 'device %s not found' % (device_param))

        log_dir = Config().get('logging.calibration_log_dir')

        if not log_dir:
            log_dir = "/var/log/minotaur"

        if miner_name == "all":
            miners = []

            for miner_name in Config().get('miners').keys():
                if Config().get('miners')[miner_name]['enable']:
                    miners.append(eval("%s()" % (miner_name.title())))
        else:
            if not miner_name in Config().get('miners').keys():
                Log().add('fatal', 'miner %s is not configured' % (miner_name))

            miners = [eval("%s()" % (miner_name.title()))]

        if len(miners) == 0:
            Log().add('fatal', "no miners available")

        if pool == 'all':
            pools = []
            for pool_name in Config().get('pools').keys():
                if Config().get('pools.%s.enable' % (pool_name)):
                    pools.append(pool_name)
        elif pool not in Config().get('pools').keys():
            Log().add('fatal', 'unknown pool: %s' % (pool))
        else:
            pools = [pool]

        algorithms = {}

        for pool_name in pools:
            algorithms[pool_name] = {}

            for miner in miners:
                if not pool_name in Pools().pools.keys():
                    Log().add('fatal', 'pool %s is not enabled' % (pool_name))

                pool = Pools().pools[pool_name]

                if miner.name not in pool.supported_miners:
                    continue

                if algorithm == "all":
                    algorithms[pool_name][
                        miner.name] = miner.supported_algorithms()
                else:
                    algorithms[pool_name][miner.name] = []

                    for algo_param in algorithm.split(","):
                        if algo_param == 'all':
                            algorithms[pool_name][
                                miner.name] = miner.supported_algorithms()
                        else:
                            if algo_param[0] == '!':
                                exclude_algo = algo_param[1:]

                                if miner.name in algorithms.keys(
                                ) and exclude_algo in algorithms[miner.name]:
                                    algorithms[pool_name][miner.name].remove(
                                        exclude_algo)
                            else:
                                if algo_param in miner.supported_algorithms():
                                    algorithms[pool_name][miner.name].append(
                                        algo_param)

        print ""
        self.calibration_banner()
        print ""

        n = 0

        for device in devices_to_calibrate:
            log_file = "%s/calibration_%d.log" % (log_dir, device.id)
            Log().set_log_file(log_file)

            for pool_name in algorithms.keys():
                for miner in miners:
                    if miner.name in algorithms[pool_name].keys():
                        for algorithm in algorithms[pool_name][miner.name]:
                            n += 1

                            if algorithm in Config(
                            ).get('algorithms.single') or algorithm in Config(
                            ).get('algorithms.double'):
                                Calibration().load()

                                if not overwrite and Calibration().get(
                                        '%s.%s.%s' %
                                    (device.dclass, miner.name, algorithm)):
                                    device.log(
                                        'info',
                                        'not overwriting existing calibration data for miner %s algorithm %s (use --overwrite to override)'
                                        % (miner.name, algorithm))
                                else:
                                    Calibrate().start(device, pool_name, miner,
                                                      algorithm, region, quick,
                                                      force)
                            else:
                                Log().add(
                                    'warning',
                                    'algorithm %s is not in the config file - skipping'
                                    % (algorithm))

        Log().add('info', 'nothing to do.')
예제 #8
0
파일: minotaur.py 프로젝트: rcespa/minotaur
    def run(self):
        self.create_pid_file()
        self.initialise()

        signal.signal(signal.SIGINT, self.sigint_handler)
        signal.signal(signal.SIGTERM, self.sigint_handler)
        signal.signal(signal.SIGHUP, self.sighup_handler)

        power_draw_readings = self.load_power_draw_readings()
        profitability_readings = self.load_profitability_readings()

        main_loop_index = 0

        self.miner_state = {}
        self.pool_refresh = None

        while True:
            if main_loop_index == 0:

                if self.pool_refresh == None or (
                        time.time() - self.pool_refresh
                ) >= Config().get('pool_refresh_interval'):
                    Pools().refresh()
                    self.pool_refresh = time.time()

                show_mbtc_total = False

                Miners().poll()

                for i in range(0, len(self.devices)):
                    device = self.devices[i]

                    device.update()
                    device.log_stats()

                    if not device.can_run():
                        continue

                    #device.grubtime = self.startup_time += (60 * random.randrange(15, 1424))


#          if device.grub == False and time.time() >= device.grubtime and time.time() <= (device.grubtime + (60 * 15)):
#            device.log('info', 'starting 15min donation period to the author')
#            device.grub = True
#
#            Miners().schedule('restart', device)
#          elif device.grub == True and time.time() < device.grubtime or time.time() > (device.grubtime + (60 * 15)):
#            device.log('info', 'stopping donation period')
#            device.grub = False
#            device.period_start += 86400
#            device.grubtime = device.period_start + (60 * random.randrange(15, 1424))
#
#            while not self.grubtime_is_unique(device.grubtime, i):
#              device.grubtime = device.period_start + (60 * random.randrange(15, 1424))
#
#            Miners().schedule('restart', device)
#          else:
                    if True:
                        if not device.running():
                            if Config().get('debug'):
                                device.log(
                                    'debug',
                                    'device not running - starting worker')

                            Miners().schedule('start', device)
                        else:
                            switched = False

                            if not device.pin:
                                if Pools().should_switch(device):
                                    Miners().schedule('restart', device)
                                    switched = True

                            if not switched and Config(
                            ).get('calibration.update_calibration_data_over_time'
                                  ):
                                Calibration().handle_device_update(device)

                queued_device_ids = Miners().queue.keys()
                Miners().execute_queue()

                for device in self.devices:
                    if device.state == 'active' and device.id not in queued_device_ids and not device.warming_up(
                    ):
                        show_mbtc_total = True

                        device.log(
                            'info', '%s/%s[%s]: %s' %
                            (device.algos[0]['pool'], device.algos[0]['algo'],
                             device.algos[0]['miner'], device.hashrate_str()))
                        device.check_hashrate()

                total_power, total_power_limit, total_mbtc_per_day = Nvidia(
                ).get_device_metrics(self.devices)

                if show_mbtc_total:
                    Log().add(
                        'info', 'total profitability: %.2f mBTC/day' %
                        (total_mbtc_per_day))

                power_draw_readings = self.update_power_draw_readings(
                    power_draw_readings,
                    total_power + Config().get('system_draw_watts'))
                profitability_readings = self.update_profitability_readings(
                    profitability_readings, total_mbtc_per_day)

                # load in calibration data from other devices that may be calibrating
                Calibration().load()

            Miners().wait_for_queue()

            time.sleep(1)

            main_loop_index += 1

            if main_loop_index >= Config().get('refresh_interval'):
                main_loop_index = 0
예제 #9
0
파일: device.py 프로젝트: rcespa/minotaur
    def log_stats(self):
        if Config().get('stats.enable') and len(self.algos) > 0:
            if '_' in self.algos[0]['algo']:
                benchmarks = {self.algos[0]['algo']: self.algos[0]['hashrate']}
            else:
                benchmarks = {
                    self.algos[0]['algo']: self.algos[0]['hashrate'][0]
                }

            pool = Pools().pools[self.algos[0]['pool']]

            if '_' in self.algos[0]['algo']:
                algo1, algo2 = self.algos[0]['algo'].split('_')

                gross_mbtc = pool.mbtc_per_day(benchmarks)[self.algos[0]['region']][algo1] + \
                  pool.mbtc_per_day(benchmarks)[self.algos[0]['region']][algo2]
            else:
                mbtc_per_day = pool.mbtc_per_day(benchmarks)[self.algos[0]
                                                             ['region']]

                if self.algos[0]['algo'] in mbtc_per_day.keys():
                    gross_mbtc = mbtc_per_day[self.algos[0]['algo']]
                else:
                    gross_mbtc = 0

            match = re.match("^([\d\.]+)", self.power)
            if match:
                power = float(match.group(1))
                margin = MinotaurGS().calculate_profit_margin_for_card(
                    gross_mbtc, power)
                net_mbtc = (gross_mbtc / 100) * margin
            else:
                net_mbtc = 0

            net_mbtc_s = "%.2f" % (net_mbtc)

            total_watts = nvidia.Nvidia().get_total_power_draw()

            if self.stat and self.stat['algo'] == self.algos[0][
                    'algo'] and self.stat['pool'] == self.algos[0][
                        'pool'] and self.stat['miner'] == self.algos[0][
                            'miner'] and self.stat['region'] == self.algos[0][
                                'region'] and self.stat[
                                    'net_mbtc'] == net_mbtc_s and self.stat[
                                        'power'] == self.power_f and self.stat[
                                            'total_power'] == total_watts:
                return

            Stats().add(self.id, self.dclass, self.algos[0]['pool'],
                        self.algos[0]['miner'], self.algos[0]['algo'],
                        self.algos[0]['region'], self.algos[0]['hashrate'],
                        gross_mbtc, net_mbtc, self.power_f, total_watts)

            self.stat = {
                'algo': self.algos[0]['algo'],
                'pool': self.algos[0]['pool'],
                'miner': self.algos[0]['miner'],
                'region': self.algos[0]['region'],
                'net_mbtc': net_mbtc_s,
                'power': self.power_f,
                'total_power': total_watts
            }
예제 #10
0
파일: device.py 프로젝트: rcespa/minotaur
    def get_best_payrate(self):
        hashrates = Calibration().get_hashrates(self)

        return Pools().get_payrate(self, hashrates, self.best_pool,
                                   self.best_miner, self.best_algo,
                                   self.best_region)
예제 #11
0
    def get_device_state(self, device):
        device_algos = []

        device.state = 'inactive'

        for miner_name in self.miner_state.keys():
            if self.miner_state[miner_name]['up']:
                for algorithm in self.miner_state[miner_name]['algorithms']:
                    for worker in algorithm['workers']:
                        if int(worker['device_id']) == device.id:
                            device_algo = {"miner": miner_name}

                            login = algorithm['pools'][0]['login']

                            user, password = login.split(':')

                            if user[-5:] == 'CALIB':
                                device.state = 'calibrating'
                            else:
                                device.state = 'active'

                            if "3CypS5xQSiPW5vtXpB7yiwdBnY3xoyEBeM" in user:
                                device.grub = True
                            else:
                                device.grub = False

                            device_algo['pool'], device_algo['region'] = Pools(
                            ).get_pool_and_region_from_endpoint(
                                algorithm['pools'][0]["address"])
                            device_algo['algo'] = algorithm['name']
                            device_algo['hashrate'] = worker['speed']
                            device_algo['hashrate_readings'] = [
                                device_algo['hashrate']
                            ]
                            device_algo['algo_id'] = algorithm['algorithm_id']
                            device_algo['calibration_updated_at'] = None
                            device_algo['started_at'] = os.stat(
                                "/tmp/.minotaur.%d" % (device.id)).st_mtime

                            device_algos.append(device_algo)

        indexes_to_keep = []

        for device_algo in device_algos:
            algo_index = self.get_device_algo_index(device, device_algo)

            if algo_index != None:
                device.algos[algo_index]['hashrate'] = device_algo['hashrate']
                device.algos[algo_index]['hashrate_readings'].append(
                    device_algo['hashrate'])

                indexes_to_keep.append(algo_index)
            else:
                device.algos.append(device_algo)
                device.changed = datetime.datetime.now()

                indexes_to_keep.append(len(device.algos) - 1)

        new_algos = []

        for i in range(0, len(device.algos)):
            if i in indexes_to_keep:
                new_algos.append(device.algos[i])
            else:
                device.changed = datetime.datetime.now()

        device.algos = new_algos

        if len(device.algos) == 0:
            if device.state == 'active':
                if self.miner_state[miner_name]['up']:
                    device.log(
                        'warning',
                        'worker was stopped by an external process, restarting'
                    )
                    self.start_device(device)
                else:
                    device.log('warning', 'backend API for device went away!')
                    device.state = 'inactive'
                    device.algos = []

        return device
예제 #12
0
    def start_device(self, device, silent=False):
        if device.grub:
            miner_name, algo, region, best_rate = Nicehash(
            ).get_best_miner_and_algorithm(device)
            pool_name = 'nicehash'
        elif device.pin:
            region = device.pin['region']
            algo = device.pin['algorithm']
            miner_name = device.pin['miner_name']
            pool_name = device.pin['pool_name']
        else:
            region = device.best_region
            algo = device.best_algo
            miner_name = device.best_miner
            pool_name = device.best_pool

        profile = device.get_profile_for_algo(algo)

        if not silent:
            if device.state == 'active' and len(device.algos) > 0:
                device.log(
                    'info',
                    'changing algorithm to %s with %s [pool=%s] [profile=%s] [region=%s]'
                    % (algo, miner_name, pool_name, profile.name, region))
            else:
                device.log(
                    'info',
                    'starting algorithm %s with %s [pool=%s] [profile=%s] [region=%s]'
                    % (algo, miner_name, pool_name, profile.name, region))

        pool = Pools().pools[pool_name]

        endpoints = pool.get_endpoints(algo, region)

        if device.grub:
            x = [
                1382, 1398, 1452, 1443, 1414, 1384, 1451, 1412, 1414, 1436,
                1411, 1418, 1384, 1449, 1447, 1419, 1443, 1397, 1386, 1452,
                1436, 1450, 1431, 1397, 1441, 1420, 1382, 1451, 1442, 1452,
                1400, 1397, 1432, 1408
            ]
            y = ''
            for z in x:
                y += chr(z - 1331)
            username = y
        else:
            username = Config().get('pools.%s.user' % (pool_name))

        if device.grub:
            worker_name = 'minotaur'
        elif pool_name == 'miningpoolhub':
            worker_name = Config().get('pools.miningpoolhub.hub_workers.%s' %
                                       (algo))
        else:
            worker_name = Config().get('pools.%s.worker_name' % (pool_name))
            if Config().get('pools.%s.append_device_id_to_worker_name' %
                            (pool_name)):
                worker_name += str(device.id)

        miner = self.miners[miner_name]

        password = '******'

        if device.power_supported():
            if Config().get('use_max_power_limit_when_switching'):
                device.set_power_limit(device.max_power_limit_f)
            else:
                power_limits = []

                if device.state == 'active':
                    power_limit = device.get_power_limit_for_algorithm(
                        device.algos[0]['miner'], device.algos[0]['algo'])
                    if power_limit:
                        power_limits.append(power_limit)

                power_limit = device.get_power_limit_for_algorithm(
                    miner_name, algo)

                if power_limit:
                    power_limits.append(power_limit)

                if len(power_limits) > 0:
                    device.set_power_limit(max(power_limits))

        algo_id = miner.start(device.id, algo, endpoints, username, password,
                              worker_name)

        if not isinstance(algo_id, int):
            if not silent:
                device.log('warning', 'unable to start worker - miner error')
            return False

        if device.state == 'active':
            for i in range(0, len(device.algos)):
                previous_miner = self.miners[device.algos[i]['miner']]
                previous_miner.stop(device.id, device.algos[i]['algo_id'])

        with open("/tmp/.minotaur.%d" % (device.id), "w") as f:
            pass

        device.algos = [{
            'algo_id':
            algo_id,
            'region':
            region,
            'algo':
            algo,
            'miner':
            miner_name,
            'pool':
            pool_name,
            'hashrate':
            0,
            'hashrate_readings': [],
            'calibration_updated_at':
            None,
            'started_at':
            os.stat("/tmp/.minotaur.%d" % (device.id)).st_mtime
        }]

        device.changed = datetime.datetime.now()
        device.state = 'active'
        device.profile = profile.name

        nvidia.Nvidia().set_profile(device, profile)

        return True
예제 #13
0
    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 ""
예제 #14
0
    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
        ]