1 #include "builtin.h" 2 3 #include "util/util.h" 4 #include "util/cache.h" 5 #include "util/symbol.h" 6 #include "util/thread.h" 7 #include "util/header.h" 8 #include "util/exec_cmd.h" 9 #include "util/trace-event.h" 10 #include "util/session.h" 11 12 static char const *script_name; 13 static char const *generate_script_lang; 14 15 static int default_start_script(const char *script __unused, 16 int argc __unused, 17 const char **argv __unused) 18 { 19 return 0; 20 } 21 22 static int default_stop_script(void) 23 { 24 return 0; 25 } 26 27 static int default_generate_script(const char *outfile __unused) 28 { 29 return 0; 30 } 31 32 static struct scripting_ops default_scripting_ops = { 33 .start_script = default_start_script, 34 .stop_script = default_stop_script, 35 .process_event = print_event, 36 .generate_script = default_generate_script, 37 }; 38 39 static struct scripting_ops *scripting_ops; 40 41 static void setup_scripting(void) 42 { 43 /* make sure PERF_EXEC_PATH is set for scripts */ 44 perf_set_argv_exec_path(perf_exec_path()); 45 46 setup_perl_scripting(); 47 48 scripting_ops = &default_scripting_ops; 49 } 50 51 static int cleanup_scripting(void) 52 { 53 return scripting_ops->stop_script(); 54 } 55 56 #include "util/parse-options.h" 57 58 #include "perf.h" 59 #include "util/debug.h" 60 61 #include "util/trace-event.h" 62 #include "util/exec_cmd.h" 63 64 static char const *input_name = "perf.data"; 65 66 static int process_sample_event(event_t *event, struct perf_session *session) 67 { 68 struct sample_data data; 69 struct thread *thread; 70 71 memset(&data, 0, sizeof(data)); 72 data.time = -1; 73 data.cpu = -1; 74 data.period = 1; 75 76 event__parse_sample(event, session->sample_type, &data); 77 78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 79 event->header.misc, 80 data.pid, data.tid, 81 (void *)(long)data.ip, 82 (long long)data.period); 83 84 thread = perf_session__findnew(session, event->ip.pid); 85 if (thread == NULL) { 86 pr_debug("problem processing %d event, skipping it.\n", 87 event->header.type); 88 return -1; 89 } 90 91 if (session->sample_type & PERF_SAMPLE_RAW) { 92 /* 93 * FIXME: better resolve from pid from the struct trace_entry 94 * field, although it should be the same than this perf 95 * event pid 96 */ 97 scripting_ops->process_event(data.cpu, data.raw_data, 98 data.raw_size, 99 data.time, thread->comm); 100 } 101 102 session->events_stats.total += data.period; 103 return 0; 104 } 105 106 static int sample_type_check(struct perf_session *session) 107 { 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) { 109 fprintf(stderr, 110 "No trace sample to read. Did you call perf record " 111 "without -R?"); 112 return -1; 113 } 114 115 return 0; 116 } 117 118 static struct perf_event_ops event_ops = { 119 .process_sample_event = process_sample_event, 120 .process_comm_event = event__process_comm, 121 .sample_type_check = sample_type_check, 122 }; 123 124 static int __cmd_trace(struct perf_session *session) 125 { 126 return perf_session__process_events(session, &event_ops); 127 } 128 129 struct script_spec { 130 struct list_head node; 131 struct scripting_ops *ops; 132 char spec[0]; 133 }; 134 135 LIST_HEAD(script_specs); 136 137 static struct script_spec *script_spec__new(const char *spec, 138 struct scripting_ops *ops) 139 { 140 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1); 141 142 if (s != NULL) { 143 strcpy(s->spec, spec); 144 s->ops = ops; 145 } 146 147 return s; 148 } 149 150 static void script_spec__delete(struct script_spec *s) 151 { 152 free(s->spec); 153 free(s); 154 } 155 156 static void script_spec__add(struct script_spec *s) 157 { 158 list_add_tail(&s->node, &script_specs); 159 } 160 161 static struct script_spec *script_spec__find(const char *spec) 162 { 163 struct script_spec *s; 164 165 list_for_each_entry(s, &script_specs, node) 166 if (strcasecmp(s->spec, spec) == 0) 167 return s; 168 return NULL; 169 } 170 171 static struct script_spec *script_spec__findnew(const char *spec, 172 struct scripting_ops *ops) 173 { 174 struct script_spec *s = script_spec__find(spec); 175 176 if (s) 177 return s; 178 179 s = script_spec__new(spec, ops); 180 if (!s) 181 goto out_delete_spec; 182 183 script_spec__add(s); 184 185 return s; 186 187 out_delete_spec: 188 script_spec__delete(s); 189 190 return NULL; 191 } 192 193 int script_spec_register(const char *spec, struct scripting_ops *ops) 194 { 195 struct script_spec *s; 196 197 s = script_spec__find(spec); 198 if (s) 199 return -1; 200 201 s = script_spec__findnew(spec, ops); 202 if (!s) 203 return -1; 204 205 return 0; 206 } 207 208 static struct scripting_ops *script_spec__lookup(const char *spec) 209 { 210 struct script_spec *s = script_spec__find(spec); 211 if (!s) 212 return NULL; 213 214 return s->ops; 215 } 216 217 static void list_available_languages(void) 218 { 219 struct script_spec *s; 220 221 fprintf(stderr, "\n"); 222 fprintf(stderr, "Scripting language extensions (used in " 223 "perf trace -s [spec:]script.[spec]):\n\n"); 224 225 list_for_each_entry(s, &script_specs, node) 226 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); 227 228 fprintf(stderr, "\n"); 229 } 230 231 static int parse_scriptname(const struct option *opt __used, 232 const char *str, int unset __used) 233 { 234 char spec[PATH_MAX]; 235 const char *script, *ext; 236 int len; 237 238 if (strcmp(str, "list") == 0) { 239 list_available_languages(); 240 return 0; 241 } 242 243 script = strchr(str, ':'); 244 if (script) { 245 len = script - str; 246 if (len >= PATH_MAX) { 247 fprintf(stderr, "invalid language specifier"); 248 return -1; 249 } 250 strncpy(spec, str, len); 251 spec[len] = '\0'; 252 scripting_ops = script_spec__lookup(spec); 253 if (!scripting_ops) { 254 fprintf(stderr, "invalid language specifier"); 255 return -1; 256 } 257 script++; 258 } else { 259 script = str; 260 ext = strchr(script, '.'); 261 if (!ext) { 262 fprintf(stderr, "invalid script extension"); 263 return -1; 264 } 265 scripting_ops = script_spec__lookup(++ext); 266 if (!scripting_ops) { 267 fprintf(stderr, "invalid script extension"); 268 return -1; 269 } 270 } 271 272 script_name = strdup(script); 273 274 return 0; 275 } 276 277 #define for_each_lang(scripts_dir, lang_dirent, lang_next) \ 278 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ 279 lang_next) \ 280 if (lang_dirent.d_type == DT_DIR && \ 281 (strcmp(lang_dirent.d_name, ".")) && \ 282 (strcmp(lang_dirent.d_name, ".."))) 283 284 #define for_each_script(lang_dir, script_dirent, script_next) \ 285 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ 286 script_next) \ 287 if (script_dirent.d_type != DT_DIR) 288 289 290 #define RECORD_SUFFIX "-record" 291 #define REPORT_SUFFIX "-report" 292 293 struct script_desc { 294 struct list_head node; 295 char *name; 296 char *half_liner; 297 char *args; 298 }; 299 300 LIST_HEAD(script_descs); 301 302 static struct script_desc *script_desc__new(const char *name) 303 { 304 struct script_desc *s = zalloc(sizeof(*s)); 305 306 if (s != NULL) 307 s->name = strdup(name); 308 309 return s; 310 } 311 312 static void script_desc__delete(struct script_desc *s) 313 { 314 free(s->name); 315 free(s); 316 } 317 318 static void script_desc__add(struct script_desc *s) 319 { 320 list_add_tail(&s->node, &script_descs); 321 } 322 323 static struct script_desc *script_desc__find(const char *name) 324 { 325 struct script_desc *s; 326 327 list_for_each_entry(s, &script_descs, node) 328 if (strcasecmp(s->name, name) == 0) 329 return s; 330 return NULL; 331 } 332 333 static struct script_desc *script_desc__findnew(const char *name) 334 { 335 struct script_desc *s = script_desc__find(name); 336 337 if (s) 338 return s; 339 340 s = script_desc__new(name); 341 if (!s) 342 goto out_delete_desc; 343 344 script_desc__add(s); 345 346 return s; 347 348 out_delete_desc: 349 script_desc__delete(s); 350 351 return NULL; 352 } 353 354 static char *ends_with(char *str, const char *suffix) 355 { 356 size_t suffix_len = strlen(suffix); 357 char *p = str; 358 359 if (strlen(str) > suffix_len) { 360 p = str + strlen(str) - suffix_len; 361 if (!strncmp(p, suffix, suffix_len)) 362 return p; 363 } 364 365 return NULL; 366 } 367 368 static char *ltrim(char *str) 369 { 370 int len = strlen(str); 371 372 while (len && isspace(*str)) { 373 len--; 374 str++; 375 } 376 377 return str; 378 } 379 380 static int read_script_info(struct script_desc *desc, const char *filename) 381 { 382 char line[BUFSIZ], *p; 383 FILE *fp; 384 385 fp = fopen(filename, "r"); 386 if (!fp) 387 return -1; 388 389 while (fgets(line, sizeof(line), fp)) { 390 p = ltrim(line); 391 if (strlen(p) == 0) 392 continue; 393 if (*p != '#') 394 continue; 395 p++; 396 if (strlen(p) && *p == '!') 397 continue; 398 399 p = ltrim(p); 400 if (strlen(p) && p[strlen(p) - 1] == '\n') 401 p[strlen(p) - 1] = '\0'; 402 403 if (!strncmp(p, "description:", strlen("description:"))) { 404 p += strlen("description:"); 405 desc->half_liner = strdup(ltrim(p)); 406 continue; 407 } 408 409 if (!strncmp(p, "args:", strlen("args:"))) { 410 p += strlen("args:"); 411 desc->args = strdup(ltrim(p)); 412 continue; 413 } 414 } 415 416 fclose(fp); 417 418 return 0; 419 } 420 421 static int list_available_scripts(const struct option *opt __used, 422 const char *s __used, int unset __used) 423 { 424 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 425 char scripts_path[MAXPATHLEN]; 426 DIR *scripts_dir, *lang_dir; 427 char script_path[MAXPATHLEN]; 428 char lang_path[MAXPATHLEN]; 429 struct script_desc *desc; 430 char first_half[BUFSIZ]; 431 char *script_root; 432 char *str; 433 434 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 435 436 scripts_dir = opendir(scripts_path); 437 if (!scripts_dir) 438 return -1; 439 440 for_each_lang(scripts_dir, lang_dirent, lang_next) { 441 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 442 lang_dirent.d_name); 443 lang_dir = opendir(lang_path); 444 if (!lang_dir) 445 continue; 446 447 for_each_script(lang_dir, script_dirent, script_next) { 448 script_root = strdup(script_dirent.d_name); 449 str = ends_with(script_root, REPORT_SUFFIX); 450 if (str) { 451 *str = '\0'; 452 desc = script_desc__findnew(script_root); 453 snprintf(script_path, MAXPATHLEN, "%s/%s", 454 lang_path, script_dirent.d_name); 455 read_script_info(desc, script_path); 456 } 457 free(script_root); 458 } 459 } 460 461 fprintf(stdout, "List of available trace scripts:\n"); 462 list_for_each_entry(desc, &script_descs, node) { 463 sprintf(first_half, "%s %s", desc->name, 464 desc->args ? desc->args : ""); 465 fprintf(stdout, " %-36s %s\n", first_half, 466 desc->half_liner ? desc->half_liner : ""); 467 } 468 469 exit(0); 470 } 471 472 static const char * const annotate_usage[] = { 473 "perf trace [<options>] <command>", 474 NULL 475 }; 476 477 static const struct option options[] = { 478 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 479 "dump raw trace in ASCII"), 480 OPT_BOOLEAN('v', "verbose", &verbose, 481 "be more verbose (show symbol address, etc)"), 482 OPT_BOOLEAN('L', "Latency", &latency_format, 483 "show latency attributes (irqs/preemption disabled, etc)"), 484 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", 485 list_available_scripts), 486 OPT_CALLBACK('s', "script", NULL, "name", 487 "script file name (lang:script name, script name, or *)", 488 parse_scriptname), 489 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 490 "generate perf-trace.xx script in specified language"), 491 492 OPT_END() 493 }; 494 495 int cmd_trace(int argc, const char **argv, const char *prefix __used) 496 { 497 int err; 498 struct perf_session *session; 499 500 symbol__init(0); 501 502 setup_scripting(); 503 504 argc = parse_options(argc, argv, options, annotate_usage, 505 PARSE_OPT_STOP_AT_NON_OPTION); 506 507 setup_pager(); 508 509 session = perf_session__new(input_name, O_RDONLY, 0, NULL); 510 if (session == NULL) 511 return -ENOMEM; 512 513 if (generate_script_lang) { 514 struct stat perf_stat; 515 516 int input = open(input_name, O_RDONLY); 517 if (input < 0) { 518 perror("failed to open file"); 519 exit(-1); 520 } 521 522 err = fstat(input, &perf_stat); 523 if (err < 0) { 524 perror("failed to stat file"); 525 exit(-1); 526 } 527 528 if (!perf_stat.st_size) { 529 fprintf(stderr, "zero-sized file, nothing to do!\n"); 530 exit(0); 531 } 532 533 scripting_ops = script_spec__lookup(generate_script_lang); 534 if (!scripting_ops) { 535 fprintf(stderr, "invalid language specifier"); 536 return -1; 537 } 538 539 perf_header__read(&session->header, input); 540 err = scripting_ops->generate_script("perf-trace"); 541 goto out; 542 } 543 544 if (script_name) { 545 err = scripting_ops->start_script(script_name, argc, argv); 546 if (err) 547 goto out; 548 } 549 550 err = __cmd_trace(session); 551 552 perf_session__delete(session); 553 cleanup_scripting(); 554 out: 555 return err; 556 } 557