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> |
---|
32 | |
---|
33 | #include <xenstat.h> |
---|
34 | |
---|
35 | #define XENTOP_VERSION "1.0" |
---|
36 | |
---|
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" |
---|
42 | |
---|
43 | #define _GNU_SOURCE |
---|
44 | #include <getopt.h> |
---|
45 | |
---|
46 | #if !defined(__GNUC__) && !defined(__GNUG__) |
---|
47 | #define __attribute__(arg) /* empty */ |
---|
48 | #endif |
---|
49 | |
---|
50 | #define KEY_ESCAPE '\x1B' |
---|
51 | |
---|
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 |
---|
62 | |
---|
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); |
---|
82 | |
---|
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); |
---|
116 | |
---|
117 | |
---|
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); |
---|
127 | |
---|
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; |
---|
149 | |
---|
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; |
---|
157 | |
---|
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 | }; |
---|
177 | |
---|
178 | const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field); |
---|
179 | |
---|
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 *); |
---|
200 | |
---|
201 | static WINDOW *cwin; |
---|
202 | |
---|
203 | /* |
---|
204 | * Function definitions |
---|
205 | */ |
---|
206 | |
---|
207 | /* Utility functions */ |
---|
208 | |
---|
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 | } |
---|
227 | |
---|
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 | } |
---|
235 | |
---|
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 | } |
---|
248 | |
---|
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 | } |
---|
257 | |
---|
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 | } |
---|
265 | |
---|
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 | } |
---|
273 | |
---|
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; |
---|
279 | |
---|
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 | } |
---|
292 | |
---|
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 | } |
---|
300 | |
---|
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 | } |
---|
309 | |
---|
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 | } |
---|
319 | |
---|
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 | } |
---|
375 | |
---|
376 | return 1; |
---|
377 | } |
---|
378 | |
---|
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 | } |
---|
388 | |
---|
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 | } |
---|
395 | |
---|
396 | /* Field functions */ |
---|
397 | |
---|
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 | } |
---|
403 | |
---|
404 | /* Prints domain name */ |
---|
405 | void print_name(xenstat_domain *domain) |
---|
406 | { |
---|
407 | print("%10s", xenstat_domain_name(domain)); |
---|
408 | } |
---|
409 | |
---|
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); |
---|
422 | |
---|
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 | } |
---|
437 | |
---|
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 | } |
---|
446 | |
---|
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 | } |
---|
453 | |
---|
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 | } |
---|
459 | |
---|
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; |
---|
465 | |
---|
466 | /* Can't calculate CPU percentage without a previous sample. */ |
---|
467 | if(prev_node == NULL) |
---|
468 | return 0.0; |
---|
469 | |
---|
470 | old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain)); |
---|
471 | if(old_domain == NULL) |
---|
472 | return 0.0; |
---|
473 | |
---|
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)); |
---|
477 | |
---|
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 | } |
---|
484 | |
---|
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 | } |
---|
489 | |
---|
490 | /* Prints cpu percentage statistic */ |
---|
491 | static void print_cpu_pct(xenstat_domain *domain) |
---|
492 | { |
---|
493 | print("%6.1f", get_cpu_pct(domain)); |
---|
494 | } |
---|
495 | |
---|
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 | } |
---|
502 | |
---|
503 | /* Prints current memory statistic */ |
---|
504 | static void print_mem(xenstat_domain *domain) |
---|
505 | { |
---|
506 | print("%10llu", xenstat_domain_cur_mem(domain)/1024); |
---|
507 | } |
---|
508 | |
---|
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 | } |
---|
516 | |
---|
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 | } |
---|
523 | |
---|
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 | } |
---|
533 | |
---|
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 | } |
---|
544 | |
---|
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 | } |
---|
552 | |
---|
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 | } |
---|
558 | |
---|
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 | } |
---|
566 | |
---|
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 | } |
---|
572 | |
---|
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 | } |
---|
580 | |
---|
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 | } |
---|
586 | |
---|
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 | } |
---|
594 | |
---|
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 | } |
---|
600 | |
---|
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; |
---|
610 | |
---|
611 | /* How many networks? */ |
---|
612 | num_networks = xenstat_domain_num_networks(domain); |
---|
613 | |
---|
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 | } |
---|
623 | |
---|
624 | return total; |
---|
625 | } |
---|
626 | |
---|
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 | } |
---|
634 | |
---|
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 | } |
---|
640 | |
---|
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 | } |
---|
648 | |
---|
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 | } |
---|
654 | |
---|
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 | } |
---|
662 | |
---|
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 | } |
---|
668 | |
---|
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 | } |
---|
676 | |
---|
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 | } |
---|
682 | |
---|
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; |
---|
694 | |
---|
695 | num_vbds = xenstat_domain_num_vbds(domain); |
---|
696 | |
---|
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 | } |
---|
713 | |
---|
714 | return total; |
---|
715 | } |
---|
716 | |
---|
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 | } |
---|
723 | |
---|
724 | /* Prints ssid statistic */ |
---|
725 | static void print_ssid(xenstat_domain *domain) |
---|
726 | { |
---|
727 | print("%4u", xenstat_domain_ssid(domain)); |
---|
728 | } |
---|
729 | |
---|
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; |
---|
743 | |
---|
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); |
---|
750 | |
---|
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 | } |
---|
761 | |
---|
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); |
---|
765 | |
---|
766 | used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node); |
---|
767 | |
---|
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 | } |
---|
776 | |
---|
777 | /* Display the top header for the domain table */ |
---|
778 | void do_header(void) |
---|
779 | { |
---|
780 | field_id i; |
---|
781 | |
---|
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 | } |
---|
797 | |
---|
798 | /* Displays bottom status line or current prompt */ |
---|
799 | void do_bottom_line(void) |
---|
800 | { |
---|
801 | move(lines()-1, 2); |
---|
802 | |
---|
803 | if (prompt != NULL) { |
---|
804 | printw("%s: %s", prompt, prompt_val); |
---|
805 | } else { |
---|
806 | addch(A_REVERSE | 'D'); addstr("elay "); |
---|
807 | |
---|
808 | /* network */ |
---|
809 | addch(A_REVERSE | 'N'); |
---|
810 | attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks"); |
---|
811 | addstr(" "); |
---|
812 | |
---|
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(" "); |
---|
818 | |
---|
819 | |
---|
820 | /* vcpus */ |
---|
821 | addch(A_REVERSE | 'V'); |
---|
822 | attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs"); |
---|
823 | addstr(" "); |
---|
824 | |
---|
825 | /* repeat */ |
---|
826 | addch(A_REVERSE | 'R'); |
---|
827 | attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header"); |
---|
828 | addstr(" "); |
---|
829 | |
---|
830 | /* sort order */ |
---|
831 | addch(A_REVERSE | 'S'); addstr("ort order "); |
---|
832 | |
---|
833 | addch(A_REVERSE | 'Q'); addstr("uit "); |
---|
834 | } |
---|
835 | } |
---|
836 | |
---|
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 | } |
---|
852 | |
---|
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; |
---|
859 | |
---|
860 | print("VCPUs(sec): "); |
---|
861 | |
---|
862 | num_vcpus = xenstat_domain_num_vcpus(domain); |
---|
863 | |
---|
864 | /* for all online vcpus dump out values */ |
---|
865 | for (i=0; i< num_vcpus; i++) { |
---|
866 | vcpu = xenstat_domain_vcpu(domain,i); |
---|
867 | |
---|
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 | } |
---|
877 | |
---|
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; |
---|
884 | |
---|
885 | /* How many networks? */ |
---|
886 | num_networks = xenstat_domain_num_networks(domain); |
---|
887 | |
---|
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); |
---|
892 | |
---|
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)); |
---|
899 | |
---|
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 | } |
---|
907 | |
---|
908 | |
---|
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; |
---|
915 | |
---|
916 | num_vbds = xenstat_domain_num_vbds(domain); |
---|
917 | |
---|
918 | for (i=0 ; i< num_vbds; i++) { |
---|
919 | char details[20]; |
---|
920 | |
---|
921 | vbd = xenstat_domain_vbd(domain,i); |
---|
922 | |
---|
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 |
---|
929 | |
---|
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 | } |
---|
937 | |
---|
938 | static void top(void) |
---|
939 | { |
---|
940 | xenstat_domain **domains; |
---|
941 | unsigned int i, num_domains = 0; |
---|
942 | |
---|
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"); |
---|
950 | |
---|
951 | /* dump summary top information */ |
---|
952 | do_summary(); |
---|
953 | |
---|
954 | /* Count the number of domains for which to report data */ |
---|
955 | num_domains = xenstat_node_num_domains(cur_node); |
---|
956 | |
---|
957 | domains = malloc(num_domains*sizeof(xenstat_domain *)); |
---|
958 | if(domains == NULL) |
---|
959 | fail("Failed to allocate memory\n"); |
---|
960 | |
---|
961 | for (i=0; i < num_domains; i++) |
---|
962 | domains[i] = xenstat_node_domain_by_index(cur_node, i); |
---|
963 | |
---|
964 | /* Sort */ |
---|
965 | qsort(domains, num_domains, sizeof(xenstat_domain *), |
---|
966 | (int(*)(const void *, const void *))compare_domains); |
---|
967 | |
---|
968 | if(first_domain_index >= num_domains) |
---|
969 | first_domain_index = num_domains-1; |
---|
970 | |
---|
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 | } |
---|
984 | |
---|
985 | if(!batch) |
---|
986 | do_bottom_line(); |
---|
987 | |
---|
988 | free(domains); |
---|
989 | } |
---|
990 | |
---|
991 | int main(int argc, char **argv) |
---|
992 | { |
---|
993 | int opt, optind = 0; |
---|
994 | int ch = ERR; |
---|
995 | |
---|
996 | struct option lopts[] = { |
---|
997 | { "help", no_argument, NULL, 'h' }, |
---|
998 | { "version", no_argument, NULL, 'V' }, |
---|
999 | { "networks", no_argument, NULL, 'n' }, |
---|
1000 | { "vbds", no_argument, NULL, 'x' }, |
---|
1001 | { "repeat-header", no_argument, NULL, 'r' }, |
---|
1002 | { "vcpus", no_argument, NULL, 'v' }, |
---|
1003 | { "delay", required_argument, NULL, 'd' }, |
---|
1004 | { "batch", no_argument, NULL, 'b' }, |
---|
1005 | { "iterations", required_argument, NULL, 'i' }, |
---|
1006 | { 0, 0, 0, 0 }, |
---|
1007 | }; |
---|
1008 | const char *sopts = "hVnxrvd:bi:"; |
---|
1009 | |
---|
1010 | if (atexit(cleanup) != 0) |
---|
1011 | fail("Failed to install cleanup handler.\n"); |
---|
1012 | |
---|
1013 | while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) { |
---|
1014 | switch (opt) { |
---|
1015 | default: |
---|
1016 | usage(argv[0]); |
---|
1017 | exit(1); |
---|
1018 | case '?': |
---|
1019 | case 'h': |
---|
1020 | usage(argv[0]); |
---|
1021 | exit(0); |
---|
1022 | case 'V': |
---|
1023 | version(); |
---|
1024 | exit(0); |
---|
1025 | case 'n': |
---|
1026 | show_networks = 1; |
---|
1027 | break; |
---|
1028 | case 'x': |
---|
1029 | show_vbds = 1; |
---|
1030 | break; |
---|
1031 | case 'r': |
---|
1032 | repeat_header = 1; |
---|
1033 | break; |
---|
1034 | case 'v': |
---|
1035 | show_vcpus = 1; |
---|
1036 | break; |
---|
1037 | case 'd': |
---|
1038 | delay = atoi(optarg); |
---|
1039 | break; |
---|
1040 | case 'b': |
---|
1041 | batch = 1; |
---|
1042 | break; |
---|
1043 | case 'i': |
---|
1044 | iterations = atoi(optarg); |
---|
1045 | loop = 0; |
---|
1046 | break; |
---|
1047 | } |
---|
1048 | } |
---|
1049 | |
---|
1050 | /* Get xenstat handle */ |
---|
1051 | xhandle = xenstat_init(); |
---|
1052 | if (xhandle == NULL) |
---|
1053 | fail("Failed to initialize xenstat library\n"); |
---|
1054 | |
---|
1055 | if (!batch) { |
---|
1056 | /* Begin curses stuff */ |
---|
1057 | cwin = initscr(); |
---|
1058 | start_color(); |
---|
1059 | cbreak(); |
---|
1060 | noecho(); |
---|
1061 | nonl(); |
---|
1062 | keypad(stdscr, TRUE); |
---|
1063 | halfdelay(5); |
---|
1064 | #ifndef __sun__ |
---|
1065 | use_default_colors(); |
---|
1066 | #endif |
---|
1067 | init_pair(1, -1, COLOR_YELLOW); |
---|
1068 | |
---|
1069 | do { |
---|
1070 | gettimeofday(&curtime, NULL); |
---|
1071 | if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) { |
---|
1072 | clear(); |
---|
1073 | top(); |
---|
1074 | oldtime = curtime; |
---|
1075 | refresh(); |
---|
1076 | if ((!loop) && !(--iterations)) |
---|
1077 | break; |
---|
1078 | } |
---|
1079 | ch = getch(); |
---|
1080 | } while (handle_key(ch)); |
---|
1081 | } else { |
---|
1082 | do { |
---|
1083 | gettimeofday(&curtime, NULL); |
---|
1084 | top(); |
---|
1085 | oldtime = curtime; |
---|
1086 | if ((!loop) && !(--iterations)) |
---|
1087 | break; |
---|
1088 | sleep(delay); |
---|
1089 | } while (1); |
---|
1090 | } |
---|
1091 | |
---|
1092 | /* Cleanup occurs in cleanup(), so no work to do here. */ |
---|
1093 | |
---|
1094 | return 0; |
---|
1095 | } |
---|