18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <inttypes.h> 38c2ecf20Sopenharmony_ci#include <sys/types.h> 48c2ecf20Sopenharmony_ci#include <sys/stat.h> 58c2ecf20Sopenharmony_ci#include <unistd.h> 68c2ecf20Sopenharmony_ci#include "builtin.h" 78c2ecf20Sopenharmony_ci#include "perf.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 108c2ecf20Sopenharmony_ci#include "util/trace-event.h" 118c2ecf20Sopenharmony_ci#include "util/tool.h" 128c2ecf20Sopenharmony_ci#include "util/session.h" 138c2ecf20Sopenharmony_ci#include "util/data.h" 148c2ecf20Sopenharmony_ci#include "util/map_symbol.h" 158c2ecf20Sopenharmony_ci#include "util/mem-events.h" 168c2ecf20Sopenharmony_ci#include "util/debug.h" 178c2ecf20Sopenharmony_ci#include "util/dso.h" 188c2ecf20Sopenharmony_ci#include "util/map.h" 198c2ecf20Sopenharmony_ci#include "util/symbol.h" 208c2ecf20Sopenharmony_ci#include <linux/err.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MEM_OPERATION_LOAD 0x1 238c2ecf20Sopenharmony_ci#define MEM_OPERATION_STORE 0x2 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct perf_mem { 268c2ecf20Sopenharmony_ci struct perf_tool tool; 278c2ecf20Sopenharmony_ci char const *input_name; 288c2ecf20Sopenharmony_ci bool hide_unresolved; 298c2ecf20Sopenharmony_ci bool dump_raw; 308c2ecf20Sopenharmony_ci bool force; 318c2ecf20Sopenharmony_ci bool phys_addr; 328c2ecf20Sopenharmony_ci int operation; 338c2ecf20Sopenharmony_ci const char *cpu_list; 348c2ecf20Sopenharmony_ci DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int parse_record_events(const struct option *opt, 388c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct perf_mem *mem = *(struct perf_mem **)opt->value; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (!strcmp(str, "list")) { 438c2ecf20Sopenharmony_ci perf_mem_events__list(); 448c2ecf20Sopenharmony_ci exit(0); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci if (perf_mem_events__parse(str)) 478c2ecf20Sopenharmony_ci exit(-1); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci mem->operation = 0; 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic const char * const __usage[] = { 548c2ecf20Sopenharmony_ci "perf mem record [<options>] [<command>]", 558c2ecf20Sopenharmony_ci "perf mem record [<options>] -- <command> [<options>]", 568c2ecf20Sopenharmony_ci NULL 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const char * const *record_mem_usage = __usage; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int __cmd_record(int argc, const char **argv, struct perf_mem *mem) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci int rec_argc, i = 0, j; 648c2ecf20Sopenharmony_ci const char **rec_argv; 658c2ecf20Sopenharmony_ci int ret; 668c2ecf20Sopenharmony_ci bool all_user = false, all_kernel = false; 678c2ecf20Sopenharmony_ci struct option options[] = { 688c2ecf20Sopenharmony_ci OPT_CALLBACK('e', "event", &mem, "event", 698c2ecf20Sopenharmony_ci "event selector. use 'perf mem record -e list' to list available events", 708c2ecf20Sopenharmony_ci parse_record_events), 718c2ecf20Sopenharmony_ci OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), 728c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 738c2ecf20Sopenharmony_ci "be more verbose (show counter open errors, etc)"), 748c2ecf20Sopenharmony_ci OPT_BOOLEAN('U', "all-user", &all_user, "collect only user level data"), 758c2ecf20Sopenharmony_ci OPT_BOOLEAN('K', "all-kernel", &all_kernel, "collect only kernel level data"), 768c2ecf20Sopenharmony_ci OPT_END() 778c2ecf20Sopenharmony_ci }; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, options, record_mem_usage, 808c2ecf20Sopenharmony_ci PARSE_OPT_KEEP_UNKNOWN); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci rec_argc = argc + 9; /* max number of arguments */ 838c2ecf20Sopenharmony_ci rec_argv = calloc(rec_argc + 1, sizeof(char *)); 848c2ecf20Sopenharmony_ci if (!rec_argv) 858c2ecf20Sopenharmony_ci return -1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci rec_argv[i++] = "record"; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (mem->operation & MEM_OPERATION_LOAD) 908c2ecf20Sopenharmony_ci perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (mem->operation & MEM_OPERATION_STORE) 938c2ecf20Sopenharmony_ci perf_mem_events[PERF_MEM_EVENTS__STORE].record = true; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record) 968c2ecf20Sopenharmony_ci rec_argv[i++] = "-W"; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci rec_argv[i++] = "-d"; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (mem->phys_addr) 1018c2ecf20Sopenharmony_ci rec_argv[i++] = "--phys-data"; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 1048c2ecf20Sopenharmony_ci if (!perf_mem_events[j].record) 1058c2ecf20Sopenharmony_ci continue; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (!perf_mem_events[j].supported) { 1088c2ecf20Sopenharmony_ci pr_err("failed: event '%s' not supported\n", 1098c2ecf20Sopenharmony_ci perf_mem_events__name(j)); 1108c2ecf20Sopenharmony_ci free(rec_argv); 1118c2ecf20Sopenharmony_ci return -1; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rec_argv[i++] = "-e"; 1158c2ecf20Sopenharmony_ci rec_argv[i++] = perf_mem_events__name(j); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (all_user) 1198c2ecf20Sopenharmony_ci rec_argv[i++] = "--all-user"; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (all_kernel) 1228c2ecf20Sopenharmony_ci rec_argv[i++] = "--all-kernel"; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci for (j = 0; j < argc; j++, i++) 1258c2ecf20Sopenharmony_ci rec_argv[i] = argv[j]; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (verbose > 0) { 1288c2ecf20Sopenharmony_ci pr_debug("calling: record "); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci while (rec_argv[j]) { 1318c2ecf20Sopenharmony_ci pr_debug("%s ", rec_argv[j]); 1328c2ecf20Sopenharmony_ci j++; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci pr_debug("\n"); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ret = cmd_record(i, rec_argv); 1388c2ecf20Sopenharmony_ci free(rec_argv); 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int 1438c2ecf20Sopenharmony_cidump_raw_samples(struct perf_tool *tool, 1448c2ecf20Sopenharmony_ci union perf_event *event, 1458c2ecf20Sopenharmony_ci struct perf_sample *sample, 1468c2ecf20Sopenharmony_ci struct machine *machine) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct perf_mem *mem = container_of(tool, struct perf_mem, tool); 1498c2ecf20Sopenharmony_ci struct addr_location al; 1508c2ecf20Sopenharmony_ci const char *fmt; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (machine__resolve(machine, &al, sample) < 0) { 1538c2ecf20Sopenharmony_ci fprintf(stderr, "problem processing %d event, skipping it.\n", 1548c2ecf20Sopenharmony_ci event->header.type); 1558c2ecf20Sopenharmony_ci return -1; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (al.filtered || (mem->hide_unresolved && al.sym == NULL)) 1598c2ecf20Sopenharmony_ci goto out_put; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (al.map != NULL) 1628c2ecf20Sopenharmony_ci al.map->dso->hit = 1; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (mem->phys_addr) { 1658c2ecf20Sopenharmony_ci if (symbol_conf.field_sep) { 1668c2ecf20Sopenharmony_ci fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s0x%016"PRIx64 1678c2ecf20Sopenharmony_ci "%s%"PRIu64"%s0x%"PRIx64"%s%s:%s\n"; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 1708c2ecf20Sopenharmony_ci "%s0x%016"PRIx64"%s%5"PRIu64"%s0x%06"PRIx64 1718c2ecf20Sopenharmony_ci "%s%s:%s\n"; 1728c2ecf20Sopenharmony_ci symbol_conf.field_sep = " "; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci printf(fmt, 1768c2ecf20Sopenharmony_ci sample->pid, 1778c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1788c2ecf20Sopenharmony_ci sample->tid, 1798c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1808c2ecf20Sopenharmony_ci sample->ip, 1818c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1828c2ecf20Sopenharmony_ci sample->addr, 1838c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1848c2ecf20Sopenharmony_ci sample->phys_addr, 1858c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1868c2ecf20Sopenharmony_ci sample->weight, 1878c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1888c2ecf20Sopenharmony_ci sample->data_src, 1898c2ecf20Sopenharmony_ci symbol_conf.field_sep, 1908c2ecf20Sopenharmony_ci al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", 1918c2ecf20Sopenharmony_ci al.sym ? al.sym->name : "???"); 1928c2ecf20Sopenharmony_ci } else { 1938c2ecf20Sopenharmony_ci if (symbol_conf.field_sep) { 1948c2ecf20Sopenharmony_ci fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64 1958c2ecf20Sopenharmony_ci "%s0x%"PRIx64"%s%s:%s\n"; 1968c2ecf20Sopenharmony_ci } else { 1978c2ecf20Sopenharmony_ci fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64 1988c2ecf20Sopenharmony_ci "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n"; 1998c2ecf20Sopenharmony_ci symbol_conf.field_sep = " "; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci printf(fmt, 2038c2ecf20Sopenharmony_ci sample->pid, 2048c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2058c2ecf20Sopenharmony_ci sample->tid, 2068c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2078c2ecf20Sopenharmony_ci sample->ip, 2088c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2098c2ecf20Sopenharmony_ci sample->addr, 2108c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2118c2ecf20Sopenharmony_ci sample->weight, 2128c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2138c2ecf20Sopenharmony_ci sample->data_src, 2148c2ecf20Sopenharmony_ci symbol_conf.field_sep, 2158c2ecf20Sopenharmony_ci al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???", 2168c2ecf20Sopenharmony_ci al.sym ? al.sym->name : "???"); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ciout_put: 2198c2ecf20Sopenharmony_ci addr_location__put(&al); 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int process_sample_event(struct perf_tool *tool, 2248c2ecf20Sopenharmony_ci union perf_event *event, 2258c2ecf20Sopenharmony_ci struct perf_sample *sample, 2268c2ecf20Sopenharmony_ci struct evsel *evsel __maybe_unused, 2278c2ecf20Sopenharmony_ci struct machine *machine) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci return dump_raw_samples(tool, event, sample, machine); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int report_raw_events(struct perf_mem *mem) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct perf_data data = { 2358c2ecf20Sopenharmony_ci .path = input_name, 2368c2ecf20Sopenharmony_ci .mode = PERF_DATA_MODE_READ, 2378c2ecf20Sopenharmony_ci .force = mem->force, 2388c2ecf20Sopenharmony_ci }; 2398c2ecf20Sopenharmony_ci int ret; 2408c2ecf20Sopenharmony_ci struct perf_session *session = perf_session__new(&data, false, 2418c2ecf20Sopenharmony_ci &mem->tool); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (IS_ERR(session)) 2448c2ecf20Sopenharmony_ci return PTR_ERR(session); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (mem->cpu_list) { 2478c2ecf20Sopenharmony_ci ret = perf_session__cpu_bitmap(session, mem->cpu_list, 2488c2ecf20Sopenharmony_ci mem->cpu_bitmap); 2498c2ecf20Sopenharmony_ci if (ret < 0) 2508c2ecf20Sopenharmony_ci goto out_delete; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = symbol__init(&session->header.env); 2548c2ecf20Sopenharmony_ci if (ret < 0) 2558c2ecf20Sopenharmony_ci goto out_delete; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (mem->phys_addr) 2588c2ecf20Sopenharmony_ci printf("# PID, TID, IP, ADDR, PHYS ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); 2598c2ecf20Sopenharmony_ci else 2608c2ecf20Sopenharmony_ci printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = perf_session__process_events(session); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciout_delete: 2658c2ecf20Sopenharmony_ci perf_session__delete(session); 2668c2ecf20Sopenharmony_ci return ret; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int report_events(int argc, const char **argv, struct perf_mem *mem) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci const char **rep_argv; 2728c2ecf20Sopenharmony_ci int ret, i = 0, j, rep_argc; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (mem->dump_raw) 2758c2ecf20Sopenharmony_ci return report_raw_events(mem); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci rep_argc = argc + 3; 2788c2ecf20Sopenharmony_ci rep_argv = calloc(rep_argc + 1, sizeof(char *)); 2798c2ecf20Sopenharmony_ci if (!rep_argv) 2808c2ecf20Sopenharmony_ci return -1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci rep_argv[i++] = "report"; 2838c2ecf20Sopenharmony_ci rep_argv[i++] = "--mem-mode"; 2848c2ecf20Sopenharmony_ci rep_argv[i++] = "-n"; /* display number of samples */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * there is no weight (cost) associated with stores, so don't print 2888c2ecf20Sopenharmony_ci * the column 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (!(mem->operation & MEM_OPERATION_LOAD)) { 2918c2ecf20Sopenharmony_ci if (mem->phys_addr) 2928c2ecf20Sopenharmony_ci rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," 2938c2ecf20Sopenharmony_ci "dso_daddr,tlb,locked,phys_daddr"; 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr," 2968c2ecf20Sopenharmony_ci "dso_daddr,tlb,locked"; 2978c2ecf20Sopenharmony_ci } else if (mem->phys_addr) 2988c2ecf20Sopenharmony_ci rep_argv[i++] = "--sort=local_weight,mem,sym,dso,symbol_daddr," 2998c2ecf20Sopenharmony_ci "dso_daddr,snoop,tlb,locked,phys_daddr"; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (j = 1; j < argc; j++, i++) 3028c2ecf20Sopenharmony_ci rep_argv[i] = argv[j]; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ret = cmd_report(i, rep_argv); 3058c2ecf20Sopenharmony_ci free(rep_argv); 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistruct mem_mode { 3108c2ecf20Sopenharmony_ci const char *name; 3118c2ecf20Sopenharmony_ci int mode; 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci#define MEM_OPT(n, m) \ 3158c2ecf20Sopenharmony_ci { .name = n, .mode = (m) } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci#define MEM_END { .name = NULL } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic const struct mem_mode mem_modes[]={ 3208c2ecf20Sopenharmony_ci MEM_OPT("load", MEM_OPERATION_LOAD), 3218c2ecf20Sopenharmony_ci MEM_OPT("store", MEM_OPERATION_STORE), 3228c2ecf20Sopenharmony_ci MEM_END 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int 3268c2ecf20Sopenharmony_ciparse_mem_ops(const struct option *opt, const char *str, int unset) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci int *mode = (int *)opt->value; 3298c2ecf20Sopenharmony_ci const struct mem_mode *m; 3308c2ecf20Sopenharmony_ci char *s, *os = NULL, *p; 3318c2ecf20Sopenharmony_ci int ret = -1; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (unset) 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* str may be NULL in case no arg is passed to -t */ 3378c2ecf20Sopenharmony_ci if (str) { 3388c2ecf20Sopenharmony_ci /* because str is read-only */ 3398c2ecf20Sopenharmony_ci s = os = strdup(str); 3408c2ecf20Sopenharmony_ci if (!s) 3418c2ecf20Sopenharmony_ci return -1; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* reset mode */ 3448c2ecf20Sopenharmony_ci *mode = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci for (;;) { 3478c2ecf20Sopenharmony_ci p = strchr(s, ','); 3488c2ecf20Sopenharmony_ci if (p) 3498c2ecf20Sopenharmony_ci *p = '\0'; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci for (m = mem_modes; m->name; m++) { 3528c2ecf20Sopenharmony_ci if (!strcasecmp(s, m->name)) 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci if (!m->name) { 3568c2ecf20Sopenharmony_ci fprintf(stderr, "unknown sampling op %s," 3578c2ecf20Sopenharmony_ci " check man page\n", s); 3588c2ecf20Sopenharmony_ci goto error; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci *mode |= m->mode; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!p) 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci s = p + 1; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci ret = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (*mode == 0) 3728c2ecf20Sopenharmony_ci *mode = MEM_OPERATION_LOAD; 3738c2ecf20Sopenharmony_cierror: 3748c2ecf20Sopenharmony_ci free(os); 3758c2ecf20Sopenharmony_ci return ret; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ciint cmd_mem(int argc, const char **argv) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct stat st; 3818c2ecf20Sopenharmony_ci struct perf_mem mem = { 3828c2ecf20Sopenharmony_ci .tool = { 3838c2ecf20Sopenharmony_ci .sample = process_sample_event, 3848c2ecf20Sopenharmony_ci .mmap = perf_event__process_mmap, 3858c2ecf20Sopenharmony_ci .mmap2 = perf_event__process_mmap2, 3868c2ecf20Sopenharmony_ci .comm = perf_event__process_comm, 3878c2ecf20Sopenharmony_ci .lost = perf_event__process_lost, 3888c2ecf20Sopenharmony_ci .fork = perf_event__process_fork, 3898c2ecf20Sopenharmony_ci .build_id = perf_event__process_build_id, 3908c2ecf20Sopenharmony_ci .namespaces = perf_event__process_namespaces, 3918c2ecf20Sopenharmony_ci .ordered_events = true, 3928c2ecf20Sopenharmony_ci }, 3938c2ecf20Sopenharmony_ci .input_name = "perf.data", 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * default to both load an store sampling 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci .operation = MEM_OPERATION_LOAD | MEM_OPERATION_STORE, 3988c2ecf20Sopenharmony_ci }; 3998c2ecf20Sopenharmony_ci const struct option mem_options[] = { 4008c2ecf20Sopenharmony_ci OPT_CALLBACK('t', "type", &mem.operation, 4018c2ecf20Sopenharmony_ci "type", "memory operations(load,store) Default load,store", 4028c2ecf20Sopenharmony_ci parse_mem_ops), 4038c2ecf20Sopenharmony_ci OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw, 4048c2ecf20Sopenharmony_ci "dump raw samples in ASCII"), 4058c2ecf20Sopenharmony_ci OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved, 4068c2ecf20Sopenharmony_ci "Only display entries resolved to a symbol"), 4078c2ecf20Sopenharmony_ci OPT_STRING('i', "input", &input_name, "file", 4088c2ecf20Sopenharmony_ci "input file name"), 4098c2ecf20Sopenharmony_ci OPT_STRING('C', "cpu", &mem.cpu_list, "cpu", 4108c2ecf20Sopenharmony_ci "list of cpus to profile"), 4118c2ecf20Sopenharmony_ci OPT_STRING_NOEMPTY('x', "field-separator", &symbol_conf.field_sep, 4128c2ecf20Sopenharmony_ci "separator", 4138c2ecf20Sopenharmony_ci "separator for columns, no spaces will be added" 4148c2ecf20Sopenharmony_ci " between columns '.' is reserved."), 4158c2ecf20Sopenharmony_ci OPT_BOOLEAN('f', "force", &mem.force, "don't complain, do it"), 4168c2ecf20Sopenharmony_ci OPT_BOOLEAN('p', "phys-data", &mem.phys_addr, "Record/Report sample physical addresses"), 4178c2ecf20Sopenharmony_ci OPT_END() 4188c2ecf20Sopenharmony_ci }; 4198c2ecf20Sopenharmony_ci const char *const mem_subcommands[] = { "record", "report", NULL }; 4208c2ecf20Sopenharmony_ci const char *mem_usage[] = { 4218c2ecf20Sopenharmony_ci NULL, 4228c2ecf20Sopenharmony_ci NULL 4238c2ecf20Sopenharmony_ci }; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (perf_mem_events__init()) { 4268c2ecf20Sopenharmony_ci pr_err("failed: memory events not supported\n"); 4278c2ecf20Sopenharmony_ci return -1; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, 4318c2ecf20Sopenharmony_ci mem_usage, PARSE_OPT_KEEP_UNKNOWN); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (!argc || !(strncmp(argv[0], "rec", 3) || mem.operation)) 4348c2ecf20Sopenharmony_ci usage_with_options(mem_usage, mem_options); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (!mem.input_name || !strlen(mem.input_name)) { 4378c2ecf20Sopenharmony_ci if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) 4388c2ecf20Sopenharmony_ci mem.input_name = "-"; 4398c2ecf20Sopenharmony_ci else 4408c2ecf20Sopenharmony_ci mem.input_name = "perf.data"; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!strncmp(argv[0], "rec", 3)) 4448c2ecf20Sopenharmony_ci return __cmd_record(argc, argv, &mem); 4458c2ecf20Sopenharmony_ci else if (!strncmp(argv[0], "rep", 3)) 4468c2ecf20Sopenharmony_ci return report_events(argc, argv, &mem); 4478c2ecf20Sopenharmony_ci else 4488c2ecf20Sopenharmony_ci usage_with_options(mem_usage, mem_options); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 452