| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | // Copyright 2016 The Prometheus Authors
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-03 04:35:24 -07:00
										 |  |  | //go:build !nocpu
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | // +build !nocpu
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2020-02-19 05:34:05 -08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2016-09-17 05:05:36 -07:00
										 |  |  | 	"unsafe" | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | #cgo LDFLAGS: | 
					
						
							|  |  |  | #include <sys/sysctl.h> | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | #include <kinfo.h> | 
					
						
							| 
									
										
										
										
											2016-09-17 10:12:48 -07:00
										 |  |  | #include <stdlib.h> | 
					
						
							| 
									
										
										
										
											2016-09-18 05:16:26 -07:00
										 |  |  | #include <stdio.h> | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 05:16:26 -07:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2018-11-17 02:02:54 -08:00
										 |  |  | getCPUTimes(uint64_t **cputime, size_t *cpu_times_len) { | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	size_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	// Get number of cpu cores.
 | 
					
						
							|  |  |  | 	int mib[2]; | 
					
						
							| 
									
										
										
										
											2016-09-18 08:36:39 -07:00
										 |  |  | 	int ncpu; | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	mib[0] = CTL_HW; | 
					
						
							|  |  |  | 	mib[1] = HW_NCPU; | 
					
						
							| 
									
										
										
										
											2016-09-18 08:36:39 -07:00
										 |  |  | 	len = sizeof(ncpu); | 
					
						
							|  |  |  | 	if (sysctl(mib, 2, &ncpu, &len, NULL, 0)) { | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	// Get the cpu times.
 | 
					
						
							| 
									
										
										
										
											2016-09-18 08:36:39 -07:00
										 |  |  | 	struct kinfo_cputime cp_t[ncpu]; | 
					
						
							|  |  |  | 	bzero(cp_t, sizeof(struct kinfo_cputime)*ncpu); | 
					
						
							|  |  |  | 	len = sizeof(cp_t[0])*ncpu; | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	if (sysctlbyname("kern.cputime", &cp_t, &len, NULL, 0)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-20 14:27:56 -07:00
										 |  |  | 	*cpu_times_len = ncpu*CPUSTATES; | 
					
						
							| 
									
										
										
										
											2016-09-18 05:16:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	uint64_t user, nice, sys, intr, idle; | 
					
						
							|  |  |  | 	user = nice = sys = intr = idle = 0; | 
					
						
							| 
									
										
										
										
											2016-09-20 14:27:56 -07:00
										 |  |  | 	*cputime = (uint64_t *) malloc(sizeof(uint64_t)*(*cpu_times_len)); | 
					
						
							| 
									
										
										
										
											2016-09-18 08:36:39 -07:00
										 |  |  | 	for (int i = 0; i < ncpu; ++i) { | 
					
						
							| 
									
										
										
										
											2016-09-20 14:27:56 -07:00
										 |  |  | 		int offset = CPUSTATES * i; | 
					
						
							|  |  |  | 		(*cputime)[offset] = cp_t[i].cp_user; | 
					
						
							|  |  |  | 		(*cputime)[offset+1] = cp_t[i].cp_nice; | 
					
						
							|  |  |  | 		(*cputime)[offset+2] = cp_t[i].cp_sys; | 
					
						
							|  |  |  | 		(*cputime)[offset+3] = cp_t[i].cp_intr; | 
					
						
							|  |  |  | 		(*cputime)[offset+4] = cp_t[i].cp_idle; | 
					
						
							| 
									
										
										
										
											2016-09-17 09:50:08 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | import "C" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | const maxCPUTimesLen = C.MAXCPU * C.CPUSTATES | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | type statCollector struct { | 
					
						
							| 
									
										
										
										
											2019-12-31 08:19:37 -08:00
										 |  |  | 	cpu    *prometheus.Desc | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	logger *slog.Logger | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	registerCollector("cpu", defaultEnabled, NewStatCollector) | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-14 04:32:35 -07:00
										 |  |  | // NewStatCollector returns a new Collector exposing CPU stats.
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func NewStatCollector(logger *slog.Logger) (Collector, error) { | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	return &statCollector{ | 
					
						
							| 
									
										
										
										
											2019-12-31 08:19:37 -08:00
										 |  |  | 		cpu:    nodeCPUSecondsDesc, | 
					
						
							|  |  |  | 		logger: logger, | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | func getDragonFlyCPUTimes() ([]float64, error) { | 
					
						
							| 
									
										
										
										
											2020-09-03 10:39:19 -07:00
										 |  |  | 	// We want time spent per-CPU per CPUSTATE.
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	// CPUSTATES (number of CPUSTATES) is defined as 5U.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 10:12:48 -07:00
										 |  |  | 	// States: CP_USER | CP_NICE | CP_SYS | CP_IDLE | CP_INTR
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2018-11-17 02:02:54 -08:00
										 |  |  | 	// Each value is in microseconds
 | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Look into sys/kern/kern_clock.c for details.
 | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		cpuTimesC      *C.uint64_t | 
					
						
							|  |  |  | 		cpuTimesLength C.size_t | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-09-10 12:13:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-17 02:02:54 -08:00
										 |  |  | 	if C.getCPUTimes(&cpuTimesC, &cpuTimesLength) == -1 { | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | 		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 { | 
					
						
							| 
									
										
										
										
											2018-11-17 02:02:54 -08:00
										 |  |  | 		cpuTimes[i] = float64(value) / float64(1000000) | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | 	return cpuTimes, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-17 05:05:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | // Expose CPU stats using sysctl.
 | 
					
						
							|  |  |  | func (c *statCollector) Update(ch chan<- prometheus.Metric) error { | 
					
						
							|  |  |  | 	var fieldsCount = 5 | 
					
						
							|  |  |  | 	cpuTimes, err := getDragonFlyCPUTimes() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 05:16:26 -07:00
										 |  |  | 	// Export order: user nice sys intr idle
 | 
					
						
							|  |  |  | 	cpuFields := []string{"user", "nice", "sys", "interrupt", "idle"} | 
					
						
							| 
									
										
										
										
											2016-09-20 14:27:56 -07:00
										 |  |  | 	for i, value := range cpuTimes { | 
					
						
							| 
									
										
										
										
											2020-02-19 05:34:05 -08:00
										 |  |  | 		cpux := strconv.Itoa(i / fieldsCount) | 
					
						
							| 
									
										
										
										
											2016-09-28 00:10:05 -07:00
										 |  |  | 		ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, value, cpux, cpuFields[i%fieldsCount]) | 
					
						
							| 
									
										
										
										
											2016-09-17 05:43:29 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 05:16:26 -07:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-09-10 09:55:21 -07:00
										 |  |  | } |