migration: introduce 'userfaultfd-wrlat.py' script
Add BCC/eBPF script to analyze userfaultfd write fault latency distribution. Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com> Reviewed-by: Peter Xu <peterx@redhat.com> Message-Id: <20210129101407.103458-6-andrey.gruzdev@virtuozzo.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
parent
8518278a6a
commit
c7243566d0
122
scripts/userfaultfd-wrlat.py
Executable file
122
scripts/userfaultfd-wrlat.py
Executable file
@ -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 <andrey.gruzdev@virtuozzo.com>
|
||||||
|
#
|
||||||
|
# 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()
|
Loading…
Reference in New Issue
Block a user