blob: 6d4bbde066fd105d7ce78af44b73d13e26788e3c [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;
30 const char *input_name;
31 struct perf_data_file output;
32 u64 bytes_written;
33 struct list_head samples;
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +030034 struct itrace_synth_opts itrace_synth_opts;
Andrew Vagin26a031e2012-08-07 16:56:04 +040035};
36
37struct event_entry {
38 struct list_head node;
39 u32 tid;
40 union perf_event event[0];
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -030041};
Tom Zanussi454c4072010-05-01 01:41:20 -050042
Adrian Huntercd17a9b2015-04-21 12:21:54 +030043static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
Tom Zanussi454c4072010-05-01 01:41:20 -050044{
Jiri Olsa34069122013-10-29 19:04:57 +010045 ssize_t size;
Tom Zanussi454c4072010-05-01 01:41:20 -050046
Adrian Huntercd17a9b2015-04-21 12:21:54 +030047 size = perf_data_file__write(&inject->output, buf, sz);
Jiri Olsa34069122013-10-29 19:04:57 +010048 if (size < 0)
49 return -errno;
Tom Zanussi454c4072010-05-01 01:41:20 -050050
Jiri Olsa34069122013-10-29 19:04:57 +010051 inject->bytes_written += size;
Tom Zanussi454c4072010-05-01 01:41:20 -050052 return 0;
53}
54
Adrian Huntercd17a9b2015-04-21 12:21:54 +030055static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
56{
57 char buf[4096];
58 ssize_t ssz;
59 int ret;
60
61 while (size > 0) {
62 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
63 if (ssz < 0)
64 return -errno;
65 ret = output_bytes(inject, buf, ssz);
66 if (ret)
67 return ret;
68 size -= ssz;
69 }
70
71 return 0;
72}
73
74static int perf_event__repipe_synth(struct perf_tool *tool,
75 union perf_event *event)
76{
77 struct perf_inject *inject = container_of(tool, struct perf_inject,
78 tool);
79
80 return output_bytes(inject, event, event->header.size);
81}
82
Arnaldo Carvalho de Melod704ebd2015-03-03 12:37:54 -030083static int perf_event__repipe_oe_synth(struct perf_tool *tool,
84 union perf_event *event,
85 struct ordered_events *oe __maybe_unused)
86{
87 return perf_event__repipe_synth(tool, event);
88}
89
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020090static int perf_event__repipe_op2_synth(struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020091 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030092 struct perf_session *session
93 __maybe_unused)
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020094{
Adrian Hunter63c2c9f2013-07-04 16:20:20 +030095 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020096}
97
Adrian Hunter47c3d102013-07-04 16:20:21 +030098static int perf_event__repipe_attr(struct perf_tool *tool,
99 union perf_event *event,
100 struct perf_evlist **pevlist)
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -0200101{
Adrian Hunter89c97d92013-10-22 10:34:09 +0300102 struct perf_inject *inject = container_of(tool, struct perf_inject,
103 tool);
Stephane Eranian1a1ed1b2012-05-15 13:28:11 +0200104 int ret;
Adrian Hunter47c3d102013-07-04 16:20:21 +0300105
106 ret = perf_event__process_attr(tool, event, pevlist);
Stephane Eranian1a1ed1b2012-05-15 13:28:11 +0200107 if (ret)
108 return ret;
109
Jiri Olsaa261e4a2014-06-05 18:51:44 +0200110 if (!inject->output.is_pipe)
Adrian Hunter89c97d92013-10-22 10:34:09 +0300111 return 0;
112
Adrian Hunter47c3d102013-07-04 16:20:21 +0300113 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -0200114}
115
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300116static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
117 union perf_event *event,
118 struct perf_session *session
119 __maybe_unused)
120{
121 struct perf_inject *inject = container_of(tool, struct perf_inject,
122 tool);
123 int ret;
124
Adrian Hunter99fa2982015-04-30 17:37:25 +0300125 if (!inject->output.is_pipe) {
126 off_t offset;
127
128 offset = lseek(inject->output.fd, 0, SEEK_CUR);
129 if (offset == -1)
130 return -errno;
131 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
132 event, offset);
133 if (ret < 0)
134 return ret;
135 }
136
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300137 if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
138 ret = output_bytes(inject, event, event->header.size);
139 if (ret < 0)
140 return ret;
141 ret = copy_bytes(inject, perf_data_file__fd(session->file),
142 event->auxtrace.size);
143 } else {
144 ret = output_bytes(inject, event,
145 event->header.size + event->auxtrace.size);
146 }
147 if (ret < 0)
148 return ret;
149
150 return event->auxtrace.size;
151}
152
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200153static int perf_event__repipe(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200154 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300155 struct perf_sample *sample __maybe_unused,
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300156 struct machine *machine __maybe_unused)
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -0200157{
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300158 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -0200159}
160
Andrew Vagin26a031e2012-08-07 16:56:04 +0400161typedef int (*inject_handler)(struct perf_tool *tool,
162 union perf_event *event,
163 struct perf_sample *sample,
164 struct perf_evsel *evsel,
165 struct machine *machine);
166
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200167static int perf_event__repipe_sample(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200168 union perf_event *event,
Andrew Vagin26a031e2012-08-07 16:56:04 +0400169 struct perf_sample *sample,
170 struct perf_evsel *evsel,
171 struct machine *machine)
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300172{
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300173 if (evsel->handler) {
174 inject_handler f = evsel->handler;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400175 return f(tool, event, sample, evsel, machine);
176 }
177
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400178 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
179
Adrian Hunter63c2c9f2013-07-04 16:20:20 +0300180 return perf_event__repipe_synth(tool, event);
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300181}
182
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200183static int perf_event__repipe_mmap(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200184 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200185 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200186 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500187{
188 int err;
189
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200190 err = perf_event__process_mmap(tool, event, sample, machine);
191 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500192
193 return err;
194}
195
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200196static int perf_event__repipe_mmap2(struct perf_tool *tool,
197 union perf_event *event,
198 struct perf_sample *sample,
199 struct machine *machine)
200{
201 int err;
202
203 err = perf_event__process_mmap2(tool, event, sample, machine);
204 perf_event__repipe(tool, event, sample, machine);
205
206 return err;
207}
208
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300209static int perf_event__repipe_fork(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200210 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200211 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200212 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500213{
214 int err;
215
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300216 err = perf_event__process_fork(tool, event, sample, machine);
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200217 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500218
219 return err;
220}
221
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300222static int perf_event__repipe_comm(struct perf_tool *tool,
223 union perf_event *event,
224 struct perf_sample *sample,
225 struct machine *machine)
226{
227 int err;
228
229 err = perf_event__process_comm(tool, event, sample, machine);
230 perf_event__repipe(tool, event, sample, machine);
231
232 return err;
233}
234
235static int perf_event__repipe_exit(struct perf_tool *tool,
236 union perf_event *event,
237 struct perf_sample *sample,
238 struct machine *machine)
239{
240 int err;
241
242 err = perf_event__process_exit(tool, event, sample, machine);
243 perf_event__repipe(tool, event, sample, machine);
244
245 return err;
246}
247
Adrian Hunter47c3d102013-07-04 16:20:21 +0300248static int perf_event__repipe_tracing_data(struct perf_tool *tool,
249 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200250 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -0500251{
252 int err;
253
Adrian Hunter47c3d102013-07-04 16:20:21 +0300254 perf_event__repipe_synth(tool, event);
255 err = perf_event__process_tracing_data(tool, event, session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500256
257 return err;
258}
259
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300260static int perf_event__repipe_id_index(struct perf_tool *tool,
261 union perf_event *event,
262 struct perf_session *session)
263{
264 int err;
265
266 perf_event__repipe_synth(tool, event);
267 err = perf_event__process_id_index(tool, event, session);
268
269 return err;
270}
271
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300272static int dso__read_build_id(struct dso *dso)
Tom Zanussi454c4072010-05-01 01:41:20 -0500273{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300274 if (dso->has_build_id)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300275 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500276
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300277 if (filename__read_build_id(dso->long_name, dso->build_id,
278 sizeof(dso->build_id)) > 0) {
279 dso->has_build_id = true;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300280 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500281 }
282
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300283 return -1;
284}
Tom Zanussi454c4072010-05-01 01:41:20 -0500285
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300286static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200287 struct machine *machine)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300288{
289 u16 misc = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300290 int err;
Tom Zanussi454c4072010-05-01 01:41:20 -0500291
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300292 if (dso__read_build_id(dso) < 0) {
293 pr_debug("no build_id found for %s\n", dso->long_name);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300294 return -1;
295 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500296
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300297 if (dso->kernel)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300298 misc = PERF_RECORD_MISC_KERNEL;
299
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300300 err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200301 machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300302 if (err) {
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300303 pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
Tom Zanussi454c4072010-05-01 01:41:20 -0500304 return -1;
305 }
306
307 return 0;
308}
309
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200310static int perf_event__inject_buildid(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200311 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200312 struct perf_sample *sample,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300313 struct perf_evsel *evsel __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200314 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500315{
316 struct addr_location al;
317 struct thread *thread;
318 u8 cpumode;
Tom Zanussi454c4072010-05-01 01:41:20 -0500319
320 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
321
Namhyung Kim13ce34d2014-05-12 09:56:42 +0900322 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
Tom Zanussi454c4072010-05-01 01:41:20 -0500323 if (thread == NULL) {
324 pr_err("problem processing %d event, skipping it.\n",
325 event->header.type);
Tom Zanussi454c4072010-05-01 01:41:20 -0500326 goto repipe;
327 }
328
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -0300329 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
Tom Zanussi454c4072010-05-01 01:41:20 -0500330
331 if (al.map != NULL) {
332 if (!al.map->dso->hit) {
333 al.map->dso->hit = 1;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300334 if (map__load(al.map, NULL) >= 0) {
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200335 dso__inject_build_id(al.map->dso, tool, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300336 /*
337 * If this fails, too bad, let the other side
338 * account this as unresolved.
339 */
Namhyung Kim393be2e2012-08-06 13:41:21 +0900340 } else {
Ingo Molnar89fe8082013-09-30 12:07:11 +0200341#ifdef HAVE_LIBELF_SUPPORT
Tom Zanussi454c4072010-05-01 01:41:20 -0500342 pr_warning("no symbols found in %s, maybe "
343 "install a debug package?\n",
344 al.map->dso->long_name);
Namhyung Kim393be2e2012-08-06 13:41:21 +0900345#endif
346 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500347 }
348 }
349
350repipe:
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200351 perf_event__repipe(tool, event, sample, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300352 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500353}
354
Andrew Vagin26a031e2012-08-07 16:56:04 +0400355static int perf_inject__sched_process_exit(struct perf_tool *tool,
356 union perf_event *event __maybe_unused,
357 struct perf_sample *sample,
358 struct perf_evsel *evsel __maybe_unused,
359 struct machine *machine __maybe_unused)
360{
361 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
362 struct event_entry *ent;
363
364 list_for_each_entry(ent, &inject->samples, node) {
365 if (sample->tid == ent->tid) {
366 list_del_init(&ent->node);
367 free(ent);
368 break;
369 }
370 }
371
372 return 0;
373}
374
375static int perf_inject__sched_switch(struct perf_tool *tool,
376 union perf_event *event,
377 struct perf_sample *sample,
378 struct perf_evsel *evsel,
379 struct machine *machine)
380{
381 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
382 struct event_entry *ent;
383
384 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
385
386 ent = malloc(event->header.size + sizeof(struct event_entry));
387 if (ent == NULL) {
388 color_fprintf(stderr, PERF_COLOR_RED,
389 "Not enough memory to process sched switch event!");
390 return -1;
391 }
392
393 ent->tid = sample->tid;
394 memcpy(&ent->event, event, event->header.size);
395 list_add(&ent->node, &inject->samples);
396 return 0;
397}
398
399static int perf_inject__sched_stat(struct perf_tool *tool,
400 union perf_event *event __maybe_unused,
401 struct perf_sample *sample,
402 struct perf_evsel *evsel,
403 struct machine *machine)
404{
405 struct event_entry *ent;
406 union perf_event *event_sw;
407 struct perf_sample sample_sw;
408 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
409 u32 pid = perf_evsel__intval(evsel, sample, "pid");
410
411 list_for_each_entry(ent, &inject->samples, node) {
412 if (pid == ent->tid)
413 goto found;
414 }
415
416 return 0;
417found:
418 event_sw = &ent->event[0];
419 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
420
421 sample_sw.period = sample->period;
422 sample_sw.time = sample->time;
423 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
Adrian Hunterd03f2172013-08-27 11:23:11 +0300424 evsel->attr.read_format, &sample_sw,
425 false);
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400426 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
Andrew Vagin26a031e2012-08-07 16:56:04 +0400427 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
428}
429
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300430static void sig_handler(int sig __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500431{
432 session_done = 1;
433}
434
Andrew Vagin26a031e2012-08-07 16:56:04 +0400435static int perf_evsel__check_stype(struct perf_evsel *evsel,
436 u64 sample_type, const char *sample_msg)
437{
438 struct perf_event_attr *attr = &evsel->attr;
439 const char *name = perf_evsel__name(evsel);
440
441 if (!(attr->sample_type & sample_type)) {
442 pr_err("Samples for %s event do not have %s attribute set.",
443 name, sample_msg);
444 return -EINVAL;
445 }
446
447 return 0;
448}
449
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300450static int __cmd_inject(struct perf_inject *inject)
Tom Zanussi454c4072010-05-01 01:41:20 -0500451{
Tom Zanussi454c4072010-05-01 01:41:20 -0500452 int ret = -EINVAL;
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900453 struct perf_session *session = inject->session;
Jiri Olsa34069122013-10-29 19:04:57 +0100454 struct perf_data_file *file_out = &inject->output;
Namhyung Kim42aa2762015-01-29 17:06:48 +0900455 int fd = perf_data_file__fd(file_out);
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300456 u64 output_data_offset;
Tom Zanussi454c4072010-05-01 01:41:20 -0500457
458 signal(SIGINT, sig_handler);
459
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300460 if (inject->build_ids || inject->sched_stat ||
461 inject->itrace_synth_opts.set) {
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300462 inject->tool.mmap = perf_event__repipe_mmap;
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200463 inject->tool.mmap2 = perf_event__repipe_mmap2;
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300464 inject->tool.fork = perf_event__repipe_fork;
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300465 inject->tool.tracing_data = perf_event__repipe_tracing_data;
Tom Zanussi454c4072010-05-01 01:41:20 -0500466 }
467
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300468 output_data_offset = session->header.data_offset;
469
Andrew Vagin54a3cf52012-08-07 16:56:05 +0400470 if (inject->build_ids) {
471 inject->tool.sample = perf_event__inject_buildid;
472 } else if (inject->sched_stat) {
Andrew Vagin26a031e2012-08-07 16:56:04 +0400473 struct perf_evsel *evsel;
474
Arnaldo Carvalho de Melo0050f7a2014-01-10 10:37:27 -0300475 evlist__for_each(session->evlist, evsel) {
Andrew Vagin26a031e2012-08-07 16:56:04 +0400476 const char *name = perf_evsel__name(evsel);
477
478 if (!strcmp(name, "sched:sched_switch")) {
479 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
480 return -EINVAL;
481
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300482 evsel->handler = perf_inject__sched_switch;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400483 } else if (!strcmp(name, "sched:sched_process_exit"))
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300484 evsel->handler = perf_inject__sched_process_exit;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400485 else if (!strncmp(name, "sched:sched_stat_", 17))
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -0300486 evsel->handler = perf_inject__sched_stat;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400487 }
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300488 } else if (inject->itrace_synth_opts.set) {
489 session->itrace_synth_opts = &inject->itrace_synth_opts;
490 inject->itrace_synth_opts.inject = true;
491 inject->tool.comm = perf_event__repipe_comm;
492 inject->tool.exit = perf_event__repipe_exit;
493 inject->tool.id_index = perf_event__repipe_id_index;
494 inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
495 inject->tool.auxtrace = perf_event__process_auxtrace;
496 inject->tool.ordered_events = true;
497 inject->tool.ordering_requires_timestamps = true;
498 /* Allow space in the header for new attributes */
499 output_data_offset = 4096;
Andrew Vagin26a031e2012-08-07 16:56:04 +0400500 }
501
Adrian Hunter99fa2982015-04-30 17:37:25 +0300502 if (!inject->itrace_synth_opts.set)
503 auxtrace_index__free(&session->auxtrace_index);
504
Jiri Olsa34069122013-10-29 19:04:57 +0100505 if (!file_out->is_pipe)
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300506 lseek(fd, output_data_offset, SEEK_SET);
Andrew Vagine558a5b2012-08-07 16:56:02 +0400507
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -0300508 ret = perf_session__process_events(session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500509
Jiri Olsa34069122013-10-29 19:04:57 +0100510 if (!file_out->is_pipe) {
Adrian Huntere38b43c2014-07-14 13:02:34 +0300511 if (inject->build_ids)
512 perf_header__set_feat(&session->header,
513 HEADER_BUILD_ID);
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300514 /*
515 * The AUX areas have been removed and replaced with
516 * synthesized hardware events, so clear the feature flag.
517 */
518 if (inject->itrace_synth_opts.set)
519 perf_header__clear_feat(&session->header,
520 HEADER_AUXTRACE);
521 session->header.data_offset = output_data_offset;
Andrew Vagine558a5b2012-08-07 16:56:02 +0400522 session->header.data_size = inject->bytes_written;
Namhyung Kim42aa2762015-01-29 17:06:48 +0900523 perf_session__write_header(session, session->evlist, fd, true);
Andrew Vagine558a5b2012-08-07 16:56:02 +0400524 }
525
Tom Zanussi454c4072010-05-01 01:41:20 -0500526 return ret;
527}
528
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300529int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500530{
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300531 struct perf_inject inject = {
532 .tool = {
533 .sample = perf_event__repipe_sample,
534 .mmap = perf_event__repipe,
Stephane Eranian5c5e8542013-08-21 12:10:25 +0200535 .mmap2 = perf_event__repipe,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300536 .comm = perf_event__repipe,
537 .fork = perf_event__repipe,
538 .exit = perf_event__repipe,
539 .lost = perf_event__repipe,
540 .read = perf_event__repipe_sample,
541 .throttle = perf_event__repipe,
542 .unthrottle = perf_event__repipe,
543 .attr = perf_event__repipe_attr,
Adrian Hunter47c3d102013-07-04 16:20:21 +0300544 .tracing_data = perf_event__repipe_op2_synth,
Adrian Huntercd17a9b2015-04-21 12:21:54 +0300545 .auxtrace_info = perf_event__repipe_op2_synth,
546 .auxtrace = perf_event__repipe_auxtrace,
547 .auxtrace_error = perf_event__repipe_op2_synth,
Arnaldo Carvalho de Melod704ebd2015-03-03 12:37:54 -0300548 .finished_round = perf_event__repipe_oe_synth,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300549 .build_id = perf_event__repipe_op2_synth,
Adrian Hunter3c659ee2014-10-27 15:49:22 +0200550 .id_index = perf_event__repipe_op2_synth,
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300551 },
Andrew Vagine558a5b2012-08-07 16:56:02 +0400552 .input_name = "-",
Andrew Vagin26a031e2012-08-07 16:56:04 +0400553 .samples = LIST_HEAD_INIT(inject.samples),
Jiri Olsa34069122013-10-29 19:04:57 +0100554 .output = {
555 .path = "-",
556 .mode = PERF_DATA_MODE_WRITE,
557 },
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300558 };
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900559 struct perf_data_file file = {
560 .mode = PERF_DATA_MODE_READ,
561 };
562 int ret;
563
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300564 const struct option options[] = {
565 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
566 "Inject build-ids into the output stream"),
Andrew Vagine558a5b2012-08-07 16:56:02 +0400567 OPT_STRING('i', "input", &inject.input_name, "file",
568 "input file name"),
Jiri Olsa34069122013-10-29 19:04:57 +0100569 OPT_STRING('o', "output", &inject.output.path, "file",
Andrew Vagine558a5b2012-08-07 16:56:02 +0400570 "output file name"),
Andrew Vagin26a031e2012-08-07 16:56:04 +0400571 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
572 "Merge sched-stat and sched-switch for getting events "
573 "where and how long tasks slept"),
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300574 OPT_INCR('v', "verbose", &verbose,
575 "be more verbose (show build ids, etc)"),
Adrian Huntera7a2b8b2014-07-22 16:17:38 +0300576 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
577 "kallsyms pathname"),
Yunlong Songccaa4742015-04-02 21:47:11 +0800578 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
Adrian Hunter0f0aa5e2015-04-09 18:54:00 +0300579 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
580 NULL, "opts", "Instruction Tracing options",
581 itrace_parse_synth_opts),
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300582 OPT_END()
583 };
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300584 const char * const inject_usage[] = {
585 "perf inject [<options>]",
586 NULL
587 };
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300588
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300589 argc = parse_options(argc, argv, options, inject_usage, 0);
Tom Zanussi454c4072010-05-01 01:41:20 -0500590
591 /*
592 * Any (unrecognized) arguments left?
593 */
594 if (argc)
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300595 usage_with_options(inject_usage, options);
Tom Zanussi454c4072010-05-01 01:41:20 -0500596
Jiri Olsa34069122013-10-29 19:04:57 +0100597 if (perf_data_file__open(&inject.output)) {
598 perror("failed to create output file");
599 return -1;
Andrew Vagine558a5b2012-08-07 16:56:02 +0400600 }
601
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -0300602 inject.tool.ordered_events = inject.sched_stat;
603
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900604 file.path = inject.input_name;
605 inject.session = perf_session__new(&file, true, &inject.tool);
606 if (inject.session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +0900607 return -1;
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900608
Namhyung Kim0a7e6d12014-08-12 15:40:45 +0900609 if (symbol__init(&inject.session->header.env) < 0)
Tom Zanussi454c4072010-05-01 01:41:20 -0500610 return -1;
611
Namhyung Kim1cb8bdc2014-08-12 15:40:37 +0900612 ret = __cmd_inject(&inject);
613
614 perf_session__delete(inject.session);
615
616 return ret;
Tom Zanussi454c4072010-05-01 01:41:20 -0500617}