ia64/xen-unstable

view tools/xenstat/libxenstat/src/xenstat.c @ 6439:af7251014caf

Formatting fixes for xenstat and xentop.
Signed-off-by: Josh Triplett <josht@us.ibm.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Fri Aug 26 08:47:49 2005 +0000 (2005-08-26)
parents 522bc50588ed
children 9404574350ce
line source
1 /* libxenstat: statistics-collection library for Xen
2 * Copyright (C) International Business Machines Corp., 2005
3 * Authors: Josh Triplett <josht@us.ibm.com>
4 * Judy Fischbach <jfisch@us.ibm.com>
5 * David Hendricks <dhendrix@us.ibm.com>
6 *
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.
11 *
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.
16 */
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <xen-interface.h>
24 #include "xenstat.h"
25 #include "version.h"
27 /*
28 * Types
29 */
30 struct xenstat_handle {
31 xi_handle *xihandle;
32 int page_size;
33 FILE *procnetdev;
34 };
36 #define SHORT_ASC_LEN 5 /* length of 65535 */
37 #define VERSION_SIZE (2 * SHORT_ASC_LEN + 1 + sizeof(xen_extraversion_t) + 1)
39 struct xenstat_node {
40 unsigned int flags;
41 unsigned long long cpu_hz;
42 unsigned int num_cpus;
43 unsigned long long tot_mem;
44 unsigned long long free_mem;
45 unsigned int num_domains;
46 char xen_version[VERSION_SIZE]; /* xen version running on this node */
47 xenstat_domain *domains; /* Array of length num_domains */
48 };
50 struct xenstat_domain {
51 unsigned int id;
52 unsigned int state;
53 unsigned long long cpu_ns;
54 unsigned int num_vcpus;
55 xenstat_vcpu *vcpus; /* Array of length num_vcpus */
56 unsigned long long cur_mem; /* Current memory reservation */
57 unsigned long long max_mem; /* Total memory allowed */
58 unsigned int ssid;
59 unsigned int num_networks;
60 xenstat_network *networks; /* Array of length num_networks */
61 };
63 struct xenstat_vcpu {
64 unsigned long long ns;
65 };
67 struct xenstat_network {
68 unsigned int id;
69 /* Received */
70 unsigned long long rbytes;
71 unsigned long long rpackets;
72 unsigned long long rerrs;
73 unsigned long long rdrop;
74 /* Transmitted */
75 unsigned long long tbytes;
76 unsigned long long tpackets;
77 unsigned long long terrs;
78 unsigned long long tdrop;
79 };
81 /*
82 * Data-collection types
83 */
84 /* Called to collect the information for the node and all the domains on
85 * it. When called, the domain information has already been collected. */
86 typedef int (*xenstat_collect_func)(xenstat_handle * handle,
87 xenstat_node * node);
88 /* Called to free the information collected by the collect function. The free
89 * function will only be called on a xenstat_node if that node includes
90 * information collected by the corresponding collector. */
91 typedef void (*xenstat_free_func)(xenstat_node * node);
92 /* Called to free any information stored in the handle. Note the lack of a
93 * matching init function; the collect functions should initialize on first
94 * use. Also, the uninit function must handle the case that the collector has
95 * never been initialized. */
96 typedef void (*xenstat_uninit_func)(xenstat_handle * handle);
97 typedef struct xenstat_collector {
98 unsigned int flag;
99 xenstat_collect_func collect;
100 xenstat_free_func free;
101 xenstat_uninit_func uninit;
102 } xenstat_collector;
104 static int xenstat_collect_vcpus(xenstat_handle * handle,
105 xenstat_node * node);
106 static int xenstat_collect_networks(xenstat_handle * handle,
107 xenstat_node * node);
108 static void xenstat_free_vcpus(xenstat_node * node);
109 static void xenstat_free_networks(xenstat_node * node);
110 static void xenstat_uninit_vcpus(xenstat_handle * handle);
111 static void xenstat_uninit_networks(xenstat_handle * handle);
113 static xenstat_collector collectors[] = {
114 { XENSTAT_VCPU, xenstat_collect_vcpus,
115 xenstat_free_vcpus, xenstat_uninit_vcpus },
116 { XENSTAT_NETWORK, xenstat_collect_networks,
117 xenstat_free_networks, xenstat_uninit_networks }
118 };
120 #define NUM_COLLECTORS (sizeof(collectors)/sizeof(xenstat_collector))
122 /*
123 * libxenstat API
124 */
125 xenstat_handle *xenstat_init()
126 {
127 xenstat_handle *handle;
129 handle = (xenstat_handle *) calloc(1, sizeof(xenstat_handle));
130 if (handle == NULL)
131 return NULL;
133 #if defined(PAGESIZE)
134 handle->page_size = PAGESIZE;
135 #elif defined(PAGE_SIZE)
136 handle->page_size = PAGE_SIZE;
137 #else
138 handle->page_size = sysconf(_SC_PAGE_SIZE);
139 if (handle->page_size < 0) {
140 perror("Failed to retrieve page size.");
141 free(handle);
142 return NULL;
143 }
144 #endif
146 handle->xihandle = xi_init();
147 if (handle->xihandle == NULL) {
148 perror("xi_init");
149 free(handle);
150 return NULL;
151 }
153 return handle;
154 }
156 void xenstat_uninit(xenstat_handle * handle)
157 {
158 unsigned int i;
159 if (handle) {
160 for (i = 0; i < NUM_COLLECTORS; i++)
161 collectors[i].uninit(handle);
162 xi_uninit(handle->xihandle);
163 free(handle);
164 }
165 }
167 xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags)
168 {
169 #define DOMAIN_CHUNK_SIZE 256
170 xenstat_node *node;
171 dom0_physinfo_t physinfo;
172 xen_extraversion_t version;
173 long vnum = 0;
174 dom0_getdomaininfo_t domaininfo[DOMAIN_CHUNK_SIZE];
175 unsigned int num_domains, new_domains;
176 unsigned int i;
178 /* Create the node */
179 node = (xenstat_node *) calloc(1, sizeof(xenstat_node));
180 if (node == NULL)
181 return NULL;
183 /* Get information about the physical system */
184 if (xi_get_physinfo(handle->xihandle, &physinfo) < 0) {
185 free(node);
186 return NULL;
187 }
189 /* Get the xen version number and xen version tag */
190 if (xi_get_xen_version(handle->xihandle, &vnum, &version) < 0) {
191 free(node);
192 return NULL;
193 }
194 snprintf(node->xen_version, VERSION_SIZE, "%ld.%ld%s\n",
195 ((vnum >> 16) & 0xFFFF), vnum & 0xFFFF, version);
197 node->cpu_hz = ((unsigned long long)physinfo.cpu_khz) * 1000ULL;
198 node->num_cpus =
199 (physinfo.threads_per_core * physinfo.cores_per_socket *
200 physinfo.sockets_per_node * physinfo.nr_nodes);
201 node->tot_mem = ((unsigned long long)physinfo.total_pages)
202 * handle->page_size;
203 node->free_mem = ((unsigned long long)physinfo.free_pages)
204 * handle->page_size;
206 /* malloc(0) is not portable, so allocate a single domain. This will
207 * be resized below. */
208 node->domains = malloc(sizeof(xenstat_domain));
209 if (node->domains == NULL) {
210 free(node);
211 return NULL;
212 }
214 num_domains = 0;
215 do {
216 xenstat_domain *domain;
218 new_domains = xi_get_domaininfolist(handle->xihandle,
219 domaininfo, num_domains,
220 DOMAIN_CHUNK_SIZE);
222 node->domains = realloc(node->domains,
223 (num_domains + new_domains)
224 * sizeof(xenstat_domain));
225 if (node->domains == NULL) {
226 free(node);
227 return NULL;
228 }
230 domain = node->domains + num_domains;
232 for (i = 0; i < new_domains; i++) {
233 /* Fill in domain using domaininfo[i] */
234 domain->id = domaininfo[i].domain;
235 domain->state = domaininfo[i].flags;
236 domain->cpu_ns = domaininfo[i].cpu_time;
237 domain->num_vcpus = domaininfo[i].n_vcpu;
238 domain->vcpus = NULL;
239 domain->cur_mem =
240 ((unsigned long long)domaininfo[i].tot_pages)
241 * handle->page_size;
242 domain->max_mem =
243 domaininfo[i].max_pages == UINT_MAX
244 ? (unsigned long long)-1
245 : (unsigned long long)(domaininfo[i].max_pages
246 * handle->page_size);
247 domain->ssid = domaininfo[i].ssidref;
248 domain->num_networks = 0;
249 domain->networks = NULL;
251 domain++;
252 }
253 num_domains += new_domains;
254 } while (new_domains == DOMAIN_CHUNK_SIZE);
255 node->num_domains = num_domains;
257 /* Run all the extra data collectors requested */
258 node->flags = 0;
259 for (i = 0; i < NUM_COLLECTORS; i++) {
260 if ((flags & collectors[i].flag) == collectors[i].flag) {
261 node->flags |= collectors[i].flag;
262 if(collectors[i].collect(handle, node) == 0) {
263 xenstat_free_node(node);
264 return NULL;
265 }
266 }
267 }
269 return node;
270 }
272 void xenstat_free_node(xenstat_node * node)
273 {
274 int i;
276 if (node) {
277 if (node->domains) {
278 for (i = 0; i < NUM_COLLECTORS; i++)
279 if((node->flags & collectors[i].flag)
280 == collectors[i].flag)
281 collectors[i].free(node);
282 free(node->domains);
283 }
284 free(node);
285 }
286 }
288 xenstat_domain *xenstat_node_domain(xenstat_node * node, unsigned int domid)
289 {
290 unsigned int i;
292 /* FIXME: binary search */
293 /* Find the appropriate domain entry in the node struct. */
294 for (i = 0; i < node->num_domains; i++) {
295 if (node->domains[i].id == domid)
296 return &(node->domains[i]);
297 }
298 return NULL;
299 }
301 xenstat_domain *xenstat_node_domain_by_index(xenstat_node * node,
302 unsigned int index)
303 {
304 if (0 <= index && index < node->num_domains)
305 return &(node->domains[index]);
306 return NULL;
307 }
309 const char *xenstat_node_xen_ver(xenstat_node * node)
310 {
311 return node->xen_version;
312 }
314 unsigned long long xenstat_node_tot_mem(xenstat_node * node)
315 {
316 return node->tot_mem;
317 }
319 unsigned long long xenstat_node_free_mem(xenstat_node * node)
320 {
321 return node->free_mem;
322 }
324 unsigned int xenstat_node_num_domains(xenstat_node * node)
325 {
326 return node->num_domains;
327 }
329 unsigned int xenstat_node_num_cpus(xenstat_node * node)
330 {
331 return node->num_cpus;
332 }
334 /* Get information about the CPU speed */
335 unsigned long long xenstat_node_cpu_hz(xenstat_node * node)
336 {
337 return node->cpu_hz;
338 }
340 /* Get the domain ID for this domain */
341 unsigned xenstat_domain_id(xenstat_domain * domain)
342 {
343 return domain->id;
344 }
346 /* Get information about how much CPU time has been used */
347 unsigned long long xenstat_domain_cpu_ns(xenstat_domain * domain)
348 {
349 return domain->cpu_ns;
350 }
352 /* Find the number of VCPUs allocated to a domain */
353 unsigned int xenstat_domain_num_vcpus(xenstat_domain * domain)
354 {
355 return domain->num_vcpus;
356 }
358 xenstat_vcpu *xenstat_domain_vcpu(xenstat_domain * domain, unsigned int vcpu)
359 {
360 if (0 <= vcpu && vcpu < domain->num_vcpus)
361 return &(domain->vcpus[vcpu]);
362 return NULL;
363 }
365 /* Find the current memory reservation for this domain */
366 unsigned long long xenstat_domain_cur_mem(xenstat_domain * domain)
367 {
368 return domain->cur_mem;
369 }
371 /* Find the maximum memory reservation for this domain */
372 unsigned long long xenstat_domain_max_mem(xenstat_domain * domain)
373 {
374 return domain->max_mem;
375 }
377 /* Find the domain's SSID */
378 unsigned int xenstat_domain_ssid(xenstat_domain * domain)
379 {
380 return domain->ssid;
381 }
383 /* Get domain states */
384 unsigned int xenstat_domain_dying(xenstat_domain * domain)
385 {
386 return (domain->state & DOMFLAGS_DYING) == DOMFLAGS_DYING;
387 }
389 unsigned int xenstat_domain_crashed(xenstat_domain * domain)
390 {
391 return ((domain->state & DOMFLAGS_SHUTDOWN) == DOMFLAGS_SHUTDOWN)
392 && (((domain->state >> DOMFLAGS_SHUTDOWNSHIFT)
393 & DOMFLAGS_SHUTDOWNMASK) == SHUTDOWN_crash);
394 }
396 unsigned int xenstat_domain_shutdown(xenstat_domain * domain)
397 {
398 return ((domain->state & DOMFLAGS_SHUTDOWN) == DOMFLAGS_SHUTDOWN)
399 && (((domain->state >> DOMFLAGS_SHUTDOWNSHIFT)
400 & DOMFLAGS_SHUTDOWNMASK) != SHUTDOWN_crash);
401 }
403 unsigned int xenstat_domain_paused(xenstat_domain * domain)
404 {
405 return (domain->state & DOMFLAGS_PAUSED) == DOMFLAGS_PAUSED;
406 }
408 unsigned int xenstat_domain_blocked(xenstat_domain * domain)
409 {
410 return (domain->state & DOMFLAGS_BLOCKED) == DOMFLAGS_BLOCKED;
411 }
413 unsigned int xenstat_domain_running(xenstat_domain * domain)
414 {
415 return (domain->state & DOMFLAGS_RUNNING) == DOMFLAGS_RUNNING;
416 }
418 /* Get the number of networks for a given domain */
419 unsigned int xenstat_domain_num_networks(xenstat_domain * domain)
420 {
421 return domain->num_networks;
422 }
424 /* Get the network handle to obtain network stats */
425 xenstat_network *xenstat_domain_network(xenstat_domain * domain,
426 unsigned int network)
427 {
428 if (domain->networks && 0 <= network && network < domain->num_networks)
429 return &(domain->networks[network]);
430 return NULL;
431 }
433 /*
434 * VCPU functions
435 */
436 /* Collect information about VCPUs */
437 static int xenstat_collect_vcpus(xenstat_handle * handle, xenstat_node * node)
438 {
439 unsigned int i, vcpu;
440 /* Fill in VCPU information */
441 for (i = 0; i < node->num_domains; i++) {
442 node->domains[i].vcpus = malloc(node->domains[i].num_vcpus
443 * sizeof(xenstat_vcpu));
444 if (node->domains[i].vcpus == NULL)
445 return 0;
447 for (vcpu = 0; vcpu < node->domains[i].num_vcpus; vcpu++) {
448 /* FIXME: need to be using a more efficient mechanism*/
449 long long vcpu_time;
450 vcpu_time =
451 xi_get_vcpu_usage(handle->xihandle,
452 node->domains[i].id,
453 vcpu);
454 if (vcpu_time < 0)
455 return 0;
456 node->domains[i].vcpus[vcpu].ns = vcpu_time;
457 }
458 }
459 return 1;
460 }
462 /* Free VCPU information */
463 static void xenstat_free_vcpus(xenstat_node * node)
464 {
465 unsigned int i;
466 for (i = 0; i < node->num_domains; i++)
467 free(node->domains[i].vcpus);
468 }
470 /* Free VCPU information in handle - nothing to do */
471 static void xenstat_uninit_vcpus(xenstat_handle * handle)
472 {
473 }
475 /* Get VCPU usage */
476 unsigned long long xenstat_vcpu_ns(xenstat_vcpu * vcpu)
477 {
478 return vcpu->ns;
479 }
481 /*
482 * Network functions
483 */
485 /* Expected format of /proc/net/dev */
486 static const char PROCNETDEV_HEADER[] =
487 "Inter-| Receive |"
488 " Transmit\n"
489 " face |bytes packets errs drop fifo frame compressed multicast|"
490 "bytes packets errs drop fifo colls carrier compressed\n";
492 /* Collect information about networks */
493 static int xenstat_collect_networks(xenstat_handle * handle,
494 xenstat_node * node)
495 {
496 /* Open and validate /proc/net/dev if we haven't already */
497 if (handle->procnetdev == NULL) {
498 char header[sizeof(PROCNETDEV_HEADER)];
499 handle->procnetdev = fopen("/proc/net/dev", "r");
500 if (handle->procnetdev == NULL) {
501 perror("Error opening /proc/net/dev");
502 return 1;
503 }
505 /* Validate the format of /proc/net/dev */
506 if (fread(header, sizeof(PROCNETDEV_HEADER) - 1, 1,
507 handle->procnetdev) != 1) {
508 perror("Error reading /proc/net/dev header");
509 return 1;
510 }
511 header[sizeof(PROCNETDEV_HEADER) - 1] = '\0';
512 if (strcmp(header, PROCNETDEV_HEADER) != 0) {
513 fprintf(stderr,
514 "Unexpected /proc/net/dev format\n");
515 return 1;
516 }
517 }
519 /* Fill in networks */
520 /* FIXME: optimize this */
521 fseek(handle->procnetdev, sizeof(PROCNETDEV_HEADER) - 1, SEEK_SET);
522 while (1) {
523 xenstat_domain *domain;
524 xenstat_network net;
525 unsigned int domid;
526 int ret = fscanf(handle->procnetdev,
527 "vif%u.%u:%llu%llu%llu%llu%*u%*u%*u%*u"
528 "%llu%llu%llu%llu%*u%*u%*u%*u\n",
529 &domid, &net.id,
530 &net.tbytes, &net.tpackets, &net.terrs,
531 &net.tdrop,
532 &net.rbytes, &net.rpackets, &net.rerrs,
533 &net.rdrop);
534 if (ret == EOF)
535 break;
536 if (ret != 10) {
537 unsigned int c;
538 do {
539 c = fgetc(handle->procnetdev);
540 } while (c != '\n' && c != EOF);
541 if (c == EOF)
542 break;
543 continue;
544 }
546 /* FIXME: this does a search for the domid */
547 domain = xenstat_node_domain(node, domid);
548 if (domain == NULL) {
549 fprintf(stderr,
550 "Found interface vif%u.%u but domain %u"
551 " does not exist.\n", domid, net.id,
552 domid);
553 continue;
554 }
555 if (domain->networks == NULL) {
556 domain->num_networks = 1;
557 domain->networks = malloc(sizeof(xenstat_network));
558 } else {
559 domain->num_networks++;
560 domain->networks =
561 realloc(domain->networks,
562 domain->num_networks *
563 sizeof(xenstat_network));
564 }
565 if (domain->networks == NULL)
566 return 1;
567 domain->networks[domain->num_networks - 1] = net;
568 }
570 return 1;
571 }
573 /* Free network information */
574 static void xenstat_free_networks(xenstat_node * node)
575 {
576 unsigned int i;
577 for (i = 0; i < node->num_domains; i++)
578 free(node->domains[i].networks);
579 }
581 /* Free network information in handle */
582 static void xenstat_uninit_networks(xenstat_handle * handle)
583 {
584 if(handle->procnetdev)
585 fclose(handle->procnetdev);
586 }
588 /* Get the network ID */
589 unsigned int xenstat_network_id(xenstat_network * network)
590 {
591 return network->id;
592 }
594 /* Get the number of receive bytes */
595 unsigned long long xenstat_network_rbytes(xenstat_network * network)
596 {
597 return network->rbytes;
598 }
600 /* Get the number of receive packets */
601 unsigned long long xenstat_network_rpackets(xenstat_network * network)
602 {
603 return network->rpackets;
604 }
606 /* Get the number of receive errors */
607 unsigned long long xenstat_network_rerrs(xenstat_network * network)
608 {
609 return network->rerrs;
610 }
612 /* Get the number of receive drops */
613 unsigned long long xenstat_network_rdrop(xenstat_network * network)
614 {
615 return network->rdrop;
616 }
618 /* Get the number of transmit bytes */
619 unsigned long long xenstat_network_tbytes(xenstat_network * network)
620 {
621 return network->tbytes;
622 }
624 /* Get the number of transmit packets */
625 unsigned long long xenstat_network_tpackets(xenstat_network * network)
626 {
627 return network->tpackets;
628 }
630 /* Get the number of transmit errors */
631 unsigned long long xenstat_network_terrs(xenstat_network * network)
632 {
633 return network->terrs;
634 }
636 /* Get the number of transmit dropped packets */
637 unsigned long long xenstat_network_tdrop(xenstat_network * network)
638 {
639 return network->tdrop;
640 }