debuggers.hg

view tools/xenstat/xentop/xentop.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 9e9746e635f9
children
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);
119 static int compare_vbd_rsect(xenstat_domain *domain1, xenstat_domain *domain2);
120 static void print_vbd_rsect(xenstat_domain *domain);
121 static int compare_vbd_wsect(xenstat_domain *domain1, xenstat_domain *domain2);
122 static void print_vbd_wsect(xenstat_domain *domain);
125 /* Section printing functions */
126 static void do_summary(void);
127 static void do_header(void);
128 static void do_bottom_line(void);
129 static void do_domain(xenstat_domain *);
130 static void do_vcpu(xenstat_domain *);
131 static void do_network(xenstat_domain *);
132 static void do_vbd(xenstat_domain *);
133 static void top(void);
135 /* Field types */
136 typedef enum field_id {
137 FIELD_DOMID,
138 FIELD_NAME,
139 FIELD_STATE,
140 FIELD_CPU,
141 FIELD_CPU_PCT,
142 FIELD_MEM,
143 FIELD_MEM_PCT,
144 FIELD_MAXMEM,
145 FIELD_MAX_PCT,
146 FIELD_VCPUS,
147 FIELD_NETS,
148 FIELD_NET_TX,
149 FIELD_NET_RX,
150 FIELD_VBDS,
151 FIELD_VBD_OO,
152 FIELD_VBD_RD,
153 FIELD_VBD_WR,
154 FIELD_VBD_RSECT,
155 FIELD_VBD_WSECT,
156 FIELD_SSID
157 } field_id;
159 typedef struct field {
160 field_id num;
161 const char *header;
162 unsigned int default_width;
163 int (*compare)(xenstat_domain *domain1, xenstat_domain *domain2);
164 void (*print)(xenstat_domain *domain);
165 } field;
167 field fields[] = {
168 { FIELD_NAME, "NAME", 10, compare_name, print_name },
169 { FIELD_STATE, "STATE", 6, compare_state, print_state },
170 { FIELD_CPU, "CPU(sec)", 10, compare_cpu, print_cpu },
171 { FIELD_CPU_PCT, "CPU(%)", 6, compare_cpu_pct, print_cpu_pct },
172 { FIELD_MEM, "MEM(k)", 10, compare_mem, print_mem },
173 { FIELD_MEM_PCT, "MEM(%)", 6, compare_mem, print_mem_pct },
174 { FIELD_MAXMEM, "MAXMEM(k)", 10, compare_maxmem, print_maxmem },
175 { FIELD_MAX_PCT, "MAXMEM(%)", 9, compare_maxmem, print_max_pct },
176 { FIELD_VCPUS, "VCPUS", 5, compare_vcpus, print_vcpus },
177 { FIELD_NETS, "NETS", 4, compare_nets, print_nets },
178 { FIELD_NET_TX, "NETTX(k)", 8, compare_net_tx, print_net_tx },
179 { FIELD_NET_RX, "NETRX(k)", 8, compare_net_rx, print_net_rx },
180 { FIELD_VBDS, "VBDS", 4, compare_vbds, print_vbds },
181 { FIELD_VBD_OO, "VBD_OO", 8, compare_vbd_oo, print_vbd_oo },
182 { FIELD_VBD_RD, "VBD_RD", 8, compare_vbd_rd, print_vbd_rd },
183 { FIELD_VBD_WR, "VBD_WR", 8, compare_vbd_wr, print_vbd_wr },
184 { FIELD_VBD_RSECT, "VBD_RSECT", 10, compare_vbd_rsect, print_vbd_rsect },
185 { FIELD_VBD_WSECT, "VBD_WSECT", 10, compare_vbd_wsect, print_vbd_wsect },
186 { FIELD_SSID, "SSID", 4, compare_ssid, print_ssid }
187 };
189 const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field);
191 /* Globals */
192 struct timeval curtime, oldtime;
193 xenstat_handle *xhandle = NULL;
194 xenstat_node *prev_node = NULL;
195 xenstat_node *cur_node = NULL;
196 field_id sort_field = FIELD_DOMID;
197 unsigned int first_domain_index = 0;
198 unsigned int delay = 3;
199 unsigned int batch = 0;
200 unsigned int loop = 1;
201 unsigned int iterations = 0;
202 int show_vcpus = 0;
203 int show_networks = 0;
204 int show_vbds = 0;
205 int show_tmem = 0;
206 int repeat_header = 0;
207 int show_full_name = 0;
208 #define PROMPT_VAL_LEN 80
209 char *prompt = NULL;
210 char prompt_val[PROMPT_VAL_LEN];
211 int prompt_val_len = 0;
212 void (*prompt_complete_func)(char *);
214 static WINDOW *cwin;
216 /*
217 * Function definitions
218 */
220 /* Utility functions */
222 /* Print usage message, using given program name */
223 static void usage(const char *program)
224 {
225 printf("Usage: %s [OPTION]\n"
226 "Displays ongoing information about xen vm resources \n\n"
227 "-h, --help display this help and exit\n"
228 "-V, --version output version information and exit\n"
229 "-d, --delay=SECONDS seconds between updates (default 3)\n"
230 "-n, --networks output vif network data\n"
231 "-x, --vbds output vbd block device data\n"
232 "-r, --repeat-header repeat table header before each domain\n"
233 "-v, --vcpus output vcpu data\n"
234 "-b, --batch output in batch mode, no user input accepted\n"
235 "-i, --iterations number of iterations before exiting\n"
236 "-f, --full-name output the full domain name (not truncated)\n"
237 "\n" XENTOP_BUGSTO,
238 program);
239 return;
240 }
242 /* Print program version information */
243 static void version(void)
244 {
245 printf("xentop " XENTOP_VERSION "\n"
246 "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
247 "\n" XENTOP_DISCLAIMER);
248 }
250 /* Clean up any open resources */
251 static void cleanup(void)
252 {
253 if(cwin != NULL && !isendwin())
254 endwin();
255 if(prev_node != NULL)
256 xenstat_free_node(prev_node);
257 if(cur_node != NULL)
258 xenstat_free_node(cur_node);
259 if(xhandle != NULL)
260 xenstat_uninit(xhandle);
261 }
263 /* Display the given message and gracefully exit */
264 static void fail(const char *str)
265 {
266 if(cwin != NULL && !isendwin())
267 endwin();
268 fprintf(stderr, "%s", str);
269 exit(1);
270 }
272 /* Return the row containing the cursor. */
273 static int current_row(void)
274 {
275 int y, x;
276 getyx(stdscr, y, x);
277 return y;
278 }
280 /* Return the number of lines on the screen. */
281 static int lines(void)
282 {
283 int y, x;
284 getmaxyx(stdscr, y, x);
285 return y;
286 }
288 /* printf-style print function which calls printw, but only if the cursor is
289 * not on the last line. */
290 static void print(const char *fmt, ...)
291 {
292 va_list args;
294 if (!batch) {
295 if((current_row() < lines()-1)) {
296 va_start(args, fmt);
297 vwprintw(stdscr, (curses_str_t)fmt, args);
298 va_end(args);
299 }
300 } else {
301 va_start(args, fmt);
302 vprintf(fmt, args);
303 va_end(args);
304 }
305 }
307 static void xentop_attron(int attr)
308 {
309 if (!batch)
310 attron(attr);
311 }
313 static void xentop_attroff(int attr)
314 {
315 if (!batch)
316 attroff(attr);
317 }
319 /* Print a string with the given attributes set. */
320 static void attr_addstr(int attr, const char *str)
321 {
322 xentop_attron(attr);
323 addstr((curses_str_t)str);
324 xentop_attroff(attr);
325 }
327 /* Handle setting the delay from the user-supplied value in prompt_val */
328 static void set_delay(char *value)
329 {
330 int new_delay;
331 new_delay = atoi(value);
332 if(new_delay > 0)
333 delay = new_delay;
334 }
336 /* Enable prompting mode with the given prompt string; call the given function
337 * when a value is available. */
338 static void set_prompt(char *new_prompt, void (*func)(char *))
339 {
340 prompt = new_prompt;
341 prompt_val[0] = '\0';
342 prompt_val_len = 0;
343 prompt_complete_func = func;
344 }
346 /* Handle user input, return 0 if the program should quit, or 1 if not */
347 static int handle_key(int ch)
348 {
349 if(prompt == NULL) {
350 /* Not prompting for input; handle interactive commands */
351 switch(ch) {
352 case 'n': case 'N':
353 show_networks ^= 1;
354 break;
355 case 'b': case 'B':
356 show_vbds ^= 1;
357 break;
358 case 't': case 'T':
359 show_tmem ^= 1;
360 break;
361 case 'r': case 'R':
362 repeat_header ^= 1;
363 break;
364 case 's': case 'S':
365 sort_field = (sort_field + 1) % NUM_FIELDS;
366 break;
367 case 'v': case 'V':
368 show_vcpus ^= 1;
369 break;
370 case KEY_DOWN:
371 first_domain_index++;
372 break;
373 case KEY_UP:
374 if(first_domain_index > 0)
375 first_domain_index--;
376 break;
377 case 'd': case 'D':
378 set_prompt("Delay(sec)", set_delay);
379 break;
380 case 'q': case 'Q': case KEY_ESCAPE:
381 return 0;
382 }
383 } else {
384 /* Prompting for input; handle line editing */
385 switch(ch) {
386 case '\r':
387 prompt_complete_func(prompt_val);
388 set_prompt(NULL, NULL);
389 break;
390 case KEY_ESCAPE:
391 set_prompt(NULL, NULL);
392 break;
393 case KEY_BACKSPACE:
394 if(prompt_val_len > 0)
395 prompt_val[--prompt_val_len] = '\0';
396 default:
397 if((prompt_val_len+1) < PROMPT_VAL_LEN
398 && isprint(ch)) {
399 prompt_val[prompt_val_len++] = (char)ch;
400 prompt_val[prompt_val_len] = '\0';
401 }
402 }
403 }
405 return 1;
406 }
408 /* Compares two integers, returning -1,0,1 for <,=,> */
409 static int compare(unsigned long long i1, unsigned long long i2)
410 {
411 if(i1 < i2)
412 return -1;
413 if(i1 > i2)
414 return 1;
415 return 0;
416 }
418 /* Comparison function for use with qsort. Compares two domains using the
419 * current sort field. */
420 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
421 {
422 return fields[sort_field].compare(*domain1, *domain2);
423 }
425 /* Field functions */
427 /* Compare domain names, returning -1,0,1 for <,=,> */
428 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
429 {
430 return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
431 }
433 /* Prints domain name */
434 void print_name(xenstat_domain *domain)
435 {
436 if(show_full_name)
437 print("%10s", xenstat_domain_name(domain));
438 else
439 print("%10.10s", xenstat_domain_name(domain));
440 }
442 struct {
443 unsigned int (*get)(xenstat_domain *);
444 char ch;
445 } state_funcs[] = {
446 { xenstat_domain_dying, 'd' },
447 { xenstat_domain_shutdown, 's' },
448 { xenstat_domain_blocked, 'b' },
449 { xenstat_domain_crashed, 'c' },
450 { xenstat_domain_paused, 'p' },
451 { xenstat_domain_running, 'r' }
452 };
453 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
455 /* Compare states of two domains, returning -1,0,1 for <,=,> */
456 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
457 {
458 unsigned int i, d1s, d2s;
459 for(i = 0; i < NUM_STATES; i++) {
460 d1s = state_funcs[i].get(domain1);
461 d2s = state_funcs[i].get(domain2);
462 if(d1s && !d2s)
463 return -1;
464 if(d2s && !d1s)
465 return 1;
466 }
467 return 0;
468 }
470 /* Prints domain state in abbreviated letter format */
471 static void print_state(xenstat_domain *domain)
472 {
473 unsigned int i;
474 for(i = 0; i < NUM_STATES; i++)
475 print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
476 : '-');
477 }
479 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
480 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
481 {
482 return -compare(xenstat_domain_cpu_ns(domain1),
483 xenstat_domain_cpu_ns(domain2));
484 }
486 /* Prints domain cpu usage in seconds */
487 static void print_cpu(xenstat_domain *domain)
488 {
489 print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
490 }
492 /* Computes the CPU percentage used for a specified domain */
493 static double get_cpu_pct(xenstat_domain *domain)
494 {
495 xenstat_domain *old_domain;
496 double us_elapsed;
498 /* Can't calculate CPU percentage without a previous sample. */
499 if(prev_node == NULL)
500 return 0.0;
502 old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
503 if(old_domain == NULL)
504 return 0.0;
506 /* Calculate the time elapsed in microseconds */
507 us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
508 +(curtime.tv_usec - oldtime.tv_usec));
510 /* In the following, nanoseconds must be multiplied by 1000.0 to
511 * convert to microseconds, then divided by 100.0 to get a percentage,
512 * resulting in a multiplication by 10.0 */
513 return ((xenstat_domain_cpu_ns(domain)
514 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
515 }
517 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
518 {
519 return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
520 }
522 /* Prints cpu percentage statistic */
523 static void print_cpu_pct(xenstat_domain *domain)
524 {
525 print("%6.1f", get_cpu_pct(domain));
526 }
528 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
529 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
530 {
531 return -compare(xenstat_domain_cur_mem(domain1),
532 xenstat_domain_cur_mem(domain2));
533 }
535 /* Prints current memory statistic */
536 static void print_mem(xenstat_domain *domain)
537 {
538 print("%10llu", xenstat_domain_cur_mem(domain)/1024);
539 }
541 /* Prints memory percentage statistic, ratio of current domain memory to total
542 * node memory */
543 static void print_mem_pct(xenstat_domain *domain)
544 {
545 print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
546 (double)xenstat_node_tot_mem(cur_node) * 100);
547 }
549 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
550 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
551 {
552 return -compare(xenstat_domain_max_mem(domain1),
553 xenstat_domain_max_mem(domain2));
554 }
556 /* Prints maximum domain memory statistic in KB */
557 static void print_maxmem(xenstat_domain *domain)
558 {
559 unsigned long long max_mem = xenstat_domain_max_mem(domain);
560 if(max_mem == ((unsigned long long)-1))
561 print("%10s", "no limit");
562 else
563 print("%10llu", max_mem/1024);
564 }
566 /* Prints memory percentage statistic, ratio of current domain memory to total
567 * node memory */
568 static void print_max_pct(xenstat_domain *domain)
569 {
570 if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
571 print("%9s", "n/a");
572 else
573 print("%9.1f", (double)xenstat_domain_max_mem(domain) /
574 (double)xenstat_node_tot_mem(cur_node) * 100);
575 }
577 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
578 * <,=,> */
579 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
580 {
581 return -compare(xenstat_domain_num_vcpus(domain1),
582 xenstat_domain_num_vcpus(domain2));
583 }
585 /* Prints number of virtual CPUs statistic */
586 static void print_vcpus(xenstat_domain *domain)
587 {
588 print("%5u", xenstat_domain_num_vcpus(domain));
589 }
591 /* Compares number of virtual networks of two domains, returning -1,0,1 for
592 * <,=,> */
593 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
594 {
595 return -compare(xenstat_domain_num_networks(domain1),
596 xenstat_domain_num_networks(domain2));
597 }
599 /* Prints number of virtual networks statistic */
600 static void print_nets(xenstat_domain *domain)
601 {
602 print("%4u", xenstat_domain_num_networks(domain));
603 }
605 /* Compares number of total network tx bytes of two domains, returning -1,0,1
606 * for <,=,> */
607 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
608 {
609 return -compare(tot_net_bytes(domain1, FALSE),
610 tot_net_bytes(domain2, FALSE));
611 }
613 /* Prints number of total network tx bytes statistic */
614 static void print_net_tx(xenstat_domain *domain)
615 {
616 print("%8llu", tot_net_bytes(domain, FALSE)/1024);
617 }
619 /* Compares number of total network rx bytes of two domains, returning -1,0,1
620 * for <,=,> */
621 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
622 {
623 return -compare(tot_net_bytes(domain1, TRUE),
624 tot_net_bytes(domain2, TRUE));
625 }
627 /* Prints number of total network rx bytes statistic */
628 static void print_net_rx(xenstat_domain *domain)
629 {
630 print("%8llu", tot_net_bytes(domain, TRUE)/1024);
631 }
633 /* Gets number of total network bytes statistic, if rx true, then rx bytes
634 * otherwise tx bytes
635 */
636 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
637 {
638 int i = 0;
639 xenstat_network *network;
640 unsigned num_networks = 0;
641 unsigned long long total = 0;
643 /* How many networks? */
644 num_networks = xenstat_domain_num_networks(domain);
646 /* Dump information for each network */
647 for (i=0; i < num_networks; i++) {
648 /* Next get the network information */
649 network = xenstat_domain_network(domain,i);
650 if (rx_flag)
651 total += xenstat_network_rbytes(network);
652 else
653 total += xenstat_network_tbytes(network);
654 }
656 return total;
657 }
659 /* Compares number of virtual block devices of two domains,
660 returning -1,0,1 for * <,=,> */
661 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2)
662 {
663 return -compare(xenstat_domain_num_vbds(domain1),
664 xenstat_domain_num_vbds(domain2));
665 }
667 /* Prints number of virtual block devices statistic */
668 static void print_vbds(xenstat_domain *domain)
669 {
670 print("%4u", xenstat_domain_num_vbds(domain));
671 }
673 /* Compares number of total VBD OO requests of two domains,
674 returning -1,0,1 * for <,=,> */
675 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2)
676 {
677 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_OO),
678 tot_vbd_reqs(domain2, FIELD_VBD_OO));
679 }
681 /* Prints number of total VBD OO requests statistic */
682 static void print_vbd_oo(xenstat_domain *domain)
683 {
684 print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_OO));
685 }
687 /* Compares number of total VBD READ requests of two domains,
688 returning -1,0,1 * for <,=,> */
689 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2)
690 {
691 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RD),
692 tot_vbd_reqs(domain2, FIELD_VBD_RD));
693 }
695 /* Prints number of total VBD READ requests statistic */
696 static void print_vbd_rd(xenstat_domain *domain)
697 {
698 print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_RD));
699 }
701 /* Compares number of total VBD WRITE requests of two domains,
702 returning -1,0,1 * for <,=,> */
703 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2)
704 {
705 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_WR),
706 tot_vbd_reqs(domain2, FIELD_VBD_WR));
707 }
709 /* Prints number of total VBD WRITE requests statistic */
710 static void print_vbd_wr(xenstat_domain *domain)
711 {
712 print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_WR));
713 }
715 /* Compares number of total VBD READ sectors of two domains,
716 returning -1,0,1 * for <,=,> */
717 static int compare_vbd_rsect(xenstat_domain *domain1, xenstat_domain *domain2)
718 {
719 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RSECT),
720 tot_vbd_reqs(domain2, FIELD_VBD_RSECT));
721 }
723 /* Prints number of total VBD READ sectors statistic */
724 static void print_vbd_rsect(xenstat_domain *domain)
725 {
726 print("%10llu", tot_vbd_reqs(domain, FIELD_VBD_RSECT));
727 }
729 /* Compares number of total VBD WRITE sectors of two domains,
730 returning -1,0,1 * for <,=,> */
731 static int compare_vbd_wsect(xenstat_domain *domain1, xenstat_domain *domain2)
732 {
733 return -compare(tot_vbd_reqs(domain1, FIELD_VBD_WSECT),
734 tot_vbd_reqs(domain2, FIELD_VBD_WSECT));
735 }
737 /* Prints number of total VBD WRITE sectors statistic */
738 static void print_vbd_wsect(xenstat_domain *domain)
739 {
740 print("%10llu", tot_vbd_reqs(domain, FIELD_VBD_WSECT));
741 }
744 /* Gets number of total VBD requests statistic,
745 * if flag is FIELD_VBD_OO, then OO requests,
746 * if flag is FIELD_VBD_RD, then READ requests,
747 * if flag is FIELD_VBD_WR, then WRITE requests,
748 * if flag is FIELD_VBD_RSECT, then READ sectors,
749 * if flag is FIELD_VBD_WSECT, then WRITE sectors.
750 */
751 static unsigned long long tot_vbd_reqs(xenstat_domain *domain, int flag)
752 {
753 int i = 0;
754 xenstat_vbd *vbd;
755 unsigned num_vbds = 0;
756 unsigned long long total = 0;
758 num_vbds = xenstat_domain_num_vbds(domain);
760 for ( i=0 ; i < num_vbds ; i++) {
761 vbd = xenstat_domain_vbd(domain,i);
762 switch(flag) {
763 case FIELD_VBD_OO:
764 total += xenstat_vbd_oo_reqs(vbd);
765 break;
766 case FIELD_VBD_RD:
767 total += xenstat_vbd_rd_reqs(vbd);
768 break;
769 case FIELD_VBD_WR:
770 total += xenstat_vbd_wr_reqs(vbd);
771 break;
772 case FIELD_VBD_RSECT:
773 total += xenstat_vbd_rd_sects(vbd);
774 break;
775 case FIELD_VBD_WSECT:
776 total += xenstat_vbd_wr_sects(vbd);
777 break;
778 default:
779 break;
780 }
781 }
783 return total;
784 }
786 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
787 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
788 {
789 return compare(xenstat_domain_ssid(domain1),
790 xenstat_domain_ssid(domain2));
791 }
793 /* Prints ssid statistic */
794 static void print_ssid(xenstat_domain *domain)
795 {
796 print("%4u", xenstat_domain_ssid(domain));
797 }
799 /* Section printing functions */
800 /* Prints the top summary, above the domain table */
801 void do_summary(void)
802 {
803 #define TIME_STR_LEN 9
804 const char *TIME_STR_FORMAT = "%H:%M:%S";
805 char time_str[TIME_STR_LEN];
806 const char *ver_str;
807 unsigned run = 0, block = 0, pause = 0,
808 crash = 0, dying = 0, shutdown = 0;
809 unsigned i, num_domains = 0;
810 unsigned long long used = 0;
811 long freeable_mb = 0;
812 xenstat_domain *domain;
813 time_t curt;
815 /* Print program name, current time, and number of domains */
816 curt = curtime.tv_sec;
817 strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT, localtime(&curt));
818 num_domains = xenstat_node_num_domains(cur_node);
819 ver_str = xenstat_node_xen_version(cur_node);
820 print("xentop - %s Xen %s\n", time_str, ver_str);
822 /* Tabulate what states domains are in for summary */
823 for (i=0; i < num_domains; i++) {
824 domain = xenstat_node_domain_by_index(cur_node,i);
825 if (xenstat_domain_running(domain)) run++;
826 else if (xenstat_domain_blocked(domain)) block++;
827 else if (xenstat_domain_paused(domain)) pause++;
828 else if (xenstat_domain_shutdown(domain)) shutdown++;
829 else if (xenstat_domain_crashed(domain)) crash++;
830 else if (xenstat_domain_dying(domain)) dying++;
831 }
833 print("%u domains: %u running, %u blocked, %u paused, "
834 "%u crashed, %u dying, %u shutdown \n",
835 num_domains, run, block, pause, crash, dying, shutdown);
837 used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node);
838 freeable_mb = xenstat_node_freeable_mb(cur_node);
840 /* Dump node memory and cpu information */
841 if ( freeable_mb <= 0 )
842 print("Mem: %lluk total, %lluk used, %lluk free ",
843 xenstat_node_tot_mem(cur_node)/1024, used/1024,
844 xenstat_node_free_mem(cur_node)/1024);
845 else
846 print("Mem: %lluk total, %lluk used, %lluk free, %ldk freeable, ",
847 xenstat_node_tot_mem(cur_node)/1024, used/1024,
848 xenstat_node_free_mem(cur_node)/1024, freeable_mb*1024);
849 print("CPUs: %u @ %lluMHz\n",
850 xenstat_node_num_cpus(cur_node),
851 xenstat_node_cpu_hz(cur_node)/1000000);
852 }
854 /* Display the top header for the domain table */
855 void do_header(void)
856 {
857 field_id i;
859 /* Turn on REVERSE highlight attribute for headings */
860 xentop_attron(A_REVERSE);
861 for(i = 0; i < NUM_FIELDS; i++) {
862 if (i != 0)
863 print(" ");
864 /* The BOLD attribute is turned on for the sort column */
865 if (i == sort_field)
866 xentop_attron(A_BOLD);
867 print("%*s", fields[i].default_width, fields[i].header);
868 if (i == sort_field)
869 xentop_attroff(A_BOLD);
870 }
871 xentop_attroff(A_REVERSE);
872 print("\n");
873 }
875 /* Displays bottom status line or current prompt */
876 void do_bottom_line(void)
877 {
878 move(lines()-1, 2);
880 if (prompt != NULL) {
881 printw("%s: %s", prompt, prompt_val);
882 } else {
883 addch(A_REVERSE | 'D'); addstr("elay ");
885 /* network */
886 addch(A_REVERSE | 'N');
887 attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
888 addstr(" ");
890 /* VBDs */
891 attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "v");
892 addch(A_REVERSE | 'B');
893 attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "ds");
894 addstr(" ");
896 /* tmem */
897 addch(A_REVERSE | 'T');
898 attr_addstr(show_tmem ? COLOR_PAIR(1) : 0, "mem");
899 addstr(" ");
902 /* vcpus */
903 addch(A_REVERSE | 'V');
904 attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
905 addstr(" ");
907 /* repeat */
908 addch(A_REVERSE | 'R');
909 attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
910 addstr(" ");
912 /* sort order */
913 addch(A_REVERSE | 'S'); addstr("ort order ");
915 addch(A_REVERSE | 'Q'); addstr("uit ");
916 }
917 }
919 /* Prints Domain information */
920 void do_domain(xenstat_domain *domain)
921 {
922 unsigned int i;
923 for (i = 0; i < NUM_FIELDS; i++) {
924 if (i != 0)
925 print(" ");
926 if (i == sort_field)
927 xentop_attron(A_BOLD);
928 fields[i].print(domain);
929 if (i == sort_field)
930 xentop_attroff(A_BOLD);
931 }
932 print("\n");
933 }
935 /* Output all vcpu information */
936 void do_vcpu(xenstat_domain *domain)
937 {
938 int i = 0;
939 unsigned num_vcpus = 0;
940 xenstat_vcpu *vcpu;
942 print("VCPUs(sec): ");
944 num_vcpus = xenstat_domain_num_vcpus(domain);
946 /* for all online vcpus dump out values */
947 for (i=0; i< num_vcpus; i++) {
948 vcpu = xenstat_domain_vcpu(domain,i);
950 if (xenstat_vcpu_online(vcpu) > 0) {
951 if (i != 0 && (i%5)==0)
952 print("\n ");
953 print(" %2u: %10llus", i,
954 xenstat_vcpu_ns(vcpu)/1000000000);
955 }
956 }
957 print("\n");
958 }
960 /* Output all network information */
961 void do_network(xenstat_domain *domain)
962 {
963 int i = 0;
964 xenstat_network *network;
965 unsigned num_networks = 0;
967 /* How many networks? */
968 num_networks = xenstat_domain_num_networks(domain);
970 /* Dump information for each network */
971 for (i=0; i < num_networks; i++) {
972 /* Next get the network information */
973 network = xenstat_domain_network(domain,i);
975 print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop ",
976 i,
977 xenstat_network_rbytes(network),
978 xenstat_network_rpackets(network),
979 xenstat_network_rerrs(network),
980 xenstat_network_rdrop(network));
982 print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
983 xenstat_network_tbytes(network),
984 xenstat_network_tpackets(network),
985 xenstat_network_terrs(network),
986 xenstat_network_tdrop(network));
987 }
988 }
991 /* Output all VBD information */
992 void do_vbd(xenstat_domain *domain)
993 {
994 int i = 0;
995 xenstat_vbd *vbd;
996 unsigned num_vbds = 0;
998 const char *vbd_type[] = {
999 "Unidentified", /* number 0 */
1000 "BlkBack", /* number 1 */
1001 "BlkTap", /* number 2 */
1002 };
1004 num_vbds = xenstat_domain_num_vbds(domain);
1006 for (i=0 ; i< num_vbds; i++) {
1007 char details[20];
1009 vbd = xenstat_domain_vbd(domain,i);
1011 #if !defined(__linux__)
1012 details[0] = '\0';
1013 #else
1014 snprintf(details, 20, "[%2x:%2x] ",
1015 MAJOR(xenstat_vbd_dev(vbd)),
1016 MINOR(xenstat_vbd_dev(vbd)));
1017 #endif
1019 print("VBD %s %4d %s OO: %8llu RD: %8llu WR: %8llu RSECT: %10llu WSECT: %10llu\n",
1020 vbd_type[xenstat_vbd_type(vbd)],
1021 xenstat_vbd_dev(vbd), details,
1022 xenstat_vbd_oo_reqs(vbd),
1023 xenstat_vbd_rd_reqs(vbd),
1024 xenstat_vbd_wr_reqs(vbd),
1025 xenstat_vbd_rd_sects(vbd),
1026 xenstat_vbd_wr_sects(vbd));
1030 /* Output all tmem information */
1031 void do_tmem(xenstat_domain *domain)
1033 xenstat_tmem *tmem = xenstat_domain_tmem(domain);
1034 unsigned long long curr_eph_pages = xenstat_tmem_curr_eph_pages(tmem);
1035 unsigned long long succ_eph_gets = xenstat_tmem_succ_eph_gets(tmem);
1036 unsigned long long succ_pers_puts = xenstat_tmem_succ_pers_puts(tmem);
1037 unsigned long long succ_pers_gets = xenstat_tmem_succ_pers_gets(tmem);
1039 if (curr_eph_pages | succ_eph_gets | succ_pers_puts | succ_pers_gets)
1040 print("Tmem: Curr eph pages: %8llu Succ eph gets: %8llu "
1041 "Succ pers puts: %8llu Succ pers gets: %8llu\n",
1042 curr_eph_pages, succ_eph_gets,
1043 succ_pers_puts, succ_pers_gets);
1047 static void top(void)
1049 xenstat_domain **domains;
1050 unsigned int i, num_domains = 0;
1052 /* Now get the node information */
1053 if (prev_node != NULL)
1054 xenstat_free_node(prev_node);
1055 prev_node = cur_node;
1056 cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
1057 if (cur_node == NULL)
1058 fail("Failed to retrieve statistics from libxenstat\n");
1060 /* dump summary top information */
1061 if (!batch)
1062 do_summary();
1064 /* Count the number of domains for which to report data */
1065 num_domains = xenstat_node_num_domains(cur_node);
1067 domains = calloc(num_domains, sizeof(xenstat_domain *));
1068 if(domains == NULL)
1069 fail("Failed to allocate memory\n");
1071 for (i=0; i < num_domains; i++)
1072 domains[i] = xenstat_node_domain_by_index(cur_node, i);
1074 /* Sort */
1075 qsort(domains, num_domains, sizeof(xenstat_domain *),
1076 (int(*)(const void *, const void *))compare_domains);
1078 if(first_domain_index >= num_domains)
1079 first_domain_index = num_domains-1;
1081 for (i = first_domain_index; i < num_domains; i++) {
1082 if(!batch && current_row() == lines()-1)
1083 break;
1084 if (i == first_domain_index || repeat_header)
1085 do_header();
1086 do_domain(domains[i]);
1087 if (show_vcpus)
1088 do_vcpu(domains[i]);
1089 if (show_networks)
1090 do_network(domains[i]);
1091 if (show_vbds)
1092 do_vbd(domains[i]);
1093 if (show_tmem)
1094 do_tmem(domains[i]);
1097 if (!batch)
1098 do_bottom_line();
1100 free(domains);
1103 static int signal_exit;
1105 static void signal_exit_handler(int sig)
1107 signal_exit = 1;
1110 int main(int argc, char **argv)
1112 int opt, optind = 0;
1113 int ch = ERR;
1115 struct option lopts[] = {
1116 { "help", no_argument, NULL, 'h' },
1117 { "version", no_argument, NULL, 'V' },
1118 { "networks", no_argument, NULL, 'n' },
1119 { "vbds", no_argument, NULL, 'x' },
1120 { "repeat-header", no_argument, NULL, 'r' },
1121 { "vcpus", no_argument, NULL, 'v' },
1122 { "delay", required_argument, NULL, 'd' },
1123 { "batch", no_argument, NULL, 'b' },
1124 { "iterations", required_argument, NULL, 'i' },
1125 { "full-name", no_argument, NULL, 'f' },
1126 { 0, 0, 0, 0 },
1127 };
1128 const char *sopts = "hVnxrvd:bi:f";
1130 if (atexit(cleanup) != 0)
1131 fail("Failed to install cleanup handler.\n");
1133 while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
1134 switch (opt) {
1135 default:
1136 usage(argv[0]);
1137 exit(1);
1138 case '?':
1139 case 'h':
1140 usage(argv[0]);
1141 exit(0);
1142 case 'V':
1143 version();
1144 exit(0);
1145 case 'n':
1146 show_networks = 1;
1147 break;
1148 case 'x':
1149 show_vbds = 1;
1150 break;
1151 case 'r':
1152 repeat_header = 1;
1153 break;
1154 case 'v':
1155 show_vcpus = 1;
1156 break;
1157 case 'd':
1158 delay = atoi(optarg);
1159 break;
1160 case 'b':
1161 batch = 1;
1162 break;
1163 case 'i':
1164 iterations = atoi(optarg);
1165 loop = 0;
1166 break;
1167 case 'f':
1168 show_full_name = 1;
1169 break;
1170 case 't':
1171 show_tmem = 1;
1172 break;
1176 /* Get xenstat handle */
1177 xhandle = xenstat_init();
1178 if (xhandle == NULL)
1179 fail("Failed to initialize xenstat library\n");
1181 if (!batch) {
1182 /* Begin curses stuff */
1183 cwin = initscr();
1184 start_color();
1185 cbreak();
1186 noecho();
1187 nonl();
1188 keypad(stdscr, TRUE);
1189 halfdelay(5);
1190 #ifndef __sun__
1191 use_default_colors();
1192 #endif
1193 init_pair(1, -1, COLOR_YELLOW);
1195 do {
1196 gettimeofday(&curtime, NULL);
1197 if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
1198 clear();
1199 top();
1200 oldtime = curtime;
1201 refresh();
1202 if ((!loop) && !(--iterations))
1203 break;
1205 ch = getch();
1206 } while (handle_key(ch));
1207 } else {
1208 struct sigaction sa = {
1209 .sa_handler = signal_exit_handler,
1210 .sa_flags = 0
1211 };
1212 sigemptyset(&sa.sa_mask);
1213 sigaction(SIGINT, &sa, NULL);
1214 sigaction(SIGTERM, &sa, NULL);
1216 do {
1217 gettimeofday(&curtime, NULL);
1218 top();
1219 fflush(stdout);
1220 oldtime = curtime;
1221 if ((!loop) && !(--iterations))
1222 break;
1223 sleep(delay);
1224 } while (!signal_exit);
1227 /* Cleanup occurs in cleanup(), so no work to do here. */
1229 return 0;