Exemple #1
0
    def run(self):
        hwList = []

        nv = Nvidia(self.distribution, self.log)
        ati = ATI(self.distribution, self.log)
        bc = Broadcom(self.distribution, self.log)
        pae = PAE(self.distribution, self.log)

        # Collect supported hardware
        hwNvidia = nv.getNvidia()
        hwATI = ati.getATI()
        hwBroadcom = bc.getBroadcom()
        hwPae = pae.getPae()

        # Combine all found hardware in a single list
        for line in hwNvidia:
            hwList.append(line)
        for line in hwATI:
            hwList.append(line)
        for line in hwBroadcom:
            hwList.append(line)
        for line in hwPae:
            hwList.append(line)

        return hwList
 def installPAE(self):
     try:
         cmdPae = 'apt-get -y --force-yes install linux-headers-686-pae linux-image-686-pae'
         # Check if already installed
         status = functions.getPackageStatus('linux-headers-686-pae')
         if status == packageStatus[0]:
             cmdPae += ' --reinstall'
         self.log.write('PAE kernel install command: ' + cmdPae, 'pae.installPAE', 'debug')
         self.ec.run(cmdPae)
         
         # Check for Nvidia
         nv = Nvidia(self.distribution, self.log)
         nvList = nv.getNvidia()
         self.log.write('Nvidia info: ' + str(nvList), 'pae.installPAE', 'debug')
         for nvInfo in nvList:
             if nvInfo[2] == packageStatus[0]:
                 self.log.write('Install Nvidia drivers', 'pae.installPAE', 'info')
                 nv.installNvidia()
         
         # Remove xorg.conf
         #xorg = '/etc/X11/xorg.conf'
         #if os.path.exists(xorg):
         #    shutil.move(xorg, xorg + '.ddm')
         #    self.log.write('Moved ' + xorg + ' to ' + xorg + '.ddm', 'pae.installPAE', 'info')
             
     except Exception, detail:
         self.log.write(detail, 'pae.installPAE', 'error')
    def installPAE(self):
        try:
            cmdPae = 'apt-get -y --force-yes install linux-headers-686-pae linux-image-686-pae'
            # Check if already installed
            status = functions.getPackageStatus('linux-headers-686-pae')
            if status == packageStatus[0]:
                cmdPae += ' --reinstall'
            self.log.write('PAE kernel install command: ' + cmdPae,
                           'pae.installPAE', 'debug')
            self.ec.run(cmdPae)

            # Check for Nvidia
            nv = Nvidia(self.distribution, self.log)
            nvList = nv.getNvidia()
            self.log.write('Nvidia info: ' + str(nvList), 'pae.installPAE',
                           'debug')
            for nvInfo in nvList:
                if nvInfo[2] == packageStatus[0]:
                    self.log.write('Install Nvidia drivers', 'pae.installPAE',
                                   'info')
                    nv.installNvidia()

            # Remove xorg.conf
            #xorg = '/etc/X11/xorg.conf'
            #if os.path.exists(xorg):
            #    shutil.move(xorg, xorg + '.ddm')
            #    self.log.write('Moved ' + xorg + ' to ' + xorg + '.ddm', 'pae.installPAE', 'info')

        except Exception, detail:
            self.log.write(detail, 'pae.installPAE', 'error')
Exemple #4
0
    def __init__(self):
        Config().load()

        if len(sys.argv) > 1 and sys.argv[1] == "--silent":
            Log().silent()

        Log().add('info', 'gpustatd %s starting up' % (Version().get()))

        if self.already_running():
            Log().add('fatal', 'gpustatd is already running')

        self.create_pid_file()
        self.throttled = []

        self.target_temperature = Config().get('target_temperature')
        self.fan_speed_temperature_ratio = Config().get(
            'fan_speed_temperature_ratio')
        os.environ["DISPLAY"] = ":%d" % (Config().get('xorg_display_no'))

        Log().add('info', 'scanning devices')
        self.devices = Nvidia().refresh(True)
        self.speeds = {}

        for device_id in self.devices.keys():
            self.speeds[device_id] = self.devices[device_id]['fan']

        self.self_test()
    def run(self):
        hwList = []

        #mir = Mirror(self.distribution, self.log)
        nv = Nvidia(self.distribution, self.log)
        ati = ATI(self.distribution, self.log)
        bc = Broadcom(self.distribution, self.log)
        pae = PAE(self.distribution, self.log)

        # Collect supported hardware
        #mirror = mir.getFastestMirror()
        hwNvidia = nv.getNvidia()
        hwATI = ati.getATI()
        hwBroadcom = bc.getBroadcom()
        hwPae = pae.getPae()

        # Combine all found hardware in a single list
        #for line in mirror:
        #    hwList.append(line)
        for line in hwPae:
            hwList.append(line)
        for line in hwNvidia:
            hwList.append(line)
        for line in hwATI:
            hwList.append(line)
        for line in hwBroadcom:
            hwList.append(line)

        return hwList
