blob: a82ce4303ff529684673a11657ef3c3fe1816173 [file] [log] [blame]
Tom Zanussi16c632d2009-11-25 01:15:48 -06001/*
Ingo Molnar133dc4c2010-11-16 18:45:39 +01002 * trace-event-perl. Feed perf script events to an embedded Perl interpreter.
Tom Zanussi16c632d2009-11-25 01:15:48 -06003 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
Tom Zanussi82d156c2010-01-27 02:27:55 -060028#include "../../perf.h"
29#include "../util.h"
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020030#include "../thread.h"
31#include "../event.h"
Tom Zanussi82d156c2010-01-27 02:27:55 -060032#include "../trace-event.h"
33
34#include <EXTERN.h>
35#include <perl.h>
36
37void boot_Perf__Trace__Context(pTHX_ CV *cv);
38void boot_DynaLoader(pTHX_ CV *cv);
39typedef PerlInterpreter * INTERP;
Tom Zanussi16c632d2009-11-25 01:15:48 -060040
Tom Zanussid1b93772009-11-25 01:15:50 -060041void xs_init(pTHX);
42
Tom Zanussid1b93772009-11-25 01:15:50 -060043void xs_init(pTHX)
44{
45 const char *file = __FILE__;
46 dXSUB_SYS;
47
48 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
49 file);
50 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
51}
52
Tom Zanussi16c632d2009-11-25 01:15:48 -060053INTERP my_perl;
54
55#define FTRACE_MAX_EVENT \
56 ((1 << (sizeof(unsigned short) * 8)) - 1)
57
58struct event *events[FTRACE_MAX_EVENT];
59
Tom Zanussi82d156c2010-01-27 02:27:55 -060060extern struct scripting_context *scripting_context;
Tom Zanussi16c632d2009-11-25 01:15:48 -060061
62static char *cur_field_name;
63static int zero_flag_atom;
64
65static void define_symbolic_value(const char *ev_name,
66 const char *field_name,
67 const char *field_value,
68 const char *field_str)
69{
70 unsigned long long value;
71 dSP;
72
73 value = eval_flag(field_value);
74
75 ENTER;
76 SAVETMPS;
77 PUSHMARK(SP);
78
79 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
80 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
81 XPUSHs(sv_2mortal(newSVuv(value)));
82 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
83
84 PUTBACK;
85 if (get_cv("main::define_symbolic_value", 0))
86 call_pv("main::define_symbolic_value", G_SCALAR);
87 SPAGAIN;
88 PUTBACK;
89 FREETMPS;
90 LEAVE;
91}
92
93static void define_symbolic_values(struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_symbolic_value(ev_name, field_name, field->value, field->str);
98 if (field->next)
99 define_symbolic_values(field->next, ev_name, field_name);
100}
101
102static void define_symbolic_field(const char *ev_name,
103 const char *field_name)
104{
105 dSP;
106
107 ENTER;
108 SAVETMPS;
109 PUSHMARK(SP);
110
111 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
112 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
113
114 PUTBACK;
115 if (get_cv("main::define_symbolic_field", 0))
116 call_pv("main::define_symbolic_field", G_SCALAR);
117 SPAGAIN;
118 PUTBACK;
119 FREETMPS;
120 LEAVE;
121}
122
123static void define_flag_value(const char *ev_name,
124 const char *field_name,
125 const char *field_value,
126 const char *field_str)
127{
128 unsigned long long value;
129 dSP;
130
131 value = eval_flag(field_value);
132
133 ENTER;
134 SAVETMPS;
135 PUSHMARK(SP);
136
137 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
138 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
139 XPUSHs(sv_2mortal(newSVuv(value)));
140 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
141
142 PUTBACK;
143 if (get_cv("main::define_flag_value", 0))
144 call_pv("main::define_flag_value", G_SCALAR);
145 SPAGAIN;
146 PUTBACK;
147 FREETMPS;
148 LEAVE;
149}
150
151static void define_flag_values(struct print_flag_sym *field,
152 const char *ev_name,
153 const char *field_name)
154{
155 define_flag_value(ev_name, field_name, field->value, field->str);
156 if (field->next)
157 define_flag_values(field->next, ev_name, field_name);
158}
159
160static void define_flag_field(const char *ev_name,
161 const char *field_name,
162 const char *delim)
163{
164 dSP;
165
166 ENTER;
167 SAVETMPS;
168 PUSHMARK(SP);
169
170 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
171 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
172 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
173
174 PUTBACK;
175 if (get_cv("main::define_flag_field", 0))
176 call_pv("main::define_flag_field", G_SCALAR);
177 SPAGAIN;
178 PUTBACK;
179 FREETMPS;
180 LEAVE;
181}
182
183static void define_event_symbols(struct event *event,
184 const char *ev_name,
185 struct print_arg *args)
186{
187 switch (args->type) {
188 case PRINT_NULL:
189 break;
190 case PRINT_ATOM:
191 define_flag_value(ev_name, cur_field_name, "0",
192 args->atom.atom);
193 zero_flag_atom = 0;
194 break;
195 case PRINT_FIELD:
196 if (cur_field_name)
197 free(cur_field_name);
198 cur_field_name = strdup(args->field.name);
199 break;
200 case PRINT_FLAGS:
201 define_event_symbols(event, ev_name, args->flags.field);
202 define_flag_field(ev_name, cur_field_name, args->flags.delim);
203 define_flag_values(args->flags.flags, ev_name, cur_field_name);
204 break;
205 case PRINT_SYMBOL:
206 define_event_symbols(event, ev_name, args->symbol.field);
207 define_symbolic_field(ev_name, cur_field_name);
208 define_symbolic_values(args->symbol.symbols, ev_name,
209 cur_field_name);
210 break;
211 case PRINT_STRING:
212 break;
213 case PRINT_TYPE:
214 define_event_symbols(event, ev_name, args->typecast.item);
215 break;
216 case PRINT_OP:
217 if (strcmp(args->op.op, ":") == 0)
218 zero_flag_atom = 1;
219 define_event_symbols(event, ev_name, args->op.left);
220 define_event_symbols(event, ev_name, args->op.right);
221 break;
222 default:
223 /* we should warn... */
224 return;
225 }
226
227 if (args->next)
228 define_event_symbols(event, ev_name, args->next);
229}
230
231static inline struct event *find_cache_event(int type)
232{
233 static char ev_name[256];
234 struct event *event;
235
236 if (events[type])
237 return events[type];
238
239 events[type] = event = trace_find_event(type);
240 if (!event)
241 return NULL;
242
243 sprintf(ev_name, "%s::%s", event->system, event->name);
244
245 define_event_symbols(event, ev_name, event->print_fmt.args);
246
247 return event;
248}
249
David Ahernbe6d8422011-03-09 22:23:23 -0700250static void perl_process_event(union perf_event *pevent __unused,
251 struct perf_sample *sample,
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300252 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200253 struct machine *machine __unused,
David Ahernbe6d8422011-03-09 22:23:23 -0700254 struct thread *thread)
Tom Zanussi16c632d2009-11-25 01:15:48 -0600255{
256 struct format_field *field;
257 static char handler[256];
258 unsigned long long val;
259 unsigned long s, ns;
260 struct event *event;
261 int type;
262 int pid;
David Ahernbe6d8422011-03-09 22:23:23 -0700263 int cpu = sample->cpu;
264 void *data = sample->raw_data;
265 unsigned long long nsecs = sample->time;
266 char *comm = thread->comm;
Tom Zanussi16c632d2009-11-25 01:15:48 -0600267
268 dSP;
269
270 type = trace_parse_common_type(data);
271
272 event = find_cache_event(type);
273 if (!event)
274 die("ug! no event found for type %d", type);
275
276 pid = trace_parse_common_pid(data);
277
278 sprintf(handler, "%s::%s", event->system, event->name);
279
280 s = nsecs / NSECS_PER_SEC;
281 ns = nsecs - s * NSECS_PER_SEC;
282
283 scripting_context->event_data = data;
284
285 ENTER;
286 SAVETMPS;
287 PUSHMARK(SP);
288
289 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
290 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
291 XPUSHs(sv_2mortal(newSVuv(cpu)));
292 XPUSHs(sv_2mortal(newSVuv(s)));
293 XPUSHs(sv_2mortal(newSVuv(ns)));
294 XPUSHs(sv_2mortal(newSViv(pid)));
295 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
296
297 /* common fields other than pid can be accessed via xsub fns */
298
299 for (field = event->format.fields; field; field = field->next) {
300 if (field->flags & FIELD_IS_STRING) {
301 int offset;
302 if (field->flags & FIELD_IS_DYNAMIC) {
303 offset = *(int *)(data + field->offset);
304 offset &= 0xffff;
305 } else
306 offset = field->offset;
307 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
308 } else { /* FIELD_IS_NUMERIC */
309 val = read_size(data + field->offset, field->size);
310 if (field->flags & FIELD_IS_SIGNED) {
311 XPUSHs(sv_2mortal(newSViv(val)));
312 } else {
313 XPUSHs(sv_2mortal(newSVuv(val)));
314 }
315 }
316 }
317
318 PUTBACK;
Tom Zanussid1b93772009-11-25 01:15:50 -0600319
Tom Zanussi16c632d2009-11-25 01:15:48 -0600320 if (get_cv(handler, 0))
321 call_pv(handler, G_SCALAR);
322 else if (get_cv("main::trace_unhandled", 0)) {
323 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
324 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
325 XPUSHs(sv_2mortal(newSVuv(cpu)));
326 XPUSHs(sv_2mortal(newSVuv(nsecs)));
327 XPUSHs(sv_2mortal(newSViv(pid)));
328 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
329 call_pv("main::trace_unhandled", G_SCALAR);
330 }
331 SPAGAIN;
332 PUTBACK;
333 FREETMPS;
334 LEAVE;
335}
336
337static void run_start_sub(void)
338{
339 dSP; /* access to Perl stack */
340 PUSHMARK(SP);
341
342 if (get_cv("main::trace_begin", 0))
343 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
344}
345
346/*
347 * Start trace script
348 */
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600349static int perl_start_script(const char *script, int argc, const char **argv)
Tom Zanussi16c632d2009-11-25 01:15:48 -0600350{
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600351 const char **command_line;
352 int i, err = 0;
Tom Zanussi16c632d2009-11-25 01:15:48 -0600353
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600354 command_line = malloc((argc + 2) * sizeof(const char *));
355 command_line[0] = "";
Tom Zanussi16c632d2009-11-25 01:15:48 -0600356 command_line[1] = script;
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600357 for (i = 2; i < argc + 2; i++)
358 command_line[i] = argv[i - 2];
Tom Zanussi16c632d2009-11-25 01:15:48 -0600359
360 my_perl = perl_alloc();
361 perl_construct(my_perl);
362
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600363 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
364 (char **)NULL)) {
365 err = -1;
366 goto error;
367 }
Tom Zanussi16c632d2009-11-25 01:15:48 -0600368
Tom Zanussi8f11d852009-12-15 02:53:37 -0600369 if (perl_run(my_perl)) {
370 err = -1;
371 goto error;
372 }
373
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600374 if (SvTRUE(ERRSV)) {
375 err = -1;
376 goto error;
377 }
Tom Zanussi16c632d2009-11-25 01:15:48 -0600378
379 run_start_sub();
380
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600381 free(command_line);
Tom Zanussi16c632d2009-11-25 01:15:48 -0600382 return 0;
Tom Zanussi586bc5c2009-12-15 02:53:35 -0600383error:
384 perl_free(my_perl);
385 free(command_line);
386
387 return err;
Tom Zanussi16c632d2009-11-25 01:15:48 -0600388}
389
390/*
391 * Stop trace script
392 */
393static int perl_stop_script(void)
394{
395 dSP; /* access to Perl stack */
396 PUSHMARK(SP);
397
398 if (get_cv("main::trace_end", 0))
399 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
400
401 perl_destruct(my_perl);
402 perl_free(my_perl);
403
Tom Zanussi16c632d2009-11-25 01:15:48 -0600404 return 0;
405}
406
407static int perl_generate_script(const char *outfile)
408{
409 struct event *event = NULL;
410 struct format_field *f;
411 char fname[PATH_MAX];
412 int not_first, count;
413 FILE *ofp;
414
415 sprintf(fname, "%s.pl", outfile);
416 ofp = fopen(fname, "w");
417 if (ofp == NULL) {
418 fprintf(stderr, "couldn't open %s\n", fname);
419 return -1;
420 }
421
Ingo Molnar133dc4c2010-11-16 18:45:39 +0100422 fprintf(ofp, "# perf script event handlers, "
423 "generated by perf script -g perl\n");
Tom Zanussi16c632d2009-11-25 01:15:48 -0600424
425 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
426 " License version 2\n\n");
427
428 fprintf(ofp, "# The common_* event handler fields are the most useful "
429 "fields common to\n");
430
431 fprintf(ofp, "# all events. They don't necessarily correspond to "
432 "the 'common_*' fields\n");
433
434 fprintf(ofp, "# in the format files. Those fields not available as "
435 "handler params can\n");
436
437 fprintf(ofp, "# be retrieved using Perl functions of the form "
438 "common_*($context).\n");
439
440 fprintf(ofp, "# See Context.pm for the list of available "
441 "functions.\n\n");
442
443 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
444 "Perf-Trace-Util/lib\";\n");
445
446 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
447 fprintf(ofp, "use Perf::Trace::Core;\n");
448 fprintf(ofp, "use Perf::Trace::Context;\n");
449 fprintf(ofp, "use Perf::Trace::Util;\n\n");
450
451 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
452 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
453
454 while ((event = trace_find_next_event(event))) {
455 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
456 fprintf(ofp, "\tmy (");
457
458 fprintf(ofp, "$event_name, ");
459 fprintf(ofp, "$context, ");
460 fprintf(ofp, "$common_cpu, ");
461 fprintf(ofp, "$common_secs, ");
462 fprintf(ofp, "$common_nsecs,\n");
463 fprintf(ofp, "\t $common_pid, ");
464 fprintf(ofp, "$common_comm,\n\t ");
465
466 not_first = 0;
467 count = 0;
468
469 for (f = event->format.fields; f; f = f->next) {
470 if (not_first++)
471 fprintf(ofp, ", ");
472 if (++count % 5 == 0)
473 fprintf(ofp, "\n\t ");
474
475 fprintf(ofp, "$%s", f->name);
476 }
477 fprintf(ofp, ") = @_;\n\n");
478
479 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
480 "$common_secs, $common_nsecs,\n\t "
481 "$common_pid, $common_comm);\n\n");
482
483 fprintf(ofp, "\tprintf(\"");
484
485 not_first = 0;
486 count = 0;
487
488 for (f = event->format.fields; f; f = f->next) {
489 if (not_first++)
490 fprintf(ofp, ", ");
491 if (count && count % 4 == 0) {
492 fprintf(ofp, "\".\n\t \"");
493 }
494 count++;
495
496 fprintf(ofp, "%s=", f->name);
497 if (f->flags & FIELD_IS_STRING ||
498 f->flags & FIELD_IS_FLAG ||
499 f->flags & FIELD_IS_SYMBOLIC)
500 fprintf(ofp, "%%s");
501 else if (f->flags & FIELD_IS_SIGNED)
502 fprintf(ofp, "%%d");
503 else
504 fprintf(ofp, "%%u");
505 }
506
507 fprintf(ofp, "\\n\",\n\t ");
508
509 not_first = 0;
510 count = 0;
511
512 for (f = event->format.fields; f; f = f->next) {
513 if (not_first++)
514 fprintf(ofp, ", ");
515
516 if (++count % 5 == 0)
517 fprintf(ofp, "\n\t ");
518
519 if (f->flags & FIELD_IS_FLAG) {
520 if ((count - 1) % 5 != 0) {
521 fprintf(ofp, "\n\t ");
522 count = 4;
523 }
524 fprintf(ofp, "flag_str(\"");
525 fprintf(ofp, "%s::%s\", ", event->system,
526 event->name);
527 fprintf(ofp, "\"%s\", $%s)", f->name,
528 f->name);
529 } else if (f->flags & FIELD_IS_SYMBOLIC) {
530 if ((count - 1) % 5 != 0) {
531 fprintf(ofp, "\n\t ");
532 count = 4;
533 }
534 fprintf(ofp, "symbol_str(\"");
535 fprintf(ofp, "%s::%s\", ", event->system,
536 event->name);
537 fprintf(ofp, "\"%s\", $%s)", f->name,
538 f->name);
539 } else
540 fprintf(ofp, "$%s", f->name);
541 }
542
543 fprintf(ofp, ");\n");
544 fprintf(ofp, "}\n\n");
545 }
546
547 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
548 "$common_cpu, $common_secs, $common_nsecs,\n\t "
549 "$common_pid, $common_comm) = @_;\n\n");
550
551 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
552 "$common_secs, $common_nsecs,\n\t $common_pid, "
553 "$common_comm);\n}\n\n");
554
555 fprintf(ofp, "sub print_header\n{\n"
556 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
557 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
558 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
559
560 fclose(ofp);
561
562 fprintf(stderr, "generated Perl script: %s\n", fname);
563
564 return 0;
565}
566
567struct scripting_ops perl_scripting_ops = {
568 .name = "Perl",
569 .start_script = perl_start_script,
570 .stop_script = perl_stop_script,
571 .process_event = perl_process_event,
572 .generate_script = perl_generate_script,
573};