Skip to content

Commit 6cdc715

Browse files
committed
fix(topology): use cache ID to aggregate shared L3 caches among NUMA nodes
Signed-off-by: LavenderQAQ <lavenderqaq.cs@gmail.com>
1 parent bea5316 commit 6cdc715

1 file changed

Lines changed: 38 additions & 2 deletions

File tree

pkg/memory/memory_cache_linux.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,20 @@ func CachesForNode(ctx context.Context, nodeID int) ([]*Cache, error) {
8282
// unique combination of level, type and processor map
8383
level := memoryCacheLevel(ctx, paths, nodeID, lpID, cacheIndex)
8484
cacheType := memoryCacheType(ctx, paths, nodeID, lpID, cacheIndex)
85-
sharedCpuMap := memoryCacheSharedCPUMap(ctx, paths, nodeID, lpID, cacheIndex)
86-
cacheKey := fmt.Sprintf("%d-%d-%s", level, cacheType, sharedCpuMap)
85+
cacheID := memoryCacheID(ctx, paths, nodeID, lpID, cacheIndex)
86+
87+
// Generate cache key for deduplication.
88+
// Use cache ID if available (modern kernels), otherwise fall back
89+
// to shared_cpu_map for older kernels. This ensures that caches
90+
// shared across NUMA nodes (e.g., L3 in Sub-NUMA Clustering) are
91+
// correctly merged into a single cache object.
92+
var cacheKey string
93+
if cacheID != -1 {
94+
cacheKey = fmt.Sprintf("%d-%d-%d", level, cacheType, cacheID)
95+
} else {
96+
sharedCpuMap := memoryCacheSharedCPUMap(ctx, paths, nodeID, lpID, cacheIndex)
97+
cacheKey = fmt.Sprintf("%d-%d-%s", level, cacheType, sharedCpuMap)
98+
}
8799

88100
cache, exists := caches[cacheKey]
89101
if !exists {
@@ -141,6 +153,30 @@ func memoryCacheLevel(
141153
return level
142154
}
143155

156+
func memoryCacheID(
157+
ctx context.Context,
158+
paths *linuxpath.Paths,
159+
nodeID int,
160+
lpID int,
161+
cacheIndex int,
162+
) int {
163+
idPath := filepath.Join(
164+
paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex),
165+
"id",
166+
)
167+
idContents, err := os.ReadFile(idPath)
168+
if err != nil {
169+
// The id file may not exist in early kernel versions, so we don't warn
170+
return -1
171+
}
172+
id, err := strconv.Atoi(string(idContents[:len(idContents)-1]))
173+
if err != nil {
174+
log.Warn(ctx, "Unable to parse int from %s", idContents)
175+
return -1
176+
}
177+
return id
178+
}
179+
144180
func memoryCacheSize(
145181
ctx context.Context,
146182
paths *linuxpath.Paths,

0 commit comments

Comments
 (0)