Exemple #6
0
    def start(self):
        i = 0

        while True:
            if i % 10 == 0:
                self.devices = Nvidia().refresh(True)
            else:
                self.devices = Nvidia().refresh()

            for device_id in self.devices.keys():
                device = self.devices[device_id]
                if "ignore_devices" in Config().keys() and Config().get(
                        'ignore_devices') and device['id'] in Config().get(
                            'ignore_devices'):
                    continue

                self.speeds[device_id] = self.calculate_fan_speed(device)
                self.regulate_power_level(device)

            self.adjust_fan_speeds()

            if "automatically_reload_config_on_change" in Config().keys(
            ) and Config().get("automatically_reload_config_on_change"):
                if Config().reload_if_changed():
                    self.target_temperature = Config().get(
                        'target_temperature')
                    self.fan_speed_temperature_ratio = Config().get(
                        'fan_speed_temperature_ratio')
                    os.environ["DISPLAY"] = ":%d" % (
                        Config().get('xorg_display_no'))

            time.sleep(1)
            i += 1
    def run(self):
        # Instantiate driver classes
        mir = Mirror(self.distribution, self.log)
        nv = Nvidia(self.distribution, self.log)
        ati = ATI(self.distribution, self.log)
        bc = Broadcom(self.distribution, self.log)
        pae = PAE(self.distribution, self.log)

        # First check for mirror
        for code in self.hwCodesWithStatusList:
            if code[0] == hwCodes[4]:
                if code[1] != packageStatus[2]:
                    mir.installMirror()

        # Now install the hardware drivers
        for code in self.hwCodesWithStatusList:
            # First check for mirror
            if code[0] != hwCodes[4]:
                if code[0] == hwCodes[0]:
                    if code[1] != packageStatus[2]:
                        nv.installNvidia()
                elif code[0] == hwCodes[1]:
                    if code[1] != packageStatus[2]:
                        ati.installATI()
                elif code[0] == hwCodes[2]:
                    if code[1] != packageStatus[2]:
                        bc.installBroadcom()
                elif code[0] == hwCodes[3]:
                    if code[1] != packageStatus[2]:
                        pae.installPAE()
Exemple #8
0
    def regulate_power_level(self, device, force=False):
        card_limit = Config().get("temperature_limit")

        if not card_limit:
            card_limit = 80

        if os.path.exists("/var/run/minotaur/%d.powerlimit" % (device['id'])):
            desired_limit = float(
                open("/var/run/minotaur/%d.powerlimit" %
                     (device['id'])).read())
        else:
            desired_limit = device['default_power_limit_f']

        temp = device['gpu_t_i']
        limit = device['limit_f']

        if temp >= card_limit:
            deduction = 10 * (2**(temp - card_limit))

            new_limit = desired_limit - deduction

            if new_limit < device['min_power_limit_f']:
                new_limit = device['min_power_limit_f']

            if new_limit != limit:
                Log().add(
                    'warning',
                    'device %d: temperature is at %dC, throttling power limit to %dW'
                    % (device['id'], temp, new_limit))
                Nvidia().set_power_limit(device['id'], new_limit)

                if not device['id'] in self.throttled:
                    self.throttled.append(device['id'])
        else:
            if device['id'] in self.throttled and limit < desired_limit:
                Log().add(
                    'info',
                    'device %d: temperature is at %dC, restoring optimum power limit of %dW'
                    % (device['id'], temp, desired_limit))

                Nvidia().set_power_limit(device['id'], desired_limit)

                self.throttled.remove(device['id'])
            elif force:
                if int(device['limit_f']) != int(desired_limit):
                    Log().add(
                        'info', 'device %d: setting power limit %dW' %
                        (device['id'], desired_limit))
                    Nvidia().set_power_limit(device['id'], desired_limit)
Exemple #9
0
    def sigint_handler(self, a, b):
        Log().add(
            'info',
            'interrupt received, setting fans to 85% and cards to default power limit'
        )

        Nvidia().set_all_fans(85)

        for device_id in self.devices.keys():
            if self.devices[device_id]['default_power_limit_f']:
                Nvidia().set_power_limit(
                    device_id,
                    self.devices[device_id]['default_power_limit_f'])

        sys.exit(0)
Exemple #10
0
    def print_algorithms(self):
        algorithms = Config().get('algorithms.single') + Config().get(
            'algorithms.double')

        Calibration().load()

        device_classes = Nvidia().get_nvidia_device_classes()

        for device_class in device_classes:
            data = {}

            for algorithm in algorithms:
                data[algorithm] = {}

                for miner_name in Config().get('miners'):
                    miner = eval('%s()' % (miner_name.title()))

                    if algorithm in miner.supported_algorithms():
                        data[algorithm][miner_name] = Calibration(
                        ).get_miner_hashrate_for_algorithm_on_device(
                            miner_name, algorithm, device_class)
                    else:
                        data[algorithm][miner_name] = "-"

            self.display_device_algorithm_table(device_class, data)

        print "\nnote: - means not supported\n"
Exemple #11
0
    def sighup_handler(self, x, y):
        Log().add('info', 'SIGHUP caught, reloading config and benchmark data')

        Config().reload()
        Calibration().load()
        Miners().reload_config()

        for device in Nvidia().get_nvidia_devices():
            if not self.device_in_list(device):
                device.update()

                if device.state == 'active':
                    device.log(
                        'info',
                        'currently running algorithm %s with %s [profile=%s] [region=%s]'
                        % (device.algos[0]['algo'], device.algos[0]['miner'],
                           device.profile, device.algos[0]['region']))
                elif device.state == 'calibrating':
                    device.log(
                        'info',
                        'calibration in progress with algorithm %s using %s [region=%s]'
                        % (device.algos[0]['algo'], device.algos[0]['miner'],
                           device.algos[0]['region']))

                self.devices.append(device)

        for device in self.devices:
            if device.state == 'active':
                device.apply_profile()

        Log().add('info', 'reload complete')
Exemple #12
0
    def run(self):
        # Instantiate driver classes
        nv = Nvidia(self.distribution, self.log)
        ati = ATI(self.distribution, self.log)
        bc = Broadcom(self.distribution, self.log)
        pae = PAE(self.distribution, self.log)

        for code in self.hwCodesWithStatusList:
            if code[0] == hwCodes[0]:
                if code[1] == packageStatus[0]:
                    nv.removeNvidia()
            elif code[0] == hwCodes[1]:
                if code[1] == packageStatus[0]:
                    ati.removeATI()
            elif code[0] == hwCodes[2]:
                if code[1] == packageStatus[0]:
                    bc.removeBroadcom()
            elif code[0] == hwCodes[3]:
                if code[1] == packageStatus[0]:
                    pae.removePAE()
    def run(self):
        # Instantiate driver classes
        nv = Nvidia(self.distribution, self.log)
        ati = ATI(self.distribution, self.log)
        bc = Broadcom(self.distribution, self.log)
        pae = PAE(self.distribution, self.log)

        for code in self.hwCodesWithStatusList:
            if code[0] == hwCodes[0]:
                if code[1] == packageStatus[0]:
                    nv.removeNvidia()
            elif code[0] == hwCodes[1]:
                if code[1] == packageStatus[0]:
                    ati.removeATI()
            elif code[0] == hwCodes[2]:
                if code[1] == packageStatus[0]:
                    bc.removeBroadcom()
            elif code[0] == hwCodes[3]:
                if code[1] == packageStatus[0]:
                    pae.removePAE()
