1*0bf02a0dSNamhyung Kim // SPDX-License-Identifier: GPL-2.0 2*0bf02a0dSNamhyung Kim #include <stdlib.h> 3*0bf02a0dSNamhyung Kim #include <stddef.h> 4*0bf02a0dSNamhyung Kim #include <ftw.h> 5*0bf02a0dSNamhyung Kim #include <fcntl.h> 6*0bf02a0dSNamhyung Kim #include <errno.h> 7*0bf02a0dSNamhyung Kim #include <unistd.h> 8*0bf02a0dSNamhyung Kim #include <pthread.h> 9*0bf02a0dSNamhyung Kim #include <sys/mman.h> 10*0bf02a0dSNamhyung Kim #include <sys/wait.h> 11*0bf02a0dSNamhyung Kim #include <linux/kernel.h> 12*0bf02a0dSNamhyung Kim #include <linux/time64.h> 13*0bf02a0dSNamhyung Kim #include <linux/list.h> 14*0bf02a0dSNamhyung Kim #include <linux/err.h> 15*0bf02a0dSNamhyung Kim #include <internal/lib.h> 16*0bf02a0dSNamhyung Kim #include <subcmd/parse-options.h> 17*0bf02a0dSNamhyung Kim 18*0bf02a0dSNamhyung Kim #include "bench.h" 19*0bf02a0dSNamhyung Kim #include "util/data.h" 20*0bf02a0dSNamhyung Kim #include "util/stat.h" 21*0bf02a0dSNamhyung Kim #include "util/debug.h" 22*0bf02a0dSNamhyung Kim #include "util/event.h" 23*0bf02a0dSNamhyung Kim #include "util/symbol.h" 24*0bf02a0dSNamhyung Kim #include "util/session.h" 25*0bf02a0dSNamhyung Kim #include "util/build-id.h" 26*0bf02a0dSNamhyung Kim #include "util/synthetic-events.h" 27*0bf02a0dSNamhyung Kim 28*0bf02a0dSNamhyung Kim #define MMAP_DEV_MAJOR 8 29*0bf02a0dSNamhyung Kim #define DSO_MMAP_RATIO 4 30*0bf02a0dSNamhyung Kim 31*0bf02a0dSNamhyung Kim static unsigned int iterations = 100; 32*0bf02a0dSNamhyung Kim static unsigned int nr_mmaps = 100; 33*0bf02a0dSNamhyung Kim static unsigned int nr_samples = 100; /* samples per mmap */ 34*0bf02a0dSNamhyung Kim 35*0bf02a0dSNamhyung Kim static u64 bench_sample_type; 36*0bf02a0dSNamhyung Kim static u16 bench_id_hdr_size; 37*0bf02a0dSNamhyung Kim 38*0bf02a0dSNamhyung Kim struct bench_data { 39*0bf02a0dSNamhyung Kim int pid; 40*0bf02a0dSNamhyung Kim int input_pipe[2]; 41*0bf02a0dSNamhyung Kim int output_pipe[2]; 42*0bf02a0dSNamhyung Kim pthread_t th; 43*0bf02a0dSNamhyung Kim }; 44*0bf02a0dSNamhyung Kim 45*0bf02a0dSNamhyung Kim struct bench_dso { 46*0bf02a0dSNamhyung Kim struct list_head list; 47*0bf02a0dSNamhyung Kim char *name; 48*0bf02a0dSNamhyung Kim int ino; 49*0bf02a0dSNamhyung Kim }; 50*0bf02a0dSNamhyung Kim 51*0bf02a0dSNamhyung Kim static int nr_dsos; 52*0bf02a0dSNamhyung Kim static struct bench_dso *dsos; 53*0bf02a0dSNamhyung Kim 54*0bf02a0dSNamhyung Kim extern int cmd_inject(int argc, const char *argv[]); 55*0bf02a0dSNamhyung Kim 56*0bf02a0dSNamhyung Kim static const struct option options[] = { 57*0bf02a0dSNamhyung Kim OPT_UINTEGER('i', "iterations", &iterations, 58*0bf02a0dSNamhyung Kim "Number of iterations used to compute average (default: 100)"), 59*0bf02a0dSNamhyung Kim OPT_UINTEGER('m', "nr-mmaps", &nr_mmaps, 60*0bf02a0dSNamhyung Kim "Number of mmap events for each iteration (default: 100)"), 61*0bf02a0dSNamhyung Kim OPT_UINTEGER('n', "nr-samples", &nr_samples, 62*0bf02a0dSNamhyung Kim "Number of sample events per mmap event (default: 100)"), 63*0bf02a0dSNamhyung Kim OPT_INCR('v', "verbose", &verbose, 64*0bf02a0dSNamhyung Kim "be more verbose (show iteration count, DSO name, etc)"), 65*0bf02a0dSNamhyung Kim OPT_END() 66*0bf02a0dSNamhyung Kim }; 67*0bf02a0dSNamhyung Kim 68*0bf02a0dSNamhyung Kim static const char *const bench_usage[] = { 69*0bf02a0dSNamhyung Kim "perf bench internals inject-build-id <options>", 70*0bf02a0dSNamhyung Kim NULL 71*0bf02a0dSNamhyung Kim }; 72*0bf02a0dSNamhyung Kim 73*0bf02a0dSNamhyung Kim /* 74*0bf02a0dSNamhyung Kim * Helper for collect_dso that adds the given file as a dso to dso_list 75*0bf02a0dSNamhyung Kim * if it contains a build-id. Stops after collecting 4 times more than 76*0bf02a0dSNamhyung Kim * we need (for MMAP2 events). 77*0bf02a0dSNamhyung Kim */ 78*0bf02a0dSNamhyung Kim static int add_dso(const char *fpath, const struct stat *sb __maybe_unused, 79*0bf02a0dSNamhyung Kim int typeflag, struct FTW *ftwbuf __maybe_unused) 80*0bf02a0dSNamhyung Kim { 81*0bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[nr_dsos]; 82*0bf02a0dSNamhyung Kim unsigned char build_id[BUILD_ID_SIZE]; 83*0bf02a0dSNamhyung Kim 84*0bf02a0dSNamhyung Kim if (typeflag == FTW_D || typeflag == FTW_SL) 85*0bf02a0dSNamhyung Kim return 0; 86*0bf02a0dSNamhyung Kim 87*0bf02a0dSNamhyung Kim if (filename__read_build_id(fpath, build_id, BUILD_ID_SIZE) < 0) 88*0bf02a0dSNamhyung Kim return 0; 89*0bf02a0dSNamhyung Kim 90*0bf02a0dSNamhyung Kim dso->name = realpath(fpath, NULL); 91*0bf02a0dSNamhyung Kim if (dso->name == NULL) 92*0bf02a0dSNamhyung Kim return -1; 93*0bf02a0dSNamhyung Kim 94*0bf02a0dSNamhyung Kim dso->ino = nr_dsos++; 95*0bf02a0dSNamhyung Kim pr_debug2(" Adding DSO: %s\n", fpath); 96*0bf02a0dSNamhyung Kim 97*0bf02a0dSNamhyung Kim /* stop if we collected enough DSOs */ 98*0bf02a0dSNamhyung Kim if ((unsigned int)nr_dsos == DSO_MMAP_RATIO * nr_mmaps) 99*0bf02a0dSNamhyung Kim return 1; 100*0bf02a0dSNamhyung Kim 101*0bf02a0dSNamhyung Kim return 0; 102*0bf02a0dSNamhyung Kim } 103*0bf02a0dSNamhyung Kim 104*0bf02a0dSNamhyung Kim static void collect_dso(void) 105*0bf02a0dSNamhyung Kim { 106*0bf02a0dSNamhyung Kim dsos = calloc(nr_mmaps * DSO_MMAP_RATIO, sizeof(*dsos)); 107*0bf02a0dSNamhyung Kim if (dsos == NULL) { 108*0bf02a0dSNamhyung Kim printf(" Memory allocation failed\n"); 109*0bf02a0dSNamhyung Kim exit(1); 110*0bf02a0dSNamhyung Kim } 111*0bf02a0dSNamhyung Kim 112*0bf02a0dSNamhyung Kim if (nftw("/usr/lib/", add_dso, 10, FTW_PHYS) < 0) 113*0bf02a0dSNamhyung Kim return; 114*0bf02a0dSNamhyung Kim 115*0bf02a0dSNamhyung Kim pr_debug(" Collected %d DSOs\n", nr_dsos); 116*0bf02a0dSNamhyung Kim } 117*0bf02a0dSNamhyung Kim 118*0bf02a0dSNamhyung Kim static void release_dso(void) 119*0bf02a0dSNamhyung Kim { 120*0bf02a0dSNamhyung Kim int i; 121*0bf02a0dSNamhyung Kim 122*0bf02a0dSNamhyung Kim for (i = 0; i < nr_dsos; i++) { 123*0bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[i]; 124*0bf02a0dSNamhyung Kim 125*0bf02a0dSNamhyung Kim free(dso->name); 126*0bf02a0dSNamhyung Kim } 127*0bf02a0dSNamhyung Kim free(dsos); 128*0bf02a0dSNamhyung Kim } 129*0bf02a0dSNamhyung Kim 130*0bf02a0dSNamhyung Kim /* Fake address used by mmap and sample events */ 131*0bf02a0dSNamhyung Kim static u64 dso_map_addr(struct bench_dso *dso) 132*0bf02a0dSNamhyung Kim { 133*0bf02a0dSNamhyung Kim return 0x400000ULL + dso->ino * 8192ULL; 134*0bf02a0dSNamhyung Kim } 135*0bf02a0dSNamhyung Kim 136*0bf02a0dSNamhyung Kim static u32 synthesize_attr(struct bench_data *data) 137*0bf02a0dSNamhyung Kim { 138*0bf02a0dSNamhyung Kim union perf_event event; 139*0bf02a0dSNamhyung Kim 140*0bf02a0dSNamhyung Kim memset(&event, 0, sizeof(event.attr) + sizeof(u64)); 141*0bf02a0dSNamhyung Kim 142*0bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_HEADER_ATTR; 143*0bf02a0dSNamhyung Kim event.header.size = sizeof(event.attr) + sizeof(u64); 144*0bf02a0dSNamhyung Kim 145*0bf02a0dSNamhyung Kim event.attr.attr.type = PERF_TYPE_SOFTWARE; 146*0bf02a0dSNamhyung Kim event.attr.attr.config = PERF_COUNT_SW_TASK_CLOCK; 147*0bf02a0dSNamhyung Kim event.attr.attr.exclude_kernel = 1; 148*0bf02a0dSNamhyung Kim event.attr.attr.sample_id_all = 1; 149*0bf02a0dSNamhyung Kim event.attr.attr.sample_type = bench_sample_type; 150*0bf02a0dSNamhyung Kim 151*0bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 152*0bf02a0dSNamhyung Kim } 153*0bf02a0dSNamhyung Kim 154*0bf02a0dSNamhyung Kim static u32 synthesize_fork(struct bench_data *data) 155*0bf02a0dSNamhyung Kim { 156*0bf02a0dSNamhyung Kim union perf_event event; 157*0bf02a0dSNamhyung Kim 158*0bf02a0dSNamhyung Kim memset(&event, 0, sizeof(event.fork) + bench_id_hdr_size); 159*0bf02a0dSNamhyung Kim 160*0bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_FORK; 161*0bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_FORK_EXEC; 162*0bf02a0dSNamhyung Kim event.header.size = sizeof(event.fork) + bench_id_hdr_size; 163*0bf02a0dSNamhyung Kim 164*0bf02a0dSNamhyung Kim event.fork.ppid = 1; 165*0bf02a0dSNamhyung Kim event.fork.ptid = 1; 166*0bf02a0dSNamhyung Kim event.fork.pid = data->pid; 167*0bf02a0dSNamhyung Kim event.fork.tid = data->pid; 168*0bf02a0dSNamhyung Kim 169*0bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 170*0bf02a0dSNamhyung Kim } 171*0bf02a0dSNamhyung Kim 172*0bf02a0dSNamhyung Kim static u32 synthesize_mmap(struct bench_data *data, struct bench_dso *dso, 173*0bf02a0dSNamhyung Kim u64 timestamp) 174*0bf02a0dSNamhyung Kim { 175*0bf02a0dSNamhyung Kim union perf_event event; 176*0bf02a0dSNamhyung Kim size_t len = offsetof(struct perf_record_mmap2, filename); 177*0bf02a0dSNamhyung Kim u64 *id_hdr_ptr = (void *)&event; 178*0bf02a0dSNamhyung Kim int ts_idx; 179*0bf02a0dSNamhyung Kim 180*0bf02a0dSNamhyung Kim len += roundup(strlen(dso->name) + 1, 8) + bench_id_hdr_size; 181*0bf02a0dSNamhyung Kim 182*0bf02a0dSNamhyung Kim memset(&event, 0, min(len, sizeof(event.mmap2))); 183*0bf02a0dSNamhyung Kim 184*0bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_MMAP2; 185*0bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_USER; 186*0bf02a0dSNamhyung Kim event.header.size = len; 187*0bf02a0dSNamhyung Kim 188*0bf02a0dSNamhyung Kim event.mmap2.pid = data->pid; 189*0bf02a0dSNamhyung Kim event.mmap2.tid = data->pid; 190*0bf02a0dSNamhyung Kim event.mmap2.maj = MMAP_DEV_MAJOR; 191*0bf02a0dSNamhyung Kim event.mmap2.ino = dso->ino; 192*0bf02a0dSNamhyung Kim 193*0bf02a0dSNamhyung Kim strcpy(event.mmap2.filename, dso->name); 194*0bf02a0dSNamhyung Kim 195*0bf02a0dSNamhyung Kim event.mmap2.start = dso_map_addr(dso); 196*0bf02a0dSNamhyung Kim event.mmap2.len = 4096; 197*0bf02a0dSNamhyung Kim event.mmap2.prot = PROT_EXEC; 198*0bf02a0dSNamhyung Kim 199*0bf02a0dSNamhyung Kim if (len > sizeof(event.mmap2)) { 200*0bf02a0dSNamhyung Kim /* write mmap2 event first */ 201*0bf02a0dSNamhyung Kim writen(data->input_pipe[1], &event, len - bench_id_hdr_size); 202*0bf02a0dSNamhyung Kim /* zero-fill sample id header */ 203*0bf02a0dSNamhyung Kim memset(id_hdr_ptr, 0, bench_id_hdr_size); 204*0bf02a0dSNamhyung Kim /* put timestamp in the right position */ 205*0bf02a0dSNamhyung Kim ts_idx = (bench_id_hdr_size / sizeof(u64)) - 2; 206*0bf02a0dSNamhyung Kim id_hdr_ptr[ts_idx] = timestamp; 207*0bf02a0dSNamhyung Kim writen(data->input_pipe[1], id_hdr_ptr, bench_id_hdr_size); 208*0bf02a0dSNamhyung Kim } else { 209*0bf02a0dSNamhyung Kim ts_idx = (len / sizeof(u64)) - 2; 210*0bf02a0dSNamhyung Kim id_hdr_ptr[ts_idx] = timestamp; 211*0bf02a0dSNamhyung Kim writen(data->input_pipe[1], &event, len); 212*0bf02a0dSNamhyung Kim } 213*0bf02a0dSNamhyung Kim return len; 214*0bf02a0dSNamhyung Kim } 215*0bf02a0dSNamhyung Kim 216*0bf02a0dSNamhyung Kim static u32 synthesize_sample(struct bench_data *data, struct bench_dso *dso, 217*0bf02a0dSNamhyung Kim u64 timestamp) 218*0bf02a0dSNamhyung Kim { 219*0bf02a0dSNamhyung Kim union perf_event event; 220*0bf02a0dSNamhyung Kim struct perf_sample sample = { 221*0bf02a0dSNamhyung Kim .tid = data->pid, 222*0bf02a0dSNamhyung Kim .pid = data->pid, 223*0bf02a0dSNamhyung Kim .ip = dso_map_addr(dso), 224*0bf02a0dSNamhyung Kim .time = timestamp, 225*0bf02a0dSNamhyung Kim }; 226*0bf02a0dSNamhyung Kim 227*0bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_SAMPLE; 228*0bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_USER; 229*0bf02a0dSNamhyung Kim event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0); 230*0bf02a0dSNamhyung Kim 231*0bf02a0dSNamhyung Kim perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample); 232*0bf02a0dSNamhyung Kim 233*0bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 234*0bf02a0dSNamhyung Kim } 235*0bf02a0dSNamhyung Kim 236*0bf02a0dSNamhyung Kim static u32 synthesize_flush(struct bench_data *data) 237*0bf02a0dSNamhyung Kim { 238*0bf02a0dSNamhyung Kim struct perf_event_header header = { 239*0bf02a0dSNamhyung Kim .size = sizeof(header), 240*0bf02a0dSNamhyung Kim .type = PERF_RECORD_FINISHED_ROUND, 241*0bf02a0dSNamhyung Kim }; 242*0bf02a0dSNamhyung Kim 243*0bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &header, header.size); 244*0bf02a0dSNamhyung Kim } 245*0bf02a0dSNamhyung Kim 246*0bf02a0dSNamhyung Kim static void *data_reader(void *arg) 247*0bf02a0dSNamhyung Kim { 248*0bf02a0dSNamhyung Kim struct bench_data *data = arg; 249*0bf02a0dSNamhyung Kim char buf[8192]; 250*0bf02a0dSNamhyung Kim int flag; 251*0bf02a0dSNamhyung Kim int n; 252*0bf02a0dSNamhyung Kim 253*0bf02a0dSNamhyung Kim flag = fcntl(data->output_pipe[0], F_GETFL); 254*0bf02a0dSNamhyung Kim fcntl(data->output_pipe[0], F_SETFL, flag | O_NONBLOCK); 255*0bf02a0dSNamhyung Kim 256*0bf02a0dSNamhyung Kim /* read out data from child */ 257*0bf02a0dSNamhyung Kim while (true) { 258*0bf02a0dSNamhyung Kim n = read(data->output_pipe[0], buf, sizeof(buf)); 259*0bf02a0dSNamhyung Kim if (n > 0) 260*0bf02a0dSNamhyung Kim continue; 261*0bf02a0dSNamhyung Kim if (n == 0) 262*0bf02a0dSNamhyung Kim break; 263*0bf02a0dSNamhyung Kim 264*0bf02a0dSNamhyung Kim if (errno != EINTR && errno != EAGAIN) 265*0bf02a0dSNamhyung Kim break; 266*0bf02a0dSNamhyung Kim 267*0bf02a0dSNamhyung Kim usleep(100); 268*0bf02a0dSNamhyung Kim } 269*0bf02a0dSNamhyung Kim 270*0bf02a0dSNamhyung Kim close(data->output_pipe[0]); 271*0bf02a0dSNamhyung Kim return NULL; 272*0bf02a0dSNamhyung Kim } 273*0bf02a0dSNamhyung Kim 274*0bf02a0dSNamhyung Kim static int setup_injection(struct bench_data *data) 275*0bf02a0dSNamhyung Kim { 276*0bf02a0dSNamhyung Kim int ready_pipe[2]; 277*0bf02a0dSNamhyung Kim int dev_null_fd; 278*0bf02a0dSNamhyung Kim char buf; 279*0bf02a0dSNamhyung Kim 280*0bf02a0dSNamhyung Kim if (pipe(ready_pipe) < 0) 281*0bf02a0dSNamhyung Kim return -1; 282*0bf02a0dSNamhyung Kim 283*0bf02a0dSNamhyung Kim if (pipe(data->input_pipe) < 0) 284*0bf02a0dSNamhyung Kim return -1; 285*0bf02a0dSNamhyung Kim 286*0bf02a0dSNamhyung Kim if (pipe(data->output_pipe) < 0) 287*0bf02a0dSNamhyung Kim return -1; 288*0bf02a0dSNamhyung Kim 289*0bf02a0dSNamhyung Kim data->pid = fork(); 290*0bf02a0dSNamhyung Kim if (data->pid < 0) 291*0bf02a0dSNamhyung Kim return -1; 292*0bf02a0dSNamhyung Kim 293*0bf02a0dSNamhyung Kim if (data->pid == 0) { 294*0bf02a0dSNamhyung Kim const char **inject_argv; 295*0bf02a0dSNamhyung Kim 296*0bf02a0dSNamhyung Kim close(data->input_pipe[1]); 297*0bf02a0dSNamhyung Kim close(data->output_pipe[0]); 298*0bf02a0dSNamhyung Kim close(ready_pipe[0]); 299*0bf02a0dSNamhyung Kim 300*0bf02a0dSNamhyung Kim dup2(data->input_pipe[0], STDIN_FILENO); 301*0bf02a0dSNamhyung Kim close(data->input_pipe[0]); 302*0bf02a0dSNamhyung Kim dup2(data->output_pipe[1], STDOUT_FILENO); 303*0bf02a0dSNamhyung Kim close(data->output_pipe[1]); 304*0bf02a0dSNamhyung Kim 305*0bf02a0dSNamhyung Kim dev_null_fd = open("/dev/null", O_WRONLY); 306*0bf02a0dSNamhyung Kim if (dev_null_fd < 0) 307*0bf02a0dSNamhyung Kim exit(1); 308*0bf02a0dSNamhyung Kim 309*0bf02a0dSNamhyung Kim dup2(dev_null_fd, STDERR_FILENO); 310*0bf02a0dSNamhyung Kim 311*0bf02a0dSNamhyung Kim inject_argv = calloc(3, sizeof(*inject_argv)); 312*0bf02a0dSNamhyung Kim if (inject_argv == NULL) 313*0bf02a0dSNamhyung Kim exit(1); 314*0bf02a0dSNamhyung Kim 315*0bf02a0dSNamhyung Kim inject_argv[0] = strdup("inject"); 316*0bf02a0dSNamhyung Kim inject_argv[1] = strdup("-b"); 317*0bf02a0dSNamhyung Kim 318*0bf02a0dSNamhyung Kim /* signal that we're ready to go */ 319*0bf02a0dSNamhyung Kim close(ready_pipe[1]); 320*0bf02a0dSNamhyung Kim 321*0bf02a0dSNamhyung Kim cmd_inject(2, inject_argv); 322*0bf02a0dSNamhyung Kim 323*0bf02a0dSNamhyung Kim exit(0); 324*0bf02a0dSNamhyung Kim } 325*0bf02a0dSNamhyung Kim 326*0bf02a0dSNamhyung Kim pthread_create(&data->th, NULL, data_reader, data); 327*0bf02a0dSNamhyung Kim 328*0bf02a0dSNamhyung Kim close(ready_pipe[1]); 329*0bf02a0dSNamhyung Kim close(data->input_pipe[0]); 330*0bf02a0dSNamhyung Kim close(data->output_pipe[1]); 331*0bf02a0dSNamhyung Kim 332*0bf02a0dSNamhyung Kim /* wait for child ready */ 333*0bf02a0dSNamhyung Kim if (read(ready_pipe[0], &buf, 1) < 0) 334*0bf02a0dSNamhyung Kim return -1; 335*0bf02a0dSNamhyung Kim close(ready_pipe[0]); 336*0bf02a0dSNamhyung Kim 337*0bf02a0dSNamhyung Kim return 0; 338*0bf02a0dSNamhyung Kim } 339*0bf02a0dSNamhyung Kim 340*0bf02a0dSNamhyung Kim static int inject_build_id(struct bench_data *data, u64 *max_rss) 341*0bf02a0dSNamhyung Kim { 342*0bf02a0dSNamhyung Kim int status; 343*0bf02a0dSNamhyung Kim unsigned int i, k; 344*0bf02a0dSNamhyung Kim struct rusage rusage; 345*0bf02a0dSNamhyung Kim u64 len = 0; 346*0bf02a0dSNamhyung Kim 347*0bf02a0dSNamhyung Kim /* this makes the child to run */ 348*0bf02a0dSNamhyung Kim if (perf_header__write_pipe(data->input_pipe[1]) < 0) 349*0bf02a0dSNamhyung Kim return -1; 350*0bf02a0dSNamhyung Kim 351*0bf02a0dSNamhyung Kim len += synthesize_attr(data); 352*0bf02a0dSNamhyung Kim len += synthesize_fork(data); 353*0bf02a0dSNamhyung Kim 354*0bf02a0dSNamhyung Kim for (i = 0; i < nr_mmaps; i++) { 355*0bf02a0dSNamhyung Kim int idx = rand() % (nr_dsos - 1); 356*0bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[idx]; 357*0bf02a0dSNamhyung Kim u64 timestamp = rand() % 1000000; 358*0bf02a0dSNamhyung Kim 359*0bf02a0dSNamhyung Kim pr_debug2(" [%d] injecting: %s\n", i+1, dso->name); 360*0bf02a0dSNamhyung Kim len += synthesize_mmap(data, dso, timestamp); 361*0bf02a0dSNamhyung Kim 362*0bf02a0dSNamhyung Kim for (k = 0; k < nr_samples; k++) 363*0bf02a0dSNamhyung Kim len += synthesize_sample(data, dso, timestamp + k * 1000); 364*0bf02a0dSNamhyung Kim 365*0bf02a0dSNamhyung Kim if ((i + 1) % 10 == 0) 366*0bf02a0dSNamhyung Kim len += synthesize_flush(data); 367*0bf02a0dSNamhyung Kim } 368*0bf02a0dSNamhyung Kim 369*0bf02a0dSNamhyung Kim /* tihs makes the child to finish */ 370*0bf02a0dSNamhyung Kim close(data->input_pipe[1]); 371*0bf02a0dSNamhyung Kim 372*0bf02a0dSNamhyung Kim wait4(data->pid, &status, 0, &rusage); 373*0bf02a0dSNamhyung Kim *max_rss = rusage.ru_maxrss; 374*0bf02a0dSNamhyung Kim 375*0bf02a0dSNamhyung Kim pr_debug(" Child %d exited with %d\n", data->pid, status); 376*0bf02a0dSNamhyung Kim 377*0bf02a0dSNamhyung Kim return 0; 378*0bf02a0dSNamhyung Kim } 379*0bf02a0dSNamhyung Kim 380*0bf02a0dSNamhyung Kim static int do_inject_loop(struct bench_data *data) 381*0bf02a0dSNamhyung Kim { 382*0bf02a0dSNamhyung Kim unsigned int i; 383*0bf02a0dSNamhyung Kim struct stats time_stats, mem_stats; 384*0bf02a0dSNamhyung Kim double time_average, time_stddev; 385*0bf02a0dSNamhyung Kim double mem_average, mem_stddev; 386*0bf02a0dSNamhyung Kim 387*0bf02a0dSNamhyung Kim srand(time(NULL)); 388*0bf02a0dSNamhyung Kim init_stats(&time_stats); 389*0bf02a0dSNamhyung Kim init_stats(&mem_stats); 390*0bf02a0dSNamhyung Kim symbol__init(NULL); 391*0bf02a0dSNamhyung Kim 392*0bf02a0dSNamhyung Kim bench_sample_type = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP; 393*0bf02a0dSNamhyung Kim bench_sample_type |= PERF_SAMPLE_TID | PERF_SAMPLE_TIME; 394*0bf02a0dSNamhyung Kim bench_id_hdr_size = 32; 395*0bf02a0dSNamhyung Kim 396*0bf02a0dSNamhyung Kim collect_dso(); 397*0bf02a0dSNamhyung Kim if (nr_dsos == 0) { 398*0bf02a0dSNamhyung Kim printf(" Cannot collect DSOs for injection\n"); 399*0bf02a0dSNamhyung Kim return -1; 400*0bf02a0dSNamhyung Kim } 401*0bf02a0dSNamhyung Kim 402*0bf02a0dSNamhyung Kim for (i = 0; i < iterations; i++) { 403*0bf02a0dSNamhyung Kim struct timeval start, end, diff; 404*0bf02a0dSNamhyung Kim u64 runtime_us, max_rss; 405*0bf02a0dSNamhyung Kim 406*0bf02a0dSNamhyung Kim pr_debug(" Iteration #%d\n", i+1); 407*0bf02a0dSNamhyung Kim 408*0bf02a0dSNamhyung Kim if (setup_injection(data) < 0) { 409*0bf02a0dSNamhyung Kim printf(" Build-id injection setup failed\n"); 410*0bf02a0dSNamhyung Kim break; 411*0bf02a0dSNamhyung Kim } 412*0bf02a0dSNamhyung Kim 413*0bf02a0dSNamhyung Kim gettimeofday(&start, NULL); 414*0bf02a0dSNamhyung Kim if (inject_build_id(data, &max_rss) < 0) { 415*0bf02a0dSNamhyung Kim printf(" Build-id injection failed\n"); 416*0bf02a0dSNamhyung Kim break; 417*0bf02a0dSNamhyung Kim } 418*0bf02a0dSNamhyung Kim 419*0bf02a0dSNamhyung Kim gettimeofday(&end, NULL); 420*0bf02a0dSNamhyung Kim timersub(&end, &start, &diff); 421*0bf02a0dSNamhyung Kim runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; 422*0bf02a0dSNamhyung Kim update_stats(&time_stats, runtime_us); 423*0bf02a0dSNamhyung Kim update_stats(&mem_stats, max_rss); 424*0bf02a0dSNamhyung Kim 425*0bf02a0dSNamhyung Kim pthread_join(data->th, NULL); 426*0bf02a0dSNamhyung Kim } 427*0bf02a0dSNamhyung Kim 428*0bf02a0dSNamhyung Kim time_average = avg_stats(&time_stats) / USEC_PER_MSEC; 429*0bf02a0dSNamhyung Kim time_stddev = stddev_stats(&time_stats) / USEC_PER_MSEC; 430*0bf02a0dSNamhyung Kim printf(" Average build-id injection took: %.3f msec (+- %.3f msec)\n", 431*0bf02a0dSNamhyung Kim time_average, time_stddev); 432*0bf02a0dSNamhyung Kim 433*0bf02a0dSNamhyung Kim /* each iteration, it processes MMAP2 + BUILD_ID + nr_samples * SAMPLE */ 434*0bf02a0dSNamhyung Kim time_average = avg_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 435*0bf02a0dSNamhyung Kim time_stddev = stddev_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 436*0bf02a0dSNamhyung Kim printf(" Average time per event: %.3f usec (+- %.3f usec)\n", 437*0bf02a0dSNamhyung Kim time_average, time_stddev); 438*0bf02a0dSNamhyung Kim 439*0bf02a0dSNamhyung Kim mem_average = avg_stats(&mem_stats); 440*0bf02a0dSNamhyung Kim mem_stddev = stddev_stats(&mem_stats); 441*0bf02a0dSNamhyung Kim printf(" Average memory usage: %.0f KB (+- %.0f KB)\n", 442*0bf02a0dSNamhyung Kim mem_average, mem_stddev); 443*0bf02a0dSNamhyung Kim 444*0bf02a0dSNamhyung Kim release_dso(); 445*0bf02a0dSNamhyung Kim return 0; 446*0bf02a0dSNamhyung Kim } 447*0bf02a0dSNamhyung Kim 448*0bf02a0dSNamhyung Kim int bench_inject_build_id(int argc, const char **argv) 449*0bf02a0dSNamhyung Kim { 450*0bf02a0dSNamhyung Kim struct bench_data data; 451*0bf02a0dSNamhyung Kim 452*0bf02a0dSNamhyung Kim argc = parse_options(argc, argv, options, bench_usage, 0); 453*0bf02a0dSNamhyung Kim if (argc) { 454*0bf02a0dSNamhyung Kim usage_with_options(bench_usage, options); 455*0bf02a0dSNamhyung Kim exit(EXIT_FAILURE); 456*0bf02a0dSNamhyung Kim } 457*0bf02a0dSNamhyung Kim 458*0bf02a0dSNamhyung Kim return do_inject_loop(&data); 459*0bf02a0dSNamhyung Kim } 460*0bf02a0dSNamhyung Kim 461