Linux Perf
perf.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * perf.c
4  *
5  * Performance analysis utility.
6  *
7  * This is the main hub from which the sub-commands (perf stat,
8  * perf top, perf record, perf report, etc.) are started.
9  */
10 #include "builtin.h"
11 
12 #include "util/env.h"
13 #include <subcmd/exec-cmd.h>
14 #include "util/config.h"
15 #include <subcmd/run-command.h>
16 #include "util/parse-events.h"
17 #include <subcmd/parse-options.h>
18 #include "util/bpf-loader.h"
19 #include "util/debug.h"
20 #include "util/event.h"
21 #include <api/fs/fs.h>
22 #include <api/fs/tracing_path.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <linux/kernel.h>
32 
33 const char perf_usage_string[] =
34  "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
35 
36 const char perf_more_info_string[] =
37  "See 'perf help COMMAND' for more information on a specific command.";
38 
39 static int use_pager = -1;
40 const char *input_name;
41 
42 struct cmd_struct {
43  const char *cmd;
44  int (*fn)(int, const char **);
45  int option;
46 };
47 
48 static struct cmd_struct commands[] = {
49  { "buildid-cache", cmd_buildid_cache, 0 },
50  { "buildid-list", cmd_buildid_list, 0 },
51  { "config", cmd_config, 0 },
52  { "c2c", cmd_c2c, 0 },
53  { "diff", cmd_diff, 0 },
54  { "evlist", cmd_evlist, 0 },
55  { "help", cmd_help, 0 },
56  { "kallsyms", cmd_kallsyms, 0 },
57  { "list", cmd_list, 0 },
58  { "record", cmd_record, 0 },
59  { "report", cmd_report, 0 },
60  { "bench", cmd_bench, 0 },
61  { "stat", cmd_stat, 0 },
62  { "timechart", cmd_timechart, 0 },
63  { "top", cmd_top, 0 },
64  { "annotate", cmd_annotate, 0 },
65  { "version", cmd_version, 0 },
66  { "script", cmd_script, 0 },
67  { "sched", cmd_sched, 0 },
68 #ifdef HAVE_LIBELF_SUPPORT
69  { "probe", cmd_probe, 0 },
70 #endif
71  { "kmem", cmd_kmem, 0 },
72  { "lock", cmd_lock, 0 },
73  { "kvm", cmd_kvm, 0 },
74  { "test", cmd_test, 0 },
75 #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
76  { "trace", cmd_trace, 0 },
77 #endif
78  { "inject", cmd_inject, 0 },
79  { "mem", cmd_mem, 0 },
80  { "data", cmd_data, 0 },
81  { "ftrace", cmd_ftrace, 0 },
82 };
83 
84 struct pager_config {
85  const char *cmd;
86  int val;
87 };
88 
89 static int pager_command_config(const char *var, const char *value, void *data)
90 {
91  struct pager_config *c = data;
92  if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd))
93  c->val = perf_config_bool(var, value);
94  return 0;
95 }
96 
97 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
98 static int check_pager_config(const char *cmd)
99 {
100  int err;
101  struct pager_config c;
102  c.cmd = cmd;
103  c.val = -1;
105  return err ?: c.val;
106 }
107 
108 static int browser_command_config(const char *var, const char *value, void *data)
109 {
110  struct pager_config *c = data;
111  if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd))
112  c->val = perf_config_bool(var, value);
113  if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd))
114  c->val = perf_config_bool(var, value) ? 2 : 0;
115  return 0;
116 }
117 
118 /*
119  * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
120  * and -1 for "not specified"
121  */
122 static int check_browser_config(const char *cmd)
123 {
124  int err;
125  struct pager_config c;
126  c.cmd = cmd;
127  c.val = -1;
129  return err ?: c.val;
130 }
131 
132 static void commit_pager_choice(void)
133 {
134  switch (use_pager) {
135  case 0:
136  setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
137  break;
138  case 1:
139  /* setup_pager(); */
140  break;
141  default:
142  break;
143  }
144 }
145 
146 struct option options[] = {
147  OPT_ARGUMENT("help", "help"),
148  OPT_ARGUMENT("version", "version"),
149  OPT_ARGUMENT("exec-path", "exec-path"),
150  OPT_ARGUMENT("html-path", "html-path"),
151  OPT_ARGUMENT("paginate", "paginate"),
152  OPT_ARGUMENT("no-pager", "no-pager"),
153  OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
154  OPT_ARGUMENT("buildid-dir", "buildid-dir"),
155  OPT_ARGUMENT("list-cmds", "list-cmds"),
156  OPT_ARGUMENT("list-opts", "list-opts"),
157  OPT_ARGUMENT("debug", "debug"),
158  OPT_END()
159 };
160 
161 static int handle_options(const char ***argv, int *argc, int *envchanged)
162 {
163  int handled = 0;
164 
165  while (*argc > 0) {
166  const char *cmd = (*argv)[0];
167  if (cmd[0] != '-')
168  break;
169 
170  /*
171  * For legacy reasons, the "version" and "help"
172  * commands can be written with "--" prepended
173  * to make them look like flags.
174  */
175  if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
176  break;
177 
178  /*
179  * Shortcut for '-h' and '-v' options to invoke help
180  * and version command.
181  */
182  if (!strcmp(cmd, "-h")) {
183  (*argv)[0] = "--help";
184  break;
185  }
186 
187  if (!strcmp(cmd, "-v")) {
188  (*argv)[0] = "--version";
189  break;
190  }
191 
192  if (!strcmp(cmd, "-vv")) {
193  (*argv)[0] = "version";
194  version_verbose = 1;
195  break;
196  }
197 
198  /*
199  * Check remaining flags.
200  */
201  if (strstarts(cmd, CMD_EXEC_PATH)) {
202  cmd += strlen(CMD_EXEC_PATH);
203  if (*cmd == '=')
204  set_argv_exec_path(cmd + 1);
205  else {
206  puts(get_argv_exec_path());
207  exit(0);
208  }
209  } else if (!strcmp(cmd, "--html-path")) {
210  puts(system_path(PERF_HTML_PATH));
211  exit(0);
212  } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
213  use_pager = 1;
214  } else if (!strcmp(cmd, "--no-pager")) {
215  use_pager = 0;
216  if (envchanged)
217  *envchanged = 1;
218  } else if (!strcmp(cmd, "--debugfs-dir")) {
219  if (*argc < 2) {
220  fprintf(stderr, "No directory given for --debugfs-dir.\n");
222  }
223  tracing_path_set((*argv)[1]);
224  if (envchanged)
225  *envchanged = 1;
226  (*argv)++;
227  (*argc)--;
228  } else if (!strcmp(cmd, "--buildid-dir")) {
229  if (*argc < 2) {
230  fprintf(stderr, "No directory given for --buildid-dir.\n");
232  }
233  set_buildid_dir((*argv)[1]);
234  if (envchanged)
235  *envchanged = 1;
236  (*argv)++;
237  (*argc)--;
238  } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
239  tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
240  fprintf(stderr, "dir: %s\n", tracing_path_mount());
241  if (envchanged)
242  *envchanged = 1;
243  } else if (!strcmp(cmd, "--list-cmds")) {
244  unsigned int i;
245 
246  for (i = 0; i < ARRAY_SIZE(commands); i++) {
247  struct cmd_struct *p = commands+i;
248  printf("%s ", p->cmd);
249  }
250  putchar('\n');
251  exit(0);
252  } else if (!strcmp(cmd, "--list-opts")) {
253  unsigned int i;
254 
255  for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
256  struct option *p = options+i;
257  printf("--%s ", p->long_name);
258  }
259  putchar('\n');
260  exit(0);
261  } else if (!strcmp(cmd, "--debug")) {
262  if (*argc < 2) {
263  fprintf(stderr, "No variable specified for --debug.\n");
265  }
266  if (perf_debug_option((*argv)[1]))
268 
269  (*argv)++;
270  (*argc)--;
271  } else {
272  fprintf(stderr, "Unknown option: %s\n", cmd);
274  }
275 
276  (*argv)++;
277  (*argc)--;
278  handled++;
279  }
280  return handled;
281 }
282 
283 #define RUN_SETUP (1<<0)
284 #define USE_PAGER (1<<1)
285 
286 static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
287 {
288  int status;
289  struct stat st;
290  char sbuf[STRERR_BUFSIZE];
291 
292  if (use_browser == -1)
294 
295  if (use_pager == -1 && p->option & RUN_SETUP)
297  if (use_pager == -1 && p->option & USE_PAGER)
298  use_pager = 1;
300 
301  perf_env__set_cmdline(&perf_env, argc, argv);
302  status = p->fn(argc, argv);
304  exit_browser(status);
306  bpf__clear();
307 
308  if (status)
309  return status & 0xff;
310 
311  /* Somebody closed stdout? */
312  if (fstat(fileno(stdout), &st))
313  return 0;
314  /* Ignore write errors for pipes and sockets.. */
315  if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
316  return 0;
317 
318  status = 1;
319  /* Check for ENOSPC and EIO errors.. */
320  if (fflush(stdout)) {
321  fprintf(stderr, "write failure on standard output: %s",
322  str_error_r(errno, sbuf, sizeof(sbuf)));
323  goto out;
324  }
325  if (ferror(stdout)) {
326  fprintf(stderr, "unknown write failure on standard output");
327  goto out;
328  }
329  if (fclose(stdout)) {
330  fprintf(stderr, "close failed on standard output: %s",
331  str_error_r(errno, sbuf, sizeof(sbuf)));
332  goto out;
333  }
334  status = 0;
335 out:
336  return status;
337 }
338 
339 static void handle_internal_command(int argc, const char **argv)
340 {
341  const char *cmd = argv[0];
342  unsigned int i;
343 
344  /* Turn "perf cmd --help" into "perf help cmd" */
345  if (argc > 1 && !strcmp(argv[1], "--help")) {
346  argv[1] = argv[0];
347  argv[0] = cmd = "help";
348  }
349 
350  for (i = 0; i < ARRAY_SIZE(commands); i++) {
351  struct cmd_struct *p = commands+i;
352  if (strcmp(p->cmd, cmd))
353  continue;
354  exit(run_builtin(p, argc, argv));
355  }
356 }
357 
358 static void execv_dashed_external(const char **argv)
359 {
360  char *cmd;
361  const char *tmp;
362  int status;
363 
364  if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
365  goto do_die;
366 
367  /*
368  * argv[0] must be the perf command, but the argv array
369  * belongs to the caller, and may be reused in
370  * subsequent loop iterations. Save argv[0] and
371  * restore it on error.
372  */
373  tmp = argv[0];
374  argv[0] = cmd;
375 
376  /*
377  * if we fail because the command is not found, it is
378  * OK to return. Otherwise, we just pass along the status code.
379  */
380  status = run_command_v_opt(argv, 0);
381  if (status != -ERR_RUN_COMMAND_EXEC) {
382  if (IS_RUN_COMMAND_ERR(status)) {
383 do_die:
384  pr_err("FATAL: unable to run '%s'", argv[0]);
385  status = -128;
386  }
387  exit(-status);
388  }
389  errno = ENOENT; /* as if we called execvp */
390 
391  argv[0] = tmp;
392  zfree(&cmd);
393 }
394 
395 static int run_argv(int *argcp, const char ***argv)
396 {
397  /* See if it's an internal command */
398  handle_internal_command(*argcp, *argv);
399 
400  /* .. then try the external ones */
401  execv_dashed_external(*argv);
402  return 0;
403 }
404 
405 static void pthread__block_sigwinch(void)
406 {
407  sigset_t set;
408 
409  sigemptyset(&set);
410  sigaddset(&set, SIGWINCH);
411  pthread_sigmask(SIG_BLOCK, &set, NULL);
412 }
413 
415 {
416  sigset_t set;
417 
418  sigemptyset(&set);
419  sigaddset(&set, SIGWINCH);
420  pthread_sigmask(SIG_UNBLOCK, &set, NULL);
421 }
422 
423 int main(int argc, const char **argv)
424 {
425  int err;
426  const char *cmd;
427  char sbuf[STRERR_BUFSIZE];
428 
429  /* libsubcmd init */
430  exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
431  pager_init(PERF_PAGER_ENVIRONMENT);
432 
433  /* The page_size is placed in util object. */
434  page_size = sysconf(_SC_PAGE_SIZE);
435 
436  cmd = extract_argv0_path(argv[0]);
437  if (!cmd)
438  cmd = "perf-help";
439 
440  srandom(time(NULL));
441 
442  err = perf_config(perf_default_config, NULL);
443  if (err)
444  return err;
445  set_buildid_dir(NULL);
446 
447  /*
448  * "perf-xxxx" is the same as "perf xxxx", but we obviously:
449  *
450  * - cannot take flags in between the "perf" and the "xxxx".
451  * - cannot execute it externally (since it would just do
452  * the same thing over again)
453  *
454  * So we just directly call the internal command handler. If that one
455  * fails to handle this, then maybe we just run a renamed perf binary
456  * that contains a dash in its name. To handle this scenario, we just
457  * fall through and ignore the "xxxx" part of the command string.
458  */
459  if (strstarts(cmd, "perf-")) {
460  cmd += 5;
461  argv[0] = cmd;
462  handle_internal_command(argc, argv);
463  /*
464  * If the command is handled, the above function does not
465  * return undo changes and fall through in such a case.
466  */
467  cmd -= 5;
468  argv[0] = cmd;
469  }
470  if (strstarts(cmd, "trace")) {
471 #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
472  setup_path();
473  argv[0] = "trace";
474  return cmd_trace(argc, argv);
475 #else
476  fprintf(stderr,
477  "trace command not available: missing audit-libs devel package at build time.\n");
478  goto out;
479 #endif
480  }
481  /* Look for flags.. */
482  argv++;
483  argc--;
484  handle_options(&argv, &argc, NULL);
486 
487  if (argc > 0) {
488  if (strstarts(argv[0], "--"))
489  argv[0] += 2;
490  } else {
491  /* The user didn't specify a command; give them help */
492  printf("\n usage: %s\n\n", perf_usage_string);
494  printf("\n %s\n\n", perf_more_info_string);
495  goto out;
496  }
497  cmd = argv[0];
498 
499  test_attr__init();
500 
501  /*
502  * We use PATH to find perf commands, but we prepend some higher
503  * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
504  * environment, and the $(perfexecdir) from the Makefile at build
505  * time.
506  */
507  setup_path();
508  /*
509  * Block SIGWINCH notifications so that the thread that wants it can
510  * unblock and get syscalls like select interrupted instead of waiting
511  * forever while the signal goes to some other non interested thread.
512  */
514 
516 
517  while (1) {
518  static int done_help;
519 
520  run_argv(&argc, &argv);
521 
522  if (errno != ENOENT)
523  break;
524 
525  if (!done_help) {
526  cmd = argv[0] = help_unknown_cmd(cmd);
527  done_help = 1;
528  } else
529  break;
530  }
531 
532  fprintf(stderr, "Failed to run command '%s': %s\n",
533  cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
534 out:
535  return 1;
536 }
int cmd_mem(int argc, const char **argv)
Definition: builtin-mem.c:386
int cmd_report(int argc, const char **argv)
int cmd_kvm(int argc, const char **argv)
Definition: builtin-kvm.c:1572
void perf_debug_setup(void)
Definition: debug.c:253
int value
Definition: python.c:1143
Definition: env.h:36
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
Definition: env.c:41
int cmd_buildid_cache(int argc, const char **argv)
int cmd_record(int argc, const char **argv)
int perf_default_config(const char *var, const char *value, void *dummy __maybe_unused)
Definition: config.c:435
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
Definition: perf.c:286
static int handle_options(const char ***argv, int *argc, int *envchanged)
Definition: perf.c:161
unsigned int page_size
Definition: util.c:40
Definition: genelf.c:61
static int check_browser_config(const char *cmd)
Definition: perf.c:122
static int browser_command_config(const char *var, const char *value, void *data)
Definition: perf.c:108
dictionary data
Definition: stat-cpi.py:4
int int err
Definition: 5sec.c:44
int perf_config_bool(const char *name, const char *value)
Definition: config.c:389
#define CMD_DEBUGFS_DIR
Definition: cache.h:13
int cmd_ftrace(int argc, const char **argv)
void bpf__clear(void)
Definition: bpf-loader.c:120
int cmd_list(int argc, const char **argv)
Definition: builtin-list.c:25
void set_buildid_dir(const char *dir)
Definition: config.c:811
int perf_debug_option(const char *str)
Definition: debug.c:186
#define RUN_SETUP
Definition: perf.c:283
#define pr_err(fmt,...)
Definition: json.h:21
int cmd_script(int argc, const char **argv)
int use_browser
Definition: setup.c:12
static int pager_command_config(const char *var, const char *value, void *data)
Definition: perf.c:89
int cmd_timechart(int argc, const char **argv)
const char * cmd
Definition: perf.c:43
int cmd_c2c(int argc, const char **argv)
Definition: builtin-c2c.c:2955
int cmd_kmem(int argc, const char **argv)
void perf_env__exit(struct perf_env *env)
Definition: env.c:11
int cmd_test(int argc, const char **argv)
Definition: builtin-test.c:673
static void commit_pager_choice(void)
Definition: perf.c:132
const char perf_more_info_string[]
Definition: perf.c:36
void perf_config__exit(void)
Definition: config.c:746
void pthread__unblock_sigwinch(void)
Definition: perf.c:414
static void pthread__block_sigwinch(void)
Definition: perf.c:405
const char * input_name
Definition: perf.c:40
int cmd_sched(int argc, const char **argv)
#define EXEC_PATH_ENVIRONMENT
Definition: cache.h:15
void list_common_cmds_help(void)
Definition: builtin-help.c:295
#define USE_PAGER
Definition: perf.c:284
int val
Definition: perf.c:86
const char * cmd
Definition: perf.c:85
int cmd_trace(int argc, const char **argv)
int cmd_lock(int argc, const char **argv)
Definition: builtin-lock.c:955
#define zfree(ptr)
Definition: util.h:25
void test_attr__init(void)
Definition: attr.c:42
const char perf_usage_string[]
Definition: perf.c:33
int cmd_version(int argc, const char **argv)
void exit_browser(bool wait_for_ok)
Definition: setup.c:106
static int check_pager_config(const char *cmd)
Definition: perf.c:98
int version_verbose
static int run_argv(int *argcp, const char ***argv)
Definition: perf.c:395
int perf_config(config_fn_t fn, void *data)
Definition: config.c:718
#define CMD_EXEC_PATH
Definition: cache.h:12
int cmd_inject(int argc, const char **argv)
static void execv_dashed_external(const char **argv)
Definition: perf.c:358
int cmd_evlist(int argc, const char **argv)
#define STRERR_BUFSIZE
Definition: debug.h:43
int cmd_stat(int argc, const char **argv)
static int use_pager
Definition: perf.c:39
int cmd_help(int argc, const char **argv)
Definition: builtin-help.c:422
int cmd_top(int argc, const char **argv)
Definition: builtin-top.c:1245
int option
Definition: perf.c:45
const char * help_unknown_cmd(const char *cmd)
int cmd_diff(int argc, const char **argv)
int cmd_probe(int argc, const char **argv)
int cmd_kallsyms(int argc, const char **argv)
int main(int argc, const char **argv)
Definition: perf.c:423
#define PERF_PAGER_ENVIRONMENT
Definition: cache.h:18
int cmd_config(int argc, const char **argv)
int cmd_data(int argc, const char **argv)
Definition: builtin-data.c:101
int cmd_annotate(int argc, const char **argv)
int cmd_buildid_list(int argc, const char **argv)
int cmd_bench(int argc, const char **argv)
static struct cmd_struct commands[]
Definition: perf.c:48
int(* fn)(int, const char **)
Definition: perf.c:44
static void handle_internal_command(int argc, const char **argv)
Definition: perf.c:339