1
/* libxenstat: statistics-collection library for Xen
2
* Copyright (C) International Business Machines Corp., 2005
3
* Authors: Josh Triplett <josh@kernel.org>
4
* Judy Fischbach <jfisch@cs.pdx.edu>
5
* David Hendricks <cro_marmot@comcast.net>
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library 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 GNU
15
* Lesser General Public License for more details.
19
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
20
* Use is subject to license terms.
28
#include "xenstat_priv.h"
31
* Data-collection types
33
/* Called to collect the information for the node and all the domains on
34
* it. When called, the domain information has already been collected.
35
* Return status is 0 if fatal error occurs, 1 for success. Collectors
36
* may prune a domain from the list if it has been deleted between the
37
* time the list was setup and the time the colector is called */
38
typedef int (*xenstat_collect_func)(xenstat_node * node);
39
/* Called to free the information collected by the collect function. The free
40
* function will only be called on a xenstat_node if that node includes
41
* information collected by the corresponding collector. */
42
typedef void (*xenstat_free_func)(xenstat_node * node);
43
/* Called to free any information stored in the handle. Note the lack of a
44
* matching init function; the collect functions should initialize on first
45
* use. Also, the uninit function must handle the case that the collector has
46
* never been initialized. */
47
typedef void (*xenstat_uninit_func)(xenstat_handle * handle);
48
typedef struct xenstat_collector {
50
xenstat_collect_func collect;
51
xenstat_free_func free;
52
xenstat_uninit_func uninit;
55
static int xenstat_collect_vcpus(xenstat_node * node);
56
static int xenstat_collect_xen_version(xenstat_node * node);
57
static void xenstat_free_vcpus(xenstat_node * node);
58
static void xenstat_free_networks(xenstat_node * node);
59
static void xenstat_free_xen_version(xenstat_node * node);
60
static void xenstat_free_vbds(xenstat_node * node);
61
static void xenstat_uninit_vcpus(xenstat_handle * handle);
62
static void xenstat_uninit_xen_version(xenstat_handle * handle);
63
static char *xenstat_get_domain_name(xenstat_handle * handle, unsigned int domain_id);
64
static void xenstat_prune_domain(xenstat_node *node, unsigned int entry);
66
static xenstat_collector collectors[] = {
67
{ XENSTAT_VCPU, xenstat_collect_vcpus,
68
xenstat_free_vcpus, xenstat_uninit_vcpus },
69
{ XENSTAT_NETWORK, xenstat_collect_networks,
70
xenstat_free_networks, xenstat_uninit_networks },
71
{ XENSTAT_XEN_VERSION, xenstat_collect_xen_version,
72
xenstat_free_xen_version, xenstat_uninit_xen_version },
73
{ XENSTAT_VBD, xenstat_collect_vbds,
74
xenstat_free_vbds, xenstat_uninit_vbds }
77
#define NUM_COLLECTORS (sizeof(collectors)/sizeof(xenstat_collector))
82
xenstat_handle *xenstat_init(void)
84
xenstat_handle *handle;
86
handle = (xenstat_handle *) calloc(1, sizeof(xenstat_handle));
91
handle->page_size = PAGESIZE;
92
#elif defined(PAGE_SIZE)
93
handle->page_size = PAGE_SIZE;
95
handle->page_size = sysconf(_SC_PAGE_SIZE);
96
if (handle->page_size < 0) {
97
perror("Failed to retrieve page size.");
103
handle->xc_handle = xc_interface_open();
104
if (handle->xc_handle == -1) {
105
perror("xc_interface_open");
110
handle->xshandle = xs_daemon_open_readonly(); /* open handle to xenstore*/
111
if (handle->xshandle == NULL) {
112
perror("unable to open xenstore");
113
xc_interface_close(handle->xc_handle);
121
void xenstat_uninit(xenstat_handle * handle)
125
for (i = 0; i < NUM_COLLECTORS; i++)
126
collectors[i].uninit(handle);
127
xc_interface_close(handle->xc_handle);
128
xs_daemon_close(handle->xshandle);
134
static inline unsigned long long parse(char *s, char *match)
136
char *s1 = strstr(s,match);
137
unsigned long long ret;
144
sscanf(s1,"%llu",&ret);
148
void domain_get_tmem_stats(xenstat_handle * handle, xenstat_domain * domain)
152
if (xc_tmem_control(handle->xc_handle,-1,TMEMC_LIST,domain->id,
153
sizeof(buffer),-1,-1,buffer) < 0)
155
domain->tmem_stats.curr_eph_pages = parse(buffer,"Ec");
156
domain->tmem_stats.succ_eph_gets = parse(buffer,"Ge");
157
domain->tmem_stats.succ_pers_puts = parse(buffer,"Pp");
158
domain->tmem_stats.succ_pers_gets = parse(buffer,"Gp");
161
xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags)
163
#define DOMAIN_CHUNK_SIZE 256
165
xc_physinfo_t physinfo = { 0 };
166
xc_domaininfo_t domaininfo[DOMAIN_CHUNK_SIZE];
167
unsigned int new_domains;
170
/* Create the node */
171
node = (xenstat_node *) calloc(1, sizeof(xenstat_node));
175
/* Store the handle in the node for later access */
176
node->handle = handle;
178
/* Get information about the physical system */
179
if (xc_physinfo(handle->xc_handle, &physinfo) < 0) {
185
node->cpu_hz = ((unsigned long long)physinfo.cpu_khz) * 1000ULL;
186
node->num_cpus = physinfo.nr_cpus;
187
node->tot_mem = ((unsigned long long)physinfo.total_pages)
189
node->free_mem = ((unsigned long long)physinfo.free_pages)
192
node->freeable_mb = (long)xc_tmem_control(handle->xc_handle, -1,
193
TMEMC_QUERY_FREEABLE_MB, -1, 0, 0, 0, NULL);
195
/* malloc(0) is not portable, so allocate a single domain. This will
196
* be resized below. */
197
node->domains = malloc(sizeof(xenstat_domain));
198
if (node->domains == NULL) {
203
node->num_domains = 0;
205
xenstat_domain *domain, *tmp;
207
new_domains = xc_domain_getinfolist(handle->xc_handle,
212
tmp = realloc(node->domains,
213
(node->num_domains + new_domains)
214
* sizeof(xenstat_domain));
222
domain = node->domains + node->num_domains;
224
/* zero out newly allocated memory in case error occurs below */
225
memset(domain, 0, new_domains * sizeof(xenstat_domain));
227
for (i = 0; i < new_domains; i++) {
228
/* Fill in domain using domaininfo[i] */
229
domain->id = domaininfo[i].domain;
230
domain->name = xenstat_get_domain_name(handle,
232
if (domain->name == NULL) {
233
if (errno == ENOMEM) {
235
xenstat_free_node(node);
239
/* failed to get name -- this means the
240
domain is being destroyed so simply
245
domain->state = domaininfo[i].flags;
246
domain->cpu_ns = domaininfo[i].cpu_time;
247
domain->num_vcpus = (domaininfo[i].max_vcpu_id+1);
248
domain->vcpus = NULL;
250
((unsigned long long)domaininfo[i].tot_pages)
253
domaininfo[i].max_pages == UINT_MAX
254
? (unsigned long long)-1
255
: (unsigned long long)(domaininfo[i].max_pages
256
* handle->page_size);
257
domain->ssid = domaininfo[i].ssidref;
258
domain->num_networks = 0;
259
domain->networks = NULL;
260
domain->num_vbds = 0;
262
domain_get_tmem_stats(handle,domain);
267
} while (new_domains == DOMAIN_CHUNK_SIZE);
270
/* Run all the extra data collectors requested */
272
for (i = 0; i < NUM_COLLECTORS; i++) {
273
if ((flags & collectors[i].flag) == collectors[i].flag) {
274
node->flags |= collectors[i].flag;
275
if(collectors[i].collect(node) == 0) {
276
xenstat_free_node(node);
285
void xenstat_free_node(xenstat_node * node)
291
for (i = 0; i < node->num_domains; i++)
292
free(node->domains[i].name);
294
for (i = 0; i < NUM_COLLECTORS; i++)
295
if((node->flags & collectors[i].flag)
296
== collectors[i].flag)
297
collectors[i].free(node);
304
xenstat_domain *xenstat_node_domain(xenstat_node * node, unsigned int domid)
308
/* FIXME: binary search */
309
/* Find the appropriate domain entry in the node struct. */
310
for (i = 0; i < node->num_domains; i++) {
311
if (node->domains[i].id == domid)
312
return &(node->domains[i]);
317
xenstat_domain *xenstat_node_domain_by_index(xenstat_node * node,
320
if (0 <= index && index < node->num_domains)
321
return &(node->domains[index]);
325
const char *xenstat_node_xen_version(xenstat_node * node)
327
return node->handle->xen_version;
330
unsigned long long xenstat_node_tot_mem(xenstat_node * node)
332
return node->tot_mem;
335
unsigned long long xenstat_node_free_mem(xenstat_node * node)
337
return node->free_mem;
340
long xenstat_node_freeable_mb(xenstat_node * node)
342
return node->freeable_mb;
345
unsigned int xenstat_node_num_domains(xenstat_node * node)
347
return node->num_domains;
350
unsigned int xenstat_node_num_cpus(xenstat_node * node)
352
return node->num_cpus;
355
/* Get information about the CPU speed */
356
unsigned long long xenstat_node_cpu_hz(xenstat_node * node)
361
/* Get the domain ID for this domain */
362
unsigned xenstat_domain_id(xenstat_domain * domain)
367
/* Get the domain name for the domain */
368
char *xenstat_domain_name(xenstat_domain * domain)
373
/* Get information about how much CPU time has been used */
374
unsigned long long xenstat_domain_cpu_ns(xenstat_domain * domain)
376
return domain->cpu_ns;
379
/* Find the number of VCPUs for a domain */
380
unsigned int xenstat_domain_num_vcpus(xenstat_domain * domain)
382
return domain->num_vcpus;
385
xenstat_vcpu *xenstat_domain_vcpu(xenstat_domain * domain, unsigned int vcpu)
387
if (0 <= vcpu && vcpu < domain->num_vcpus)
388
return &(domain->vcpus[vcpu]);
392
/* Find the current memory reservation for this domain */
393
unsigned long long xenstat_domain_cur_mem(xenstat_domain * domain)
395
return domain->cur_mem;
398
/* Find the maximum memory reservation for this domain */
399
unsigned long long xenstat_domain_max_mem(xenstat_domain * domain)
401
return domain->max_mem;
404
/* Find the domain's SSID */
405
unsigned int xenstat_domain_ssid(xenstat_domain * domain)
410
/* Get domain states */
411
unsigned int xenstat_domain_dying(xenstat_domain * domain)
413
return (domain->state & XEN_DOMINF_dying) == XEN_DOMINF_dying;
416
unsigned int xenstat_domain_crashed(xenstat_domain * domain)
418
return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
419
&& (((domain->state >> XEN_DOMINF_shutdownshift)
420
& XEN_DOMINF_shutdownmask) == SHUTDOWN_crash);
423
unsigned int xenstat_domain_shutdown(xenstat_domain * domain)
425
return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
426
&& (((domain->state >> XEN_DOMINF_shutdownshift)
427
& XEN_DOMINF_shutdownmask) != SHUTDOWN_crash);
430
unsigned int xenstat_domain_paused(xenstat_domain * domain)
432
return (domain->state & XEN_DOMINF_paused) == XEN_DOMINF_paused;
435
unsigned int xenstat_domain_blocked(xenstat_domain * domain)
437
return (domain->state & XEN_DOMINF_blocked) == XEN_DOMINF_blocked;
440
unsigned int xenstat_domain_running(xenstat_domain * domain)
442
return (domain->state & XEN_DOMINF_running) == XEN_DOMINF_running;
445
/* Get the number of networks for a given domain */
446
unsigned int xenstat_domain_num_networks(xenstat_domain * domain)
448
return domain->num_networks;
451
/* Get the network handle to obtain network stats */
452
xenstat_network *xenstat_domain_network(xenstat_domain * domain,
453
unsigned int network)
455
if (domain->networks && 0 <= network && network < domain->num_networks)
456
return &(domain->networks[network]);
460
/* Get the number of VBDs for a given domain */
461
unsigned int xenstat_domain_num_vbds(xenstat_domain * domain)
463
return domain->num_vbds;
466
/* Get the VBD handle to obtain VBD stats */
467
xenstat_vbd *xenstat_domain_vbd(xenstat_domain * domain,
470
if (domain->vbds && 0 <= vbd && vbd < domain->num_vbds)
471
return &(domain->vbds[vbd]);
478
/* Collect information about VCPUs */
479
static int xenstat_collect_vcpus(xenstat_node * node)
481
unsigned int i, vcpu, inc_index;
483
/* Fill in VCPU information */
484
for (i = 0; i < node->num_domains; i+=inc_index) {
485
inc_index = 1; /* default is to increment to next domain */
487
node->domains[i].vcpus = malloc(node->domains[i].num_vcpus
488
* sizeof(xenstat_vcpu));
489
if (node->domains[i].vcpus == NULL)
492
for (vcpu = 0; vcpu < node->domains[i].num_vcpus; vcpu++) {
493
/* FIXME: need to be using a more efficient mechanism*/
496
if (xc_vcpu_getinfo(node->handle->xc_handle,
497
node->domains[i].id, vcpu, &info) != 0) {
498
if (errno == ENOMEM) {
503
/* domain is in transition - remove
505
xenstat_prune_domain(node, i);
507
/* remember not to increment index! */
513
node->domains[i].vcpus[vcpu].online = info.online;
514
node->domains[i].vcpus[vcpu].ns = info.cpu_time;
521
/* Free VCPU information */
522
static void xenstat_free_vcpus(xenstat_node * node)
525
for (i = 0; i < node->num_domains; i++)
526
free(node->domains[i].vcpus);
529
/* Free VCPU information in handle - nothing to do */
530
static void xenstat_uninit_vcpus(xenstat_handle * handle)
534
/* Get VCPU online status */
535
unsigned int xenstat_vcpu_online(xenstat_vcpu * vcpu)
541
unsigned long long xenstat_vcpu_ns(xenstat_vcpu * vcpu)
550
/* Free network information */
551
static void xenstat_free_networks(xenstat_node * node)
554
for (i = 0; i < node->num_domains; i++)
555
free(node->domains[i].networks);
558
/* Get the network ID */
559
unsigned int xenstat_network_id(xenstat_network * network)
564
/* Get the number of receive bytes */
565
unsigned long long xenstat_network_rbytes(xenstat_network * network)
567
return network->rbytes;
570
/* Get the number of receive packets */
571
unsigned long long xenstat_network_rpackets(xenstat_network * network)
573
return network->rpackets;
576
/* Get the number of receive errors */
577
unsigned long long xenstat_network_rerrs(xenstat_network * network)
579
return network->rerrs;
582
/* Get the number of receive drops */
583
unsigned long long xenstat_network_rdrop(xenstat_network * network)
585
return network->rdrop;
588
/* Get the number of transmit bytes */
589
unsigned long long xenstat_network_tbytes(xenstat_network * network)
591
return network->tbytes;
594
/* Get the number of transmit packets */
595
unsigned long long xenstat_network_tpackets(xenstat_network * network)
597
return network->tpackets;
600
/* Get the number of transmit errors */
601
unsigned long long xenstat_network_terrs(xenstat_network * network)
603
return network->terrs;
606
/* Get the number of transmit dropped packets */
607
unsigned long long xenstat_network_tdrop(xenstat_network * network)
609
return network->tdrop;
613
* Xen version functions
616
/* Collect Xen version information */
617
static int xenstat_collect_xen_version(xenstat_node * node)
620
xen_extraversion_t version;
622
/* Collect Xen version information if not already collected */
623
if (node->handle->xen_version[0] == '\0') {
624
/* Get the Xen version number and extraversion string */
625
vnum = xc_version(node->handle->xc_handle,
626
XENVER_version, NULL);
631
if (xc_version(node->handle->xc_handle, XENVER_extraversion,
634
/* Format the version information as a string and store it */
635
snprintf(node->handle->xen_version, VERSION_SIZE, "%ld.%ld%s",
636
((vnum >> 16) & 0xFFFF), vnum & 0xFFFF, version);
642
/* Free Xen version information in node - nothing to do */
643
static void xenstat_free_xen_version(xenstat_node * node)
647
/* Free Xen version information in handle - nothing to do */
648
static void xenstat_uninit_xen_version(xenstat_handle * handle)
656
/* Free VBD information */
657
static void xenstat_free_vbds(xenstat_node * node)
660
for (i = 0; i < node->num_domains; i++)
661
free(node->domains[i].vbds);
664
/* Get the back driver type for Virtual Block Device */
665
unsigned int xenstat_vbd_type(xenstat_vbd * vbd)
667
return vbd->back_type;
670
/* Get the major number of VBD device */
671
unsigned int xenstat_vbd_dev(xenstat_vbd * vbd)
676
/* Get the number of OO(Out of) requests */
677
unsigned long long xenstat_vbd_oo_reqs(xenstat_vbd * vbd)
682
/* Get the number of READ requests */
683
unsigned long long xenstat_vbd_rd_reqs(xenstat_vbd * vbd)
688
/* Get the number of WRITE requests */
689
unsigned long long xenstat_vbd_wr_reqs(xenstat_vbd * vbd)
694
/* Get the number of READ sectors */
695
unsigned long long xenstat_vbd_rd_sects(xenstat_vbd * vbd)
697
return vbd->rd_sects;
700
/* Get the number of WRITE sectors */
701
unsigned long long xenstat_vbd_wr_sects(xenstat_vbd * vbd)
703
return vbd->wr_sects;
710
xenstat_tmem *xenstat_domain_tmem(xenstat_domain * domain)
712
return &domain->tmem_stats;
715
/* Get the current number of ephemeral pages */
716
unsigned long long xenstat_tmem_curr_eph_pages(xenstat_tmem *tmem)
718
return tmem->curr_eph_pages;
721
/* Get the number of successful ephemeral gets */
722
unsigned long long xenstat_tmem_succ_eph_gets(xenstat_tmem *tmem)
724
return tmem->succ_eph_gets;
727
/* Get the number of successful persistent puts */
728
unsigned long long xenstat_tmem_succ_pers_puts(xenstat_tmem *tmem)
730
return tmem->succ_pers_puts;
733
/* Get the number of successful persistent gets */
734
unsigned long long xenstat_tmem_succ_pers_gets(xenstat_tmem *tmem)
736
return tmem->succ_pers_gets;
740
static char *xenstat_get_domain_name(xenstat_handle *handle, unsigned int domain_id)
742
char path[80], *vmpath;
744
snprintf(path, sizeof(path),"/local/domain/%i/vm", domain_id);
746
vmpath = xs_read(handle->xshandle, XBT_NULL, path, NULL);
751
snprintf(path, sizeof(path),"%s/name", vmpath);
754
return xs_read(handle->xshandle, XBT_NULL, path, NULL);
757
/* Remove specified entry from list of domains */
758
static void xenstat_prune_domain(xenstat_node *node, unsigned int entry)
760
/* nothing to do if array is empty or entry is beyond end */
761
if (node->num_domains == 0 || entry >= node->num_domains)
764
/* decrement count of domains */
767
/* shift entries following specified entry up by one */
768
if (entry < node->num_domains) {
769
xenstat_domain *domain = &node->domains[entry];
770
memmove(domain,domain+1,(node->num_domains - entry) * sizeof(xenstat_domain) );
773
/* zero out original last entry from node -- not
774
strictly necessary but safer! */
775
memset(&node->domains[node->num_domains], 0, sizeof(xenstat_domain));