Skip to content

Commit

Permalink
libbpf-tools: add funclatency
Browse files Browse the repository at this point in the history
This is a port of BCC's funclatency.  Usage:

---------
Time functions and print latency as a histogram

Usage: funclatency [-h] [-m|-u] [-p PID] [-d DURATION] [ -i INTERVAL ]
                   [-T] FUNCTION
       Choices for FUNCTION: FUNCTION         (kprobe)
                             LIBRARY:FUNCTION (uprobe a library in -p PID)
                             :FUNCTION        (uprobe the binary of -p PID)

  -m, --milliseconds         Output in milliseconds
  -u, --microseconds         Output in microseconds
  -p, --pid=PID              Process ID to trace
  -d, --duration=DURATION    Duration to trace
  -i, --interval=INTERVAL    Summary interval in seconds
  -T, --timestamp            Print timestamp

  -?, --help                 Give this help list
      --usage                Give a short usage message
  -V, --version              Print program version

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

Examples:
  ./funclatency do_sys_open         # time the do_sys_open() kernel function
  ./funclatency -m do_nanosleep     # time do_nanosleep(), in milliseconds
  ./funclatency -u vfs_read         # time vfs_read(), in microseconds
  ./funclatency -p 181 vfs_read     # time process 181 only
  ./funclatency -p 181 c:read       # time the read() C library function
  ./funclatency -p 181 :foo         # time foo() from pid 181's userspace
  ./funclatency -i 2 -d 10 vfs_read # output every 2 seconds, for 10s
  ./funclatency -mTi 5 vfs_read     # output every 5 seconds, with timestamps

---------

It supports kprobes and has limited support for uprobes.  Currently, you
cannot uprobe a library unless you provide a PID.  It does not support
wildcard patterns.

Some of the functions for uprobes are useful for other programs, so I
put those in uprobe_helpers.{c,h}.

Signed-off-by: Barret Rhoden <[email protected]>
  • Loading branch information
Barret Rhoden authored and yonghong-song committed Mar 5, 2021
1 parent 9999397 commit 08d6340
Show file tree
Hide file tree
Showing 7 changed files with 675 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 @@ -9,6 +9,7 @@
/drsnoop
/execsnoop
/filelife
/funclatency
/hardirqs
/llcstat
/numamove
Expand Down
2 changes: 2 additions & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ APPS = \
drsnoop \
execsnoop \
filelife \
funclatency \
hardirqs \
llcstat \
numamove \
Expand All @@ -47,6 +48,7 @@ COMMON_OBJ = \
$(OUTPUT)/syscall_helpers.o \
$(OUTPUT)/errno_helpers.o \
$(OUTPUT)/map_helpers.o \
$(OUTPUT)/uprobe_helpers.o \
#

.PHONY: all
Expand Down
71 changes: 71 additions & 0 deletions libbpf-tools/funclatency.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021 Google LLC. */
#include "vmlinux.h"
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "funclatency.h"
#include "bits.bpf.h"

const volatile pid_t targ_tgid;
const volatile int units;

/* key: pid. value: start time */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_PIDS);
__type(key, u32);
__type(value, u64);
} starts SEC(".maps");

__u32 hist[MAX_SLOTS];

SEC("kprobe/dummy_kprobe")
int BPF_KPROBE(dummy_kprobe)
{
u64 id = bpf_get_current_pid_tgid();
u32 tgid = id >> 32;
u32 pid = id;
u64 nsec;

if (targ_tgid && targ_tgid != tgid)
return 0;
nsec = bpf_ktime_get_ns();
bpf_map_update_elem(&starts, &pid, &nsec, BPF_ANY);

return 0;
}

SEC("kretprobe/dummy_kretprobe")
int BPF_KRETPROBE(dummy_kretprobe)
{
u64 *start;
u64 nsec = bpf_ktime_get_ns();
u64 id = bpf_get_current_pid_tgid();
u32 pid = id;
u64 slot, delta;

start = bpf_map_lookup_elem(&starts, &pid);
if (!start)
return 0;

delta = nsec - *start;

switch (units) {
case USEC:
delta /= 1000;
break;
case MSEC:
delta /= 1000000;
break;
}

slot = log2l(delta);
if (slot >= MAX_SLOTS)
slot = MAX_SLOTS - 1;
__sync_fetch_and_add(&hist[slot], 1);

return 0;
}

char LICENSE[] SEC("license") = "GPL";
Loading

0 comments on commit 08d6340

Please sign in to comment.