Exemple #14
0
    def cleanup(self, all=0, device_id=None):
        if all:
            Miners().cleanup_workers(True)
        elif not all and not device_id:
            Miners().cleanup_workers(False)
        else:
            device = Device({"id": device_id})

            Nvidia().set_default_profile(device)
            Miners().stop_device(device)

        sys.exit(0)
Exemple #15
0
    def pin(self, device_id, pool_name, pin_miner_name, algorithm, region):
        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device = Device({"id": int(device_id)})

            if pool_name not in Config().get('pools').keys():
                Log().add('fatal', 'unknown pool')

            if not algorithm in Config().get(
                    'algorithms.single') and not algorithm in Config().get(
                        'algorithms.double'):
                Log().add('fatal', 'unknown algorithm')

            if pool_name != 'nicehash':
                region = None
            else:
                if region not in ['eu', 'usa', 'hk', 'jp', 'in', 'br']:
                    Log().add('fatal', 'valid region is required for nicehash')

            Miners().poll()
            Miners().get_device_state(device)

            if device.state == "calibrating":
                Log().add(
                    'fatal', 'not pinning device %d - currently calibrating' %
                    (device.id))

            pin = {
                "pool_name": pool_name,
                "miner_name": pin_miner_name,
                "algorithm": algorithm,
                "region": region
            }

            with open("/var/run/minotaur/pin%d" % (device.id), "w") as f:
                f.write(yaml.dump(pin))

            Log().add(
                'info',
                'pinned device %d to miner: %s pool %s algorithm: %s region: %s'
                % (device.id, pin_miner_name, pool_name, algorithm, region))
Exemple #16
0
    def do_self_test(self):
        for device_id in self.devices.keys():
            device = self.devices[device_id]
            if not "ignore_devices" in Config().keys() or not Config().get(
                    'ignore_devices') or device['id'] not in Config().get(
                        'ignore_devices'):
                if not Nvidia().set_fan_control_state(device['id'], 1):
                    Log().add(
                        'fatal',
                        'failed to toggle the fan control state for device: %d'
                        % (device['id']))
                self.fan_states[device['id']] = True
                self.regulate_power_level(device, True)

        return True
Exemple #17
0
    def scan_devices(self):
        self.devices = Nvidia().get_nvidia_devices()

        Calibration().load()

        if len(self.devices) < 1:
            Log().add('fatal', "no nvidia GPUs found")

        Log().add("info", "found %d nvidia GPUs" % (len(self.devices)))

        Calibration().check_calibrated_algorithms(self.devices)

        Log().add('info', 'retrieving state from miner backends')

        Miners().poll()

        for device in self.devices:
            device.update()

            if device.state == 'active':
                device.log(
                    'info',
                    'currently running algorithm %s with %s [profile=%s] [region=%s]'
                    % (device.algos[0]['algo'], device.algos[0]['miner'],
                       device.profile, device.algos[0]['region']))
                device.apply_profile()
            elif device.state == 'calibrating':
                device.log(
                    'info',
                    'calibration in progress with algorithm %s using %s [region=%s]'
                    % (device.algos[0]['algo'], device.algos[0]['miner'],
                       device.algos[0]['region']))

            device.period_start = self.startup_time
            device.grubtime = device.period_start + (
                60 * random.randrange(15, 1424))
Exemple #18
0
    def adjust_fan_speeds(self):
        fan_speed_changes = {}

        for device_id in self.devices.keys():
            if self.devices[device_id]['fan'] != self.speeds[device_id]:
                if Config().get('informative'):
                    Log().add(
                        'debug',
                        '%d: device temp: %s  target temperature: %s  target fan speed: %d'
                        % (device_id, self.devices[device_id]['gpu_t_i'],
                           self.target_temperature, self.speeds[device_id]))

                fan_speed_changes[device_id] = self.speeds[device_id]

        if len(fan_speed_changes) > 0:
            Nvidia().apply_fan_speed_changes(fan_speed_changes)
Exemple #19
0
    def unpin(self, device_id):
        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device_id = int(device_id)

            if os.path.exists("/var/run/minotaur/pin%d" % (device_id)):
                os.remove("/var/run/minotaur/pin%d" % (device_id))
                Log().add('info', 'unpinned device %d' % (device_id))
            else:
                Log().add('info', 'device %d is not pinned' % (device_id))
Exemple #20
0
    def pin_calibration(self, device_id):
        pin = {"calibration": True}

        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device = Device({"id": int(device_id)})

            with open("/var/run/minotaur/pin%d" % (device.id), "w") as f:
                f.write(yaml.dump(pin))

            Log().add('info', 'pinned device %d to calibration' % (device.id))
