Linux Perf
builtin-mem.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 #include <inttypes.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include "builtin.h"
7 #include "perf.h"
8 
9 #include <subcmd/parse-options.h>
10 #include "util/trace-event.h"
11 #include "util/tool.h"
12 #include "util/session.h"
13 #include "util/data.h"
14 #include "util/mem-events.h"
15 #include "util/debug.h"
16 #include "util/symbol.h"
17 
18 #define MEM_OPERATION_LOAD 0x1
19 #define MEM_OPERATION_STORE 0x2
20 
21 struct perf_mem {
22  struct perf_tool tool;
23  char const *input_name;
25  bool dump_raw;
26  bool force;
27  bool phys_addr;
28  int operation;
29  const char *cpu_list;
30  DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
31 };
32 
33 static int parse_record_events(const struct option *opt,
34  const char *str, int unset __maybe_unused)
35 {
36  struct perf_mem *mem = *(struct perf_mem **)opt->value;
37  int j;
38 
39  if (strcmp(str, "list")) {
40  if (!perf_mem_events__parse(str)) {
41  mem->operation = 0;
42  return 0;
43  }
44  exit(-1);
45  }
46 
47  for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
48  struct perf_mem_event *e = &perf_mem_events[j];
49 
50  fprintf(stderr, "%-13s%-*s%s\n",
51  e->tag,
52  verbose > 0 ? 25 : 0,
53  verbose > 0 ? perf_mem_events__name(j) : "",
54  e->supported ? ": available" : "");
55  }
56  exit(0);
57 }
58 
59 static const char * const __usage[] = {
60  "perf mem record [<options>] [<command>]",
61  "perf mem record [<options>] -- <command> [<options>]",
62  NULL
63 };
64 
65 static const char * const *record_mem_usage = __usage;
66 
67 static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
68 {
69  int rec_argc, i = 0, j;
70  const char **rec_argv;
71  int ret;
72  bool all_user = false, all_kernel = false;
73  struct option options[] = {
74  OPT_CALLBACK('e', "event", &mem, "event",
75  "event selector. use 'perf mem record -e list' to list available events",
77  OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"),
78  OPT_INCR('v', "verbose", &verbose,
79  "be more verbose (show counter open errors, etc)"),
80  OPT_BOOLEAN('U', "all-user", &all_user, "collect only user level data"),
81  OPT_BOOLEAN('K', "all-kernel", &all_kernel, "collect only kernel level data"),
82  OPT_END()
83  };
84 
85  argc = parse_options(argc, argv, options, record_mem_usage,
86  PARSE_OPT_KEEP_UNKNOWN);
87 
88  rec_argc = argc + 9; /* max number of arguments */
89  rec_argv = calloc(rec_argc + 1, sizeof(char *));
90  if (!rec_argv)
91  return -1;
92 
93  rec_argv[i++] = "record";
94 
95  if (mem->operation & MEM_OPERATION_LOAD)
97 
98  if (mem->operation & MEM_OPERATION_STORE)
100 
102  rec_argv[i++] = "-W";
103 
104  rec_argv[i++] = "-d";
105 
106  if (mem->phys_addr)
107  rec_argv[i++] = "--phys-data";
108 
109  for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
110  if (!perf_mem_events[j].record)
111  continue;
112 
113  if (!perf_mem_events[j].supported) {
114  pr_err("failed: event '%s' not supported\n",
116  free(rec_argv);
117  return -1;
118  }
119 
120  rec_argv[i++] = "-e";
121  rec_argv[i++] = perf_mem_events__name(j);
122  };
123 
124  if (all_user)
125  rec_argv[i++] = "--all-user";
126 
127  if (all_kernel)
128  rec_argv[i++] = "--all-kernel";
129 
130  for (j = 0; j < argc; j++, i++)
131  rec_argv[i] = argv[j];
132 
133  if (verbose > 0) {
134  pr_debug("calling: record ");
135 
136  while (rec_argv[j]) {
137  pr_debug("%s ", rec_argv[j]);
138  j++;
139  }
140  pr_debug("\n");
141  }
142 
143  ret = cmd_record(i, rec_argv);
144  free(rec_argv);
145  return ret;
146 }
147 
148 static int
150  union perf_event *event,
151  struct perf_sample *sample,
152  struct machine *machine)
153 {
154  struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
155  struct addr_location al;
156  const char *fmt;
157 
158  if (machine__resolve(machine, &al, sample) < 0) {
159  fprintf(stderr, "problem processing %d event, skipping it.\n",
160  event->header.type);
161  return -1;
162  }
163 
164  if (al.filtered || (mem->hide_unresolved && al.sym == NULL))
165  goto out_put;
166 
167  if (al.map != NULL)
168  al.map->dso->hit = 1;
169 
170  if (mem->phys_addr) {
171  if (symbol_conf.field_sep) {
172  fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s0x%016"PRIx64
173  "%s%"PRIu64"%s0x%"PRIx64"%s%s:%s\n";
174  } else {
175  fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
176  "%s0x%016"PRIx64"%s%5"PRIu64"%s0x%06"PRIx64
177  "%s%s:%s\n";
178  symbol_conf.field_sep = " ";
179  }
180 
181  printf(fmt,
182  sample->pid,
184  sample->tid,
186  sample->ip,
188  sample->addr,
190  sample->phys_addr,
192  sample->weight,
194  sample->data_src,
196  al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
197  al.sym ? al.sym->name : "???");
198  } else {
199  if (symbol_conf.field_sep) {
200  fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64
201  "%s0x%"PRIx64"%s%s:%s\n";
202  } else {
203  fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
204  "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n";
205  symbol_conf.field_sep = " ";
206  }
207 
208  printf(fmt,
209  sample->pid,
211  sample->tid,
213  sample->ip,
215  sample->addr,
217  sample->weight,
219  sample->data_src,
221  al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
222  al.sym ? al.sym->name : "???");
223  }
224 out_put:
225  addr_location__put(&al);
226  return 0;
227 }
228 
230  union perf_event *event,
231  struct perf_sample *sample,
232  struct perf_evsel *evsel __maybe_unused,
233  struct machine *machine)
234 {
235  return dump_raw_samples(tool, event, sample, machine);
236 }
237 
238 static int report_raw_events(struct perf_mem *mem)
239 {
240  struct perf_data data = {
241  .file = {
242  .path = input_name,
243  },
244  .mode = PERF_DATA_MODE_READ,
245  .force = mem->force,
246  };
247  int ret;
248  struct perf_session *session = perf_session__new(&data, false,
249  &mem->tool);
250 
251  if (session == NULL)
252  return -1;
253 
254  if (mem->cpu_list) {
255  ret = perf_session__cpu_bitmap(session, mem->cpu_list,
256  mem->cpu_bitmap);
257  if (ret < 0)
258  goto out_delete;
259  }
260 
261  ret = symbol__init(&session->header.env);
262  if (ret < 0)
263  goto out_delete;
264 
265  if (mem->phys_addr)
266  printf("# PID, TID, IP, ADDR, PHYS ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
267  else
268  printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
269 
270  ret = perf_session__process_events(session);
271 
272 out_delete:
273  perf_session__delete(session);
274  return ret;
275 }
276 
277 static int report_events(int argc, const char **argv, struct perf_mem *mem)
278 {
279  const char **rep_argv;
280  int ret, i = 0, j, rep_argc;
281 
282  if (mem->dump_raw)
283  return report_raw_events(mem);
284 
285  rep_argc = argc + 3;
286  rep_argv = calloc(rep_argc + 1, sizeof(char *));
287  if (!rep_argv)
288  return -1;
289 
290  rep_argv[i++] = "report";
291  rep_argv[i++] = "--mem-mode";
292  rep_argv[i++] = "-n"; /* display number of samples */
293 
294  /*
295  * there is no weight (cost) associated with stores, so don't print
296  * the column
297  */
298  if (!(mem->operation & MEM_OPERATION_LOAD)) {
299  if (mem->phys_addr)
300  rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr,"
301  "dso_daddr,tlb,locked,phys_daddr";
302  else
303  rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr,"
304  "dso_daddr,tlb,locked";
305  } else if (mem->phys_addr)
306  rep_argv[i++] = "--sort=local_weight,mem,sym,dso,symbol_daddr,"
307  "dso_daddr,snoop,tlb,locked,phys_daddr";
308 
309  for (j = 1; j < argc; j++, i++)
310  rep_argv[i] = argv[j];
311 
312  ret = cmd_report(i, rep_argv);
313  free(rep_argv);
314  return ret;
315 }
316 
317 struct mem_mode {
318  const char *name;
319  int mode;
320 };
321 
322 #define MEM_OPT(n, m) \
323  { .name = n, .mode = (m) }
324 
325 #define MEM_END { .name = NULL }
326 
327 static const struct mem_mode mem_modes[]={
328  MEM_OPT("load", MEM_OPERATION_LOAD),
329  MEM_OPT("store", MEM_OPERATION_STORE),
330  MEM_END
331 };
332 
333 static int
334 parse_mem_ops(const struct option *opt, const char *str, int unset)
335 {
336  int *mode = (int *)opt->value;
337  const struct mem_mode *m;
338  char *s, *os = NULL, *p;
339  int ret = -1;
340 
341  if (unset)
342  return 0;
343 
344  /* str may be NULL in case no arg is passed to -t */
345  if (str) {
346  /* because str is read-only */
347  s = os = strdup(str);
348  if (!s)
349  return -1;
350 
351  /* reset mode */
352  *mode = 0;
353 
354  for (;;) {
355  p = strchr(s, ',');
356  if (p)
357  *p = '\0';
358 
359  for (m = mem_modes; m->name; m++) {
360  if (!strcasecmp(s, m->name))
361  break;
362  }
363  if (!m->name) {
364  fprintf(stderr, "unknown sampling op %s,"
365  " check man page\n", s);
366  goto error;
367  }
368 
369  *mode |= m->mode;
370 
371  if (!p)
372  break;
373 
374  s = p + 1;
375  }
376  }
377  ret = 0;
378 
379  if (*mode == 0)
380  *mode = MEM_OPERATION_LOAD;
381 error:
382  free(os);
383  return ret;
384 }
385 
386 int cmd_mem(int argc, const char **argv)
387 {
388  struct stat st;
389  struct perf_mem mem = {
390  .tool = {
392  .mmap = perf_event__process_mmap,
393  .mmap2 = perf_event__process_mmap2,
394  .comm = perf_event__process_comm,
395  .lost = perf_event__process_lost,
396  .fork = perf_event__process_fork,
397  .build_id = perf_event__process_build_id,
398  .namespaces = perf_event__process_namespaces,
399  .ordered_events = true,
400  },
401  .input_name = "perf.data",
402  /*
403  * default to both load an store sampling
404  */
406  };
407  const struct option mem_options[] = {
408  OPT_CALLBACK('t', "type", &mem.operation,
409  "type", "memory operations(load,store) Default load,store",
410  parse_mem_ops),
411  OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
412  "dump raw samples in ASCII"),
413  OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
414  "Only display entries resolved to a symbol"),
415  OPT_STRING('i', "input", &input_name, "file",
416  "input file name"),
417  OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
418  "list of cpus to profile"),
419  OPT_STRING_NOEMPTY('x', "field-separator", &symbol_conf.field_sep,
420  "separator",
421  "separator for columns, no spaces will be added"
422  " between columns '.' is reserved."),
423  OPT_BOOLEAN('f', "force", &mem.force, "don't complain, do it"),
424  OPT_BOOLEAN('p', "phys-data", &mem.phys_addr, "Record/Report sample physical addresses"),
425  OPT_END()
426  };
427  const char *const mem_subcommands[] = { "record", "report", NULL };
428  const char *mem_usage[] = {
429  NULL,
430  NULL
431  };
432 
433  if (perf_mem_events__init()) {
434  pr_err("failed: memory events not supported\n");
435  return -1;
436  }
437 
438  argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
439  mem_usage, PARSE_OPT_KEEP_UNKNOWN);
440 
441  if (!argc || !(strncmp(argv[0], "rec", 3) || mem.operation))
442  usage_with_options(mem_usage, mem_options);
443 
444  if (!mem.input_name || !strlen(mem.input_name)) {
445  if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
446  mem.input_name = "-";
447  else
448  mem.input_name = "perf.data";
449  }
450 
451  if (!strncmp(argv[0], "rec", 3))
452  return __cmd_record(argc, argv, &mem);
453  else if (!strncmp(argv[0], "rep", 3))
454  return report_events(argc, argv, &mem);
455  else
456  usage_with_options(mem_usage, mem_options);
457 
458  return 0;
459 }
int cmd_mem(int argc, const char **argv)
Definition: builtin-mem.c:386
int cmd_report(int argc, const char **argv)
bool hide_unresolved
Definition: builtin-mem.c:24
static const struct mem_mode mem_modes[]
Definition: builtin-mem.c:327
u64 weight
Definition: event.h:199
static int parse_mem_ops(const struct option *opt, const char *str, int unset)
Definition: builtin-mem.c:334
int machine__resolve(struct machine *machine, struct addr_location *al, struct perf_sample *sample)
Definition: event.c:1601
u64 data_src
Definition: event.h:203
int cmd_record(int argc, const char **argv)
static int dump_raw_samples(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: builtin-mem.c:149
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1385
u64 addr
Definition: event.h:195
static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
Definition: builtin-mem.c:67
struct perf_data_file file
Definition: data.h:18
int perf_mem_events__init(void)
Definition: mem-events.c:82
bool phys_addr
Definition: builtin-mem.c:27
struct perf_env env
Definition: header.h:82
const char * long_name
Definition: dso.h:173
int perf_event__process_comm(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1273
int perf_event__process_fork(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1408
u8 hit
Definition: dso.h:162
u64 phys_addr
Definition: event.h:204
int perf_event__process_build_id(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_session *session)
Definition: header.c:3922
unsigned int perf_mem_events__loads_ldlat
Definition: mem-events.c:16
#define MEM_END
Definition: builtin-mem.c:325
u64 ip
Definition: event.h:192
#define pr_err(fmt,...)
Definition: json.h:21
void perf_session__delete(struct perf_session *session)
Definition: session.c:187
const char * name
Definition: builtin-mem.c:318
if(!yyg->yy_init)
static const char *const * record_mem_usage
Definition: builtin-mem.c:65
char * perf_mem_events__name(int i)
Definition: mem-events.c:31
void addr_location__put(struct addr_location *al)
Definition: event.c:1661
struct map * map
Definition: symbol.h:210
#define mem
#define pr_debug(fmt,...)
Definition: json.h:27
Definition: tool.h:44
const char * fmt
Definition: dso.c:193
static struct perf_session * session
Definition: builtin-lock.c:34
static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __maybe_unused, struct machine *machine)
Definition: builtin-mem.c:229
struct dso * dso
Definition: map.h:45
u32 pid
Definition: event.h:193
u32 tid
Definition: event.h:193
static int str(yyscan_t scanner, int token)
char name[0]
Definition: symbol.h:66
struct symbol * sym
Definition: symbol.h:211
#define event
const char * cpu_list
Definition: builtin-mem.c:29
struct perf_tool tool
Definition: builtin-mem.c:22
const char * field_sep
Definition: symbol.h:123
static int report_events(int argc, const char **argv, struct perf_mem *mem)
Definition: builtin-mem.c:277
Definition: data.h:17
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS)
struct perf_event_header header
Definition: event.h:624
int operation
Definition: builtin-mem.c:28
#define MEM_OPERATION_LOAD
Definition: builtin-mem.c:18
static int report_raw_events(struct perf_mem *mem)
Definition: builtin-mem.c:238
struct perf_session * perf_session__new(struct perf_data *data, bool repipe, struct perf_tool *tool)
Definition: session.c:116
int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1393
int perf_session__process_events(struct perf_session *session)
Definition: session.c:1945
#define MEM_OPERATION_STORE
Definition: builtin-mem.c:19
char const * input_name
Definition: builtin-mem.c:23
static int parse_record_events(const struct option *opt, const char *str, int unset __maybe_unused)
Definition: builtin-mem.c:33
static const char *const __usage[]
Definition: builtin-mem.c:59
int perf_mem_events__parse(const char *str)
Definition: mem-events.c:46
struct perf_header header
Definition: session.h:23
int symbol__init(struct perf_env *env)
Definition: symbol.c:2112
void free(void *)
const char * tag
Definition: mem-events.h:14
#define MAX_NR_CPUS
Definition: perf.h:27
int perf_event__process_lost(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1289
int verbose
Definition: jevents.c:53
int perf_session__cpu_bitmap(struct perf_session *session, const char *cpu_list, unsigned long *cpu_bitmap)
Definition: session.c:2051
int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine)
Definition: event.c:1281
bool force
Definition: builtin-mem.c:26
#define MEM_OPT(n, m)
Definition: builtin-mem.c:322
bool dump_raw
Definition: builtin-mem.c:25
struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]
Definition: mem-events.c:20
const char * path
Definition: data.h:13
event_sample sample
Definition: tool.h:45