Skip to content

Commit

Permalink
libbpf-tools: add CO-RE dcstat.
Browse files Browse the repository at this point in the history
dcstat is a simple tool that counts the various disk cache statistics.

Signed-off-by: Pratima Bhat <pratima.bhat@sony.com>
  • Loading branch information
Pratima12035 committed Apr 30, 2024
1 parent 679166b commit e14353c
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 0 deletions.
1 change: 1 addition & 0 deletions libbpf-tools/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
/capable
/cpudist
/cpufreq
/dcstat
/drsnoop
/execsnoop
/exitsnoop
Expand Down
1 change: 1 addition & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ APPS = \
capable \
cpudist \
cpufreq \
dcstat \
drsnoop \
execsnoop \
exitsnoop \
Expand Down
36 changes: 36 additions & 0 deletions libbpf-tools/dcstat.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright 2024 Sony Group Corporation
//
// Based on dcstat(8) from BCC by Brendan Gregg

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "dcstat.h"

__u64 stats[S_MAXSTAT] = {};

static __always_inline int inc_stats(int key)
{
__atomic_add_fetch(&stats[key], 1, __ATOMIC_RELAXED);
return 0;
}

SEC("kprobe/lookup_fast")
int BPF_KPROBE(lookup_fast)
{
return inc_stats(S_REFS);
}

SEC("kretprobe/d_lookup")
int BPF_KRETPROBE(d_lookup_ret)
{
inc_stats(S_SLOW);
if (PT_REGS_RC(ctx) == 0) {
inc_stats(S_MISS);
}

return 0;
}

char LICENSE[] SEC("license") = "GPL";
216 changes: 216 additions & 0 deletions libbpf-tools/dcstat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright 2024 Sony Group Corporation
//
// Based on dcstat(8) from BCC by Brendan Gregg

#include <argp.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bpf/bpf.h>
#include "dcstat.h"
#include "dcstat.skel.h"
#include "btf_helpers.h"
#include "trace_helpers.h"

const char *argp_program_version = "dcstat 0.1";
const char *argp_program_bug_address =
"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
static const char argp_program_doc[] =
"\ndcstat: Count various disk cache statistics\n"
"\n"
"EXAMPLES:\n"
" dcstat # interval one second\n"
" dcstat 5 3 # interval five seconds, three output lines\n";
static char args_doc[] = "[interval [count]]";

static const struct argp_option opts[] =
{
{ "verbose", 'v', NULL, 0, "Verbose debug output" },
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
{},
};

static struct env
{
bool verbose;
int count;
int interval;
} env = {
.interval = 1,
};

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
long interval;
long count;

switch (key) {
case 'h':
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
break;
case 'v':
env.verbose = true;
break;
case ARGP_KEY_ARG:
switch (state->arg_num) {
case 0:
errno = 0;
interval = strtol(arg, NULL, 10);
if (errno || interval <= 0 || interval > INT_MAX) {
fprintf(stderr, "invalid interval: %s\n", arg);
argp_usage(state);
}
env.interval = interval;
break;
case 1:
errno = 0;
count = strtol(arg, NULL, 10);
if (errno || count < 0 || count > INT_MAX) {
fprintf(stderr, "invalid count: %s\n", arg);
argp_usage(state);
}
env.count = count;
break;
default:
argp_usage(state);
break;
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}

static 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 const char *strftime_now(char *s, size_t max, const char *format)
{
struct tm *tm;
time_t t;

t = time(NULL);
tm = localtime(&t);
if (tm == NULL) {
fprintf(stderr, "localtime: %s\n", strerror(errno));
return "<failed>";
}

if (strftime(s, max, format, tm) == 0) {
fprintf(stderr, "strftime error\n");
return "<failed>";
}

return s;
}

static const char *stat_types_names[] =
{
[S_REFS] = "REFS",
[S_SLOW] = "SLOW",
[S_MISS] = "MISS",
};

void print_header(void)
{
int i;

printf("%-8s ", "TIME");
for (i = 0; i < S_MAXSTAT; i++) {
printf("%8s/s", stat_types_names[i]);
}
printf(" %-8s\n", "HITS");
}

static void print_and_reset_stats(__u64 stats[S_MAXSTAT])
{
char s[16];
__u64 val, ref, miss, hit;
double pct = 0;
int i;

printf("%-8s: ", strftime_now(s, sizeof(s), "%H:%M:%S"));
for (i = 0; i < S_MAXSTAT; i++) {
val = __atomic_exchange_n(&stats[i], 0, __ATOMIC_RELAXED);
if (i == 0)
ref = val;
if (i == 2)
miss = val;
printf(" %8llu", val / env.interval);
}
hit = ref - miss;
pct = 100.0 * hit / ref;
printf(" %8.2f\n", pct);
}

int main(int argc, char **argv)
{
LIBBPF_OPTS(bpf_object_open_opts, open_opts);
static const struct argp argp = {
.options = opts,
.parser = parse_arg,
.doc = argp_program_doc,
.args_doc = args_doc,
};
struct dcstat_bpf *skel;
int err;

err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
if (err)
return err;

libbpf_set_print(libbpf_print_fn);

err = ensure_core_btf(&open_opts);
if (err) {
fprintf(stderr, "failed to fetch necessary BTF for CO-RE: %s\n",
strerror(-err));
return 1;
}

skel = dcstat_bpf__open();
if (!skel) {
fprintf(stderr, "failed to open BPF skelect\n");
return 1;
}

err = dcstat_bpf__load(skel);
if (err) {
fprintf(stderr, "failed to load BPF skelect: %d\n", err);
goto cleanup;
}

if (!skel->bss) {
fprintf(stderr, "Memory-mapping BPF maps is supported starting from Linux "
"5.7, please upgrade.\n");
goto cleanup;
}

err = dcstat_bpf__attach(skel);
if (err) {
fprintf(stderr, "failed to attach BPF programs: %s\n",
strerror(-err));
goto cleanup;
}

print_header();
do {
sleep(env.interval);
print_and_reset_stats(skel->bss->stats);
} while (!env.count || --env.count);

cleanup:
dcstat_bpf__destroy(skel);
cleanup_core_btf(&open_opts);

return err != 0;
}
14 changes: 14 additions & 0 deletions libbpf-tools/dcstat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright 2024 Sony Group Corporation

#ifndef __DCSTAT_H
#define __DCSTAT_H

enum stats {
S_REFS,
S_SLOW,
S_MISS,
S_MAXSTAT
};

#endif /* __DCSTAT_H */

0 comments on commit e14353c

Please sign in to comment.