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
0d9e091
commit 34f8985
Showing
7 changed files
with
324 additions
and
23 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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/.output | ||
/bitesize | ||
/cpudist | ||
/drsnoop | ||
/execsnoop | ||
|
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
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,59 @@ | ||
// 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 "bitesize.h" | ||
#include "bits.bpf.h" | ||
|
||
const volatile char targ_comm[TASK_COMM_LEN] = {}; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(max_entries, 10240); | ||
__type(key, struct hist_key); | ||
__type(value, struct hist); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
} hists SEC(".maps"); | ||
|
||
static struct hist initial_hist; | ||
|
||
static __always_inline bool comm_filtered(const char *comm) | ||
{ | ||
int i; | ||
|
||
for (i = 0; targ_comm[i] != '\0' && i < TASK_COMM_LEN; i++) { | ||
if (comm[i] != targ_comm[i]) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
SEC("tp_btf/block_rq_issue") | ||
int BPF_PROG(tp_btf__block_rq_issue, struct request_queue *q, | ||
struct request *rq) | ||
{ | ||
struct hist_key hkey; | ||
struct hist *histp; | ||
u64 slot; | ||
|
||
bpf_get_current_comm(&hkey.comm, sizeof(hkey.comm)); | ||
if (!comm_filtered(hkey.comm)) | ||
return 0; | ||
|
||
histp = bpf_map_lookup_elem(&hists, &hkey); | ||
if (!histp) { | ||
bpf_map_update_elem(&hists, &hkey, &initial_hist, 0); | ||
histp = bpf_map_lookup_elem(&hists, &hkey); | ||
if (!histp) | ||
return 0; | ||
} | ||
slot = log2l(rq->__data_len / 1024); | ||
if (slot >= MAX_SLOTS) | ||
slot = MAX_SLOTS - 1; | ||
__sync_fetch_and_add(&histp->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,219 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
// Copyright (c) 2020 Wenbo Zhang | ||
// | ||
// Based on bitesize(8) from BCC by Brendan Gregg. | ||
// 16-Jun-2020 Wenbo Zhang Created this. | ||
#include <argp.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <time.h> | ||
#include <bpf/libbpf.h> | ||
#include <bpf/bpf.h> | ||
#include "bitesize.h" | ||
#include "bitesize.skel.h" | ||
#include "trace_helpers.h" | ||
|
||
static struct env { | ||
char *comm; | ||
int comm_len; | ||
time_t interval; | ||
bool timestamp; | ||
bool verbose; | ||
int times; | ||
} env = { | ||
.interval = 99999999, | ||
.times = 99999999, | ||
}; | ||
|
||
static volatile bool exiting; | ||
|
||
const char *argp_program_version = "bitesize 0.1"; | ||
const char *argp_program_bug_address = "<[email protected]>"; | ||
const char argp_program_doc[] = | ||
"Summarize block device I/O size as a histogram.\n" | ||
"\n" | ||
"USAGE: bitesize [-h] [-T] [-m] [interval] [count]\n" | ||
"\n" | ||
"EXAMPLES:\n" | ||
" bitesize # summarize block I/O latency as a histogram\n" | ||
" bitesize 1 10 # print 1 second summaries, 10 times\n" | ||
" bitesize -T 1 # 1s summaries with timestamps\n" | ||
" bitesize -c fio # trace fio only\n"; | ||
|
||
static const struct argp_option opts[] = { | ||
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" }, | ||
{ "timestamp", 'T', NULL, 0, "Include timestamp on output" }, | ||
{ "comm", 'c', "COMM", 0, "Trace this comm only" }, | ||
{ "verbose", 'v', NULL, 0, "Verbose debug output" }, | ||
{}, | ||
}; | ||
|
||
static error_t parse_arg(int key, char *arg, struct argp_state *state) | ||
{ | ||
static int pos_args, len; | ||
|
||
switch (key) { | ||
case 'v': | ||
env.verbose = true; | ||
break; | ||
case 'h': | ||
argp_usage(state); | ||
break; | ||
case 'c': | ||
env.comm = arg; | ||
len = strlen(arg) + 1; | ||
env.comm_len = len > TASK_COMM_LEN ? TASK_COMM_LEN : len; | ||
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; | ||
} | ||
|
||
static int print_log2_hists(int fd) | ||
{ | ||
struct hist_key lookup_key, next_key; | ||
struct hist hist; | ||
int err; | ||
|
||
memset(lookup_key.comm, '?', sizeof(lookup_key.comm)); | ||
while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) { | ||
err = bpf_map_lookup_elem(fd, &next_key, &hist); | ||
if (err < 0) { | ||
fprintf(stderr, "failed to lookup hist: %d\n", err); | ||
return -1; | ||
} | ||
printf("\nProcess Name = %s\n", next_key.comm); | ||
print_log2_hist(hist.slots, MAX_SLOTS, "Kbytes"); | ||
lookup_key = next_key; | ||
} | ||
|
||
memset(lookup_key.comm, '?', sizeof(lookup_key.comm)); | ||
while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) { | ||
err = bpf_map_delete_elem(fd, &next_key); | ||
if (err < 0) { | ||
fprintf(stderr, "failed to cleanup hist : %d\n", err); | ||
return -1; | ||
} | ||
lookup_key = next_key; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
static const struct argp argp = { | ||
.options = opts, | ||
.parser = parse_arg, | ||
.doc = argp_program_doc, | ||
}; | ||
struct bitesize_bpf *obj; | ||
struct tm *tm; | ||
char ts[32]; | ||
int fd, err; | ||
time_t t; | ||
|
||
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 = bitesize_bpf__open(); | ||
if (!obj) { | ||
fprintf(stderr, "failed to open and/or load BPF ojbect\n"); | ||
return 1; | ||
} | ||
|
||
/* initialize global data (filtering options) */ | ||
if (env.comm) | ||
strncpy((char*)obj->rodata->targ_comm, env.comm, env.comm_len); | ||
|
||
err = bitesize_bpf__load(obj); | ||
if (err) { | ||
fprintf(stderr, "failed to load BPF object: %d\n", err); | ||
goto cleanup; | ||
} | ||
|
||
err = bitesize_bpf__attach(obj); | ||
if (err) { | ||
fprintf(stderr, "failed to attach BPF programs\n"); | ||
goto cleanup; | ||
} | ||
|
||
fd = bpf_map__fd(obj->maps.hists); | ||
|
||
signal(SIGINT, sig_handler); | ||
|
||
printf("Tracing block device I/O... 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); | ||
} | ||
|
||
err = print_log2_hists(fd); | ||
if (err) | ||
break; | ||
|
||
if (exiting || --env.times == 0) | ||
break; | ||
} | ||
|
||
cleanup: | ||
bitesize_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,15 @@ | ||
#ifndef __BITESIZE_H | ||
#define __BITESIZE_H | ||
|
||
#define TASK_COMM_LEN 16 | ||
#define MAX_SLOTS 20 | ||
|
||
struct hist_key { | ||
char comm[TASK_COMM_LEN]; | ||
}; | ||
|
||
struct hist { | ||
__u32 slots[MAX_SLOTS]; | ||
}; | ||
|
||
#endif /* __BITESIZE_H */ |
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,28 @@ | ||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ | ||
#ifndef __BITS_BPF_H | ||
#define __BITS_BPF_H | ||
|
||
static __always_inline u64 log2(u32 v) | ||
{ | ||
u32 shift, r; | ||
|
||
r = (v > 0xFFFF) << 4; v >>= r; | ||
shift = (v > 0xFF) << 3; v >>= shift; r |= shift; | ||
shift = (v > 0xF) << 2; v >>= shift; r |= shift; | ||
shift = (v > 0x3) << 1; v >>= shift; r |= shift; | ||
r |= (v >> 1); | ||
|
||
return r; | ||
} | ||
|
||
static __always_inline u64 log2l(u64 v) | ||
{ | ||
u32 hi = v >> 32; | ||
|
||
if (hi) | ||
return log2(hi) + 32; | ||
else | ||
return log2(v); | ||
} | ||
|
||
#endif /* __BITS_BPF_H */ |
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