initial commit
This commit is contained in:
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright © 2017 Scott Alfter
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
123
README.md
Normal file
123
README.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
nvOC MiningPoolHub Switcher
|
||||||
|
===========================
|
||||||
|
|
||||||
|
nvOC makes it easy to squeeze more hashrate out of your GPUs. MiningPoolHub
|
||||||
|
makes it easy to mine altcoins and get paid in Bitcoin. However, nvOC is a
|
||||||
|
customized Ubuntu Linux and the management software MiningPoolHub recommends
|
||||||
|
for profit switching only runs under Windows. Their approach to
|
||||||
|
coin-switching with nVidia GPUs under Linux is to loop through a bunch of
|
||||||
|
different miners, erroring out on all but the currently-profitable coin. I
|
||||||
|
lost nearly four hours this morning when a miner didn't exit properly during
|
||||||
|
a switch.
|
||||||
|
|
||||||
|
This set of scripts bridges the gap. With them, you can use the miners
|
||||||
|
included in nvOC (and others that you might add) to mine whatever's most
|
||||||
|
profitable at MiningPoolHub. For each supported algorithm, you can
|
||||||
|
customize power, clockspeed, and fan speed settings as you consider
|
||||||
|
appropriate.
|
||||||
|
|
||||||
|
Setup
|
||||||
|
-----
|
||||||
|
|
||||||
|
1. ssh into your mining rig's m1 account.
|
||||||
|
2. Clone these files into the same directory as nvOC's oneBash script.
|
||||||
|
3. Disable oneBash by commenting out all lines in ~/2unix. oneBash should
|
||||||
|
be invoked manually if you add/remove GPUs so it can reconfigure
|
||||||
|
/etc/X11/xorg.conf, but it otherwise isn't used. To keep gnome-terminal
|
||||||
|
from sucking down CPU cycles by constantly restarting the 2unix script, you
|
||||||
|
might want to include something like "sleep 86400" at the end.
|
||||||
|
4. Edit mph_conf.json. You'll set your user and miner names here. You can
|
||||||
|
also customize your overclocking settings for each algorithm here.
|
||||||
|
5. If your network is IPv6-enabled, note that nvOC (as of v17) has a problem
|
||||||
|
connecting to IPv6 hosts. MiningPoolHub makes its API available over both IPv6
|
||||||
|
and IPv4, so to force it to use IPv4 in the meantime, edit /etc/hosts as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
`104.27.168.52 miningpoolhub.com`
|
||||||
|
6. Set mph_switch.py to launch with a cronjob:
|
||||||
|
|
||||||
|
`0,10,20,30,40,50 * * * * (cd /media/m1/1263-A96E && python2.7 mph_switch.py mph_conf.json)`
|
||||||
|
|
||||||
|
Every 10 minutes, the script will run and determine which miner needs to
|
||||||
|
start up. If it's already running, it will leave it alone. If it needs to
|
||||||
|
switch, it kills one miner and starts the other. If nothing's running
|
||||||
|
(because the rig just rebooted or the miner crashed), it will start the
|
||||||
|
miner.
|
||||||
|
|
||||||
|
current-profit is a text file that will be updated on every run of switch.py
|
||||||
|
to show which is currently the most profitable. Profitability is determined
|
||||||
|
by the MiningPoolHub API and is a unitless number; higher is better.
|
||||||
|
|
||||||
|
algo-log is a list of coins and algorithms the switcher has selected when
|
||||||
|
run. If you start seeing repeats of the same algo every 10 minutes, that's
|
||||||
|
a sign that something has gone wrong with your GPUs and you might want to
|
||||||
|
consider a reboot.
|
||||||
|
|
||||||
|
Miners are started in Screen sessions (http://www.gnu.org/software/screen)
|
||||||
|
that can be viewed over an ssh login session:
|
||||||
|
|
||||||
|
`screen -dr miner`
|
||||||
|
|
||||||
|
When the rig switches algorithms, the Screen session will be closed and a
|
||||||
|
new one opened. Repeat the above to monitor it, or you could use something
|
||||||
|
like this on a monitoring workstation:
|
||||||
|
|
||||||
|
`while true; do screen -dr miner; done`
|
||||||
|
|
||||||
|
Adding Algorithms
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Some algorithms supported by MiningPoolHub can't be mined with the miners
|
||||||
|
included in nvOC. If you add the appropriate software, though, you can mine
|
||||||
|
these as well. Instructions to add these capabilities will follow.
|
||||||
|
|
||||||
|
Sia
|
||||||
|
---
|
||||||
|
|
||||||
|
To add the miner:
|
||||||
|
|
||||||
|
`sudo apt install golang-go
|
||||||
|
mkdir /home/m1/gocode
|
||||||
|
GOPATH=/home/m1/gocode go get github.com/robvanmieghem/gominer`
|
||||||
|
|
||||||
|
To enable mining, create a new object named "sia" within the "miners"
|
||||||
|
list in mph_conf.json. Here's what I use:
|
||||||
|
|
||||||
|
```
|
||||||
|
"miners":
|
||||||
|
{
|
||||||
|
[existing entries deleted for brevity]
|
||||||
|
"Sia":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a sia -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
CryptoNight
|
||||||
|
-----------
|
||||||
|
|
||||||
|
To add the miner:
|
||||||
|
|
||||||
|
`cd /home/m1
|
||||||
|
git clone https://github.com/KlausT/ccminer-cryptonight KTccminer-cryptonight
|
||||||
|
cd KTccminer-cryptonight
|
||||||
|
./autoreconf.sh
|
||||||
|
./configure --with-cuda-/usr/local/cuda-8.0
|
||||||
|
make`
|
||||||
|
|
||||||
|
To enable mining, create a new object named "cryptonight" within the "miners"
|
||||||
|
list in mph_conf.json. Here's what I use:
|
||||||
|
|
||||||
|
```
|
||||||
|
"miners":
|
||||||
|
{
|
||||||
|
[existing entries deleted for brevity]
|
||||||
|
"Cryptonight":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/KTccminer-cryptonight/ccminer -a cryptonight -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": -200, "mem_oc": 1000, "fan": [70,75,70]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
68
mph_conf.json
Normal file
68
mph_conf.json
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"user_name": "salfter",
|
||||||
|
"miner_name": "miner10",
|
||||||
|
"card_type": "nvidia",
|
||||||
|
"miners":
|
||||||
|
{
|
||||||
|
"Blake-Vanilla":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a vanilla -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Equihash":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/zec/v3_4/miner --eexit 3 --fee 0 --pec --server {HOST} --user {NAME}.{MINER} --pass z --port {PORT}",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Ethash":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/eth/Genoil-U/ethminer -S {HOST}:{PORT} -O {NAME}.{MINER}:x -U",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": -200, "mem_oc": 1000, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Groestl":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a groestl -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Keccak":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a keccak -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Lyra2RE2":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a lyra2v2 -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Myriad-Groestl":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a myr-gr -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"NeoScrypt":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a neoscrypt -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Qubit":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a qubit -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Scrypt":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a scrypt -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"Skein":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a skein -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
},
|
||||||
|
"X11":
|
||||||
|
{
|
||||||
|
"bin": "/home/m1/SPccminer/ccminer -a x11 -o stratum+tcp://{HOST}:{PORT} -u {NAME}.{MINER} -p x",
|
||||||
|
"power_limit": [115,115,95], "gpu_oc": [-100,-100,0], "mem_oc": 0, "fan": [70,75,70]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
123
mph_switch.py
Normal file
123
mph_switch.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env python2.7
|
||||||
|
|
||||||
|
import pprint
|
||||||
|
import json
|
||||||
|
import urllib2
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
# load config
|
||||||
|
|
||||||
|
cfg=json.loads(open(sys.argv[1]).read())
|
||||||
|
|
||||||
|
card_type=cfg["card_type"]
|
||||||
|
miners=cfg["miners"]
|
||||||
|
user_name=cfg["user_name"]
|
||||||
|
miner_name=cfg["miner_name"]
|
||||||
|
|
||||||
|
os.environ["DISPLAY"]=":0"
|
||||||
|
|
||||||
|
# grab something from a website
|
||||||
|
|
||||||
|
def fetch(url):
|
||||||
|
r=urllib2.Request(url)
|
||||||
|
r.add_header("User-Agent", "Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1")
|
||||||
|
r.add_header("Pragma", "no-cache")
|
||||||
|
return urllib2.build_opener().open(r).read()
|
||||||
|
|
||||||
|
# main
|
||||||
|
|
||||||
|
data=json.loads(fetch("http://miningpoolhub.com/?page=api&action=getminingandprofitsstatistics"))["return"]
|
||||||
|
|
||||||
|
coins={}
|
||||||
|
for i in reversed(data): # weed out unconfigured algos, do string substitutions
|
||||||
|
try:
|
||||||
|
miner=miners[i["algo"]]
|
||||||
|
coins[i["coin_name"]]=miner["bin"].format(HOST=i["host"], PORT=str(i["port"]), NAME=user_name, MINER=miner_name)
|
||||||
|
except:
|
||||||
|
data.remove(i)
|
||||||
|
|
||||||
|
sort={}
|
||||||
|
for i in data:
|
||||||
|
sort[i["coin_name"]+" ("+i["algo"]+")"]=i["normalized_profit_"+card_type]
|
||||||
|
sort=sorted(sort.items(), key=lambda x:x[1], reverse=True)
|
||||||
|
log=open("current-profit", "w")
|
||||||
|
for i in sort:
|
||||||
|
log.write(i[0]+": "+str(i[1])+"\n")
|
||||||
|
log.close()
|
||||||
|
|
||||||
|
max_profit_val=0 # find the most profitable coin
|
||||||
|
for i in data:
|
||||||
|
if i["normalized_profit_"+card_type]>max_profit_val:
|
||||||
|
max_profit=i
|
||||||
|
max_profit_val=i["normalized_profit_"+card_type]
|
||||||
|
|
||||||
|
miner=miners[max_profit["algo"]]
|
||||||
|
coin=coins[max_profit["coin_name"]]
|
||||||
|
|
||||||
|
# see if miner's already running
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_output(["pgrep", "-f", "^"+coin.replace("+", "\\+")])
|
||||||
|
current=1
|
||||||
|
except:
|
||||||
|
current=0
|
||||||
|
if (current==0):
|
||||||
|
other=0
|
||||||
|
for algo in coins:
|
||||||
|
try:
|
||||||
|
subprocess.check_output(["pgrep", "-f", "^"+coins[algo].replace("+", "\\+")])
|
||||||
|
other=1
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if (current==0):
|
||||||
|
# log a change
|
||||||
|
algo_log=open("algo-log", "a")
|
||||||
|
algo_log.write(str(datetime.datetime.now())+": "+max_profit["coin_name"]+" ("+max_profit["algo"]+")\n")
|
||||||
|
algo_log.close()
|
||||||
|
if (other==1):
|
||||||
|
# kill existing miners
|
||||||
|
for algo in coins:
|
||||||
|
subprocess.call(["pkill", "-f", "^"+coins[algo].replace("+", "\\+")])
|
||||||
|
time.sleep(3)
|
||||||
|
if card_type=="nvidia": # update card settings
|
||||||
|
cards=int(subprocess.check_output("nvidia-smi --query-gpu=count --format=csv,noheader,nounits".split(" ")).split("\n")[-2])
|
||||||
|
for i in range(0, cards):
|
||||||
|
# power limit
|
||||||
|
if type(miner["power_limit"]) is int:
|
||||||
|
subprocess.call(("sudo nvidia-smi -i "+str(i)+" -pl "+str(miner["power_limit"])).split(" "))
|
||||||
|
else:
|
||||||
|
subprocess.call(("sudo nvidia-smi -i "+str(i)+" -pl "+str(miner["power_limit"][i])).split(" "))
|
||||||
|
# core overclock
|
||||||
|
if type(miner["gpu_oc"]) is int:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[2]="+str(miner["gpu_oc"])).split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[3]="+str(miner["gpu_oc"])).split(" "))
|
||||||
|
else:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[2]="+str(miner["gpu_oc"][i])).split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUGraphicsClockOffset[3]="+str(miner["gpu_oc"][i])).split(" "))
|
||||||
|
# memory overclock
|
||||||
|
if type(miner["mem_oc"]) is int:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[2]="+str(miner["mem_oc"])).split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[3]="+str(miner["mem_oc"])).split(" "))
|
||||||
|
else:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[2]="+str(miner["mem_oc"][i])).split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUMemoryTransferRateOffset[3]="+str(miner["mem_oc"][i])).split(" "))
|
||||||
|
# fan speed
|
||||||
|
if type(miner["fan"]) is int:
|
||||||
|
if (miner["fan"]==0):
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=0").split(" "))
|
||||||
|
else:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=1").split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [fan:"+str(i)+"]/GPUTargetFanSpeed="+str(miner["fan"])).split(" "))
|
||||||
|
else:
|
||||||
|
if (miner["fan"][i]==0):
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=0").split(" "))
|
||||||
|
else:
|
||||||
|
subprocess.call(("nvidia-settings -a [gpu:"+str(i)+"]/GPUFanControlState=1").split(" "))
|
||||||
|
subprocess.call(("nvidia-settings -a [fan:"+str(i)+"]/GPUTargetFanSpeed="+str(miner["fan"][i])).split(" "))
|
||||||
|
# launch new miner
|
||||||
|
subprocess.call(("screen -dmS miner "+coin).split(" "))
|
||||||
Reference in New Issue
Block a user