Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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