package consumer import ( "fmt" "os/exec" "time" zlog "amuz.es/src/infra/goutils/logger/zap" "bytes" "amuz.es/src/infra/goutils/handler" "amuz.es/src/infra/cpu_ctrl/producer" "go.uber.org/zap" ) var () type fanControl struct { processorCount int handler *handler.Handler fanSpeedConsumer chan producer.FanspeedInfo sampleDuration time.Duration logger *zap.SugaredLogger } type FanControl interface { Consumer() chan<- producer.FanspeedInfo StartControl() } func NewFanControl(processorCount int, sampleDuration time.Duration, handler *handler.Handler) FanControl { return &fanControl{ processorCount: processorCount, handler: handler, fanSpeedConsumer: make(chan producer.FanspeedInfo, processorCount), sampleDuration: sampleDuration, logger: zlog.New(nil, "fanspeed"), } } func (c *fanControl) Consumer() chan<- producer.FanspeedInfo { return c.fanSpeedConsumer } func (c *fanControl) StartControl() { defer c.handler.DecreaseWait() defer func() { if err := recover(); err != nil { c.handler.NotifyError(err.(error)) } }() defer close(c.fanSpeedConsumer) defer c.logger.Info("Fan control stopped") c.logger.Info("Fan control started") ticker := time.Tick(c.sampleDuration) pastFanSpeedList, newFanSpeedList := make([]int, c.processorCount), make([]int, c.processorCount) for { select { case <-ticker: if !compareFanSpeed(pastFanSpeedList, newFanSpeedList) { copy(pastFanSpeedList, newFanSpeedList) go c.applyFanspeed(pastFanSpeedList) } case changedSpeed := <-c.fanSpeedConsumer: newFanSpeedList[changedSpeed.Id] = changedSpeed.FanSpeed case <-c.handler.Done(): return } } } func (c *fanControl) applyFanspeed(newFanSpeedList []int) { args := make([]string, 0) args = append(args, "raw", "0x3a", "0x01", ) for _, item := range newFanSpeedList { args = append(args, fmt.Sprintf("0x%x", item)) } args = append(args, "0x0", "0x0", "0x0", "0x0", "0x0", "0x0", ) cmd := exec.Command("ipmitool", args...) if err := cmd.Run(); err != nil { c.handler.NotifyError(err) return } buf := bytes.NewBufferString("") for _, item := range newFanSpeedList { buf.WriteString(fmt.Sprintf("0x%x", item)) buf.WriteRune(' ') } c.logger.Infof("Commit fan speed with %s", buf.String()) } func compareFanSpeed(old, new []int) bool { new = new[:len(old)] // this line is the key for i, v := range old { if v != new[i] { // here is no bounds checking for b[i] return false } } return true }