1 /* 2 * perf.c 3 * 4 * Performance analysis utility. 5 * 6 * This is the main hub from which the sub-commands (perf stat, 7 * perf top, perf record, perf report, etc.) are started. 8 */ 9 #include "builtin.h" 10 11 #include "util/exec_cmd.h" 12 #include "util/cache.h" 13 #include "util/quote.h" 14 #include "util/run-command.h" 15 16 const char perf_usage_string[] = 17 "perf [--version] [--help] COMMAND [ARGS]"; 18 19 const char perf_more_info_string[] = 20 "See 'perf help COMMAND' for more information on a specific command."; 21 22 static int use_pager = -1; 23 struct pager_config { 24 const char *cmd; 25 int val; 26 }; 27 28 static int pager_command_config(const char *var, const char *value, void *data) 29 { 30 struct pager_config *c = data; 31 if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) 32 c->val = perf_config_bool(var, value); 33 return 0; 34 } 35 36 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ 37 int check_pager_config(const char *cmd) 38 { 39 struct pager_config c; 40 c.cmd = cmd; 41 c.val = -1; 42 perf_config(pager_command_config, &c); 43 return c.val; 44 } 45 46 static void commit_pager_choice(void) { 47 switch (use_pager) { 48 case 0: 49 setenv("PERF_PAGER", "cat", 1); 50 break; 51 case 1: 52 /* setup_pager(); */ 53 break; 54 default: 55 break; 56 } 57 } 58 59 static int handle_options(const char*** argv, int* argc, int* envchanged) 60 { 61 int handled = 0; 62 63 while (*argc > 0) { 64 const char *cmd = (*argv)[0]; 65 if (cmd[0] != '-') 66 break; 67 68 /* 69 * For legacy reasons, the "version" and "help" 70 * commands can be written with "--" prepended 71 * to make them look like flags. 72 */ 73 if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version")) 74 break; 75 76 /* 77 * Check remaining flags. 78 */ 79 if (!prefixcmp(cmd, "--exec-path")) { 80 cmd += 11; 81 if (*cmd == '=') 82 perf_set_argv_exec_path(cmd + 1); 83 else { 84 puts(perf_exec_path()); 85 exit(0); 86 } 87 } else if (!strcmp(cmd, "--html-path")) { 88 puts(system_path(PERF_HTML_PATH)); 89 exit(0); 90 } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { 91 use_pager = 1; 92 } else if (!strcmp(cmd, "--no-pager")) { 93 use_pager = 0; 94 if (envchanged) 95 *envchanged = 1; 96 } else if (!strcmp(cmd, "--perf-dir")) { 97 if (*argc < 2) { 98 fprintf(stderr, "No directory given for --perf-dir.\n" ); 99 usage(perf_usage_string); 100 } 101 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); 102 if (envchanged) 103 *envchanged = 1; 104 (*argv)++; 105 (*argc)--; 106 handled++; 107 } else if (!prefixcmp(cmd, "--perf-dir=")) { 108 setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1); 109 if (envchanged) 110 *envchanged = 1; 111 } else if (!strcmp(cmd, "--work-tree")) { 112 if (*argc < 2) { 113 fprintf(stderr, "No directory given for --work-tree.\n" ); 114 usage(perf_usage_string); 115 } 116 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); 117 if (envchanged) 118 *envchanged = 1; 119 (*argv)++; 120 (*argc)--; 121 } else if (!prefixcmp(cmd, "--work-tree=")) { 122 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 123 if (envchanged) 124 *envchanged = 1; 125 } else { 126 fprintf(stderr, "Unknown option: %s\n", cmd); 127 usage(perf_usage_string); 128 } 129 130 (*argv)++; 131 (*argc)--; 132 handled++; 133 } 134 return handled; 135 } 136 137 static int handle_alias(int *argcp, const char ***argv) 138 { 139 int envchanged = 0, ret = 0, saved_errno = errno; 140 int count, option_count; 141 const char** new_argv; 142 const char *alias_command; 143 char *alias_string; 144 145 alias_command = (*argv)[0]; 146 alias_string = alias_lookup(alias_command); 147 if (alias_string) { 148 if (alias_string[0] == '!') { 149 if (*argcp > 1) { 150 struct strbuf buf; 151 152 strbuf_init(&buf, PATH_MAX); 153 strbuf_addstr(&buf, alias_string); 154 sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); 155 free(alias_string); 156 alias_string = buf.buf; 157 } 158 ret = system(alias_string + 1); 159 if (ret >= 0 && WIFEXITED(ret) && 160 WEXITSTATUS(ret) != 127) 161 exit(WEXITSTATUS(ret)); 162 die("Failed to run '%s' when expanding alias '%s'", 163 alias_string + 1, alias_command); 164 } 165 count = split_cmdline(alias_string, &new_argv); 166 if (count < 0) 167 die("Bad alias.%s string", alias_command); 168 option_count = handle_options(&new_argv, &count, &envchanged); 169 if (envchanged) 170 die("alias '%s' changes environment variables\n" 171 "You can use '!perf' in the alias to do this.", 172 alias_command); 173 memmove(new_argv - option_count, new_argv, 174 count * sizeof(char *)); 175 new_argv -= option_count; 176 177 if (count < 1) 178 die("empty alias for %s", alias_command); 179 180 if (!strcmp(alias_command, new_argv[0])) 181 die("recursive alias: %s", alias_command); 182 183 new_argv = realloc(new_argv, sizeof(char*) * 184 (count + *argcp + 1)); 185 /* insert after command name */ 186 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); 187 new_argv[count+*argcp] = NULL; 188 189 *argv = new_argv; 190 *argcp += count - 1; 191 192 ret = 1; 193 } 194 195 errno = saved_errno; 196 197 return ret; 198 } 199 200 const char perf_version_string[] = PERF_VERSION; 201 202 #define RUN_SETUP (1<<0) 203 #define USE_PAGER (1<<1) 204 /* 205 * require working tree to be present -- anything uses this needs 206 * RUN_SETUP for reading from the configuration file. 207 */ 208 #define NEED_WORK_TREE (1<<2) 209 210 struct cmd_struct { 211 const char *cmd; 212 int (*fn)(int, const char **, const char *); 213 int option; 214 }; 215 216 static int run_builtin(struct cmd_struct *p, int argc, const char **argv) 217 { 218 int status; 219 struct stat st; 220 const char *prefix; 221 222 prefix = NULL; 223 if (p->option & RUN_SETUP) 224 prefix = NULL; /* setup_perf_directory(); */ 225 226 if (use_pager == -1 && p->option & RUN_SETUP) 227 use_pager = check_pager_config(p->cmd); 228 if (use_pager == -1 && p->option & USE_PAGER) 229 use_pager = 1; 230 commit_pager_choice(); 231 232 if (p->option & NEED_WORK_TREE) 233 /* setup_work_tree() */; 234 235 status = p->fn(argc, argv, prefix); 236 if (status) 237 return status & 0xff; 238 239 /* Somebody closed stdout? */ 240 if (fstat(fileno(stdout), &st)) 241 return 0; 242 /* Ignore write errors for pipes and sockets.. */ 243 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) 244 return 0; 245 246 /* Check for ENOSPC and EIO errors.. */ 247 if (fflush(stdout)) 248 die("write failure on standard output: %s", strerror(errno)); 249 if (ferror(stdout)) 250 die("unknown write failure on standard output"); 251 if (fclose(stdout)) 252 die("close failed on standard output: %s", strerror(errno)); 253 return 0; 254 } 255 256 static void handle_internal_command(int argc, const char **argv) 257 { 258 const char *cmd = argv[0]; 259 static struct cmd_struct commands[] = { 260 { "help", cmd_help, 0 }, 261 { "list", cmd_list, 0 }, 262 { "record", cmd_record, 0 }, 263 { "report", cmd_report, 0 }, 264 { "stat", cmd_stat, 0 }, 265 { "top", cmd_top, 0 }, 266 { "annotate", cmd_annotate, 0 }, 267 { "version", cmd_version, 0 }, 268 }; 269 int i; 270 static const char ext[] = STRIP_EXTENSION; 271 272 if (sizeof(ext) > 1) { 273 i = strlen(argv[0]) - strlen(ext); 274 if (i > 0 && !strcmp(argv[0] + i, ext)) { 275 char *argv0 = strdup(argv[0]); 276 argv[0] = cmd = argv0; 277 argv0[i] = '\0'; 278 } 279 } 280 281 /* Turn "perf cmd --help" into "perf help cmd" */ 282 if (argc > 1 && !strcmp(argv[1], "--help")) { 283 argv[1] = argv[0]; 284 argv[0] = cmd = "help"; 285 } 286 287 for (i = 0; i < ARRAY_SIZE(commands); i++) { 288 struct cmd_struct *p = commands+i; 289 if (strcmp(p->cmd, cmd)) 290 continue; 291 exit(run_builtin(p, argc, argv)); 292 } 293 } 294 295 static void execv_dashed_external(const char **argv) 296 { 297 struct strbuf cmd = STRBUF_INIT; 298 const char *tmp; 299 int status; 300 301 strbuf_addf(&cmd, "perf-%s", argv[0]); 302 303 /* 304 * argv[0] must be the perf command, but the argv array 305 * belongs to the caller, and may be reused in 306 * subsequent loop iterations. Save argv[0] and 307 * restore it on error. 308 */ 309 tmp = argv[0]; 310 argv[0] = cmd.buf; 311 312 /* 313 * if we fail because the command is not found, it is 314 * OK to return. Otherwise, we just pass along the status code. 315 */ 316 status = run_command_v_opt(argv, 0); 317 if (status != -ERR_RUN_COMMAND_EXEC) { 318 if (IS_RUN_COMMAND_ERR(status)) 319 die("unable to run '%s'", argv[0]); 320 exit(-status); 321 } 322 errno = ENOENT; /* as if we called execvp */ 323 324 argv[0] = tmp; 325 326 strbuf_release(&cmd); 327 } 328 329 static int run_argv(int *argcp, const char ***argv) 330 { 331 int done_alias = 0; 332 333 while (1) { 334 /* See if it's an internal command */ 335 handle_internal_command(*argcp, *argv); 336 337 /* .. then try the external ones */ 338 execv_dashed_external(*argv); 339 340 /* It could be an alias -- this works around the insanity 341 * of overriding "perf log" with "perf show" by having 342 * alias.log = show 343 */ 344 if (done_alias || !handle_alias(argcp, argv)) 345 break; 346 done_alias = 1; 347 } 348 349 return done_alias; 350 } 351 352 353 int main(int argc, const char **argv) 354 { 355 const char *cmd; 356 357 cmd = perf_extract_argv0_path(argv[0]); 358 if (!cmd) 359 cmd = "perf-help"; 360 361 /* 362 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 363 * 364 * - cannot take flags in between the "perf" and the "xxxx". 365 * - cannot execute it externally (since it would just do 366 * the same thing over again) 367 * 368 * So we just directly call the internal command handler, and 369 * die if that one cannot handle it. 370 */ 371 if (!prefixcmp(cmd, "perf-")) { 372 cmd += 5; 373 argv[0] = cmd; 374 handle_internal_command(argc, argv); 375 die("cannot handle %s internally", cmd); 376 } 377 378 /* Look for flags.. */ 379 argv++; 380 argc--; 381 handle_options(&argv, &argc, NULL); 382 commit_pager_choice(); 383 if (argc > 0) { 384 if (!prefixcmp(argv[0], "--")) 385 argv[0] += 2; 386 } else { 387 /* The user didn't specify a command; give them help */ 388 printf("\n usage: %s\n\n", perf_usage_string); 389 list_common_cmds_help(); 390 printf("\n %s\n\n", perf_more_info_string); 391 exit(1); 392 } 393 cmd = argv[0]; 394 395 /* 396 * We use PATH to find perf commands, but we prepend some higher 397 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 398 * environment, and the $(perfexecdir) from the Makefile at build 399 * time. 400 */ 401 setup_path(); 402 403 while (1) { 404 static int done_help = 0; 405 static int was_alias = 0; 406 407 was_alias = run_argv(&argc, &argv); 408 if (errno != ENOENT) 409 break; 410 411 if (was_alias) { 412 fprintf(stderr, "Expansion of alias '%s' failed; " 413 "'%s' is not a perf-command\n", 414 cmd, argv[0]); 415 exit(1); 416 } 417 if (!done_help) { 418 cmd = argv[0] = help_unknown_cmd(cmd); 419 done_help = 1; 420 } else 421 break; 422 } 423 424 fprintf(stderr, "Failed to run command '%s': %s\n", 425 cmd, strerror(errno)); 426 427 return 1; 428 } 429