10bf02a0dSNamhyung Kim // SPDX-License-Identifier: GPL-2.0 20bf02a0dSNamhyung Kim #include <stdlib.h> 30bf02a0dSNamhyung Kim #include <stddef.h> 40bf02a0dSNamhyung Kim #include <ftw.h> 50bf02a0dSNamhyung Kim #include <fcntl.h> 60bf02a0dSNamhyung Kim #include <errno.h> 70bf02a0dSNamhyung Kim #include <unistd.h> 80bf02a0dSNamhyung Kim #include <pthread.h> 90bf02a0dSNamhyung Kim #include <sys/mman.h> 100bf02a0dSNamhyung Kim #include <sys/wait.h> 110bf02a0dSNamhyung Kim #include <linux/kernel.h> 120bf02a0dSNamhyung Kim #include <linux/time64.h> 130bf02a0dSNamhyung Kim #include <linux/list.h> 140bf02a0dSNamhyung Kim #include <linux/err.h> 150bf02a0dSNamhyung Kim #include <internal/lib.h> 160bf02a0dSNamhyung Kim #include <subcmd/parse-options.h> 170bf02a0dSNamhyung Kim 180bf02a0dSNamhyung Kim #include "bench.h" 190bf02a0dSNamhyung Kim #include "util/data.h" 200bf02a0dSNamhyung Kim #include "util/stat.h" 210bf02a0dSNamhyung Kim #include "util/debug.h" 220bf02a0dSNamhyung Kim #include "util/event.h" 230bf02a0dSNamhyung Kim #include "util/symbol.h" 240bf02a0dSNamhyung Kim #include "util/session.h" 250bf02a0dSNamhyung Kim #include "util/build-id.h" 260bf02a0dSNamhyung Kim #include "util/synthetic-events.h" 270bf02a0dSNamhyung Kim 280bf02a0dSNamhyung Kim #define MMAP_DEV_MAJOR 8 290bf02a0dSNamhyung Kim #define DSO_MMAP_RATIO 4 300bf02a0dSNamhyung Kim 310bf02a0dSNamhyung Kim static unsigned int iterations = 100; 320bf02a0dSNamhyung Kim static unsigned int nr_mmaps = 100; 330bf02a0dSNamhyung Kim static unsigned int nr_samples = 100; /* samples per mmap */ 340bf02a0dSNamhyung Kim 350bf02a0dSNamhyung Kim static u64 bench_sample_type; 360bf02a0dSNamhyung Kim static u16 bench_id_hdr_size; 370bf02a0dSNamhyung Kim 380bf02a0dSNamhyung Kim struct bench_data { 390bf02a0dSNamhyung Kim int pid; 400bf02a0dSNamhyung Kim int input_pipe[2]; 410bf02a0dSNamhyung Kim int output_pipe[2]; 420bf02a0dSNamhyung Kim pthread_t th; 430bf02a0dSNamhyung Kim }; 440bf02a0dSNamhyung Kim 450bf02a0dSNamhyung Kim struct bench_dso { 460bf02a0dSNamhyung Kim struct list_head list; 470bf02a0dSNamhyung Kim char *name; 480bf02a0dSNamhyung Kim int ino; 490bf02a0dSNamhyung Kim }; 500bf02a0dSNamhyung Kim 510bf02a0dSNamhyung Kim static int nr_dsos; 520bf02a0dSNamhyung Kim static struct bench_dso *dsos; 530bf02a0dSNamhyung Kim 540bf02a0dSNamhyung Kim extern int cmd_inject(int argc, const char *argv[]); 550bf02a0dSNamhyung Kim 560bf02a0dSNamhyung Kim static const struct option options[] = { 570bf02a0dSNamhyung Kim OPT_UINTEGER('i', "iterations", &iterations, 580bf02a0dSNamhyung Kim "Number of iterations used to compute average (default: 100)"), 590bf02a0dSNamhyung Kim OPT_UINTEGER('m', "nr-mmaps", &nr_mmaps, 600bf02a0dSNamhyung Kim "Number of mmap events for each iteration (default: 100)"), 610bf02a0dSNamhyung Kim OPT_UINTEGER('n', "nr-samples", &nr_samples, 620bf02a0dSNamhyung Kim "Number of sample events per mmap event (default: 100)"), 630bf02a0dSNamhyung Kim OPT_INCR('v', "verbose", &verbose, 640bf02a0dSNamhyung Kim "be more verbose (show iteration count, DSO name, etc)"), 650bf02a0dSNamhyung Kim OPT_END() 660bf02a0dSNamhyung Kim }; 670bf02a0dSNamhyung Kim 680bf02a0dSNamhyung Kim static const char *const bench_usage[] = { 690bf02a0dSNamhyung Kim "perf bench internals inject-build-id <options>", 700bf02a0dSNamhyung Kim NULL 710bf02a0dSNamhyung Kim }; 720bf02a0dSNamhyung Kim 730bf02a0dSNamhyung Kim /* 740bf02a0dSNamhyung Kim * Helper for collect_dso that adds the given file as a dso to dso_list 750bf02a0dSNamhyung Kim * if it contains a build-id. Stops after collecting 4 times more than 760bf02a0dSNamhyung Kim * we need (for MMAP2 events). 770bf02a0dSNamhyung Kim */ 780bf02a0dSNamhyung Kim static int add_dso(const char *fpath, const struct stat *sb __maybe_unused, 790bf02a0dSNamhyung Kim int typeflag, struct FTW *ftwbuf __maybe_unused) 800bf02a0dSNamhyung Kim { 810bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[nr_dsos]; 820aba7f03SJiri Olsa struct build_id bid; 830bf02a0dSNamhyung Kim 840bf02a0dSNamhyung Kim if (typeflag == FTW_D || typeflag == FTW_SL) 850bf02a0dSNamhyung Kim return 0; 860bf02a0dSNamhyung Kim 87f766819cSJiri Olsa if (filename__read_build_id(fpath, &bid) < 0) 880bf02a0dSNamhyung Kim return 0; 890bf02a0dSNamhyung Kim 900bf02a0dSNamhyung Kim dso->name = realpath(fpath, NULL); 910bf02a0dSNamhyung Kim if (dso->name == NULL) 920bf02a0dSNamhyung Kim return -1; 930bf02a0dSNamhyung Kim 940bf02a0dSNamhyung Kim dso->ino = nr_dsos++; 950bf02a0dSNamhyung Kim pr_debug2(" Adding DSO: %s\n", fpath); 960bf02a0dSNamhyung Kim 970bf02a0dSNamhyung Kim /* stop if we collected enough DSOs */ 980bf02a0dSNamhyung Kim if ((unsigned int)nr_dsos == DSO_MMAP_RATIO * nr_mmaps) 990bf02a0dSNamhyung Kim return 1; 1000bf02a0dSNamhyung Kim 1010bf02a0dSNamhyung Kim return 0; 1020bf02a0dSNamhyung Kim } 1030bf02a0dSNamhyung Kim 1040bf02a0dSNamhyung Kim static void collect_dso(void) 1050bf02a0dSNamhyung Kim { 1060bf02a0dSNamhyung Kim dsos = calloc(nr_mmaps * DSO_MMAP_RATIO, sizeof(*dsos)); 1070bf02a0dSNamhyung Kim if (dsos == NULL) { 1080bf02a0dSNamhyung Kim printf(" Memory allocation failed\n"); 1090bf02a0dSNamhyung Kim exit(1); 1100bf02a0dSNamhyung Kim } 1110bf02a0dSNamhyung Kim 1120bf02a0dSNamhyung Kim if (nftw("/usr/lib/", add_dso, 10, FTW_PHYS) < 0) 1130bf02a0dSNamhyung Kim return; 1140bf02a0dSNamhyung Kim 1150bf02a0dSNamhyung Kim pr_debug(" Collected %d DSOs\n", nr_dsos); 1160bf02a0dSNamhyung Kim } 1170bf02a0dSNamhyung Kim 1180bf02a0dSNamhyung Kim static void release_dso(void) 1190bf02a0dSNamhyung Kim { 1200bf02a0dSNamhyung Kim int i; 1210bf02a0dSNamhyung Kim 1220bf02a0dSNamhyung Kim for (i = 0; i < nr_dsos; i++) { 1230bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[i]; 1240bf02a0dSNamhyung Kim 1250bf02a0dSNamhyung Kim free(dso->name); 1260bf02a0dSNamhyung Kim } 1270bf02a0dSNamhyung Kim free(dsos); 1280bf02a0dSNamhyung Kim } 1290bf02a0dSNamhyung Kim 1300bf02a0dSNamhyung Kim /* Fake address used by mmap and sample events */ 1310bf02a0dSNamhyung Kim static u64 dso_map_addr(struct bench_dso *dso) 1320bf02a0dSNamhyung Kim { 1330bf02a0dSNamhyung Kim return 0x400000ULL + dso->ino * 8192ULL; 1340bf02a0dSNamhyung Kim } 1350bf02a0dSNamhyung Kim 1360bf02a0dSNamhyung Kim static u32 synthesize_attr(struct bench_data *data) 1370bf02a0dSNamhyung Kim { 1380bf02a0dSNamhyung Kim union perf_event event; 1390bf02a0dSNamhyung Kim 1400bf02a0dSNamhyung Kim memset(&event, 0, sizeof(event.attr) + sizeof(u64)); 1410bf02a0dSNamhyung Kim 1420bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_HEADER_ATTR; 1430bf02a0dSNamhyung Kim event.header.size = sizeof(event.attr) + sizeof(u64); 1440bf02a0dSNamhyung Kim 1450bf02a0dSNamhyung Kim event.attr.attr.type = PERF_TYPE_SOFTWARE; 1460bf02a0dSNamhyung Kim event.attr.attr.config = PERF_COUNT_SW_TASK_CLOCK; 1470bf02a0dSNamhyung Kim event.attr.attr.exclude_kernel = 1; 1480bf02a0dSNamhyung Kim event.attr.attr.sample_id_all = 1; 1490bf02a0dSNamhyung Kim event.attr.attr.sample_type = bench_sample_type; 1500bf02a0dSNamhyung Kim 1510bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 1520bf02a0dSNamhyung Kim } 1530bf02a0dSNamhyung Kim 1540bf02a0dSNamhyung Kim static u32 synthesize_fork(struct bench_data *data) 1550bf02a0dSNamhyung Kim { 1560bf02a0dSNamhyung Kim union perf_event event; 1570bf02a0dSNamhyung Kim 1580bf02a0dSNamhyung Kim memset(&event, 0, sizeof(event.fork) + bench_id_hdr_size); 1590bf02a0dSNamhyung Kim 1600bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_FORK; 1610bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_FORK_EXEC; 1620bf02a0dSNamhyung Kim event.header.size = sizeof(event.fork) + bench_id_hdr_size; 1630bf02a0dSNamhyung Kim 1640bf02a0dSNamhyung Kim event.fork.ppid = 1; 1650bf02a0dSNamhyung Kim event.fork.ptid = 1; 1660bf02a0dSNamhyung Kim event.fork.pid = data->pid; 1670bf02a0dSNamhyung Kim event.fork.tid = data->pid; 1680bf02a0dSNamhyung Kim 1690bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 1700bf02a0dSNamhyung Kim } 1710bf02a0dSNamhyung Kim 1720bf02a0dSNamhyung Kim static u32 synthesize_mmap(struct bench_data *data, struct bench_dso *dso, 1730bf02a0dSNamhyung Kim u64 timestamp) 1740bf02a0dSNamhyung Kim { 1750bf02a0dSNamhyung Kim union perf_event event; 1760bf02a0dSNamhyung Kim size_t len = offsetof(struct perf_record_mmap2, filename); 1770bf02a0dSNamhyung Kim u64 *id_hdr_ptr = (void *)&event; 1780bf02a0dSNamhyung Kim int ts_idx; 1790bf02a0dSNamhyung Kim 1800bf02a0dSNamhyung Kim len += roundup(strlen(dso->name) + 1, 8) + bench_id_hdr_size; 1810bf02a0dSNamhyung Kim 1820bf02a0dSNamhyung Kim memset(&event, 0, min(len, sizeof(event.mmap2))); 1830bf02a0dSNamhyung Kim 1840bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_MMAP2; 1850bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_USER; 1860bf02a0dSNamhyung Kim event.header.size = len; 1870bf02a0dSNamhyung Kim 1880bf02a0dSNamhyung Kim event.mmap2.pid = data->pid; 1890bf02a0dSNamhyung Kim event.mmap2.tid = data->pid; 1900bf02a0dSNamhyung Kim event.mmap2.maj = MMAP_DEV_MAJOR; 1910bf02a0dSNamhyung Kim event.mmap2.ino = dso->ino; 1920bf02a0dSNamhyung Kim 1930bf02a0dSNamhyung Kim strcpy(event.mmap2.filename, dso->name); 1940bf02a0dSNamhyung Kim 1950bf02a0dSNamhyung Kim event.mmap2.start = dso_map_addr(dso); 1960bf02a0dSNamhyung Kim event.mmap2.len = 4096; 1970bf02a0dSNamhyung Kim event.mmap2.prot = PROT_EXEC; 1980bf02a0dSNamhyung Kim 1990bf02a0dSNamhyung Kim if (len > sizeof(event.mmap2)) { 2000bf02a0dSNamhyung Kim /* write mmap2 event first */ 2010bf02a0dSNamhyung Kim writen(data->input_pipe[1], &event, len - bench_id_hdr_size); 2020bf02a0dSNamhyung Kim /* zero-fill sample id header */ 2030bf02a0dSNamhyung Kim memset(id_hdr_ptr, 0, bench_id_hdr_size); 2040bf02a0dSNamhyung Kim /* put timestamp in the right position */ 2050bf02a0dSNamhyung Kim ts_idx = (bench_id_hdr_size / sizeof(u64)) - 2; 2060bf02a0dSNamhyung Kim id_hdr_ptr[ts_idx] = timestamp; 2070bf02a0dSNamhyung Kim writen(data->input_pipe[1], id_hdr_ptr, bench_id_hdr_size); 2080bf02a0dSNamhyung Kim } else { 2090bf02a0dSNamhyung Kim ts_idx = (len / sizeof(u64)) - 2; 2100bf02a0dSNamhyung Kim id_hdr_ptr[ts_idx] = timestamp; 2110bf02a0dSNamhyung Kim writen(data->input_pipe[1], &event, len); 2120bf02a0dSNamhyung Kim } 2130bf02a0dSNamhyung Kim return len; 2140bf02a0dSNamhyung Kim } 2150bf02a0dSNamhyung Kim 2160bf02a0dSNamhyung Kim static u32 synthesize_sample(struct bench_data *data, struct bench_dso *dso, 2170bf02a0dSNamhyung Kim u64 timestamp) 2180bf02a0dSNamhyung Kim { 2190bf02a0dSNamhyung Kim union perf_event event; 2200bf02a0dSNamhyung Kim struct perf_sample sample = { 2210bf02a0dSNamhyung Kim .tid = data->pid, 2220bf02a0dSNamhyung Kim .pid = data->pid, 2230bf02a0dSNamhyung Kim .ip = dso_map_addr(dso), 2240bf02a0dSNamhyung Kim .time = timestamp, 2250bf02a0dSNamhyung Kim }; 2260bf02a0dSNamhyung Kim 2270bf02a0dSNamhyung Kim event.header.type = PERF_RECORD_SAMPLE; 2280bf02a0dSNamhyung Kim event.header.misc = PERF_RECORD_MISC_USER; 2290bf02a0dSNamhyung Kim event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0); 2300bf02a0dSNamhyung Kim 2310bf02a0dSNamhyung Kim perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample); 2320bf02a0dSNamhyung Kim 2330bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &event, event.header.size); 2340bf02a0dSNamhyung Kim } 2350bf02a0dSNamhyung Kim 2360bf02a0dSNamhyung Kim static u32 synthesize_flush(struct bench_data *data) 2370bf02a0dSNamhyung Kim { 2380bf02a0dSNamhyung Kim struct perf_event_header header = { 2390bf02a0dSNamhyung Kim .size = sizeof(header), 2400bf02a0dSNamhyung Kim .type = PERF_RECORD_FINISHED_ROUND, 2410bf02a0dSNamhyung Kim }; 2420bf02a0dSNamhyung Kim 2430bf02a0dSNamhyung Kim return writen(data->input_pipe[1], &header, header.size); 2440bf02a0dSNamhyung Kim } 2450bf02a0dSNamhyung Kim 2460bf02a0dSNamhyung Kim static void *data_reader(void *arg) 2470bf02a0dSNamhyung Kim { 2480bf02a0dSNamhyung Kim struct bench_data *data = arg; 2490bf02a0dSNamhyung Kim char buf[8192]; 2500bf02a0dSNamhyung Kim int flag; 2510bf02a0dSNamhyung Kim int n; 2520bf02a0dSNamhyung Kim 2530bf02a0dSNamhyung Kim flag = fcntl(data->output_pipe[0], F_GETFL); 2540bf02a0dSNamhyung Kim fcntl(data->output_pipe[0], F_SETFL, flag | O_NONBLOCK); 2550bf02a0dSNamhyung Kim 2560bf02a0dSNamhyung Kim /* read out data from child */ 2570bf02a0dSNamhyung Kim while (true) { 2580bf02a0dSNamhyung Kim n = read(data->output_pipe[0], buf, sizeof(buf)); 2590bf02a0dSNamhyung Kim if (n > 0) 2600bf02a0dSNamhyung Kim continue; 2610bf02a0dSNamhyung Kim if (n == 0) 2620bf02a0dSNamhyung Kim break; 2630bf02a0dSNamhyung Kim 2640bf02a0dSNamhyung Kim if (errno != EINTR && errno != EAGAIN) 2650bf02a0dSNamhyung Kim break; 2660bf02a0dSNamhyung Kim 2670bf02a0dSNamhyung Kim usleep(100); 2680bf02a0dSNamhyung Kim } 2690bf02a0dSNamhyung Kim 2700bf02a0dSNamhyung Kim close(data->output_pipe[0]); 2710bf02a0dSNamhyung Kim return NULL; 2720bf02a0dSNamhyung Kim } 2730bf02a0dSNamhyung Kim 274bf7ef5ddSNamhyung Kim static int setup_injection(struct bench_data *data, bool build_id_all) 2750bf02a0dSNamhyung Kim { 2760bf02a0dSNamhyung Kim int ready_pipe[2]; 2770bf02a0dSNamhyung Kim int dev_null_fd; 2780bf02a0dSNamhyung Kim char buf; 2790bf02a0dSNamhyung Kim 2800bf02a0dSNamhyung Kim if (pipe(ready_pipe) < 0) 2810bf02a0dSNamhyung Kim return -1; 2820bf02a0dSNamhyung Kim 2830bf02a0dSNamhyung Kim if (pipe(data->input_pipe) < 0) 2840bf02a0dSNamhyung Kim return -1; 2850bf02a0dSNamhyung Kim 2860bf02a0dSNamhyung Kim if (pipe(data->output_pipe) < 0) 2870bf02a0dSNamhyung Kim return -1; 2880bf02a0dSNamhyung Kim 2890bf02a0dSNamhyung Kim data->pid = fork(); 2900bf02a0dSNamhyung Kim if (data->pid < 0) 2910bf02a0dSNamhyung Kim return -1; 2920bf02a0dSNamhyung Kim 2930bf02a0dSNamhyung Kim if (data->pid == 0) { 2940bf02a0dSNamhyung Kim const char **inject_argv; 295bf7ef5ddSNamhyung Kim int inject_argc = 2; 2960bf02a0dSNamhyung Kim 2970bf02a0dSNamhyung Kim close(data->input_pipe[1]); 2980bf02a0dSNamhyung Kim close(data->output_pipe[0]); 2990bf02a0dSNamhyung Kim close(ready_pipe[0]); 3000bf02a0dSNamhyung Kim 3010bf02a0dSNamhyung Kim dup2(data->input_pipe[0], STDIN_FILENO); 3020bf02a0dSNamhyung Kim close(data->input_pipe[0]); 3030bf02a0dSNamhyung Kim dup2(data->output_pipe[1], STDOUT_FILENO); 3040bf02a0dSNamhyung Kim close(data->output_pipe[1]); 3050bf02a0dSNamhyung Kim 3060bf02a0dSNamhyung Kim dev_null_fd = open("/dev/null", O_WRONLY); 3070bf02a0dSNamhyung Kim if (dev_null_fd < 0) 3080bf02a0dSNamhyung Kim exit(1); 3090bf02a0dSNamhyung Kim 3100bf02a0dSNamhyung Kim dup2(dev_null_fd, STDERR_FILENO); 3110bf02a0dSNamhyung Kim 312bf7ef5ddSNamhyung Kim if (build_id_all) 313bf7ef5ddSNamhyung Kim inject_argc++; 314bf7ef5ddSNamhyung Kim 315bf7ef5ddSNamhyung Kim inject_argv = calloc(inject_argc + 1, sizeof(*inject_argv)); 3160bf02a0dSNamhyung Kim if (inject_argv == NULL) 3170bf02a0dSNamhyung Kim exit(1); 3180bf02a0dSNamhyung Kim 3190bf02a0dSNamhyung Kim inject_argv[0] = strdup("inject"); 3200bf02a0dSNamhyung Kim inject_argv[1] = strdup("-b"); 321bf7ef5ddSNamhyung Kim if (build_id_all) 322bf7ef5ddSNamhyung Kim inject_argv[2] = strdup("--buildid-all"); 3230bf02a0dSNamhyung Kim 3240bf02a0dSNamhyung Kim /* signal that we're ready to go */ 3250bf02a0dSNamhyung Kim close(ready_pipe[1]); 3260bf02a0dSNamhyung Kim 327bf7ef5ddSNamhyung Kim cmd_inject(inject_argc, inject_argv); 3280bf02a0dSNamhyung Kim 3290bf02a0dSNamhyung Kim exit(0); 3300bf02a0dSNamhyung Kim } 3310bf02a0dSNamhyung Kim 3320bf02a0dSNamhyung Kim pthread_create(&data->th, NULL, data_reader, data); 3330bf02a0dSNamhyung Kim 3340bf02a0dSNamhyung Kim close(ready_pipe[1]); 3350bf02a0dSNamhyung Kim close(data->input_pipe[0]); 3360bf02a0dSNamhyung Kim close(data->output_pipe[1]); 3370bf02a0dSNamhyung Kim 3380bf02a0dSNamhyung Kim /* wait for child ready */ 3390bf02a0dSNamhyung Kim if (read(ready_pipe[0], &buf, 1) < 0) 3400bf02a0dSNamhyung Kim return -1; 3410bf02a0dSNamhyung Kim close(ready_pipe[0]); 3420bf02a0dSNamhyung Kim 3430bf02a0dSNamhyung Kim return 0; 3440bf02a0dSNamhyung Kim } 3450bf02a0dSNamhyung Kim 3460bf02a0dSNamhyung Kim static int inject_build_id(struct bench_data *data, u64 *max_rss) 3470bf02a0dSNamhyung Kim { 3480bf02a0dSNamhyung Kim int status; 3490bf02a0dSNamhyung Kim unsigned int i, k; 3500bf02a0dSNamhyung Kim struct rusage rusage; 3510bf02a0dSNamhyung Kim u64 len = 0; 3520bf02a0dSNamhyung Kim 3530bf02a0dSNamhyung Kim /* this makes the child to run */ 3540bf02a0dSNamhyung Kim if (perf_header__write_pipe(data->input_pipe[1]) < 0) 3550bf02a0dSNamhyung Kim return -1; 3560bf02a0dSNamhyung Kim 3570bf02a0dSNamhyung Kim len += synthesize_attr(data); 3580bf02a0dSNamhyung Kim len += synthesize_fork(data); 3590bf02a0dSNamhyung Kim 3600bf02a0dSNamhyung Kim for (i = 0; i < nr_mmaps; i++) { 3610bf02a0dSNamhyung Kim int idx = rand() % (nr_dsos - 1); 3620bf02a0dSNamhyung Kim struct bench_dso *dso = &dsos[idx]; 3630bf02a0dSNamhyung Kim u64 timestamp = rand() % 1000000; 3640bf02a0dSNamhyung Kim 3650bf02a0dSNamhyung Kim pr_debug2(" [%d] injecting: %s\n", i+1, dso->name); 3660bf02a0dSNamhyung Kim len += synthesize_mmap(data, dso, timestamp); 3670bf02a0dSNamhyung Kim 3680bf02a0dSNamhyung Kim for (k = 0; k < nr_samples; k++) 3690bf02a0dSNamhyung Kim len += synthesize_sample(data, dso, timestamp + k * 1000); 3700bf02a0dSNamhyung Kim 3710bf02a0dSNamhyung Kim if ((i + 1) % 10 == 0) 3720bf02a0dSNamhyung Kim len += synthesize_flush(data); 3730bf02a0dSNamhyung Kim } 3740bf02a0dSNamhyung Kim 375*a78e724fSXiong Zhenwu /* this makes the child to finish */ 3760bf02a0dSNamhyung Kim close(data->input_pipe[1]); 3770bf02a0dSNamhyung Kim 3780bf02a0dSNamhyung Kim wait4(data->pid, &status, 0, &rusage); 3790bf02a0dSNamhyung Kim *max_rss = rusage.ru_maxrss; 3800bf02a0dSNamhyung Kim 3810bf02a0dSNamhyung Kim pr_debug(" Child %d exited with %d\n", data->pid, status); 3820bf02a0dSNamhyung Kim 3830bf02a0dSNamhyung Kim return 0; 3840bf02a0dSNamhyung Kim } 3850bf02a0dSNamhyung Kim 386bf7ef5ddSNamhyung Kim static void do_inject_loop(struct bench_data *data, bool build_id_all) 3870bf02a0dSNamhyung Kim { 3880bf02a0dSNamhyung Kim unsigned int i; 3890bf02a0dSNamhyung Kim struct stats time_stats, mem_stats; 3900bf02a0dSNamhyung Kim double time_average, time_stddev; 3910bf02a0dSNamhyung Kim double mem_average, mem_stddev; 3920bf02a0dSNamhyung Kim 3930bf02a0dSNamhyung Kim init_stats(&time_stats); 3940bf02a0dSNamhyung Kim init_stats(&mem_stats); 3950bf02a0dSNamhyung Kim 396bf7ef5ddSNamhyung Kim pr_debug(" Build-id%s injection benchmark\n", build_id_all ? "-all" : ""); 3970bf02a0dSNamhyung Kim 3980bf02a0dSNamhyung Kim for (i = 0; i < iterations; i++) { 3990bf02a0dSNamhyung Kim struct timeval start, end, diff; 4000bf02a0dSNamhyung Kim u64 runtime_us, max_rss; 4010bf02a0dSNamhyung Kim 4020bf02a0dSNamhyung Kim pr_debug(" Iteration #%d\n", i+1); 4030bf02a0dSNamhyung Kim 404bf7ef5ddSNamhyung Kim if (setup_injection(data, build_id_all) < 0) { 4050bf02a0dSNamhyung Kim printf(" Build-id injection setup failed\n"); 4060bf02a0dSNamhyung Kim break; 4070bf02a0dSNamhyung Kim } 4080bf02a0dSNamhyung Kim 4090bf02a0dSNamhyung Kim gettimeofday(&start, NULL); 4100bf02a0dSNamhyung Kim if (inject_build_id(data, &max_rss) < 0) { 4110bf02a0dSNamhyung Kim printf(" Build-id injection failed\n"); 4120bf02a0dSNamhyung Kim break; 4130bf02a0dSNamhyung Kim } 4140bf02a0dSNamhyung Kim 4150bf02a0dSNamhyung Kim gettimeofday(&end, NULL); 4160bf02a0dSNamhyung Kim timersub(&end, &start, &diff); 4170bf02a0dSNamhyung Kim runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; 4180bf02a0dSNamhyung Kim update_stats(&time_stats, runtime_us); 4190bf02a0dSNamhyung Kim update_stats(&mem_stats, max_rss); 4200bf02a0dSNamhyung Kim 4210bf02a0dSNamhyung Kim pthread_join(data->th, NULL); 4220bf02a0dSNamhyung Kim } 4230bf02a0dSNamhyung Kim 4240bf02a0dSNamhyung Kim time_average = avg_stats(&time_stats) / USEC_PER_MSEC; 4250bf02a0dSNamhyung Kim time_stddev = stddev_stats(&time_stats) / USEC_PER_MSEC; 426bf7ef5ddSNamhyung Kim printf(" Average build-id%s injection took: %.3f msec (+- %.3f msec)\n", 427bf7ef5ddSNamhyung Kim build_id_all ? "-all" : "", time_average, time_stddev); 4280bf02a0dSNamhyung Kim 4290bf02a0dSNamhyung Kim /* each iteration, it processes MMAP2 + BUILD_ID + nr_samples * SAMPLE */ 4300bf02a0dSNamhyung Kim time_average = avg_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 4310bf02a0dSNamhyung Kim time_stddev = stddev_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 4320bf02a0dSNamhyung Kim printf(" Average time per event: %.3f usec (+- %.3f usec)\n", 4330bf02a0dSNamhyung Kim time_average, time_stddev); 4340bf02a0dSNamhyung Kim 4350bf02a0dSNamhyung Kim mem_average = avg_stats(&mem_stats); 4360bf02a0dSNamhyung Kim mem_stddev = stddev_stats(&mem_stats); 4370bf02a0dSNamhyung Kim printf(" Average memory usage: %.0f KB (+- %.0f KB)\n", 4380bf02a0dSNamhyung Kim mem_average, mem_stddev); 439bf7ef5ddSNamhyung Kim } 440bf7ef5ddSNamhyung Kim 441bf7ef5ddSNamhyung Kim static int do_inject_loops(struct bench_data *data) 442bf7ef5ddSNamhyung Kim { 443bf7ef5ddSNamhyung Kim 444bf7ef5ddSNamhyung Kim srand(time(NULL)); 445bf7ef5ddSNamhyung Kim symbol__init(NULL); 446bf7ef5ddSNamhyung Kim 447bf7ef5ddSNamhyung Kim bench_sample_type = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP; 448bf7ef5ddSNamhyung Kim bench_sample_type |= PERF_SAMPLE_TID | PERF_SAMPLE_TIME; 449bf7ef5ddSNamhyung Kim bench_id_hdr_size = 32; 450bf7ef5ddSNamhyung Kim 451bf7ef5ddSNamhyung Kim collect_dso(); 452bf7ef5ddSNamhyung Kim if (nr_dsos == 0) { 453bf7ef5ddSNamhyung Kim printf(" Cannot collect DSOs for injection\n"); 454bf7ef5ddSNamhyung Kim return -1; 455bf7ef5ddSNamhyung Kim } 456bf7ef5ddSNamhyung Kim 457bf7ef5ddSNamhyung Kim do_inject_loop(data, false); 458bf7ef5ddSNamhyung Kim do_inject_loop(data, true); 4590bf02a0dSNamhyung Kim 4600bf02a0dSNamhyung Kim release_dso(); 4610bf02a0dSNamhyung Kim return 0; 4620bf02a0dSNamhyung Kim } 4630bf02a0dSNamhyung Kim 4640bf02a0dSNamhyung Kim int bench_inject_build_id(int argc, const char **argv) 4650bf02a0dSNamhyung Kim { 4660bf02a0dSNamhyung Kim struct bench_data data; 4670bf02a0dSNamhyung Kim 4680bf02a0dSNamhyung Kim argc = parse_options(argc, argv, options, bench_usage, 0); 4690bf02a0dSNamhyung Kim if (argc) { 4700bf02a0dSNamhyung Kim usage_with_options(bench_usage, options); 4710bf02a0dSNamhyung Kim exit(EXIT_FAILURE); 4720bf02a0dSNamhyung Kim } 4730bf02a0dSNamhyung Kim 474bf7ef5ddSNamhyung Kim return do_inject_loops(&data); 4750bf02a0dSNamhyung Kim } 4760bf02a0dSNamhyung Kim 477