forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Wenbo Zhang <[email protected]>
- Loading branch information
1 parent
3953c60
commit bf4668d
Showing
5 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
/opensnoop | ||
/readahead | ||
/runqslower | ||
/softirqs | ||
/syscount | ||
/tcpconnect | ||
/tcpconnlat | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ APPS = \ | |
opensnoop \ | ||
readahead \ | ||
runqslower \ | ||
softirqs \ | ||
syscount \ | ||
tcpconnect \ | ||
tcpconnlat \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (c) 2020 Wenbo Zhang | ||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include "softirqs.h" | ||
#include "bits.bpf.h" | ||
#include "maps.bpf.h" | ||
|
||
const volatile bool targ_dist = false; | ||
const volatile bool targ_ns = false; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, u32); | ||
__type(value, u64); | ||
} start SEC(".maps"); | ||
|
||
__u64 counts[NR_SOFTIRQS]; | ||
struct hist hists[NR_SOFTIRQS]; | ||
|
||
SEC("tp_btf/softirq_entry") | ||
int BPF_PROG(softirq_entry, unsigned int vec_nr) | ||
{ | ||
u64 ts = bpf_ktime_get_ns(); | ||
u32 key = 0; | ||
|
||
bpf_map_update_elem(&start, &key, &ts, 0); | ||
return 0; | ||
} | ||
|
||
SEC("tp_btf/softirq_exit") | ||
int BPF_PROG(softirq_exit, unsigned int vec_nr) | ||
{ | ||
u32 key = 0; | ||
s64 delta; | ||
u64 *tsp; | ||
|
||
if (vec_nr >= NR_SOFTIRQS) | ||
return 0; | ||
tsp = bpf_map_lookup_elem(&start, &key); | ||
if (!tsp || !*tsp) | ||
return 0; | ||
delta = bpf_ktime_get_ns() - *tsp; | ||
if (delta < 0) | ||
return 0; | ||
if (!targ_ns) | ||
delta /= 1000U; | ||
|
||
if (!targ_dist) { | ||
__sync_fetch_and_add(&counts[vec_nr], delta); | ||
} else { | ||
struct hist *hist; | ||
u64 slot; | ||
|
||
hist = &hists[vec_nr]; | ||
slot = log2(delta); | ||
if (slot >= MAX_SLOTS) | ||
slot = MAX_SLOTS - 1; | ||
__sync_fetch_and_add(&hist->slots[slot], 1); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
// Copyright (c) 2020 Wenbo Zhang | ||
// | ||
// Based on softirq(8) from BCC by Brendan Gregg & Sasha Goldshtein. | ||
// 15-Aug-2020 Wenbo Zhang Created this. | ||
#include <argp.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <time.h> | ||
#include <unistd.h> | ||
#include <bpf/libbpf.h> | ||
#include <bpf/bpf.h> | ||
#include "softirqs.h" | ||
#include "softirqs.skel.h" | ||
#include "trace_helpers.h" | ||
|
||
struct env { | ||
bool distributed; | ||
bool nanoseconds; | ||
time_t interval; | ||
int times; | ||
bool timestamp; | ||
bool verbose; | ||
} env = { | ||
.interval = 99999999, | ||
.times = 99999999, | ||
}; | ||
|
||
static volatile bool exiting; | ||
|
||
const char *argp_program_version = "softirqs 0.1"; | ||
const char *argp_program_bug_address = "<[email protected]>"; | ||
const char argp_program_doc[] = | ||
"Summarize soft irq event time as histograms.\n" | ||
"\n" | ||
"USAGE: softirqs [--help] [-T] [-N] [-d] [interval] [count]\n" | ||
"\n" | ||
"EXAMPLES:\n" | ||
" softirqss # sum soft irq event time\n" | ||
" softirqss -d # show soft irq event time as histograms\n" | ||
" softirqss 1 10 # print 1 second summaries, 10 times\n" | ||
" softirqss -NT 1 # 1s summaries, nanoseconds, and timestamps\n"; | ||
|
||
static const struct argp_option opts[] = { | ||
{ "distributed", 'd', NULL, 0, "Show distributions as histograms" }, | ||
{ "timestamp", 'T', NULL, 0, "Include timestamp on output" }, | ||
{ "nanoseconds", 'N', NULL, 0, "Output in nanoseconds" }, | ||
{ "verbose", 'v', NULL, 0, "Verbose debug output" }, | ||
{}, | ||
}; | ||
|
||
static error_t parse_arg(int key, char *arg, struct argp_state *state) | ||
{ | ||
static int pos_args; | ||
|
||
switch (key) { | ||
case 'v': | ||
env.verbose = true; | ||
break; | ||
case 'd': | ||
env.distributed = true; | ||
break; | ||
case 'N': | ||
env.nanoseconds = true; | ||
break; | ||
case 'T': | ||
env.timestamp = true; | ||
break; | ||
case ARGP_KEY_ARG: | ||
errno = 0; | ||
if (pos_args == 0) { | ||
env.interval = strtol(arg, NULL, 10); | ||
if (errno) { | ||
fprintf(stderr, "invalid internal\n"); | ||
argp_usage(state); | ||
} | ||
} else if (pos_args == 1) { | ||
env.times = strtol(arg, NULL, 10); | ||
if (errno) { | ||
fprintf(stderr, "invalid times\n"); | ||
argp_usage(state); | ||
} | ||
} else { | ||
fprintf(stderr, | ||
"unrecognized positional argument: %s\n", arg); | ||
argp_usage(state); | ||
} | ||
pos_args++; | ||
break; | ||
default: | ||
return ARGP_ERR_UNKNOWN; | ||
} | ||
return 0; | ||
} | ||
|
||
int libbpf_print_fn(enum libbpf_print_level level, | ||
const char *format, va_list args) | ||
{ | ||
if (level == LIBBPF_DEBUG && !env.verbose) | ||
return 0; | ||
return vfprintf(stderr, format, args); | ||
} | ||
|
||
static void sig_handler(int sig) | ||
{ | ||
exiting = true; | ||
} | ||
|
||
enum { | ||
HI_SOFTIRQ = 0, | ||
TIMER_SOFTIRQ = 1, | ||
NET_TX_SOFTIRQ = 2, | ||
NET_RX_SOFTIRQ = 3, | ||
BLOCK_SOFTIRQ = 4, | ||
IRQ_POLL_SOFTIRQ = 5, | ||
TASKLET_SOFTIRQ = 6, | ||
SCHED_SOFTIRQ = 7, | ||
HRTIMER_SOFTIRQ = 8, | ||
RCU_SOFTIRQ = 9, | ||
NR_SOFTIRQS = 10, | ||
}; | ||
|
||
static char *vec_names[] = { | ||
[HI_SOFTIRQ] = "hi", | ||
[TIMER_SOFTIRQ] = "timer", | ||
[NET_TX_SOFTIRQ] = "net_tx", | ||
[NET_RX_SOFTIRQ] = "net_rx", | ||
[BLOCK_SOFTIRQ] = "block", | ||
[IRQ_POLL_SOFTIRQ] = "irq_poll", | ||
[TASKLET_SOFTIRQ] = "tasklet", | ||
[SCHED_SOFTIRQ] = "sched", | ||
[HRTIMER_SOFTIRQ] = "hrtimer", | ||
[RCU_SOFTIRQ] = "rcu", | ||
}; | ||
|
||
static int print_count(struct softirqs_bpf__bss *bss) | ||
{ | ||
const char *units = env.nanoseconds ? "nsecs" : "usecs"; | ||
__u64 count; | ||
__u32 vec; | ||
|
||
printf("%-16s %6s%5s\n", "SOFTIRQ", "TOTAL_", units); | ||
|
||
for (vec = 0; vec < NR_SOFTIRQS; vec++) { | ||
count = __atomic_exchange_n(&bss->counts[vec], 0, | ||
__ATOMIC_RELAXED); | ||
if (count > 0) | ||
printf("%-16s %11llu\n", vec_names[vec], count); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static struct hist zero; | ||
|
||
static int print_hist(struct softirqs_bpf__bss *bss) | ||
{ | ||
const char *units = env.nanoseconds ? "nsecs" : "usecs"; | ||
__u32 vec; | ||
|
||
for (vec = 0; vec < NR_SOFTIRQS; vec++) { | ||
struct hist hist = bss->hists[vec]; | ||
|
||
bss->hists[vec] = zero; | ||
if (!memcmp(&zero, &hist, sizeof(hist))) | ||
continue; | ||
printf("softirq = %s\n", vec_names[vec]); | ||
print_log2_hist(hist.slots, MAX_SLOTS, units); | ||
printf("\n"); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
static const struct argp argp = { | ||
.options = opts, | ||
.parser = parse_arg, | ||
.doc = argp_program_doc, | ||
}; | ||
struct softirqs_bpf *obj; | ||
struct tm *tm; | ||
char ts[32]; | ||
time_t t; | ||
int err; | ||
|
||
err = argp_parse(&argp, argc, argv, 0, NULL, NULL); | ||
if (err) | ||
return err; | ||
|
||
libbpf_set_print(libbpf_print_fn); | ||
|
||
err = bump_memlock_rlimit(); | ||
if (err) { | ||
fprintf(stderr, "failed to increase rlimit: %d\n", err); | ||
return 1; | ||
} | ||
|
||
obj = softirqs_bpf__open(); | ||
if (!obj) { | ||
fprintf(stderr, "failed to open and/or load BPF object\n"); | ||
return 1; | ||
} | ||
|
||
/* initialize global data (filtering options) */ | ||
obj->rodata->targ_dist = env.distributed; | ||
obj->rodata->targ_ns = env.nanoseconds; | ||
|
||
err = softirqs_bpf__load(obj); | ||
if (err) { | ||
fprintf(stderr, "failed to load BPF object: %d\n", err); | ||
goto cleanup; | ||
} | ||
|
||
err = softirqs_bpf__attach(obj); | ||
if (err) { | ||
fprintf(stderr, "failed to attach BPF programs\n"); | ||
goto cleanup; | ||
} | ||
|
||
signal(SIGINT, sig_handler); | ||
|
||
printf("Tracing soft irq event time... Hit Ctrl-C to end.\n"); | ||
|
||
/* main: poll */ | ||
while (1) { | ||
sleep(env.interval); | ||
printf("\n"); | ||
|
||
if (env.timestamp) { | ||
time(&t); | ||
tm = localtime(&t); | ||
strftime(ts, sizeof(ts), "%H:%M:%S", tm); | ||
printf("%-8s\n", ts); | ||
} | ||
|
||
if (!env.distributed) | ||
err = print_count(obj->bss); | ||
else | ||
err = print_hist(obj->bss); | ||
if (err) | ||
break; | ||
|
||
if (exiting || --env.times == 0) | ||
break; | ||
} | ||
|
||
cleanup: | ||
softirqs_bpf__destroy(obj); | ||
|
||
return err != 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ | ||
#ifndef __SOFTIRQS_H | ||
#define __SOFTIRQS_H | ||
|
||
#define MAX_SLOTS 20 | ||
|
||
struct hist { | ||
__u32 slots[MAX_SLOTS]; | ||
}; | ||
|
||
#endif /* __SOFTIRQS_H */ |