| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | // Copyright 2019 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-09-27 13:57:03 -07:00
										 |  |  | //go:build !norapl
 | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | // +build !norapl
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	"strconv" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 00:25:05 -08:00
										 |  |  | 	"github.com/alecthomas/kingpin/v2" | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | 	"github.com/prometheus/procfs/sysfs" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | const raplCollectorSubsystem = "rapl" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | type raplCollector struct { | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 	fs     sysfs.FS | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	logger *slog.Logger | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	joulesMetricDesc *prometheus.Desc | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 	registerCollector(raplCollectorSubsystem, defaultEnabled, NewRaplCollector) | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	raplZoneLabel = kingpin.Flag("collector.rapl.enable-zone-label", "Enables service unit metric unit_start_time_seconds").Bool() | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | // NewRaplCollector returns a new Collector exposing RAPL metrics.
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func NewRaplCollector(logger *slog.Logger) (Collector, error) { | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	fs, err := sysfs.NewFS(*sysPath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 	joulesMetricDesc := prometheus.NewDesc( | 
					
						
							|  |  |  | 		prometheus.BuildFQName(namespace, raplCollectorSubsystem, "joules_total"), | 
					
						
							|  |  |  | 		"Current RAPL value in joules", | 
					
						
							|  |  |  | 		[]string{"index", "path", "rapl_zone"}, nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	collector := raplCollector{ | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 		fs:               fs, | 
					
						
							|  |  |  | 		logger:           logger, | 
					
						
							|  |  |  | 		joulesMetricDesc: joulesMetricDesc, | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return &collector, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update implements Collector and exposes RAPL related metrics.
 | 
					
						
							|  |  |  | func (c *raplCollector) Update(ch chan<- prometheus.Metric) error { | 
					
						
							|  |  |  | 	// nil zones are fine when platform doesn't have powercap files present.
 | 
					
						
							|  |  |  | 	zones, err := sysfs.GetRaplZones(c.fs) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 		if errors.Is(err, os.ErrNotExist) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			c.logger.Debug("Platform doesn't have powercap files present", "err", err) | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 			return ErrNoData | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-02-05 09:16:17 -08:00
										 |  |  | 		if errors.Is(err, os.ErrPermission) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			c.logger.Debug("Can't access powercap files", "err", err) | 
					
						
							| 
									
										
										
										
											2021-02-05 09:16:17 -08:00
										 |  |  | 			return ErrNoData | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-01 07:21:36 -07:00
										 |  |  | 		return fmt.Errorf("failed to retrieve rapl stats: %w", err) | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, rz := range zones { | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 		microJoules, err := rz.GetEnergyMicrojoules() | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-21 10:28:54 -07:00
										 |  |  | 			if errors.Is(err, os.ErrPermission) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 				c.logger.Debug("Can't access energy_uj file", "zone", rz, "err", err) | 
					
						
							| 
									
										
										
										
											2021-07-21 10:28:54 -07:00
										 |  |  | 				return ErrNoData | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		joules := float64(microJoules) / 1000000.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if *raplZoneLabel { | 
					
						
							|  |  |  | 			ch <- c.joulesMetricWithZoneLabel(rz, joules) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ch <- c.joulesMetric(rz, joules) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-17 04:32:16 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-27 14:09:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (c *raplCollector) joulesMetric(z sysfs.RaplZone, v float64) prometheus.Metric { | 
					
						
							|  |  |  | 	index := strconv.Itoa(z.Index) | 
					
						
							|  |  |  | 	descriptor := prometheus.NewDesc( | 
					
						
							|  |  |  | 		prometheus.BuildFQName( | 
					
						
							|  |  |  | 			namespace, | 
					
						
							|  |  |  | 			raplCollectorSubsystem, | 
					
						
							|  |  |  | 			fmt.Sprintf("%s_joules_total", SanitizeMetricName(z.Name)), | 
					
						
							|  |  |  | 		), | 
					
						
							|  |  |  | 		fmt.Sprintf("Current RAPL %s value in joules", z.Name), | 
					
						
							|  |  |  | 		[]string{"index", "path"}, nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return prometheus.MustNewConstMetric( | 
					
						
							|  |  |  | 		descriptor, | 
					
						
							|  |  |  | 		prometheus.CounterValue, | 
					
						
							|  |  |  | 		v, | 
					
						
							|  |  |  | 		index, | 
					
						
							|  |  |  | 		z.Path, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *raplCollector) joulesMetricWithZoneLabel(z sysfs.RaplZone, v float64) prometheus.Metric { | 
					
						
							|  |  |  | 	index := strconv.Itoa(z.Index) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return prometheus.MustNewConstMetric( | 
					
						
							|  |  |  | 		c.joulesMetricDesc, | 
					
						
							|  |  |  | 		prometheus.CounterValue, | 
					
						
							|  |  |  | 		v, | 
					
						
							|  |  |  | 		index, | 
					
						
							|  |  |  | 		z.Path, | 
					
						
							|  |  |  | 		z.Name, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | } |