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 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 /* page-align build ID start */ 107 addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1)); 108 109 /* to guarantee MADV_PAGEOUT work reliably, we need to ensure that 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 /* check if page has been evicted */ 118 mincore(addr, page_sz, vec); 119 if (!(vec[0] & 1)) 120 break; 121 /* if page is still resident re-attempt MADV_POPULATE_READ/MADV_PAGEOUT */ 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 /* page-out build ID */); 143 if (!strcmp("uprobe-paged-in", argv[1])) 144 return trigger_uprobe(true /* page-in build ID */); 145 146 error: 147 fprintf(stderr, "usage: %s <bench|usdt>\n", argv[0]); 148 return -1; 149 } 150