123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- #!/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()
|