Skip to content

Commit

Permalink
migration: introduce 'userfaultfd-wrlat.py' script
Browse files Browse the repository at this point in the history
Add BCC/eBPF script to analyze userfaultfd write fault latency distribution.

Signed-off-by: Andrey Gruzdev <[email protected]>
Reviewed-by: Peter Xu <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Dr. David Alan Gilbert <[email protected]>
  • Loading branch information
Andrey Gruzdev authored and dagrh committed Feb 8, 2021
1 parent 8518278 commit c724356
Showing 1 changed file with 122 additions and 0 deletions.
122 changes: 122 additions & 0 deletions scripts/userfaultfd-wrlat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/python3
#
# userfaultfd-wrlat Summarize userfaultfd write fault latencies.
# Events are continuously accumulated for the
# run, while latency distribution histogram is
# dumped each 'interval' seconds.
#
# For Linux, uses BCC, eBPF.
#
# USAGE: userfaultfd-lat [interval [count]]
#
# Copyright Virtuozzo GmbH, 2020
#
# Authors:
# Andrey Gruzdev <[email protected]>
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.

from __future__ import print_function
from bcc import BPF
from ctypes import c_ushort, c_int, c_ulonglong
from time import sleep
from sys import argv

def usage():
print("USAGE: %s [interval [count]]" % argv[0])
exit()

# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/mm.h>
BPF_HASH(ev_start, u32, u64);
BPF_HISTOGRAM(ev_delta_hist, u64);
/* Trace UFFD page fault start event. */
static void do_event_start()
{
/* Using "(u32)" to drop group ID which is upper 32 bits */
u32 tid = (u32) bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns();
ev_start.update(&tid, &ts);
}
/* Trace UFFD page fault end event. */
static void do_event_end()
{
/* Using "(u32)" to drop group ID which is upper 32 bits */
u32 tid = (u32) bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns();
u64 *tsp;
tsp = ev_start.lookup(&tid);
if (tsp) {
u64 delta = ts - (*tsp);
/* Transform time delta to milliseconds */
ev_delta_hist.increment(bpf_log2l(delta / 1000000));
ev_start.delete(&tid);
}
}
/* KPROBE for handle_userfault(). */
int probe_handle_userfault(struct pt_regs *ctx, struct vm_fault *vmf,
unsigned long reason)
{
/* Trace only UFFD write faults. */
if (reason & VM_UFFD_WP) {
do_event_start();
}
return 0;
}
/* KRETPROBE for handle_userfault(). */
int retprobe_handle_userfault(struct pt_regs *ctx)
{
do_event_end();
return 0;
}
"""

# arguments
interval = 10
count = -1
if len(argv) > 1:
try:
interval = int(argv[1])
if interval == 0:
raise
if len(argv) > 2:
count = int(argv[2])
except: # also catches -h, --help
usage()

# load BPF program
b = BPF(text=bpf_text)
# attach KRPOBEs
b.attach_kprobe(event="handle_userfault", fn_name="probe_handle_userfault")
b.attach_kretprobe(event="handle_userfault", fn_name="retprobe_handle_userfault")

# header
print("Tracing UFFD-WP write fault latency... Hit Ctrl-C to end.")

# output
loop = 0
do_exit = 0
while (1):
if count > 0:
loop += 1
if loop > count:
exit()
try:
sleep(interval)
except KeyboardInterrupt:
pass; do_exit = 1

print()
b["ev_delta_hist"].print_log2_hist("msecs")
if do_exit:
exit()

0 comments on commit c724356

Please sign in to comment.