qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

userfaultfd-wrlat.py (2938B)


      1 #!/usr/bin/python3
      2 #
      3 # userfaultfd-wrlat Summarize userfaultfd write fault latencies.
      4 #                   Events are continuously accumulated for the
      5 #                   run, while latency distribution histogram is
      6 #                   dumped each 'interval' seconds.
      7 #
      8 #                   For Linux, uses BCC, eBPF.
      9 #
     10 # USAGE: userfaultfd-lat [interval [count]]
     11 #
     12 # Copyright Virtuozzo GmbH, 2020
     13 #
     14 # Authors:
     15 #   Andrey Gruzdev   <andrey.gruzdev@virtuozzo.com>
     16 #
     17 # This work is licensed under the terms of the GNU GPL, version 2 or
     18 # later.  See the COPYING file in the top-level directory.
     19 
     20 from __future__ import print_function
     21 from bcc import BPF
     22 from ctypes import c_ushort, c_int, c_ulonglong
     23 from time import sleep
     24 from sys import argv
     25 
     26 def usage():
     27     print("USAGE: %s [interval [count]]" % argv[0])
     28     exit()
     29 
     30 # define BPF program
     31 bpf_text = """
     32 #include <uapi/linux/ptrace.h>
     33 #include <linux/mm.h>
     34 
     35 BPF_HASH(ev_start, u32, u64);
     36 BPF_HISTOGRAM(ev_delta_hist, u64);
     37 
     38 /* Trace UFFD page fault start event. */
     39 static void do_event_start()
     40 {
     41     /* Using "(u32)" to drop group ID which is upper 32 bits */
     42     u32 tid = (u32) bpf_get_current_pid_tgid();
     43     u64 ts = bpf_ktime_get_ns();
     44 
     45     ev_start.update(&tid, &ts);
     46 }
     47 
     48 /* Trace UFFD page fault end event. */
     49 static void do_event_end()
     50 {
     51     /* Using "(u32)" to drop group ID which is upper 32 bits */
     52     u32 tid = (u32) bpf_get_current_pid_tgid();
     53     u64 ts = bpf_ktime_get_ns();
     54     u64 *tsp;
     55 
     56     tsp = ev_start.lookup(&tid);
     57     if (tsp) {
     58         u64 delta = ts - (*tsp);
     59         /* Transform time delta to milliseconds */
     60         ev_delta_hist.increment(bpf_log2l(delta / 1000000));
     61         ev_start.delete(&tid);
     62     }
     63 }
     64 
     65 /* KPROBE for handle_userfault(). */
     66 int probe_handle_userfault(struct pt_regs *ctx, struct vm_fault *vmf,
     67         unsigned long reason)
     68 {
     69     /* Trace only UFFD write faults. */
     70     if (reason & VM_UFFD_WP) {
     71         do_event_start();
     72     }
     73     return 0;
     74 }
     75 
     76 /* KRETPROBE for handle_userfault(). */
     77 int retprobe_handle_userfault(struct pt_regs *ctx)
     78 {
     79     do_event_end();
     80     return 0;
     81 }
     82 """
     83 
     84 # arguments
     85 interval = 10
     86 count = -1
     87 if len(argv) > 1:
     88     try:
     89         interval = int(argv[1])
     90         if interval == 0:
     91             raise
     92         if len(argv) > 2:
     93             count = int(argv[2])
     94     except:    # also catches -h, --help
     95         usage()
     96 
     97 # load BPF program
     98 b = BPF(text=bpf_text)
     99 # attach KRPOBEs
    100 b.attach_kprobe(event="handle_userfault", fn_name="probe_handle_userfault")
    101 b.attach_kretprobe(event="handle_userfault", fn_name="retprobe_handle_userfault")
    102 
    103 # header
    104 print("Tracing UFFD-WP write fault latency... Hit Ctrl-C to end.")
    105 
    106 # output
    107 loop = 0
    108 do_exit = 0
    109 while (1):
    110     if count > 0:
    111         loop += 1
    112         if loop > count:
    113             exit()
    114     try:
    115         sleep(interval)
    116     except KeyboardInterrupt:
    117         pass; do_exit = 1
    118 
    119     print()
    120     b["ev_delta_hist"].print_log2_hist("msecs")
    121     if do_exit:
    122         exit()