diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 8252ed0ba5d0..58924c67f818 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -4,12 +4,116 @@ #include "debug.h" #include "builtin.h" #include +#include "mem-events.h" static const char * const c2c_usage[] = { "perf c2c", NULL }; +static int parse_record_events(const struct option *opt __maybe_unused, + const char *str, int unset __maybe_unused) +{ + bool *event_set = (bool *) opt->value; + + *event_set = true; + return perf_mem_events__parse(str); +} + + +static const char * const __usage_record[] = { + "perf c2c record [] []", + "perf c2c record [] -- []", + NULL +}; + +static const char * const *record_mem_usage = __usage_record; + +static int perf_c2c__record(int argc, const char **argv) +{ + int rec_argc, i = 0, j; + const char **rec_argv; + int ret; + bool all_user = false, all_kernel = false; + bool event_set = false; + struct option options[] = { + OPT_CALLBACK('e', "event", &event_set, "event", + "event selector. Use 'perf mem record -e list' to list available events", + parse_record_events), + OPT_INCR('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"), + OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"), + OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"), + OPT_END() + }; + + if (perf_mem_events__init()) { + pr_err("failed: memory events not supported\n"); + return -1; + } + + argc = parse_options(argc, argv, options, record_mem_usage, + PARSE_OPT_KEEP_UNKNOWN); + + rec_argc = argc + 10; /* max number of arguments */ + rec_argv = calloc(rec_argc + 1, sizeof(char *)); + if (!rec_argv) + return -1; + + rec_argv[i++] = "record"; + + if (!event_set) { + perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true; + perf_mem_events[PERF_MEM_EVENTS__STORE].record = true; + } + + if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record) + rec_argv[i++] = "-W"; + + rec_argv[i++] = "-d"; + rec_argv[i++] = "--sample-cpu"; + + for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { + if (!perf_mem_events[j].record) + continue; + + if (!perf_mem_events[j].supported) { + pr_err("failed: event '%s' not supported\n", + perf_mem_events[j].name); + return -1; + } + + rec_argv[i++] = "-e"; + rec_argv[i++] = perf_mem_events__name(j); + }; + + if (all_user) + rec_argv[i++] = "--all-user"; + + if (all_kernel) + rec_argv[i++] = "--all-kernel"; + + for (j = 0; j < argc; j++, i++) + rec_argv[i] = argv[j]; + + if (verbose > 0) { + pr_debug("calling: "); + + j = 0; + + while (rec_argv[j]) { + pr_debug("%s ", rec_argv[j]); + j++; + } + pr_debug("\n"); + } + + ret = cmd_record(i, rec_argv, NULL); + free(rec_argv); + return ret; +} + int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused) { const struct option c2c_options[] = { @@ -19,5 +123,15 @@ int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused) argc = parse_options(argc, argv, c2c_options, c2c_usage, PARSE_OPT_STOP_AT_NON_OPTION); + + if (!argc) + usage_with_options(c2c_usage, c2c_options); + + if (!strncmp(argv[0], "rec", 3)) { + return perf_c2c__record(argc, argv); + } else { + usage_with_options(c2c_usage, c2c_options); + } + return 0; }