Skip to content

Commit

Permalink
Implement Remote Status API (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielboliveira authored and jolan committed Oct 2, 2017
1 parent 47d953e commit 44ea5a2
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 61 deletions.
107 changes: 80 additions & 27 deletions README.md
Expand Up @@ -30,7 +30,53 @@ Stratum/pool mining:
gominer -o stratum+tcp://pool:port -m username -n password
```

## Linux Build Pre-Requisites
## Status API

There is a built-in status API to report miner information. You can set an
address and port with `--apilisten`. There are configuration examples on
[sample-gominer.conf](sample-gominer.conf). If no port is specified, then it
will listen by default on `3333`.

Example usage:

```sh
$ gominer --apilisten="localhost"
```

Example output:

```sh
$ curl http://localhost:3333/
> {
"validShares": 0,
"staleShares": 0,
"invalidShares": 0,
"totalShares": 0,
"sharesPerMinute": 0,
"started": 1504453881,
"uptime": 6,
"devices": [{
"index": 2,
"deviceName": "GeForce GT 750M",
"deviceType": "GPU",
"hashRate": 110127366.53846154,
"hashRateFormatted": "110MH/s",
"fanPercent": 0,
"temperature": 0,
"started": 1504453880
}],
"pool": {
"started": 1504453881,
"uptime": 6
}
}
```

## Building

### Linux

#### Pre-Requisites

You will either need to install CUDA for NVIDIA graphics cards or OpenCL
library/headers that support your device such as: AMDGPU-PRO (for newer AMD
Expand All @@ -47,7 +93,7 @@ gominer has been built successfully on Ubuntu 16.04 with go1.6.2, go1.7.1,
g++ 5.4.0, and beignet-dev 1.1.1-2 although other combinations should work as
well.

## Linux Build Instructions
#### Instructions

To download and build gominer, run:

Expand Down Expand Up @@ -75,60 +121,67 @@ For OpenCL with AMD Device Library (ADL) support:
go build -tags opencladl
```

## Windows Build Pre-Requisites
### Windows

#### Pre-Requisites

- Download and install the official Go Windows binaries from [https://golang.dl/](https://golang.org/dl/)
- Download and install Git for Windows from [https://git-for-windows.github.io/](https://git-for-windows.github.io/)
* Make sure to select the Git-Bash option when prompted
- Download the MinGW-w64 installer from [https://sourceforge.net/projects/mingw-w64/files/Toolchains targetting Win32/Personal Builds/mingw-builds/installer/](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/)
* Select the x64 toolchain and use defaults for the other questions
- Set the environment variable GOPATH to C:\Users\username\go
- Set the environment variable GOPATH to `C:\Users\username\go`
- Check that the GOROOT environment variable is set to C:\Go
* This should have been done by the Go installer
- Add the following locations to your PATH C:\Users\username\go\bin;C:\Go\bin
- Add C:\Program Files\mingw-w64\x84_64-6.2.0-posix-seh-rt_v5-rev1\mingw64\bin to your PATH (This is the latest release as of 2016-09-29)
- go get github.com/Masterminds/glide
- Add the following locations to your PATH: `C:\Users\username\go\bin;C:\Go\bin`
- Add `C:\Program Files\mingw-w64\x84_64-6.2.0-posix-seh-rt_v5-rev1\mingw64\bin` to your PATH (This is the latest release as of 2016-09-29)
- `go get github.com/Masterminds/glide`
* You should be able to type ```glide``` and get glide's usage display. If not, double check the steps above
- go get github.com/decred/gominer
- `go get github.com/decred/gominer`
* Compilation will most likely fail which can be safely ignored for now.
- Change to the gominer directory
* If using the Windows Command Prompt:
```cd %GOPATH%/src/github.com/decred/gominer``` or if using git-bash ```cd $GOPATH/src/github.com/decred/gominer```
```cd %GOPATH%/src/github.com/decred/gominer```
* If using git-bash
```cd $GOPATH/src/github.com/decred/gominer```
- Install dependencies via glide
* ```glide install```

### CUDA Specific Steps
#### Build Instructions

##### CUDA

###### Pre-Requisites

- Download Microsoft Visual Studio 2013 from [https://www.microsoft.com/en-us/download/details.aspx?id=44914](https://www.microsoft.com/en-us/download/details.aspx?id=44914)
- Add C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin to your PATH
- Add `C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin` to your PATH
- Install CUDA 7.0 from [https://developer.nvidia.com/cuda-toolkit-70](https://developer.nvidia.com/cuda-toolkit-70)
- Add C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\bin to your PATH
- Add `C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\bin` to your PATH

###### Steps
- Using git-bash:
* ```cd $GOPATH/src/github.com/decred/gominer```
* ```mingw32-make.exe```
- Copy dependencies:
* ```copy obj/decred.dll .```
* ```copy nvidia/NVSMI/nvml.dll .```

### OpenCL/ADL Specific Steps
##### OpenCL/ADL

###### Pre-Requisites

- Download AMD APP SDK v3.0 from [http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/](http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/)
* Samples may be unselected from the install to save space as only the libraries and headers are needed
- Copy or Move C:\Program Files (x86)\AMD APP SDK\3.0 to C:\appsdk
* Ensure the folders C:\appsdk\include and C:\appsdk\lib are populated
- Copy or Move `C:\Program Files (x86)\AMD APP SDK\3.0` to `C:\appsdk`
* Ensure the folders `C:\appsdk\include` and `C:\appsdk\lib` are populated
- Change to the library directory C:\appsdk\lib\x86_64
* ```cd C:\appsdk\lib\x86_64```
- Copy and prepare the ADL library for linking
* ```copy c:\Windows\SysWOW64\atiadlxx.dll .```
* ```gendef atiadlxx.dll```
* ```dlltool --output-lib libatiadlxx.a --input-def atiadlxx.def```

## Windows Build Instructions

### CUDA

- Using git-bash:
* ```cd $GOPATH/src/github.com/decred/gominer```
* ```mingw32-make.exe```
- Copy dependencies:
* ```copy obj/decred.dll .```
* ```copy nvidia/NVSMI/nvml.dll .```

### OpenCL / OpenCL w/ADL support
###### Steps

- For OpenCL:
* ```go build -tags opencl```
Expand Down
75 changes: 55 additions & 20 deletions config.go
Expand Up @@ -28,13 +28,18 @@ const (
)

var (
minerHomeDir = dcrutil.AppDataDir("gominer", false)
dcrdHomeDir = dcrutil.AppDataDir("dcrd", false)
defaultConfigFile = filepath.Join(minerHomeDir, defaultConfigFilename)
defaultRPCServer = "localhost"
defaultRPCCertFile = filepath.Join(dcrdHomeDir, "rpc.cert")
defaultLogDir = filepath.Join(minerHomeDir, defaultLogDirname)
defaultAutocalibrate = 500
minerHomeDir = dcrutil.AppDataDir("gominer", false)
dcrdHomeDir = dcrutil.AppDataDir("dcrd", false)
defaultConfigFile = filepath.Join(minerHomeDir, defaultConfigFilename)
defaultRPCServer = "localhost"
defaultRPCCertFile = filepath.Join(dcrdHomeDir, "rpc.cert")
defaultRPCPortMainNet = "9109"
defaultRPCPortTestNet = "19109"
defaultRPCPortSimNet = "19556"
defaultAPIHost = "localhost"
defaultAPIPort = "3333"
defaultLogDir = filepath.Join(minerHomeDir, defaultLogDirname)
defaultAutocalibrate = 500

minIntensity = 8
maxIntensity = 31
Expand All @@ -59,6 +64,9 @@ type config struct {
CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"`
MemProfile string `long:"memprofile" description:"Write mem profile to the specified file"`

// Status API options
APIListeners []string `long:"apilisten" description:"Add an interface/port to expose miner status API"`

// RPC connection options
RPCUser string `short:"u" long:"rpcuser" description:"RPC username"`
RPCPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password"`
Expand Down Expand Up @@ -92,26 +100,40 @@ type config struct {
PoolPassword string `short:"n" long:"poolpass" default-mask:"-" description:"Pool password"`
}

// removeDuplicateAddresses returns a new slice with all duplicate entries in
// addrs removed.
func removeDuplicateAddresses(addrs []string) []string {
result := make([]string, 0, len(addrs))
seen := map[string]struct{}{}
for _, val := range addrs {
if _, ok := seen[val]; !ok {
result = append(result, val)
seen[val] = struct{}{}
}
}
return result
}

// normalizeAddress returns addr with the passed default port appended if
// there is not already a port specified.
func normalizeAddress(addr string, useTestNet, useSimNet bool) string {
func normalizeAddress(addr string, defaultPort string) string {
_, _, err := net.SplitHostPort(addr)
if err != nil {
var defaultPort string
switch {
case useTestNet:
defaultPort = "19109"
case useSimNet:
defaultPort = "19556"
default:
defaultPort = "9109"
}

return net.JoinHostPort(addr, defaultPort)
}
return addr
}

// normalizeAddresses returns a new slice with all the passed peer addresses
// normalized with the given default port, and all duplicates removed.
func normalizeAddresses(addrs []string, defaultPort string) []string {
for i, addr := range addrs {
addrs[i] = normalizeAddress(addr, defaultPort)
}

return removeDuplicateAddresses(addrs)
}

// filesExists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
Expand Down Expand Up @@ -549,13 +571,26 @@ func loadConfig() (*config, []string, error) {
return nil, nil, err
}

if len(cfg.APIListeners) != 0 {
cfg.APIListeners = normalizeAddresses(cfg.APIListeners, defaultAPIPort)
}

// Handle environment variable expansion in the RPC certificate path.
cfg.RPCCert = cleanAndExpandPath(cfg.RPCCert)

var defaultRPCPort string
switch {
case cfg.TestNet:
defaultRPCPort = defaultRPCPortTestNet
case cfg.SimNet:
defaultRPCPort = defaultRPCPortSimNet
default:
defaultRPCPort = defaultRPCPortMainNet
}

// Add default port to RPC server based on --testnet flag
// if needed.
cfg.RPCServer = normalizeAddress(cfg.RPCServer, cfg.TestNet,
cfg.SimNet)
cfg.RPCServer = normalizeAddress(cfg.RPCServer, defaultRPCPort)

// Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid
Expand Down
21 changes: 15 additions & 6 deletions device.go
Expand Up @@ -317,15 +317,10 @@ func (d *Device) PrintStats() {
return
}

diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF)
d.Lock()
defer d.Unlock()
averageHashRate := (float64(diffOneShareHashesAvg) *
float64(d.allDiffOneShares)) /
float64(secondsElapsed)

fanPercent := atomic.LoadUint32(&d.fanPercent)
temperature := atomic.LoadUint32(&d.temperature)
averageHashRate, fanPercent, temperature := d.Status()

if fanPercent != 0 || temperature != 0 {
minrLog.Infof("DEV #%d (%s) %v Fan=%v%% T=%vC",
Expand Down Expand Up @@ -360,3 +355,17 @@ func (d *Device) UpdateFanTemp() {
}
}
}

func (d *Device) Status() (float64, uint32, uint32) {
secondsElapsed := uint32(time.Now().Unix()) - d.started
diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF)

averageHashRate := (float64(diffOneShareHashesAvg) *
float64(d.allDiffOneShares)) /
float64(secondsElapsed)

fanPercent := atomic.LoadUint32(&d.fanPercent)
temperature := atomic.LoadUint32(&d.temperature)

return averageHashRate, fanPercent, temperature
}
4 changes: 4 additions & 0 deletions main.go
Expand Up @@ -82,6 +82,10 @@ func gominerMain() error {
return err
}

if len(cfg.APIListeners) != 0 {
go RunMonitor(m)
}

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
Expand Down
30 changes: 22 additions & 8 deletions miner.go
Expand Up @@ -158,11 +158,9 @@ func (m *Miner) printStatsThread() {

for {
if !cfg.Benchmark {
valid, rejected, stale, total, utility := m.Status()

if cfg.Pool != "" {
valid := atomic.LoadUint64(&m.pool.ValidShares)
rejected := atomic.LoadUint64(&m.pool.InvalidShares)
stale := atomic.LoadUint64(&m.staleShares)
total := valid + rejected + stale
minrLog.Infof("Global stats: Accepted: %v, Rejected: %v, Stale: %v, Total: %v",
valid,
rejected,
Expand All @@ -171,13 +169,9 @@ func (m *Miner) printStatsThread() {
)
secondsElapsed := uint32(time.Now().Unix()) - m.started
if (secondsElapsed / 60) > 0 {
utility := float64(valid) / (float64(secondsElapsed) / float64(60))
minrLog.Infof("Global utility (accepted shares/min): %v", utility)
}
} else {
valid := atomic.LoadUint64(&m.validShares)
rejected := atomic.LoadUint64(&m.invalidShares)
total := valid + rejected
minrLog.Infof("Global stats: Accepted: %v, Rejected: %v, Total: %v",
valid,
rejected,
Expand Down Expand Up @@ -241,3 +235,23 @@ func (m *Miner) Stop() {
d.Stop()
}
}

func (m *Miner) Status() (uint64, uint64, uint64, uint64, float64) {
if cfg.Pool != "" {
valid := atomic.LoadUint64(&m.pool.ValidShares)
rejected := atomic.LoadUint64(&m.pool.InvalidShares)
stale := atomic.LoadUint64(&m.staleShares)
total := valid + rejected + stale

secondsElapsed := uint32(time.Now().Unix()) - m.started
utility := float64(valid) / (float64(secondsElapsed) / float64(60))

return valid, rejected, stale, total, utility
}

valid := atomic.LoadUint64(&m.validShares)
rejected := atomic.LoadUint64(&m.invalidShares)
total := valid + rejected

return valid, rejected, 0, total, 0
}

0 comments on commit 44ea5a2

Please sign in to comment.