ia64/xen-unstable

view tools/xenstat/xentop/xentop.c @ 17824:f70dff36213b

xenstat: some cleanups
sprintf -> snprintf
malloc(n * m) -> calloc(n, m)
get rid of a cast

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 10 14:15:53 2008 +0100 (2008-06-10)
parents 2ed94b9b10b3
children 750919688b61
line source
1 /*
2 * Copyright (C) International Business Machines Corp., 2005
3 * Author(s): Judy Fischbach <jfisch@cs.pdx.edu>
4 * David Hendricks <cro_marmot@comcast.net>
5 * Josh Triplett <josh@kernel.org>
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 <stdarg.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #if defined(__linux__)
33 #include <linux/kdev_t.h>
34 #endif
36 #include <xenstat.h>
38 #define XENTOP_VERSION "1.0"
40 #define XENTOP_DISCLAIMER \
41 "Copyright (C) 2005 International Business Machines Corp\n"\
42 "This is free software; see the source for copying conditions.There is NO\n"\
43 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
44 #define XENTOP_BUGSTO "Report bugs to <xen-tools@lists.xensource.com>.\n"
46 #define _GNU_SOURCE
47 #include <getopt.h>
49 #if !defined(__GNUC__) && !defined(__GNUG__)
50 #define __attribute__(arg) /* empty */
51 #endif
53 #define KEY_ESCAPE '\x1B'
55 #ifdef HOST_SunOS
56 /* Old curses library on Solaris takes non-const strings. Also, ERR interferes
57 * with curse's definition.
58 */
59 #undef ERR
60 #define ERR (-1)
61 #define curses_str_t char *
62 #else
63 #define curses_str_t const char *
64 #endif
66 /*
67 * Function prototypes
68 */
69 /* Utility functions */
70 static void usage(const char *);
71 static void version(void);
72 static void cleanup(void);
73 static void fail(const char *);
74 static int current_row(void);
75 static int lines(void);
76 static void print(const char *, ...) __attribute__((format(printf,1,2)));
77 static void attr_addstr(int attr, const char *str);
78 static void set_delay(char *value);
79 static void set_prompt(char *new_prompt, void (*func)(char *));
80 static int handle_key(int);
81 static int compare(unsigned long long, unsigned long long);
82 static int compare_domains(xenstat_domain **, xenstat_domain **);
83 static unsigned long long tot_net_bytes( xenstat_domain *, int);
84 static unsigned long long tot_vbd_reqs( xenstat_domain *, int);
86 /* Field functions */
87 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2);
88 static void print_state(xenstat_domain *domain);
89 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2);
90 static void print_cpu(xenstat_domain *domain);
91 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2);
92 static void print_cpu_pct(xenstat_domain *domain);
93 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2);
94 static void print_mem(xenstat_domain *domain);
95 static void print_mem_pct(xenstat_domain *domain);
96 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2);
97 static void print_maxmem(xenstat_domain *domain);
98 static void print_max_pct(xenstat_domain *domain);
99 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2);
100 static void print_vcpus(xenstat_domain *domain);
101 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2);
102 static void print_nets(xenstat_domain *domain);
103 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2);
104 static void print_net_tx(xenstat_domain *domain);
105 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2);
106 static void print_net_rx(xenstat_domain *domain);
107 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2);
108 static void print_ssid(xenstat_domain *domain);
109 static int compare_name(xenstat_domain *domain1, xenstat_domain *domain2);
110 static void print_name(xenstat_domain *domain);
111 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2);
112 static void print_vbds(xenstat_domain *domain);
113 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2);
114 static void print_vbd_oo(xenstat_domain *domain);
115 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2);
116 static void print_vbd_rd(xenstat_domain *domain);
117 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2);
118 static void print_vbd_wr(xenstat_domain *domain);
121 /* Section printing functions */
122 static void do_summary(void);
123 static void do_header(void);
124 static void do_bottom_line(void);
125 static void do_domain(xenstat_domain *);
126 static void do_vcpu(xenstat_domain *);
127 static void do_network(xenstat_domain *);
128 static void do_vbd(xenstat_domain *);
129 static void top(void);
131 /* Field types */
132 typedef enum field_id {
133 FIELD_DOMID,
134 FIELD_NAME,
135 FIELD_STATE,
136 FIELD_CPU,
137 FIELD_CPU_PCT,
138 FIELD_MEM,
139 FIELD_MEM_PCT,
140 FIELD_MAXMEM,
141 FIELD_MAX_PCT,
142 FIELD_VCPUS,
143 FIELD_NETS,
144 FIELD_NET_TX,
145 FIELD_NET_RX,
146 FIELD_VBDS,
147 FIELD_VBD_OO,
148 FIELD_VBD_RD,
149 FIELD_VBD_WR,
150 FIELD_SSID
151 } field_id;
153 typedef struct field {
154 field_id num;
155 const char *header;
156 unsigned int default_width;
157 int (*compare)(xenstat_domain *domain1, xenstat_domain *domain2);
158 void (*print)(xenstat_domain *domain);
159 } field;
161 field fields[] = {
162 { FIELD_NAME, "NAME", 10, compare_name, print_name },
163 { FIELD_STATE, "STATE", 6, compare_state, print_state },
164 { FIELD_CPU, "CPU(sec)", 10, compare_cpu, print_cpu },
165 { FIELD_CPU_PCT, "CPU(%)", 6, compare_cpu_pct, print_cpu_pct },
166 { FIELD_MEM, "MEM(k)", 10, compare_mem, print_mem },
167 { FIELD_MEM_PCT, "MEM(%)", 6, compare_mem, print_mem_pct },
168 { FIELD_MAXMEM, "MAXMEM(k)", 10, compare_maxmem, print_maxmem },
169 { FIELD_MAX_PCT, "MAXMEM(%)", 9, compare_maxmem, print_max_pct },
170 { FIELD_VCPUS, "VCPUS", 5, compare_vcpus, print_vcpus },
171 { FIELD_NETS, "NETS", 4, compare_nets, print_nets },
172 { FIELD_NET_TX, "NETTX(k)", 8, compare_net_tx, print_net_tx },
173 { FIELD_NET_RX, "NETRX(k)", 8, compare_net_rx, print_net_rx },
174 { FIELD_VBDS, "VBDS", 4, compare_vbds, print_vbds },
175 { FIELD_VBD_OO, "VBD_OO", 8, compare_vbd_oo, print_vbd_oo },
176 { FIELD_VBD_RD, "VBD_RD", 8, compare_vbd_rd, print_vbd_rd },
177 { FIELD_VBD_WR, "VBD_WR", 8, compare_vbd_wr, print_vbd_wr },
178 { FIELD_SSID, "SSID", 4, compare_ssid, print_ssid }
179 };
181 const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field);
183 /* Globals */
184 struct timeval curtime, oldtime;
185 xenstat_handle *xhandle = NULL;
186 xenstat_node *prev_node = NULL;
187 xenstat_node *cur_node = NULL;
188 field_id sort_field = FIELD_DOMID;
189 unsigned int first_domain_index = 0;
190 unsigned int delay = 3;
191 unsigned int batch = 0;
192 unsigned int loop = 1;
193 unsigned int iterations = 0;
194 int show_vcpus = 0;
195 int show_networks = 0;
196 int show_vbds = 0;
197 int repeat_header = 0;
198 #define PROMPT_VAL_LEN 80
199 char *prompt = NULL;
200 char prompt_val[PROMPT_VAL_LEN];
201 int prompt_val_len = 0;
202 void (*prompt_complete_func)(char *);
204 static WINDOW *cwin;
206 /*
207 * Function definitions
208 */
210 /* Utility functions */
212 /* Print usage message, using given program name */
213 static void usage(const char *program)
214 {
215 printf("Usage: %s [OPTION]\n"
216 "Displays ongoing information about xen vm resources \n\n"
217 "-h, --help display this help and exit\n"
218 "-V, --version output version information and exit\n"
219 "-d, --delay=SECONDS seconds between updates (default 3)\n"
220 "-n, --networks output vif network data\n"
221 "-x, --vbds output vbd block device data\n"
222 "-r, --repeat-header repeat table header before each domain\n"
223 "-v, --vcpus output vcpu data\n"
224 "-b, --batch output in batch mode, no user input accepted\n"
225 "-i, --iterations number of iterations before exiting\n"
226 "\n" XENTOP_BUGSTO,
227 program);
228 return;
229 }
231 /* Print program version information */
232 static void version(void)
233 {
234 printf("xentop " XENTOP_VERSION "\n"
235 "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
236 "\n" XENTOP_DISCLAIMER);
237 }
239 /* Clean up any open resources */
240 static void cleanup(void)
241 {
242 if(cwin != NULL && !isendwin())
243 endwin();
244 if(prev_node != NULL)
245 xenstat_free_node(prev_node);
246 if(cur_node != NULL)
247 xenstat_free_node(cur_node);
248 if(xhandle != NULL)
249 xenstat_uninit(xhandle);
250 }
252 /* Display the given message and gracefully exit */
253 static void fail(const char *str)
254 {
255 if(cwin != NULL && !isendwin())
256 endwin();
257 fprintf(stderr, str);
258 exit(1);
259 }
261 /* Return the row containing the cursor. */
262 static int current_row(void)
263 {
264 int y, x;
265 getyx(stdscr, y, x);
266 return y;
267 }
269 /* Return the number of lines on the screen. */
270 static int lines(void)
271 {
272 int y, x;
273 getmaxyx(stdscr, y, x);
274 return y;
275 }
277 /* printf-style print function which calls printw, but only if the cursor is
278 * not on the last line. */
279 static void print(const char *fmt, ...)
280 {
281 va_list args;
283 if (!batch) {
284 if((current_row() < lines()-1)) {
285 va_start(args, fmt);
286 vwprintw(stdscr, (curses_str_t)fmt, args);
287 va_end(args);
288 }
289 } else {
290 va_start(args, fmt);
291 vprintf(fmt, args);
292 va_end(args);
293 }
294 }
296 static void xentop_attron(int attr)
297 {
298 if (!batch)
299 attron(attr);
300 }
302 static void xentop_attroff(int attr)
303 {
304 if (!batch)
305 attroff(attr);
306 }
308 /* Print a string with the given attributes set. */
309 static void attr_addstr(int attr, const char *str)
310 {
311 xentop_attron(attr);
312 addstr((curses_str_t)str);
313 xentop_attroff(attr);
314 }
316 /* Handle setting the delay from the user-supplied value in prompt_val */
317 static void set_delay(char *value)
318 {
319 int new_delay;
320 new_delay = atoi(value);
321 if(new_delay > 0)
322 delay = new_delay;
323 }
325 /* Enable prompting mode with the given prompt string; call the given function
326 * when a value is available. */
327 static void set_prompt(char *new_prompt, void (*func)(char *))
328 {
329 prompt = new_prompt;
330 prompt_val[0] = '\0';
331 prompt_val_len = 0;
332 prompt_complete_func = func;
333 }
335 /* Handle user input, return 0 if the program should quit, or 1 if not */
336 static int handle_key(int ch)
337 {
338 if(prompt == NULL) {
339 /* Not prompting for input; handle interactive commands */
340 switch(ch) {
341 case 'n': case 'N':
342 show_networks ^= 1;
343 break;
344 case 'b': case 'B':
345 show_vbds ^= 1;
346 break;
347 case 'r': case 'R':
348 repeat_header ^= 1;
349 break;
350 case 's': case 'S':
351 sort_field = (sort_field + 1) % NUM_FIELDS;
352 break;
353 case 'v': case 'V':
354 show_vcpus ^= 1;
355 break;
356 case KEY_DOWN:
357 first_domain_index++;
358 break;
359 case KEY_UP:
360 if(first_domain_index > 0)
361 first_domain_index--;
362 break;
363 case 'd': case 'D':
364 set_prompt("Delay(sec)", set_delay);
365 break;
366 case 'q': case 'Q': case KEY_ESCAPE:
367 return 0;
368 }
369 } else {
370 /* Prompting for input; handle line editing */
371 switch(ch) {
372 case '\r':
373 prompt_complete_func(prompt_val);
374 set_prompt(NULL, NULL);
375 break;
376 case KEY_ESCAPE:
377 set_prompt(NULL, NULL);
378 break;
379 case KEY_BACKSPACE:
380 if(prompt_val_len > 0)
381 prompt_val[--prompt_val_len] = '\0';
382 default:
383 if((prompt_val_len+1) < PROMPT_VAL_LEN
384 && isprint(ch)) {
385 prompt_val[prompt_val_len++] = (char)ch;
386 prompt_val[prompt_val_len] = '\0';
387 }
388 }
389 }
391 return 1;
392 }
394 /* Compares two integers, returning -1,0,1 for <,=,> */
395 static int compare(unsigned long long i1, unsigned long long i2)
396 {
397 if(i1 < i2)
398 return -1;
399 if(i1 > i2)
400 return 1;
401 return 0;
402 }
404 /* Comparison function for use with qsort. Compares two domains using the
405 * current sort field. */
406 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
407 {
408 return fields[sort_field].compare(*domain1, *domain2);
409 }
411 /* Field functions */
413 /* Compare domain names, returning -1,0,1 for <,=,> */
414 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
415 {
416 return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
417 }
419 /* Prints domain name */
420 void print_name(xenstat_domain *domain)
421 {
422 print("%10s", xenstat_domain_name(domain));
423 }
425 struct {
426 unsigned int (*get)(xenstat_domain *);
427 char ch;
428 } state_funcs[] = {
429 { xenstat_domain_dying, 'd' },
430 { xenstat_domain_shutdown, 's' },
431 { xenstat_domain_blocked, 'b' },
432 { xenstat_domain_crashed, 'c' },
433 { xenstat_domain_paused, 'p' },
434 { xenstat_domain_running, 'r' }
435 };
436 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
438 /* Compare states of two domains, returning -1,0,1 for <,=,> */
439 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
440 {
441 unsigned int i, d1s, d2s;
442 for(i = 0; i < NUM_STATES; i++) {
443 d1s = state_funcs[i].get(domain1);
444 d2s = state_funcs[i].get(domain2);
445 if(d1s && !d2s)
446 return -1;
447 if(d2s && !d1s)
448 return 1;
449 }
450 return 0;
451 }
453 /* Prints domain state in abbreviated letter format */
454 static void print_state(xenstat_domain *domain)
455 {
456 unsigned int i;
457 for(i = 0; i < NUM_STATES; i++)
458 print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
459 : '-');
460 }
462 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
463 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
464 {
465 return -compare(xenstat_domain_cpu_ns(domain1),
466 xenstat_domain_cpu_ns(domain2));
467 }
469 /* Prints domain cpu usage in seconds */
470 static void print_cpu(xenstat_domain *domain)
471 {
472 print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
473 }
475 /* Computes the CPU percentage used for a specified domain */
476 static double get_cpu_pct(xenstat_domain *domain)
477 {
478 xenstat_domain *old_domain;
479 double us_elapsed;
481 /* Can't calculate CPU percentage without a previous sample. */
482 if(prev_node == NULL)
483 return 0.0;
485 old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
486 if(old_domain == NULL)
487 return 0.0;
489 /* Calculate the time elapsed in microseconds */
490 us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
491 +(curtime.tv_usec - oldtime.tv_usec));
493 /* In the following, nanoseconds must be multiplied by 1000.0 to
494 * convert to microseconds, then divided by 100.0 to get a percentage,
495 * resulting in a multiplication by 10.0 */
496 return ((xenstat_domain_cpu_ns(domain)
497 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
498 }
500 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
501 {
502 return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
503 }
505 /* Prints cpu percentage statistic */
506 static void print_cpu_pct(xenstat_domain *domain)
507 {
508 print("%6.1f", get_cpu_pct(domain));
509 }
511 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
512 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
513 {
514 return -compare(xenstat_domain_cur_mem(domain1),
515 xenstat_domain_cur_mem(domain2));
516 }
518 /* Prints current memory statistic */
519 static void print_mem(xenstat_domain *domain)
520 {
521 print("%10llu", xenstat_domain_cur_mem(domain)/1024);
522 }
524 /* Prints memory percentage statistic, ratio of current domain memory to total
525 * node memory */
526 static void print_mem_pct(xenstat_domain *domain)
527 {
528 print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
529 (double)xenstat_node_tot_mem(cur_node) * 100);
530 }
532 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
533 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
534 {
535 return -compare(xenstat_domain_max_mem(domain1),
536 xenstat_domain_max_mem(domain2));
537 }
539 /* Prints maximum domain memory statistic in KB */
540 static void print_maxmem(xenstat_domain *domain)
541 {
542 unsigned long long max_mem = xenstat_domain_max_mem(domain);
543 if(max_mem == ((unsigned long long)-1))
544 print("%10s", "no limit");
545 else
546 print("%10llu", max_mem/1024);
547 }
549 /* Prints memory percentage statistic, ratio of current domain memory to total
550 * node memory */
551 static void print_max_pct(xenstat_domain *domain)
552 {
553 if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
554 print("%9s", "n/a");
555 else
556 print("%9.1f", (double)xenstat_domain_max_mem(domain) /
557 (double)xenstat_node_tot_mem(cur_node) * 100);
558 }
560 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
561 * <,=,> */
562 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
563 {
564 return -compare(xenstat_domain_num_vcpus(domain1),
565 xenstat_domain_num_vcpus(domain2));
566 }
568 /* Prints number of virtual CPUs statistic */
569 static void print_vcpus(xenstat_domain *domain)
570 {
571 print("%5u", xenstat_domain_num_vcpus(domain));
572 }
574 /* Compares number of virtual networks of two domains, returning -1,0,1 for
575 * <,=,> */
576 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
577 {
578 return -compare(xenstat_domain_num_networks(domain1),
579 xenstat_domain_num_networks(domain2));
580 }
582 /* Prints number of virtual networks statistic */
583 static void print_nets(xenstat_domain *domain)
584 {
585 print("%4u", xenstat_domain_num_networks(domain));
586 }
588 /* Compares number of total network tx bytes of two domains, returning -1,0,1
589 * for <,=,> */
590 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
591 {
592 return -compare(tot_net_bytes(domain1, FALSE),
593 tot_net_bytes(domain2, FALSE));
594 }
596 /* Prints number of total network tx bytes statistic */
597 static void print_net_tx(xenstat_domain *domain)
598 {
599 print("%8llu", tot_net_bytes(domain, FALSE)/1024);
600 }
602 /* Compares number of total network rx bytes of two domains, returning -1,0,1
603 * for <,=,> */
604 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
605 {
606 return -compare(tot_net_bytes(domain1, TRUE),
607 tot_net_bytes(domain2, TRUE));
608 }
610 /* Prints number of total network rx bytes statistic */
611 static void print_net_rx(xenstat_domain *domain)
612 {
613 print("%8llu", tot_net_bytes(domain, TRUE)/1024);
614 }
616 /* Gets number of total network bytes statistic, if rx true, then rx bytes
617 * otherwise tx bytes
618 */
619 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
620 {
621 int i = 0;
622 xenstat_network *network;
623 unsigned num_networks = 0;
624 unsigned long long total = 0;
626 /* How many networks? */
627 num_networks = xenstat_domain_num_networks(domain);
629 /* Dump information for each network */
630 for (i=0; i < num_networks; i++) {
631 /* Next get the network information */
632 network = xenstat_domain_network(domain,i);
633 if (rx_flag)
634 total += xenstat_network_rbytes(network);
635 else
636 total += xenstat_network_tbytes(network);
637 }
639 return total;
640 }
642 /* Compares number of virtual block devices of two domains,
643 returning -1,0,1 for * <,=,> */
644 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2)
645 {
646 return -compare(xenstat_domain_num_vbds(domain1),
647 xenstat_domain_num_vbds(domain2));
648 }
650 /* Prints number of virtual block devices statistic */
651 static void print_vbds(xenstat_domain *domain)
652 {
653 print("%4u", xenstat_domain_num_vbds(domain));
654 }
656 /* Compares number of total VBD OO requests of two domains,
657 returning -1,0,1 * for <,=,> */
658 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2)
659 {
660 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_OO),
661 tot_vbd_reqs(domain2, FIELD_VBD_OO));
662 }
664 /* Prints number of total VBD OO requests statistic */
665 static void print_vbd_oo(xenstat_domain *domain)
666 {
667 print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_OO));
668 }
670 /* Compares number of total VBD READ requests of two domains,
671 returning -1,0,1 * for <,=,> */
672 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2)
673 {
674 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RD),
675 tot_vbd_reqs(domain2, FIELD_VBD_RD));
676 }
678 /* Prints number of total VBD READ requests statistic */
679 static void print_vbd_rd(xenstat_domain *domain)
680 {
681 print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_RD));
682 }
684 /* Compares number of total VBD WRITE requests of two domains,
685 returning -1,0,1 * for <,=,> */
686 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2)
687 {
688 return -compare(tot_vbd_reqs(domain1,FIELD_VBD_WR),
689 tot_vbd_reqs(domain2,FIELD_VBD_WR));
690 }
692 /* Prints number of total VBD WRITE requests statistic */
693 static void print_vbd_wr(xenstat_domain *domain)
694 {
695 print("%8llu", tot_vbd_reqs(domain,FIELD_VBD_WR));
696 }
698 /* Gets number of total VBD requests statistic,
699 * if flag is FIELD_VBD_OO, then OO requests,
700 * if flag is FIELD_VBD_RD, then READ requests and
701 * if flag is FIELD_VBD_WR, then WRITE requests.
702 */
703 static unsigned long long tot_vbd_reqs(xenstat_domain *domain, int flag)
704 {
705 int i = 0;
706 xenstat_vbd *vbd;
707 unsigned num_vbds = 0;
708 unsigned long long total = 0;
710 num_vbds = xenstat_domain_num_vbds(domain);
712 for ( i=0 ; i < num_vbds ; i++) {
713 vbd = xenstat_domain_vbd(domain,i);
714 switch(flag) {
715 case FIELD_VBD_OO:
716 total += xenstat_vbd_oo_reqs(vbd);
717 break;
718 case FIELD_VBD_RD:
719 total += xenstat_vbd_rd_reqs(vbd);
720 break;
721 case FIELD_VBD_WR:
722 total += xenstat_vbd_wr_reqs(vbd);
723 break;
724 default:
725 break;
726 }
727 }
729 return total;
730 }
732 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
733 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
734 {
735 return compare(xenstat_domain_ssid(domain1),
736 xenstat_domain_ssid(domain2));
737 }
739 /* Prints ssid statistic */
740 static void print_ssid(xenstat_domain *domain)
741 {
742 print("%4u", xenstat_domain_ssid(domain));
743 }
745 /* Section printing functions */
746 /* Prints the top summary, above the domain table */
747 void do_summary(void)
748 {
749 #define TIME_STR_LEN 9
750 const char *TIME_STR_FORMAT = "%H:%M:%S";
751 char time_str[TIME_STR_LEN];
752 const char *ver_str;
753 unsigned run = 0, block = 0, pause = 0,
754 crash = 0, dying = 0, shutdown = 0;
755 unsigned i, num_domains = 0;
756 unsigned long long used = 0;
757 xenstat_domain *domain;
758 time_t curt;
760 /* Print program name, current time, and number of domains */
761 curt = curtime.tv_sec;
762 strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT, localtime(&curt));
763 num_domains = xenstat_node_num_domains(cur_node);
764 ver_str = xenstat_node_xen_version(cur_node);
765 print("xentop - %s Xen %s\n", time_str, ver_str);
767 /* Tabulate what states domains are in for summary */
768 for (i=0; i < num_domains; i++) {
769 domain = xenstat_node_domain_by_index(cur_node,i);
770 if (xenstat_domain_running(domain)) run++;
771 else if (xenstat_domain_blocked(domain)) block++;
772 else if (xenstat_domain_paused(domain)) pause++;
773 else if (xenstat_domain_shutdown(domain)) shutdown++;
774 else if (xenstat_domain_crashed(domain)) crash++;
775 else if (xenstat_domain_dying(domain)) dying++;
776 }
778 print("%u domains: %u running, %u blocked, %u paused, "
779 "%u crashed, %u dying, %u shutdown \n",
780 num_domains, run, block, pause, crash, dying, shutdown);
782 used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node);
784 /* Dump node memory and cpu information */
785 print("Mem: %lluk total, %lluk used, %lluk free "
786 "CPUs: %u @ %lluMHz\n",
787 xenstat_node_tot_mem(cur_node)/1024, used/1024,
788 xenstat_node_free_mem(cur_node)/1024,
789 xenstat_node_num_cpus(cur_node),
790 xenstat_node_cpu_hz(cur_node)/1000000);
791 }
793 /* Display the top header for the domain table */
794 void do_header(void)
795 {
796 field_id i;
798 /* Turn on REVERSE highlight attribute for headings */
799 xentop_attron(A_REVERSE);
800 for(i = 0; i < NUM_FIELDS; i++) {
801 if (i != 0)
802 print(" ");
803 /* The BOLD attribute is turned on for the sort column */
804 if (i == sort_field)
805 xentop_attron(A_BOLD);
806 print("%*s", fields[i].default_width, fields[i].header);
807 if (i == sort_field)
808 xentop_attroff(A_BOLD);
809 }
810 xentop_attroff(A_REVERSE);
811 print("\n");
812 }
814 /* Displays bottom status line or current prompt */
815 void do_bottom_line(void)
816 {
817 move(lines()-1, 2);
819 if (prompt != NULL) {
820 printw("%s: %s", prompt, prompt_val);
821 } else {
822 addch(A_REVERSE | 'D'); addstr("elay ");
824 /* network */
825 addch(A_REVERSE | 'N');
826 attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
827 addstr(" ");
829 /* VBDs */
830 attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "v");
831 addch(A_REVERSE | 'B');
832 attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "ds");
833 addstr(" ");
836 /* vcpus */
837 addch(A_REVERSE | 'V');
838 attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
839 addstr(" ");
841 /* repeat */
842 addch(A_REVERSE | 'R');
843 attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
844 addstr(" ");
846 /* sort order */
847 addch(A_REVERSE | 'S'); addstr("ort order ");
849 addch(A_REVERSE | 'Q'); addstr("uit ");
850 }
851 }
853 /* Prints Domain information */
854 void do_domain(xenstat_domain *domain)
855 {
856 unsigned int i;
857 for (i = 0; i < NUM_FIELDS; i++) {
858 if (i != 0)
859 print(" ");
860 if (i == sort_field)
861 xentop_attron(A_BOLD);
862 fields[i].print(domain);
863 if (i == sort_field)
864 xentop_attroff(A_BOLD);
865 }
866 print("\n");
867 }
869 /* Output all vcpu information */
870 void do_vcpu(xenstat_domain *domain)
871 {
872 int i = 0;
873 unsigned num_vcpus = 0;
874 xenstat_vcpu *vcpu;
876 print("VCPUs(sec): ");
878 num_vcpus = xenstat_domain_num_vcpus(domain);
880 /* for all online vcpus dump out values */
881 for (i=0; i< num_vcpus; i++) {
882 vcpu = xenstat_domain_vcpu(domain,i);
884 if (xenstat_vcpu_online(vcpu) > 0) {
885 if (i != 0 && (i%5)==0)
886 print("\n ");
887 print(" %2u: %10llus", i,
888 xenstat_vcpu_ns(vcpu)/1000000000);
889 }
890 }
891 print("\n");
892 }
894 /* Output all network information */
895 void do_network(xenstat_domain *domain)
896 {
897 int i = 0;
898 xenstat_network *network;
899 unsigned num_networks = 0;
901 /* How many networks? */
902 num_networks = xenstat_domain_num_networks(domain);
904 /* Dump information for each network */
905 for (i=0; i < num_networks; i++) {
906 /* Next get the network information */
907 network = xenstat_domain_network(domain,i);
909 print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop ",
910 i,
911 xenstat_network_rbytes(network),
912 xenstat_network_rpackets(network),
913 xenstat_network_rerrs(network),
914 xenstat_network_rdrop(network));
916 print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
917 xenstat_network_tbytes(network),
918 xenstat_network_tpackets(network),
919 xenstat_network_terrs(network),
920 xenstat_network_tdrop(network));
921 }
922 }
925 /* Output all VBD information */
926 void do_vbd(xenstat_domain *domain)
927 {
928 int i = 0;
929 xenstat_vbd *vbd;
930 unsigned num_vbds = 0;
932 const char *vbd_type[] = {
933 "Unidentified", /* number 0 */
934 "BlkBack", /* number 1 */
935 "BlkTap", /* number 2 */
936 };
938 num_vbds = xenstat_domain_num_vbds(domain);
940 for (i=0 ; i< num_vbds; i++) {
941 char details[20];
943 vbd = xenstat_domain_vbd(domain,i);
945 #if !defined(__linux__)
946 details[0] = '\0';
947 #else
948 snprintf(details, 20, "[%2x:%2x] ",
949 MAJOR(xenstat_vbd_dev(vbd)),
950 MINOR(xenstat_vbd_dev(vbd)));
951 #endif
953 print("VBD %s %4d %s OO: %8llu RD: %8llu WR: %8llu\n",
954 vbd_type[xenstat_vbd_type(vbd)],
955 xenstat_vbd_dev(vbd), details,
956 xenstat_vbd_oo_reqs(vbd),
957 xenstat_vbd_rd_reqs(vbd),
958 xenstat_vbd_wr_reqs(vbd));
959 }
960 }
962 static void top(void)
963 {
964 xenstat_domain **domains;
965 unsigned int i, num_domains = 0;
967 /* Now get the node information */
968 if (prev_node != NULL)
969 xenstat_free_node(prev_node);
970 prev_node = cur_node;
971 cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
972 if (cur_node == NULL)
973 fail("Failed to retrieve statistics from libxenstat\n");
975 /* dump summary top information */
976 if (!batch)
977 do_summary();
979 /* Count the number of domains for which to report data */
980 num_domains = xenstat_node_num_domains(cur_node);
982 domains = calloc(num_domains, sizeof(xenstat_domain *));
983 if(domains == NULL)
984 fail("Failed to allocate memory\n");
986 for (i=0; i < num_domains; i++)
987 domains[i] = xenstat_node_domain_by_index(cur_node, i);
989 /* Sort */
990 qsort(domains, num_domains, sizeof(xenstat_domain *),
991 (int(*)(const void *, const void *))compare_domains);
993 if(first_domain_index >= num_domains)
994 first_domain_index = num_domains-1;
996 for (i = first_domain_index; i < num_domains; i++) {
997 if(!batch && current_row() == lines()-1)
998 break;
999 if (i == first_domain_index || repeat_header)
1000 do_header();
1001 do_domain(domains[i]);
1002 if (show_vcpus)
1003 do_vcpu(domains[i]);
1004 if (show_networks)
1005 do_network(domains[i]);
1006 if (show_vbds)
1007 do_vbd(domains[i]);
1010 if (!batch)
1011 do_bottom_line();
1013 free(domains);
1016 static int signal_exit;
1018 void signal_exit_handler(int sig)
1020 signal_exit = 1;
1023 int main(int argc, char **argv)
1025 int opt, optind = 0;
1026 int ch = ERR;
1028 struct option lopts[] = {
1029 { "help", no_argument, NULL, 'h' },
1030 { "version", no_argument, NULL, 'V' },
1031 { "networks", no_argument, NULL, 'n' },
1032 { "vbds", no_argument, NULL, 'x' },
1033 { "repeat-header", no_argument, NULL, 'r' },
1034 { "vcpus", no_argument, NULL, 'v' },
1035 { "delay", required_argument, NULL, 'd' },
1036 { "batch", no_argument, NULL, 'b' },
1037 { "iterations", required_argument, NULL, 'i' },
1038 { 0, 0, 0, 0 },
1039 };
1040 const char *sopts = "hVnxrvd:bi:";
1042 if (atexit(cleanup) != 0)
1043 fail("Failed to install cleanup handler.\n");
1045 while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
1046 switch (opt) {
1047 default:
1048 usage(argv[0]);
1049 exit(1);
1050 case '?':
1051 case 'h':
1052 usage(argv[0]);
1053 exit(0);
1054 case 'V':
1055 version();
1056 exit(0);
1057 case 'n':
1058 show_networks = 1;
1059 break;
1060 case 'x':
1061 show_vbds = 1;
1062 break;
1063 case 'r':
1064 repeat_header = 1;
1065 break;
1066 case 'v':
1067 show_vcpus = 1;
1068 break;
1069 case 'd':
1070 delay = atoi(optarg);
1071 break;
1072 case 'b':
1073 batch = 1;
1074 break;
1075 case 'i':
1076 iterations = atoi(optarg);
1077 loop = 0;
1078 break;
1082 /* Get xenstat handle */
1083 xhandle = xenstat_init();
1084 if (xhandle == NULL)
1085 fail("Failed to initialize xenstat library\n");
1087 if (!batch) {
1088 /* Begin curses stuff */
1089 cwin = initscr();
1090 start_color();
1091 cbreak();
1092 noecho();
1093 nonl();
1094 keypad(stdscr, TRUE);
1095 halfdelay(5);
1096 #ifndef __sun__
1097 use_default_colors();
1098 #endif
1099 init_pair(1, -1, COLOR_YELLOW);
1101 do {
1102 gettimeofday(&curtime, NULL);
1103 if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
1104 clear();
1105 top();
1106 oldtime = curtime;
1107 refresh();
1108 if ((!loop) && !(--iterations))
1109 break;
1111 ch = getch();
1112 } while (handle_key(ch));
1113 } else {
1114 struct sigaction sa = {
1115 .sa_handler = signal_exit_handler,
1116 .sa_flags = 0
1117 };
1118 sigemptyset(&sa.sa_mask);
1119 sigaction(SIGINT, &sa, NULL);
1120 sigaction(SIGTERM, &sa, NULL);
1122 do {
1123 gettimeofday(&curtime, NULL);
1124 top();
1125 fflush(stdout);
1126 oldtime = curtime;
1127 if ((!loop) && !(--iterations))
1128 break;
1129 sleep(delay);
1130 } while (!signal_exit);
1133 /* Cleanup occurs in cleanup(), so no work to do here. */
1135 return 0;