forked from bpftrace/bpftrace
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrunqlat.bt
More file actions
206 lines (200 loc) · 9.67 KB
/
Copy pathrunqlat.bt
File metadata and controls
206 lines (200 loc) · 9.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env bpftrace
// runqlat.bt CPU scheduler run queue latency as a histogram.
// For Linux, uses bpftrace, eBPF.
//
// Example of usage:
//
// # ./runqlat.bt
// Attaching 5 probes...
// Tracing CPU scheduler... Hit Ctrl-C to end.
// ^C
//
//
//
// @usecs:
// [0] 1 | |
// [1] 11 |@@ |
// [2, 4) 16 |@@@ |
// [4, 8) 43 |@@@@@@@@@@ |
// [8, 16) 134 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
// [16, 32) 220 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
// [32, 64) 117 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
// [64, 128) 84 |@@@@@@@@@@@@@@@@@@@ |
// [128, 256) 10 |@@ |
// [256, 512) 2 | |
// [512, 1K) 5 |@ |
// [1K, 2K) 5 |@ |
// [2K, 4K) 5 |@ |
// [4K, 8K) 4 | |
// [8K, 16K) 1 | |
// [16K, 32K) 2 | |
// [32K, 64K) 0 | |
// [64K, 128K) 1 | |
// [128K, 256K) 0 | |
// [256K, 512K) 0 | |
// [512K, 1M) 1 | |
//
// This is an idle system where most of the time we are waiting for less than
// 128 microseconds, shown by the mode above. As an example of reading the output,
// the above histogram shows 220 scheduling events with a run queue latency of
// between 16 and 32 microseconds.
//
// The output also shows an outlier taking between 0.5 and 1 seconds: ??? XXX
// likely work was scheduled behind another higher priority task, and had to wait
// briefly. The kernel decides whether it is worth migrating such work to an
// idle CPU, or leaving it wait its turn on its current CPU run queue where
// the CPU caches should be hotter.
//
//
// I'll now add a single-threaded CPU bound workload to this system, and bind
// it on one CPU:
//
// # ./runqlat.bt
// Attaching 5 probes...
// Tracing CPU scheduler... Hit Ctrl-C to end.
// ^C
//
//
//
// @usecs:
// [1] 6 |@@@ |
// [2, 4) 26 |@@@@@@@@@@@@@ |
// [4, 8) 97 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
// [8, 16) 72 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
// [16, 32) 17 |@@@@@@@@@ |
// [32, 64) 19 |@@@@@@@@@@ |
// [64, 128) 20 |@@@@@@@@@@ |
// [128, 256) 3 |@ |
// [256, 512) 0 | |
// [512, 1K) 0 | |
// [1K, 2K) 1 | |
// [2K, 4K) 1 | |
// [4K, 8K) 4 |@@ |
// [8K, 16K) 3 |@ |
// [16K, 32K) 0 | |
// [32K, 64K) 0 | |
// [64K, 128K) 0 | |
// [128K, 256K) 1 | |
// [256K, 512K) 0 | |
// [512K, 1M) 0 | |
// [1M, 2M) 1 | |
//
// That didn't make much difference.
//
//
// Now I'll add a second single-threaded CPU workload, and bind it to the same
// CPU, causing contention:
//
// # ./runqlat.bt
// Attaching 5 probes...
// Tracing CPU scheduler... Hit Ctrl-C to end.
// ^C
//
//
//
// @usecs:
// [0] 1 | |
// [1] 8 |@@@ |
// [2, 4) 28 |@@@@@@@@@@@@ |
// [4, 8) 95 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
// [8, 16) 120 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
// [16, 32) 22 |@@@@@@@@@ |
// [32, 64) 10 |@@@@ |
// [64, 128) 7 |@@@ |
// [128, 256) 3 |@ |
// [256, 512) 1 | |
// [512, 1K) 0 | |
// [1K, 2K) 0 | |
// [2K, 4K) 2 | |
// [4K, 8K) 4 |@ |
// [8K, 16K) 107 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
// [16K, 32K) 0 | |
// [32K, 64K) 0 | |
// [64K, 128K) 0 | |
// [128K, 256K) 0 | |
// [256K, 512K) 1 | |
//
// There's now a second mode between 8 and 16 milliseconds, as each thread must
// wait its turn on the one CPU.
//
//
// Now I'll run 10 CPU-bound threads on one CPU:
//
// # ./runqlat.bt
// Attaching 5 probes...
// Tracing CPU scheduler... Hit Ctrl-C to end.
// ^C
//
//
//
// @usecs:
// [0] 2 | |
// [1] 10 |@ |
// [2, 4) 38 |@@@@ |
// [4, 8) 63 |@@@@@@ |
// [8, 16) 106 |@@@@@@@@@@@ |
// [16, 32) 28 |@@@ |
// [32, 64) 13 |@ |
// [64, 128) 15 |@ |
// [128, 256) 2 | |
// [256, 512) 2 | |
// [512, 1K) 1 | |
// [1K, 2K) 1 | |
// [2K, 4K) 2 | |
// [4K, 8K) 4 | |
// [8K, 16K) 3 | |
// [16K, 32K) 0 | |
// [32K, 64K) 478 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
// [64K, 128K) 1 | |
// [128K, 256K) 0 | |
// [256K, 512K) 0 | |
// [512K, 1M) 0 | |
// [1M, 2M) 1 | |
//
// This shows that most of the time threads need to wait their turn, with the
// largest mode between 32 and 64 milliseconds.
//
// This is a bpftrace version of the bcc tool of the same name.
// The bcc version provides options to customize the output.
//
// Copyright 2018 Netflix, Inc.
//
// 17-Sep-2018 Brendan Gregg Created this.
#ifndef BPFTRACE_HAVE_BTF
#include <linux/sched.h>
#else
// With BTF providing types, full headers are not needed.
// We only need to supply the preprocessor defines used in this script.
// TASK_RUNNING is not arch-dependant and has not changed in the linux
// git history (it is not part of the stable API though)
#define TASK_RUNNING 0
#endif
BEGIN
{
printf("Tracing CPU scheduler... Hit Ctrl-C to end.\n");
}
tracepoint:sched:sched_wakeup,
tracepoint:sched:sched_wakeup_new
{
@qtime[args.pid] = nsecs;
}
tracepoint:sched:sched_switch
{
if (args.prev_state == TASK_RUNNING) {
@qtime[args.prev_pid] = nsecs;
}
// Ignore the idle task
if (args.next_pid == 0) {
return;
}
$ns = @qtime[args.next_pid];
if $ns {
@usecs = hist((nsecs - $ns) / 1000);
// Swallowing deletion failures as they are expected
$ignore = delete(@qtime, args.next_pid);
}
}
END
{
clear(@qtime);
}