1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <sys/mman.h>
8 #include <unistd.h>
9 #include <sdt.h>
10
11 #ifndef MADV_POPULATE_READ
12 #define MADV_POPULATE_READ 22
13 #endif
14
uprobe(void)15 int __attribute__((weak)) uprobe(void)
16 {
17 return 0;
18 }
19
20 #define __PASTE(a, b) a##b
21 #define PASTE(a, b) __PASTE(a, b)
22
23 #define NAME(name, idx) PASTE(name, idx)
24
25 #define DEF(name, idx) int __attribute__((weak)) NAME(name, idx)(void) { return 0; }
26 #define CALL(name, idx) NAME(name, idx)();
27
28 #define F(body, name, idx) body(name, idx)
29
30 #define F10(body, name, idx) \
31 F(body, PASTE(name, idx), 0) F(body, PASTE(name, idx), 1) F(body, PASTE(name, idx), 2) \
32 F(body, PASTE(name, idx), 3) F(body, PASTE(name, idx), 4) F(body, PASTE(name, idx), 5) \
33 F(body, PASTE(name, idx), 6) F(body, PASTE(name, idx), 7) F(body, PASTE(name, idx), 8) \
34 F(body, PASTE(name, idx), 9)
35
36 #define F100(body, name, idx) \
37 F10(body, PASTE(name, idx), 0) F10(body, PASTE(name, idx), 1) F10(body, PASTE(name, idx), 2) \
38 F10(body, PASTE(name, idx), 3) F10(body, PASTE(name, idx), 4) F10(body, PASTE(name, idx), 5) \
39 F10(body, PASTE(name, idx), 6) F10(body, PASTE(name, idx), 7) F10(body, PASTE(name, idx), 8) \
40 F10(body, PASTE(name, idx), 9)
41
42 #define F1000(body, name, idx) \
43 F100(body, PASTE(name, idx), 0) F100(body, PASTE(name, idx), 1) F100(body, PASTE(name, idx), 2) \
44 F100(body, PASTE(name, idx), 3) F100(body, PASTE(name, idx), 4) F100(body, PASTE(name, idx), 5) \
45 F100(body, PASTE(name, idx), 6) F100(body, PASTE(name, idx), 7) F100(body, PASTE(name, idx), 8) \
46 F100(body, PASTE(name, idx), 9)
47
48 #define F10000(body, name, idx) \
49 F1000(body, PASTE(name, idx), 0) F1000(body, PASTE(name, idx), 1) F1000(body, PASTE(name, idx), 2) \
50 F1000(body, PASTE(name, idx), 3) F1000(body, PASTE(name, idx), 4) F1000(body, PASTE(name, idx), 5) \
51 F1000(body, PASTE(name, idx), 6) F1000(body, PASTE(name, idx), 7) F1000(body, PASTE(name, idx), 8) \
52 F1000(body, PASTE(name, idx), 9)
53
54 F10000(DEF, uprobe_multi_func_, 0)
55 F10000(DEF, uprobe_multi_func_, 1)
56 F10000(DEF, uprobe_multi_func_, 2)
57 F10000(DEF, uprobe_multi_func_, 3)
58 F10000(DEF, uprobe_multi_func_, 4)
59
bench(void)60 static int bench(void)
61 {
62 F10000(CALL, uprobe_multi_func_, 0)
63 F10000(CALL, uprobe_multi_func_, 1)
64 F10000(CALL, uprobe_multi_func_, 2)
65 F10000(CALL, uprobe_multi_func_, 3)
66 F10000(CALL, uprobe_multi_func_, 4)
67 return 0;
68 }
69
70 #define PROBE STAP_PROBE(test, usdt);
71
72 #define PROBE10 PROBE PROBE PROBE PROBE PROBE \
73 PROBE PROBE PROBE PROBE PROBE
74 #define PROBE100 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10 \
75 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10
76 #define PROBE1000 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100 \
77 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100
78 #define PROBE10000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 \
79 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000
80
usdt(void)81 static int usdt(void)
82 {
83 PROBE10000
84 PROBE10000
85 PROBE10000
86 PROBE10000
87 PROBE10000
88 return 0;
89 }
90
91 extern char build_id_start[];
92 extern char build_id_end[];
93
trigger_uprobe(bool build_id_resident)94 int __attribute__((weak)) trigger_uprobe(bool build_id_resident)
95 {
96 int page_sz = sysconf(_SC_PAGESIZE);
97 void *addr;
98
99 /* page-align build ID start */
100 addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1));
101
102 /* to guarantee MADV_PAGEOUT work reliably, we need to ensure that
103 * memory range is mapped into current process, so we unconditionally
104 * do MADV_POPULATE_READ, and then MADV_PAGEOUT, if necessary
105 */
106 madvise(addr, page_sz, MADV_POPULATE_READ);
107 if (!build_id_resident)
108 madvise(addr, page_sz, MADV_PAGEOUT);
109
110 (void)uprobe();
111
112 return 0;
113 }
114
main(int argc,char ** argv)115 int main(int argc, char **argv)
116 {
117 if (argc != 2)
118 goto error;
119
120 if (!strcmp("bench", argv[1]))
121 return bench();
122 if (!strcmp("usdt", argv[1]))
123 return usdt();
124 if (!strcmp("uprobe-paged-out", argv[1]))
125 return trigger_uprobe(false /* page-out build ID */);
126 if (!strcmp("uprobe-paged-in", argv[1]))
127 return trigger_uprobe(true /* page-in build ID */);
128
129 error:
130 fprintf(stderr, "usage: %s <bench|usdt>\n", argv[0]);
131 return -1;
132 }
133