source: trunk/packages/xen-common/xen-common/tools/xenstat/xentop/xentop.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 29.5 KB
Line 
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 */
67static void usage(const char *);
68static void version(void);
69static void cleanup(void);
70static void fail(const char *);
71static int current_row(void);
72static int lines(void);
73static void print(const char *, ...) __attribute__((format(printf,1,2)));
74static void attr_addstr(int attr, const char *str);
75static void set_delay(char *value);
76static void set_prompt(char *new_prompt, void (*func)(char *));
77static int handle_key(int);
78static int compare(unsigned long long, unsigned long long);
79static int compare_domains(xenstat_domain **, xenstat_domain **);
80static unsigned long long tot_net_bytes( xenstat_domain *, int);
81static unsigned long long tot_vbd_reqs( xenstat_domain *, int);
82
83/* Field functions */
84static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2);
85static void print_state(xenstat_domain *domain);
86static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2);
87static void print_cpu(xenstat_domain *domain);
88static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2);
89static void print_cpu_pct(xenstat_domain *domain);
90static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2);
91static void print_mem(xenstat_domain *domain);
92static void print_mem_pct(xenstat_domain *domain);
93static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2);
94static void print_maxmem(xenstat_domain *domain);
95static void print_max_pct(xenstat_domain *domain);
96static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2);
97static void print_vcpus(xenstat_domain *domain);
98static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2);
99static void print_nets(xenstat_domain *domain);
100static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2);
101static void print_net_tx(xenstat_domain *domain);
102static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2);
103static void print_net_rx(xenstat_domain *domain);
104static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2);
105static void print_ssid(xenstat_domain *domain);
106static int compare_name(xenstat_domain *domain1, xenstat_domain *domain2);
107static void print_name(xenstat_domain *domain);
108static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2);
109static void print_vbds(xenstat_domain *domain);
110static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2);
111static void print_vbd_oo(xenstat_domain *domain);
112static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2);
113static void print_vbd_rd(xenstat_domain *domain);
114static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2);
115static void print_vbd_wr(xenstat_domain *domain);
116
117
118/* Section printing functions */
119static void do_summary(void);
120static void do_header(void);
121static void do_bottom_line(void);
122static void do_domain(xenstat_domain *);
123static void do_vcpu(xenstat_domain *);
124static void do_network(xenstat_domain *);
125static void do_vbd(xenstat_domain *);
126static void top(void);
127
128/* Field types */
129typedef 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
150typedef 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
158field 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
178const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field);
179
180/* Globals */
181struct timeval curtime, oldtime;
182xenstat_handle *xhandle = NULL;
183xenstat_node *prev_node = NULL;
184xenstat_node *cur_node = NULL;
185field_id sort_field = FIELD_DOMID;
186unsigned int first_domain_index = 0;
187unsigned int delay = 3;
188unsigned int batch = 0;
189unsigned int loop = 1;
190unsigned int iterations = 0;
191int show_vcpus = 0;
192int show_networks = 0;
193int show_vbds = 0;
194int repeat_header = 0;
195#define PROMPT_VAL_LEN 80
196char *prompt = NULL;
197char prompt_val[PROMPT_VAL_LEN];
198int prompt_val_len = 0;
199void (*prompt_complete_func)(char *);
200
201static WINDOW *cwin;
202
203/*
204 * Function definitions
205 */
206
207/* Utility functions */
208
209/* Print usage message, using given program name */
210static 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 */
229static 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 */
237static 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 */
250static 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. */
259static 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. */
267static 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. */
276static 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. */
294static 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 */
302static 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. */
312static 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 */
321static 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 <,=,> */
380static 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. */
391static 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 <,=,> */
399int 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 */
405void print_name(xenstat_domain *domain)
406{
407        print("%10s", xenstat_domain_name(domain));
408}
409
410struct {
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};
421const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
422
423/* Compare states of two domains, returning -1,0,1 for <,=,> */
424static 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 */
439static 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 <,=,> */
448static 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 */
455static 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 */
461static 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
485static 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 */
491static 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 <,=,> */
497static 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 */
504static 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 */
511static 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 <,=,> */
518static 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 */
525static 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 */
536static 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 * <,=,> */
547static 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 */
554static 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 * <,=,> */
561static 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 */
568static 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 <,=,> */
575static 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 */
582static 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 <,=,> */
589static 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 */
596static 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 */
604static 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 * <,=,> */
629static 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 */
636static 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 <,=,> */
643static 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 */
650static 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 <,=,> */
657static 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 */
664static 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 <,=,> */
671static 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 */
678static 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 */
688static 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 <,=,> */
718static 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 */
725static 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 */
732void 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 */
778void 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 */
799void 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 */
838void 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 */
854void 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 */
879void 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 */
910void 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
938static 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
991int 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}
Note: See TracBrowser for help on using the repository browser.