| 
									
										
										
										
											2020-07-02 05:43:14 -07:00
										 |  |  | // Copyright 2020 The Prometheus Authors
 | 
					
						
							|  |  |  | // 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 !nointerrupts
 | 
					
						
							| 
									
										
										
										
											2020-07-02 05:43:14 -07:00
										 |  |  | // +build !nointerrupts
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"unsafe" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | 	"golang.org/x/sys/unix" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	KERN_INTRCNT        = 63 | 
					
						
							|  |  |  | 	KERN_INTRCNT_NUM    = 1 | 
					
						
							|  |  |  | 	KERN_INTRCNT_CNT    = 2 | 
					
						
							|  |  |  | 	KERN_INTRCNT_NAME   = 3 | 
					
						
							|  |  |  | 	KERN_INTRCNT_VECTOR = 4 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func nintr() _C_int { | 
					
						
							|  |  |  | 	mib := [3]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NUM} | 
					
						
							|  |  |  | 	buf, err := sysctl(mib[:]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return *(*_C_int)(unsafe.Pointer(&buf[0])) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func intr(idx _C_int) (itr interrupt, err error) { | 
					
						
							|  |  |  | 	mib := [4]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NAME, idx} | 
					
						
							|  |  |  | 	buf, err := sysctl(mib[:]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dev := *(*[128]byte)(unsafe.Pointer(&buf[0])) | 
					
						
							|  |  |  | 	itr.device = string(dev[:]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mib[2] = KERN_INTRCNT_VECTOR | 
					
						
							|  |  |  | 	buf, err = sysctl(mib[:]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	itr.vector = *(*int)(unsafe.Pointer(&buf[0])) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mib[2] = KERN_INTRCNT_CNT | 
					
						
							|  |  |  | 	buf, err = sysctl(mib[:]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	count := *(*uint64)(unsafe.Pointer(&buf[0])) | 
					
						
							|  |  |  | 	itr.values = []float64{float64(count)} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 04:54:40 -07:00
										 |  |  | var interruptLabelNames = []string{"cpu", "type", "devices"} | 
					
						
							| 
									
										
										
										
											2020-07-02 05:43:14 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) error { | 
					
						
							|  |  |  | 	interrupts, err := getInterrupts() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("couldn't get interrupts: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for dev, interrupt := range interrupts { | 
					
						
							|  |  |  | 		for cpuNo, value := range interrupt.values { | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 			interruptType := fmt.Sprintf("%d", interrupt.vector) | 
					
						
							|  |  |  | 			filterName := interruptType + ";" + dev | 
					
						
							|  |  |  | 			if c.nameFilter.ignored(filterName) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 				c.logger.Debug("ignoring interrupt name", "filter_name", filterName) | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !c.includeZeros && value == 0.0 { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 				c.logger.Debug("ignoring interrupt with zero value", "filter_name", filterName, "cpu", cpuNo) | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-07-02 05:43:14 -07:00
										 |  |  | 			ch <- c.desc.mustNewConstMetric( | 
					
						
							|  |  |  | 				value, | 
					
						
							|  |  |  | 				strconv.Itoa(cpuNo), | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 				interruptType, | 
					
						
							| 
									
										
										
										
											2020-07-02 05:43:14 -07:00
										 |  |  | 				dev, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type interrupt struct { | 
					
						
							|  |  |  | 	vector int | 
					
						
							|  |  |  | 	device string | 
					
						
							|  |  |  | 	values []float64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getInterrupts() (map[string]interrupt, error) { | 
					
						
							|  |  |  | 	var interrupts = map[string]interrupt{} | 
					
						
							|  |  |  | 	n := nintr() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := _C_int(0); i < n; i++ { | 
					
						
							|  |  |  | 		itr, err := intr(i) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		interrupts[itr.device] = itr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return interrupts, nil | 
					
						
							|  |  |  | } |