| 1 | |
| 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 |
|
| 15 | #ifndef MADV_PAGEOUT
|
| 16 | #define MADV_PAGEOUT 21
|
| 17 | #endif
|
| 18 |
|
| 19 | int __attribute__((weak)) uprobe(void)
|
| 20 | {
|
| 21 | return 0;
|
| 22 | }
|
| 23 |
|
| 24 | #define __PASTE(a, b) a##b
|
| 25 | #define PASTE(a, b) __PASTE(a, b)
|
| 26 |
|
| 27 | #define NAME(name, idx) PASTE(name, idx)
|
| 28 |
|
| 29 | #define DEF(name, idx) int __attribute__((weak)) NAME(name, idx)(void) { return 0; }
|
| 30 | #define CALL(name, idx) NAME(name, idx)();
|
| 31 |
|
| 32 | #define F(body, name, idx) body(name, idx)
|
| 33 |
|
| 34 | #define F10(body, name, idx) \
|
| 35 | F(body, PASTE(name, idx), 0) F(body, PASTE(name, idx), 1) F(body, PASTE(name, idx), 2) \
|
| 36 | F(body, PASTE(name, idx), 3) F(body, PASTE(name, idx), 4) F(body, PASTE(name, idx), 5) \
|
| 37 | F(body, PASTE(name, idx), 6) F(body, PASTE(name, idx), 7) F(body, PASTE(name, idx), 8) \
|
| 38 | F(body, PASTE(name, idx), 9)
|
| 39 |
|
| 40 | #define F100(body, name, idx) \
|
| 41 | F10(body, PASTE(name, idx), 0) F10(body, PASTE(name, idx), 1) F10(body, PASTE(name, idx), 2) \
|
| 42 | F10(body, PASTE(name, idx), 3) F10(body, PASTE(name, idx), 4) F10(body, PASTE(name, idx), 5) \
|
| 43 | F10(body, PASTE(name, idx), 6) F10(body, PASTE(name, idx), 7) F10(body, PASTE(name, idx), 8) \
|
| 44 | F10(body, PASTE(name, idx), 9)
|
| 45 |
|
| 46 | #define F1000(body, name, idx) \
|
| 47 | F100(body, PASTE(name, idx), 0) F100(body, PASTE(name, idx), 1) F100(body, PASTE(name, idx), 2) \
|
| 48 | F100(body, PASTE(name, idx), 3) F100(body, PASTE(name, idx), 4) F100(body, PASTE(name, idx), 5) \
|
| 49 | F100(body, PASTE(name, idx), 6) F100(body, PASTE(name, idx), 7) F100(body, PASTE(name, idx), 8) \
|
| 50 | F100(body, PASTE(name, idx), 9)
|
| 51 |
|
| 52 | #define F10000(body, name, idx) \
|
| 53 | F1000(body, PASTE(name, idx), 0) F1000(body, PASTE(name, idx), 1) F1000(body, PASTE(name, idx), 2) \
|
| 54 | F1000(body, PASTE(name, idx), 3) F1000(body, PASTE(name, idx), 4) F1000(body, PASTE(name, idx), 5) \
|
| 55 | F1000(body, PASTE(name, idx), 6) F1000(body, PASTE(name, idx), 7) F1000(body, PASTE(name, idx), 8) \
|
| 56 | F1000(body, PASTE(name, idx), 9)
|
| 57 |
|
| 58 | F10000(DEF, uprobe_multi_func_, 0)
|
| 59 | F10000(DEF, uprobe_multi_func_, 1)
|
| 60 | F10000(DEF, uprobe_multi_func_, 2)
|
| 61 | F10000(DEF, uprobe_multi_func_, 3)
|
| 62 | F10000(DEF, uprobe_multi_func_, 4)
|
| 63 |
|
| 64 | static int bench(void)
|
| 65 | {
|
| 66 | F10000(CALL, uprobe_multi_func_, 0)
|
| 67 | F10000(CALL, uprobe_multi_func_, 1)
|
| 68 | F10000(CALL, uprobe_multi_func_, 2)
|
| 69 | F10000(CALL, uprobe_multi_func_, 3)
|
| 70 | F10000(CALL, uprobe_multi_func_, 4)
|
| 71 | return 0;
|
| 72 | }
|
| 73 |
|
| 74 | #define PROBE STAP_PROBE(test, usdt);
|
| 75 |
|
| 76 | #define PROBE10 PROBE PROBE PROBE PROBE PROBE \
|
| 77 | PROBE PROBE PROBE PROBE PROBE
|
| 78 | #define PROBE100 PROBE10 PROBE10 PROBE10 PROBE10 PROBE10 \
|
| 79 | PROBE10 PROBE10 PROBE10 PROBE10 PROBE10
|
| 80 | #define PROBE1000 PROBE100 PROBE100 PROBE100 PROBE100 PROBE100 \
|
| 81 | PROBE100 PROBE100 PROBE100 PROBE100 PROBE100
|
| 82 | #define PROBE10000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000 \
|
| 83 | PROBE1000 PROBE1000 PROBE1000 PROBE1000 PROBE1000
|
| 84 |
|
| 85 | static int usdt(void)
|
| 86 | {
|
| 87 | PROBE10000
|
| 88 | PROBE10000
|
| 89 | PROBE10000
|
| 90 | PROBE10000
|
| 91 | PROBE10000
|
| 92 | return 0;
|
| 93 | }
|
| 94 |
|
| 95 | extern char build_id_start[];
|
| 96 | extern char build_id_end[];
|
| 97 |
|
| 98 | int __attribute__((weak)) trigger_uprobe(bool build_id_resident)
|
| 99 | {
|
| 100 | int page_sz = sysconf(_SC_PAGESIZE);
|
| 101 | void *addr;
|
| 102 |
|
| 103 | unsigned char vec[1];
|
| 104 | int poll = 0;
|
| 105 |
|
| 106 |
|
| 107 | addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1));
|
| 108 |
|
| 109 | |
| 110 | * memory range is mapped into current process, so we unconditionally
|
| 111 | * do MADV_POPULATE_READ, and then MADV_PAGEOUT, if necessary
|
| 112 |
|
| 113 | madvise(addr, page_sz, MADV_POPULATE_READ);
|
| 114 | if (!build_id_resident) {
|
| 115 | do {
|
| 116 | madvise(addr, page_sz, MADV_PAGEOUT);
|
| 117 |
|
| 118 | mincore(addr, page_sz, vec);
|
| 119 | if (!(vec[0] & 1))
|
| 120 | break;
|
| 121 |
|
| 122 | madvise(addr, page_sz, MADV_POPULATE_READ);
|
| 123 | poll++;
|
| 124 | usleep(100);
|
| 125 | } while (poll < 500);
|
| 126 | }
|
| 127 | (void)uprobe();
|
| 128 |
|
| 129 | return 0;
|
| 130 | }
|
| 131 |
|
| 132 | int main(int argc, char **argv)
|
| 133 | {
|
| 134 | if (argc != 2)
|
| 135 | goto error;
|
| 136 |
|
| 137 | if (!strcmp("bench", argv[1]))
|
| 138 | return bench();
|
| 139 | if (!strcmp("usdt", argv[1]))
|
| 140 | return usdt();
|
| 141 | if (!strcmp("uprobe-paged-out", argv[1]))
|
| 142 | return trigger_uprobe(false );
|
| 143 | if (!strcmp("uprobe-paged-in", argv[1]))
|
| 144 | return trigger_uprobe(true );
|
| 145 |
|
| 146 | error:
|
| 147 | fprintf(stderr,
|
| 148 | "usage: %s <bench|usdt|uprobe-paged-out|uprobe-paged-in>\n",
|
| 149 | argv[0]);
|
| 150 | return -1;
|
| 151 | }
|