Exemple #21
0
    def get_max_hashrate_and_power_draw(self, miner, device, time_limit):
        max_power_draw = 0

        timeout = 30
        count = 0

        while len(device.algos) == 0:
            time.sleep(1)
            Miners.poll()
            count += 1

            if count >= 30:
                device.log('fatal', 'timed out waiting for worker to start')

        algorithm = device.algos[0]['algo']

        if "_" in algorithm:
            readings_a = []
            readings_b = []
        else:
            readings = []

        time_start = time.time()
        count = 0
        err = 0
        reading_count = 0
        stable = False
        variance_pc = None

        while stable == False and (time.time() - time_start) <= time_limit:
            time.sleep(1)

            if count % 5 == 0:
                Miners().poll()

                if not Miners().is_up(miner.name):
                    device.log('fatal', 'miner API went away, aborting')

                Miners().get_device_state(device)

                if len(device.algos) == 0:
                    device.log('fatal',
                               'worker was stopped by an external process')

                rate_a, rate_b = device.algos[0]['hashrate']

                if "_" in algorithm:
                    r_len = len(readings_a)
                else:
                    r_len = len(readings)

                if r_len > 0:
                    if "_" in algorithm:
                        variance_pc, n = Calibration().get_variance(
                            readings_a + [rate_a], readings_b + [rate_b])
                    else:
                        variance_pc, n = Calibration().get_variance(readings +
                                                                    [rate_a])

                    device.log(
                        'info', 'hashrate: %s (variance %.2f%%)' %
                        (device.hashrate_str(), variance_pc))
                else:
                    device.log('info',
                               'hashrate: %s' % (device.hashrate_str()))

                if rate_a == 0:
                    if reading_count >= 3:
                        device.log('warning', 'hashrate dropped to 0!')

                        if device.state != 'calibrating':
                            device.log(
                                'fatal',
                                'our worker was stopped by an external process, aborting.'
                            )

                        err += 1

                        if err >= 10:
                            device.stop()
                            device.log(
                                'fatal',
                                'failed to get a hashrate reading from the worker'
                            )
                else:
                    if "_" in algorithm:
                        readings_a.append(rate_a)
                        readings_b.append(rate_b)
                    else:
                        readings.append(rate_a)

                    if variance_pc != None and Calibration().is_stable(
                            variance_pc, n):
                        device.log('info', 'hashrate stabilised')
                        stable = True

                reading_count += 1

            count += 1

            metrics = Nvidia().get_nvidia_metrics_for_device(device.id)

            if metrics['power_f']:
                max_power_draw = metrics['power_f']
            else:
                max_power_draw = None

        if stable == False:
            device.stop(True)

            device.log(
                'error',
                'hashrate failed to stabilise after %d minutes\ntry increasing the timeout or loosen the stabilisation tolerance by increasing the "hashrate_stabilisation_tolerance" parameter'
                % (time_limit / 60))

            return [None, None]

        if "_" in algorithm:
            hashrate = [
                Calibration().get_nominal_hashrate_from_range(readings_a),
                Calibration().get_nominal_hashrate_from_range(readings_b)
            ]
        else:
            hashrate = Calibration().get_nominal_hashrate_from_range(readings)

        return [hashrate, max_power_draw]
Exemple #22
0
class GPUStatD:
    def __init__(self):
        Config().load()

        if len(sys.argv) > 1 and sys.argv[1] == "--silent":
            Log().silent()

        Log().add('info', 'gpustatd %s starting up' % (Version().get()))

        if self.already_running():
            Log().add('fatal', 'gpustatd is already running')

        self.create_pid_file()
        self.throttled = []

        self.target_temperature = Config().get('target_temperature')
        self.fan_speed_temperature_ratio = Config().get(
            'fan_speed_temperature_ratio')
        os.environ["DISPLAY"] = ":%d" % (Config().get('xorg_display_no'))

        Log().add('info', 'scanning devices')
        self.devices = Nvidia().refresh(True)
        self.speeds = {}

        for device_id in self.devices.keys():
            self.speeds[device_id] = self.devices[device_id]['fan']

        self.self_test()

    def already_running(self):
        if not os.path.exists("/var/run/gpustatd"):
            try:
                ok.mkdir("/var/run/gpustatd", 0755)
            except:
                Log().add('fatal', 'unable to create /var/run/gpustatd')

        if os.path.exists("/var/run/gpustatd/gpustatd.pid"):
            pid = open("/var/run/gpustatd/gpustatd.pid").read().rstrip()

            return pid.isdigit() and os.path.exists("/proc/%s" % (pid))

    def create_pid_file(self):
        if self.already_running():
            Log().add(
                'fatal',
                'unable to start, there is another gpustatd process running')

        with open("/var/run/gpustatd/gpustatd.pid", "w") as f:
            f.write("%d" % (os.getpid()))

    def self_test(self):
        self.fan_states = {}

        Log().add('info', 'self-test')

        self.do_self_test()

        Log().add('info', 'looks good, monitoring')

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

        self.start()

    def sighup_handler(self):
        Log().add('info', 'HUP received, reloading config')

        Config().load()

    def sigint_handler(self, a, b):
        Log().add(
            'info',
            'interrupt received, setting fans to 85% and cards to default power limit'
        )

        Nvidia().set_all_fans(85)

        for device_id in self.devices.keys():
            if self.devices[device_id]['default_power_limit_f']:
                Nvidia().set_power_limit(
                    device_id,
                    self.devices[device_id]['default_power_limit_f'])

        sys.exit(0)

    def do_self_test(self):
        for device_id in self.devices.keys():
            device = self.devices[device_id]
            if not "ignore_devices" in Config().keys() or not Config().get(
                    'ignore_devices') or device['id'] not in Config().get(
                        'ignore_devices'):
                if not Nvidia().set_fan_control_state(device['id'], 1):
                    Log().add(
                        'fatal',
                        'failed to toggle the fan control state for device: %d'
                        % (device['id']))
                self.fan_states[device['id']] = True
                self.regulate_power_level(device, True)

        return True

    def start(self):
        i = 0

        while True:
            if i % 10 == 0:
                self.devices = Nvidia().refresh(True)
            else:
                self.devices = Nvidia().refresh()

            for device_id in self.devices.keys():
                device = self.devices[device_id]
                if "ignore_devices" in Config().keys() and Config().get(
                        'ignore_devices') and device['id'] in Config().get(
                            'ignore_devices'):
                    continue

                self.speeds[device_id] = self.calculate_fan_speed(device)
                self.regulate_power_level(device)

            self.adjust_fan_speeds()

            if "automatically_reload_config_on_change" in Config().keys(
            ) and Config().get("automatically_reload_config_on_change"):
                if Config().reload_if_changed():
                    self.target_temperature = Config().get(
                        'target_temperature')
                    self.fan_speed_temperature_ratio = Config().get(
                        'fan_speed_temperature_ratio')
                    os.environ["DISPLAY"] = ":%d" % (
                        Config().get('xorg_display_no'))

            time.sleep(1)
            i += 1

    def ensure_control_state(self, device_id, state):
        if self.fan_states[device_id] != state:
            Nvidia().set_fan_control_state(device_id, state)
            self.fan_states[device_id] = state

    def calculate_fan_speed(self, device):
        if device['gpu_t_i'] >= self.target_temperature:
            fan_speed = 100
        else:
            fan_speed = 100 - ((self.target_temperature - device['gpu_t_i']) *
                               self.fan_speed_temperature_ratio)

        if fan_speed < 0:
            fan_speed = 20

        return fan_speed

    def adjust_fan_speeds(self):
        fan_speed_changes = {}

        for device_id in self.devices.keys():
            if self.devices[device_id]['fan'] != self.speeds[device_id]:
                if Config().get('informative'):
                    Log().add(
                        'debug',
                        '%d: device temp: %s  target temperature: %s  target fan speed: %d'
                        % (device_id, self.devices[device_id]['gpu_t_i'],
                           self.target_temperature, self.speeds[device_id]))

                fan_speed_changes[device_id] = self.speeds[device_id]

        if len(fan_speed_changes) > 0:
            Nvidia().apply_fan_speed_changes(fan_speed_changes)

    def regulate_power_level(self, device, force=False):
        card_limit = Config().get("temperature_limit")

        if not card_limit:
            card_limit = 80

        if os.path.exists("/var/run/minotaur/%d.powerlimit" % (device['id'])):
            desired_limit = float(
                open("/var/run/minotaur/%d.powerlimit" %
                     (device['id'])).read())
        else:
            desired_limit = device['default_power_limit_f']

        temp = device['gpu_t_i']
        limit = device['limit_f']

        if temp >= card_limit:
            deduction = 10 * (2**(temp - card_limit))

            new_limit = desired_limit - deduction

            if new_limit < device['min_power_limit_f']:
                new_limit = device['min_power_limit_f']

            if new_limit != limit:
                Log().add(
                    'warning',
                    'device %d: temperature is at %dC, throttling power limit to %dW'
                    % (device['id'], temp, new_limit))
                Nvidia().set_power_limit(device['id'], new_limit)

                if not device['id'] in self.throttled:
                    self.throttled.append(device['id'])
        else:
            if device['id'] in self.throttled and limit < desired_limit:
                Log().add(
                    'info',
                    'device %d: temperature is at %dC, restoring optimum power limit of %dW'
                    % (device['id'], temp, desired_limit))

                Nvidia().set_power_limit(device['id'], desired_limit)

                self.throttled.remove(device['id'])
            elif force:
                if int(device['limit_f']) != int(desired_limit):
                    Log().add(
                        'info', 'device %d: setting power limit %dW' %
                        (device['id'], desired_limit))
                    Nvidia().set_power_limit(device['id'], desired_limit)
