|
|
|
|
@ -28,9 +28,26 @@ import ( |
|
|
|
|
#cgo LDFLAGS: -lkvm |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
#include <kvm.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <sys/param.h> |
|
|
|
|
#include <sys/pcpu.h> |
|
|
|
|
#include <sys/resource.h> |
|
|
|
|
#include <sys/sysctl.h> |
|
|
|
|
#include <sys/time.h> |
|
|
|
|
|
|
|
|
|
long _clockrate() { |
|
|
|
|
struct clockinfo clockrate; |
|
|
|
|
size_t size = sizeof(clockrate); |
|
|
|
|
int res = sysctlbyname("kern.clockrate", &clockrate, &size, NULL, 0); |
|
|
|
|
if (res == -1) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (size != sizeof(clockrate)) { |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
return clockrate.stathz > 0 ? clockrate.stathz : clockrate.hz; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
import "C" |
|
|
|
|
|
|
|
|
|
@ -70,16 +87,37 @@ func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) { |
|
|
|
|
} |
|
|
|
|
defer C.kvm_close(kd) |
|
|
|
|
|
|
|
|
|
// The cp_time variable is an array of CPUSTATES long integers -- in
|
|
|
|
|
// the same format as the kern.cp_time sysctl. According to the
|
|
|
|
|
// comments in sys/kern/kern_clock.c, the frequency of this timer will
|
|
|
|
|
// be stathz (or hz, if stathz is zero).
|
|
|
|
|
clockrate, err := getClockRate() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ncpus := C.kvm_getncpus(kd) |
|
|
|
|
for i := 0; i < int(ncpus); i++ { |
|
|
|
|
pcpu := C.kvm_getpcpu(kd, C.int(i)) |
|
|
|
|
cp_time := ((*C.struct_pcpu)(unsafe.Pointer(pcpu))).pc_cp_time |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "user"}).Set(float64(cp_time[C.CP_USER])) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "nice"}).Set(float64(cp_time[C.CP_NICE])) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "system"}).Set(float64(cp_time[C.CP_SYS])) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "interrupt"}).Set(float64(cp_time[C.CP_INTR])) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "idle"}).Set(float64(cp_time[C.CP_IDLE])) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "user"}).Set(float64(cp_time[C.CP_USER])/clockrate) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "nice"}).Set(float64(cp_time[C.CP_NICE])/clockrate) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "system"}).Set(float64(cp_time[C.CP_SYS])/clockrate) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "interrupt"}).Set(float64(cp_time[C.CP_INTR])/clockrate) |
|
|
|
|
c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "idle"}).Set(float64(cp_time[C.CP_IDLE])/clockrate) |
|
|
|
|
} |
|
|
|
|
c.cpu.Collect(ch) |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getClockRate() (float64, error) { |
|
|
|
|
clockrate := C._clockrate() |
|
|
|
|
if clockrate == -1 { |
|
|
|
|
return 0, errors.New("sysctl(kern.clockrate) failed") |
|
|
|
|
} else if clockrate == -2 { |
|
|
|
|
return 0, errors.New("sysctl(kern.clockrate) failed, wrong buffer size") |
|
|
|
|
} else if clockrate <= 0 { |
|
|
|
|
return 0, errors.New("sysctl(kern.clockrate) bad clocktime") |
|
|
|
|
} |
|
|
|
|
return float64(clockrate), nil |
|
|
|
|
} |
|
|
|
|
|