Skip to content

Commit 39d28bc

Browse files
committed
collector/slabinfo: index duplicate slab entries
/proc/slabinfo can list the same slab name more than once, for example one cache per device instance. Labelling only by slab name therefore produces duplicate label sets, causing the registry to reject the scrape. Add an index label carrying each entry's position among entries sharing the same slab name. This preserves one series per kernel cache and keeps each entry's own counts and geometry. The label name matches the existing ordinal index convention used by other collectors. The ordinal follows /proc/slabinfo ordering and is not a stable identity. It is assigned after filtering so excluded slabs do not consume an index. Fixes #3506 Signed-off-by: Kyle Mason <kyle@kylemason.org>
1 parent ac83e37 commit 39d28bc

4 files changed

Lines changed: 239 additions & 56 deletions

File tree

‎collector/fixtures/e2e-64k-page-output.txt‎

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3774,34 +3774,34 @@ node_scrape_collector_success{collector="zfs"} 1
37743774
node_scrape_collector_success{collector="zoneinfo"} 1
37753775
# HELP node_slabinfo_active_objects The number of objects that are currently active (i.e., in use).
37763776
# TYPE node_slabinfo_active_objects gauge
3777-
node_slabinfo_active_objects{slab="dmaengine-unmap-128"} 1206
3778-
node_slabinfo_active_objects{slab="kmalloc-8192"} 132
3779-
node_slabinfo_active_objects{slab="kmem_cache"} 320
3780-
node_slabinfo_active_objects{slab="tw_sock_TCP"} 704
3777+
node_slabinfo_active_objects{index="0",slab="dmaengine-unmap-128"} 1206
3778+
node_slabinfo_active_objects{index="0",slab="kmalloc-8192"} 132
3779+
node_slabinfo_active_objects{index="0",slab="kmem_cache"} 320
3780+
node_slabinfo_active_objects{index="0",slab="tw_sock_TCP"} 704
37813781
# HELP node_slabinfo_object_size_bytes The size of objects in this slab, in bytes.
37823782
# TYPE node_slabinfo_object_size_bytes gauge
3783-
node_slabinfo_object_size_bytes{slab="dmaengine-unmap-128"} 1088
3784-
node_slabinfo_object_size_bytes{slab="kmalloc-8192"} 8192
3785-
node_slabinfo_object_size_bytes{slab="kmem_cache"} 256
3786-
node_slabinfo_object_size_bytes{slab="tw_sock_TCP"} 256
3783+
node_slabinfo_object_size_bytes{index="0",slab="dmaengine-unmap-128"} 1088
3784+
node_slabinfo_object_size_bytes{index="0",slab="kmalloc-8192"} 8192
3785+
node_slabinfo_object_size_bytes{index="0",slab="kmem_cache"} 256
3786+
node_slabinfo_object_size_bytes{index="0",slab="tw_sock_TCP"} 256
37873787
# HELP node_slabinfo_objects The total number of allocated objects (i.e., objects that are both in use and not in use).
37883788
# TYPE node_slabinfo_objects gauge
3789-
node_slabinfo_objects{slab="dmaengine-unmap-128"} 1320
3790-
node_slabinfo_objects{slab="kmalloc-8192"} 148
3791-
node_slabinfo_objects{slab="kmem_cache"} 320
3792-
node_slabinfo_objects{slab="tw_sock_TCP"} 864
3789+
node_slabinfo_objects{index="0",slab="dmaengine-unmap-128"} 1320
3790+
node_slabinfo_objects{index="0",slab="kmalloc-8192"} 148
3791+
node_slabinfo_objects{index="0",slab="kmem_cache"} 320
3792+
node_slabinfo_objects{index="0",slab="tw_sock_TCP"} 864
37933793
# HELP node_slabinfo_objects_per_slab The number of objects stored in each slab.
37943794
# TYPE node_slabinfo_objects_per_slab gauge
3795-
node_slabinfo_objects_per_slab{slab="dmaengine-unmap-128"} 30
3796-
node_slabinfo_objects_per_slab{slab="kmalloc-8192"} 4
3797-
node_slabinfo_objects_per_slab{slab="kmem_cache"} 32
3798-
node_slabinfo_objects_per_slab{slab="tw_sock_TCP"} 32
3795+
node_slabinfo_objects_per_slab{index="0",slab="dmaengine-unmap-128"} 30
3796+
node_slabinfo_objects_per_slab{index="0",slab="kmalloc-8192"} 4
3797+
node_slabinfo_objects_per_slab{index="0",slab="kmem_cache"} 32
3798+
node_slabinfo_objects_per_slab{index="0",slab="tw_sock_TCP"} 32
37993799
# HELP node_slabinfo_pages_per_slab The number of pages allocated for each slab.
38003800
# TYPE node_slabinfo_pages_per_slab gauge
3801-
node_slabinfo_pages_per_slab{slab="dmaengine-unmap-128"} 8
3802-
node_slabinfo_pages_per_slab{slab="kmalloc-8192"} 8
3803-
node_slabinfo_pages_per_slab{slab="kmem_cache"} 2
3804-
node_slabinfo_pages_per_slab{slab="tw_sock_TCP"} 2
3801+
node_slabinfo_pages_per_slab{index="0",slab="dmaengine-unmap-128"} 8
3802+
node_slabinfo_pages_per_slab{index="0",slab="kmalloc-8192"} 8
3803+
node_slabinfo_pages_per_slab{index="0",slab="kmem_cache"} 2
3804+
node_slabinfo_pages_per_slab{index="0",slab="tw_sock_TCP"} 2
38053805
# HELP node_sockstat_FRAG6_inuse Number of FRAG6 sockets in state inuse.
38063806
# TYPE node_sockstat_FRAG6_inuse gauge
38073807
node_sockstat_FRAG6_inuse 0

