xref: /openbmc/linux/tools/perf/bench/inject-buildid.c (revision 0bf02a0d80427f263195c1e5a4c8ada14bd5d261)
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