#include #include #include #include #include #include #include #include #include #include #if defined(__linux__) #include #endif #include #include #include #include double sum_cpu_pct, sum_mem_pct; double *load_vector = NULL; double *sloadvec = NULL; unsigned int delay = 3; unsigned int window = 10; struct timeval curtime, oldtime; xenstat_handle *xhandle = NULL; xenstat_node *prev_node = NULL; xenstat_node *cur_node = NULL; static int signal_exit; static int count = 0; typedef struct load_svector { double *load_vector; struct load_svector *next; } load_svector, *load_svector_ptr; static void signal_exit_handler(int sig) { signal_exit = 1; } struct sigaction sa = { .sa_handler = signal_exit_handler, .sa_flags = 0 }; /* Clean up any open resources */ static void cleanup(void) { if(prev_node != NULL) xenstat_free_node(prev_node); if(cur_node != NULL) xenstat_free_node(cur_node); if(xhandle != NULL) xenstat_uninit(xhandle); } /* Field types */ typedef enum field_id { FIELD_DOMID, FIELD_NAME, FIELD_STATE, FIELD_CPU, FIELD_CPU_PCT, FIELD_MEM, FIELD_MEM_PCT, FIELD_MAXMEM, FIELD_MAX_PCT, FIELD_VCPUS, FIELD_NETS, FIELD_NET_TX, FIELD_NET_RX, FIELD_VBDS, FIELD_VBD_OO, FIELD_VBD_RD, FIELD_VBD_WR, FIELD_SSID } field_id; /* * Function prototypes */ /* Computes the CPU percentage used for a specified domain */ static double get_cpu_pct(xenstat_domain *domain) { xenstat_domain *old_domain; double us_elapsed; /* Can't calculate CPU percentage without a previous sample. */ if(prev_node == NULL) return 0.0; old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain)); if(old_domain == NULL) return 0.0; /* Calculate the time elapsed in microseconds */ us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0 +(curtime.tv_usec - oldtime.tv_usec)); /* In the following, nanoseconds must be multiplied by 1000.0 to * convert to microseconds, then divided by 100.0 to get a percentage, * resulting in a multiplication by 10.0 */ return ((xenstat_domain_cpu_ns(domain) -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed; } /* Prints memory percentage statistic, ratio of current domain memory to total * node memory */ static double get_mem_pct(xenstat_domain *domain) { return ((double)xenstat_domain_cur_mem(domain) / (double)xenstat_node_tot_mem(cur_node) * 100); } /* Gets number of total network bytes statistic, if rx true, then rx bytes * otherwise tx bytes */ static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag) { int i = 0; xenstat_network *network; unsigned num_networks = 0; unsigned long long total = 0; /* How many networks? */ num_networks = xenstat_domain_num_networks(domain); /* Dump information for each network */ for (i=0; i < num_networks; i++) { /* Next get the network information */ network = xenstat_domain_network(domain,i); if (rx_flag) total += xenstat_network_rbytes(network); else total += xenstat_network_tbytes(network); } return total; } /* Gets number of total VBD requests statistic, * if flag is FIELD_VBD_OO, then OO requests, * if flag is FIELD_VBD_RD, then READ requests and * if flag is FIELD_VBD_WR, then WRITE requests. */ static unsigned long long tot_vbd_reqs(xenstat_domain *domain, int flag) { int i = 0; xenstat_vbd *vbd; unsigned num_vbds = 0; unsigned long long total = 0; num_vbds = xenstat_domain_num_vbds(domain); for ( i=0 ; i < num_vbds ; i++) { vbd = xenstat_domain_vbd(domain,i); switch(flag) { case FIELD_VBD_OO: total += xenstat_vbd_oo_reqs(vbd); break; case FIELD_VBD_RD: total += xenstat_vbd_rd_reqs(vbd); break; case FIELD_VBD_WR: total += xenstat_vbd_wr_reqs(vbd); break; default: break; } } return total; } static void calc_load_vector_stats(double *load_vector, struct load_svector **loadsvec, struct load_svector **loadscurr, struct load_svector **loadswin, int num_domains, int window) { int i; struct load_svector *svec = calloc(1, sizeof(struct load_svector)); svec->load_vector = calloc(num_domains, sizeof(double)); for (i=0; i < num_domains; i++) { svec->load_vector[i] = load_vector[i]; } svec->next = NULL; if((*loadsvec) == NULL) { (*loadsvec) = svec; (*loadswin) = svec; } else { (*loadscurr)->next = svec; if((*loadswin) == NULL) { (*loadswin) = svec; } } (*loadscurr) = svec; if(count == 0) { count = window - 1; } else { count = count - 1; } if(count == 0) { int k = 0; int start = 0; int idx = 0; struct load_svector *tmp; double *sloadvec = NULL; sloadvec = calloc((num_domains*window), sizeof(double)); do { for (k = start; k < (num_domains+start); k++) { sloadvec[k] = (((*loadswin))->load_vector)[idx]; idx++; } start = k; idx = 0; tmp = (*loadswin)->next; (*loadswin) = tmp; } while((*loadswin) != NULL); assert(sloadvec); if(sloadvec != NULL) { // I know this is what assert does.. int u = 0; double mean, std, var, skew, kurtosis, autocorr = 0.0; for (u = 0; u < (num_domains*window); u++) { fprintf(stderr, "Stats Array Id: %d Elem: %f \n", u, sloadvec[u]); } mean = gsl_stats_mean(sloadvec, sizeof(double), (num_domains*window)); std = gsl_stats_sd(sloadvec, sizeof(double), (num_domains*window)); var = gsl_stats_variance(sloadvec, sizeof(double), (num_domains*window)); skew = gsl_stats_skew(sloadvec, sizeof(double), (num_domains*window)); kurtosis = gsl_stats_kurtosis(sloadvec, sizeof(double), (num_domains*window)); autocorr = gsl_stats_lag1_autocorrelation(sloadvec, sizeof(double), (num_domains*window)); fprintf(stderr, "%g %g %g %g %g %g %g \n", mean, std, var, (std/mean), skew, kurtosis, autocorr); free(sloadvec); } } } static void get_virtual_server_load(xenstat_domain **domains, unsigned int num_domains, xenstat_node *cur_node, double **load_vector) { double cpu_pct, mem_pct; unsigned int i; unsigned long long net_bytes; unsigned long long vbd_reqs; unsigned long long used = 0; for (i=0; i < num_domains; i++) { cpu_pct = get_cpu_pct(domains[i]); mem_pct = get_mem_pct(domains[i]); net_bytes = tot_net_bytes(domains[i], 1); vbd_reqs = tot_vbd_reqs(domains[i], 1); sum_cpu_pct += cpu_pct; sum_mem_pct += mem_pct; (*load_vector)[i] = (0.5 * cpu_pct) + (0.5 * mem_pct); //fprintf("CPU: %g MEM: %g Net Bytes: %llu VBD Bytes: %llu \n", cpu_pct, mem_pct, net_bytes, vbd_reqs); //fprintf("CPU: %g MEM: %g \n", cpu_pct, mem_pct); //fprintf(stderr, "%g", (*load_vector)[i]); } //fprintf(stderr, "%s", "\n"); used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node); //fprintf("Mem: %lluk total, %lluk used, %lluk free " // "CPUs: %u @ %lluMHz\n", // xenstat_node_tot_mem(cur_node)/1024, used/1024, // xenstat_node_free_mem(cur_node)/1024, // xenstat_node_num_cpus(cur_node), // xenstat_node_cpu_hz(cur_node)/1000000); } int main(int argc, char **argv) { xenstat_domain **domains; unsigned int i, num_domains = 0; static struct load_svector *loadsvec, *loadscurr, *loadswin = NULL; if (atexit(cleanup) != 0) fprintf(stderr, "%s", "Failed to install cleanup handler.\n"); xhandle = xenstat_init(); if (xhandle == NULL) fprintf(stderr, "%s", "Failed to initialize xenstat library\n"); delay = atoi(argv[1]); window = atoi(argv[2]); sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); do { gettimeofday(&curtime, NULL); /* Now get the node information */ if (prev_node != NULL) xenstat_free_node(prev_node); prev_node = cur_node; cur_node = xenstat_get_node(xhandle, XENSTAT_ALL); if (cur_node == NULL) fprintf(stderr, "%s", "Failed to retrieve statistics from libxenstat\n"); /* Count the number of domains for which to report data */ num_domains = xenstat_node_num_domains(cur_node); domains = calloc(num_domains, sizeof(xenstat_domain *)); if(domains == NULL) fprintf(stderr, "%s", "Failed to allocate memory\n"); for (i=0; i < num_domains; i++) domains[i] = xenstat_node_domain_by_index(cur_node, i); load_vector = calloc(num_domains, sizeof(double)); get_virtual_server_load(domains, num_domains, cur_node, &load_vector); oldtime = curtime; calc_load_vector_stats(load_vector, &loadsvec, &loadscurr, &loadswin, num_domains, window); free(domains); free(load_vector); sleep(delay); } while (!signal_exit); /* fprintf("Autocorrelation %g \n", gsl_stats_lag1_autocorrelation(load_vector, sizeof(double), (num_domains))); */ }