xref: /aosp_15_r20/external/bcc/tools/slabratetop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# slabratetop  Summarize kmem_cache_alloc() calls.
5*387f9dfdSAndroid Build Coastguard Worker#              For Linux, uses BCC, eBPF.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: slabratetop [-h] [-C] [-r MAXROWS] [interval] [count]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# This uses in-kernel BPF maps to store cache summaries for efficiency.
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# SEE ALSO: slabtop(1), which shows the cache volumes.
12*387f9dfdSAndroid Build Coastguard Worker#
13*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
14*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
15*387f9dfdSAndroid Build Coastguard Worker#
16*387f9dfdSAndroid Build Coastguard Worker# 15-Oct-2016   Brendan Gregg   Created this.
17*387f9dfdSAndroid Build Coastguard Worker# 23-Jan-2023   Rong Tao        Introduce kernel internal data structure and
18*387f9dfdSAndroid Build Coastguard Worker#                               functions to temporarily solve problem for
19*387f9dfdSAndroid Build Coastguard Worker#                               >=5.16(TODO: fix this workaround)
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
22*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
23*387f9dfdSAndroid Build Coastguard Workerfrom bcc.utils import printb
24*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
25*387f9dfdSAndroid Build Coastguard Workerimport argparse
26*387f9dfdSAndroid Build Coastguard Workerfrom subprocess import call
27*387f9dfdSAndroid Build Coastguard Worker
28*387f9dfdSAndroid Build Coastguard Worker# arguments
29*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
30*387f9dfdSAndroid Build Coastguard Worker    ./slabratetop            # kmem_cache_alloc() top, 1 second refresh
31*387f9dfdSAndroid Build Coastguard Worker    ./slabratetop -C         # don't clear the screen
32*387f9dfdSAndroid Build Coastguard Worker    ./slabratetop 5          # 5 second summaries
33*387f9dfdSAndroid Build Coastguard Worker    ./slabratetop 5 10       # 5 second summaries, 10 times only
34*387f9dfdSAndroid Build Coastguard Worker"""
35*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
36*387f9dfdSAndroid Build Coastguard Worker    description="Kernel SLAB/SLUB memory cache allocation rate top",
37*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
38*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
39*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--noclear", action="store_true",
40*387f9dfdSAndroid Build Coastguard Worker    help="don't clear the screen")
41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-r", "--maxrows", default=20,
42*387f9dfdSAndroid Build Coastguard Worker    help="maximum rows to print, default 20")
43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=1,
44*387f9dfdSAndroid Build Coastguard Worker    help="output interval, in seconds")
45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999,
46*387f9dfdSAndroid Build Coastguard Worker    help="number of outputs")
47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
48*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
49*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
50*387f9dfdSAndroid Build Coastguard Workerinterval = int(args.interval)
51*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count)
52*387f9dfdSAndroid Build Coastguard Workermaxrows = int(args.maxrows)
53*387f9dfdSAndroid Build Coastguard Workerclear = not int(args.noclear)
54*387f9dfdSAndroid Build Coastguard Workerdebug = 0
55*387f9dfdSAndroid Build Coastguard Worker
56*387f9dfdSAndroid Build Coastguard Worker# linux stats
57*387f9dfdSAndroid Build Coastguard Workerloadavg = "/proc/loadavg"
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker# define BPF program
60*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
61*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
62*387f9dfdSAndroid Build Coastguard Worker#include <linux/mm.h>
63*387f9dfdSAndroid Build Coastguard Worker#include <linux/kasan.h>
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker// memcg_cache_params is a part of kmem_cache, but is not publicly exposed in
66*387f9dfdSAndroid Build Coastguard Worker// kernel versions 5.4 to 5.8.  Define an empty struct for it here to allow the
67*387f9dfdSAndroid Build Coastguard Worker// bpf program to compile.  It has been completely removed in kernel version
68*387f9dfdSAndroid Build Coastguard Worker// 5.9, but it does not hurt to have it here for versions 5.4 to 5.8.
69*387f9dfdSAndroid Build Coastguard Workerstruct memcg_cache_params {};
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker// introduce kernel interval slab structure and slab_address() function, solved
72*387f9dfdSAndroid Build Coastguard Worker// 'undefined' error for >=5.16. TODO: we should fix this workaround if BCC
73*387f9dfdSAndroid Build Coastguard Worker// framework support BTF/CO-RE.
74*387f9dfdSAndroid Build Coastguard Workerstruct slab {
75*387f9dfdSAndroid Build Coastguard Worker    unsigned long __page_flags;
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker#if defined(CONFIG_SLAB)
78*387f9dfdSAndroid Build Coastguard Worker
79*387f9dfdSAndroid Build Coastguard Worker    struct kmem_cache *slab_cache;
80*387f9dfdSAndroid Build Coastguard Worker    union {
81*387f9dfdSAndroid Build Coastguard Worker        struct {
82*387f9dfdSAndroid Build Coastguard Worker            struct list_head slab_list;
83*387f9dfdSAndroid Build Coastguard Worker            void *freelist; /* array of free object indexes */
84*387f9dfdSAndroid Build Coastguard Worker            void *s_mem;    /* first object */
85*387f9dfdSAndroid Build Coastguard Worker        };
86*387f9dfdSAndroid Build Coastguard Worker        struct rcu_head rcu_head;
87*387f9dfdSAndroid Build Coastguard Worker    };
88*387f9dfdSAndroid Build Coastguard Worker    unsigned int active;
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker#elif defined(CONFIG_SLUB)
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker    struct kmem_cache *slab_cache;
93*387f9dfdSAndroid Build Coastguard Worker    union {
94*387f9dfdSAndroid Build Coastguard Worker        struct {
95*387f9dfdSAndroid Build Coastguard Worker            union {
96*387f9dfdSAndroid Build Coastguard Worker                struct list_head slab_list;
97*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_SLUB_CPU_PARTIAL
98*387f9dfdSAndroid Build Coastguard Worker                struct {
99*387f9dfdSAndroid Build Coastguard Worker                    struct slab *next;
100*387f9dfdSAndroid Build Coastguard Worker                        int slabs;      /* Nr of slabs left */
101*387f9dfdSAndroid Build Coastguard Worker                };
102*387f9dfdSAndroid Build Coastguard Worker#endif
103*387f9dfdSAndroid Build Coastguard Worker            };
104*387f9dfdSAndroid Build Coastguard Worker            /* Double-word boundary */
105*387f9dfdSAndroid Build Coastguard Worker            void *freelist;         /* first free object */
106*387f9dfdSAndroid Build Coastguard Worker            union {
107*387f9dfdSAndroid Build Coastguard Worker                unsigned long counters;
108*387f9dfdSAndroid Build Coastguard Worker                struct {
109*387f9dfdSAndroid Build Coastguard Worker                    unsigned inuse:16;
110*387f9dfdSAndroid Build Coastguard Worker                    unsigned objects:15;
111*387f9dfdSAndroid Build Coastguard Worker                    unsigned frozen:1;
112*387f9dfdSAndroid Build Coastguard Worker                };
113*387f9dfdSAndroid Build Coastguard Worker            };
114*387f9dfdSAndroid Build Coastguard Worker        };
115*387f9dfdSAndroid Build Coastguard Worker        struct rcu_head rcu_head;
116*387f9dfdSAndroid Build Coastguard Worker    };
117*387f9dfdSAndroid Build Coastguard Worker    unsigned int __unused;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker#elif defined(CONFIG_SLOB)
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker    struct list_head slab_list;
122*387f9dfdSAndroid Build Coastguard Worker    void *__unused_1;
123*387f9dfdSAndroid Build Coastguard Worker    void *freelist;         /* first free block */
124*387f9dfdSAndroid Build Coastguard Worker    long units;
125*387f9dfdSAndroid Build Coastguard Worker    unsigned int __unused_2;
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Worker#else
128*387f9dfdSAndroid Build Coastguard Worker#error "Unexpected slab allocator configured"
129*387f9dfdSAndroid Build Coastguard Worker#endif
130*387f9dfdSAndroid Build Coastguard Worker
131*387f9dfdSAndroid Build Coastguard Worker    atomic_t __page_refcount;
132*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_MEMCG
133*387f9dfdSAndroid Build Coastguard Worker    unsigned long memcg_data;
134*387f9dfdSAndroid Build Coastguard Worker#endif
135*387f9dfdSAndroid Build Coastguard Worker};
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker// slab_address() will not be used, and NULL will be returned directly, which
138*387f9dfdSAndroid Build Coastguard Worker// can avoid adaptation of different kernel versions
139*387f9dfdSAndroid Build Coastguard Workerstatic inline void *slab_address(const struct slab *slab)
140*387f9dfdSAndroid Build Coastguard Worker{
141*387f9dfdSAndroid Build Coastguard Worker    return NULL;
142*387f9dfdSAndroid Build Coastguard Worker}
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_64BIT
145*387f9dfdSAndroid Build Coastguard Workertypedef __uint128_t freelist_full_t;
146*387f9dfdSAndroid Build Coastguard Worker#else
147*387f9dfdSAndroid Build Coastguard Workertypedef u64 freelist_full_t;
148*387f9dfdSAndroid Build Coastguard Worker#endif
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Workertypedef union {
151*387f9dfdSAndroid Build Coastguard Worker	struct {
152*387f9dfdSAndroid Build Coastguard Worker		void *freelist;
153*387f9dfdSAndroid Build Coastguard Worker		unsigned long counter;
154*387f9dfdSAndroid Build Coastguard Worker	};
155*387f9dfdSAndroid Build Coastguard Worker	freelist_full_t full;
156*387f9dfdSAndroid Build Coastguard Worker} freelist_aba_t;
157*387f9dfdSAndroid Build Coastguard Worker
158*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_SLUB
159*387f9dfdSAndroid Build Coastguard Worker#include <linux/slub_def.h>
160*387f9dfdSAndroid Build Coastguard Worker#else
161*387f9dfdSAndroid Build Coastguard Worker#include <linux/slab_def.h>
162*387f9dfdSAndroid Build Coastguard Worker#endif
163*387f9dfdSAndroid Build Coastguard Worker
164*387f9dfdSAndroid Build Coastguard Worker#define CACHE_NAME_SIZE 32
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker// the key for the output summary
167*387f9dfdSAndroid Build Coastguard Workerstruct info_t {
168*387f9dfdSAndroid Build Coastguard Worker    char name[CACHE_NAME_SIZE];
169*387f9dfdSAndroid Build Coastguard Worker};
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Worker// the value of the output summary
172*387f9dfdSAndroid Build Coastguard Workerstruct val_t {
173*387f9dfdSAndroid Build Coastguard Worker    u64 count;
174*387f9dfdSAndroid Build Coastguard Worker    u64 size;
175*387f9dfdSAndroid Build Coastguard Worker};
176*387f9dfdSAndroid Build Coastguard Worker
177*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct info_t, struct val_t);
178*387f9dfdSAndroid Build Coastguard Worker
179*387f9dfdSAndroid Build Coastguard Workerint kprobe__kmem_cache_alloc(struct pt_regs *ctx, struct kmem_cache *cachep)
180*387f9dfdSAndroid Build Coastguard Worker{
181*387f9dfdSAndroid Build Coastguard Worker    struct info_t info = {};
182*387f9dfdSAndroid Build Coastguard Worker    const char *name = cachep->name;
183*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&info.name, sizeof(info.name), name);
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker    struct val_t *valp, zero = {};
186*387f9dfdSAndroid Build Coastguard Worker    valp = counts.lookup_or_try_init(&info, &zero);
187*387f9dfdSAndroid Build Coastguard Worker    if (valp) {
188*387f9dfdSAndroid Build Coastguard Worker        valp->count++;
189*387f9dfdSAndroid Build Coastguard Worker        valp->size += cachep->size;
190*387f9dfdSAndroid Build Coastguard Worker    }
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Worker    return 0;
193*387f9dfdSAndroid Build Coastguard Worker}
194*387f9dfdSAndroid Build Coastguard Worker"""
195*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
196*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
197*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
198*387f9dfdSAndroid Build Coastguard Worker        exit()
199*387f9dfdSAndroid Build Coastguard Worker
200*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
201*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
202*387f9dfdSAndroid Build Coastguard Worker
203*387f9dfdSAndroid Build Coastguard Workerprint('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval)
204*387f9dfdSAndroid Build Coastguard Worker
205*387f9dfdSAndroid Build Coastguard Worker# output
206*387f9dfdSAndroid Build Coastguard Workerexiting = 0
207*387f9dfdSAndroid Build Coastguard Workerwhile 1:
208*387f9dfdSAndroid Build Coastguard Worker    try:
209*387f9dfdSAndroid Build Coastguard Worker        sleep(interval)
210*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
211*387f9dfdSAndroid Build Coastguard Worker        exiting = 1
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Worker    # header
214*387f9dfdSAndroid Build Coastguard Worker    if clear:
215*387f9dfdSAndroid Build Coastguard Worker        call("clear")
216*387f9dfdSAndroid Build Coastguard Worker    else:
217*387f9dfdSAndroid Build Coastguard Worker        print()
218*387f9dfdSAndroid Build Coastguard Worker    with open(loadavg) as stats:
219*387f9dfdSAndroid Build Coastguard Worker        print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read()))
220*387f9dfdSAndroid Build Coastguard Worker    print("%-32s %6s %10s" % ("CACHE", "ALLOCS", "BYTES"))
221*387f9dfdSAndroid Build Coastguard Worker
222*387f9dfdSAndroid Build Coastguard Worker    # by-TID output
223*387f9dfdSAndroid Build Coastguard Worker    counts = b.get_table("counts")
224*387f9dfdSAndroid Build Coastguard Worker    line = 0
225*387f9dfdSAndroid Build Coastguard Worker    for k, v in reversed(sorted(counts.items(),
226*387f9dfdSAndroid Build Coastguard Worker                                key=lambda counts: counts[1].size)):
227*387f9dfdSAndroid Build Coastguard Worker        printb(b"%-32s %6d %10d" % (k.name, v.count, v.size))
228*387f9dfdSAndroid Build Coastguard Worker
229*387f9dfdSAndroid Build Coastguard Worker        line += 1
230*387f9dfdSAndroid Build Coastguard Worker        if line >= maxrows:
231*387f9dfdSAndroid Build Coastguard Worker            break
232*387f9dfdSAndroid Build Coastguard Worker    counts.clear()
233*387f9dfdSAndroid Build Coastguard Worker
234*387f9dfdSAndroid Build Coastguard Worker    countdown -= 1
235*387f9dfdSAndroid Build Coastguard Worker    if exiting or countdown == 0:
236*387f9dfdSAndroid Build Coastguard Worker        print("Detaching...")
237*387f9dfdSAndroid Build Coastguard Worker        exit()
238