func getDragonFlyCPUTimes() ([]float64, error) { // We want time spent per-cpu per CPUSTATE. // CPUSTATES (number of CPUSTATES) is defined as 5U. // States: CP_USER | CP_NICE | CP_SYS | CP_IDLE | CP_INTR // // Each value is a counter incremented at frequency // kern.cputimer.freq // // Look into sys/kern/kern_clock.c for details. var ( cpuTimesC *C.uint64_t cpuTimerFreq C.long cpuTimesLength C.size_t ) if C.getCPUTimes(&cpuTimesC, &cpuTimesLength, &cpuTimerFreq) == -1 { return nil, errors.New("could not retrieve CPU times") } defer C.free(unsafe.Pointer(cpuTimesC)) cput := (*[maxCPUTimesLen]C.uint64_t)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength] cpuTimes := make([]float64, cpuTimesLength) for i, value := range cput { cpuTimes[i] = float64(value) / float64(cpuTimerFreq) } return cpuTimes, nil }
// Expose CPU stats using sysctl. func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) { // We want time spent per-cpu per CPUSTATE. // CPUSTATES (number of CPUSTATES) is defined as 5U. // Order: CP_USER | CP_NICE | CP_SYS | CP_IDLE | CP_INTR // sysctl kern.cp_times provides hw.ncpu * CPUSTATES long integers: // hw.ncpu * (space-separated list of the above variables) // // Each value is a counter incremented at frequency // kern.clockrate.(stathz | hz) // // Look into sys/kern/kern_clock.c for details. var ncpu C.int var cpuTimesC *C.double var cpuTimesLength C.size_t if C.getCPUTimes(&ncpu, &cpuTimesC, &cpuTimesLength) == -1 { return errors.New("could not retrieve CPU times") } defer C.freeCPUTimes(cpuTimesC) if cpuTimesLength > maxCPUTimesLen { return errors.New("more CPU's than MAXCPU?") } // Convert C.double array to Go array (https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices). cpuTimes := (*[maxCPUTimesLen]C.double)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength] for cpu := 0; cpu < int(ncpu); cpu++ { base_idx := C.CPUSTATES * cpu c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(cpu), "mode": "user"}).Set(float64(cpuTimes[base_idx+C.CP_USER])) c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(cpu), "mode": "nice"}).Set(float64(cpuTimes[base_idx+C.CP_NICE])) c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(cpu), "mode": "system"}).Set(float64(cpuTimes[base_idx+C.CP_SYS])) c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(cpu), "mode": "interrupt"}).Set(float64(cpuTimes[base_idx+C.CP_INTR])) c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(cpu), "mode": "idle"}).Set(float64(cpuTimes[base_idx+C.CP_IDLE])) } c.cpu.Collect(ch) return err }