blob: cc905f1d31244b4dfa0245d29d4e132a1a6cc5f2 [file] [log] [blame]
Tom Zanussi454c4072010-05-01 01:41:20 -05001/*
2 * builtin-inject.c
3 *
4 * Builtin inject command: Examine the live mode (stdin) event stream
5 * and repipe it to stdout while optionally injecting additional
6 * events into it.
7 */
8#include "builtin.h"
9
10#include "perf.h"
Andrew Vagin26a031e2012-08-07 16:56:04 +040011#include "util/color.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
Tom Zanussi454c4072010-05-01 01:41:20 -050014#include "util/session.h"
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020015#include "util/tool.h"
Tom Zanussi454c4072010-05-01 01:41:20 -050016#include "util/debug.h"
Andrew Vagin54a3cf52012-08-07 16:56:05 +040017#include "util/build-id.h"
Jiri Olsaf5fc14122013-10-15 16:27:32 +020018#include "util/data.h"
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +030019#include "util/auxtrace.h"
Tom Zanussi454c4072010-05-01 01:41:20 -050020
21#include "util/parse-options.h"
22
Andrew Vagin26a031e2012-08-07 16:56:04 +040023#include <linux/list.h>
24
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -030025struct perf_inject {
Jiri Olsa34069122013-10-29 19:04:57 +010026 struct perf_tool tool;
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +090027 struct perf_session *session;
Jiri Olsa34069122013-10-29 19:04:57 +010028 bool build_ids;
29 bool sched_stat;
Adrian Huntercd10b282015-04-30 17:37:26 +030030 bool have_auxtrace;
Jiri Olsa34069122013-10-29 19:04:57 +010031 const char *input_name;
32 struct perf_data_file output;
33 u64 bytes_written;
34 struct list_head samples;
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +030035 struct itrace_synth_opts itrace_synth_opts;
Andrew Vagin26a031e2012-08-07 16:56:04 +040036};
37
38struct event_entry {
39 struct list_head node;
40 u32 tid;
41 union perf_event event[0];
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -030042};
Tom Zanussi454c4072010-05-01 01:41:20 -050043
Adrian Huntercd17a9b2015-04-21 12:21:54 +030044static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
Tom Zanussi454c4072010-05-01 01:41:20 -050045{
Jiri Olsa34069122013-10-29 19:04:57 +010046 ssize_t size;
Tom Zanussi454c4072010-05-01 01:41:20 -050047
Adrian Huntercd17a9b2015-04-21 12:21:54 +030048 size = perf_data_file__write(&inject->output, buf, sz);
Jiri Olsa34069122013-10-29 19:04:57 +010049 if (size < 0)
50 return -errno;
Tom Zanussi454c4072010-05-01 01:41:20 -050051
Jiri Olsa34069122013-10-29 19:04:57 +010052 inject->bytes_written += size;
Tom Zanussi454c4072010-05-01 01:41:20 -050053 return 0;
54}
55
Adrian Huntercd17a9b2015-04-21 12:21:54 +030056static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
57{
58 char buf[4096];
59 ssize_t ssz;
60 int ret;
61
62 while (size > 0) {
63 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
64 if (ssz < 0)
65 return -errno;
66 ret = output_bytes(inject, buf, ssz);
67 if (ret)
68 return ret;
69 size -= ssz;
70 }
71
72 return 0;
73}
74
75static int perf_event__repipe_synth(struct perf_tool *tool,
76 union perf_event *event)
77{
78 struct perf_inject *inject = container_of(tool, struct perf_inject,
79 tool);
80
81 return output_bytes(inject, event, event->header.size);
82}
83
Arnaldo Carvalho de Melod704ebd2015-03-03 12:37:54 -030084static int perf_event__repipe_oe_synth(struct perf_tool *tool,
85 union perf_event *event,
86 struct ordered_events *oe __maybe_unused)
87{
88 return perf_event__repipe_synth(tool, event);
89}
90
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020091static int perf_event__repipe_op2_synth(struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020092 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030093 struct perf_session *session
94 __maybe_unused)
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020095{
Adrian Hunter63c2c9f2013-07-04 16:20:20 +030096 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020097}
98
Adrian Hunter47c3d102013-07-04 16:20:21 +030099static int perf_event__repipe_attr(struct perf_tool *tool,
100 union perf_event *event,
101 struct perf_evlist **pevlist)
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -0200102{
Adrian Hunter89c97d92013-10-22 10:34:09 +0300103 struct perf_inject *inject = container_of(tool, struct perf_inject,
104 tool);
Stephane Eranian1a1ed1b2012-05-15 13:28:11 +0200105 int ret;
Adrian Hunter47c3d102013-07-04 16:20:21 +0300106
107 ret = perf_event__process_attr(tool, event, pevlist);
Stephane Eranian1a1ed1b2012-05-15 13:28:11 +0200108 if (ret)
109 return ret;
110
Jiri Olsaa261e4a2014-06-05 18:51:44 +0200111 if (!inject->output.is_pipe)
Adrian Hunter89c97d92013-10-22 10:34:09 +0300112 return 0;
113
Adrian Hunter47c3d102013-07-04 16:20:21 +0300114 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -0200115}
116
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300117static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
118 union perf_event *event,
119 struct perf_session *session
120 __maybe_unused)
121{
122 struct perf_inject *inject = container_of(tool, struct perf_inject,
123 tool);
124 int ret;
125
Adrian Huntercd10b282015-04-30 17:37:26 +0300126 inject->have_auxtrace = true;
127
Adrian Hunter99fa2982015-04-30 17:37:25 +0300128 if (!inject->output.is_pipe) {
129 off_t offset;
130
131 offset = lseek(inject->output.fd, 0, SEEK_CUR);
132 if (offset == -1)
133 return -errno;
134 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
135 event, offset);
136 if (ret < 0)
137 return ret;
138 }
139
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300140 if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
141 ret = output_bytes(inject, event, event->header.size);
142 if (ret < 0)
143 return ret;
144 ret = copy_bytes(inject, perf_data_file__fd(session->file),
145 event->auxtrace.size);
146 } else {
147 ret = output_bytes(inject, event,
148 event->header.size + event->auxtrace.size);
149 }
150 if (ret < 0)
151 return ret;
152
153 return event->auxtrace.size;
154}
155
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200156static int perf_event__repipe(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200157 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300158 struct perf_sample *sample __maybe_unused,
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300159 struct machine *machine __maybe_unused)
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -0200160{
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300161 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -0200162}
163
Andrew Vagin26a031e2012-08-07 16:56:04 +0400164typedef int (*inject_handler)(struct perf_tool *tool,
165 union perf_event *event,
166 struct perf_sample *sample,
167 struct perf_evsel *evsel,
168 struct machine *machine);
169
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200170static int perf_event__repipe_sample(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200171 union perf_event *event,
Andrew Vagin26a031e2012-08-07 16:56:04 +0400172 struct perf_sample *sample,
173 struct perf_evsel *evsel,
174 struct machine *machine)
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300175{
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300176 if (evsel->handler) {
177 inject_handler f = evsel->handler;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400178 return f(tool, event, sample, evsel, machine);
179 }
180
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400181 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
182
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300183 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300184}
185
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200186static int perf_event__repipe_mmap(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200187 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200188 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200189 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500190{
191 int err;
192
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200193 err = perf_event__process_mmap(tool, event, sample, machine);
194 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500195
196 return err;
197}
198
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200199static int perf_event__repipe_mmap2(struct perf_tool *tool,
200 union perf_event *event,
201 struct perf_sample *sample,
202 struct machine *machine)
203{
204 int err;
205
206 err = perf_event__process_mmap2(tool, event, sample, machine);
207 perf_event__repipe(tool, event, sample, machine);
208
209 return err;
210}
211
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300212static int perf_event__repipe_fork(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200213 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200214 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200215 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500216{
217 int err;
218
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300219 err = perf_event__process_fork(tool, event, sample, machine);
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200220 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500221
222 return err;
223}
224
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300225static int perf_event__repipe_comm(struct perf_tool *tool,
226 union perf_event *event,
227 struct perf_sample *sample,
228 struct machine *machine)
229{
230 int err;
231
232 err = perf_event__process_comm(tool, event, sample, machine);
233 perf_event__repipe(tool, event, sample, machine);
234
235 return err;
236}
237
238static int perf_event__repipe_exit(struct perf_tool *tool,
239 union perf_event *event,
240 struct perf_sample *sample,
241 struct machine *machine)
242{
243 int err;
244
245 err = perf_event__process_exit(tool, event, sample, machine);
246 perf_event__repipe(tool, event, sample, machine);
247
248 return err;
249}
250
Adrian Hunter47c3d102013-07-04 16:20:21 +0300251static int perf_event__repipe_tracing_data(struct perf_tool *tool,
252 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200253 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -0500254{
255 int err;
256
Adrian Hunter47c3d102013-07-04 16:20:21 +0300257 perf_event__repipe_synth(tool, event);
258 err = perf_event__process_tracing_data(tool, event, session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500259
260 return err;
261}
262
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300263static int perf_event__repipe_id_index(struct perf_tool *tool,
264 union perf_event *event,
265 struct perf_session *session)
266{
267 int err;
268
269 perf_event__repipe_synth(tool, event);
270 err = perf_event__process_id_index(tool, event, session);
271
272 return err;
273}
274
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300275static int dso__read_build_id(struct dso *dso)
Tom Zanussi454c4072010-05-01 01:41:20 -0500276{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300277 if (dso->has_build_id)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300278 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500279
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300280 if (filename__read_build_id(dso->long_name, dso->build_id,
281 sizeof(dso->build_id)) > 0) {
282 dso->has_build_id = true;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300283 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500284 }
285
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300286 return -1;
287}
Tom Zanussi454c4072010-05-01 01:41:20 -0500288
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300289static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200290 struct machine *machine)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300291{
292 u16 misc = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300293 int err;
Tom Zanussi454c4072010-05-01 01:41:20 -0500294
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300295 if (dso__read_build_id(dso) < 0) {
296 pr_debug("no build_id found for %s\n", dso->long_name);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300297 return -1;
298 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500299
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300300 if (dso->kernel)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300301 misc = PERF_RECORD_MISC_KERNEL;
302
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300303 err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200304 machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300305 if (err) {
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300306 pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
Tom Zanussi454c4072010-05-01 01:41:20 -0500307 return -1;
308 }
309
310 return 0;
311}
312
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200313static int perf_event__inject_buildid(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200314 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200315 struct perf_sample *sample,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300316 struct perf_evsel *evsel __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200317 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500318{
319 struct addr_location al;
320 struct thread *thread;
321 u8 cpumode;
Tom Zanussi454c4072010-05-01 01:41:20 -0500322
323 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
324
Namhyung Kim13ce34d2014-05-12 09:56:42 +0900325 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
Tom Zanussi454c4072010-05-01 01:41:20 -0500326 if (thread == NULL) {
327 pr_err("problem processing %d event, skipping it.\n",
328 event->header.type);
Tom Zanussi454c4072010-05-01 01:41:20 -0500329 goto repipe;
330 }
331
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -0300332 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
Tom Zanussi454c4072010-05-01 01:41:20 -0500333
334 if (al.map != NULL) {
335 if (!al.map->dso->hit) {
336 al.map->dso->hit = 1;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300337 if (map__load(al.map, NULL) >= 0) {
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200338 dso__inject_build_id(al.map->dso, tool, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300339 /*
340 * If this fails, too bad, let the other side
341 * account this as unresolved.
342 */
Namhyung Kim393be2e2012-08-06 13:41:21 +0900343 } else {
Ingo Molnar89fe8082013-09-30 12:07:11 +0200344#ifdef HAVE_LIBELF_SUPPORT
Tom Zanussi454c4072010-05-01 01:41:20 -0500345 pr_warning("no symbols found in %s, maybe "
346 "install a debug package?\n",
347 al.map->dso->long_name);
Namhyung Kim393be2e2012-08-06 13:41:21 +0900348#endif
349 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500350 }
351 }
352
353repipe:
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200354 perf_event__repipe(tool, event, sample, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300355 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500356}
357
Andrew Vagin26a031e2012-08-07 16:56:04 +0400358static int perf_inject__sched_process_exit(struct perf_tool *tool,
359 union perf_event *event __maybe_unused,
360 struct perf_sample *sample,
361 struct perf_evsel *evsel __maybe_unused,
362 struct machine *machine __maybe_unused)
363{
364 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
365 struct event_entry *ent;
366
367 list_for_each_entry(ent, &inject->samples, node) {
368 if (sample->tid == ent->tid) {
369 list_del_init(&ent->node);
370 free(ent);
371 break;
372 }
373 }
374
375 return 0;
376}
377
378static int perf_inject__sched_switch(struct perf_tool *tool,
379 union perf_event *event,
380 struct perf_sample *sample,
381 struct perf_evsel *evsel,
382 struct machine *machine)
383{
384 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
385 struct event_entry *ent;
386
387 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
388
389 ent = malloc(event->header.size + sizeof(struct event_entry));
390 if (ent == NULL) {
391 color_fprintf(stderr, PERF_COLOR_RED,
392 "Not enough memory to process sched switch event!");
393 return -1;
394 }
395
396 ent->tid = sample->tid;
397 memcpy(&ent->event, event, event->header.size);
398 list_add(&ent->node, &inject->samples);
399 return 0;
400}
401
402static int perf_inject__sched_stat(struct perf_tool *tool,
403 union perf_event *event __maybe_unused,
404 struct perf_sample *sample,
405 struct perf_evsel *evsel,
406 struct machine *machine)
407{
408 struct event_entry *ent;
409 union perf_event *event_sw;
410 struct perf_sample sample_sw;
411 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
412 u32 pid = perf_evsel__intval(evsel, sample, "pid");
413
414 list_for_each_entry(ent, &inject->samples, node) {
415 if (pid == ent->tid)
416 goto found;
417 }
418
419 return 0;
420found:
421 event_sw = &ent->event[0];
422 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
423
424 sample_sw.period = sample->period;
425 sample_sw.time = sample->time;
426 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
Adrian Hunterd03f2172013-08-27 11:23:11 +0300427 evsel->attr.read_format, &sample_sw,
428 false);
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400429 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
Andrew Vagin26a031e2012-08-07 16:56:04 +0400430 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
431}
432
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300433static void sig_handler(int sig __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500434{
435 session_done = 1;
436}
437
Andrew Vagin26a031e2012-08-07 16:56:04 +0400438static int perf_evsel__check_stype(struct perf_evsel *evsel,
439 u64 sample_type, const char *sample_msg)
440{
441 struct perf_event_attr *attr = &evsel->attr;
442 const char *name = perf_evsel__name(evsel);
443
444 if (!(attr->sample_type & sample_type)) {
445 pr_err("Samples for %s event do not have %s attribute set.",
446 name, sample_msg);
447 return -EINVAL;
448 }
449
450 return 0;
451}
452
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300453static int __cmd_inject(struct perf_inject *inject)
Tom Zanussi454c4072010-05-01 01:41:20 -0500454{
Tom Zanussi454c4072010-05-01 01:41:20 -0500455 int ret = -EINVAL;
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900456 struct perf_session *session = inject->session;
Jiri Olsa34069122013-10-29 19:04:57 +0100457 struct perf_data_file *file_out = &inject->output;
Namhyung Kim42aa2762015-01-29 17:06:48 +0900458 int fd = perf_data_file__fd(file_out);
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300459 u64 output_data_offset;
Tom Zanussi454c4072010-05-01 01:41:20 -0500460
461 signal(SIGINT, sig_handler);
462
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300463 if (inject->build_ids || inject->sched_stat ||
464 inject->itrace_synth_opts.set) {
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300465 inject->tool.mmap = perf_event__repipe_mmap;
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200466 inject->tool.mmap2 = perf_event__repipe_mmap2;
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300467 inject->tool.fork = perf_event__repipe_fork;
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300468 inject->tool.tracing_data = perf_event__repipe_tracing_data;
Tom Zanussi454c4072010-05-01 01:41:20 -0500469 }
470
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300471 output_data_offset = session->header.data_offset;
472
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400473 if (inject->build_ids) {
474 inject->tool.sample = perf_event__inject_buildid;
475 } else if (inject->sched_stat) {
Andrew Vagin26a031e2012-08-07 16:56:04 +0400476 struct perf_evsel *evsel;
477
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -0300478 evlist__for_each(session->evlist, evsel) {
Andrew Vagin26a031e2012-08-07 16:56:04 +0400479 const char *name = perf_evsel__name(evsel);
480
481 if (!strcmp(name, "sched:sched_switch")) {
482 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
483 return -EINVAL;
484
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300485 evsel->handler = perf_inject__sched_switch;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400486 } else if (!strcmp(name, "sched:sched_process_exit"))
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300487 evsel->handler = perf_inject__sched_process_exit;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400488 else if (!strncmp(name, "sched:sched_stat_", 17))
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300489 evsel->handler = perf_inject__sched_stat;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400490 }
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300491 } else if (inject->itrace_synth_opts.set) {
492 session->itrace_synth_opts = &inject->itrace_synth_opts;
493 inject->itrace_synth_opts.inject = true;
494 inject->tool.comm = perf_event__repipe_comm;
495 inject->tool.exit = perf_event__repipe_exit;
496 inject->tool.id_index = perf_event__repipe_id_index;
497 inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
498 inject->tool.auxtrace = perf_event__process_auxtrace;
499 inject->tool.ordered_events = true;
500 inject->tool.ordering_requires_timestamps = true;
501 /* Allow space in the header for new attributes */
502 output_data_offset = 4096;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400503 }
504
Adrian Hunter99fa2982015-04-30 17:37:25 +0300505 if (!inject->itrace_synth_opts.set)
506 auxtrace_index__free(&session->auxtrace_index);
507
Jiri Olsa34069122013-10-29 19:04:57 +0100508 if (!file_out->is_pipe)
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300509 lseek(fd, output_data_offset, SEEK_SET);
Andrew Vagine558a5b2012-08-07 16:56:02 +0400510
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -0300511 ret = perf_session__process_events(session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500512
Jiri Olsa34069122013-10-29 19:04:57 +0100513 if (!file_out->is_pipe) {
Adrian Huntercd10b282015-04-30 17:37:26 +0300514 if (inject->build_ids) {
Adrian Huntere38b43c2014-07-14 13:02:34 +0300515 perf_header__set_feat(&session->header,
516 HEADER_BUILD_ID);
Adrian Huntercd10b282015-04-30 17:37:26 +0300517 if (inject->have_auxtrace)
518 dsos__hit_all(session);
519 }
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300520 /*
521 * The AUX areas have been removed and replaced with
522 * synthesized hardware events, so clear the feature flag.
523 */
524 if (inject->itrace_synth_opts.set)
525 perf_header__clear_feat(&session->header,
526 HEADER_AUXTRACE);
527 session->header.data_offset = output_data_offset;
Andrew Vagine558a5b2012-08-07 16:56:02 +0400528 session->header.data_size = inject->bytes_written;
Namhyung Kim42aa2762015-01-29 17:06:48 +0900529 perf_session__write_header(session, session->evlist, fd, true);
Andrew Vagine558a5b2012-08-07 16:56:02 +0400530 }
531
Tom Zanussi454c4072010-05-01 01:41:20 -0500532 return ret;
533}
534
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300535int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500536{
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300537 struct perf_inject inject = {
538 .tool = {
539 .sample = perf_event__repipe_sample,
540 .mmap = perf_event__repipe,
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200541 .mmap2 = perf_event__repipe,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300542 .comm = perf_event__repipe,
543 .fork = perf_event__repipe,
544 .exit = perf_event__repipe,
545 .lost = perf_event__repipe,
546 .read = perf_event__repipe_sample,
547 .throttle = perf_event__repipe,
548 .unthrottle = perf_event__repipe,
549 .attr = perf_event__repipe_attr,
Adrian Hunter47c3d102013-07-04 16:20:21 +0300550 .tracing_data = perf_event__repipe_op2_synth,
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300551 .auxtrace_info = perf_event__repipe_op2_synth,
552 .auxtrace = perf_event__repipe_auxtrace,
553 .auxtrace_error = perf_event__repipe_op2_synth,
Arnaldo Carvalho de Melod704ebd2015-03-03 12:37:54 -0300554 .finished_round = perf_event__repipe_oe_synth,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300555 .build_id = perf_event__repipe_op2_synth,
Adrian Hunter3c659ee2014-10-27 15:49:22 +0200556 .id_index = perf_event__repipe_op2_synth,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300557 },
Andrew Vagine558a5b2012-08-07 16:56:02 +0400558 .input_name = "-",
Andrew Vagin26a031e2012-08-07 16:56:04 +0400559 .samples = LIST_HEAD_INIT(inject.samples),
Jiri Olsa34069122013-10-29 19:04:57 +0100560 .output = {
561 .path = "-",
562 .mode = PERF_DATA_MODE_WRITE,
563 },
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300564 };
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900565 struct perf_data_file file = {
566 .mode = PERF_DATA_MODE_READ,
567 };
568 int ret;
569
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300570 const struct option options[] = {
571 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
572 "Inject build-ids into the output stream"),
Andrew Vagine558a5b2012-08-07 16:56:02 +0400573 OPT_STRING('i', "input", &inject.input_name, "file",
574 "input file name"),
Jiri Olsa34069122013-10-29 19:04:57 +0100575 OPT_STRING('o', "output", &inject.output.path, "file",
Andrew Vagine558a5b2012-08-07 16:56:02 +0400576 "output file name"),
Andrew Vagin26a031e2012-08-07 16:56:04 +0400577 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
578 "Merge sched-stat and sched-switch for getting events "
579 "where and how long tasks slept"),
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300580 OPT_INCR('v', "verbose", &verbose,
581 "be more verbose (show build ids, etc)"),
Adrian Huntera7a2b8b2014-07-22 16:17:38 +0300582 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
583 "kallsyms pathname"),
Yunlong Songccaa4742015-04-02 21:47:11 +0800584 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300585 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
586 NULL, "opts", "Instruction Tracing options",
587 itrace_parse_synth_opts),
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300588 OPT_END()
589 };
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300590 const char * const inject_usage[] = {
591 "perf inject [<options>]",
592 NULL
593 };
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300594
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300595 argc = parse_options(argc, argv, options, inject_usage, 0);
Tom Zanussi454c4072010-05-01 01:41:20 -0500596
597 /*
598 * Any (unrecognized) arguments left?
599 */
600 if (argc)
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300601 usage_with_options(inject_usage, options);
Tom Zanussi454c4072010-05-01 01:41:20 -0500602
Jiri Olsa34069122013-10-29 19:04:57 +0100603 if (perf_data_file__open(&inject.output)) {
604 perror("failed to create output file");
605 return -1;
Andrew Vagine558a5b2012-08-07 16:56:02 +0400606 }
607
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -0300608 inject.tool.ordered_events = inject.sched_stat;
609
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900610 file.path = inject.input_name;
611 inject.session = perf_session__new(&file, true, &inject.tool);
612 if (inject.session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +0900613 return -1;
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900614
Namhyung Kim0a7e6d12014-08-12 15:40:45 +0900615 if (symbol__init(&inject.session->header.env) < 0)
Tom Zanussi454c4072010-05-01 01:41:20 -0500616 return -1;
617
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900618 ret = __cmd_inject(&inject);
619
620 perf_session__delete(inject.session);
621
622 return ret;
Tom Zanussi454c4072010-05-01 01:41:20 -0500623}