// Expose CPU stats using KVM.
func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) {
	if os.Geteuid() != 0 && os.Getegid() != 2 {
		return errors.New("caller should be either root user or kmem group to access /dev/mem")
	}

	var errbuf *C.char
	kd := C.kvm_open(nil, nil, nil, C.O_RDONLY, errbuf)
	if errbuf != nil {
		return errors.New("failed to call kvm_open()")
	}
	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]) / 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
}
// Expose CPU stats using KVM.
func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) {
	if os.Geteuid() != 0 && os.Getegid() != 2 {
		return errors.New("caller should be either root user or kmem group to access /dev/mem")
	}

	var errbuf *C.char
	kd := C.kvm_open(nil, nil, nil, C.O_RDONLY, errbuf)
	if errbuf != nil {
		return errors.New("failed to call kvm_open()")
	}
	defer C.kvm_close(kd)

	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.Collect(ch)
	return err
}