1
0
Fork 0
cpu_ctrl/main.go

168 lines
4.4 KiB
Go

package main
import (
"errors"
"os"
"os/signal"
"runtime"
"syscall"
"time"
"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"
"amuz.es/src/infra/cpu_ctrl/consumer"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
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()
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()
SetPoint = app.Flag("set-point", "Set pointe tempeture").Short('t').Default("38.0").Float64()
log = logger.NewLogger("cpu_ctrl")
)
func init() {
app.Version("0.3")
if _, err := app.Parse(os.Args[1:]); err != nil {
panic(err)
}
logger.InitLogger(*verbose, "", &logger.Config{FileName: "Stderr"})
setMaxProcs()
}
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)
}
}
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
}
}
}
func FanoutTempeture(sender <-chan processor.TempetureInfo, handler util.Handler, receivers ...chan<- processor.TempetureInfo) {
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
}
}
}
func main() {
var (
processorCount = processor.GetProcessorCount()
processors []processor.Processor
exitSignal = make(chan os.Signal, 1)
handler = util.NewHandler()
sampleDuration = time.Second
)
log.Infof("Cpu fan controller")
if processorCount == 0 {
handler.NotifyError(errors.New("cpu not found!"))
}
var (
tempetureChannel = make(chan processor.TempetureInfo)
fanspeedChannel = make(chan processor.FanspeedInfo)
)
defer close(tempetureChannel)
defer close(fanspeedChannel)
processors = make([]processor.Processor, 0, processorCount)
for i := 0; i < processorCount; i++ {
if info, err := processor.NewProcessorInfo(handler, i, sampleDuration,
*P, *I, *D, *SetPoint, 0x64, 0x4,
tempetureChannel, fanspeedChannel,
);
err != nil {
handler.NotifyError(err)
} else {
processors = append(processors, info)
handler.IncreaseWait()
go info.StartMonitoring()
}
}
fanController := consumer.NewFanControl(processorCount, sampleDuration, handler)
metricLogger := consumer.NewInfluxMetric("", processorCount, handler)
handler.IncreaseWait()
go FanoutTempeture(tempetureChannel, handler, metricLogger.TempetureConsumer())
handler.IncreaseWait()
go FanoutSpeed(fanspeedChannel, handler, fanController.Consumer(), metricLogger.FanSpeedConsumer())
handler.IncreaseWait()
go fanController.StartControl()
handler.IncreaseWait()
go metricLogger.StartLogging()
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
daemon.NotifyDaemon(daemon.DaemonStarted)
defer daemon.NotifyDaemon(daemon.DaemonStopping)
defer close(exitSignal)
defer handler.GracefullWait()
select {
case <-handler.Done():
log.Infoln("Service request to close this application")
case err := <-handler.Error():
log.Errorf("%s", err)
case sysSignal := <-exitSignal:
log.Warnf("SYSCALL! %s", sysSignal.String())
}
}