You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.0 KiB
117 lines
3.0 KiB
#!/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 = BPF_F_REUSE_STACKID;
|
|
|
|
/*
|
|
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_init(&key, &zero);
|
|
(*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
|