Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e78346e
resctrl-mon: OTel telemetry via goresctrl pkg/monitor
cmcantalupo Aug 21, 2026
1788d48
resctrl-mon: address review feedback on telemetry plugin and deployment
cmcantalupo Aug 26, 2026
d9196c4
resctrl-mon: point goresctrl dep at upstream main
cmcantalupo Sep 11, 2026
4b6a16d
resctrl-mon: preserve OTel accumulator across filter-only reloads
cmcantalupo Sep 11, 2026
ea44234
resctrl-mon: drop trailing blank line in Helm _helpers.tpl
cmcantalupo Sep 11, 2026
c4b3b6b
resctrl-mon: fix sync removal race and bound telemetry shutdown
cmcantalupo Sep 21, 2026
9456662
resctrl-mon: complete in-memory telemetry defaults
cmcantalupo Sep 21, 2026
45f0d6c
resctrl-mon: reap stale tracked groups on resync after missed teardown
cmcantalupo Sep 22, 2026
945c3c2
resctrl-mon: normalize empty telemetry collections to avoid spurious …
cmcantalupo Sep 23, 2026
29c65db
resctrl-mon: serialize NRI handlers and the background reconciler
cmcantalupo Sep 25, 2026
9a7757e
resctrl-mon: fix configuration at startup
cmcantalupo Sep 25, 2026
54cfed2
resctrl-mon: keep a pod's mon_group until its last sandbox is removed
cmcantalupo Sep 25, 2026
b2b695d
resctrl-mon: bound metrics collection rate on the Prometheus endpoint
cmcantalupo Sep 25, 2026
624fdc9
resctrl-mon: keep managing mon_groups when telemetry fails to start
cmcantalupo Sep 25, 2026
549f962
resctrl-mon: pin Prometheus naming and document exported metrics
cmcantalupo Sep 25, 2026
a3b19d0
resctrl-mon: stop the metrics server before the meter provider
cmcantalupo Sep 25, 2026
61130e3
resctrl-mon: fix stale reconciler comments
cmcantalupo Sep 25, 2026
ddcd9ca
resctrl-mon: document limitations
cmcantalupo Sep 25, 2026
f34b608
resctrl-mon: fix leftover stale comments; document config is read at …
cmcantalupo Sep 25, 2026
20ded8c
resctrl-mon: harden the reference OTel collector manifests
cmcantalupo Sep 25, 2026
c42b1f9
Makefile: drop install-plugins from the resctrl-mon series
cmcantalupo Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions cmd/plugins/resctrl-mon/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright The NRI Plugins Authors. All Rights Reserved.
//
// 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.

package main

import (
"path/filepath"
"strings"

"github.com/intel/goresctrl/pkg/monitor"
"go.opentelemetry.io/otel/attribute"
otelmetric "go.opentelemetry.io/otel/metric"
)

// coreAETFiles are counter files that appear under mon_PERF_PKG_* but are
// always exported (not gated by perfCounters.enabled).
var coreAETFiles = map[string]bool{
"core_energy": true,
"activity": true,
}

// resctrlManager is the subset of *monitor.Manager the plugin depends on.
// Defining it as an interface lets tests substitute a fake whose Reconcile
// records the live set instead of performing filesystem rmdir, which on tmpfs
// cannot delete a realistic mon_group the way the resctrl kernel does.
type resctrlManager interface {
EnsureGroup(key, rdtClass string) (*monitor.Group, error)
AssignPID(key string, pid int) error
Remove(key string) error
List() []string
Reconcile(live []string) error
RegisterOTelInstruments(meter otelmetric.Meter, opts ...monitor.OTelOption) (*monitor.Registration, error)
}

// setupMetrics registers OTel instruments via the goresctrl adapter.
func setupMetrics(mgr resctrlManager, cfg telemetryConfig, resctrlRoot string, meter otelmetric.Meter) (*monitor.Registration, error) {
return mgr.RegisterOTelInstruments(meter,
monitor.WithFilter(perfCounterFilter(cfg)),
monitor.WithAttributes(groupAttributesFor(resctrlRoot)),
)
}

// perfCounterFilter returns a FilterFunc that implements the perf counter gate.
func perfCounterFilter(cfg telemetryConfig) monitor.FilterFunc {
return func(r monitor.Reading) bool {
// Core AET files (core_energy, activity) are always allowed regardless
// of which domain they appear under.
if coreAETFiles[r.Name] {
return true
}
// Non-PERF_PKG domains (mon_L3_*) are always allowed.
if !strings.HasPrefix(r.Domain, "mon_PERF_PKG_") {
return true
}
// This is a perf counter under mon_PERF_PKG_*. Check the gate.
if !cfg.PerfCounters.Enabled {
return false
}
// Apply include/exclude lists if configured.
if len(cfg.PerfCounters.Include) > 0 {
for _, pattern := range cfg.PerfCounters.Include {
if matchGlob(pattern, r.Name) {
return true
}
}
return false
}
if len(cfg.PerfCounters.Exclude) > 0 {
for _, pattern := range cfg.PerfCounters.Exclude {
if matchGlob(pattern, r.Name) {
return false
}
}
}
return true
}
}

// groupAttributesFor returns a per-group OTel attribute function bound to the
// configured resctrl root, which is needed to recognize the root ctrl_group.
func groupAttributesFor(resctrlRoot string) monitor.AttributeFunc {
root := filepath.Clean(resctrlRoot)
return func(key, path string) []attribute.KeyValue {
return []attribute.KeyValue{
attribute.String("k8s.pod.uid", key),
attribute.String("resctrl.control_group", controlGroupOf(root, path)),
// The manager validates and tracks pod UIDs only, so every exported
// group is pod-sourced.
attribute.String("resctrl.group.source", "pod"),
}
}
}

// matchGlob does simple glob matching (only * is supported as wildcard).
func matchGlob(pattern, name string) bool {
if !strings.Contains(pattern, "*") {
return pattern == name
}
parts := strings.Split(pattern, "*")
// The name must start with the segment before the first '*' and end with
// the segment after the last '*'.
if !strings.HasPrefix(name, parts[0]) {
return false
}
name = name[len(parts[0]):]
last := parts[len(parts)-1]
if !strings.HasSuffix(name, last) {
return false
}
name = name[:len(name)-len(last)]
// Any interior segments must appear in order.
for _, seg := range parts[1 : len(parts)-1] {
i := strings.Index(name, seg)
if i < 0 {
return false
}
name = name[i+len(seg):]
}
return true
}

// controlGroupOf extracts the CTRL group name from a mon_group path, relative
// to the configured resctrl root.
// e.g. root=/sys/fs/resctrl, "/sys/fs/resctrl/COS1/mon_groups/abc-123" → "COS1"
// e.g. root=/sys/fs/resctrl, "/sys/fs/resctrl/mon_groups/abc-123" → "" (root)
func controlGroupOf(resctrlRoot, groupPath string) string {
ctrlDir := filepath.Dir(filepath.Dir(groupPath))
if filepath.Clean(ctrlDir) == filepath.Clean(resctrlRoot) {
return ""
}
return filepath.Base(ctrlDir)
}
Loading
Loading