github.com/Cloud-Foundations/Dominator@v0.3.4/lib/cpulimiter/limiter.go (about) 1 package cpulimiter 2 3 import ( 4 "runtime" 5 "time" 6 7 "github.com/Cloud-Foundations/Dominator/lib/wsyscall" 8 ) 9 10 var minCheckInterval = time.Millisecond * 10 11 12 func newCpuLimiter(cpuPercent uint) *CpuLimiter { 13 cl := new(CpuLimiter) 14 cl.setCpuPercent(cpuPercent) 15 return cl 16 } 17 18 func (cl *CpuLimiter) getConfCpuPercent() uint { 19 cl.mutex.Lock() 20 defer cl.mutex.Unlock() 21 return cl.confCpuPercent 22 } 23 24 func (cl *CpuLimiter) limit() error { 25 cl.mutex.Lock() 26 defer cl.mutex.Unlock() 27 if cl.cpuPercent >= 100 { 28 return nil 29 } 30 now := time.Now() 31 if cl.lastProbeTime.IsZero() { // Initialise. 32 var rusage wsyscall.Rusage 33 err := wsyscall.Getrusage(wsyscall.RUSAGE_THREAD, &rusage) 34 if err != nil { 35 return err 36 } 37 cl.lastProbeTime = now 38 cl.lastProbeCpuTime = rusage.Utime 39 return nil 40 } 41 wallTimeSinceLastProbe := now.Sub(cl.lastProbeTime) 42 if wallTimeSinceLastProbe < minCheckInterval { 43 return nil 44 } 45 var rusage wsyscall.Rusage 46 if err := wsyscall.Getrusage(wsyscall.RUSAGE_THREAD, &rusage); err != nil { 47 return err 48 } 49 cpuTimeSinceLastProbe := time.Duration(rusage.Utime.Sec- 50 cl.lastProbeCpuTime.Sec) * time.Second 51 cpuTimeSinceLastProbe += time.Duration( 52 rusage.Utime.Usec-cl.lastProbeCpuTime.Usec) * time.Microsecond 53 sleepTime := cpuTimeSinceLastProbe*100/time.Duration(cl.cpuPercent) - 54 wallTimeSinceLastProbe 55 cl.mutex.Unlock() 56 time.Sleep(sleepTime) 57 cl.mutex.Lock() 58 cl.lastProbeTime = time.Now() 59 cl.lastProbeCpuTime = rusage.Utime 60 return nil 61 } 62 63 func (cl *CpuLimiter) setCpuPercent(cpuPercent uint) { 64 if cpuPercent < 1 { 65 cpuPercent = 1 66 } else if cpuPercent > 100 { 67 cpuPercent = 100 68 } 69 singleCpuPercent := cpuPercent * uint(runtime.NumCPU()) 70 if singleCpuPercent > 100 { 71 singleCpuPercent = 100 72 } 73 cl.mutex.Lock() 74 defer cl.mutex.Unlock() 75 cl.confCpuPercent = cpuPercent 76 cl.cpuPercent = singleCpuPercent 77 cl.lastProbeTime = time.Time{} // Reset calculations. 78 }