‎collector/fixtures/e2e-output.txt‎

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,34 +3806,34 @@ node_scrape_collector_success{collector="zfs"} 1
38063806
node_scrape_collector_success{collector="zoneinfo"} 1
38073807
# HELP node_slabinfo_active_objects The number of objects that are currently active (i.e., in use).
38083808
# TYPE node_slabinfo_active_objects gauge
3809-
node_slabinfo_active_objects{slab="dmaengine-unmap-128"} 1206
3810-
node_slabinfo_active_objects{slab="kmalloc-8192"} 132
3811-
node_slabinfo_active_objects{slab="kmem_cache"} 320
3812-
node_slabinfo_active_objects{slab="tw_sock_TCP"} 704
3809+
node_slabinfo_active_objects{index="0",slab="dmaengine-unmap-128"} 1206
3810+
node_slabinfo_active_objects{index="0",slab="kmalloc-8192"} 132
3811+
node_slabinfo_active_objects{index="0",slab="kmem_cache"} 320
3812+
node_slabinfo_active_objects{index="0",slab="tw_sock_TCP"} 704
38133813
# HELP node_slabinfo_object_size_bytes The size of objects in this slab, in bytes.
38143814
# TYPE node_slabinfo_object_size_bytes gauge
3815-
node_slabinfo_object_size_bytes{slab="dmaengine-unmap-128"} 1088
3816-
node_slabinfo_object_size_bytes{slab="kmalloc-8192"} 8192
3817-
node_slabinfo_object_size_bytes{slab="kmem_cache"} 256
3818-
node_slabinfo_object_size_bytes{slab="tw_sock_TCP"} 256
3815+
node_slabinfo_object_size_bytes{index="0",slab="dmaengine-unmap-128"} 1088
3816+
node_slabinfo_object_size_bytes{index="0",slab="kmalloc-8192"} 8192
3817+
node_slabinfo_object_size_bytes{index="0",slab="kmem_cache"} 256
3818+
node_slabinfo_object_size_bytes{index="0",slab="tw_sock_TCP"} 256
38193819
# HELP node_slabinfo_objects The total number of allocated objects (i.e., objects that are both in use and not in use).
38203820
# TYPE node_slabinfo_objects gauge
3821-
node_slabinfo_objects{slab="dmaengine-unmap-128"} 1320
3822-
node_slabinfo_objects{slab="kmalloc-8192"} 148
3823-
node_slabinfo_objects{slab="kmem_cache"} 320
3824-
node_slabinfo_objects{slab="tw_sock_TCP"} 864
3821+
node_slabinfo_objects{index="0",slab="dmaengine-unmap-128"} 1320
3822+
node_slabinfo_objects{index="0",slab="kmalloc-8192"} 148
3823+
node_slabinfo_objects{index="0",slab="kmem_cache"} 320
3824+
node_slabinfo_objects{index="0",slab="tw_sock_TCP"} 864
38253825
# HELP node_slabinfo_objects_per_slab The number of objects stored in each slab.
38263826
# TYPE node_slabinfo_objects_per_slab gauge
3827-
node_slabinfo_objects_per_slab{slab="dmaengine-unmap-128"} 30
3828-
node_slabinfo_objects_per_slab{slab="kmalloc-8192"} 4
3829-
node_slabinfo_objects_per_slab{slab="kmem_cache"} 32
3830-
node_slabinfo_objects_per_slab{slab="tw_sock_TCP"} 32
3827+
node_slabinfo_objects_per_slab{index="0",slab="dmaengine-unmap-128"} 30
3828+
node_slabinfo_objects_per_slab{index="0",slab="kmalloc-8192"} 4
3829+
node_slabinfo_objects_per_slab{index="0",slab="kmem_cache"} 32
3830+
node_slabinfo_objects_per_slab{index="0",slab="tw_sock_TCP"} 32
38313831
# HELP node_slabinfo_pages_per_slab The number of pages allocated for each slab.
38323832
# TYPE node_slabinfo_pages_per_slab gauge
3833-
node_slabinfo_pages_per_slab{slab="dmaengine-unmap-128"} 8
3834-
node_slabinfo_pages_per_slab{slab="kmalloc-8192"} 8
3835-
node_slabinfo_pages_per_slab{slab="kmem_cache"} 2
3836-
node_slabinfo_pages_per_slab{slab="tw_sock_TCP"} 2
3833+
node_slabinfo_pages_per_slab{index="0",slab="dmaengine-unmap-128"} 8
3834+
node_slabinfo_pages_per_slab{index="0",slab="kmalloc-8192"} 8
3835+
node_slabinfo_pages_per_slab{index="0",slab="kmem_cache"} 2
3836+
node_slabinfo_pages_per_slab{index="0",slab="tw_sock_TCP"} 2
38373837
# HELP node_sockstat_FRAG6_inuse Number of FRAG6 sockets in state inuse.
38383838
# TYPE node_sockstat_FRAG6_inuse gauge
38393839
node_sockstat_FRAG6_inuse 0

