master
py 121 lines 2.83 KB
Raw
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 bcc import BPF
21 from ctypes import c_ushort, c_int, c_ulonglong
22 from time import sleep
23 from sys import argv
24
25 def usage():
26 print("USAGE: %s [interval [count]]" % argv[0])
27 exit()
28
29 # define BPF program
30 bpf_text = """
31 #include <uapi/linux/ptrace.h>
32 #include <linux/mm.h>
33
34 BPF_HASH(ev_start, u32, u64);
35 BPF_HISTOGRAM(ev_delta_hist, u64);
36
37 /* Trace UFFD page fault start event. */
38 static void do_event_start()
39 {
40 /* Using "(u32)" to drop group ID which is upper 32 bits */
41 u32 tid = (u32) bpf_get_current_pid_tgid();
42 u64 ts = bpf_ktime_get_ns();
43
44 ev_start.update(&tid, &ts);
45 }
46
47 /* Trace UFFD page fault end event. */
48 static void do_event_end()
49 {
50 /* Using "(u32)" to drop group ID which is upper 32 bits */
51 u32 tid = (u32) bpf_get_current_pid_tgid();
52 u64 ts = bpf_ktime_get_ns();
53 u64 *tsp;
54
55 tsp = ev_start.lookup(&tid);
56 if (tsp) {
57 u64 delta = ts - (*tsp);
58 /* Transform time delta to milliseconds */
59 ev_delta_hist.increment(bpf_log2l(delta / 1000000));
60 ev_start.delete(&tid);
61 }
62 }
63
64 /* KPROBE for handle_userfault(). */
65 int probe_handle_userfault(struct pt_regs *ctx, struct vm_fault *vmf,
66 unsigned long reason)
67 {
68 /* Trace only UFFD write faults. */
69 if (reason & VM_UFFD_WP) {
70 do_event_start();
71 }
72 return 0;
73 }
74
75 /* KRETPROBE for handle_userfault(). */
76 int retprobe_handle_userfault(struct pt_regs *ctx)
77 {
78 do_event_end();
79 return 0;
80 }
81 """
82
83 # arguments
84 interval = 10
85 count = -1
86 if len(argv) > 1:
87 try:
88 interval = int(argv[1])
89 if interval == 0:
90 raise
91 if len(argv) > 2:
92 count = int(argv[2])
93 except: # also catches -h, --help
94 usage()
95
96 # load BPF program
97 b = BPF(text=bpf_text)
98 # attach KRPOBEs
99 b.attach_kprobe(event="handle_userfault", fn_name="probe_handle_userfault")
100 b.attach_kretprobe(event="handle_userfault", fn_name="retprobe_handle_userfault")
101
102 # header
103 print("Tracing UFFD-WP write fault latency... Hit Ctrl-C to end.")
104
105 # output
106 loop = 0
107 do_exit = 0
108 while (1):
109 if count > 0:
110 loop += 1
111 if loop > count:
112 exit()
113 try:
114 sleep(interval)
115 except KeyboardInterrupt:
116 pass; do_exit = 1
117
118 print()
119 b["ev_delta_hist"].print_log2_hist("msecs")
120 if do_exit:
121 exit()