cmd/syncthing: Start CPU usage monitoring not from init (fixes #4183)

Starting stuff from init() is an antipattern, and the innerProcess
variable isn't 100% reliable. We should sort out the other uses of it as
well in due time.

Also removing the hack on innerProcess as I happened to see it and the
affected versions are now <1% users.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4185
This commit is contained in:
Jakob Borg
2017-05-31 18:14:04 +00:00
committed by Audrius Butkevicius
parent b49bbe82dd
commit 803da92ca9
5 changed files with 88 additions and 59 deletions

View File

@@ -11,7 +11,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math"
"net"
"net/http"
"os"
@@ -69,6 +68,7 @@ type apiService struct {
configChanged chan struct{} // signals intentional listener close due to config change
started chan string // signals startup complete by sending the listener address, for testing only
startedOnce chan struct{} // the service has started successfully at least once
cpu rater
guiErrors logger.Recorder
systemLog logger.Recorder
@@ -121,7 +121,11 @@ type connectionsIntf interface {
Status() map[string]interface{}
}
func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connectionsIntf, errors, systemLog logger.Recorder) *apiService {
type rater interface {
Rate() float64
}
func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connectionsIntf, errors, systemLog logger.Recorder, cpu rater) *apiService {
service := &apiService{
id: id,
cfg: cfg,
@@ -142,6 +146,7 @@ func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKey
startedOnce: make(chan struct{}),
guiErrors: errors,
systemLog: systemLog,
cpu: cpu,
}
return service
@@ -847,30 +852,6 @@ func (s *apiService) flushResponse(resp string, w http.ResponseWriter) {
f.Flush()
}
// 10 second average. Magic alpha value comes from looking at EWMA package
// definitions of EWMA1, EWMA5. The tick rate *must* be five seconds (hard
// coded in the EWMA package).
var cpuTickRate = 5 * time.Second
var cpuAverage = metrics.NewEWMA(1 - math.Exp(-float64(cpuTickRate)/float64(time.Second)/10.0))
func init() {
if !innerProcess {
return
}
go func() {
// Initialize prevUsage to an actual value returned by cpuUsage
// instead of zero, because at least Windows returns a huge negative
// number here that then slowly increments...
prevUsage := cpuUsage()
for range time.NewTicker(cpuTickRate).C {
curUsage := cpuUsage()
cpuAverage.Update(int64((curUsage - prevUsage) / time.Millisecond))
prevUsage = curUsage
cpuAverage.Tick()
}
}()
}
func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
@@ -899,7 +880,7 @@ func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) {
res["connectionServiceStatus"] = s.connectionsService.Status()
// cpuUsage.Rate() is in milliseconds per second, so dividing by ten
// gives us percent
res["cpuPercent"] = cpuAverage.Rate() / 10 / float64(runtime.NumCPU())
res["cpuPercent"] = s.cpu.Rate() / 10 / float64(runtime.NumCPU())
res["pathSeparator"] = string(filepath.Separator)
res["uptime"] = int(time.Since(startTime).Seconds())
res["startTime"] = startTime