18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <stdlib.h> 38c2ecf20Sopenharmony_ci#include <stddef.h> 48c2ecf20Sopenharmony_ci#include <ftw.h> 58c2ecf20Sopenharmony_ci#include <fcntl.h> 68c2ecf20Sopenharmony_ci#include <errno.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <pthread.h> 98c2ecf20Sopenharmony_ci#include <sys/mman.h> 108c2ecf20Sopenharmony_ci#include <sys/wait.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/time64.h> 138c2ecf20Sopenharmony_ci#include <linux/list.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <internal/lib.h> 168c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "bench.h" 198c2ecf20Sopenharmony_ci#include "util/data.h" 208c2ecf20Sopenharmony_ci#include "util/stat.h" 218c2ecf20Sopenharmony_ci#include "util/debug.h" 228c2ecf20Sopenharmony_ci#include "util/event.h" 238c2ecf20Sopenharmony_ci#include "util/symbol.h" 248c2ecf20Sopenharmony_ci#include "util/session.h" 258c2ecf20Sopenharmony_ci#include "util/build-id.h" 268c2ecf20Sopenharmony_ci#include "util/synthetic-events.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MMAP_DEV_MAJOR 8 298c2ecf20Sopenharmony_ci#define DSO_MMAP_RATIO 4 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned int iterations = 100; 328c2ecf20Sopenharmony_cistatic unsigned int nr_mmaps = 100; 338c2ecf20Sopenharmony_cistatic unsigned int nr_samples = 100; /* samples per mmap */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic u64 bench_sample_type; 368c2ecf20Sopenharmony_cistatic u16 bench_id_hdr_size; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct bench_data { 398c2ecf20Sopenharmony_ci int pid; 408c2ecf20Sopenharmony_ci int input_pipe[2]; 418c2ecf20Sopenharmony_ci int output_pipe[2]; 428c2ecf20Sopenharmony_ci pthread_t th; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct bench_dso { 468c2ecf20Sopenharmony_ci struct list_head list; 478c2ecf20Sopenharmony_ci char *name; 488c2ecf20Sopenharmony_ci int ino; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int nr_dsos; 528c2ecf20Sopenharmony_cistatic struct bench_dso *dsos; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciextern int cmd_inject(int argc, const char *argv[]); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const struct option options[] = { 578c2ecf20Sopenharmony_ci OPT_UINTEGER('i', "iterations", &iterations, 588c2ecf20Sopenharmony_ci "Number of iterations used to compute average (default: 100)"), 598c2ecf20Sopenharmony_ci OPT_UINTEGER('m', "nr-mmaps", &nr_mmaps, 608c2ecf20Sopenharmony_ci "Number of mmap events for each iteration (default: 100)"), 618c2ecf20Sopenharmony_ci OPT_UINTEGER('n', "nr-samples", &nr_samples, 628c2ecf20Sopenharmony_ci "Number of sample events per mmap event (default: 100)"), 638c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 648c2ecf20Sopenharmony_ci "be more verbose (show iteration count, DSO name, etc)"), 658c2ecf20Sopenharmony_ci OPT_END() 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const char *const bench_usage[] = { 698c2ecf20Sopenharmony_ci "perf bench internals inject-build-id <options>", 708c2ecf20Sopenharmony_ci NULL 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * Helper for collect_dso that adds the given file as a dso to dso_list 758c2ecf20Sopenharmony_ci * if it contains a build-id. Stops after collecting 4 times more than 768c2ecf20Sopenharmony_ci * we need (for MMAP2 events). 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic int add_dso(const char *fpath, const struct stat *sb __maybe_unused, 798c2ecf20Sopenharmony_ci int typeflag, struct FTW *ftwbuf __maybe_unused) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct bench_dso *dso = &dsos[nr_dsos]; 828c2ecf20Sopenharmony_ci struct build_id bid; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (typeflag == FTW_D || typeflag == FTW_SL) 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (filename__read_build_id(fpath, &bid) < 0) 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci dso->name = realpath(fpath, NULL); 918c2ecf20Sopenharmony_ci if (dso->name == NULL) 928c2ecf20Sopenharmony_ci return -1; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci dso->ino = nr_dsos++; 958c2ecf20Sopenharmony_ci pr_debug2(" Adding DSO: %s\n", fpath); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* stop if we collected enough DSOs */ 988c2ecf20Sopenharmony_ci if ((unsigned int)nr_dsos == DSO_MMAP_RATIO * nr_mmaps) 998c2ecf20Sopenharmony_ci return 1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void collect_dso(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci dsos = calloc(nr_mmaps * DSO_MMAP_RATIO, sizeof(*dsos)); 1078c2ecf20Sopenharmony_ci if (dsos == NULL) { 1088c2ecf20Sopenharmony_ci printf(" Memory allocation failed\n"); 1098c2ecf20Sopenharmony_ci exit(1); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (nftw("/usr/lib/", add_dso, 10, FTW_PHYS) < 0) 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci pr_debug(" Collected %d DSOs\n", nr_dsos); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void release_dso(void) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int i; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci for (i = 0; i < nr_dsos; i++) { 1238c2ecf20Sopenharmony_ci struct bench_dso *dso = &dsos[i]; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci free(dso->name); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci free(dsos); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Fake address used by mmap and sample events */ 1318c2ecf20Sopenharmony_cistatic u64 dso_map_addr(struct bench_dso *dso) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return 0x400000ULL + dso->ino * 8192ULL; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic ssize_t synthesize_attr(struct bench_data *data) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci union perf_event event; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci memset(&event, 0, sizeof(event.attr) + sizeof(u64)); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_HEADER_ATTR; 1438c2ecf20Sopenharmony_ci event.header.size = sizeof(event.attr) + sizeof(u64); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci event.attr.attr.type = PERF_TYPE_SOFTWARE; 1468c2ecf20Sopenharmony_ci event.attr.attr.config = PERF_COUNT_SW_TASK_CLOCK; 1478c2ecf20Sopenharmony_ci event.attr.attr.exclude_kernel = 1; 1488c2ecf20Sopenharmony_ci event.attr.attr.sample_id_all = 1; 1498c2ecf20Sopenharmony_ci event.attr.attr.sample_type = bench_sample_type; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return writen(data->input_pipe[1], &event, event.header.size); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic ssize_t synthesize_fork(struct bench_data *data) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci union perf_event event; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci memset(&event, 0, sizeof(event.fork) + bench_id_hdr_size); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_FORK; 1618c2ecf20Sopenharmony_ci event.header.misc = PERF_RECORD_MISC_FORK_EXEC; 1628c2ecf20Sopenharmony_ci event.header.size = sizeof(event.fork) + bench_id_hdr_size; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci event.fork.ppid = 1; 1658c2ecf20Sopenharmony_ci event.fork.ptid = 1; 1668c2ecf20Sopenharmony_ci event.fork.pid = data->pid; 1678c2ecf20Sopenharmony_ci event.fork.tid = data->pid; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return writen(data->input_pipe[1], &event, event.header.size); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic ssize_t synthesize_mmap(struct bench_data *data, struct bench_dso *dso, u64 timestamp) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci union perf_event event; 1758c2ecf20Sopenharmony_ci size_t len = offsetof(struct perf_record_mmap2, filename); 1768c2ecf20Sopenharmony_ci u64 *id_hdr_ptr = (void *)&event; 1778c2ecf20Sopenharmony_ci int ts_idx; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci len += roundup(strlen(dso->name) + 1, 8) + bench_id_hdr_size; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci memset(&event, 0, min(len, sizeof(event.mmap2))); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_MMAP2; 1848c2ecf20Sopenharmony_ci event.header.misc = PERF_RECORD_MISC_USER; 1858c2ecf20Sopenharmony_ci event.header.size = len; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci event.mmap2.pid = data->pid; 1888c2ecf20Sopenharmony_ci event.mmap2.tid = data->pid; 1898c2ecf20Sopenharmony_ci event.mmap2.maj = MMAP_DEV_MAJOR; 1908c2ecf20Sopenharmony_ci event.mmap2.ino = dso->ino; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci strcpy(event.mmap2.filename, dso->name); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci event.mmap2.start = dso_map_addr(dso); 1958c2ecf20Sopenharmony_ci event.mmap2.len = 4096; 1968c2ecf20Sopenharmony_ci event.mmap2.prot = PROT_EXEC; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (len > sizeof(event.mmap2)) { 1998c2ecf20Sopenharmony_ci /* write mmap2 event first */ 2008c2ecf20Sopenharmony_ci if (writen(data->input_pipe[1], &event, len - bench_id_hdr_size) < 0) 2018c2ecf20Sopenharmony_ci return -1; 2028c2ecf20Sopenharmony_ci /* zero-fill sample id header */ 2038c2ecf20Sopenharmony_ci memset(id_hdr_ptr, 0, bench_id_hdr_size); 2048c2ecf20Sopenharmony_ci /* put timestamp in the right position */ 2058c2ecf20Sopenharmony_ci ts_idx = (bench_id_hdr_size / sizeof(u64)) - 2; 2068c2ecf20Sopenharmony_ci id_hdr_ptr[ts_idx] = timestamp; 2078c2ecf20Sopenharmony_ci if (writen(data->input_pipe[1], id_hdr_ptr, bench_id_hdr_size) < 0) 2088c2ecf20Sopenharmony_ci return -1; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return len; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ts_idx = (len / sizeof(u64)) - 2; 2148c2ecf20Sopenharmony_ci id_hdr_ptr[ts_idx] = timestamp; 2158c2ecf20Sopenharmony_ci return writen(data->input_pipe[1], &event, len); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic ssize_t synthesize_sample(struct bench_data *data, struct bench_dso *dso, u64 timestamp) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci union perf_event event; 2218c2ecf20Sopenharmony_ci struct perf_sample sample = { 2228c2ecf20Sopenharmony_ci .tid = data->pid, 2238c2ecf20Sopenharmony_ci .pid = data->pid, 2248c2ecf20Sopenharmony_ci .ip = dso_map_addr(dso), 2258c2ecf20Sopenharmony_ci .time = timestamp, 2268c2ecf20Sopenharmony_ci }; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_SAMPLE; 2298c2ecf20Sopenharmony_ci event.header.misc = PERF_RECORD_MISC_USER; 2308c2ecf20Sopenharmony_ci event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return writen(data->input_pipe[1], &event, event.header.size); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic ssize_t synthesize_flush(struct bench_data *data) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct perf_event_header header = { 2408c2ecf20Sopenharmony_ci .size = sizeof(header), 2418c2ecf20Sopenharmony_ci .type = PERF_RECORD_FINISHED_ROUND, 2428c2ecf20Sopenharmony_ci }; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return writen(data->input_pipe[1], &header, header.size); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void *data_reader(void *arg) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct bench_data *data = arg; 2508c2ecf20Sopenharmony_ci char buf[8192]; 2518c2ecf20Sopenharmony_ci int flag; 2528c2ecf20Sopenharmony_ci int n; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci flag = fcntl(data->output_pipe[0], F_GETFL); 2558c2ecf20Sopenharmony_ci fcntl(data->output_pipe[0], F_SETFL, flag | O_NONBLOCK); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* read out data from child */ 2588c2ecf20Sopenharmony_ci while (true) { 2598c2ecf20Sopenharmony_ci n = read(data->output_pipe[0], buf, sizeof(buf)); 2608c2ecf20Sopenharmony_ci if (n > 0) 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci if (n == 0) 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (errno != EINTR && errno != EAGAIN) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci usleep(100); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci close(data->output_pipe[0]); 2728c2ecf20Sopenharmony_ci return NULL; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int setup_injection(struct bench_data *data, bool build_id_all) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int ready_pipe[2]; 2788c2ecf20Sopenharmony_ci int dev_null_fd; 2798c2ecf20Sopenharmony_ci char buf; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (pipe(ready_pipe) < 0) 2828c2ecf20Sopenharmony_ci return -1; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (pipe(data->input_pipe) < 0) 2858c2ecf20Sopenharmony_ci return -1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (pipe(data->output_pipe) < 0) 2888c2ecf20Sopenharmony_ci return -1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci data->pid = fork(); 2918c2ecf20Sopenharmony_ci if (data->pid < 0) 2928c2ecf20Sopenharmony_ci return -1; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (data->pid == 0) { 2958c2ecf20Sopenharmony_ci const char **inject_argv; 2968c2ecf20Sopenharmony_ci int inject_argc = 2; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci close(data->input_pipe[1]); 2998c2ecf20Sopenharmony_ci close(data->output_pipe[0]); 3008c2ecf20Sopenharmony_ci close(ready_pipe[0]); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci dup2(data->input_pipe[0], STDIN_FILENO); 3038c2ecf20Sopenharmony_ci close(data->input_pipe[0]); 3048c2ecf20Sopenharmony_ci dup2(data->output_pipe[1], STDOUT_FILENO); 3058c2ecf20Sopenharmony_ci close(data->output_pipe[1]); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci dev_null_fd = open("/dev/null", O_WRONLY); 3088c2ecf20Sopenharmony_ci if (dev_null_fd < 0) 3098c2ecf20Sopenharmony_ci exit(1); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci dup2(dev_null_fd, STDERR_FILENO); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (build_id_all) 3148c2ecf20Sopenharmony_ci inject_argc++; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci inject_argv = calloc(inject_argc + 1, sizeof(*inject_argv)); 3178c2ecf20Sopenharmony_ci if (inject_argv == NULL) 3188c2ecf20Sopenharmony_ci exit(1); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci inject_argv[0] = strdup("inject"); 3218c2ecf20Sopenharmony_ci inject_argv[1] = strdup("-b"); 3228c2ecf20Sopenharmony_ci if (build_id_all) 3238c2ecf20Sopenharmony_ci inject_argv[2] = strdup("--buildid-all"); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* signal that we're ready to go */ 3268c2ecf20Sopenharmony_ci close(ready_pipe[1]); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci cmd_inject(inject_argc, inject_argv); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci exit(0); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pthread_create(&data->th, NULL, data_reader, data); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci close(ready_pipe[1]); 3368c2ecf20Sopenharmony_ci close(data->input_pipe[0]); 3378c2ecf20Sopenharmony_ci close(data->output_pipe[1]); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* wait for child ready */ 3408c2ecf20Sopenharmony_ci if (read(ready_pipe[0], &buf, 1) < 0) 3418c2ecf20Sopenharmony_ci return -1; 3428c2ecf20Sopenharmony_ci close(ready_pipe[0]); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int inject_build_id(struct bench_data *data, u64 *max_rss) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int status; 3508c2ecf20Sopenharmony_ci unsigned int i, k; 3518c2ecf20Sopenharmony_ci struct rusage rusage; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* this makes the child to run */ 3548c2ecf20Sopenharmony_ci if (perf_header__write_pipe(data->input_pipe[1]) < 0) 3558c2ecf20Sopenharmony_ci return -1; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (synthesize_attr(data) < 0) 3588c2ecf20Sopenharmony_ci return -1; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (synthesize_fork(data) < 0) 3618c2ecf20Sopenharmony_ci return -1; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci for (i = 0; i < nr_mmaps; i++) { 3648c2ecf20Sopenharmony_ci int idx = rand() % (nr_dsos - 1); 3658c2ecf20Sopenharmony_ci struct bench_dso *dso = &dsos[idx]; 3668c2ecf20Sopenharmony_ci u64 timestamp = rand() % 1000000; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci pr_debug2(" [%d] injecting: %s\n", i+1, dso->name); 3698c2ecf20Sopenharmony_ci if (synthesize_mmap(data, dso, timestamp) < 0) 3708c2ecf20Sopenharmony_ci return -1; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci for (k = 0; k < nr_samples; k++) { 3738c2ecf20Sopenharmony_ci if (synthesize_sample(data, dso, timestamp + k * 1000) < 0) 3748c2ecf20Sopenharmony_ci return -1; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if ((i + 1) % 10 == 0) { 3788c2ecf20Sopenharmony_ci if (synthesize_flush(data) < 0) 3798c2ecf20Sopenharmony_ci return -1; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* tihs makes the child to finish */ 3848c2ecf20Sopenharmony_ci close(data->input_pipe[1]); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci wait4(data->pid, &status, 0, &rusage); 3878c2ecf20Sopenharmony_ci *max_rss = rusage.ru_maxrss; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pr_debug(" Child %d exited with %d\n", data->pid, status); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void do_inject_loop(struct bench_data *data, bool build_id_all) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci unsigned int i; 3978c2ecf20Sopenharmony_ci struct stats time_stats, mem_stats; 3988c2ecf20Sopenharmony_ci double time_average, time_stddev; 3998c2ecf20Sopenharmony_ci double mem_average, mem_stddev; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci init_stats(&time_stats); 4028c2ecf20Sopenharmony_ci init_stats(&mem_stats); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci pr_debug(" Build-id%s injection benchmark\n", build_id_all ? "-all" : ""); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 0; i < iterations; i++) { 4078c2ecf20Sopenharmony_ci struct timeval start, end, diff; 4088c2ecf20Sopenharmony_ci u64 runtime_us, max_rss; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci pr_debug(" Iteration #%d\n", i+1); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (setup_injection(data, build_id_all) < 0) { 4138c2ecf20Sopenharmony_ci printf(" Build-id injection setup failed\n"); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci gettimeofday(&start, NULL); 4188c2ecf20Sopenharmony_ci if (inject_build_id(data, &max_rss) < 0) { 4198c2ecf20Sopenharmony_ci printf(" Build-id injection failed\n"); 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci gettimeofday(&end, NULL); 4248c2ecf20Sopenharmony_ci timersub(&end, &start, &diff); 4258c2ecf20Sopenharmony_ci runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; 4268c2ecf20Sopenharmony_ci update_stats(&time_stats, runtime_us); 4278c2ecf20Sopenharmony_ci update_stats(&mem_stats, max_rss); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci pthread_join(data->th, NULL); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci time_average = avg_stats(&time_stats) / USEC_PER_MSEC; 4338c2ecf20Sopenharmony_ci time_stddev = stddev_stats(&time_stats) / USEC_PER_MSEC; 4348c2ecf20Sopenharmony_ci printf(" Average build-id%s injection took: %.3f msec (+- %.3f msec)\n", 4358c2ecf20Sopenharmony_ci build_id_all ? "-all" : "", time_average, time_stddev); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* each iteration, it processes MMAP2 + BUILD_ID + nr_samples * SAMPLE */ 4388c2ecf20Sopenharmony_ci time_average = avg_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 4398c2ecf20Sopenharmony_ci time_stddev = stddev_stats(&time_stats) / (nr_mmaps * (nr_samples + 2)); 4408c2ecf20Sopenharmony_ci printf(" Average time per event: %.3f usec (+- %.3f usec)\n", 4418c2ecf20Sopenharmony_ci time_average, time_stddev); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci mem_average = avg_stats(&mem_stats); 4448c2ecf20Sopenharmony_ci mem_stddev = stddev_stats(&mem_stats); 4458c2ecf20Sopenharmony_ci printf(" Average memory usage: %.0f KB (+- %.0f KB)\n", 4468c2ecf20Sopenharmony_ci mem_average, mem_stddev); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int do_inject_loops(struct bench_data *data) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci srand(time(NULL)); 4538c2ecf20Sopenharmony_ci symbol__init(NULL); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci bench_sample_type = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP; 4568c2ecf20Sopenharmony_ci bench_sample_type |= PERF_SAMPLE_TID | PERF_SAMPLE_TIME; 4578c2ecf20Sopenharmony_ci bench_id_hdr_size = 32; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci collect_dso(); 4608c2ecf20Sopenharmony_ci if (nr_dsos == 0) { 4618c2ecf20Sopenharmony_ci printf(" Cannot collect DSOs for injection\n"); 4628c2ecf20Sopenharmony_ci return -1; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci do_inject_loop(data, false); 4668c2ecf20Sopenharmony_ci do_inject_loop(data, true); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci release_dso(); 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ciint bench_inject_build_id(int argc, const char **argv) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct bench_data data; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, options, bench_usage, 0); 4778c2ecf20Sopenharmony_ci if (argc) { 4788c2ecf20Sopenharmony_ci usage_with_options(bench_usage, options); 4798c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return do_inject_loops(&data); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 485