mirror of
https://github.com/cryptonote-social/csminer.git
synced 2024-09-11 05:35:23 +03:00
move stats into own package
This commit is contained in:
parent
14dec3b86f
commit
64e33fbf4e
@ -3,12 +3,14 @@ package minerlib
|
||||
import (
|
||||
"github.com/cryptonote-social/csminer/blockchain"
|
||||
"github.com/cryptonote-social/csminer/crylog"
|
||||
"github.com/cryptonote-social/csminer/minerlib/stats"
|
||||
"github.com/cryptonote-social/csminer/rx"
|
||||
"github.com/cryptonote-social/csminer/stratum/client"
|
||||
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -35,15 +37,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// miner client stats
|
||||
sharesAccepted int64
|
||||
sharesRejected int64
|
||||
poolSideHashes int64
|
||||
clientSideHashes, recentHashes int64
|
||||
startTime time.Time // when the miner started up
|
||||
lastStatsResetTime time.Time
|
||||
lastStatsUpdateTime time.Time
|
||||
|
||||
// miner config
|
||||
configMutex sync.Mutex
|
||||
plArgs *PoolLoginArgs
|
||||
@ -54,16 +47,6 @@ var (
|
||||
cl client.Client
|
||||
)
|
||||
|
||||
func tallyHashes(hashes int64) {
|
||||
atomic.AddInt64(&clientSideHashes, hashes)
|
||||
atomic.AddInt64(&recentHashes, hashes)
|
||||
}
|
||||
|
||||
func resetRecentStats() {
|
||||
atomic.StoreInt64(&recentHashes, 0)
|
||||
lastStatsResetTime = time.Now()
|
||||
}
|
||||
|
||||
type PoolLoginArgs struct {
|
||||
// username: a properly formatted pool username.
|
||||
Username string
|
||||
@ -193,7 +176,7 @@ func InitMiner(args *InitMinerArgs) *InitMinerResponse {
|
||||
} else {
|
||||
r.Code = 1
|
||||
}
|
||||
startTime = time.Now()
|
||||
stats.Init()
|
||||
threads = args.Threads
|
||||
go func() {
|
||||
MiningLoop(awaitLogin())
|
||||
@ -257,7 +240,6 @@ func MiningLoop(jobChan <-chan *client.MultiClientJob) {
|
||||
var wg sync.WaitGroup // used to wait for stopped worker threads to finish
|
||||
var stopper uint32 // atomic int used to signal rxlib worker threads to stop mining
|
||||
|
||||
resetRecentStats()
|
||||
//wasJustMining := false
|
||||
|
||||
for {
|
||||
@ -267,6 +249,7 @@ func MiningLoop(jobChan <-chan *client.MultiClientJob) {
|
||||
if job == nil {
|
||||
crylog.Warn("stratum client died")
|
||||
jobChan = reconnectClient()
|
||||
stats.ResetRecent()
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -275,6 +258,7 @@ func MiningLoop(jobChan <-chan *client.MultiClientJob) {
|
||||
// Stop existing mining, if any, and wait for mining threads to finish.
|
||||
atomic.StoreUint32(&stopper, 1)
|
||||
wg.Wait()
|
||||
printStats(true /*isMining*/)
|
||||
|
||||
// Check if we need to reinitialize rx dataset
|
||||
newSeed, err := hex.DecodeString(job.SeedHash)
|
||||
@ -286,7 +270,7 @@ func MiningLoop(jobChan <-chan *client.MultiClientJob) {
|
||||
crylog.Info("New seed:", job.SeedHash)
|
||||
rx.SeedRX(newSeed, runtime.GOMAXPROCS(0))
|
||||
lastSeed = newSeed
|
||||
resetRecentStats()
|
||||
stats.ResetRecent()
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&stopper, 0)
|
||||
@ -299,6 +283,19 @@ func MiningLoop(jobChan <-chan *client.MultiClientJob) {
|
||||
defer crylog.Info("Mining loop terminated")
|
||||
}
|
||||
|
||||
func printStats(isMining bool) {
|
||||
s := stats.GetSnapshot(isMining)
|
||||
crylog.Info("=====================================")
|
||||
crylog.Info("Shares [accepted:rejected]:", s.SharesAccepted, ":", s.SharesRejected)
|
||||
crylog.Info("Hashes [client:pool]:", s.ClientSideHashes, ":", s.PoolSideHashes)
|
||||
if s.RecentHashrate > 0.0 {
|
||||
crylog.Info("Hashes/sec [inception:recent]:",
|
||||
strconv.FormatFloat(s.Hashrate, 'f', 2, 64), ":",
|
||||
strconv.FormatFloat(s.RecentHashrate, 'f', 2, 64))
|
||||
}
|
||||
crylog.Info("=====================================")
|
||||
}
|
||||
|
||||
func goMine(wg *sync.WaitGroup, stopper *uint32, job client.MultiClientJob, thread int) {
|
||||
defer wg.Done()
|
||||
input, err := hex.DecodeString(job.Blob)
|
||||
@ -314,10 +311,10 @@ func goMine(wg *sync.WaitGroup, stopper *uint32, job client.MultiClientJob, thre
|
||||
for {
|
||||
res := rx.HashUntil(input, uint64(diffTarget), thread, hash, nonce, stopper)
|
||||
if res <= 0 {
|
||||
tallyHashes(-res)
|
||||
stats.TallyHashes(-res)
|
||||
break
|
||||
}
|
||||
tallyHashes(res)
|
||||
stats.TallyHashes(res)
|
||||
crylog.Info("Share found by thread", thread, "w/ target:", blockchain.HashDifficulty(hash))
|
||||
fnonce := hex.EncodeToString(nonce)
|
||||
// If the client is alive, submit the share in a separate thread so we can resume hashing
|
||||
@ -335,12 +332,11 @@ func goMine(wg *sync.WaitGroup, stopper *uint32, job client.MultiClientJob, thre
|
||||
return
|
||||
}
|
||||
if len(resp.Error) > 0 {
|
||||
atomic.AddInt64(&sharesRejected, 1)
|
||||
stats.ShareRejected()
|
||||
crylog.Warn("Submit work server error:", jobid, resp.Error)
|
||||
return
|
||||
}
|
||||
atomic.AddInt64(&sharesAccepted, 1)
|
||||
atomic.AddInt64(&poolSideHashes, diffTarget)
|
||||
stats.ShareAccepted(diffTarget)
|
||||
}(fnonce, job.JobID)
|
||||
}
|
||||
}
|
||||
|
207
minerlib/stats/stats.go
Normal file
207
minerlib/stats/stats.go
Normal file
@ -0,0 +1,207 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
mutex sync.RWMutex
|
||||
|
||||
// client side stats
|
||||
startTime time.Time // when the miner started up
|
||||
lastResetTime time.Time
|
||||
lastUpdateTime time.Time
|
||||
sharesAccepted int64
|
||||
sharesRejected int64
|
||||
poolSideHashes int64
|
||||
clientSideHashes, recentHashes int64
|
||||
|
||||
// pool stats
|
||||
lastPoolUserQuery string
|
||||
lastPoolUpdateTime time.Time
|
||||
ppropProgress float64
|
||||
hashrate1, hashrate24 int64
|
||||
lifetimeHashes int64
|
||||
paid, owed, accumulated float64
|
||||
timeToReward string
|
||||
)
|
||||
|
||||
func Init() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
now := time.Now()
|
||||
startTime = now
|
||||
lastResetTime = now
|
||||
lastUpdateTime = now
|
||||
}
|
||||
|
||||
func TallyHashes(hashes int64) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
lastUpdateTime = time.Now()
|
||||
clientSideHashes += hashes
|
||||
recentHashes += hashes
|
||||
}
|
||||
|
||||
func ShareAccepted(diffTarget int64) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
sharesAccepted++
|
||||
poolSideHashes += diffTarget
|
||||
}
|
||||
|
||||
func ShareRejected() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
sharesRejected++
|
||||
}
|
||||
|
||||
// Call every time an event happens that may induce a big change in hashrate,
|
||||
// e.g. reseeding, adding/removing threads, restablishing a connection.
|
||||
func ResetRecent() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
recentHashes = 0
|
||||
now := time.Now()
|
||||
lastUpdateTime = now
|
||||
lastResetTime = now
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
SharesAccepted, SharesRejected int64
|
||||
ClientSideHashes, PoolSideHashes int64
|
||||
Hashrate, RecentHashrate float64
|
||||
}
|
||||
|
||||
func GetSnapshot(isMining bool) *Snapshot {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
r := &Snapshot{}
|
||||
r.SharesAccepted = sharesAccepted
|
||||
r.SharesRejected = sharesRejected
|
||||
r.ClientSideHashes = clientSideHashes
|
||||
r.PoolSideHashes = poolSideHashes
|
||||
|
||||
var elapsedOverall float64
|
||||
if isMining {
|
||||
// if we're actively mining then hash count is only accurate
|
||||
// as of the last update time
|
||||
elapsedOverall = lastUpdateTime.Sub(startTime).Seconds()
|
||||
} else {
|
||||
elapsedOverall = time.Now().Sub(startTime).Seconds()
|
||||
}
|
||||
// Recent stats are only accurate up to the last update time
|
||||
elapsedRecent := lastUpdateTime.Sub(lastResetTime).Seconds()
|
||||
|
||||
if elapsedRecent > 0.0 && elapsedOverall > 0.0 {
|
||||
r.Hashrate = float64(clientSideHashes) / elapsedOverall
|
||||
r.RecentHashrate = float64(recentHashes) / elapsedRecent
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func RefreshPoolStats(username string) error {
|
||||
c := &http.Client{
|
||||
Timeout: 15 * time.Second,
|
||||
}
|
||||
uri := "https://cryptonote.social/json/WorkerStats"
|
||||
sbody := "{\"Coin\": \"xmr\", \"Worker\": \"" + username + "\"}\n"
|
||||
body := strings.NewReader(sbody)
|
||||
resp, err := c.Post(uri, "", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s := &struct {
|
||||
Code int
|
||||
CycleProgress float64
|
||||
Hashrate1 int64
|
||||
Hashrate24 int64
|
||||
LifetimeHashes int64
|
||||
LifetimeBestHash int64
|
||||
Donate float64
|
||||
AmountPaid float64
|
||||
AmountOwed float64
|
||||
}{}
|
||||
err = json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now get pool stats
|
||||
uri = "https://cryptonote.social/json/PoolStats"
|
||||
sbody = "{\"Coin\": \"xmr\"}\n"
|
||||
body = strings.NewReader(sbody)
|
||||
resp2, err := http.DefaultClient.Post(uri, "", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp2.Body.Close()
|
||||
b, err = ioutil.ReadAll(resp2.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps := &struct {
|
||||
Code int
|
||||
NextBlockReward float64
|
||||
Margin float64
|
||||
PPROPProgress float64
|
||||
PPROPHashrate int64
|
||||
NetworkDifficulty int64
|
||||
SmoothedDifficulty int64 // Network difficulty averaged over the past hour
|
||||
}{}
|
||||
err = json.Unmarshal(b, &ps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
diff := float64(ps.SmoothedDifficulty)
|
||||
if diff == 0.0 {
|
||||
diff = float64(ps.NetworkDifficulty)
|
||||
}
|
||||
hr := float64(ps.PPROPHashrate)
|
||||
var ttreward string
|
||||
if hr > 0.0 {
|
||||
ttr := (diff*(1.0+ps.Margin) - (ps.PPROPProgress * diff)) / hr / 3600.0 / 24.0
|
||||
if ttr > 0.0 {
|
||||
if ttr < 1.0 {
|
||||
ttr *= 24.0
|
||||
if ttr < 1.0 {
|
||||
ttr *= 60.0
|
||||
ttreward = strconv.FormatFloat(ttr, 'f', 2, 64) + " min"
|
||||
} else {
|
||||
ttreward = strconv.FormatFloat(ttr, 'f', 2, 64) + " hrs"
|
||||
}
|
||||
} else {
|
||||
ttreward = strconv.FormatFloat(ttr, 'f', 2, 64) + " days"
|
||||
}
|
||||
} else if ttr < 0.0 {
|
||||
ttreward = "overdue"
|
||||
}
|
||||
}
|
||||
|
||||
mutex.Lock()
|
||||
lastPoolUserQuery = username
|
||||
lastPoolUpdateTime = time.Now()
|
||||
ppropProgress = s.CycleProgress / (1.0 + ps.Margin)
|
||||
hashrate1 = s.Hashrate1
|
||||
hashrate24 = s.Hashrate24
|
||||
lifetimeHashes = s.LifetimeHashes
|
||||
paid = s.AmountPaid
|
||||
owed = s.AmountOwed
|
||||
timeToReward = ttreward
|
||||
mutex.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user