ia64/xen-unstable

view tools/xenstat/xentop/xentop.c @ 14166:69dec539c19f

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