forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoffcputime.lua
More file actions
executable file
·118 lines (96 loc) · 3.04 KB
/
offcputime.lua
File metadata and controls
executable file
·118 lines (96 loc) · 3.04 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
#!/usr/bin/env bcc-lua
--[[
Copyright 2016 GitHub, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]
local program = [[
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
#define MINBLOCK_US 1
struct key_t {
char name[TASK_COMM_LEN];
int stack_id;
};
BPF_HASH(counts, struct key_t);
BPF_HASH(start, u32);
BPF_STACK_TRACE(stack_traces, 10240);
int oncpu(struct pt_regs *ctx, struct task_struct *prev) {
u32 pid;
u64 ts, *tsp;
// record previous thread sleep time
if (FILTER) {
pid = prev->pid;
ts = bpf_ktime_get_ns();
start.update(&pid, &ts);
}
// calculate current thread's delta time
pid = bpf_get_current_pid_tgid();
tsp = start.lookup(&pid);
if (tsp == 0)
return 0; // missed start or filtered
u64 delta = bpf_ktime_get_ns() - *tsp;
start.delete(&pid);
delta = delta / 1000;
if (delta < MINBLOCK_US)
return 0;
// create map key
u64 zero = 0, *val;
struct key_t key = {};
int stack_flags = 0;
/*
if (!(prev->flags & PF_KTHREAD))
stack_flags |= BPF_F_USER_STACK;
*/
bpf_get_current_comm(&key.name, sizeof(key.name));
key.stack_id = stack_traces.get_stackid(ctx, stack_flags);
val = counts.lookup_or_try_init(&key, &zero);
if (val) {
(*val) += delta;
}
return 0;
}
]]
return function(BPF, utils)
local ffi = require("ffi")
local parser = utils.argparse("offcputime", "Summarize off-cpu time")
parser:flag("-u --user-only")
parser:option("-p --pid"):convert(tonumber)
parser:flag("-f --folded")
parser:option("-d --duration", "duration to trace for", 9999999):convert(tonumber)
local args = parser:parse()
local ksym = BPF.SymbolCache()
local filter = "1"
local MAXDEPTH = 20
if args.pid then
filter = "pid == %d" % args.pid
elseif args.user_only then
filter = "!(prev->flags & PF_KTHREAD)"
end
local text = program:gsub("FILTER", filter)
local b = BPF:new{text=text}
b:attach_kprobe{event="finish_task_switch", fn_name="oncpu"}
if BPF.num_open_kprobes() == 0 then
print("no functions matched. quitting...")
return
end
print("Sleeping for %d seconds..." % args.duration)
pcall(utils.posix.sleep, args.duration)
print("Tracing...")
local counts = b:get_table("counts")
local stack_traces = b:get_table("stack_traces")
for k, v in counts:items() do
for addr in stack_traces:walk(tonumber(k.stack_id)) do
print(" %-16p %s" % {addr, ksym:resolve(addr)})
end
print(" %-16s %s" % {"-", ffi.string(k.name)})
print(" %d\n" % tonumber(v))
end
end