ia64/xen-unstable

view tools/xenstat/xentop/xentop.c @ 10553:7a7066ae2e77

[XENTOP] Fix CPU percentage display in batch mode.
From: shaocyou <shaocyou@jp.fujitsu.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Jun 28 10:24:05 2006 +0100 (2006-06-28)
parents e5cf18c05e8b
children 85b092b4567d
line source
1 /*
2 * Copyright (C) International Business Machines Corp., 2005
3 * Author(s): Judy Fischbach <jfisch@us.ibm.com>
4 * David Hendricks <dhendrix@us.ibm.com>
5 * Josh Triplett <josht@us.ibm.com>
6 * based on code from Anthony Liguori <aliguori@us.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; under version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 #include <curses.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/time.h>
28 #include <time.h>
29 #include <unistd.h>
31 #include <xenstat.h>
33 #define XENTOP_VERSION "1.0"
35 #define XENTOP_DISCLAIMER \
36 "Copyright (C) 2005 International Business Machines Corp\n"\
37 "This is free software; see the source for copying conditions.There is NO\n"\
38 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
39 #define XENTOP_BUGSTO "Report bugs to <dsteklof@us.ibm.com>.\n"
41 #define _GNU_SOURCE
42 #include <getopt.h>
44 #if !defined(__GNUC__) && !defined(__GNUG__)
45 #define __attribute__(arg) /* empty */
46 #endif
48 #define KEY_ESCAPE '\x1B'
50 /*
51 * Function prototypes
52 */
53 /* Utility functions */
54 static void usage(const char *);
55 static void version(void);
56 static void cleanup(void);
57 static void fail(const char *);
58 static int current_row(void);
59 static int lines(void);
60 static void print(const char *, ...) __attribute__((format(printf,1,2)));
61 static void attr_addstr(int attr, const char *str);
62 static void set_delay(char *value);
63 static void set_prompt(char *new_prompt, void (*func)(char *));
64 static int handle_key(int);
65 static int compare(unsigned long long, unsigned long long);
66 static int compare_domains(xenstat_domain **, xenstat_domain **);
67 static unsigned long long tot_net_bytes( xenstat_domain *, int);
69 /* Field functions */
70 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2);
71 static void print_state(xenstat_domain *domain);
72 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2);
73 static void print_cpu(xenstat_domain *domain);
74 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2);
75 static void print_cpu_pct(xenstat_domain *domain);
76 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2);
77 static void print_mem(xenstat_domain *domain);
78 static void print_mem_pct(xenstat_domain *domain);
79 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2);
80 static void print_maxmem(xenstat_domain *domain);
81 static void print_max_pct(xenstat_domain *domain);
82 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2);
83 static void print_vcpus(xenstat_domain *domain);
84 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2);
85 static void print_nets(xenstat_domain *domain);
86 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2);
87 static void print_net_tx(xenstat_domain *domain);
88 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2);
89 static void print_net_rx(xenstat_domain *domain);
90 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2);
91 static void print_ssid(xenstat_domain *domain);
92 static int compare_name(xenstat_domain *domain1, xenstat_domain *domain2);
93 static void print_name(xenstat_domain *domain);
95 /* Section printing functions */
96 static void do_summary(void);
97 static void do_header(void);
98 static void do_bottom_line(void);
99 static void do_domain(xenstat_domain *);
100 static void do_vcpu(xenstat_domain *);
101 static void do_network(xenstat_domain *);
102 static void top(void);
104 /* Field types */
105 typedef enum field_id {
106 FIELD_DOMID,
107 FIELD_NAME,
108 FIELD_STATE,
109 FIELD_CPU,
110 FIELD_CPU_PCT,
111 FIELD_MEM,
112 FIELD_MEM_PCT,
113 FIELD_MAXMEM,
114 FIELD_MAX_PCT,
115 FIELD_VCPUS,
116 FIELD_NETS,
117 FIELD_NET_TX,
118 FIELD_NET_RX,
119 FIELD_SSID
120 } field_id;
122 typedef struct field {
123 field_id num;
124 const char *header;
125 unsigned int default_width;
126 int (*compare)(xenstat_domain *domain1, xenstat_domain *domain2);
127 void (*print)(xenstat_domain *domain);
128 } field;
130 field fields[] = {
131 { FIELD_NAME, "NAME", 10, compare_name, print_name },
132 { FIELD_STATE, "STATE", 6, compare_state, print_state },
133 { FIELD_CPU, "CPU(sec)", 10, compare_cpu, print_cpu },
134 { FIELD_CPU_PCT, "CPU(%)", 6, compare_cpu_pct, print_cpu_pct },
135 { FIELD_MEM, "MEM(k)", 10, compare_mem, print_mem },
136 { FIELD_MEM_PCT, "MEM(%)", 6, compare_mem, print_mem_pct },
137 { FIELD_MAXMEM, "MAXMEM(k)", 10, compare_maxmem, print_maxmem },
138 { FIELD_MAX_PCT, "MAXMEM(%)", 9, compare_maxmem, print_max_pct },
139 { FIELD_VCPUS, "VCPUS", 5, compare_vcpus, print_vcpus },
140 { FIELD_NETS, "NETS", 4, compare_nets, print_nets },
141 { FIELD_NET_TX, "NETTX(k)", 8, compare_net_tx, print_net_tx },
142 { FIELD_NET_RX, "NETRX(k)", 8, compare_net_rx, print_net_rx },
143 { FIELD_SSID, "SSID", 4, compare_ssid, print_ssid }
144 };
146 const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field);
148 /* Globals */
149 struct timeval curtime, oldtime;
150 xenstat_handle *xhandle = NULL;
151 xenstat_node *prev_node = NULL;
152 xenstat_node *cur_node = NULL;
153 field_id sort_field = FIELD_DOMID;
154 unsigned int first_domain_index = 0;
155 unsigned int delay = 3;
156 unsigned int batch = 0;
157 unsigned int loop = 1;
158 unsigned int iterations = 0;
159 int show_vcpus = 0;
160 int show_networks = 0;
161 int repeat_header = 0;
162 #define PROMPT_VAL_LEN 80
163 char *prompt = NULL;
164 char prompt_val[PROMPT_VAL_LEN];
165 int prompt_val_len = 0;
166 void (*prompt_complete_func)(char *);
168 /*
169 * Function definitions
170 */
172 /* Utility functions */
174 /* Print usage message, using given program name */
175 static void usage(const char *program)
176 {
177 printf("Usage: %s [OPTION]\n"
178 "Displays ongoing information about xen vm resources \n\n"
179 "-h, --help display this help and exit\n"
180 "-V, --version output version information and exit\n"
181 "-d, --delay=SECONDS seconds between updates (default 3)\n"
182 "-n, --networks output vif network data\n"
183 "-r, --repeat-header repeat table header before each domain\n"
184 "-v, --vcpus output vcpu data\n"
185 "-b, --batch output in batch mode, no user input accepted\n"
186 "-i, --iterations number of iterations before exiting\n"
187 "\n" XENTOP_BUGSTO,
188 program);
189 return;
190 }
192 /* Print program version information */
193 static void version(void)
194 {
195 printf("xentop " XENTOP_VERSION "\n"
196 "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
197 "\n" XENTOP_DISCLAIMER);
198 }
200 /* Clean up any open resources */
201 static void cleanup(void)
202 {
203 if(!isendwin())
204 endwin();
205 if(prev_node != NULL)
206 xenstat_free_node(prev_node);
207 if(cur_node != NULL)
208 xenstat_free_node(cur_node);
209 if(xhandle != NULL)
210 xenstat_uninit(xhandle);
211 }
213 /* Display the given message and gracefully exit */
214 static void fail(const char *str)
215 {
216 if(!isendwin())
217 endwin();
218 fprintf(stderr, str);
219 exit(1);
220 }
222 /* Return the row containing the cursor. */
223 static int current_row(void)
224 {
225 int y, x;
226 getyx(stdscr, y, x);
227 return y;
228 }
230 /* Return the number of lines on the screen. */
231 static int lines(void)
232 {
233 int y, x;
234 getmaxyx(stdscr, y, x);
235 return y;
236 }
238 /* printf-style print function which calls printw, but only if the cursor is
239 * not on the last line. */
240 static void print(const char *fmt, ...)
241 {
242 va_list args;
244 if (!batch) {
245 if((current_row() < lines()-1)) {
246 va_start(args, fmt);
247 vw_printw(stdscr, fmt, args);
248 va_end(args);
249 }
250 } else {
251 va_start(args, fmt);
252 vprintf(fmt, args);
253 va_end(args);
254 }
255 }
257 /* Print a string with the given attributes set. */
258 static void attr_addstr(int attr, const char *str)
259 {
260 attron(attr);
261 addstr(str);
262 attroff(attr);
263 }
265 /* Handle setting the delay from the user-supplied value in prompt_val */
266 static void set_delay(char *value)
267 {
268 int new_delay;
269 new_delay = atoi(value);
270 if(new_delay > 0)
271 delay = new_delay;
272 }
274 /* Enable prompting mode with the given prompt string; call the given function
275 * when a value is available. */
276 static void set_prompt(char *new_prompt, void (*func)(char *))
277 {
278 prompt = new_prompt;
279 prompt_val[0] = '\0';
280 prompt_val_len = 0;
281 prompt_complete_func = func;
282 }
284 /* Handle user input, return 0 if the program should quit, or 1 if not */
285 static int handle_key(int ch)
286 {
287 if(prompt == NULL) {
288 /* Not prompting for input; handle interactive commands */
289 switch(ch) {
290 case 'n': case 'N':
291 show_networks ^= 1;
292 break;
293 case 'r': case 'R':
294 repeat_header ^= 1;
295 break;
296 case 's': case 'S':
297 sort_field = (sort_field + 1) % NUM_FIELDS;
298 break;
299 case 'v': case 'V':
300 show_vcpus ^= 1;
301 break;
302 case KEY_DOWN:
303 first_domain_index++;
304 break;
305 case KEY_UP:
306 if(first_domain_index > 0)
307 first_domain_index--;
308 break;
309 case 'd': case 'D':
310 set_prompt("Delay(sec)", set_delay);
311 break;
312 case 'q': case 'Q': case KEY_ESCAPE:
313 return 0;
314 }
315 } else {
316 /* Prompting for input; handle line editing */
317 switch(ch) {
318 case '\r':
319 prompt_complete_func(prompt_val);
320 set_prompt(NULL, NULL);
321 break;
322 case KEY_ESCAPE:
323 set_prompt(NULL, NULL);
324 break;
325 case KEY_BACKSPACE:
326 if(prompt_val_len > 0)
327 prompt_val[--prompt_val_len] = '\0';
328 default:
329 if((prompt_val_len+1) < PROMPT_VAL_LEN
330 && isprint(ch)) {
331 prompt_val[prompt_val_len++] = (char)ch;
332 prompt_val[prompt_val_len] = '\0';
333 }
334 }
335 }
337 return 1;
338 }
340 /* Compares two integers, returning -1,0,1 for <,=,> */
341 static int compare(unsigned long long i1, unsigned long long i2)
342 {
343 if(i1 < i2)
344 return -1;
345 if(i1 > i2)
346 return 1;
347 return 0;
348 }
350 /* Comparison function for use with qsort. Compares two domains using the
351 * current sort field. */
352 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
353 {
354 return fields[sort_field].compare(*domain1, *domain2);
355 }
357 /* Field functions */
359 /* Compare domain names, returning -1,0,1 for <,=,> */
360 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
361 {
362 return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
363 }
365 /* Prints domain name */
366 void print_name(xenstat_domain *domain)
367 {
368 print("%10s", xenstat_domain_name(domain));
369 }
371 struct {
372 unsigned int (*get)(xenstat_domain *);
373 char ch;
374 } state_funcs[] = {
375 { xenstat_domain_dying, 'd' },
376 { xenstat_domain_shutdown, 's' },
377 { xenstat_domain_blocked, 'b' },
378 { xenstat_domain_crashed, 'c' },
379 { xenstat_domain_paused, 'p' },
380 { xenstat_domain_running, 'r' }
381 };
382 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
384 /* Compare states of two domains, returning -1,0,1 for <,=,> */
385 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
386 {
387 unsigned int i, d1s, d2s;
388 for(i = 0; i < NUM_STATES; i++) {
389 d1s = state_funcs[i].get(domain1);
390 d2s = state_funcs[i].get(domain2);
391 if(d1s && !d2s)
392 return -1;
393 if(d2s && !d1s)
394 return 1;
395 }
396 return 0;
397 }
399 /* Prints domain state in abbreviated letter format */
400 static void print_state(xenstat_domain *domain)
401 {
402 unsigned int i;
403 for(i = 0; i < NUM_STATES; i++)
404 print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
405 : '-');
406 }
408 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
409 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
410 {
411 return -compare(xenstat_domain_cpu_ns(domain1),
412 xenstat_domain_cpu_ns(domain2));
413 }
415 /* Prints domain cpu usage in seconds */
416 static void print_cpu(xenstat_domain *domain)
417 {
418 print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
419 }
421 /* Computes the CPU percentage used for a specified domain */
422 static double get_cpu_pct(xenstat_domain *domain)
423 {
424 xenstat_domain *old_domain;
425 double us_elapsed;
427 /* Can't calculate CPU percentage without a previous sample. */
428 if(prev_node == NULL)
429 return 0.0;
431 old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
432 if(old_domain == NULL)
433 return 0.0;
435 /* Calculate the time elapsed in microseconds */
436 us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
437 +(curtime.tv_usec - oldtime.tv_usec));
439 /* In the following, nanoseconds must be multiplied by 1000.0 to
440 * convert to microseconds, then divided by 100.0 to get a percentage,
441 * resulting in a multiplication by 10.0 */
442 return ((xenstat_domain_cpu_ns(domain)
443 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
444 }
446 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
447 {
448 return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
449 }
451 /* Prints cpu percentage statistic */
452 static void print_cpu_pct(xenstat_domain *domain)
453 {
454 print("%6.1f", get_cpu_pct(domain));
455 }
457 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
458 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
459 {
460 return -compare(xenstat_domain_cur_mem(domain1),
461 xenstat_domain_cur_mem(domain2));
462 }
464 /* Prints current memory statistic */
465 static void print_mem(xenstat_domain *domain)
466 {
467 print("%10llu", xenstat_domain_cur_mem(domain)/1024);
468 }
470 /* Prints memory percentage statistic, ratio of current domain memory to total
471 * node memory */
472 static void print_mem_pct(xenstat_domain *domain)
473 {
474 print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
475 (double)xenstat_node_tot_mem(cur_node) * 100);
476 }
478 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
479 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
480 {
481 return -compare(xenstat_domain_max_mem(domain1),
482 xenstat_domain_max_mem(domain2));
483 }
485 /* Prints maximum domain memory statistic in KB */
486 static void print_maxmem(xenstat_domain *domain)
487 {
488 unsigned long long max_mem = xenstat_domain_max_mem(domain);
489 if(max_mem == ((unsigned long long)-1))
490 print("%10s", "no limit");
491 else
492 print("%10llu", max_mem/1024);
493 }
495 /* Prints memory percentage statistic, ratio of current domain memory to total
496 * node memory */
497 static void print_max_pct(xenstat_domain *domain)
498 {
499 if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
500 print("%9s", "n/a");
501 else
502 print("%9.1f", (double)xenstat_domain_max_mem(domain) /
503 (double)xenstat_node_tot_mem(cur_node) * 100);
504 }
506 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
507 * <,=,> */
508 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
509 {
510 return -compare(xenstat_domain_num_vcpus(domain1),
511 xenstat_domain_num_vcpus(domain2));
512 }
514 /* Prints number of virtual CPUs statistic */
515 static void print_vcpus(xenstat_domain *domain)
516 {
517 print("%5u", xenstat_domain_num_vcpus(domain));
518 }
520 /* Compares number of virtual networks of two domains, returning -1,0,1 for
521 * <,=,> */
522 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
523 {
524 return -compare(xenstat_domain_num_networks(domain1),
525 xenstat_domain_num_networks(domain2));
526 }
528 /* Prints number of virtual networks statistic */
529 static void print_nets(xenstat_domain *domain)
530 {
531 print("%4u", xenstat_domain_num_networks(domain));
532 }
534 /* Compares number of total network tx bytes of two domains, returning -1,0,1
535 * for <,=,> */
536 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
537 {
538 return -compare(tot_net_bytes(domain1, FALSE),
539 tot_net_bytes(domain2, FALSE));
540 }
542 /* Prints number of total network tx bytes statistic */
543 static void print_net_tx(xenstat_domain *domain)
544 {
545 print("%8llu", tot_net_bytes(domain, FALSE)/1024);
546 }
548 /* Compares number of total network rx bytes of two domains, returning -1,0,1
549 * for <,=,> */
550 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
551 {
552 return -compare(tot_net_bytes(domain1, TRUE),
553 tot_net_bytes(domain2, TRUE));
554 }
556 /* Prints number of total network rx bytes statistic */
557 static void print_net_rx(xenstat_domain *domain)
558 {
559 print("%8llu", tot_net_bytes(domain, TRUE)/1024);
560 }
562 /* Gets number of total network bytes statistic, if rx true, then rx bytes
563 * otherwise tx bytes
564 */
565 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
566 {
567 int i = 0;
568 xenstat_network *network;
569 unsigned num_networks = 0;
570 unsigned long long total = 0;
572 /* How many networks? */
573 num_networks = xenstat_domain_num_networks(domain);
575 /* Dump information for each network */
576 for (i=0; i < num_networks; i++) {
577 /* Next get the network information */
578 network = xenstat_domain_network(domain,i);
579 if (rx_flag)
580 total += xenstat_network_rbytes(network);
581 else
582 total += xenstat_network_tbytes(network);
583 }
585 return total;
586 }
588 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
589 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
590 {
591 return compare(xenstat_domain_ssid(domain1),
592 xenstat_domain_ssid(domain2));
593 }
595 /* Prints ssid statistic */
596 static void print_ssid(xenstat_domain *domain)
597 {
598 print("%4u", xenstat_domain_ssid(domain));
599 }
601 /* Section printing functions */
602 /* Prints the top summary, above the domain table */
603 void do_summary(void)
604 {
605 #define TIME_STR_LEN 9
606 const char *TIME_STR_FORMAT = "%H:%M:%S";
607 char time_str[TIME_STR_LEN];
608 const char *ver_str;
609 unsigned run = 0, block = 0, pause = 0,
610 crash = 0, dying = 0, shutdown = 0;
611 unsigned i, num_domains = 0;
612 unsigned long long used = 0;
613 xenstat_domain *domain;
615 /* Print program name, current time, and number of domains */
616 strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT,
617 localtime(&curtime.tv_sec));
618 num_domains = xenstat_node_num_domains(cur_node);
619 ver_str = xenstat_node_xen_version(cur_node);
620 print("xentop - %s Xen %s\n", time_str, ver_str);
622 /* Tabulate what states domains are in for summary */
623 for (i=0; i < num_domains; i++) {
624 domain = xenstat_node_domain_by_index(cur_node,i);
625 if (xenstat_domain_running(domain)) run++;
626 else if (xenstat_domain_blocked(domain)) block++;
627 else if (xenstat_domain_paused(domain)) pause++;
628 else if (xenstat_domain_shutdown(domain)) shutdown++;
629 else if (xenstat_domain_crashed(domain)) crash++;
630 else if (xenstat_domain_dying(domain)) dying++;
631 }
633 print("%u domains: %u running, %u blocked, %u paused, "
634 "%u crashed, %u dying, %u shutdown \n",
635 num_domains, run, block, pause, crash, dying, shutdown);
637 used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node);
639 /* Dump node memory and cpu information */
640 print("Mem: %lluk total, %lluk used, %lluk free "
641 "CPUs: %u @ %lluMHz\n",
642 xenstat_node_tot_mem(cur_node)/1024, used/1024,
643 xenstat_node_free_mem(cur_node)/1024,
644 xenstat_node_num_cpus(cur_node),
645 xenstat_node_cpu_hz(cur_node)/1000000);
646 }
648 /* Display the top header for the domain table */
649 void do_header(void)
650 {
651 field_id i;
653 /* Turn on REVERSE highlight attribute for headings */
654 attron(A_REVERSE);
655 for(i = 0; i < NUM_FIELDS; i++) {
656 if(i != 0)
657 print(" ");
658 /* The BOLD attribute is turned on for the sort column */
659 if(i == sort_field)
660 attron(A_BOLD);
661 print("%*s", fields[i].default_width, fields[i].header);
662 if(i == sort_field)
663 attroff(A_BOLD);
664 }
665 attroff(A_REVERSE);
666 print("\n");
667 }
669 /* Displays bottom status line or current prompt */
670 void do_bottom_line(void)
671 {
672 move(lines()-1, 2);
674 if (prompt != NULL) {
675 printw("%s: %s", prompt, prompt_val);
676 } else {
677 addch(A_REVERSE | 'D'); addstr("elay ");
679 /* network */
680 addch(A_REVERSE | 'N');
681 attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
682 addstr(" ");
684 /* vcpus */
685 addch(A_REVERSE | 'V');
686 attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
687 addstr(" ");
689 /* repeat */
690 addch(A_REVERSE | 'R');
691 attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
692 addstr(" ");
694 /* sort order */
695 addch(A_REVERSE | 'S'); addstr("ort order ");
697 addch(A_REVERSE | 'Q'); addstr("uit ");
698 }
699 }
701 /* Prints Domain information */
702 void do_domain(xenstat_domain *domain)
703 {
704 unsigned int i;
705 for(i = 0; i < NUM_FIELDS; i++) {
706 if(i != 0)
707 print(" ");
708 if(i == sort_field)
709 attron(A_BOLD);
710 fields[i].print(domain);
711 if(i == sort_field)
712 attroff(A_BOLD);
713 }
714 print("\n");
715 }
717 /* Output all vcpu information */
718 void do_vcpu(xenstat_domain *domain)
719 {
720 int i = 0;
721 unsigned num_vcpus = 0;
722 xenstat_vcpu *vcpu;
724 print("VCPUs(sec): ");
726 num_vcpus = xenstat_domain_num_vcpus(domain);
728 /* for all online vcpus dump out values */
729 for (i=0; i< num_vcpus; i++) {
730 vcpu = xenstat_domain_vcpu(domain,i);
732 if (xenstat_vcpu_online(vcpu) > 0) {
733 if (i != 0 && (i%5)==0)
734 print("\n ");
735 print(" %2u: %10llus", i,
736 xenstat_vcpu_ns(vcpu)/1000000000);
737 }
738 }
739 print("\n");
740 }
742 /* Output all network information */
743 void do_network(xenstat_domain *domain)
744 {
745 int i = 0;
746 xenstat_network *network;
747 unsigned num_networks = 0;
749 /* How many networks? */
750 num_networks = xenstat_domain_num_networks(domain);
752 /* Dump information for each network */
753 for (i=0; i < num_networks; i++) {
754 /* Next get the network information */
755 network = xenstat_domain_network(domain,i);
757 print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop ",
758 i,
759 xenstat_network_rbytes(network),
760 xenstat_network_rpackets(network),
761 xenstat_network_rerrs(network),
762 xenstat_network_rdrop(network));
764 print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
765 xenstat_network_tbytes(network),
766 xenstat_network_tpackets(network),
767 xenstat_network_terrs(network),
768 xenstat_network_tdrop(network));
769 }
770 }
772 static void top(void)
773 {
774 xenstat_domain **domains;
775 unsigned int i, num_domains = 0;
777 /* Now get the node information */
778 if (prev_node != NULL)
779 xenstat_free_node(prev_node);
780 prev_node = cur_node;
781 cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
782 if (cur_node == NULL)
783 fail("Failed to retrieve statistics from libxenstat\n");
785 /* dump summary top information */
786 do_summary();
788 /* Count the number of domains for which to report data */
789 num_domains = xenstat_node_num_domains(cur_node);
791 domains = malloc(num_domains*sizeof(xenstat_domain *));
792 if(domains == NULL)
793 fail("Failed to allocate memory\n");
795 for (i=0; i < num_domains; i++)
796 domains[i] = xenstat_node_domain_by_index(cur_node, i);
798 /* Sort */
799 qsort(domains, num_domains, sizeof(xenstat_domain *),
800 (int(*)(const void *, const void *))compare_domains);
802 if(first_domain_index >= num_domains)
803 first_domain_index = num_domains-1;
805 for (i = first_domain_index; i < num_domains; i++) {
806 if(current_row() == lines()-1)
807 break;
808 if (i == first_domain_index || repeat_header)
809 do_header();
810 do_domain(domains[i]);
811 if (show_vcpus)
812 do_vcpu(domains[i]);
813 if (show_networks)
814 do_network(domains[i]);
815 }
817 if(!batch)
818 do_bottom_line();
819 }
821 int main(int argc, char **argv)
822 {
823 int opt, optind = 0;
824 int ch = ERR;
826 struct option lopts[] = {
827 { "help", no_argument, NULL, 'h' },
828 { "version", no_argument, NULL, 'V' },
829 { "networks", no_argument, NULL, 'n' },
830 { "repeat-header", no_argument, NULL, 'r' },
831 { "vcpus", no_argument, NULL, 'v' },
832 { "delay", required_argument, NULL, 'd' },
833 { "batch", no_argument, NULL, 'b' },
834 { "iterations", required_argument, NULL, 'i' },
835 { 0, 0, 0, 0 },
836 };
837 const char *sopts = "hVbnvd:bi:";
839 if (atexit(cleanup) != 0)
840 fail("Failed to install cleanup handler.\n");
842 while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
843 switch (opt) {
844 case 'h':
845 case '?':
846 default:
847 usage(argv[0]);
848 exit(0);
849 case 'V':
850 version();
851 exit(0);
852 case 'n':
853 show_networks = 1;
854 break;
855 case 'r':
856 repeat_header = 1;
857 break;
858 case 'v':
859 show_vcpus = 1;
860 break;
861 case 'd':
862 delay = atoi(optarg);
863 break;
864 case 'b':
865 batch = 1;
866 break;
867 case 'i':
868 iterations = atoi(optarg);
869 loop = 0;
870 break;
871 }
872 }
874 /* Get xenstat handle */
875 xhandle = xenstat_init();
876 if (xhandle == NULL)
877 fail("Failed to initialize xenstat library\n");
879 if (!batch) {
880 /* Begin curses stuff */
881 initscr();
882 start_color();
883 cbreak();
884 noecho();
885 nonl();
886 keypad(stdscr, TRUE);
887 halfdelay(5);
888 use_default_colors();
889 init_pair(1, -1, COLOR_YELLOW);
891 do {
892 gettimeofday(&curtime, NULL);
893 if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
894 clear();
895 top();
896 oldtime = curtime;
897 refresh();
898 if ((!loop) && !(--iterations))
899 break;
900 }
901 ch = getch();
902 } while (handle_key(ch));
903 } else {
904 do {
905 gettimeofday(&curtime, NULL);
906 top();
907 oldtime = curtime;
908 sleep(delay);
909 if ((!loop) && !(--iterations))
910 break;
911 } while (1);
912 }
914 /* Cleanup occurs in cleanup(), so no work to do here. */
916 return 0;
917 }