‎collector/slabinfo_linux.go‎

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package collector
1818
import (
1919
"fmt"
2020
"log/slog"
21+
"strconv"
2122

2223
"github.com/alecthomas/kingpin/v2"
2324
"github.com/prometheus/client_golang/prometheus"
@@ -50,7 +51,7 @@ func NewSlabinfoCollector(logger *slog.Logger) (Collector, error) {
5051
return &slabinfoCollector{logger: logger,
5152
fs: fs,
5253
subsystem: "slabinfo",
53-
labels: []string{"slab"},
54+
labels: []string{"slab", "index"},
5455
slabNameFilter: newDeviceFilter(*slabNameExclude, *slabNameInclude),
5556
}, nil
5657
}
@@ -61,71 +62,84 @@ func (c *slabinfoCollector) Update(ch chan<- prometheus.Metric) error {
6162
return fmt.Errorf("couldn't get %s: %w", c.subsystem, err)
6263
}
6364

65+
// /proc/slabinfo can list the same slab name more than once, for example one
66+
// cache per device instance. The kernel permits this: the duplicate-name check
67+
// in kmem_cache_sanity_check() only WARNs, and is compiled out unless
68+
// CONFIG_DEBUG_VM is set. Labelling by name alone therefore produces duplicate
69+
// label sets, which fails the entire scrape.
70+
//
71+
// Each entry is given its position among the entries sharing its name, so every
72+
// cache keeps its own series and its own geometry. The ordinal reflects the
73+
// order of /proc/slabinfo and is not a stable identity: if a cache is created
74+
// or destroyed, subsequent entries shift.
75+
seen := make(map[string]int, len(slabinfo.Slabs))
6476
for _, slab := range slabinfo.Slabs {
6577
if c.slabNameFilter.ignored(slab.Name) {
6678
continue
6779
}
68-
ch <- c.activeObjects(slab.Name, slab.ObjActive)
69-
ch <- c.objects(slab.Name, slab.ObjNum)
70-
ch <- c.objectSizeBytes(slab.Name, slab.ObjSize)
71-
ch <- c.objectsPerSlab(slab.Name, slab.ObjPerSlab)
72-
ch <- c.pagesPerSlab(slab.Name, slab.PagesPerSlab)
80+
index := strconv.Itoa(seen[slab.Name])
81+
seen[slab.Name]++
82+
ch <- c.activeObjects(slab.Name, index, slab.ObjActive)
83+
ch <- c.objects(slab.Name, index, slab.ObjNum)
84+
ch <- c.objectSizeBytes(slab.Name, index, slab.ObjSize)
85+
ch <- c.objectsPerSlab(slab.Name, index, slab.ObjPerSlab)
86+
ch <- c.pagesPerSlab(slab.Name, index, slab.PagesPerSlab)
7387
}
7488

7589
return nil
7690
}
7791

