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 <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <errno.h>
25 #include <signal.h>
26 
27 #include <xenctrl.h>
28 #include <inttypes.h>
29 #include <sys/time.h>
30 
31 #include <xen-tools/libs.h>
32 
33 #define MAX_PKG_RESIDENCIES 12
34 #define MAX_CORE_RESIDENCIES 8
35 
36 static xc_interface *xc_handle;
37 static unsigned int max_cpu_nr;
38 
39 /* help message */
show_help(void)40 void show_help(void)
41 {
42     fprintf(stderr,
43             "xen power management control tool\n\n"
44             "usage: xenpm <command> [args]\n\n"
45             "xenpm command list:\n\n"
46             " get-cpuidle-states    [cpuid]       list cpu idle info of CPU <cpuid> or all\n"
47             " get-cpufreq-states    [cpuid]       list cpu freq info of CPU <cpuid> or all\n"
48             " get-cpufreq-average   [cpuid]       average cpu frequency since last invocation\n"
49             "                                     for CPU <cpuid> or all\n"
50             " get-cpufreq-para      [cpuid]       list cpu freq parameter of CPU <cpuid> or all\n"
51             " set-scaling-maxfreq   [cpuid] <HZ>  set max cpu frequency <HZ> on CPU <cpuid>\n"
52             "                                     or all CPUs\n"
53             " set-scaling-minfreq   [cpuid] <HZ>  set min cpu frequency <HZ> on CPU <cpuid>\n"
54             "                                     or all CPUs\n"
55             " set-scaling-speed     [cpuid] <num> set scaling speed on CPU <cpuid> or all\n"
56             "                                     it is used in userspace governor.\n"
57             " set-scaling-governor  [cpuid] <gov> set scaling governor on CPU <cpuid> or all\n"
58             "                                     as userspace/performance/powersave/ondemand\n"
59             " set-sampling-rate     [cpuid] <num> set sampling rate on CPU <cpuid> or all\n"
60             "                                     it is used in ondemand governor.\n"
61             " set-up-threshold      [cpuid] <num> set up threshold on CPU <cpuid> or all\n"
62             "                                     it is used in ondemand governor.\n"
63             " get-cpu-topology                    get thread/core/socket topology info\n"
64             " set-sched-smt           enable|disable enable/disable scheduler smt power saving\n"
65             " set-vcpu-migration-delay      <num> set scheduler vcpu migration delay in us\n"
66             " get-vcpu-migration-delay            get scheduler vcpu migration delay\n"
67             " set-max-cstate        <num>|'unlimited' [<num2>|'unlimited']\n"
68             "                                     set the C-State limitation (<num> >= 0) and\n"
69             "                                     optionally the C-sub-state limitation (<num2> >= 0)\n"
70             " start [seconds]                     start collect Cx/Px statistics,\n"
71             "                                     output after CTRL-C or SIGINT or several seconds.\n"
72             " enable-turbo-mode     [cpuid]       enable Turbo Mode for processors that support it.\n"
73             " disable-turbo-mode    [cpuid]       disable Turbo Mode for processors that support it.\n"
74             );
75 }
76 /* wrapper function */
help_func(int argc,char * argv[])77 void help_func(int argc, char *argv[])
78 {
79     show_help();
80 }
81 
parse_cpuid(const char * arg,int * cpuid)82 static void parse_cpuid(const char *arg, int *cpuid)
83 {
84     if ( sscanf(arg, "%d", cpuid) != 1 || *cpuid < 0 )
85     {
86         if ( strcasecmp(arg, "all") )
87         {
88             fprintf(stderr, "Invalid CPU identifier: '%s'\n", arg);
89             exit(EINVAL);
90         }
91         *cpuid = -1;
92     }
93 }
94 
parse_cpuid_and_int(int argc,char * argv[],int * cpuid,int * val,const char * what)95 static void parse_cpuid_and_int(int argc, char *argv[],
96                                 int *cpuid, int *val, const char *what)
97 {
98     if ( argc == 0 )
99     {
100          fprintf(stderr, "Missing %s\n", what);
101          exit(EINVAL);
102     }
103 
104     if ( argc > 1 )
105         parse_cpuid(argv[0], cpuid);
106 
107     if ( sscanf(argv[argc > 1], "%d", val) != 1 )
108     {
109         fprintf(stderr, "Invalid %s '%s'\n", what, argv[argc > 1]);
110         exit(EINVAL);
111     }
112 }
113 
print_cxstat(int cpuid,struct xc_cx_stat * cxstat)114 static void print_cxstat(int cpuid, struct xc_cx_stat *cxstat)
115 {
116     unsigned int i;
117 
118     printf("cpu id               : %d\n", cpuid);
119     printf("total C-states       : %d\n", cxstat->nr);
120     printf("idle time(ms)        : %"PRIu64"\n",
121            cxstat->idle_time/1000000UL);
122     for ( i = 0; i < cxstat->nr; i++ )
123     {
124         printf("C%-20d: transition [%20"PRIu64"]\n",
125                i, cxstat->triggers[i]);
126         printf("                       residency  [%20"PRIu64" ms]\n",
127                cxstat->residencies[i]/1000000UL);
128     }
129     for ( i = 0; i < MAX_PKG_RESIDENCIES && i < cxstat->nr_pc; ++i )
130         if ( cxstat->pc[i] )
131            printf("pc%d                  : [%20"PRIu64" ms]\n", i + 1,
132                   cxstat->pc[i] / 1000000UL);
133     for ( i = 0; i < MAX_CORE_RESIDENCIES && i < cxstat->nr_cc; ++i )
134         if ( cxstat->cc[i] )
135            printf("cc%d                  : [%20"PRIu64" ms]\n", i + 1,
136                   cxstat->cc[i] / 1000000UL);
137     printf("\n");
138 }
139 
140 /* show cpu idle information on CPU cpuid */
get_cxstat_by_cpuid(xc_interface * xc_handle,int cpuid,struct xc_cx_stat * cxstat)141 static int get_cxstat_by_cpuid(xc_interface *xc_handle, int cpuid, struct xc_cx_stat *cxstat)
142 {
143     int ret = 0;
144     int max_cx_num = 0;
145 
146     ret = xc_pm_get_max_cx(xc_handle, cpuid, &max_cx_num);
147     if ( ret )
148         return -errno;
149 
150     if ( !cxstat )
151         return -EINVAL;
152 
153     if ( !max_cx_num )
154         return -ENODEV;
155 
156     cxstat->triggers = calloc(max_cx_num, sizeof(*cxstat->triggers));
157     cxstat->residencies = calloc(max_cx_num, sizeof(*cxstat->residencies));
158     cxstat->pc = calloc(MAX_PKG_RESIDENCIES, sizeof(*cxstat->pc));
159     cxstat->cc = calloc(MAX_CORE_RESIDENCIES, sizeof(*cxstat->cc));
160     if ( !cxstat->triggers || !cxstat->residencies ||
161          !cxstat->pc || !cxstat->cc )
162     {
163         free(cxstat->cc);
164         free(cxstat->pc);
165         free(cxstat->residencies);
166         free(cxstat->triggers);
167         return -ENOMEM;
168     }
169 
170     cxstat->nr = max_cx_num;
171     cxstat->nr_pc = MAX_PKG_RESIDENCIES;
172     cxstat->nr_cc = MAX_CORE_RESIDENCIES;
173 
174     ret = xc_pm_get_cxstat(xc_handle, cpuid, cxstat);
175     if( ret )
176     {
177         ret = -errno;
178         free(cxstat->triggers);
179         free(cxstat->residencies);
180         free(cxstat->pc);
181         free(cxstat->cc);
182         cxstat->triggers = NULL;
183         cxstat->residencies = NULL;
184         cxstat->pc = NULL;
185         cxstat->cc = NULL;
186     }
187 
188     return ret;
189 }
190 
show_max_cstate(xc_interface * xc_handle)191 static int show_max_cstate(xc_interface *xc_handle)
192 {
193     int ret = 0;
194     uint32_t value;
195 
196     if ( (ret = xc_get_cpuidle_max_cstate(xc_handle, &value)) )
197         return ret;
198 
199     if ( value < XEN_SYSCTL_CX_UNLIMITED )
200     {
201         printf("Max possible C-state: C%"PRIu32"\n", value);
202         if ( (ret = xc_get_cpuidle_max_csubstate(xc_handle, &value)) )
203             return ret;
204         if ( value < XEN_SYSCTL_CX_UNLIMITED )
205             printf("Max possible substate: %"PRIu32"\n\n", value);
206         else
207             puts("");
208     }
209     else
210         printf("All C-states allowed\n\n");
211 
212     return 0;
213 }
214 
show_cxstat_by_cpuid(xc_interface * xc_handle,int cpuid)215 static int show_cxstat_by_cpuid(xc_interface *xc_handle, int cpuid)
216 {
217     int ret = 0;
218     struct xc_cx_stat cxstatinfo;
219 
220     ret = get_cxstat_by_cpuid(xc_handle, cpuid, &cxstatinfo);
221     if ( ret )
222     {
223         if ( ret == -ENODEV )
224             fprintf(stderr,
225                     "Either Xen cpuidle is disabled or no valid information is registered!\n");
226         return ret;
227     }
228 
229     print_cxstat(cpuid, &cxstatinfo);
230 
231     free(cxstatinfo.triggers);
232     free(cxstatinfo.residencies);
233     free(cxstatinfo.pc);
234     free(cxstatinfo.cc);
235     return 0;
236 }
237 
cxstat_func(int argc,char * argv[])238 void cxstat_func(int argc, char *argv[])
239 {
240     int cpuid = -1;
241 
242     if ( argc > 0 )
243         parse_cpuid(argv[0], &cpuid);
244 
245     show_max_cstate(xc_handle);
246 
247     if ( cpuid < 0 )
248     {
249         /* show cxstates on all cpus */
250         int i;
251         for ( i = 0; i < max_cpu_nr; i++ )
252             if ( show_cxstat_by_cpuid(xc_handle, i) == -ENODEV )
253                 break;
254     }
255     else
256         show_cxstat_by_cpuid(xc_handle, cpuid);
257 }
258 
print_pxstat(int cpuid,struct xc_px_stat * pxstat)259 static void print_pxstat(int cpuid, struct xc_px_stat *pxstat)
260 {
261     int i;
262 
263     printf("cpu id               : %d\n", cpuid);
264     printf("total P-states       : %d\n", pxstat->total);
265     printf("usable P-states      : %d\n", pxstat->usable);
266     printf("current frequency    : %"PRIu64" MHz\n",
267            pxstat->pt[pxstat->cur].freq);
268     for ( i = 0; i < pxstat->total; i++ )
269     {
270         if ( pxstat->cur == i )
271             printf("*P%-9d", i);
272         else
273             printf("P%-10d", i);
274         printf("[%4"PRIu64" MHz]", pxstat->pt[i].freq);
275         printf(": transition [%20"PRIu64"]\n",
276                pxstat->pt[i].count);
277         printf("                       residency  [%20"PRIu64" ms]\n",
278                pxstat->pt[i].residency/1000000UL);
279     }
280     printf("\n");
281 }
282 
283 /* show cpu frequency information on CPU cpuid */
get_pxstat_by_cpuid(xc_interface * xc_handle,int cpuid,struct xc_px_stat * pxstat)284 static int get_pxstat_by_cpuid(xc_interface *xc_handle, int cpuid, struct xc_px_stat *pxstat)
285 {
286     int ret = 0;
287     int max_px_num = 0;
288 
289     ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px_num);
290     if ( ret )
291         return -errno;
292 
293     if ( !pxstat)
294         return -EINVAL;
295 
296     pxstat->trans_pt = malloc(max_px_num * max_px_num *
297                               sizeof(uint64_t));
298     if ( !pxstat->trans_pt )
299         return -ENOMEM;
300     pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val));
301     if ( !pxstat->pt )
302     {
303         free(pxstat->trans_pt);
304         return -ENOMEM;
305     }
306 
307     ret = xc_pm_get_pxstat(xc_handle, cpuid, pxstat);
308     if( ret )
309     {
310         ret = -errno;
311         free(pxstat->trans_pt);
312         free(pxstat->pt);
313         pxstat->trans_pt = NULL;
314         pxstat->pt = NULL;
315     }
316 
317     return ret;
318 }
319 
320 /* show cpu actual average freq information on CPU cpuid */
get_avgfreq_by_cpuid(xc_interface * xc_handle,int cpuid,int * avgfreq)321 static int get_avgfreq_by_cpuid(xc_interface *xc_handle, int cpuid, int *avgfreq)
322 {
323     int ret = 0;
324 
325     ret = xc_get_cpufreq_avgfreq(xc_handle, cpuid, avgfreq);
326     if ( ret )
327         ret = -errno;
328 
329     return ret;
330 }
331 
show_pxstat_by_cpuid(xc_interface * xc_handle,int cpuid)332 static int show_pxstat_by_cpuid(xc_interface *xc_handle, int cpuid)
333 {
334     int ret = 0;
335     struct xc_px_stat pxstatinfo;
336 
337     ret = get_pxstat_by_cpuid(xc_handle, cpuid, &pxstatinfo);
338     if ( ret )
339         return ret;
340 
341     print_pxstat(cpuid, &pxstatinfo);
342 
343     free(pxstatinfo.trans_pt);
344     free(pxstatinfo.pt);
345     return 0;
346 }
347 
pxstat_func(int argc,char * argv[])348 void pxstat_func(int argc, char *argv[])
349 {
350     int cpuid = -1;
351 
352     if ( argc > 0 )
353         parse_cpuid(argv[0], &cpuid);
354 
355     if ( cpuid < 0 )
356     {
357         /* show pxstates on all cpus */
358         int i;
359         for ( i = 0; i < max_cpu_nr; i++ )
360             if ( show_pxstat_by_cpuid(xc_handle, i) == -ENODEV )
361                 break;
362     }
363     else
364         show_pxstat_by_cpuid(xc_handle, cpuid);
365 }
366 
show_cpufreq_by_cpuid(xc_interface * xc_handle,int cpuid)367 static int show_cpufreq_by_cpuid(xc_interface *xc_handle, int cpuid)
368 {
369     int ret = 0;
370     int average_cpufreq;
371 
372     ret = get_avgfreq_by_cpuid(xc_handle, cpuid, &average_cpufreq);
373     if ( ret )
374         return ret;
375 
376     printf("cpu id               : %d\n", cpuid);
377     printf("average cpu frequency: %d\n", average_cpufreq);
378     printf("\n");
379     return 0;
380 }
381 
cpufreq_func(int argc,char * argv[])382 void cpufreq_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 average frequency on all cpus */
392         int i;
393         for ( i = 0; i < max_cpu_nr; i++ )
394             if ( show_cpufreq_by_cpuid(xc_handle, i) == -ENODEV )
395                 break;
396     }
397     else
398         show_cpufreq_by_cpuid(xc_handle, cpuid);
399 }
400 
401 static uint64_t usec_start, usec_end;
402 static struct xc_cx_stat *cxstat, *cxstat_start, *cxstat_end;
403 static struct xc_px_stat *pxstat, *pxstat_start, *pxstat_end;
404 static int *avgfreq;
405 static uint64_t *sum, *sum_cx, *sum_px;
406 
signal_int_handler(int signo)407 static void signal_int_handler(int signo)
408 {
409     int i, j, k;
410     struct timeval tv;
411     int cx_cap = 0, px_cap = 0;
412     xc_cputopo_t *cputopo = NULL;
413     unsigned max_cpus = 0;
414 
415     if ( xc_cputopoinfo(xc_handle, &max_cpus, NULL) != 0 )
416     {
417         fprintf(stderr, "failed to discover number of CPUs: %s\n",
418                 strerror(errno));
419         goto out;
420     }
421 
422     cputopo = calloc(max_cpus, sizeof(*cputopo));
423     if ( cputopo == NULL )
424     {
425 	fprintf(stderr, "failed to allocate hypercall buffers\n");
426 	goto out;
427     }
428 
429     if ( gettimeofday(&tv, NULL) )
430     {
431         fprintf(stderr, "failed to get timeofday\n");
432         goto out;
433     }
434     usec_end = tv.tv_sec * 1000000UL + tv.tv_usec;
435 
436     if ( get_cxstat_by_cpuid(xc_handle, 0, NULL) != -ENODEV )
437     {
438         cx_cap = 1;
439         for ( i = 0; i < max_cpu_nr; i++ )
440             if ( !get_cxstat_by_cpuid(xc_handle, i, &cxstat_end[i]) )
441                 for ( j = 0; j < cxstat_end[i].nr; j++ )
442                 {
443                     int64_t diff = (int64_t)cxstat_end[i].residencies[j] -
444                         (int64_t)cxstat_start[i].residencies[j];
445                     if ( diff >=0 )
446                         sum_cx[i] += diff;
447                 }
448     }
449 
450     if ( get_pxstat_by_cpuid(xc_handle, 0, NULL) != -ENODEV )
451     {
452         px_cap = 1;
453         for ( i = 0; i < max_cpu_nr; i++ )
454             if ( !get_pxstat_by_cpuid(xc_handle, i , &pxstat_end[i]) )
455                 for ( j = 0; j < pxstat_end[i].total; j++ )
456                     sum_px[i] += pxstat_end[i].pt[j].residency -
457                                  pxstat_start[i].pt[j].residency;
458     }
459 
460     for ( i = 0; i < max_cpu_nr; i++ )
461         get_avgfreq_by_cpuid(xc_handle, i, &avgfreq[i]);
462 
463     printf("Elapsed time (ms): %"PRIu64"\n", (usec_end - usec_start) / 1000UL);
464     for ( i = 0; i < max_cpu_nr; i++ )
465     {
466         uint64_t res, triggers;
467         double avg_res;
468 
469         printf("\nCPU%d:\tResidency(ms)\t\tAvg Res(ms)\n",i);
470         if ( cx_cap && sum_cx[i] > 0 )
471         {
472             for ( j = 0; j < cxstat_end[i].nr; j++ )
473             {
474                 int64_t diff = (int64_t)cxstat_end[i].residencies[j] -
475                     (int64_t)cxstat_start[i].residencies[j];
476 
477                 res = ( diff >= 0 ) ? diff : 0;
478                 triggers = cxstat_end[i].triggers[j] -
479                     cxstat_start[i].triggers[j];
480                 /*
481                  * triggers may be zero if the CPU has been in this state for
482                  * the whole sample or if it never entered the state
483                  */
484                 if ( triggers == 0 && cxstat_end[i].last == j )
485                     avg_res =  (double)sum_cx[i]/1000000.0;
486                 else
487                     avg_res = (triggers==0) ? 0: (double)res/triggers/1000000.0;
488                 printf("  C%d\t%"PRIu64"\t(%5.2f%%)\t%.2f\n", j, res/1000000UL,
489                         100 * res / (double)sum_cx[i], avg_res );
490             }
491             printf("\n");
492         }
493         if ( px_cap && sum_px[i]>0 )
494         {
495             for ( j = 0; j < pxstat_end[i].total; j++ )
496             {
497                 res = pxstat_end[i].pt[j].residency -
498                     pxstat_start[i].pt[j].residency;
499                 printf("  P%d\t%"PRIu64"\t(%5.2f%%)\n", j,
500                         res / 1000000UL, 100UL * res / (double)sum_px[i]);
501             }
502         }
503         if ( px_cap && avgfreq[i] )
504             printf("  Avg freq\t%d\tKHz\n", avgfreq[i]);
505     }
506 
507     if ( cx_cap && !xc_cputopoinfo(xc_handle, &max_cpus, cputopo) )
508     {
509         uint32_t socket_ids[MAX_NR_CPU];
510         uint32_t core_ids[MAX_NR_CPU];
511         uint32_t socket_nr = 0;
512         uint32_t core_nr = 0;
513 
514         if ( max_cpus > MAX_NR_CPU )
515             max_cpus = MAX_NR_CPU;
516         /* check validity */
517         for ( i = 0; i < max_cpus; i++ )
518         {
519             if ( cputopo[i].core == XEN_INVALID_CORE_ID ||
520                  cputopo[i].socket == XEN_INVALID_SOCKET_ID )
521                 break;
522         }
523         if ( i >= max_cpus )
524         {
525             /* find socket nr & core nr per socket */
526             for ( i = 0; i < max_cpus; i++ )
527             {
528                 for ( j = 0; j < socket_nr; j++ )
529                     if ( cputopo[i].socket == socket_ids[j] )
530                         break;
531                 if ( j == socket_nr )
532                 {
533                     socket_ids[j] = cputopo[i].socket;
534                     socket_nr++;
535                 }
536 
537                 for ( j = 0; j < core_nr; j++ )
538                     if ( cputopo[i].core == core_ids[j] )
539                         break;
540                 if ( j == core_nr )
541                 {
542                     core_ids[j] = cputopo[i].core;
543                     core_nr++;
544                 }
545             }
546 
547             /* print out CC? and PC? */
548             for ( i = 0; i < socket_nr; i++ )
549             {
550                 unsigned int n;
551                 uint64_t res;
552 
553                 for ( j = 0; j < max_cpus; j++ )
554                 {
555                     if ( cputopo[j].socket == socket_ids[i] )
556                         break;
557                 }
558                 printf("\nSocket %d\n", socket_ids[i]);
559                 for ( n = 0; n < MAX_PKG_RESIDENCIES; ++n )
560                 {
561                     if ( n >= cxstat_end[j].nr_pc )
562                         continue;
563                     res = cxstat_end[j].pc[n];
564                     if ( n < cxstat_start[j].nr_pc )
565                         res -= cxstat_start[j].pc[n];
566                     printf("\tPC%u\t%"PRIu64" ms\t%.2f%%\n",
567                            n + 1, res / 1000000UL,
568                            100UL * res / (double)sum_cx[j]);
569                 }
570                 for ( k = 0; k < core_nr; k++ )
571                 {
572                     for ( j = 0; j < max_cpus; j++ )
573                     {
574                         if ( cputopo[j].socket == socket_ids[i] &&
575                              cputopo[j].core == core_ids[k] )
576                             break;
577                     }
578                     printf("\t Core %d CPU %d\n", core_ids[k], j);
579                     for ( n = 0; n < MAX_CORE_RESIDENCIES; ++n )
580                     {
581                         if ( n >= cxstat_end[j].nr_cc )
582                             continue;
583                         res = cxstat_end[j].cc[n];
584                         if ( n < cxstat_start[j].nr_cc )
585                             res -= cxstat_start[j].cc[n];
586                         printf("\t\tCC%u\t%"PRIu64" ms\t%.2f%%\n",
587                                n + 1, res / 1000000UL,
588                                100UL * res / (double)sum_cx[j]);
589                     }
590                 }
591             }
592         }
593     }
594 
595     /* some clean up and then exits */
596     for ( i = 0; i < 2 * max_cpu_nr; i++ )
597     {
598         free(cxstat[i].triggers);
599         free(cxstat[i].residencies);
600         free(cxstat[i].pc);
601         free(cxstat[i].cc);
602         free(pxstat[i].trans_pt);
603         free(pxstat[i].pt);
604     }
605     free(cxstat);
606     free(pxstat);
607     free(sum);
608     free(avgfreq);
609 out:
610     free(cputopo);
611     xc_interface_close(xc_handle);
612     exit(0);
613 }
614 
start_gather_func(int argc,char * argv[])615 void start_gather_func(int argc, char *argv[])
616 {
617     int i;
618     struct timeval tv;
619     int timeout = 0;
620 
621     if ( argc == 1 )
622     {
623         sscanf(argv[0], "%d", &timeout);
624         if ( timeout <= 0 )
625             fprintf(stderr, "failed to set timeout seconds, falling back...\n");
626         else
627             printf("Timeout set to %d seconds\n", timeout);
628     }
629 
630     if ( gettimeofday(&tv, NULL) )
631     {
632         fprintf(stderr, "failed to get timeofday\n");
633         return ;
634     }
635     usec_start = tv.tv_sec * 1000000UL + tv.tv_usec;
636 
637     sum = calloc(2 * max_cpu_nr, sizeof(*sum));
638     if ( sum == NULL )
639         return ;
640     cxstat = calloc(2 * max_cpu_nr, sizeof(*cxstat));
641     if ( cxstat == NULL )
642     {
643         free(sum);
644         return ;
645     }
646     pxstat = calloc(2 * max_cpu_nr, sizeof(*pxstat));
647     if ( pxstat == NULL )
648     {
649         free(sum);
650         free(cxstat);
651         return ;
652     }
653     avgfreq = calloc(max_cpu_nr, sizeof(*avgfreq));
654     if ( avgfreq == NULL )
655     {
656         free(sum);
657         free(cxstat);
658         free(pxstat);
659         return ;
660     }
661     sum_cx = sum;
662     sum_px = sum + max_cpu_nr;
663     cxstat_start = cxstat;
664     cxstat_end = cxstat + max_cpu_nr;
665     pxstat_start = pxstat;
666     pxstat_end = pxstat + max_cpu_nr;
667 
668     if ( get_cxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV &&
669          get_pxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV )
670     {
671         fprintf(stderr, "Xen cpu idle and frequency is disabled!\n");
672         return ;
673     }
674 
675     for ( i = 0; i < max_cpu_nr; i++ )
676     {
677         get_cxstat_by_cpuid(xc_handle, i, &cxstat_start[i]);
678         get_pxstat_by_cpuid(xc_handle, i, &pxstat_start[i]);
679         get_avgfreq_by_cpuid(xc_handle, i, &avgfreq[i]);
680     }
681 
682     if (signal(SIGINT, signal_int_handler) == SIG_ERR)
683     {
684         fprintf(stderr, "failed to set signal int handler\n");
685         free(sum);
686         free(pxstat);
687         free(cxstat);
688         free(avgfreq);
689         return ;
690     }
691 
692     if ( timeout > 0 )
693     {
694         if ( signal(SIGALRM, signal_int_handler) == SIG_ERR )
695         {
696             fprintf(stderr, "failed to set signal alarm handler\n");
697             free(sum);
698             free(pxstat);
699             free(cxstat);
700             free(avgfreq);
701             return ;
702         }
703         alarm(timeout);
704     }
705 
706     printf("Start sampling, waiting for CTRL-C or SIGINT or SIGALARM signal ...\n");
707 
708     pause();
709 }
710 
711 /* print out parameters about cpu frequency */
print_cpufreq_para(int cpuid,struct xc_get_cpufreq_para * p_cpufreq)712 static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq)
713 {
714     int i;
715 
716     printf("cpu id               : %d\n", cpuid);
717 
718     printf("affected_cpus        :");
719     for ( i = 0; i < p_cpufreq->cpu_num; i++ )
720         printf(" %d", p_cpufreq->affected_cpus[i]);
721     printf("\n");
722 
723     printf("cpuinfo frequency    : max [%u] min [%u] cur [%u]\n",
724            p_cpufreq->cpuinfo_max_freq,
725            p_cpufreq->cpuinfo_min_freq,
726            p_cpufreq->cpuinfo_cur_freq);
727 
728     printf("scaling_driver       : %s\n", p_cpufreq->scaling_driver);
729 
730     printf("scaling_avail_gov    : %s\n",
731            p_cpufreq->scaling_available_governors);
732 
733     printf("current_governor     : %s\n", p_cpufreq->scaling_governor);
734     if ( !strncmp(p_cpufreq->scaling_governor,
735                   "userspace", CPUFREQ_NAME_LEN) )
736     {
737         printf("  userspace specific :\n");
738         printf("    scaling_setspeed : %u\n",
739                p_cpufreq->u.userspace.scaling_setspeed);
740     }
741     else if ( !strncmp(p_cpufreq->scaling_governor,
742                        "ondemand", CPUFREQ_NAME_LEN) )
743     {
744         printf("  ondemand specific  :\n");
745         printf("    sampling_rate    : max [%u] min [%u] cur [%u]\n",
746                p_cpufreq->u.ondemand.sampling_rate_max,
747                p_cpufreq->u.ondemand.sampling_rate_min,
748                p_cpufreq->u.ondemand.sampling_rate);
749         printf("    up_threshold     : %u\n",
750                p_cpufreq->u.ondemand.up_threshold);
751     }
752 
753     printf("scaling_avail_freq   :");
754     for ( i = 0; i < p_cpufreq->freq_num; i++ )
755         if ( p_cpufreq->scaling_available_frequencies[i] ==
756              p_cpufreq->scaling_cur_freq )
757             printf(" *%d", p_cpufreq->scaling_available_frequencies[i]);
758         else
759             printf(" %d", p_cpufreq->scaling_available_frequencies[i]);
760     printf("\n");
761 
762     printf("scaling frequency    : max [%u] min [%u] cur [%u]\n",
763            p_cpufreq->scaling_max_freq,
764            p_cpufreq->scaling_min_freq,
765            p_cpufreq->scaling_cur_freq);
766 
767     printf("turbo mode           : %s\n",
768            p_cpufreq->turbo_enabled ? "enabled" : "disabled or n/a");
769     printf("\n");
770 }
771 
772 /* show cpu frequency parameters information on CPU cpuid */
show_cpufreq_para_by_cpuid(xc_interface * xc_handle,int cpuid)773 static int show_cpufreq_para_by_cpuid(xc_interface *xc_handle, int cpuid)
774 {
775     int ret = 0;
776     struct xc_get_cpufreq_para cpufreq_para, *p_cpufreq = &cpufreq_para;
777 
778     p_cpufreq->cpu_num = 0;
779     p_cpufreq->freq_num = 0;
780     p_cpufreq->gov_num = 0;
781     p_cpufreq->affected_cpus = NULL;
782     p_cpufreq->scaling_available_frequencies = NULL;
783     p_cpufreq->scaling_available_governors = NULL;
784     p_cpufreq->turbo_enabled = 0;
785 
786     do
787     {
788         free(p_cpufreq->affected_cpus);
789         free(p_cpufreq->scaling_available_frequencies);
790         free(p_cpufreq->scaling_available_governors);
791 
792         p_cpufreq->affected_cpus = NULL;
793         p_cpufreq->scaling_available_frequencies = NULL;
794         p_cpufreq->scaling_available_governors = NULL;
795 
796         if (!(p_cpufreq->affected_cpus =
797               malloc(p_cpufreq->cpu_num * sizeof(uint32_t))))
798         {
799             fprintf(stderr,
800                     "[CPU%d] failed to malloc for affected_cpus\n",
801                     cpuid);
802             ret = -ENOMEM;
803             goto out;
804         }
805         if (!(p_cpufreq->scaling_available_frequencies =
806               malloc(p_cpufreq->freq_num * sizeof(uint32_t))))
807         {
808             fprintf(stderr,
809                     "[CPU%d] failed to malloc for scaling_available_frequencies\n",
810                     cpuid);
811             ret = -ENOMEM;
812             goto out;
813         }
814         if (!(p_cpufreq->scaling_available_governors =
815               malloc(p_cpufreq->gov_num * CPUFREQ_NAME_LEN * sizeof(char))))
816         {
817             fprintf(stderr,
818                     "[CPU%d] failed to malloc for scaling_available_governors\n",
819                     cpuid);
820             ret = -ENOMEM;
821             goto out;
822         }
823 
824         ret = xc_get_cpufreq_para(xc_handle, cpuid, p_cpufreq);
825     } while ( ret && errno == EAGAIN );
826 
827     if ( ret == 0 )
828         print_cpufreq_para(cpuid, p_cpufreq);
829     else if ( errno == ENODEV )
830     {
831         ret = -ENODEV;
832         fprintf(stderr, "Xen cpufreq is not enabled!\n");
833     }
834     else
835         fprintf(stderr,
836                 "[CPU%d] failed to get cpufreq parameter\n",
837                 cpuid);
838 
839 out:
840     free(p_cpufreq->scaling_available_governors);
841     free(p_cpufreq->scaling_available_frequencies);
842     free(p_cpufreq->affected_cpus);
843 
844     return ret;
845 }
846 
cpufreq_para_func(int argc,char * argv[])847 void cpufreq_para_func(int argc, char *argv[])
848 {
849     int cpuid = -1;
850 
851     if ( argc > 0 )
852         parse_cpuid(argv[0], &cpuid);
853 
854     if ( cpuid < 0 )
855     {
856         /* show cpu freqency information on all cpus */
857         int i;
858         for ( i = 0; i < max_cpu_nr; i++ )
859             if ( show_cpufreq_para_by_cpuid(xc_handle, i) == -ENODEV )
860                 break;
861     }
862     else
863         show_cpufreq_para_by_cpuid(xc_handle, cpuid);
864 }
865 
scaling_max_freq_func(int argc,char * argv[])866 void scaling_max_freq_func(int argc, char *argv[])
867 {
868     int cpuid = -1, freq = -1;
869 
870     parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency");
871 
872     if ( cpuid < 0 )
873     {
874         int i;
875         for ( i = 0; i < max_cpu_nr; i++ )
876             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MAX_FREQ, freq) )
877                 fprintf(stderr,
878                         "[CPU%d] failed to set scaling max freq (%d - %s)\n",
879                         i, errno, strerror(errno));
880     }
881     else
882     {
883         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MAX_FREQ, freq) )
884             fprintf(stderr, "failed to set scaling max freq (%d - %s)\n",
885                     errno, strerror(errno));
886     }
887 }
888 
scaling_min_freq_func(int argc,char * argv[])889 void scaling_min_freq_func(int argc, char *argv[])
890 {
891     int cpuid = -1, freq = -1;
892 
893     parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency");
894 
895     if ( cpuid < 0 )
896     {
897         int i;
898         for ( i = 0; i < max_cpu_nr; i++ )
899             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MIN_FREQ, freq) )
900                 fprintf(stderr,
901                         "[CPU%d] failed to set scaling min freq (%d - %s)\n",
902                         i, errno, strerror(errno));
903     }
904     else
905     {
906         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MIN_FREQ, freq) )
907             fprintf(stderr, "failed to set scaling min freq (%d - %s)\n",
908                     errno, strerror(errno));
909     }
910 }
911 
scaling_speed_func(int argc,char * argv[])912 void scaling_speed_func(int argc, char *argv[])
913 {
914     int cpuid = -1, speed = -1;
915 
916     parse_cpuid_and_int(argc, argv, &cpuid, &speed, "speed");
917 
918     if ( cpuid < 0 )
919     {
920         int i;
921         for ( i = 0; i < max_cpu_nr; i++ )
922             if ( xc_set_cpufreq_para(xc_handle, i, SCALING_SETSPEED, speed) )
923                 fprintf(stderr,
924                         "[CPU%d] failed to set scaling speed (%d - %s)\n",
925                         i, errno, strerror(errno));
926     }
927     else
928     {
929         if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_SETSPEED, speed) )
930             fprintf(stderr, "failed to set scaling speed (%d - %s)\n",
931                     errno, strerror(errno));
932     }
933 }
934 
scaling_sampling_rate_func(int argc,char * argv[])935 void scaling_sampling_rate_func(int argc, char *argv[])
936 {
937     int cpuid = -1, rate = -1;
938 
939     parse_cpuid_and_int(argc, argv, &cpuid, &rate, "rate");
940 
941     if ( cpuid < 0 )
942     {
943         int i;
944         for ( i = 0; i < max_cpu_nr; i++ )
945             if ( xc_set_cpufreq_para(xc_handle, i, SAMPLING_RATE, rate) )
946                 fprintf(stderr,
947                         "[CPU%d] failed to set scaling sampling rate (%d - %s)\n",
948                         i, errno, strerror(errno));
949     }
950     else
951     {
952         if ( xc_set_cpufreq_para(xc_handle, cpuid, SAMPLING_RATE, rate) )
953             fprintf(stderr, "failed to set scaling sampling rate (%d - %s)\n",
954                     errno, strerror(errno));
955     }
956 }
957 
scaling_up_threshold_func(int argc,char * argv[])958 void scaling_up_threshold_func(int argc, char *argv[])
959 {
960     int cpuid = -1, threshold = -1;
961 
962     parse_cpuid_and_int(argc, argv, &cpuid, &threshold, "threshold");
963 
964     if ( cpuid < 0 )
965     {
966         int i;
967         for ( i = 0; i < max_cpu_nr; i++ )
968             if ( xc_set_cpufreq_para(xc_handle, i, UP_THRESHOLD, threshold) )
969                 fprintf(stderr,
970                         "[CPU%d] failed to set up scaling threshold (%d - %s)\n",
971                         i, errno, strerror(errno));
972     }
973     else
974     {
975         if ( xc_set_cpufreq_para(xc_handle, cpuid, UP_THRESHOLD, threshold) )
976             fprintf(stderr, "failed to set up scaling threshold (%d - %s)\n",
977                     errno, strerror(errno));
978     }
979 }
980 
scaling_governor_func(int argc,char * argv[])981 void scaling_governor_func(int argc, char *argv[])
982 {
983     int cpuid = -1;
984     char *name;
985 
986     if ( argc >= 2 )
987     {
988         parse_cpuid(argv[0], &cpuid);
989         name = argv[1];
990     }
991     else if ( argc > 0 )
992         name = argv[0];
993     else
994     {
995         fprintf(stderr, "Missing argument(s)\n");
996         exit(EINVAL);
997     }
998 
999     if ( cpuid < 0 )
1000     {
1001         int i;
1002         for ( i = 0; i < max_cpu_nr; i++ )
1003             if ( xc_set_cpufreq_gov(xc_handle, i, name) )
1004                 fprintf(stderr, "[CPU%d] failed to set governor name (%d - %s)\n",
1005                         i, errno, strerror(errno));
1006     }
1007     else
1008     {
1009         if ( xc_set_cpufreq_gov(xc_handle, cpuid, name) )
1010             fprintf(stderr, "failed to set governor name (%d - %s)\n",
1011                     errno, strerror(errno));
1012     }
1013 }
1014 
cpu_topology_func(int argc,char * argv[])1015 void cpu_topology_func(int argc, char *argv[])
1016 {
1017     xc_cputopo_t *cputopo = NULL;
1018     unsigned max_cpus = 0;
1019     int i, rc;
1020 
1021     if ( xc_cputopoinfo(xc_handle, &max_cpus, NULL) != 0 )
1022     {
1023         rc = errno;
1024         fprintf(stderr, "failed to discover number of CPUs (%d - %s)\n",
1025                 errno, strerror(errno));
1026         goto out;
1027     }
1028 
1029     cputopo = calloc(max_cpus, sizeof(*cputopo));
1030     if ( cputopo == NULL )
1031     {
1032 	rc = ENOMEM;
1033 	fprintf(stderr, "failed to allocate hypercall buffers\n");
1034 	goto out;
1035     }
1036 
1037     if ( xc_cputopoinfo(xc_handle, &max_cpus, cputopo) )
1038     {
1039         rc = errno;
1040         fprintf(stderr, "Cannot get Xen CPU topology (%d - %s)\n",
1041                 errno, strerror(errno));
1042         goto out;
1043     }
1044 
1045     printf("CPU\tcore\tsocket\tnode\n");
1046     for ( i = 0; i < max_cpus; i++ )
1047     {
1048         if ( cputopo[i].core == XEN_INVALID_CORE_ID )
1049             continue;
1050         printf("CPU%d\t %d\t %d\t %d\n",
1051                i, cputopo[i].core, cputopo[i].socket, cputopo[i].node);
1052     }
1053     rc = 0;
1054 out:
1055     free(cputopo);
1056     if ( rc )
1057         exit(rc);
1058 }
1059 
set_sched_smt_func(int argc,char * argv[])1060 void set_sched_smt_func(int argc, char *argv[])
1061 {
1062     int value;
1063 
1064     if ( argc != 1 ) {
1065         fprintf(stderr, "Missing or invalid argument(s)\n");
1066         exit(EINVAL);
1067     }
1068 
1069     if ( !strcasecmp(argv[0], "disable") )
1070         value = 0;
1071     else if ( !strcasecmp(argv[0], "enable") )
1072         value = 1;
1073     else
1074     {
1075         fprintf(stderr, "Invalid argument: %s\n", argv[0]);
1076         exit(EINVAL);
1077     }
1078 
1079     if ( !xc_set_sched_opt_smt(xc_handle, value) )
1080         printf("%s sched_smt_power_savings succeeded\n", argv[0]);
1081     else
1082         fprintf(stderr, "%s sched_smt_power_savings failed (%d - %s)\n",
1083                 argv[0], errno, strerror(errno));
1084 }
1085 
set_vcpu_migration_delay_func(int argc,char * argv[])1086 void set_vcpu_migration_delay_func(int argc, char *argv[])
1087 {
1088     struct xen_sysctl_credit_schedule sparam;
1089     int value;
1090 
1091     fprintf(stderr, "WARNING: using xenpm for this purpose is deprecated."
1092            " Check out `xl sched-credit -s -m DELAY'\n");
1093 
1094     if ( argc != 1 || (value = atoi(argv[0])) < 0 ) {
1095         fprintf(stderr, "Missing or invalid argument(s)\n");
1096         exit(EINVAL);
1097     }
1098 
1099     if ( xc_sched_credit_params_get(xc_handle, 0, &sparam) < 0 ) {
1100         fprintf(stderr, "getting Credit scheduler parameters failed\n");
1101         exit(EINVAL);
1102     }
1103     sparam.vcpu_migr_delay_us = value;
1104 
1105     if ( !xc_sched_credit_params_set(xc_handle, 0, &sparam) )
1106         printf("set vcpu migration delay to %d us succeeded\n", value);
1107     else
1108         fprintf(stderr, "set vcpu migration delay failed (%d - %s)\n",
1109                 errno, strerror(errno));
1110 }
1111 
get_vcpu_migration_delay_func(int argc,char * argv[])1112 void get_vcpu_migration_delay_func(int argc, char *argv[])
1113 {
1114     struct xen_sysctl_credit_schedule sparam;
1115 
1116     fprintf(stderr, "WARNING: using xenpm for this purpose is deprecated."
1117            " Check out `xl sched-credit -s'\n");
1118 
1119     if ( argc )
1120         fprintf(stderr, "Ignoring argument(s)\n");
1121 
1122     if ( !xc_sched_credit_params_get(xc_handle, 0, &sparam) )
1123         printf("Scheduler vcpu migration delay is %d us\n",
1124                sparam.vcpu_migr_delay_us);
1125     else
1126         fprintf(stderr,
1127                 "Failed to get scheduler vcpu migration delay (%d - %s)\n",
1128                 errno, strerror(errno));
1129 }
1130 
set_max_cstate_func(int argc,char * argv[])1131 void set_max_cstate_func(int argc, char *argv[])
1132 {
1133     int value, subval = XEN_SYSCTL_CX_UNLIMITED;
1134     char buf[12];
1135 
1136     if ( argc < 1 || argc > 2 ||
1137          (sscanf(argv[0], "%d", &value) == 1
1138           ? value < 0
1139           : (value = XEN_SYSCTL_CX_UNLIMITED, strcmp(argv[0], "unlimited"))) ||
1140          (argc == 2 &&
1141           (sscanf(argv[1], "%d", &subval) == 1
1142            ? subval < 0
1143            : (subval = XEN_SYSCTL_CX_UNLIMITED, strcmp(argv[1], "unlimited")))) )
1144     {
1145         fprintf(stderr, "Missing, excess, or invalid argument(s)\n");
1146         exit(EINVAL);
1147     }
1148 
1149     snprintf(buf, ARRAY_SIZE(buf), "C%d", value);
1150 
1151     if ( !xc_set_cpuidle_max_cstate(xc_handle, (uint32_t)value) )
1152         printf("max C-state set to %s\n", value >= 0 ? buf : argv[0]);
1153     else
1154     {
1155         fprintf(stderr, "Failed to set max C-state to %s (%d - %s)\n",
1156                 value >= 0 ? buf : argv[0], errno, strerror(errno));
1157         return;
1158     }
1159 
1160     if ( value != XEN_SYSCTL_CX_UNLIMITED )
1161     {
1162         snprintf(buf, ARRAY_SIZE(buf), "%d", subval);
1163 
1164         if ( !xc_set_cpuidle_max_csubstate(xc_handle, (uint32_t)subval) )
1165             printf("max C-substate set to %s succeeded\n",
1166                    subval >= 0 ? buf : "unlimited");
1167         else
1168             fprintf(stderr, "Failed to set max C-substate to %s (%d - %s)\n",
1169                     subval >= 0 ? buf : "unlimited", errno, strerror(errno));
1170     }
1171 }
1172 
enable_turbo_mode(int argc,char * argv[])1173 void enable_turbo_mode(int argc, char *argv[])
1174 {
1175     int cpuid = -1;
1176 
1177     if ( argc > 0 )
1178         parse_cpuid(argv[0], &cpuid);
1179 
1180     if ( cpuid < 0 )
1181     {
1182         /* enable turbo modes on all cpus,
1183          * only make effects on dbs governor */
1184         int i;
1185         for ( i = 0; i < max_cpu_nr; i++ )
1186             if ( xc_enable_turbo(xc_handle, i) )
1187                 fprintf(stderr,
1188                         "[CPU%d] failed to enable turbo mode (%d - %s)\n",
1189                         i, errno, strerror(errno));
1190     }
1191     else if ( xc_enable_turbo(xc_handle, cpuid) )
1192         fprintf(stderr, "failed to enable turbo mode (%d - %s)\n",
1193                 errno, strerror(errno));
1194 }
1195 
disable_turbo_mode(int argc,char * argv[])1196 void disable_turbo_mode(int argc, char *argv[])
1197 {
1198     int cpuid = -1;
1199 
1200     if ( argc > 0 )
1201         parse_cpuid(argv[0], &cpuid);
1202 
1203     if ( cpuid < 0 )
1204     {
1205         /* disable turbo modes on all cpus,
1206          * only make effects on dbs governor */
1207         int i;
1208         for ( i = 0; i < max_cpu_nr; i++ )
1209             if ( xc_disable_turbo(xc_handle, i) )
1210                 fprintf(stderr,
1211                         "[CPU%d] failed to disable turbo mode (%d - %s)\n",
1212                         i, errno, strerror(errno));
1213     }
1214     else if ( xc_disable_turbo(xc_handle, cpuid) )
1215         fprintf(stderr, "failed to disable turbo mode (%d - %s)\n",
1216                 errno, strerror(errno));
1217 }
1218 
1219 struct {
1220     const char *name;
1221     void (*function)(int argc, char *argv[]);
1222 } main_options[] = {
1223     { "help", help_func },
1224     { "get-cpuidle-states", cxstat_func },
1225     { "get-cpufreq-states", pxstat_func },
1226     { "get-cpufreq-average", cpufreq_func },
1227     { "start", start_gather_func },
1228     { "get-cpufreq-para", cpufreq_para_func },
1229     { "set-scaling-maxfreq", scaling_max_freq_func },
1230     { "set-scaling-minfreq", scaling_min_freq_func },
1231     { "set-scaling-governor", scaling_governor_func },
1232     { "set-scaling-speed", scaling_speed_func },
1233     { "set-sampling-rate", scaling_sampling_rate_func },
1234     { "set-up-threshold", scaling_up_threshold_func },
1235     { "get-cpu-topology", cpu_topology_func},
1236     { "set-sched-smt", set_sched_smt_func},
1237     { "get-vcpu-migration-delay", get_vcpu_migration_delay_func},
1238     { "set-vcpu-migration-delay", set_vcpu_migration_delay_func},
1239     { "set-max-cstate", set_max_cstate_func},
1240     { "enable-turbo-mode", enable_turbo_mode },
1241     { "disable-turbo-mode", disable_turbo_mode },
1242 };
1243 
main(int argc,char * argv[])1244 int main(int argc, char *argv[])
1245 {
1246     int i, ret = 0;
1247     xc_physinfo_t physinfo = { 0 };
1248     int nr_matches = 0;
1249     int matches_main_options[ARRAY_SIZE(main_options)];
1250 
1251     if ( argc < 2 )
1252     {
1253         show_help();
1254         return 0;
1255     }
1256 
1257     xc_handle = xc_interface_open(0,0,0);
1258     if ( !xc_handle )
1259     {
1260         fprintf(stderr, "failed to get the handler\n");
1261         return EIO;
1262     }
1263 
1264     ret = xc_physinfo(xc_handle, &physinfo);
1265     if ( ret )
1266     {
1267         ret = errno;
1268         fprintf(stderr, "failed to get processor information (%d - %s)\n",
1269                 ret, strerror(ret));
1270         xc_interface_close(xc_handle);
1271         return ret;
1272     }
1273     max_cpu_nr = physinfo.max_cpu_id + 1;
1274 
1275     /* calculate how many options match with user's input */
1276     for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
1277         if ( !strncmp(main_options[i].name, argv[1], strlen(argv[1])) )
1278             matches_main_options[nr_matches++] = i;
1279 
1280     if ( nr_matches > 1 )
1281     {
1282         fprintf(stderr, "Ambiguous options: ");
1283         for ( i = 0; i < nr_matches; i++ )
1284             fprintf(stderr, " %s", main_options[matches_main_options[i]].name);
1285         fprintf(stderr, "\n");
1286         ret = EINVAL;
1287     }
1288     else if ( nr_matches == 1 )
1289         /* dispatch to the corresponding function handler */
1290         main_options[matches_main_options[0]].function(argc - 2, argv + 2);
1291     else
1292     {
1293         show_help();
1294         ret = EINVAL;
1295     }
1296 
1297     xc_interface_close(xc_handle);
1298     return ret;
1299 }
1300 
1301