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