78-
func (c *slabinfoCollector) activeObjects(label string, val int64) prometheus.Metric {
92+
func (c *slabinfoCollector) activeObjects(label, index string, val int64) prometheus.Metric {
7993
desc := prometheus.NewDesc(
8094
prometheus.BuildFQName(namespace, c.subsystem, "active_objects"),
8195
"The number of objects that are currently active (i.e., in use).",
8296
c.labels, nil)
8397

8498
return prometheus.MustNewConstMetric(
85-
desc, prometheus.GaugeValue, float64(val), label,
99+
desc, prometheus.GaugeValue, float64(val), label, index,
86100
)
87101
}
88102

89-
func (c *slabinfoCollector) objects(label string, val int64) prometheus.Metric {
103+
func (c *slabinfoCollector) objects(label, index string, val int64) prometheus.Metric {
90104
desc := prometheus.NewDesc(
91105
prometheus.BuildFQName(namespace, c.subsystem, "objects"),
92106
"The total number of allocated objects (i.e., objects that are both in use and not in use).",
93107
c.labels, nil)
94108

95109
return prometheus.MustNewConstMetric(
96-
desc, prometheus.GaugeValue, float64(val), label,
110+
desc, prometheus.GaugeValue, float64(val), label, index,
97111
)
98112
}
99113

100-
func (c *slabinfoCollector) objectSizeBytes(label string, val int64) prometheus.Metric {
114+
func (c *slabinfoCollector) objectSizeBytes(label, index string, val int64) prometheus.Metric {
101115
desc := prometheus.NewDesc(
102116
prometheus.BuildFQName(namespace, c.subsystem, "object_size_bytes"),
103117
"The size of objects in this slab, in bytes.",
104118
c.labels, nil)
105119

106120
return prometheus.MustNewConstMetric(
107-
desc, prometheus.GaugeValue, float64(val), label,
121+
desc, prometheus.GaugeValue, float64(val), label, index,
108122
)
109123
}
110124

111-
func (c *slabinfoCollector) objectsPerSlab(label string, val int64) prometheus.Metric {
125+
func (c *slabinfoCollector) objectsPerSlab(label, index string, val int64) prometheus.Metric {
112126
desc := prometheus.NewDesc(
113127
prometheus.BuildFQName(namespace, c.subsystem, "objects_per_slab"),
114128
"The number of objects stored in each slab.",
115129
c.labels, nil)
116130

117131
return prometheus.MustNewConstMetric(
118-
desc, prometheus.GaugeValue, float64(val), label,
132+
desc, prometheus.GaugeValue, float64(val), label, index,
119133
)
120134
}
121135

122-
func (c *slabinfoCollector) pagesPerSlab(label string, val int64) prometheus.Metric {
136+
func (c *slabinfoCollector) pagesPerSlab(label, index string, val int64) prometheus.Metric {
123137
desc := prometheus.NewDesc(
124138
prometheus.BuildFQName(namespace, c.subsystem, "pages_per_slab"),
125139
"The number of pages allocated for each slab.",
126140
c.labels, nil)
127141

128142
return prometheus.MustNewConstMetric(
129-
desc, prometheus.GaugeValue, float64(val), label,
143+
desc, prometheus.GaugeValue, float64(val), label, index,
130144
)
131145
}

‎collector/slabinfo_linux_test.go‎

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Copyright 2026 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
//go:build !noslabinfo
15+
16+
package collector
17+
18+
import (
19+
"log/slog"
20+
"os"
21+
"path/filepath"
22+
"testing"
23+
24+
"github.com/prometheus/client_golang/prometheus"
25+
)
26+
27+
const slabinfoHeader = `slabinfo - version: 2.1
28+
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
29+
`
30+
31+
// writeSlabinfo writes body into a temporary procfs and points the collector at
32+
// it for the duration of the test. procPath is a package-global flag value, so
33+
// it is restored afterwards to keep these tests independent of execution order.
34+
// These tests must not call t.Parallel() for the same reason.
35+
func writeSlabinfo(t *testing.T, body string) {
36+
t.Helper()
37+
dir := t.TempDir()
38+
if err := os.WriteFile(filepath.Join(dir, "slabinfo"), []byte(slabinfoHeader+body), 0o644); err != nil {
39+
t.Fatal(err)
40+
}
41+
orig := *procPath
42+
t.Cleanup(func() { *procPath = orig })
43+
*procPath = dir
44+
}
45+
46+
// gatherSlabinfo collects through a registry, which is what surfaces duplicate
47+
// label sets, and keys the result by "metric/slab/index".
48+
func gatherSlabinfo(t *testing.T) map[string]float64 {
49+
t.Helper()
50+
c, err := NewSlabinfoCollector(slog.New(slog.NewTextHandler(os.Stderr, nil)))
51+
if err != nil {
52+
t.Fatal(err)
53+
}
54+
reg := prometheus.NewPedanticRegistry()
55+
if err := reg.Register(prometheus.CollectorFunc(func(ch chan<- prometheus.Metric) {
56+
if err := c.Update(ch); err != nil {
57+
t.Errorf("Update failed: %v", err)
58+
}
59+
})); err != nil {
60+
t.Fatal(err)
61+
}
62+
mfs, err := reg.Gather()
63+
if err != nil {
64+
t.Fatalf("Gather failed: %v", err)
65+
}
66+
got := map[string]float64{}
67+
for _, mf := range mfs {
68+
for _, m := range mf.Metric {
69+
var name, index string
70+
for _, l := range m.Label {
71+
switch l.GetName() {
72+
case "slab":
73+
name = l.GetValue()
74+
case "index":
75+
index = l.GetValue()
76+
}
77+
}
78+
got[mf.GetName()+"/"+name+"/"+index] = m.GetGauge().GetValue()
79+
}
80+
}
81+
return got
82+
}
83+
84+
func checkSlabinfo(t *testing.T, got map[string]float64, want map[string]float64) {
85+
t.Helper()
86+
for key, w := range want {
87+
if g, ok := got[key]; !ok {
88+
t.Errorf("%s: missing", key)
89+
} else if g != w {
90+
t.Errorf("%s: got %v, want %v", key, g, w)
91+
}
92+
}
93+
}
94+
95+
// A slab name may appear more than once, for example one cache per device
96+
// instance. Each entry keeps its own series, distinguished by the index label.
97+
func TestSlabinfoDuplicateSlabNames(t *testing.T) {
98+
writeSlabinfo(t, `kmem_cache 320 320 256 32 2 : tunables 0 0 0 : slabdata 10 10 0
99+
mlx5_fs_ftes 44 44 736 44 8 : tunables 0 0 0 : slabdata 1 1 0
100+
mlx5_fs_fgs 42 42 776 42 8 : tunables 0 0 0 : slabdata 1 1 0
101+
mlx5_fs_ftes 396 396 736 44 8 : tunables 0 0 0 : slabdata 9 9 0
102+
mlx5_fs_fgs 84 84 776 42 8 : tunables 0 0 0 : slabdata 2 2 0
103+
`)
104+
checkSlabinfo(t, gatherSlabinfo(t), map[string]float64{
105+
"node_slabinfo_active_objects/mlx5_fs_ftes/0": 44,
106+
"node_slabinfo_active_objects/mlx5_fs_ftes/1": 396,
107+
"node_slabinfo_objects/mlx5_fs_ftes/1": 396,
108+
"node_slabinfo_active_objects/mlx5_fs_fgs/0": 42,
109+
"node_slabinfo_active_objects/mlx5_fs_fgs/1": 84,
110+
"node_slabinfo_object_size_bytes/mlx5_fs_ftes/1": 736,
111+
"node_slabinfo_objects_per_slab/mlx5_fs_ftes/1": 44,
112+
"node_slabinfo_pages_per_slab/mlx5_fs_ftes/1": 8,
113+
"node_slabinfo_active_objects/kmem_cache/0": 320,
114+
})
115+
}
116+
117+
// Slabs with distinct names each get index 0.
118+
func TestSlabinfoDistinctSlabNames(t *testing.T) {
119+
writeSlabinfo(t, `tw_sock_TCP 704 864 256 32 2 : tunables 0 0 0 : slabdata 27 27 0
120+
kmem_cache 320 320 256 32 2 : tunables 0 0 0 : slabdata 10 10 0
121+
`)
122+
checkSlabinfo(t, gatherSlabinfo(t), map[string]float64{
123+
"node_slabinfo_active_objects/tw_sock_TCP/0": 704,
124+
"node_slabinfo_objects/tw_sock_TCP/0": 864,
125+
"node_slabinfo_active_objects/kmem_cache/0": 320,
126+
"node_slabinfo_objects/kmem_cache/0": 320,
127+
})
128+
}
129+
130+
// The kernel does not guarantee that same-named caches share geometry: the
131+
// duplicate-name check in kmem_cache_sanity_check() only WARNs and is compiled
132+
// out without CONFIG_DEBUG_VM, and object_size is per-cache. Indexing keeps each
133+
// cache's own geometry, so no representative value has to be chosen.
134+
func TestSlabinfoDuplicateSlabNamesDifferentGeometry(t *testing.T) {
135+
writeSlabinfo(t, `weird_cache 10 10 128 32 2 : tunables 0 0 0 : slabdata 1 1 0
136+
weird_cache 20 20 256 16 4 : tunables 0 0 0 : slabdata 2 2 0
137+
`)
138+
checkSlabinfo(t, gatherSlabinfo(t), map[string]float64{
139+
"node_slabinfo_active_objects/weird_cache/0": 10,
140+
"node_slabinfo_object_size_bytes/weird_cache/0": 128,
141+
"node_slabinfo_objects_per_slab/weird_cache/0": 32,
142+
"node_slabinfo_pages_per_slab/weird_cache/0": 2,
143+
"node_slabinfo_active_objects/weird_cache/1": 20,
144+
"node_slabinfo_object_size_bytes/weird_cache/1": 256,
145+
"node_slabinfo_objects_per_slab/weird_cache/1": 16,
146+
"node_slabinfo_pages_per_slab/weird_cache/1": 4,
147+
})
148+
}
149+
150+
// Excluded slabs must not consume an index, so the ordinals of the remaining
151+
// entries stay contiguous.
152+
func TestSlabinfoIndexIgnoresFilteredSlabs(t *testing.T) {
153+
orig := *slabNameExclude
154+
t.Cleanup(func() { *slabNameExclude = orig })
155+
*slabNameExclude = "^drop_me$"
156+
157+
writeSlabinfo(t, `dup_cache 10 10 128 32 2 : tunables 0 0 0 : slabdata 1 1 0
158+
drop_me 99 99 999 99 9 : tunables 0 0 0 : slabdata 9 9 0
159+
dup_cache 20 20 128 32 2 : tunables 0 0 0 : slabdata 2 2 0
160+
`)
161+
got := gatherSlabinfo(t)
162+
checkSlabinfo(t, got, map[string]float64{
163+
"node_slabinfo_active_objects/dup_cache/0": 10,
164+
"node_slabinfo_active_objects/dup_cache/1": 20,
165+
})
166+
if _, ok := got["node_slabinfo_active_objects/drop_me/0"]; ok {
167+
t.Error("excluded slab was collected")
168+
}
169+
}

0 commit comments

Comments
 (0)