1 /*
2  * xenpm.c: list the power information of the available processors
3  * Copyright (c) 2008, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; If not, see <http://www.gnu.org/licenses/>.
16  */
17 #define MAX_NR_CPU 512
18 
19 #include <ctype.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <getopt.h>
26 #include <errno.h>
27 #include <signal.h>
28 
29 #include <xenctrl.h>
30 #include <inttypes.h>
31 #include <sys/time.h>
32 
33 #include <xen-tools/common-macros.h>
34 
35 #define MAX_PKG_RESIDENCIES 12
36 #define MAX_CORE_RESIDENCIES 8
37 
38 static xc_interface *xc_handle;
39 static unsigned int max_cpu_nr;
40 
41 /* help message */
show_help(void)42 void show_help(void)
43 {
44     fprintf(stderr,
45             "xen power management control tool\n\n"
46             "usage: xenpm <command> [args]\n\n"
47             "xenpm command list:\n\n"
48             " get-cpuidle-states    [cpuid]       list cpu idle info of CPU <cpuid> or all\n"
49             " get-cpufreq-states    [cpuid]       list cpu freq info of CPU <cpuid> or all\n"
50             " get-cpufreq-average   [cpuid]       average cpu frequency since last invocation\n"
51             "                                     for CPU <cpuid> or all\n"
52             " get-cpufreq-para      [cpuid]       list cpu freq parameter of CPU <cpuid> or all\n"
53             " set-scaling-maxfreq   [cpuid] <HZ>  set max cpu frequency <HZ> on CPU <cpuid>\n"
54             "                                     or all CPUs\n"
55             " set-scaling-minfreq   [cpuid] <HZ>  set min cpu frequency <HZ> on CPU <cpuid>\n"
56             "                                     or all CPUs\n"
57             " set-scaling-speed     [cpuid] <num> set scaling speed on CPU <cpuid> or all\n"
58             "                                     it is used in userspace governor.\n"
59             " set-scaling-governor  [cpuid] <gov> set scaling governor on CPU <cpuid> or all\n"
60             "                                     as userspace/performance/powersave/ondemand\n"
61             " set-sampling-rate     [cpuid] <num> set sampling rate on CPU <cpuid> or all\n"
62             "                                     it is used in ondemand governor.\n"
63             " set-up-threshold      [cpuid] <num> set up threshold on CPU <cpuid> or all\n"
64             "                                     it is used in ondemand governor.\n"
65             " get-cpu-topology                    get thread/core/socket topology info\n"
66             " set-sched-smt           enable|disable enable/disable scheduler smt power saving\n"
67             " set-vcpu-migration-delay      <num> set scheduler vcpu migration delay in us\n"
68             " get-vcpu-migration-delay            get scheduler vcpu migration delay\n"
69             " set-max-cstate        <num>|'unlimited' [<num2>|'unlimited']\n"
70             "                                     set the C-State limitation (<num> >= 0) and\n"
71             "                                     optionally the C-sub-state limitation (<num2> >= 0)\n"
72             " set-cpufreq-cppc      [cpuid] [balance|performance|powersave] <param:val>*\n"
73             "                                     set Hardware P-State (HWP) parameters\n"
74             "                                     on CPU <cpuid> or all if omitted.\n"
75             "                                     optionally a preset of one of:\n"
76             "                                       balance|performance|powersave\n"
77             "                                     an optional list of param:val arguments\n"
78             "                                       minimum:N (0-255)\n"
79             "                                       maximum:N (0-255)\n"
80             "                                           get-cpufreq-para lowest/highest\n"
81             "                                           values are limits for\n"
82             "                                           minumum/maximum.\n"
83             "                                       desired:N (0-255)\n"
84             "                                           set explicit performance target.\n"
85             "                                           non-zero disables auto-HWP mode.\n"
86             "                                       energy-perf:N (0-255)\n"
87             "                                                   energy/performance hint\n"
88             "                                                   lower - favor performance\n"
89             "                                                   higher - favor powersave\n"
90             "                                                   128 - balance\n"
91             "                                       act-window:N{,m,u}s range 1us-1270s\n"
92             "                                           window for internal calculations.\n"
93             "                                           units default to \"us\" if unspecified.\n"
94             "                                           truncates un-representable values.\n"
95             "                                           0 lets the hardware decide.\n"
96             " start [seconds]                     start collect Cx/Px statistics,\n"
97             "                                     output after CTRL-C or SIGINT or several seconds.\n"
98             " enable-turbo-mode     [cpuid]       enable Turbo Mode for processors that support it.\n"
99             " disable-turbo-mode    [cpuid]       disable Turbo Mode for processors that support it.\n"
100             );
101 }
102 /* wrapper function */
help_func(int argc,char * argv[])103 void help_func(int argc, char *argv[])
104 {
105     show_help();
106 }
107 
parse_cpuid(const char * arg,int * cpuid)108 static void parse_cpuid(const char *arg, int *cpuid)
109 {
110     if ( sscanf(arg, "%d", cpuid) != 1 || *cpuid < 0 )
111     {
112         if ( strcasecmp(arg, "all") )
113         {
114             fprintf(stderr, "Invalid CPU identifier: '%s'\n", arg);
115             exit(EINVAL);
116         }
117         *cpuid = -1;
118     }
119 }
120 
parse_cpuid_and_int(int argc,char * argv[],int * cpuid,int * val,const char * what)121 static void parse_cpuid_and_int(int argc, char *argv[],
122                                 int *cpuid, int *val, const char *what)
123 {
124     if ( argc == 0 )
125     {
126          fprintf(stderr, "Missing %s\n", what);
127          exit(EINVAL);
128     }
129 
130     if ( argc > 1 )
131         parse_cpuid(argv[0], cpuid);
132 
133     if ( sscanf(argv[argc > 1], "%d", val) != 1 )
134     {
135         fprintf(stderr, "Invalid %s '%s'\n", what, argv[argc > 1]);
136         exit(EINVAL);
137     }
138 }
139 
print_cxstat(int cpuid,struct xc_cx_stat * cxstat)140 static void print_cxstat(int cpuid, struct xc_cx_stat *cxstat)
141 {
142     unsigned int i;
143 
144     printf("cpu id               : %d\n", cpuid);
145     printf("total C-states       : %d\n", cxstat->nr);
146     printf("idle time(ms)        : %"PRIu64"\n",
147            cxstat->idle_time/1000000UL);
148     for ( i = 0; i < cxstat->nr; i++ )
149     {
150         printf("C%-20d: transition [%20"PRIu64"]\n",
151                i, cxstat->triggers[i]);
152         printf("                       residency  [%20"PRIu64" ms]\n",
153                cxstat->residencies[i]/1000000UL);
154     }
155     for ( i = 0; i < MAX_PKG_RESIDENCIES && i < cxstat->nr_pc; ++i )
156         if ( cxstat->pc[i] )
157            printf("pc%d                  : [%20"PRIu64" ms]\n", i + 1,
158                   cxstat->pc[i] / 1000000UL);
159     for ( i = 0; i < MAX_CORE_RESIDENCIES && i < cxstat->nr_cc; ++i )
160         if ( cxstat->cc[i] )
161            printf("cc%d                  : [%20"PRIu64" ms]\n", i + 1,
162                   cxstat->cc[i] / 1000000UL);
163     printf("\n");
164 }
165 
166 /* show cpu idle information on CPU cpuid */
get_cxstat_by_cpuid(xc_interface * xc_handle,int cpuid,struct xc_cx_stat * cxstat)167 static int get_cxstat_by_cpuid(xc_interface *xc_handle, int cpuid, struct xc_cx_stat *cxstat)
168 {
169     int ret = 0;
170     int max_cx_num = 0;
171 
172     ret = xc_pm_get_max_cx(xc_handle, cpuid, &max_cx_num);
173     if ( ret )
174         return -errno;
175 
176     if ( !cxstat )
177         return -EINVAL;
178 
179     if ( !max_cx_num )
180         return -ENODEV;
181 
182     cxstat->triggers = calloc(max_cx_num, sizeof(*cxstat->triggers));
183     cxstat->residencies = calloc(max_cx_num, sizeof(*cxstat->residencies));
184     cxstat->pc = calloc(MAX_PKG_RESIDENCIES, sizeof(*cxstat->pc));
185     cxstat->cc = calloc(MAX_CORE_RESIDENCIES, sizeof(*cxstat->cc));
186     if ( !cxstat->triggers || !cxstat->residencies ||
187          !cxstat->pc || !cxstat->cc )
188     {
189         free(cxstat->cc);
190         free(cxstat->pc);
191         free(cxstat->residencies);
192         free(cxstat->triggers);
193         return -ENOMEM;
194     }
195 
196     cxstat->nr = max_cx_num;
197     cxstat->nr_pc = MAX_PKG_RESIDENCIES;
198     cxstat->nr_cc = MAX_CORE_RESIDENCIES;
199 
200     ret = xc_pm_get_cxstat(xc_handle, cpuid, cxstat);
201     if( ret )
202     {
203         ret = -errno;
204         free(cxstat->triggers);
205         free(cxstat->residencies);
206         free(cxstat->pc);
207         free(cxstat->cc);
208         cxstat->triggers = NULL;
209         cxstat->residencies = NULL;
210         cxstat->pc = NULL;
211         cxstat->cc = NULL;
212     }
213 
214     return ret;
215 }
216 
show_max_cstate(xc_interface * xc_handle)217 static int show_max_cstate(xc_interface *xc_handle)
218 {
219     int ret = 0;
220     uint32_t value;
221 
222     if ( (ret = xc_get_cpuidle_max_cstate(xc_handle, &value)) )
223         return ret;
224 
225     if ( value < XEN_SYSCTL_CX_UNLIMITED )
226     {
227         printf("Max possible C-state: C%"PRIu32"\n", value);
228         if ( (ret = xc_get_cpuidle_max_csubstate(xc_handle, &value)) )
229             return ret;
230         if ( value < XEN_SYSCTL_CX_UNLIMITED )
231             printf("Max possible substate: %"PRIu32"\n\n", value);
232         else
233             puts("");
234     }
235     else
236         printf("All C-states allowed\n\n");
237 
238     return 0;
239 }
240 
show_cxstat_by_cpuid(xc_interface * xc_handle,int cpuid)241 static int show_cxstat_by_cpuid(xc_interface *xc_handle, int cpuid)
242 {
243     int ret = 0;
244     struct xc_cx_stat cxstatinfo;
245 
246     ret = get_cxstat_by_cpuid(xc_handle, cpuid, &cxstatinfo);
247     if ( ret )
248     {
249         if ( ret == -ENODEV )
250             fprintf(stderr,
251                     "Either Xen cpuidle is disabled or no valid information is registered!\n");
252         return ret;
253     }
254 
255     print_cxstat(cpuid, &cxstatinfo);
256 
257     free(cxstatinfo.triggers);
258     free(cxstatinfo.residencies);
259     free(cxstatinfo.pc);
260     free(cxstatinfo.cc);
261     return 0;
262 }
263 
cxstat_func(int argc,char * argv[])264 void cxstat_func(int argc, char *argv[])
265 {
266     int cpuid = -1;
267 
268     if ( argc > 0 )
269         parse_cpuid(argv[0], &cpuid);
270 
271     show_max_cstate(xc_handle);
272 
273     if ( cpuid < 0 )
274     {
275         /* show cxstates on all cpus */
276         int i;
277         for ( i = 0; i < max_cpu_nr; i++ )
278             if ( show_cxstat_by_cpuid(xc_handle, i) == -ENODEV )
279                 break;
280     }
281     else
282         show_cxstat_by_cpuid(xc_handle, cpuid);
283 }
284 
print_pxstat(int cpuid,struct xc_px_stat * pxstat)285 static void print_pxstat(int cpuid, struct xc_px_stat *pxstat)
286 {
287     int i;
288 
289     printf("cpu id               : %d\n", cpuid);
290     printf("total P-states       : %d\n", pxstat->total);
291     printf("usable P-states      : %d\n", pxstat->usable);
292     printf("current frequency    : %"PRIu64" MHz\n",
293            pxstat->pt[pxstat->cur].freq);
294     for ( i = 0; i < pxstat->total; i++ )
295     {
296         if ( pxstat->cur == i )
297             printf("*P%-9d", i);
298         else
299             printf("P%-10d", i);
300         printf("[%4"PRIu64" MHz]", pxstat->pt[i].freq);
301         printf(": transition [%20"PRIu64"]\n",
302                pxstat->pt[i].count);
303         printf("                       residency  [%20"PRIu64" ms]\n",
304                pxstat->pt[i].residency/1000000UL);
305     }
306     printf("\n");
307 }
308 
309 /* show cpu frequency information on CPU cpuid */
get_pxstat_by_cpuid(xc_interface * xc_handle,int cpuid,struct xc_px_stat * pxstat)310 static int get_pxstat_by_cpuid(xc_interface *xc_handle, int cpuid, struct xc_px_stat *pxstat)
311 {
312     int ret = 0;
313     int max_px_num = 0;
314 
315     ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px_num);
316     if ( ret )
317         return -errno;
318 
319     if ( !pxstat)
320         return -EINVAL;
321 
322     pxstat->trans_pt = malloc(max_px_num * max_px_num *
323                               sizeof(uint64_t));
324     if ( !pxstat->trans_pt )
325         return -ENOMEM;
326     pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val));
327     if ( !pxstat->pt )
328     {
329         free(pxstat->trans_pt);
330         return -ENOMEM;
331     }
332 
333     ret = xc_pm_get_pxstat(xc_handle, cpuid, pxstat);
334     if( ret )
335     {
336         ret = -errno;
337         free(pxstat->trans_pt);
338         free(pxstat->pt);
339         pxstat->trans_pt = NULL;
340         pxstat->pt = NULL;
341     }
342 
343     return ret;
344 }
345 
346 /* show cpu actual average freq information on CPU cpuid */
get_avgfreq_by_cpuid(xc_interface * xc_handle,int cpuid,int * avgfreq)347 static int get_avgfreq_by_cpuid(xc_interface *xc_handle, int cpuid, int *avgfreq)
348 {
349     int ret = 0;
350 
351     ret = xc_get_cpufreq_avgfreq(xc_handle, cpuid, avgfreq);
352     if ( ret )
353         ret = -errno;
354 
355     return ret;
356 }
357 
show_pxstat_by_cpuid(xc_interface * xc_handle,int cpuid)358 static int show_pxstat_by_cpuid(xc_interface *xc_handle, int cpuid)
359 {
360     int ret = 0;
361     struct xc_px_stat pxstatinfo;
362 
363     ret = get_pxstat_by_cpuid(xc_handle, cpuid, &pxstatinfo);
364     if ( ret )
365     {
366         if ( ret == -ENODEV )
367             fprintf(stderr,
368                     "Either Xen cpufreq is disabled or no valid information is registered!\n");
369         else if ( ret == -EOPNOTSUPP )
370             fprintf(stderr,
371                     "P-State information not supported.  Try 'get-cpufreq-average' or 'start'.\n");
372         return ret;
373     }
374 
375     print_pxstat(cpuid, &pxstatinfo);
376 
377     free(pxstatinfo.trans_pt);
378     free(pxstatinfo.pt);
379     return 0;
380 }
381 
pxstat_func(int argc,char * argv[])382 void pxstat_func(int argc, char *argv[])
383 {
384     int cpuid = -1;
385 
386     if ( argc > 0 )
387         parse_cpuid(argv[0], &cpuid);
388 
389     if ( cpuid < 0 )
390     {
391         /* show pxstates on all cpus */
392         int i;
393         for ( i = 0; i < max_cpu_nr; i++ )
394         {
395             int ret = show_pxstat_by_cpuid(xc_handle, i);
396 
397             if ( ret == -ENODEV || ret == -EOPNOTSUPP )
398                 break;
399         }
400     }
401     else
402         show_pxstat_by_cpuid(xc_handle, cpuid);
403 }
404 
show_cpufreq_by_cpuid(xc_interface * xc_handle,int cpuid)405 static int show_cpufreq_by_cpuid(xc_interface *xc_handle, int cpuid)
406 {
407     int ret = 0;
408     int average_cpufreq;
409 
410     ret = get_avgfreq_by_cpuid(xc_handle, cpuid, &average_cpufreq);
411     if ( ret )
412         return ret;
413 
414     printf("cpu id               : %d\n", cpuid);
415     printf("average cpu frequency: %d\n", average_cpufreq);
416     printf("\n");
417     return 0;
418 }
419 
cpufreq_func(int argc,char * argv[])420 void cpufreq_func(int argc, char *argv[])
421 {
422     int cpuid = -1;
423 
424     if ( argc > 0 )
425         parse_cpuid(argv[0], &cpuid);
426 
427     if ( cpuid < 0 )
428     {
429         /* show average frequency on all cpus */
430         int i;
431         for ( i = 0; i < max_cpu_nr; i++ )
432             if ( show_cpufreq_by_cpuid(xc_handle, i) == -ENODEV )
433                 break;
434     }
435     else
436         show_cpufreq_by_cpuid(xc_handle, cpuid);
437 }
438 
439 static uint64_t usec_start, usec_end;
440 static struct xc_cx_stat *cxstat, *cxstat_start, *cxstat_end;
441 static struct xc_px_stat *pxstat, *pxstat_start, *pxstat_end;
442 static int *avgfreq;
443 static uint64_t *sum, *sum_cx, *sum_px;
444 
signal_int_handler(int signo)445 static void signal_int_handler(int signo)
446 {
447     int i, j, k, ret;
448     struct timeval tv;
449     int cx_cap = 0, px_cap = 0;
450     xc_cputopo_t *cputopo = NULL;
451     unsigned max_cpus = 0;
452 
453     if ( xc_cputopoinfo(xc_handle, &max_cpus, NULL) != 0 )
454     {
455         fprintf(stderr, "failed to discover number of CPUs: %s\n",
456                 strerror(errno));
457         goto out;
458     }
459 
460     cputopo = calloc(max_cpus, sizeof(*cputopo));
461     if ( cputopo == NULL )
462     {
463 	fprintf(stderr, "failed to allocate hypercall buffers\n");
464 	goto out;
465     }
466 
467     if ( gettimeofday(&tv, NULL) )
468     {
469         fprintf(stderr, "failed to get timeofday\n");
470         goto out;
471     }
472     usec_end = tv.tv_sec * 1000000UL + tv.tv_usec;
473 
474     if ( get_cxstat_by_cpuid(xc_handle, 0, NULL) != -ENODEV )
475     {
476         cx_cap = 1;
477         for ( i = 0; i < max_cpu_nr; i++ )
478             if ( !get_cxstat_by_cpuid(xc_handle, i, &cxstat_end[i]) )
479                 for ( j = 0; j < cxstat_end[i].nr; j++ )
480                 {
481                     int64_t diff = (int64_t)cxstat_end[i].residencies[j] -
482                         (int64_t)cxstat_start[i].residencies[j];
483                     if ( diff >=0 )
484                         sum_cx[i] += diff;
485                 }
486     }
487 
488     ret = get_pxstat_by_cpuid(xc_handle, 0, NULL);
489     if ( ret != -ENODEV && ret != -EOPNOTSUPP )
490     {
491         px_cap = 1;
492         for ( i = 0; i < max_cpu_nr; i++ )
493             if ( !get_pxstat_by_cpuid(xc_handle, i , &pxstat_end[i]) )
494                 for ( j = 0; j < pxstat_end[i].total; j++ )
495                     sum_px[i] += pxstat_end[i].pt[j].residency -
496                                  pxstat_start[i].pt[j].residency;
497     }
498 
499     for ( i = 0; i < max_cpu_nr; i++ )
500         get_avgfreq_by_cpuid(xc_handle, i, &avgfreq[i]);
501 
502     printf("Elapsed time (ms): %"PRIu64"\n", (usec_end - usec_start) / 1000UL);
503     for ( i = 0; i < max_cpu_nr; i++ )
504     {
505         uint64_t res, triggers;
506         double avg_res;
507 
508         printf("\nCPU%d:\tResidency(ms)\t\tAvg Res(ms)\n",i);
509         if ( cx_cap && sum_cx[i] > 0 )
510         {
511             for ( j = 0; j < cxstat_end[i].nr; j++ )
512             {
513                 int64_t diff = (int64_t)cxstat_end[i].residencies[j] -
514                     (int64_t)cxstat_start[i].residencies[j];
515 
516                 res = ( diff >= 0 ) ? diff : 0;
517                 triggers = cxstat_end[i].triggers[j] -
518                     cxstat_start[i].triggers[j];
519                 /*
520                  * triggers may be zero if the CPU has been in this state for
521                  * the whole sample or if it never entered the state
522                  */
523                 if ( triggers == 0 && cxstat_end[i].last == j )
524                     avg_res =  (double)sum_cx[i]/1000000.0;
525                 else
526                     avg_res = (triggers==0) ? 0: (double)res/triggers/1000000.0;
527                 printf("  C%d\t%"PRIu64"\t(%5.2f%%)\t%.2f\n", j, res/1000000UL,
528                         100 * res / (double)sum_cx[i], avg_res );
529             }
530             printf("\n");
531         }
532         if ( px_cap && sum_px[i]>0 )
533         {
534             for ( j = 0; j < pxstat_end[i].total; j++ )
535             {
536                 res = pxstat_end[i].pt[j].residency -
537                     pxstat_start[i].pt[j].residency;
538                 printf("  P%d\t%"PRIu64"\t(%5.2f%%)\n", j,
539                         res / 1000000UL, 100UL * res / (double)sum_px[i]);
540             }
541         }
542         if ( px_cap && avgfreq[i] )
543             printf("  Avg freq\t%d\tKHz\n", avgfreq[i]);
544     }
545 
546     if ( cx_cap && !xc_cputopoinfo(xc_handle, &max_cpus, cputopo) )
547     {
548         uint32_t socket_ids[MAX_NR_CPU];
549         uint32_t core_ids[MAX_NR_CPU];
550         uint32_t socket_nr = 0;
551         uint32_t core_nr = 0;
552 
553         if ( max_cpus > MAX_NR_CPU )
554             max_cpus = MAX_NR_CPU;
555         /* check validity */
556         for ( i = 0; i < max_cpus; i++ )
557         {
558             if ( cputopo[i].core == XEN_INVALID_CORE_ID ||
559                  cputopo[i].socket == XEN_INVALID_SOCKET_ID )
560                 break;
561         }
562         if ( i >= max_cpus )
563         {
564             /* find socket nr & core nr per socket */
565             for ( i = 0; i < max_cpus; i++ )
566             {
567                 for ( j = 0; j < socket_nr; j++ )
568                     if ( cputopo[i].socket == socket_ids[j] )
569                         break;
570                 if ( j == socket_nr )
571                 {
572                     socket_ids[j] = cputopo[i].socket;
573                     socket_nr++;
574                 }
575 
576                 for ( j = 0; j < core_nr; j++ )
577                     if ( cputopo[i].core == core_ids[j] )
578                         break;
579                 if ( j == core_nr )
580                 {
581                     core_ids[j] = cputopo[i].core;
582                     core_nr++;
583                 }
584             }
585 
586             /* print out CC? and PC? */
587             for ( i = 0; i < socket_nr; i++ )
588             {
589                 unsigned int n;
590                 uint64_t res;
591 
592                 for ( j = 0; j < max_cpus; j++ )
593                 {
594                     if ( cputopo[j].socket == socket_ids[i] )
595                         break;
596                 }
597                 printf("\nSocket %d\n", socket_ids[i]);
598                 for ( n = 0; n < MAX_PKG_RESIDENCIES; ++n )
599                 {
600                     if ( n >= cxstat_end[j].nr_pc )
601                         continue;
602                     res = cxstat_end[j].pc[n];
603                     if ( n < cxstat_start[j].nr_pc )
604                         res -= cxstat_start[j].pc[n];
605                     printf("\tPC%u\t%"PRIu64" ms\t%.2f%%\n",
606                            n + 1, res / 1000000UL,
607                            100UL * res / (double)sum_cx[j]);
608                 }
609                 for ( k = 0; k < core_nr; k++ )
610                 {
611                     for ( j = 0; j < max_cpus; j++ )
612                     {
613                         if ( cputopo[j].socket == socket_ids[i] &&
614                              cputopo[j].core == core_ids[k] )
615                             break;
616                     }
617                     printf("\t Core %d CPU %d\n", core_ids[k], j);
618                     for ( n = 0; n < MAX_CORE_RESIDENCIES; ++n )
619                     {
620                         if ( n >= cxstat_end[j].nr_cc )
621                             continue;
622                         res = cxstat_end[j].cc[n];
623                         if ( n < cxstat_start[j].nr_cc )
624                             res -= cxstat_start[j].cc[n];
625                         printf("\t\tCC%u\t%"PRIu64" ms\t%.2f%%\n",
626                                n + 1, res / 1000000UL,
627                                100UL * res / (double)sum_cx[j]);
628                     }
629                 }
630             }
631         }
632     }
633 
634     /* some clean up and then exits */
635     for ( i = 0; i < 2 * max_cpu_nr; i++ )
636     {
637         free(cxstat[i].triggers);
638         free(cxstat[i].residencies);
639         free(cxstat[i].pc);
640         free(cxstat[i].cc);
641         free(pxstat[i].trans_pt);
642         free(pxstat[i].pt);
643     }
644     free(cxstat);
645     free(pxstat);
646     free(sum);
647     free(avgfreq);
648 out:
649     free(cputopo);
650     xc_interface_close(xc_handle);
651     exit(0);
652 }
653 
start_gather_func(int argc,char * argv[])654 void start_gather_func(int argc, char *argv[])
655 {
656     int i;
657     struct timeval tv;
658     int timeout = 0;
659 
660     if ( argc == 1 )
661     {
662         sscanf(argv[0], "%d", &timeout);
663         if ( timeout <= 0 )
664             fprintf(stderr, "failed to set timeout seconds, falling back...\n");
665         else
666             printf("Timeout set to %d seconds\n", timeout);
667     }
668 
669     if ( gettimeofday(&tv, NULL) )
670     {
671         fprintf(stderr, "failed to get timeofday\n");
672         return ;
673     }
674     usec_start = tv.tv_sec * 1000000UL + tv.tv_usec;
675 
676     sum = calloc(2 * max_cpu_nr, sizeof(*sum));
677     if ( sum == NULL )
678         return ;
679     cxstat = calloc(2 * max_cpu_nr, sizeof(*cxstat));
680     if ( cxstat == NULL )
681     {
682         free(sum);
683         return ;
684     }
685     pxstat = calloc(2 * max_cpu_nr, sizeof(*pxstat));
686     if ( pxstat == NULL )
687     {
688         free(sum);
689         free(cxstat);
690         return ;
691     }
692     avgfreq = calloc(max_cpu_nr, sizeof(*avgfreq));
693     if ( avgfreq == NULL )
694     {
695         free(sum);
696         free(cxstat);
697         free(pxstat);
698         return ;
699     }
700     sum_cx = sum;
701     sum_px = sum + max_cpu_nr;
702     cxstat_start = cxstat;
703     cxstat_end = cxstat + max_cpu_nr;
704     pxstat_start = pxstat;
705     pxstat_end = pxstat + max_cpu_nr;
706 
707     if ( get_cxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV &&
708          get_pxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV )
709     {
710         fprintf(stderr, "Xen cpu idle and frequency is disabled!\n");
711         return ;
712     }
713 
714     for ( i = 0; i < max_cpu_nr; i++ )
715     {
716         get_cxstat_by_cpuid(xc_handle, i, &cxstat_start[i]);
717         get_pxstat_by_cpuid(xc_handle, i, &pxstat_start[i]);
718         get_avgfreq_by_cpuid(xc_handle, i, &avgfreq[i]);
719     }
720 
721     if (signal(SIGINT, signal_int_handler) == SIG_ERR)
722     {
723         fprintf(stderr, "failed to set signal int handler\n");
724         free(sum);
725         free(pxstat);
726         free(cxstat);
727         free(avgfreq);
728         return ;
729     }
730 
731     if ( timeout > 0 )
732     {
733         if ( signal(SIGALRM, signal_int_handler) == SIG_ERR )
734         {
735             fprintf(stderr, "failed to set signal alarm handler\n");
736             free(sum);
737             free(pxstat);
738             free(cxstat);
739             free(avgfreq);
740             return ;
741         }
742         alarm(timeout);
743     }
744 
745     printf("Start sampling, waiting for CTRL-C or SIGINT or SIGALARM signal ...\n");
746 
747     pause();
748 }
749 
calculate_activity_window(const xc_cppc_para_t * cppc,const char ** units)750 static unsigned int calculate_activity_window(const xc_cppc_para_t *cppc,
751                                               const char **units)
752 {
753     unsigned int mantissa = MASK_EXTR(cppc->activity_window,
754                                       XEN_CPPC_ACT_WINDOW_MANTISSA_MASK);
755     unsigned int exponent = MASK_EXTR(cppc->activity_window,
756                                       XEN_CPPC_ACT_WINDOW_EXPONENT_MASK);
757     unsigned int multiplier = 1;
758     unsigned int i;
759 
760     /*
761      * SDM only states a 0 register is hardware selected, and doesn't mention
762      * a 0 mantissa with a non-0 exponent.  Only special case a 0 register.
763      */
764     if ( cppc->activity_window == 0 )
765     {
766         *units = "hardware selected";
767 
768         return 0;
769     }
770 
771     if ( exponent >= 6 )
772     {
773         *units = "s";
774         exponent -= 6;
775     }
776     else if ( exponent >= 3 )
777     {
778         *units = "ms";
779         exponent -= 3;
780     }
781     else
782         *units = "us";
783 
784     for ( i = 0; i < exponent; i++ )
785         multiplier *= 10;
786 
787     return mantissa * multiplier;
788 }
789 
790 /* print out parameters about cpu frequency */
print_cpufreq_para(int cpuid,struct xc_get_cpufreq_para * p_cpufreq)791 static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq)
792 {
793     bool hwp = strcmp(p_cpufreq->scaling_driver, XEN_HWP_DRIVER_NAME) == 0;
794     int i;
795 
796     printf("cpu id               : %d\n", cpuid);
797 
798     printf("affected_cpus        :");
799     for ( i = 0; i < p_cpufreq->cpu_num; i++ )
800         printf(" %d", p_cpufreq->affected_cpus[i]);
801     printf("\n");
802 
803     if ( hwp )
804         printf("cpuinfo frequency    : base [%"PRIu32"] max [%"PRIu32"]\n",
805                p_cpufreq->cpuinfo_min_freq,
806                p_cpufreq->cpuinfo_max_freq);
807     else
808         printf("cpuinfo frequency    : max [%u] min [%u] cur [%u]\n",
809                p_cpufreq->cpuinfo_max_freq,
810                p_cpufreq->cpuinfo_min_freq,
811                p_cpufreq->cpuinfo_cur_freq);
812 
813     printf("scaling_driver       : %s\n", p_cpufreq->scaling_driver);
814 
815     if ( hwp )
816     {
817         const xc_cppc_para_t *cppc = &p_cpufreq->u.cppc_para;
818 
819         printf("cppc variables       :\n");
820         printf("  hardware limits    : lowest [%"PRIu32"] lowest nonlinear [%"PRIu32"]\n",
821                cppc->lowest, cppc->lowest_nonlinear);
822         printf("                     : nominal [%"PRIu32"] highest [%"PRIu32"]\n",
823                cppc->nominal, cppc->highest);
824         printf("  configured limits  : min [%"PRIu32"] max [%"PRIu32"] energy perf [%"PRIu32"]\n",
825                cppc->minimum, cppc->maximum, cppc->energy_perf);
826 
827         if ( cppc->features & XEN_SYSCTL_CPPC_FEAT_ACT_WINDOW )
828         {
829             unsigned int activity_window;
830             const char *units;
831 
832             activity_window = calculate_activity_window(cppc, &units);
833             printf("                     : activity_window [%"PRIu32" %s]\n",
834                    activity_window, units);
835         }
836 
837         printf("                     : desired [%"PRIu32"%s]\n",
838                cppc->desired,
839                cppc->desired ? "" : " hw autonomous");
840     }
841     else
842     {
843         printf("scaling_avail_gov    : %s\n",
844                p_cpufreq->scaling_available_governors);
845 
846         printf("current_governor     : %s\n", p_cpufreq->u.s.scaling_governor);
847         if ( !strncmp(p_cpufreq->u.s.scaling_governor,
848                       "userspace", CPUFREQ_NAME_LEN) )
849         {
850             printf("  userspace specific :\n");
851             printf("    scaling_setspeed : %u\n",
852                    p_cpufreq->u.s.u.userspace.scaling_setspeed);
853         }
854         else if ( !strncmp(p_cpufreq->u.s.scaling_governor,
855                            "ondemand", CPUFREQ_NAME_LEN) )
856         {
857             printf("  ondemand specific  :\n");
858             printf("    sampling_rate    : max [%u] min [%u] cur [%u]\n",
859                    p_cpufreq->u.s.u.ondemand.sampling_rate_max,
860                    p_cpufreq->u.s.u.ondemand.sampling_rate_min,
861                    p_cpufreq->u.s.u.ondemand.sampling_rate);
862             printf("    up_threshold     : %u\n",
863                    p_cpufreq->u.s.u.ondemand.up_threshold);
864         }
865 
866         printf("scaling_avail_freq   :");
867         for ( i = 0; i < p_cpufreq->freq_num; i++ )
868             if ( p_cpufreq->scaling_available_frequencies[i] ==
869                  p_cpufreq->u.s.scaling_cur_freq )
870                 printf(" *%d", p_cpufreq->scaling_available_frequencies[i]);
871             else
872                 printf(" %d", p_cpufreq->scaling_available_frequencies[i]);
873         printf("\n");
874 
875         printf("scaling frequency    : max [%u] min [%u] cur [%u]\n",
876                p_cpufreq->u.s.scaling_max_freq,
877                p_cpufreq->u.s.scaling_min_freq,
878                p_cpufreq->u.s.scaling_cur_freq);
879     }
880 
881     printf("turbo mode           : %s\n",
882            p_cpufreq->turbo_enabled ? "enabled" : "disabled or n/a");
883     printf("\n");
884 }
885 
886 /* show cpu frequency parameters information on CPU cpuid */
show_cpufreq_para_by_cpuid(xc_interface * xc_handle,int cpuid)887 static int show_cpufreq_para_by_cpuid(xc_interface *xc_handle, int cpuid)
888 {
889     int ret = 0;
890     struct xc_get_cpufreq_para cpufreq_para, *p_cpufreq = &cpufreq_para;
891 
892     p_cpufreq->cpu_num = 0;
893     p_cpufreq->freq_num = 0;
894     p_cpufreq->gov_num = 0;
895     p_cpufreq->affected_cpus = NULL;
896     p_cpufreq->scaling_available_frequencies = NULL;
897     p_cpufreq->scaling_available_governors = NULL;
898     p_cpufreq->turbo_enabled = 0;
899 
900     do
901     {
902         free(p_cpufreq->affected_cpus);
903         free(p_cpufreq->scaling_available_frequencies);
904         free(p_cpufreq->scaling_available_governors);
905 
906         p_cpufreq->affected_cpus = NULL;
907         p_cpufreq->scaling_available_frequencies = NULL;
908         p_cpufreq->scaling_available_governors = NULL;
909 
910         if (!(p_cpufreq->affected_cpus =
911               malloc(p_cpufreq->cpu_num * sizeof(uint32_t))))
912         {
913             fprintf(stderr,
914                     "[CPU%d] failed to malloc for affected_cpus\n",
915                     cpuid);
916             ret = -ENOMEM;
917             goto out;
918         }
919         if (!(p_cpufreq->scaling_available_frequencies =
920               malloc(p_cpufreq->freq_num * sizeof(uint32_t))))
921         {
922             fprintf(stderr,
923                     "[CPU%d] failed to malloc for scaling_available_frequencies\n",
924                     cpuid);
925             ret = -ENOMEM;
926             goto out;
927         }
928         if (p_cpufreq->gov_num &&
929             !(p_cpufreq->scaling_available_governors =
930               malloc(p_cpufreq->gov_num * CPUFREQ_NAME_LEN * sizeof(char))))
931         {
932             fprintf(stderr,
933                     "[CPU%d] failed to malloc for scaling_available_governors\n",
934                     cpuid);
935             ret = -ENOMEM;
936             goto out;
937         }
938 
939         ret = xc_get_cpufreq_para(xc_handle, cpuid, p_cpufreq);
940     } while ( ret && errno == EAGAIN );
941 
942     if ( ret == 0 )
943         print_cpufreq_para(cpuid, p_cpufreq);
944     else if ( errno == ENODEV )
945     {
946         ret = -ENODEV;
947         fprintf(stderr, "Xen cpufreq is not enabled!\n");
948     }
949     else
950         fprintf(stderr,
951                 "[CPU%d] failed to get cpufreq parameter\n",
952                 cpuid);
953 
954 out:
955     free(p_cpufreq->scaling_available_governors);
956     free(p_cpufreq->scaling_available_frequencies);
957     free(p_cpufreq->affected_cpus);
958 
959     return ret;
960 }
961 
cpufreq_para_func(int argc,char * argv[])962 void cpufreq_para_func(int argc, char *argv[])
963 {
964     int cpuid = -1;
965 
966     if ( argc > 0 )
967         parse_cpuid(argv[0], &cpuid);
968 
969     if ( cpuid < 0 )
970     {
971         /* show cpu freqency information on all cpus */
972         int i;
973         for ( i = 0; i < max_cpu_nr; i++ )
974             if ( show_cpufreq_para_by_cpuid(xc_handle, i) == -ENODEV )
975                 break;
976     }
977     else
978         show_cpufreq_para_by_cpuid(xc_handle, cpuid);
979 }
980 
scaling_max_freq_func(int argc,char * argv[])981 void scaling_max_freq_func(int argc, char *argv[])
982 {
983     int cpuid = -1, freq = -1;
984 
985     parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency");
986 
987     if ( cpuid < 0 )
988     {
989         int i;
990         for ( i = 0; i < max_cpu_nr; i++ )
991             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MAX_FREQ, freq) )
992                 fprintf(stderr,
993                         "[CPU%d] failed to set scaling max freq (%d - %s)\n",
994                         i, errno, strerror(errno));
995     }
996     else
997     {
998         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MAX_FREQ, freq) )
999             fprintf(stderr, "failed to set scaling max freq (%d - %s)\n",
1000                     errno, strerror(errno));
1001     }
1002 }
1003 
scaling_min_freq_func(int argc,char * argv[])1004 void scaling_min_freq_func(int argc, char *argv[])
1005 {
1006     int cpuid = -1, freq = -1;
1007 
1008     parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency");
1009 
1010     if ( cpuid < 0 )
1011     {
1012         int i;
1013         for ( i = 0; i < max_cpu_nr; i++ )
1014             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MIN_FREQ, freq) )
1015                 fprintf(stderr,
1016                         "[CPU%d] failed to set scaling min freq (%d - %s)\n",
1017                         i, errno, strerror(errno));
1018     }
1019     else
1020     {
1021         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MIN_FREQ, freq) )
1022             fprintf(stderr, "failed to set scaling min freq (%d - %s)\n",
1023                     errno, strerror(errno));
1024     }
1025 }
1026 
scaling_speed_func(int argc,char * argv[])1027 void scaling_speed_func(int argc, char *argv[])
1028 {
1029     int cpuid = -1, speed = -1;
1030 
1031     parse_cpuid_and_int(argc, argv, &cpuid, &speed, "speed");
1032 
1033     if ( cpuid < 0 )
1034     {
1035         int i;
1036         for ( i = 0; i < max_cpu_nr; i++ )
1037             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_SETSPEED, speed) )
1038                 fprintf(stderr,
1039                         "[CPU%d] failed to set scaling speed (%d - %s)\n",
1040                         i, errno, strerror(errno));
1041     }
1042     else
1043     {
1044         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_SETSPEED, speed) )
1045             fprintf(stderr, "failed to set scaling speed (%d - %s)\n",
1046                     errno, strerror(errno));
1047     }
1048 }
1049 
scaling_sampling_rate_func(int argc,char * argv[])1050 void scaling_sampling_rate_func(int argc, char *argv[])
1051 {
1052     int cpuid = -1, rate = -1;
1053 
1054     parse_cpuid_and_int(argc, argv, &cpuid, &rate, "rate");
1055 
1056     if ( cpuid < 0 )
1057     {
1058         int i;
1059         for ( i = 0; i < max_cpu_nr; i++ )
1060             if ( xc_set_cpufreq_para(xc_handle, i, SAMPLING_RATE, rate) )
1061                 fprintf(stderr,
1062                         "[CPU%d] failed to set scaling sampling rate (%d - %s)\n",
1063                         i, errno, strerror(errno));
1064     }
1065     else
1066     {
1067         if ( xc_set_cpufreq_para(xc_handle, cpuid, SAMPLING_RATE, rate) )
1068             fprintf(stderr, "failed to set scaling sampling rate (%d - %s)\n",
1069                     errno, strerror(errno));
1070     }
1071 }
1072 
scaling_up_threshold_func(int argc,char * argv[])1073 void scaling_up_threshold_func(int argc, char *argv[])
1074 {
1075     int cpuid = -1, threshold = -1;
1076 
1077     parse_cpuid_and_int(argc, argv, &cpuid, &threshold, "threshold");
1078 
1079     if ( cpuid < 0 )
1080     {
1081         int i;
1082         for ( i = 0; i < max_cpu_nr; i++ )
1083             if ( xc_set_cpufreq_para(xc_handle, i, UP_THRESHOLD, threshold) )
1084                 fprintf(stderr,
1085                         "[CPU%d] failed to set up scaling threshold (%d - %s)\n",
1086                         i, errno, strerror(errno));
1087     }
1088     else
1089     {
1090         if ( xc_set_cpufreq_para(xc_handle, cpuid, UP_THRESHOLD, threshold) )
1091             fprintf(stderr, "failed to set up scaling threshold (%d - %s)\n",
1092                     errno, strerror(errno));
1093     }
1094 }
1095 
scaling_governor_func(int argc,char * argv[])1096 void scaling_governor_func(int argc, char *argv[])
1097 {
1098     int cpuid = -1;
1099     char *name;
1100 
1101     if ( argc >= 2 )
1102     {
1103         parse_cpuid(argv[0], &cpuid);
1104         name = argv[1];
1105     }
1106     else if ( argc > 0 )
1107         name = argv[0];
1108     else
1109     {
1110         fprintf(stderr, "Missing argument(s)\n");
1111         exit(EINVAL);
1112     }
1113 
1114     if ( cpuid < 0 )
1115     {
1116         int i;
1117         for ( i = 0; i < max_cpu_nr; i++ )
1118             if ( xc_set_cpufreq_gov(xc_handle, i, name) )
1119                 fprintf(stderr, "[CPU%d] failed to set governor name (%d - %s)\n",
1120                         i, errno, strerror(errno));
1121     }
1122     else
1123     {
1124         if ( xc_set_cpufreq_gov(xc_handle, cpuid, name) )
1125             fprintf(stderr, "failed to set governor name (%d - %s)\n",
1126                     errno, strerror(errno));
1127     }
1128 }
1129 
cpu_topology_func(int argc,char * argv[])1130 void cpu_topology_func(int argc, char *argv[])
1131 {
1132     xc_cputopo_t *cputopo = NULL;
1133     unsigned max_cpus = 0;
1134     int i, rc;
1135 
1136     if ( xc_cputopoinfo(xc_handle, &max_cpus, NULL) != 0 )
1137     {
1138         rc = errno;
1139         fprintf(stderr, "failed to discover number of CPUs (%d - %s)\n",
1140                 errno, strerror(errno));
1141         goto out;
1142     }
1143 
1144     cputopo = calloc(max_cpus, sizeof(*cputopo));
1145     if ( cputopo == NULL )
1146     {
1147 	rc = ENOMEM;
1148 	fprintf(stderr, "failed to allocate hypercall buffers\n");
1149 	goto out;
1150     }
1151 
1152     if ( xc_cputopoinfo(xc_handle, &max_cpus, cputopo) )
1153     {
1154         rc = errno;
1155         fprintf(stderr, "Cannot get Xen CPU topology (%d - %s)\n",
1156                 errno, strerror(errno));
1157         goto out;
1158     }
1159 
1160     printf("CPU\tcore\tsocket\tnode\n");
1161     for ( i = 0; i < max_cpus; i++ )
1162     {
1163         if ( cputopo[i].core == XEN_INVALID_CORE_ID )
1164             continue;
1165         printf("CPU%d\t %d\t %d\t %d\n",
1166                i, cputopo[i].core, cputopo[i].socket, cputopo[i].node);
1167     }
1168     rc = 0;
1169 out:
1170     free(cputopo);
1171     if ( rc )
1172         exit(rc);
1173 }
1174 
set_sched_smt_func(int argc,char * argv[])1175 void set_sched_smt_func(int argc, char *argv[])
1176 {
1177     int value;
1178 
1179     if ( argc != 1 ) {
1180         fprintf(stderr, "Missing or invalid argument(s)\n");
1181         exit(EINVAL);
1182     }
1183 
1184     if ( !strcasecmp(argv[0], "disable") )
1185         value = 0;
1186     else if ( !strcasecmp(argv[0], "enable") )
1187         value = 1;
1188     else
1189     {
1190         fprintf(stderr, "Invalid argument: %s\n", argv[0]);
1191         exit(EINVAL);
1192     }
1193 
1194     if ( !xc_set_sched_opt_smt(xc_handle, value) )
1195         printf("%s sched_smt_power_savings succeeded\n", argv[0]);
1196     else
1197         fprintf(stderr, "%s sched_smt_power_savings failed (%d - %s)\n",
1198                 argv[0], errno, strerror(errno));
1199 }
1200 
set_vcpu_migration_delay_func(int argc,char * argv[])1201 void set_vcpu_migration_delay_func(int argc, char *argv[])
1202 {
1203     struct xen_sysctl_credit_schedule sparam;
1204     int value;
1205 
1206     fprintf(stderr, "WARNING: using xenpm for this purpose is deprecated."
1207            " Check out `xl sched-credit -s -m DELAY'\n");
1208 
1209     if ( argc != 1 || (value = atoi(argv[0])) < 0 ) {
1210         fprintf(stderr, "Missing or invalid argument(s)\n");
1211         exit(EINVAL);
1212     }
1213 
1214     if ( xc_sched_credit_params_get(xc_handle, 0, &sparam) < 0 ) {
1215         fprintf(stderr, "getting Credit scheduler parameters failed\n");
1216         exit(EINVAL);
1217     }
1218     sparam.vcpu_migr_delay_us = value;
1219 
1220     if ( !xc_sched_credit_params_set(xc_handle, 0, &sparam) )
1221         printf("set vcpu migration delay to %d us succeeded\n", value);
1222     else
1223         fprintf(stderr, "set vcpu migration delay failed (%d - %s)\n",
1224                 errno, strerror(errno));
1225 }
1226 
get_vcpu_migration_delay_func(int argc,char * argv[])1227 void get_vcpu_migration_delay_func(int argc, char *argv[])
1228 {
1229     struct xen_sysctl_credit_schedule sparam;
1230 
1231     fprintf(stderr, "WARNING: using xenpm for this purpose is deprecated."
1232            " Check out `xl sched-credit -s'\n");
1233 
1234     if ( argc )
1235         fprintf(stderr, "Ignoring argument(s)\n");
1236 
1237     if ( !xc_sched_credit_params_get(xc_handle, 0, &sparam) )
1238         printf("Scheduler vcpu migration delay is %d us\n",
1239                sparam.vcpu_migr_delay_us);
1240     else
1241         fprintf(stderr,
1242                 "Failed to get scheduler vcpu migration delay (%d - %s)\n",
1243                 errno, strerror(errno));
1244 }
1245 
set_max_cstate_func(int argc,char * argv[])1246 void set_max_cstate_func(int argc, char *argv[])
1247 {
1248     int value, subval = XEN_SYSCTL_CX_UNLIMITED;
1249     char buf[12];
1250 
1251     if ( argc < 1 || argc > 2 ||
1252          (sscanf(argv[0], "%d", &value) == 1
1253           ? value < 0
1254           : (value = XEN_SYSCTL_CX_UNLIMITED, strcmp(argv[0], "unlimited"))) ||
1255          (argc == 2 &&
1256           (sscanf(argv[1], "%d", &subval) == 1
1257            ? subval < 0
1258            : (subval = XEN_SYSCTL_CX_UNLIMITED, strcmp(argv[1], "unlimited")))) )
1259     {
1260         fprintf(stderr, "Missing, excess, or invalid argument(s)\n");
1261         exit(EINVAL);
1262     }
1263 
1264     snprintf(buf, ARRAY_SIZE(buf), "C%d", value);
1265 
1266     if ( !xc_set_cpuidle_max_cstate(xc_handle, (uint32_t)value) )
1267         printf("max C-state set to %s\n", value >= 0 ? buf : argv[0]);
1268     else
1269     {
1270         fprintf(stderr, "Failed to set max C-state to %s (%d - %s)\n",
1271                 value >= 0 ? buf : argv[0], errno, strerror(errno));
1272         return;
1273     }
1274 
1275     if ( value != XEN_SYSCTL_CX_UNLIMITED )
1276     {
1277         snprintf(buf, ARRAY_SIZE(buf), "%d", subval);
1278 
1279         if ( !xc_set_cpuidle_max_csubstate(xc_handle, (uint32_t)subval) )
1280             printf("max C-substate set to %s succeeded\n",
1281                    subval >= 0 ? buf : "unlimited");
1282         else
1283             fprintf(stderr, "Failed to set max C-substate to %s (%d - %s)\n",
1284                     subval >= 0 ? buf : "unlimited", errno, strerror(errno));
1285     }
1286 }
1287 
enable_turbo_mode(int argc,char * argv[])1288 void enable_turbo_mode(int argc, char *argv[])
1289 {
1290     int cpuid = -1;
1291 
1292     if ( argc > 0 )
1293         parse_cpuid(argv[0], &cpuid);
1294 
1295     if ( cpuid < 0 )
1296     {
1297         /* enable turbo modes on all cpus,
1298          * only make effects on dbs governor */
1299         int i;
1300         for ( i = 0; i < max_cpu_nr; i++ )
1301             if ( xc_enable_turbo(xc_handle, i) )
1302                 fprintf(stderr,
1303                         "[CPU%d] failed to enable turbo mode (%d - %s)\n",
1304                         i, errno, strerror(errno));
1305     }
1306     else if ( xc_enable_turbo(xc_handle, cpuid) )
1307         fprintf(stderr, "failed to enable turbo mode (%d - %s)\n",
1308                 errno, strerror(errno));
1309 }
1310 
disable_turbo_mode(int argc,char * argv[])1311 void disable_turbo_mode(int argc, char *argv[])
1312 {
1313     int cpuid = -1;
1314 
1315     if ( argc > 0 )
1316         parse_cpuid(argv[0], &cpuid);
1317 
1318     if ( cpuid < 0 )
1319     {
1320         /* disable turbo modes on all cpus,
1321          * only make effects on dbs governor */
1322         int i;
1323         for ( i = 0; i < max_cpu_nr; i++ )
1324             if ( xc_disable_turbo(xc_handle, i) )
1325                 fprintf(stderr,
1326                         "[CPU%d] failed to disable turbo mode (%d - %s)\n",
1327                         i, errno, strerror(errno));
1328     }
1329     else if ( xc_disable_turbo(xc_handle, cpuid) )
1330         fprintf(stderr, "failed to disable turbo mode (%d - %s)\n",
1331                 errno, strerror(errno));
1332 }
1333 
1334 /*
1335  * Parse activity_window:NNN{us,ms,s} and validate range.
1336  *
1337  * Activity window is a 7bit mantissa (0-127) with a 3bit exponent (0-7) base
1338  * 10 in microseconds.  So the range is 1 microsecond to 1270 seconds.  A value
1339  * of 0 lets the hardware autonomously select the window.
1340  *
1341  * Return 0 on success
1342  *       -1 on error
1343  */
parse_activity_window(xc_set_cppc_para_t * set_cppc,unsigned long u,const char * suffix)1344 static int parse_activity_window(xc_set_cppc_para_t *set_cppc, unsigned long u,
1345                                  const char *suffix)
1346 {
1347     unsigned int exponent = 0;
1348     unsigned int multiplier = 1;
1349 
1350     if ( suffix && suffix[0] )
1351     {
1352         if ( strcmp(suffix, "s") == 0 )
1353         {
1354             multiplier = 1000 * 1000;
1355             exponent = 6;
1356         }
1357         else if ( strcmp(suffix, "ms") == 0 )
1358         {
1359             multiplier = 1000;
1360             exponent = 3;
1361         }
1362         else if ( strcmp(suffix, "us") != 0 )
1363         {
1364             fprintf(stderr, "invalid activity window units: \"%s\"\n", suffix);
1365 
1366             return -1;
1367         }
1368     }
1369 
1370     /* u * multipler > 1270 * 1000 * 1000 transformed to avoid overflow. */
1371     if ( u > 1270 * 1000 * 1000 / multiplier )
1372     {
1373         fprintf(stderr, "activity window is too large\n");
1374 
1375         return -1;
1376     }
1377 
1378     /* looking for 7 bits of mantissa and 3 bits of exponent */
1379     while ( u > 127 )
1380     {
1381         u += 5; /* Round up to mitigate truncation rounding down
1382                    e.g. 128 -> 120 vs 128 -> 130. */
1383         u /= 10;
1384         exponent += 1;
1385     }
1386 
1387     set_cppc->activity_window =
1388         MASK_INSR(exponent, XEN_CPPC_ACT_WINDOW_EXPONENT_MASK) |
1389         MASK_INSR(u, XEN_CPPC_ACT_WINDOW_MANTISSA_MASK);
1390     set_cppc->set_params |= XEN_SYSCTL_CPPC_SET_ACT_WINDOW;
1391 
1392     return 0;
1393 }
1394 
parse_cppc_opts(xc_set_cppc_para_t * set_cppc,int * cpuid,int argc,char * argv[])1395 static int parse_cppc_opts(xc_set_cppc_para_t *set_cppc, int *cpuid,
1396                            int argc, char *argv[])
1397 {
1398     int i = 0;
1399 
1400     if ( argc < 1 )
1401     {
1402         fprintf(stderr, "Missing arguments\n");
1403         return -1;
1404     }
1405 
1406     if ( isdigit(argv[i][0]) )
1407     {
1408         if ( sscanf(argv[i], "%d", cpuid) != 1 || *cpuid < 0 )
1409         {
1410             fprintf(stderr, "Could not parse cpuid \"%s\"\n", argv[i]);
1411             return -1;
1412         }
1413 
1414         i++;
1415     }
1416 
1417     if ( i == argc )
1418     {
1419         fprintf(stderr, "Missing arguments\n");
1420         return -1;
1421     }
1422 
1423     if ( strcasecmp(argv[i], "powersave") == 0 )
1424     {
1425         set_cppc->set_params = XEN_SYSCTL_CPPC_SET_PRESET_POWERSAVE;
1426         i++;
1427     }
1428     else if ( strcasecmp(argv[i], "performance") == 0 )
1429     {
1430         set_cppc->set_params = XEN_SYSCTL_CPPC_SET_PRESET_PERFORMANCE;
1431         i++;
1432     }
1433     else if ( strcasecmp(argv[i], "balance") == 0 )
1434     {
1435         set_cppc->set_params = XEN_SYSCTL_CPPC_SET_PRESET_BALANCE;
1436         i++;
1437     }
1438 
1439     for ( ; i < argc; i++)
1440     {
1441         unsigned long val;
1442         char *param = argv[i];
1443         char *value;
1444         char *suffix;
1445         int ret;
1446 
1447         value = strchr(param, ':');
1448         if ( value == NULL )
1449         {
1450             fprintf(stderr, "\"%s\" is an invalid cppc parameter\n", argv[i]);
1451             return -1;
1452         }
1453 
1454         value[0] = '\0';
1455         value++;
1456 
1457         errno = 0;
1458         val = strtoul(value, &suffix, 10);
1459         if ( (errno && val == ULONG_MAX) || value == suffix )
1460         {
1461             fprintf(stderr, "Could not parse number \"%s\"\n", value);
1462             return -1;
1463         }
1464 
1465         if ( strncasecmp(param, "act-window", strlen(param)) == 0 )
1466         {
1467             ret = parse_activity_window(set_cppc, val, suffix);
1468             if (ret)
1469                 return -1;
1470 
1471             continue;
1472         }
1473 
1474         if ( val > 255 )
1475         {
1476             fprintf(stderr, "\"%s\" value \"%lu\" is out of range\n", param,
1477                     val);
1478             return -1;
1479         }
1480 
1481         if ( suffix && suffix[0] )
1482         {
1483             fprintf(stderr, "Suffix \"%s\" is invalid\n", suffix);
1484             return -1;
1485         }
1486 
1487         if ( strncasecmp(param, "minimum", MAX(2, strlen(param))) == 0 )
1488         {
1489             set_cppc->minimum = val;
1490             set_cppc->set_params |= XEN_SYSCTL_CPPC_SET_MINIMUM;
1491         }
1492         else if ( strncasecmp(param, "maximum", MAX(2, strlen(param))) == 0 )
1493         {
1494             set_cppc->maximum = val;
1495             set_cppc->set_params |= XEN_SYSCTL_CPPC_SET_MAXIMUM;
1496         }
1497         else if ( strncasecmp(param, "desired", strlen(param)) == 0 )
1498         {
1499             set_cppc->desired = val;
1500             set_cppc->set_params |= XEN_SYSCTL_CPPC_SET_DESIRED;
1501         }
1502         else if ( strncasecmp(param, "energy-perf", strlen(param)) == 0 )
1503         {
1504             set_cppc->energy_perf = val;
1505             set_cppc->set_params |= XEN_SYSCTL_CPPC_SET_ENERGY_PERF;
1506         }
1507         else
1508         {
1509             fprintf(stderr, "\"%s\" is an invalid parameter\n", param);
1510             return -1;
1511         }
1512     }
1513 
1514     if ( set_cppc->set_params == 0 )
1515     {
1516         fprintf(stderr, "No parameters set in request\n");
1517         return -1;
1518     }
1519 
1520     return 0;
1521 }
1522 
cppc_set_func(int argc,char * argv[])1523 static void cppc_set_func(int argc, char *argv[])
1524 {
1525     xc_set_cppc_para_t set_cppc = {};
1526     unsigned int max_cpuid = max_cpu_nr;
1527     int cpuid = -1;
1528     unsigned int i = 0;
1529     uint32_t set_params;
1530 
1531     if ( parse_cppc_opts(&set_cppc, &cpuid, argc, argv) )
1532         exit(EINVAL);
1533 
1534     if ( cpuid != -1 )
1535     {
1536         i = cpuid;
1537         max_cpuid = i + 1;
1538     }
1539 
1540     set_params = set_cppc.set_params;
1541     for ( ; i < max_cpuid; i++ ) {
1542         if ( xc_set_cpufreq_cppc(xc_handle, i, &set_cppc) )
1543             fprintf(stderr, "[CPU%d] failed to set cppc params (%d - %s)\n",
1544                     i, errno, strerror(errno));
1545     }
1546 
1547     if ( (set_params ^ set_cppc.set_params) & XEN_SYSCTL_CPPC_SET_ACT_WINDOW )
1548         printf("Activity window not supported and omitted\n");
1549 }
1550 
1551 struct {
1552     const char *name;
1553     void (*function)(int argc, char *argv[]);
1554 } main_options[] = {
1555     { "help", help_func },
1556     { "get-cpuidle-states", cxstat_func },
1557     { "get-cpufreq-states", pxstat_func },
1558     { "get-cpufreq-average", cpufreq_func },
1559     { "start", start_gather_func },
1560     { "get-cpufreq-para", cpufreq_para_func },
1561     { "set-cpufreq-cppc", cppc_set_func },
1562     { "set-scaling-maxfreq", scaling_max_freq_func },
1563     { "set-scaling-minfreq", scaling_min_freq_func },
1564     { "set-scaling-governor", scaling_governor_func },
1565     { "set-scaling-speed", scaling_speed_func },
1566     { "set-sampling-rate", scaling_sampling_rate_func },
1567     { "set-up-threshold", scaling_up_threshold_func },
1568     { "get-cpu-topology", cpu_topology_func},
1569     { "set-sched-smt", set_sched_smt_func},
1570     { "get-vcpu-migration-delay", get_vcpu_migration_delay_func},
1571     { "set-vcpu-migration-delay", set_vcpu_migration_delay_func},
1572     { "set-max-cstate", set_max_cstate_func},
1573     { "enable-turbo-mode", enable_turbo_mode },
1574     { "disable-turbo-mode", disable_turbo_mode },
1575 };
1576 
main(int argc,char * argv[])1577 int main(int argc, char *argv[])
1578 {
1579     int i, ret = 0;
1580     xc_physinfo_t physinfo;
1581     int nr_matches = 0;
1582     int matches_main_options[ARRAY_SIZE(main_options)];
1583 
1584     if ( argc < 2 )
1585     {
1586         show_help();
1587         return 0;
1588     }
1589 
1590     xc_handle = xc_interface_open(0,0,0);
1591     if ( !xc_handle )
1592     {
1593         fprintf(stderr, "failed to get the handler\n");
1594         return EIO;
1595     }
1596 
1597     ret = xc_physinfo(xc_handle, &physinfo);
1598     if ( ret )
1599     {
1600         ret = errno;
1601         fprintf(stderr, "failed to get processor information (%d - %s)\n",
1602                 ret, strerror(ret));
1603         xc_interface_close(xc_handle);
1604         return ret;
1605     }
1606     max_cpu_nr = physinfo.max_cpu_id + 1;
1607 
1608     /* calculate how many options match with user's input */
1609     for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
1610         if ( !strncmp(main_options[i].name, argv[1], strlen(argv[1])) )
1611             matches_main_options[nr_matches++] = i;
1612 
1613     if ( nr_matches > 1 )
1614     {
1615         fprintf(stderr, "Ambiguous options: ");
1616         for ( i = 0; i < nr_matches; i++ )
1617             fprintf(stderr, " %s", main_options[matches_main_options[i]].name);
1618         fprintf(stderr, "\n");
1619         ret = EINVAL;
1620     }
1621     else if ( nr_matches == 1 )
1622         /* dispatch to the corresponding function handler */
1623         main_options[matches_main_options[0]].function(argc - 2, argv + 2);
1624     else
1625     {
1626         show_help();
1627         ret = EINVAL;
1628     }
1629 
1630     xc_interface_close(xc_handle);
1631     return ret;
1632 }
1633 
1634