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) ) 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()) defer close(tempetureChannel) handler.IncreaseWait() go FanoutSpeed(fanspeedChannel, handler, fanController.Consumer(), metricLogger.FanSpeedConsumer()) defer close(fanspeedChannel) 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()) } }