1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Ideas taken over from the perf userspace tool (included in the Linus
6*4882a593Smuzhiyun * kernel git repo): subcommand builtins and param parsing.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <string.h>
12*4882a593Smuzhiyun #include <unistd.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <sched.h>
15*4882a593Smuzhiyun #include <sys/types.h>
16*4882a593Smuzhiyun #include <sys/stat.h>
17*4882a593Smuzhiyun #include <sys/utsname.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "builtin.h"
20*4882a593Smuzhiyun #include "helpers/helpers.h"
21*4882a593Smuzhiyun #include "helpers/bitmask.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static int cmd_help(int argc, const char **argv);
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* Global cpu_info object available for all binaries
28*4882a593Smuzhiyun * Info only retrieved from CPU 0
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * Values will be zero/unknown on non X86 archs
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun struct cpupower_cpu_info cpupower_cpu_info;
33*4882a593Smuzhiyun int run_as_root;
34*4882a593Smuzhiyun int base_cpu;
35*4882a593Smuzhiyun /* Affected cpus chosen by -c/--cpu param */
36*4882a593Smuzhiyun struct bitmask *cpus_chosen;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #ifdef DEBUG
39*4882a593Smuzhiyun int be_verbose;
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static void print_help(void);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun struct cmd_struct {
45*4882a593Smuzhiyun const char *cmd;
46*4882a593Smuzhiyun int (*main)(int, const char **);
47*4882a593Smuzhiyun int needs_root;
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun static struct cmd_struct commands[] = {
51*4882a593Smuzhiyun { "frequency-info", cmd_freq_info, 0 },
52*4882a593Smuzhiyun { "frequency-set", cmd_freq_set, 1 },
53*4882a593Smuzhiyun { "idle-info", cmd_idle_info, 0 },
54*4882a593Smuzhiyun { "idle-set", cmd_idle_set, 1 },
55*4882a593Smuzhiyun { "set", cmd_set, 1 },
56*4882a593Smuzhiyun { "info", cmd_info, 0 },
57*4882a593Smuzhiyun { "monitor", cmd_monitor, 0 },
58*4882a593Smuzhiyun { "help", cmd_help, 0 },
59*4882a593Smuzhiyun /* { "bench", cmd_bench, 1 }, */
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
print_help(void)62*4882a593Smuzhiyun static void print_help(void)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun unsigned int i;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #ifdef DEBUG
67*4882a593Smuzhiyun printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
68*4882a593Smuzhiyun #else
69*4882a593Smuzhiyun printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun printf(_("Supported commands are:\n"));
72*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(commands); i++)
73*4882a593Smuzhiyun printf("\t%s\n", commands[i].cmd);
74*4882a593Smuzhiyun printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
75*4882a593Smuzhiyun printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
print_man_page(const char * subpage)78*4882a593Smuzhiyun static int print_man_page(const char *subpage)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun int len;
81*4882a593Smuzhiyun char *page;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun len = 10; /* enough for "cpupower-" */
84*4882a593Smuzhiyun if (subpage != NULL)
85*4882a593Smuzhiyun len += strlen(subpage);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun page = malloc(len);
88*4882a593Smuzhiyun if (!page)
89*4882a593Smuzhiyun return -ENOMEM;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun sprintf(page, "cpupower");
92*4882a593Smuzhiyun if ((subpage != NULL) && strcmp(subpage, "help")) {
93*4882a593Smuzhiyun strcat(page, "-");
94*4882a593Smuzhiyun strcat(page, subpage);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun execlp("man", "man", page, NULL);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* should not be reached */
100*4882a593Smuzhiyun return -EINVAL;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
cmd_help(int argc,const char ** argv)103*4882a593Smuzhiyun static int cmd_help(int argc, const char **argv)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun if (argc > 1) {
106*4882a593Smuzhiyun print_man_page(argv[1]); /* exits within execlp() */
107*4882a593Smuzhiyun return EXIT_FAILURE;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun print_help();
111*4882a593Smuzhiyun return EXIT_SUCCESS;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
print_version(void)114*4882a593Smuzhiyun static void print_version(void)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun printf(PACKAGE " " VERSION "\n");
117*4882a593Smuzhiyun printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
handle_options(int * argc,const char *** argv)120*4882a593Smuzhiyun static void handle_options(int *argc, const char ***argv)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun int ret, x, new_argc = 0;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (*argc < 1)
125*4882a593Smuzhiyun return;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) {
128*4882a593Smuzhiyun const char *param = (*argv)[x];
129*4882a593Smuzhiyun if (!strcmp(param, "-h") || !strcmp(param, "--help")) {
130*4882a593Smuzhiyun print_help();
131*4882a593Smuzhiyun exit(EXIT_SUCCESS);
132*4882a593Smuzhiyun } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) {
133*4882a593Smuzhiyun if (*argc < 2) {
134*4882a593Smuzhiyun print_help();
135*4882a593Smuzhiyun exit(EXIT_FAILURE);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun if (!strcmp((*argv)[x+1], "all"))
138*4882a593Smuzhiyun bitmask_setall(cpus_chosen);
139*4882a593Smuzhiyun else {
140*4882a593Smuzhiyun ret = bitmask_parselist(
141*4882a593Smuzhiyun (*argv)[x+1], cpus_chosen);
142*4882a593Smuzhiyun if (ret < 0) {
143*4882a593Smuzhiyun fprintf(stderr, _("Error parsing cpu "
144*4882a593Smuzhiyun "list\n"));
145*4882a593Smuzhiyun exit(EXIT_FAILURE);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun x += 1;
149*4882a593Smuzhiyun /* Cut out param: cpupower -c 1 info -> cpupower info */
150*4882a593Smuzhiyun new_argc += 2;
151*4882a593Smuzhiyun continue;
152*4882a593Smuzhiyun } else if (!strcmp(param, "-v") ||
153*4882a593Smuzhiyun !strcmp(param, "--version")) {
154*4882a593Smuzhiyun print_version();
155*4882a593Smuzhiyun exit(EXIT_SUCCESS);
156*4882a593Smuzhiyun #ifdef DEBUG
157*4882a593Smuzhiyun } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) {
158*4882a593Smuzhiyun be_verbose = 1;
159*4882a593Smuzhiyun new_argc++;
160*4882a593Smuzhiyun continue;
161*4882a593Smuzhiyun #endif
162*4882a593Smuzhiyun } else {
163*4882a593Smuzhiyun fprintf(stderr, "Unknown option: %s\n", param);
164*4882a593Smuzhiyun print_help();
165*4882a593Smuzhiyun exit(EXIT_FAILURE);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun *argc -= new_argc;
169*4882a593Smuzhiyun *argv += new_argc;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
main(int argc,const char * argv[])172*4882a593Smuzhiyun int main(int argc, const char *argv[])
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun const char *cmd;
175*4882a593Smuzhiyun unsigned int i, ret;
176*4882a593Smuzhiyun struct stat statbuf;
177*4882a593Smuzhiyun struct utsname uts;
178*4882a593Smuzhiyun char pathname[32];
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun argc--;
183*4882a593Smuzhiyun argv += 1;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun handle_options(&argc, &argv);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun cmd = argv[0];
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (argc < 1) {
190*4882a593Smuzhiyun print_help();
191*4882a593Smuzhiyun return EXIT_FAILURE;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun setlocale(LC_ALL, "");
195*4882a593Smuzhiyun textdomain(PACKAGE);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* Turn "perf cmd --help" into "perf help cmd" */
198*4882a593Smuzhiyun if (argc > 1 && !strcmp(argv[1], "--help")) {
199*4882a593Smuzhiyun argv[1] = argv[0];
200*4882a593Smuzhiyun argv[0] = cmd = "help";
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun base_cpu = sched_getcpu();
204*4882a593Smuzhiyun if (base_cpu < 0) {
205*4882a593Smuzhiyun fprintf(stderr, _("No valid cpus found.\n"));
206*4882a593Smuzhiyun return EXIT_FAILURE;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun get_cpu_info(&cpupower_cpu_info);
210*4882a593Smuzhiyun run_as_root = !geteuid();
211*4882a593Smuzhiyun if (run_as_root) {
212*4882a593Smuzhiyun ret = uname(&uts);
213*4882a593Smuzhiyun sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
214*4882a593Smuzhiyun if (!ret && !strcmp(uts.machine, "x86_64") &&
215*4882a593Smuzhiyun stat(pathname, &statbuf) != 0) {
216*4882a593Smuzhiyun if (system("modprobe msr") == -1)
217*4882a593Smuzhiyun fprintf(stderr, _("MSR access not available.\n"));
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(commands); i++) {
222*4882a593Smuzhiyun struct cmd_struct *p = commands + i;
223*4882a593Smuzhiyun if (strcmp(p->cmd, cmd))
224*4882a593Smuzhiyun continue;
225*4882a593Smuzhiyun if (!run_as_root && p->needs_root) {
226*4882a593Smuzhiyun fprintf(stderr, _("Subcommand %s needs root "
227*4882a593Smuzhiyun "privileges\n"), cmd);
228*4882a593Smuzhiyun return EXIT_FAILURE;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun ret = p->main(argc, argv);
231*4882a593Smuzhiyun if (cpus_chosen)
232*4882a593Smuzhiyun bitmask_free(cpus_chosen);
233*4882a593Smuzhiyun return ret;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun print_help();
236*4882a593Smuzhiyun return EXIT_FAILURE;
237*4882a593Smuzhiyun }
238