18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Ideas taken over from the perf userspace tool (included in the Linus 68c2ecf20Sopenharmony_ci * kernel git repo): subcommand builtins and param parsing. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <errno.h> 148c2ecf20Sopenharmony_ci#include <sched.h> 158c2ecf20Sopenharmony_ci#include <sys/types.h> 168c2ecf20Sopenharmony_ci#include <sys/stat.h> 178c2ecf20Sopenharmony_ci#include <sys/utsname.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "builtin.h" 208c2ecf20Sopenharmony_ci#include "helpers/helpers.h" 218c2ecf20Sopenharmony_ci#include "helpers/bitmask.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int cmd_help(int argc, const char **argv); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Global cpu_info object available for all binaries 288c2ecf20Sopenharmony_ci * Info only retrieved from CPU 0 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Values will be zero/unknown on non X86 archs 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistruct cpupower_cpu_info cpupower_cpu_info; 338c2ecf20Sopenharmony_ciint run_as_root; 348c2ecf20Sopenharmony_ciint base_cpu; 358c2ecf20Sopenharmony_ci/* Affected cpus chosen by -c/--cpu param */ 368c2ecf20Sopenharmony_cistruct bitmask *cpus_chosen; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef DEBUG 398c2ecf20Sopenharmony_ciint be_verbose; 408c2ecf20Sopenharmony_ci#endif 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void print_help(void); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct cmd_struct { 458c2ecf20Sopenharmony_ci const char *cmd; 468c2ecf20Sopenharmony_ci int (*main)(int, const char **); 478c2ecf20Sopenharmony_ci int needs_root; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct cmd_struct commands[] = { 518c2ecf20Sopenharmony_ci { "frequency-info", cmd_freq_info, 0 }, 528c2ecf20Sopenharmony_ci { "frequency-set", cmd_freq_set, 1 }, 538c2ecf20Sopenharmony_ci { "idle-info", cmd_idle_info, 0 }, 548c2ecf20Sopenharmony_ci { "idle-set", cmd_idle_set, 1 }, 558c2ecf20Sopenharmony_ci { "set", cmd_set, 1 }, 568c2ecf20Sopenharmony_ci { "info", cmd_info, 0 }, 578c2ecf20Sopenharmony_ci { "monitor", cmd_monitor, 0 }, 588c2ecf20Sopenharmony_ci { "help", cmd_help, 0 }, 598c2ecf20Sopenharmony_ci /* { "bench", cmd_bench, 1 }, */ 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void print_help(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned int i; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#ifdef DEBUG 678c2ecf20Sopenharmony_ci printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); 688c2ecf20Sopenharmony_ci#else 698c2ecf20Sopenharmony_ci printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci printf(_("Supported commands are:\n")); 728c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(commands); i++) 738c2ecf20Sopenharmony_ci printf("\t%s\n", commands[i].cmd); 748c2ecf20Sopenharmony_ci printf(_("\nNot all commands can make use of the -c cpulist option.\n")); 758c2ecf20Sopenharmony_ci printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int print_man_page(const char *subpage) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int len; 818c2ecf20Sopenharmony_ci char *page; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci len = 10; /* enough for "cpupower-" */ 848c2ecf20Sopenharmony_ci if (subpage != NULL) 858c2ecf20Sopenharmony_ci len += strlen(subpage); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci page = malloc(len); 888c2ecf20Sopenharmony_ci if (!page) 898c2ecf20Sopenharmony_ci return -ENOMEM; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci sprintf(page, "cpupower"); 928c2ecf20Sopenharmony_ci if ((subpage != NULL) && strcmp(subpage, "help")) { 938c2ecf20Sopenharmony_ci strcat(page, "-"); 948c2ecf20Sopenharmony_ci strcat(page, subpage); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci execlp("man", "man", page, NULL); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* should not be reached */ 1008c2ecf20Sopenharmony_ci return -EINVAL; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int cmd_help(int argc, const char **argv) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci if (argc > 1) { 1068c2ecf20Sopenharmony_ci print_man_page(argv[1]); /* exits within execlp() */ 1078c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci print_help(); 1118c2ecf20Sopenharmony_ci return EXIT_SUCCESS; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void print_version(void) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci printf(PACKAGE " " VERSION "\n"); 1178c2ecf20Sopenharmony_ci printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void handle_options(int *argc, const char ***argv) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci int ret, x, new_argc = 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (*argc < 1) 1258c2ecf20Sopenharmony_ci return; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) { 1288c2ecf20Sopenharmony_ci const char *param = (*argv)[x]; 1298c2ecf20Sopenharmony_ci if (!strcmp(param, "-h") || !strcmp(param, "--help")) { 1308c2ecf20Sopenharmony_ci print_help(); 1318c2ecf20Sopenharmony_ci exit(EXIT_SUCCESS); 1328c2ecf20Sopenharmony_ci } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { 1338c2ecf20Sopenharmony_ci if (*argc < 2) { 1348c2ecf20Sopenharmony_ci print_help(); 1358c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci if (!strcmp((*argv)[x+1], "all")) 1388c2ecf20Sopenharmony_ci bitmask_setall(cpus_chosen); 1398c2ecf20Sopenharmony_ci else { 1408c2ecf20Sopenharmony_ci ret = bitmask_parselist( 1418c2ecf20Sopenharmony_ci (*argv)[x+1], cpus_chosen); 1428c2ecf20Sopenharmony_ci if (ret < 0) { 1438c2ecf20Sopenharmony_ci fprintf(stderr, _("Error parsing cpu " 1448c2ecf20Sopenharmony_ci "list\n")); 1458c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci x += 1; 1498c2ecf20Sopenharmony_ci /* Cut out param: cpupower -c 1 info -> cpupower info */ 1508c2ecf20Sopenharmony_ci new_argc += 2; 1518c2ecf20Sopenharmony_ci continue; 1528c2ecf20Sopenharmony_ci } else if (!strcmp(param, "-v") || 1538c2ecf20Sopenharmony_ci !strcmp(param, "--version")) { 1548c2ecf20Sopenharmony_ci print_version(); 1558c2ecf20Sopenharmony_ci exit(EXIT_SUCCESS); 1568c2ecf20Sopenharmony_ci#ifdef DEBUG 1578c2ecf20Sopenharmony_ci } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { 1588c2ecf20Sopenharmony_ci be_verbose = 1; 1598c2ecf20Sopenharmony_ci new_argc++; 1608c2ecf20Sopenharmony_ci continue; 1618c2ecf20Sopenharmony_ci#endif 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci fprintf(stderr, "Unknown option: %s\n", param); 1648c2ecf20Sopenharmony_ci print_help(); 1658c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci *argc -= new_argc; 1698c2ecf20Sopenharmony_ci *argv += new_argc; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint main(int argc, const char *argv[]) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci const char *cmd; 1758c2ecf20Sopenharmony_ci unsigned int i, ret; 1768c2ecf20Sopenharmony_ci struct stat statbuf; 1778c2ecf20Sopenharmony_ci struct utsname uts; 1788c2ecf20Sopenharmony_ci char pathname[32]; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci argc--; 1838c2ecf20Sopenharmony_ci argv += 1; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci handle_options(&argc, &argv); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci cmd = argv[0]; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (argc < 1) { 1908c2ecf20Sopenharmony_ci print_help(); 1918c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci setlocale(LC_ALL, ""); 1958c2ecf20Sopenharmony_ci textdomain(PACKAGE); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Turn "perf cmd --help" into "perf help cmd" */ 1988c2ecf20Sopenharmony_ci if (argc > 1 && !strcmp(argv[1], "--help")) { 1998c2ecf20Sopenharmony_ci argv[1] = argv[0]; 2008c2ecf20Sopenharmony_ci argv[0] = cmd = "help"; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci base_cpu = sched_getcpu(); 2048c2ecf20Sopenharmony_ci if (base_cpu < 0) { 2058c2ecf20Sopenharmony_ci fprintf(stderr, _("No valid cpus found.\n")); 2068c2ecf20Sopenharmony_ci return EXIT_FAILURE; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci get_cpu_info(&cpupower_cpu_info); 2108c2ecf20Sopenharmony_ci run_as_root = !geteuid(); 2118c2ecf20Sopenharmony_ci if (run_as_root) { 2128c2ecf20Sopenharmony_ci ret = uname(&uts); 2138c2ecf20Sopenharmony_ci sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); 2148c2ecf20Sopenharmony_ci if (!ret && !strcmp(uts.machine, "x86_64") && 2158c2ecf20Sopenharmony_ci stat(pathname, &statbuf) != 0) { 2168c2ecf20Sopenharmony_ci if (system("modprobe msr") == -1) 2178c2ecf20Sopenharmony_ci fprintf(stderr, _("MSR access not available.\n")); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(commands); i++) { 2228c2ecf20Sopenharmony_ci struct cmd_struct *p = commands + i; 2238c2ecf20Sopenharmony_ci if (strcmp(p->cmd, cmd)) 2248c2ecf20Sopenharmony_ci continue; 2258c2ecf20Sopenharmony_ci if (!run_as_root && p->needs_root) { 2268c2ecf20Sopenharmony_ci fprintf(stderr, _("Subcommand %s needs root " 2278c2ecf20Sopenharmony_ci "privileges\n"), cmd); 2288c2ecf20Sopenharmony_ci return EXIT_FAILURE; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci ret = p->main(argc, argv); 2318c2ecf20Sopenharmony_ci if (cpus_chosen) 2328c2ecf20Sopenharmony_ci bitmask_free(cpus_chosen); 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci print_help(); 2368c2ecf20Sopenharmony_ci return EXIT_FAILURE; 2378c2ecf20Sopenharmony_ci} 238