ia64/xen-unstable

view tools/xenstat/xentop/xentop.c @ 8740:3d7ea7972b39

Update patches for linux 2.6.15.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Feb 02 17:16:00 2006 +0000 (2006-02-02)
parents e70ea9465b31
children e5cf18c05e8b
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 int show_vcpus = 0;
157 int show_networks = 0;
158 int repeat_header = 0;
159 #define PROMPT_VAL_LEN 80
160 char *prompt = NULL;
161 char prompt_val[PROMPT_VAL_LEN];
162 int prompt_val_len = 0;
163 void (*prompt_complete_func)(char *);
165 /*
166 * Function definitions
167 */
169 /* Utility functions */
171 /* Print usage message, using given program name */
172 static void usage(const char *program)
173 {
174 printf("Usage: %s [OPTION]\n"
175 "Displays ongoing information about xen vm resources \n\n"
176 "-h, --help display this help and exit\n"
177 "-V, --version output version information and exit\n"
178 "-d, --delay=SECONDS seconds between updates (default 3)\n"
179 "-n, --networks output vif network data\n"
180 "-r, --repeat-header repeat table header before each domain\n"
181 "-v, --vcpus output vcpu data\n"
182 "\n" XENTOP_BUGSTO,
183 program);
184 return;
185 }
187 /* Print program version information */
188 static void version(void)
189 {
190 printf("xentop " XENTOP_VERSION "\n"
191 "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
192 "\n" XENTOP_DISCLAIMER);
193 }
195 /* Clean up any open resources */
196 static void cleanup(void)
197 {
198 if(!isendwin())
199 endwin();
200 if(prev_node != NULL)
201 xenstat_free_node(prev_node);
202 if(cur_node != NULL)
203 xenstat_free_node(cur_node);
204 if(xhandle != NULL)
205 xenstat_uninit(xhandle);
206 }
208 /* Display the given message and gracefully exit */
209 static void fail(const char *str)
210 {
211 if(!isendwin())
212 endwin();
213 fprintf(stderr, str);
214 exit(1);
215 }
217 /* Return the row containing the cursor. */
218 static int current_row(void)
219 {
220 int y, x;
221 getyx(stdscr, y, x);
222 return y;
223 }
225 /* Return the number of lines on the screen. */
226 static int lines(void)
227 {
228 int y, x;
229 getmaxyx(stdscr, y, x);
230 return y;
231 }
233 /* printf-style print function which calls printw, but only if the cursor is
234 * not on the last line. */
235 static void print(const char *fmt, ...)
236 {
237 va_list args;
239 if(current_row() < lines()-1) {
240 va_start(args, fmt);
241 vw_printw(stdscr, fmt, args);
242 va_end(args);
243 }
244 }
246 /* Print a string with the given attributes set. */
247 static void attr_addstr(int attr, const char *str)
248 {
249 attron(attr);
250 addstr(str);
251 attroff(attr);
252 }
254 /* Handle setting the delay from the user-supplied value in prompt_val */
255 static void set_delay(char *value)
256 {
257 int new_delay;
258 new_delay = atoi(value);
259 if(new_delay > 0)
260 delay = new_delay;
261 }
263 /* Enable prompting mode with the given prompt string; call the given function
264 * when a value is available. */
265 static void set_prompt(char *new_prompt, void (*func)(char *))
266 {
267 prompt = new_prompt;
268 prompt_val[0] = '\0';
269 prompt_val_len = 0;
270 prompt_complete_func = func;
271 }
273 /* Handle user input, return 0 if the program should quit, or 1 if not */
274 static int handle_key(int ch)
275 {
276 if(prompt == NULL) {
277 /* Not prompting for input; handle interactive commands */
278 switch(ch) {
279 case 'n': case 'N':
280 show_networks ^= 1;
281 break;
282 case 'r': case 'R':
283 repeat_header ^= 1;
284 break;
285 case 's': case 'S':
286 sort_field = (sort_field + 1) % NUM_FIELDS;
287 break;
288 case 'v': case 'V':
289 show_vcpus ^= 1;
290 break;
291 case KEY_DOWN:
292 first_domain_index++;
293 break;
294 case KEY_UP:
295 if(first_domain_index > 0)
296 first_domain_index--;
297 break;
298 case 'd': case 'D':
299 set_prompt("Delay(sec)", set_delay);
300 break;
301 case 'q': case 'Q': case KEY_ESCAPE:
302 return 0;
303 }
304 } else {
305 /* Prompting for input; handle line editing */
306 switch(ch) {
307 case '\r':
308 prompt_complete_func(prompt_val);
309 set_prompt(NULL, NULL);
310 break;
311 case KEY_ESCAPE:
312 set_prompt(NULL, NULL);
313 break;
314 case KEY_BACKSPACE:
315 if(prompt_val_len > 0)
316 prompt_val[--prompt_val_len] = '\0';
317 default:
318 if((prompt_val_len+1) < PROMPT_VAL_LEN
319 && isprint(ch)) {
320 prompt_val[prompt_val_len++] = (char)ch;
321 prompt_val[prompt_val_len] = '\0';
322 }
323 }
324 }
326 return 1;
327 }
329 /* Compares two integers, returning -1,0,1 for <,=,> */
330 static int compare(unsigned long long i1, unsigned long long i2)
331 {
332 if(i1 < i2)
333 return -1;
334 if(i1 > i2)
335 return 1;
336 return 0;
337 }
339 /* Comparison function for use with qsort. Compares two domains using the
340 * current sort field. */
341 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
342 {
343 return fields[sort_field].compare(*domain1, *domain2);
344 }
346 /* Field functions */
348 /* Compare domain names, returning -1,0,1 for <,=,> */
349 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
350 {
351 return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
352 }
354 /* Prints domain name */
355 void print_name(xenstat_domain *domain)
356 {
357 print("%10s", xenstat_domain_name(domain));
358 }
360 struct {
361 unsigned int (*get)(xenstat_domain *);
362 char ch;
363 } state_funcs[] = {
364 { xenstat_domain_dying, 'd' },
365 { xenstat_domain_shutdown, 's' },
366 { xenstat_domain_blocked, 'b' },
367 { xenstat_domain_crashed, 'c' },
368 { xenstat_domain_paused, 'p' },
369 { xenstat_domain_running, 'r' }
370 };
371 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
373 /* Compare states of two domains, returning -1,0,1 for <,=,> */
374 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
375 {
376 unsigned int i, d1s, d2s;
377 for(i = 0; i < NUM_STATES; i++) {
378 d1s = state_funcs[i].get(domain1);
379 d2s = state_funcs[i].get(domain2);
380 if(d1s && !d2s)
381 return -1;
382 if(d2s && !d1s)
383 return 1;
384 }
385 return 0;
386 }
388 /* Prints domain state in abbreviated letter format */
389 static void print_state(xenstat_domain *domain)
390 {
391 unsigned int i;
392 for(i = 0; i < NUM_STATES; i++)
393 print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
394 : '-');
395 }
397 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
398 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
399 {
400 return -compare(xenstat_domain_cpu_ns(domain1),
401 xenstat_domain_cpu_ns(domain2));
402 }
404 /* Prints domain cpu usage in seconds */
405 static void print_cpu(xenstat_domain *domain)
406 {
407 print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
408 }
410 /* Computes the CPU percentage used for a specified domain */
411 static double get_cpu_pct(xenstat_domain *domain)
412 {
413 xenstat_domain *old_domain;
414 double us_elapsed;
416 /* Can't calculate CPU percentage without a previous sample. */
417 if(prev_node == NULL)
418 return 0.0;
420 old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
421 if(old_domain == NULL)
422 return 0.0;
424 /* Calculate the time elapsed in microseconds */
425 us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
426 +(curtime.tv_usec - oldtime.tv_usec));
428 /* In the following, nanoseconds must be multiplied by 1000.0 to
429 * convert to microseconds, then divided by 100.0 to get a percentage,
430 * resulting in a multiplication by 10.0 */
431 return ((xenstat_domain_cpu_ns(domain)
432 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
433 }
435 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
436 {
437 return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
438 }
440 /* Prints cpu percentage statistic */
441 static void print_cpu_pct(xenstat_domain *domain)
442 {
443 print("%6.1f", get_cpu_pct(domain));
444 }
446 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
447 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
448 {
449 return -compare(xenstat_domain_cur_mem(domain1),
450 xenstat_domain_cur_mem(domain2));
451 }
453 /* Prints current memory statistic */
454 static void print_mem(xenstat_domain *domain)
455 {
456 print("%10llu", xenstat_domain_cur_mem(domain)/1024);
457 }
459 /* Prints memory percentage statistic, ratio of current domain memory to total
460 * node memory */
461 static void print_mem_pct(xenstat_domain *domain)
462 {
463 print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
464 (double)xenstat_node_tot_mem(cur_node) * 100);
465 }
467 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
468 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
469 {
470 return -compare(xenstat_domain_max_mem(domain1),
471 xenstat_domain_max_mem(domain2));
472 }
474 /* Prints maximum domain memory statistic in KB */
475 static void print_maxmem(xenstat_domain *domain)
476 {
477 unsigned long long max_mem = xenstat_domain_max_mem(domain);
478 if(max_mem == ((unsigned long long)-1))
479 print("%10s", "no limit");
480 else
481 print("%10llu", max_mem/1024);
482 }
484 /* Prints memory percentage statistic, ratio of current domain memory to total
485 * node memory */
486 static void print_max_pct(xenstat_domain *domain)
487 {
488 if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
489 print("%9s", "n/a");
490 else
491 print("%9.1f", (double)xenstat_domain_max_mem(domain) /
492 (double)xenstat_node_tot_mem(cur_node) * 100);
493 }
495 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
496 * <,=,> */
497 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
498 {
499 return -compare(xenstat_domain_num_vcpus(domain1),
500 xenstat_domain_num_vcpus(domain2));
501 }
503 /* Prints number of virtual CPUs statistic */
504 static void print_vcpus(xenstat_domain *domain)
505 {
506 print("%5u", xenstat_domain_num_vcpus(domain));
507 }
509 /* Compares number of virtual networks of two domains, returning -1,0,1 for
510 * <,=,> */
511 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
512 {
513 return -compare(xenstat_domain_num_networks(domain1),
514 xenstat_domain_num_networks(domain2));
515 }
517 /* Prints number of virtual networks statistic */
518 static void print_nets(xenstat_domain *domain)
519 {
520 print("%4u", xenstat_domain_num_networks(domain));
521 }
523 /* Compares number of total network tx bytes of two domains, returning -1,0,1
524 * for <,=,> */
525 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
526 {
527 return -compare(tot_net_bytes(domain1, FALSE),
528 tot_net_bytes(domain2, FALSE));
529 }
531 /* Prints number of total network tx bytes statistic */
532 static void print_net_tx(xenstat_domain *domain)
533 {
534 print("%8llu", tot_net_bytes(domain, FALSE)/1024);
535 }
537 /* Compares number of total network rx bytes of two domains, returning -1,0,1
538 * for <,=,> */
539 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
540 {
541 return -compare(tot_net_bytes(domain1, TRUE),
542 tot_net_bytes(domain2, TRUE));
543 }
545 /* Prints number of total network rx bytes statistic */
546 static void print_net_rx(xenstat_domain *domain)
547 {
548 print("%8llu", tot_net_bytes(domain, TRUE)/1024);
549 }
551 /* Gets number of total network bytes statistic, if rx true, then rx bytes
552 * otherwise tx bytes
553 */
554 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
555 {
556 int i = 0;
557 xenstat_network *network;
558 unsigned num_networks = 0;
559 unsigned long long total = 0;
561 /* How many networks? */
562 num_networks = xenstat_domain_num_networks(domain);
564 /* Dump information for each network */
565 for (i=0; i < num_networks; i++) {
566 /* Next get the network information */
567 network = xenstat_domain_network(domain,i);
568 if (rx_flag)
569 total += xenstat_network_rbytes(network);
570 else
571 total += xenstat_network_tbytes(network);
572 }
574 return total;
575 }
577 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
578 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
579 {
580 return compare(xenstat_domain_ssid(domain1),
581 xenstat_domain_ssid(domain2));
582 }
584 /* Prints ssid statistic */
585 static void print_ssid(xenstat_domain *domain)
586 {
587 print("%4u", xenstat_domain_ssid(domain));
588 }
590 /* Section printing functions */
591 /* Prints the top summary, above the domain table */
592 void do_summary(void)
593 {
594 #define TIME_STR_LEN 9
595 const char *TIME_STR_FORMAT = "%H:%M:%S";
596 char time_str[TIME_STR_LEN];
597 const char *ver_str;
598 unsigned run = 0, block = 0, pause = 0,
599 crash = 0, dying = 0, shutdown = 0;
600 unsigned i, num_domains = 0;
601 unsigned long long used = 0;
602 xenstat_domain *domain;
604 /* Print program name, current time, and number of domains */
605 strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT,
606 localtime(&curtime.tv_sec));
607 num_domains = xenstat_node_num_domains(cur_node);
608 ver_str = xenstat_node_xen_version(cur_node);
609 print("xentop - %s Xen %s\n", time_str, ver_str);
611 /* Tabulate what states domains are in for summary */
612 for (i=0; i < num_domains; i++) {
613 domain = xenstat_node_domain_by_index(cur_node,i);
614 if (xenstat_domain_running(domain)) run++;
615 else if (xenstat_domain_blocked(domain)) block++;
616 else if (xenstat_domain_paused(domain)) pause++;
617 else if (xenstat_domain_shutdown(domain)) shutdown++;
618 else if (xenstat_domain_crashed(domain)) crash++;
619 else if (xenstat_domain_dying(domain)) dying++;
620 }
622 print("%u domains: %u running, %u blocked, %u paused, "
623 "%u crashed, %u dying, %u shutdown \n",
624 num_domains, run, block, pause, crash, dying, shutdown);
626 used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node);
628 /* Dump node memory and cpu information */
629 print("Mem: %lluk total, %lluk used, %lluk free "
630 "CPUs: %u @ %lluMHz\n",
631 xenstat_node_tot_mem(cur_node)/1024, used/1024,
632 xenstat_node_free_mem(cur_node)/1024,
633 xenstat_node_num_cpus(cur_node),
634 xenstat_node_cpu_hz(cur_node)/1000000);
635 }
637 /* Display the top header for the domain table */
638 void do_header(void)
639 {
640 field_id i;
642 /* Turn on REVERSE highlight attribute for headings */
643 attron(A_REVERSE);
644 for(i = 0; i < NUM_FIELDS; i++) {
645 if(i != 0)
646 print(" ");
647 /* The BOLD attribute is turned on for the sort column */
648 if(i == sort_field)
649 attron(A_BOLD);
650 print("%*s", fields[i].default_width, fields[i].header);
651 if(i == sort_field)
652 attroff(A_BOLD);
653 }
654 attroff(A_REVERSE);
655 print("\n");
656 }
658 /* Displays bottom status line or current prompt */
659 void do_bottom_line(void)
660 {
661 move(lines()-1, 2);
663 if (prompt != NULL) {
664 printw("%s: %s", prompt, prompt_val);
665 } else {
666 addch(A_REVERSE | 'D'); addstr("elay ");
668 /* network */
669 addch(A_REVERSE | 'N');
670 attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
671 addstr(" ");
673 /* vcpus */
674 addch(A_REVERSE | 'V');
675 attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
676 addstr(" ");
678 /* repeat */
679 addch(A_REVERSE | 'R');
680 attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
681 addstr(" ");
683 /* sort order */
684 addch(A_REVERSE | 'S'); addstr("ort order ");
686 addch(A_REVERSE | 'Q'); addstr("uit ");
687 }
688 }
690 /* Prints Domain information */
691 void do_domain(xenstat_domain *domain)
692 {
693 unsigned int i;
694 for(i = 0; i < NUM_FIELDS; i++) {
695 if(i != 0)
696 print(" ");
697 if(i == sort_field)
698 attron(A_BOLD);
699 fields[i].print(domain);
700 if(i == sort_field)
701 attroff(A_BOLD);
702 }
703 print("\n");
704 }
706 /* Output all vcpu information */
707 void do_vcpu(xenstat_domain *domain)
708 {
709 int i = 0;
710 unsigned num_vcpus = 0;
711 xenstat_vcpu *vcpu;
713 print("VCPUs(sec): ");
715 num_vcpus = xenstat_domain_num_vcpus(domain);
717 /* for all online vcpus dump out values */
718 for (i=0; i< num_vcpus; i++) {
719 vcpu = xenstat_domain_vcpu(domain,i);
721 if (xenstat_vcpu_online(vcpu) > 0) {
722 if (i != 0 && (i%5)==0)
723 print("\n ");
724 print(" %2u: %10llus", i,
725 xenstat_vcpu_ns(vcpu)/1000000000);
726 }
727 }
728 print("\n");
729 }
731 /* Output all network information */
732 void do_network(xenstat_domain *domain)
733 {
734 int i = 0;
735 xenstat_network *network;
736 unsigned num_networks = 0;
738 /* How many networks? */
739 num_networks = xenstat_domain_num_networks(domain);
741 /* Dump information for each network */
742 for (i=0; i < num_networks; i++) {
743 /* Next get the network information */
744 network = xenstat_domain_network(domain,i);
746 print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop ",
747 i,
748 xenstat_network_rbytes(network),
749 xenstat_network_rpackets(network),
750 xenstat_network_rerrs(network),
751 xenstat_network_rdrop(network));
753 print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
754 xenstat_network_tbytes(network),
755 xenstat_network_tpackets(network),
756 xenstat_network_terrs(network),
757 xenstat_network_tdrop(network));
758 }
759 }
761 static void top(void)
762 {
763 xenstat_domain **domains;
764 unsigned int i, num_domains = 0;
766 /* Now get the node information */
767 if (prev_node != NULL)
768 xenstat_free_node(prev_node);
769 prev_node = cur_node;
770 cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
771 if (cur_node == NULL)
772 fail("Failed to retrieve statistics from libxenstat\n");
774 /* dump summary top information */
775 do_summary();
777 /* Count the number of domains for which to report data */
778 num_domains = xenstat_node_num_domains(cur_node);
780 domains = malloc(num_domains*sizeof(xenstat_domain *));
781 if(domains == NULL)
782 fail("Failed to allocate memory\n");
784 for (i=0; i < num_domains; i++)
785 domains[i] = xenstat_node_domain_by_index(cur_node, i);
787 /* Sort */
788 qsort(domains, num_domains, sizeof(xenstat_domain *),
789 (int(*)(const void *, const void *))compare_domains);
791 if(first_domain_index >= num_domains)
792 first_domain_index = num_domains-1;
794 for (i = first_domain_index; i < num_domains; i++) {
795 if(current_row() == lines()-1)
796 break;
797 if (i == first_domain_index || repeat_header)
798 do_header();
799 do_domain(domains[i]);
800 if (show_vcpus)
801 do_vcpu(domains[i]);
802 if (show_networks)
803 do_network(domains[i]);
804 }
806 do_bottom_line();
807 }
809 int main(int argc, char **argv)
810 {
811 int opt, optind = 0;
812 int ch = ERR;
814 struct option lopts[] = {
815 { "help", no_argument, NULL, 'h' },
816 { "version", no_argument, NULL, 'V' },
817 { "networks", no_argument, NULL, 'n' },
818 { "repeat-header", no_argument, NULL, 'r' },
819 { "vcpus", no_argument, NULL, 'v' },
820 { "delay", required_argument, NULL, 'd' },
821 { 0, 0, 0, 0 },
822 };
823 const char *sopts = "hVbnvd:";
825 if (atexit(cleanup) != 0)
826 fail("Failed to install cleanup handler.\n");
828 while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
829 switch (opt) {
830 case 'h':
831 case '?':
832 default:
833 usage(argv[0]);
834 exit(0);
835 case 'V':
836 version();
837 exit(0);
838 case 'n':
839 show_networks = 1;
840 break;
841 case 'r':
842 repeat_header = 1;
843 break;
844 case 'v':
845 show_vcpus = 1;
846 break;
847 case 'd':
848 delay = atoi(optarg);
849 break;
850 }
851 }
853 /* Get xenstat handle */
854 xhandle = xenstat_init();
855 if (xhandle == NULL)
856 fail("Failed to initialize xenstat library\n");
858 /* Begin curses stuff */
859 initscr();
860 start_color();
861 cbreak();
862 noecho();
863 nonl();
864 keypad(stdscr, TRUE);
865 halfdelay(5);
866 use_default_colors();
867 init_pair(1, -1, COLOR_YELLOW);
869 do {
870 gettimeofday(&curtime, NULL);
871 if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
872 clear();
873 top();
874 oldtime = curtime;
875 refresh();
876 }
877 ch = getch();
878 } while (handle_key(ch));
880 /* Cleanup occurs in cleanup(), so no work to do here. */
882 return 0;
883 }