2017-09-05 01:13:03 +09:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-09-06 07:53:17 +09:00
|
|
|
"errors"
|
2017-09-05 01:13:03 +09:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2017-09-10 16:28:50 +09:00
|
|
|
"runtime"
|
2017-09-05 01:13:03 +09:00
|
|
|
"syscall"
|
|
|
|
"time"
|
2017-09-07 01:26:04 +09:00
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
"amuz.es/src/infra/cpu_ctrl/daemon"
|
|
|
|
"amuz.es/src/infra/cpu_ctrl/logger"
|
|
|
|
"amuz.es/src/infra/cpu_ctrl/processor"
|
|
|
|
"amuz.es/src/infra/cpu_ctrl/util"
|
2017-09-11 00:22:51 +09:00
|
|
|
"amuz.es/src/infra/cpu_ctrl/consumer"
|
2017-09-11 01:49:54 +09:00
|
|
|
|
|
|
|
"gopkg.in/alecthomas/kingpin.v2"
|
2017-09-05 01:13:03 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2017-09-11 01:49:54 +09:00
|
|
|
app = kingpin.New("cpu_ctrl", "Interactive CPU fan controller").Author("Sangbum Kim")
|
|
|
|
verbose = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
|
|
|
|
P = app.Flag("proportional-gain", "Set proportional gain value.").Short('p').Default("1.5").Float64()
|
2017-09-11 01:58:42 +09:00
|
|
|
I = app.Flag("integral-gain", "Set integral gain value.").Short('i').Default("0.4").Float64()
|
|
|
|
D = app.Flag("derivative-gain", "Set derivative gain value.").Short('d').Default("2.0").Float64()
|
2017-09-11 01:49:54 +09:00
|
|
|
SetPoint = app.Flag("set-point", "Set pointe tempeture").Short('t').Default("38.0").Float64()
|
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
log = logger.NewLogger("cpu_ctrl")
|
2017-09-05 01:13:03 +09:00
|
|
|
)
|
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
func init() {
|
2017-09-11 01:49:54 +09:00
|
|
|
app.Version("0.3")
|
|
|
|
if _, err := app.Parse(os.Args[1:]); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
logger.InitLogger(*verbose, "", &logger.Config{FileName: "Stderr"})
|
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
setMaxProcs()
|
2017-09-05 01:13:03 +09:00
|
|
|
}
|
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
func setMaxProcs() {
|
|
|
|
// TODO(vmarmol): Consider limiting if we have a CPU mask in effect.
|
|
|
|
// Allow as many threads as we have cores unless the user specified a value.
|
|
|
|
var numProcs int
|
|
|
|
// if *maxProcs < 1 {
|
|
|
|
numProcs = runtime.NumCPU()
|
|
|
|
// } else {
|
|
|
|
// numProcs = *maxProcs
|
|
|
|
// }
|
|
|
|
runtime.GOMAXPROCS(numProcs)
|
|
|
|
|
|
|
|
// Check if the setting was successful.
|
|
|
|
actualNumProcs := runtime.GOMAXPROCS(0)
|
|
|
|
if actualNumProcs != numProcs {
|
|
|
|
log.Printf("Specified max procs of %v but using %v\n", numProcs, actualNumProcs)
|
2017-09-05 01:13:03 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-11 07:41:59 +09:00
|
|
|
func FanoutSpeed(sender <-chan processor.FanspeedInfo, handler util.Handler, receivers ...chan<- processor.FanspeedInfo) {
|
|
|
|
defer handler.DecreaseWait()
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
handler.NotifyError(err.(error))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case tempeture := <-sender:
|
|
|
|
for _, receiver := range receivers {
|
|
|
|
select {
|
|
|
|
case receiver <- tempeture:
|
|
|
|
default:
|
|
|
|
log.Warn("Some Tempeture consumer blocked!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case <-handler.Done():
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-11 00:22:51 +09:00
|
|
|
func FanoutTempeture(sender <-chan processor.TempetureInfo, handler util.Handler, receivers ...chan<- processor.TempetureInfo) {
|
2017-09-10 19:45:30 +09:00
|
|
|
defer handler.DecreaseWait()
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
handler.NotifyError(err.(error))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case tempeture := <-sender:
|
|
|
|
for _, receiver := range receivers {
|
|
|
|
select {
|
|
|
|
case receiver <- tempeture:
|
|
|
|
default:
|
|
|
|
log.Warn("Some Tempeture consumer blocked!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case <-handler.Done():
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-11 00:22:51 +09:00
|
|
|
|
2017-09-05 01:13:03 +09:00
|
|
|
func main() {
|
2017-09-10 19:45:30 +09:00
|
|
|
|
2017-09-05 01:13:03 +09:00
|
|
|
var (
|
2017-09-10 16:28:50 +09:00
|
|
|
processorCount = processor.GetProcessorCount()
|
|
|
|
processors []processor.Processor
|
|
|
|
exitSignal = make(chan os.Signal, 1)
|
|
|
|
handler = util.NewHandler()
|
|
|
|
sampleDuration = time.Second
|
2017-09-05 01:13:03 +09:00
|
|
|
)
|
2017-09-11 01:49:54 +09:00
|
|
|
log.Infof("Cpu fan controller")
|
2017-09-05 01:13:03 +09:00
|
|
|
|
2017-09-06 07:53:17 +09:00
|
|
|
if processorCount == 0 {
|
2017-09-10 16:28:50 +09:00
|
|
|
handler.NotifyError(errors.New("cpu not found!"))
|
2017-09-06 07:53:17 +09:00
|
|
|
}
|
2017-09-11 07:41:59 +09:00
|
|
|
var (
|
|
|
|
tempetureChannel = make(chan processor.TempetureInfo)
|
|
|
|
fanspeedChannel = make(chan processor.FanspeedInfo)
|
|
|
|
)
|
2017-09-10 16:28:50 +09:00
|
|
|
processors = make([]processor.Processor, 0, processorCount)
|
2017-09-05 01:13:03 +09:00
|
|
|
for i := 0; i < processorCount; i++ {
|
2017-09-10 16:28:50 +09:00
|
|
|
if info, err := processor.NewProcessorInfo(handler, i, sampleDuration,
|
2017-09-11 01:49:54 +09:00
|
|
|
*P, *I, *D, *SetPoint, 0x64, 0x4,
|
2017-09-11 07:41:59 +09:00
|
|
|
tempetureChannel, fanspeedChannel,
|
2017-09-10 16:28:50 +09:00
|
|
|
);
|
|
|
|
err != nil {
|
|
|
|
handler.NotifyError(err)
|
2017-09-06 07:53:17 +09:00
|
|
|
} else {
|
2017-09-10 16:28:50 +09:00
|
|
|
processors = append(processors, info)
|
2017-09-11 00:22:51 +09:00
|
|
|
handler.IncreaseWait()
|
2017-09-10 16:28:50 +09:00
|
|
|
go info.StartMonitoring()
|
2017-09-06 07:53:17 +09:00
|
|
|
}
|
2017-09-05 01:13:03 +09:00
|
|
|
}
|
2017-09-10 16:28:50 +09:00
|
|
|
|
2017-09-11 07:41:59 +09:00
|
|
|
fanController := consumer.NewFanControl(processorCount, sampleDuration, handler)
|
|
|
|
metricLogger := consumer.NewInfluxMetric("", processorCount, handler)
|
|
|
|
|
2017-09-11 07:44:30 +09:00
|
|
|
|
2017-09-11 07:41:59 +09:00
|
|
|
handler.IncreaseWait()
|
|
|
|
go FanoutTempeture(tempetureChannel, handler, metricLogger.TempetureConsumer())
|
2017-09-11 07:44:30 +09:00
|
|
|
defer close(tempetureChannel)
|
|
|
|
|
2017-09-11 07:41:59 +09:00
|
|
|
handler.IncreaseWait()
|
|
|
|
go FanoutSpeed(fanspeedChannel, handler, fanController.Consumer(), metricLogger.FanSpeedConsumer())
|
2017-09-11 07:44:30 +09:00
|
|
|
defer close(fanspeedChannel)
|
|
|
|
|
2017-09-10 16:28:50 +09:00
|
|
|
handler.IncreaseWait()
|
2017-09-11 00:22:51 +09:00
|
|
|
go fanController.StartControl()
|
2017-09-11 07:41:59 +09:00
|
|
|
handler.IncreaseWait()
|
|
|
|
go metricLogger.StartLogging()
|
2017-09-10 16:28:50 +09:00
|
|
|
|
2017-09-05 01:13:03 +09:00
|
|
|
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
2017-09-10 16:28:50 +09:00
|
|
|
daemon.NotifyDaemon(daemon.DaemonStarted)
|
|
|
|
defer daemon.NotifyDaemon(daemon.DaemonStopping)
|
|
|
|
defer close(exitSignal)
|
|
|
|
defer handler.GracefullWait()
|
2017-09-05 01:13:03 +09:00
|
|
|
|
|
|
|
select {
|
2017-09-10 16:28:50 +09:00
|
|
|
case <-handler.Done():
|
|
|
|
log.Infoln("Service request to close this application")
|
|
|
|
case err := <-handler.Error():
|
|
|
|
log.Errorf("%s", err)
|
2017-09-05 01:13:03 +09:00
|
|
|
case sysSignal := <-exitSignal:
|
2017-09-10 16:28:50 +09:00
|
|
|
log.Warnf("SYSCALL! %s", sysSignal.String())
|
2017-09-05 01:13:03 +09:00
|
|
|
}
|
|
|
|
}
|