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  }