aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
authorTom Zanussi <tzanussi@gmail.com>2009-12-15 03:53:38 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-15 04:31:32 -0500
commit4b9c0c596ea826ef784eb83f663c5351ed01ba6d (patch)
tree8e22badb64e744d61d2ed4f6d12a0ebeb05a61c3 /tools/perf/builtin-trace.c
parent8f11d85a0e7e9025acea7493e6864089c8b52f42 (diff)
perf trace/scripting: List available scripts
Lists the available perf trace scripts, one per line e.g.: root@tropicana:~# perf trace -l List of available trace scripts: workqueue-stats workqueue stats (ins/exe/create/destroy) wakeup-latency system-wide min/max/avg wakeup latency rw-by-file <comm> r/w activity for a program, by file check-perf-trace useless but exhaustive test script rw-by-pid system-wide r/w activity To be consistent with the other listing options in perf, the current latency trace option was changed to '-L', and '-l' is now used to access the script listing as: To create the list, it searches each scripts/*/bin directory for files ending with "-report" and reads information found in certain comment lines contained in those shell scripts: - if the comment line starts with "description:", the rest of the line is used as a 'half-line' description. To keep each line in the list to a single line, the description should be limited to 40 characters (the rest of the line contains the script name and args) - if the comment line starts with "args:", the rest of the line names the args the script supports. Required args should be surrounded by <> brackets, optional args by [] brackets. The current scripts in scripts/perl/bin have also been updated with description: and args: comments. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org LKML-Reference: <1260867220-15699-5-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c199
1 files changed, 198 insertions, 1 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 88b0353d4019..7674153c4bbe 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -274,6 +274,201 @@ static int parse_scriptname(const struct option *opt __used,
274 return 0; 274 return 0;
275} 275}
276 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
293struct script_desc {
294 struct list_head node;
295 char *name;
296 char *half_liner;
297 char *args;
298};
299
300LIST_HEAD(script_descs);
301
302static 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
312static void script_desc__delete(struct script_desc *s)
313{
314 free(s->name);
315 free(s);
316}
317
318static void script_desc__add(struct script_desc *s)
319{
320 list_add_tail(&s->node, &script_descs);
321}
322
323static 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
333static 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
348out_delete_desc:
349 script_desc__delete(s);
350
351 return NULL;
352}
353
354static 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
368static 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
380static 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
421static 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
277static const char * const annotate_usage[] = { 472static const char * const annotate_usage[] = {
278 "perf trace [<options>] <command>", 473 "perf trace [<options>] <command>",
279 NULL 474 NULL
@@ -284,8 +479,10 @@ static const struct option options[] = {
284 "dump raw trace in ASCII"), 479 "dump raw trace in ASCII"),
285 OPT_BOOLEAN('v', "verbose", &verbose, 480 OPT_BOOLEAN('v', "verbose", &verbose,
286 "be more verbose (show symbol address, etc)"), 481 "be more verbose (show symbol address, etc)"),
287 OPT_BOOLEAN('l', "latency", &latency_format, 482 OPT_BOOLEAN('L', "Latency", &latency_format,
288 "show latency attributes (irqs/preemption disabled, etc)"), 483 "show latency attributes (irqs/preemption disabled, etc)"),
484 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
485 list_available_scripts),
289 OPT_CALLBACK('s', "script", NULL, "name", 486 OPT_CALLBACK('s', "script", NULL, "name",
290 "script file name (lang:script name, script name, or *)", 487 "script file name (lang:script name, script name, or *)",
291 parse_scriptname), 488 parse_scriptname),