| #include <linux/compiler.h> |
| #include <linux/kernel.h> |
| #include "util.h" |
| #include "debug.h" |
| #include "builtin.h" |
| #include <subcmd/parse-options.h> |
| #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 [<options>] [<command>]", |
| "perf c2c record [<options>] -- <command> [<options>]", |
| 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[] = { |
| OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
| OPT_END() |
| }; |
| |
| 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; |
| } |