blob: aa1a7b4981d75426ae4ea769dd264652fe5dee75 [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
20from time import sleep, strftime
21import argparse
22import signal
23from subprocess import call
24
25# arguments
26examples = """examples:
27 ./slabratetop # kmem_cache_alloc() top, 1 second refresh
28 ./slabratetop -C # don't clear the screen
29 ./slabratetop 5 # 5 second summaries
30 ./slabratetop 5 10 # 5 second summaries, 10 times only
31"""
32parser = argparse.ArgumentParser(
33 description="Kernel SLAB/SLUB memory cache allocation rate top",
34 formatter_class=argparse.RawDescriptionHelpFormatter,
35 epilog=examples)
36parser.add_argument("-C", "--noclear", action="store_true",
37 help="don't clear the screen")
38parser.add_argument("-r", "--maxrows", default=20,
39 help="maximum rows to print, default 20")
40parser.add_argument("interval", nargs="?", default=1,
41 help="output interval, in seconds")
42parser.add_argument("count", nargs="?", default=99999999,
43 help="number of outputs")
44args = parser.parse_args()
45interval = int(args.interval)
46countdown = int(args.count)
47maxrows = int(args.maxrows)
48clear = not int(args.noclear)
49debug = 0
50
51# linux stats
52loadavg = "/proc/loadavg"
53
54# signal handler
55def signal_ignore(signal, frame):
56 print()
57
58# define BPF program
59bpf_text = """
60#include <uapi/linux/ptrace.h>
61#include <linux/mm.h>
62#include <linux/slab.h>
63#include <linux/slub_def.h>
64
65#define CACHE_NAME_SIZE 32
66
67// the key for the output summary
68struct info_t {
69 char name[CACHE_NAME_SIZE];
70};
71
72// the value of the output summary
73struct val_t {
74 u64 count;
75 u64 size;
76};
77
78BPF_HASH(counts, struct info_t, struct val_t);
79
80int kprobe__kmem_cache_alloc(struct pt_regs *ctx, struct kmem_cache *cachep)
81{
82 struct info_t info = {};
83 bpf_probe_read(&info.name, sizeof(info.name), (void *)cachep->name);
84
85 struct val_t *valp, zero = {};
86 valp = counts.lookup_or_init(&info, &zero);
87 valp->count++;
88 valp->size += cachep->size;
89
90 return 0;
91}
92"""
93if debug:
94 print(bpf_text)
95
96# initialize BPF
97b = BPF(text=bpf_text)
98
99print('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval)
100
101# output
102exiting = 0
103while 1:
104 try:
105 sleep(interval)
106 except KeyboardInterrupt:
107 exiting = 1
108
109 # header
110 if clear:
111 call("clear")
112 else:
113 print()
114 with open(loadavg) as stats:
115 print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read()))
116 print("%-32s %6s %10s" % ("CACHE", "ALLOCS", "BYTES"))
117
118 # by-TID output
119 counts = b.get_table("counts")
120 line = 0
121 for k, v in reversed(sorted(counts.items(),
122 key=lambda counts: counts[1].size)):
Rafael F78948e42017-03-26 14:54:25 +0200123 print("%-32s %6d %10d" % (k.name.decode(), v.count, v.size))
Brendan Gregg203b4c92016-10-18 12:10:24 -0700124
125 line += 1
126 if line >= maxrows:
127 break
128 counts.clear()
129
130 countdown -= 1
131 if exiting or countdown == 0:
132 print("Detaching...")
133 exit()