blob: 101c585684a87f2af5f214c6fd79f62797d73db7 [file] [log] [blame]
Brendan Gregg203b4c92016-10-18 12:10:24 -07001#!/usr/bin/python
2# @lint-avoid-python-3-compatibility-imports
3#
4# slabratetop Summarize kmem_cache_alloc() calls.
5# For Linux, uses BCC, eBPF.
6#
7# USAGE: slabratetop [-h] [-C] [-r MAXROWS] [interval] [count]
8#
9# This uses in-kernel BPF maps to store cache summaries for efficiency.
10#
11# SEE ALSO: slabtop(1), which shows the cache volumes.
12#
13# Copyright 2016 Netflix, Inc.
14# Licensed under the Apache License, Version 2.0 (the "License")
15#
16# 15-Oct-2016 Brendan Gregg Created this.
17
18from __future__ import print_function
19from bcc import BPF
Brenden Blanco42d60982017-04-24 14:31:28 -070020from bcc.utils import printb
Brendan Gregg203b4c92016-10-18 12:10:24 -070021from time import sleep, strftime
22import argparse
23import signal
24from subprocess import call
25
26# arguments
27examples = """examples:
28 ./slabratetop # kmem_cache_alloc() top, 1 second refresh
29 ./slabratetop -C # don't clear the screen
30 ./slabratetop 5 # 5 second summaries
31 ./slabratetop 5 10 # 5 second summaries, 10 times only
32"""
33parser = argparse.ArgumentParser(
34 description="Kernel SLAB/SLUB memory cache allocation rate top",
35 formatter_class=argparse.RawDescriptionHelpFormatter,
36 epilog=examples)
37parser.add_argument("-C", "--noclear", action="store_true",
38 help="don't clear the screen")
39parser.add_argument("-r", "--maxrows", default=20,
40 help="maximum rows to print, default 20")
41parser.add_argument("interval", nargs="?", default=1,
42 help="output interval, in seconds")
43parser.add_argument("count", nargs="?", default=99999999,
44 help="number of outputs")
Nathan Scottcf0792f2018-02-02 16:56:50 +110045parser.add_argument("--ebpf", action="store_true",
46 help=argparse.SUPPRESS)
Brendan Gregg203b4c92016-10-18 12:10:24 -070047args = parser.parse_args()
48interval = int(args.interval)
49countdown = int(args.count)
50maxrows = int(args.maxrows)
51clear = not int(args.noclear)
52debug = 0
53
54# linux stats
55loadavg = "/proc/loadavg"
56
57# signal handler
58def signal_ignore(signal, frame):
59 print()
60
61# define BPF program
62bpf_text = """
63#include <uapi/linux/ptrace.h>
64#include <linux/mm.h>
65#include <linux/slab.h>
Gary Linfa103452018-03-14 18:14:56 +080066#ifdef CONFIG_SLUB
Brendan Gregg203b4c92016-10-18 12:10:24 -070067#include <linux/slub_def.h>
Gary Linfa103452018-03-14 18:14:56 +080068#else
69#include <linux/slab_def.h>
70#endif
Brendan Gregg203b4c92016-10-18 12:10:24 -070071
72#define CACHE_NAME_SIZE 32
73
74// the key for the output summary
75struct info_t {
76 char name[CACHE_NAME_SIZE];
77};
78
79// the value of the output summary
80struct val_t {
81 u64 count;
82 u64 size;
83};
84
85BPF_HASH(counts, struct info_t, struct val_t);
86
87int kprobe__kmem_cache_alloc(struct pt_regs *ctx, struct kmem_cache *cachep)
88{
89 struct info_t info = {};
Paul Chaignonf86f7e82018-06-14 02:20:03 +020090 const char *name = cachep->name;
91 bpf_probe_read(&info.name, sizeof(info.name), name);
Brendan Gregg203b4c92016-10-18 12:10:24 -070092
93 struct val_t *valp, zero = {};
94 valp = counts.lookup_or_init(&info, &zero);
95 valp->count++;
96 valp->size += cachep->size;
97
98 return 0;
99}
100"""
Nathan Scottcf0792f2018-02-02 16:56:50 +1100101if debug or args.ebpf:
Brendan Gregg203b4c92016-10-18 12:10:24 -0700102 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100103 if args.ebpf:
104 exit()
Brendan Gregg203b4c92016-10-18 12:10:24 -0700105
106# initialize BPF
107b = BPF(text=bpf_text)
108
109print('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval)
110
111# output
112exiting = 0
113while 1:
114 try:
115 sleep(interval)
116 except KeyboardInterrupt:
117 exiting = 1
118
119 # header
120 if clear:
121 call("clear")
122 else:
123 print()
124 with open(loadavg) as stats:
125 print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read()))
126 print("%-32s %6s %10s" % ("CACHE", "ALLOCS", "BYTES"))
127
128 # by-TID output
129 counts = b.get_table("counts")
130 line = 0
131 for k, v in reversed(sorted(counts.items(),
132 key=lambda counts: counts[1].size)):
Brenden Blanco42d60982017-04-24 14:31:28 -0700133 printb(b"%-32s %6d %10d" % (k.name, v.count, v.size))
Brendan Gregg203b4c92016-10-18 12:10:24 -0700134
135 line += 1
136 if line >= maxrows:
137 break
138 counts.clear()
139
140 countdown -= 1
141 if exiting or countdown == 0:
142 print("Detaching...")
143 exit()