Exemple #23
0
 def ensure_control_state(self, device_id, state):
     if self.fan_states[device_id] != state:
         Nvidia().set_fan_control_state(device_id, state)
         self.fan_states[device_id] = state
Exemple #24
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 ""
Exemple #25
0
    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
Exemple #26
0
    def print_devices(self):
        for device in Nvidia().get_nvidia_devices(1):
            print "%d: %s [class: %s]" % (device.id, device.name,
                                          device.dclass)

        sys.exit()
Exemple #27
0
class Minotaur:
    def __init__(self):
        self.data_path = os.getenv("HOME") + "/.minotaur"
        if not os.path.exists(self.data_path):
            os.mkdir(self.data_path)

        self.power_file = self.data_path + "/power.dat"
        self.profitability_file = self.data_path + "/profitability.dat"
        self.currency_rate_file = self.data_path + "/currencies.dat"

        self.startup_time = time.time()
        Config().load()

    def already_running(self):
        if not os.path.exists("/var/run/minotaur"):
            try:
                ok.mkdir("/var/run/minotaur", 0755)
            except:
                Log().add('fatal', 'unable to create /var/run/minotaur')

        if os.path.exists("/var/run/minotaur/minotaur.pid"):
            pid = open("/var/run/minotaur/minotaur.pid").read().rstrip()

            return pid.isdigit() and os.path.exists("/proc/%s" % (pid))

    def create_pid_file(self):
        if self.already_running():
            Log().add(
                'fatal',
                'unable to start, there is another minotaur process running')

        with open("/var/run/minotaur/minotaur.pid", "w") as f:
            f.write("%d" % (os.getpid()))

    def banner(self):
        version = Version().get()

        line = "-" * (20 + len(version))

        print
        print "  /%s/" % (line)
        print " / minotaur %s by m4rkw /" % (version)
        print "/%s/" % (line)
        print

    def usage(self):
        self.banner()
        print "usage: %s [command] [options]" % (sys.argv[0])
        print
        print "## quickstart"
        print
        print " %s --quickstart" % (sys.argv[0])
        print
        print "quickstart mode will calibrate the 5 most profitable Nicehash algorithms"
        print "in fast mode (no power tuning) and then start mining. See the README for"
        print "more information."
        print
        print "## calibration"
        print
        print " %s --calibrate <device id / name / class | all> <pool (nicehash/ethermine/all)> <miner> <algorithms | all> [region (eu/usa)] [--quick] [--overwrite] [--force]" % (
            sys.argv[0])
        print
        print "     --quick : skip power calibration and just do the initial run at default power"
        print " --overwrite : replace existing calibration data"
        print "     --force : take-over a device from minotaur and use it for calibration"
        print
        print "## mining"
        print
        print " %s --mine" % (sys.argv[0])
        print
        print "## misc"
        print
        print " %s --devices                                         # list devices" % (
            sys.argv[0])
        print " %s --algos                                           # list algorithms and calibrated hashrates" % (
            sys.argv[0])
        print " %s --cleanup                                         # stop workers (not calibration runs)" % (
            sys.argv[0])
        print " %s --cleanup <device id>                             # stop workers for device" % (
            sys.argv[0])
        print " %s --cleanup-all                                     # stop all workers (including calibration runs)" % (
            sys.argv[0])
        print " %s --pin <device id> <pool> <miner> <algo> [region]  # pin a device to a specific miner+algorithm" % (
            sys.argv[0])
        print " %s --pin <device id> idle                            # pin a device to idle (ie don't use)" % (
            sys.argv[0])
        print " %s --unpin <device id>                               # unpin a device from a specific miner+algorithm" % (
            sys.argv[0])
        print " %s --stats [hours]                                   # show stats (default last 24 hours)" % (
            sys.argv[0])
        print " %s --help                                            # display this help page" % (
            sys.argv[0])
        print
        sys.exit()

    def initialise(self):
        self.banner()

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

        self.check_for_update()

        Pools()
        Miners()

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

        self.scan_devices()

    def check_for_update(self):
        try:
            opener = urllib2.build_opener(NoRedirection,
                                          urllib2.HTTPCookieProcessor())

            resp = opener.open(
                "https://github.com/m4rkw/minotaur/releases/latest")

            latest_version = resp.headers['Location'].split('/')[-1][1:]

            if self.is_newer(latest_version, Version().get()):
                Log().add('info',
                          'new version available: v%s' % (latest_version))
        except:
            Log().add('warning', 'failed to check for updates')
            pass

    def is_newer(self, latest_version, current_version):
        latest_version = latest_version.replace('v', '').split(".")
        current_version = current_version.replace('v', '').split(".")

        if int(latest_version[0]) > int(current_version[0]):
            return True
        elif int(latest_version[0]) < int(current_version[0]):
            return False

        if int(latest_version[1]) > int(current_version[1]):
            return True
        elif int(latest_version[1]) < int(current_version[1]):
            return False

        if len(latest_version) > 2 and len(current_version) < 3:
            return True

        if len(latest_version) > 2 and len(current_version) < 3:
            return True

        if len(latest_version) > 2 and len(current_version) > 2:
            return int(latest_version[2]) > int(current_version[2])

        return False

    def sigint_handler(self, a, b):
        Log().add('info', 'interrupt received, cleaning up')

        try:
            Miners().cleanup_workers()
        except:
            pass

        sys.exit(0)

    def cleanup(self, all=0, device_id=None):
        if all:
            Miners().cleanup_workers(True)
        elif not all and not device_id:
            Miners().cleanup_workers(False)
        else:
            device = Device({"id": device_id})

            Nvidia().set_default_profile(device)
            Miners().stop_device(device)

        sys.exit(0)

    def scan_devices(self):
        self.devices = Nvidia().get_nvidia_devices()

        Calibration().load()

        if len(self.devices) < 1:
            Log().add('fatal', "no nvidia GPUs found")

        Log().add("info", "found %d nvidia GPUs" % (len(self.devices)))

        Calibration().check_calibrated_algorithms(self.devices)

        Log().add('info', 'retrieving state from miner backends')

        Miners().poll()

        for device in self.devices:
            device.update()

            if device.state == 'active':
                device.log(
                    'info',
                    'currently running algorithm %s with %s [profile=%s] [region=%s]'
                    % (device.algos[0]['algo'], device.algos[0]['miner'],
                       device.profile, device.algos[0]['region']))
                device.apply_profile()
            elif device.state == 'calibrating':
                device.log(
                    'info',
                    'calibration in progress with algorithm %s using %s [region=%s]'
                    % (device.algos[0]['algo'], device.algos[0]['miner'],
                       device.algos[0]['region']))

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

    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

    def grubtime_is_unique(self, grubtime, i):
        _from = grubtime
        _to = grubtime + (15 * 60)

        for j in range(0, len(self.devices)):
            if i != j:
                _from2 = self.devices[j].grubtime
                _to2 = _from2 + (15 * 60)

                for x in range(_from2, _to2):
                    if x in range(_from, _to):
                        return False

        return True

    def load_power_draw_readings(self):
        if os.path.exists(
                self.power_file) and os.path.getsize(self.power_file) > 0:
            return pickle.loads(open(self.power_file).read())

        return []

    def load_profitability_readings(self):
        if os.path.exists(self.profitability_file) and os.path.getsize(
                self.profitability_file) > 0:
            return pickle.loads(open(self.profitability_file).read())

        return []

    def trim_readings(self, readings, max_time):
        new_readings = []

        for reading in readings:
            if int(time.time()) - reading["timestamp"] <= max_time:
                new_readings.append(reading)

        return new_readings

    def update_power_draw_readings(self, power_draw_readings, total_power):
        power_draw_readings.append({
            "timestamp": int(time.time()),
            "reading": total_power
        })
        power_draw_readings = self.trim_readings(
            power_draw_readings,
            max(Config().get('live_data')['power_draw_averages']))

        with open(self.power_file + ".new", "w") as f:
            f.write(pickle.dumps(power_draw_readings))
        os.rename(self.power_file + ".new", self.power_file)

        return power_draw_readings

    def update_profitability_readings(self, profitability_readings,
                                      total_mbtc_per_day):
        profitability_readings.append({
            "timestamp": int(time.time()),
            "reading": total_mbtc_per_day
        })
        profitability_readings = self.trim_readings(
            profitability_readings,
            max(Config().get('live_data')['profitability_averages']))

        with open(self.profitability_file + ".new", "w") as f:
            f.write(pickle.dumps(profitability_readings))
        os.rename(self.profitability_file + ".new", self.profitability_file)

        return profitability_readings

    def sighup_handler(self, x, y):
        Log().add('info', 'SIGHUP caught, reloading config and benchmark data')

        Config().reload()
        Calibration().load()
        Miners().reload_config()

        for device in Nvidia().get_nvidia_devices():
            if not self.device_in_list(device):
                device.update()

                if device.state == 'active':
                    device.log(
                        'info',
                        'currently running algorithm %s with %s [profile=%s] [region=%s]'
                        % (device.algos[0]['algo'], device.algos[0]['miner'],
                           device.profile, device.algos[0]['region']))
                elif device.state == 'calibrating':
                    device.log(
                        'info',
                        'calibration in progress with algorithm %s using %s [region=%s]'
                        % (device.algos[0]['algo'], device.algos[0]['miner'],
                           device.algos[0]['region']))

                self.devices.append(device)

        for device in self.devices:
            if device.state == 'active':
                device.apply_profile()

        Log().add('info', 'reload complete')

    def device_in_list(self, device):
        for l_device in self.devices:
            if l_device.id == device.id:
                return True

        return False

    def calibration_banner(self):
        print "-" * 84
        Log().add(
            'info',
            'PLEASE NOTE: this process will not automatically overclock your card unless'
        )
        Log().add(
            'info',
            'you have enabled overclocking and configured a device profile with overclock'
        )
        Log().add(
            'info',
            'settings. You and you alone are responsible for any overclock settings that'
        )
        Log().add(
            'info',
            'you want to run this benchmark process with. We do not advise overclocking'
        )
        Log().add(
            'info',
            'and are not responsible for any hardware damage that may occur when using'
        )
        Log().add('info', 'this tool.')
        print "-" * 84

    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.')

    def print_devices(self):
        for device in Nvidia().get_nvidia_devices(1):
            print "%d: %s [class: %s]" % (device.id, device.name,
                                          device.dclass)

        sys.exit()

    def print_algorithms(self):
        algorithms = Config().get('algorithms.single') + Config().get(
            'algorithms.double')

        Calibration().load()

        device_classes = Nvidia().get_nvidia_device_classes()

        for device_class in device_classes:
            data = {}

            for algorithm in algorithms:
                data[algorithm] = {}

                for miner_name in Config().get('miners'):
                    miner = eval('%s()' % (miner_name.title()))

                    if algorithm in miner.supported_algorithms():
                        data[algorithm][miner_name] = Calibration(
                        ).get_miner_hashrate_for_algorithm_on_device(
                            miner_name, algorithm, device_class)
                    else:
                        data[algorithm][miner_name] = "-"

            self.display_device_algorithm_table(device_class, data)

        print "\nnote: - means not supported\n"

    def display_device_algorithm_table(self, device_class, data):
        print "\n"

        algo_width = self.get_width(data.keys()) + 2
        total_width = algo_width

        sys.stdout.write(device_class.ljust(algo_width))

        miner_widths = {}

        for miner_name in sorted(Config().get('miners').keys()):
            miner_widths[miner_name] = self.get_miner_width(data,
                                                            miner_name) + 2
            total_width += miner_widths[miner_name] + 2

            sys.stdout.write(miner_name.rjust(miner_widths[miner_name]))

        sys.stdout.write("\n")
        sys.stdout.write("-" * total_width)
        sys.stdout.write("\n")
        sys.stdout.flush()

        for algorithm in sorted(data.keys()):
            sys.stdout.write(algorithm.ljust(algo_width))

            for miner_name in sorted(data[algorithm].keys()):
                sys.stdout.write(data[algorithm][miner_name].rjust(
                    miner_widths[miner_name]))

            sys.stdout.write("\n")

    def get_width(self, values):
        width = 0

        for s in values:
            if len(s) > width:
                width = len(s)

        return width

    def get_miner_width(self, data, miner_name):
        width = len(miner_name)

        for a in data.keys():
            if len(data[a][miner_name]) > width:
                width = len(data[a][miner_name])

        return width

    def get_miners_for_algorithm(self, algorithm):
        miners = []

        for miner_name in Config().get('miners'):
            if Config().get('miners')[miner_name]['enable']:
                miner = eval('%s()' % (miner_name.title()))

                if algorithm in miner.supported_algorithms():
                    miners.append(miner_name)

        return miners

    def pin(self, device_id, pool_name, pin_miner_name, algorithm, region):
        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device = Device({"id": int(device_id)})

            if pool_name not in Config().get('pools').keys():
                Log().add('fatal', 'unknown pool')

            if not algorithm in Config().get(
                    'algorithms.single') and not algorithm in Config().get(
                        'algorithms.double'):
                Log().add('fatal', 'unknown algorithm')

            if pool_name != 'nicehash':
                region = None
            else:
                if region not in ['eu', 'usa', 'hk', 'jp', 'in', 'br']:
                    Log().add('fatal', 'valid region is required for nicehash')

            Miners().poll()
            Miners().get_device_state(device)

            if device.state == "calibrating":
                Log().add(
                    'fatal', 'not pinning device %d - currently calibrating' %
                    (device.id))

            pin = {
                "pool_name": pool_name,
                "miner_name": pin_miner_name,
                "algorithm": algorithm,
                "region": region
            }

            with open("/var/run/minotaur/pin%d" % (device.id), "w") as f:
                f.write(yaml.dump(pin))

            Log().add(
                'info',
                'pinned device %d to miner: %s pool %s algorithm: %s region: %s'
                % (device.id, pin_miner_name, pool_name, algorithm, region))

    def pin_idle(self, device_id):
        pin = {"idle": True}

        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device = Device({"id": int(device_id)})

            with open("/var/run/minotaur/pin%d" % (device.id), "w") as f:
                f.write(yaml.dump(pin))

            Log().add('info', 'pinned device %d to idle' % (device.id))

    def pin_calibration(self, device_id):
        pin = {"calibration": True}

        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device = Device({"id": int(device_id)})

            with open("/var/run/minotaur/pin%d" % (device.id), "w") as f:
                f.write(yaml.dump(pin))

            Log().add('info', 'pinned device %d to calibration' % (device.id))

    def unpin(self, device_id):
        device_ids = []

        if device_id == 'all':
            for device in Nvidia().get_nvidia_devices():
                device_ids.append(device.id)
        else:
            for device_id in device_id.split(","):
                device_ids.append(int(device_id))

        if len(device_ids) == 0:
            Log().add('fatal', 'no devices selected')

        for device_id in device_ids:
            device_id = int(device_id)

            if os.path.exists("/var/run/minotaur/pin%d" % (device_id)):
                os.remove("/var/run/minotaur/pin%d" % (device_id))
                Log().add('info', 'unpinned device %d' % (device_id))
            else:
                Log().add('info', 'device %d is not pinned' % (device_id))

    def device_pinned(self, device_id):
        if os.path.exists("/var/run/minotaur/pin%d" % (device_id)):
            return yaml.load(
                open("/var/run/minotaur/pin%d" % (device_id)).read())

        return False

    def stats(self, hours=24):
        if hours == 1:
            suffix = ''
        else:
            suffix = 's'

        print "\nstats for the last %d hour%s:\n" % (hours, suffix)

        stats_file = "/var/log/minotaur/minotaur.csv"

        if not os.path.exists(stats_file):
            print "%s not found" % (stats_file)
            sys.exit(1)
        else:
            total = 0
            algos = {}
            devices = {}

            logs = Stats().get_logs_for_period(stats_file, hours)
            width = 0

            for item in logs:
                if len(item['algorithm']) > width:
                    width = len(item['algorithm'])

                if item['device_id'] not in devices.keys():
                    devices[item['device_id']] = item
                else:
                    time_on_algo = (
                        parser.parse(item['timestamp']) - parser.parse(
                            devices[item['device_id']]['timestamp'])).seconds
                    if devices[item['device_id']]['net_mbtc'] != '':
                        net = float(devices[item['device_id']]['net_mbtc'])

                    earning = (net / 86400) * time_on_algo

                    if item['algorithm'] not in algos.keys():
                        algos[item['algorithm']] = 0

                    total += earning
                    algos[item['algorithm']] += earning

                    devices[item['device_id']] = item

            print " from: %s" % (logs[0]['timestamp'])
            print "   to: %s\n" % (logs[len(logs) - 1]['timestamp'])

            total_s = "%.2f" % (total)

            print "total: %s mBTC" % (total_s.rjust(7))

            if os.path.exists(self.currency_rate_file):
                exchange_rate = pickle.loads(
                    open(self.currency_rate_file).read())

                fiat = (total / 1000) * float(exchange_rate['rate'])
                fiat_s = "%.2f" % (fiat)

                print "       %s  %s" % (fiat_s.rjust(7),
                                         Config().get('electricity_currency'))

            total_seconds = hours * 3600
            rate = ((total / total_seconds) * 86400)

            rate_s = "%.2f" % (rate)

            print "\n rate: %s mBTC/day" % (rate_s.rjust(7))

            if os.path.exists(self.currency_rate_file):
                exchange_rate = pickle.loads(
                    open(self.currency_rate_file).read())

                fiat = (rate / 1000) * float(exchange_rate['rate'])

                day_s = "%.2f" % (fiat)
                month_s = "%.2f" % (fiat * 30)

                print "       %s  %s/day" % (
                    day_s.rjust(7), Config().get('electricity_currency'))
                print "       %s  %s/month" % (
                    month_s.rjust(7), Config().get('electricity_currency'))

            print "\nincome by algorithm:\n"

            for w in sorted(algos, key=algos.get, reverse=True):
                if os.path.exists(self.currency_rate_file):
                    exchange_rate = pickle.loads(
                        open(self.currency_rate_file).read())

                    fiat = (algos[w] / 1000) * float(exchange_rate['rate'])

                    suffix = "  %.2f %s" % (
                        fiat, Config().get('electricity_currency'))
                else:
                    suffix = ""

                print "%s: %.4f mBTC%s" % (w.rjust(width), algos[w], suffix)

            print ""

            sys.exit()

    def get_latest_version(self):
        opener = urllib2.build_opener(NoRedirection,
                                      urllib2.HTTPCookieProcessor())
        resp = opener.open("https://github.com/m4rkw/minotaur/releases/latest")
        return resp.headers['Location'].split('/')[-1][1:]

    def upgrade(self):
        print "checking for update"

        latest_version = self.get_latest_version()
        current_version = Version().get
        current_version = '0.8.9'

        if self.is_newer(latest_version, current_version):
            print 'new version available: v%s' % (latest_version)

            sys.stdout.write('upgrade? (y/n) ')
            line = sys.stdin.readline()
            if line[0].lower() == 'y':
                self.do_upgrade()
        else:
            print 'you are already running the latest version.'

    def do_upgrade(self):
        if os.getuid() != 0:
            print 'elevating with sudo, you may need to enter your password below..'
            os.system("sudo %s --do-upgrade" % (sys.argv[0]))
            sys.exit(0)
        else:
            latest_version = self.get_latest_version()
            print "downloading minotaur-%s_centos7.tar.gz" % (latest_version)
            os.system(
                "curl -L -s -o /tmp/minotaur.tar.gz https://github.com/m4rkw/minotaur/releases/download/v%s/minotaur-%s_centos7.tar.gz"
                % (latest_version, latest_version))
            os.system("tar -C /tmp -zxf /tmp/minotaur.tar.gz")

            print "installing minotaur"
            copyfile("/tmp/minotaur-%s/minotaur" % (latest_version),
                     sys.argv[0])

            print "cleaning up"
            os.system("rm -rf /tmp/minotaur-%s /tmp/minotaur.tar.gz" %
                      (latest_version))

            print "done!"

        sys.exit(0)
Exemple #28
0
    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.')