// Copyright (C) <2008>, Intel Corporation // Author: jiajun.xu@xxxxxxxxx // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License version // 2 as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int changeset_check(int xc_handle, int *cs) { char *delim = " "; char *tmp; int i = 1; int ret = 0; xen_changeset_info_t changeset; ret = xc_version(xc_handle, XENVER_changeset, &changeset); if ( ret ) { printf("get xen changeset num failed\n"); return ret; } tmp = strtok(changeset, delim); i++; while ( tmp ) { tmp = strtok(NULL, delim); if ( i == 7 ) break; i++; } delim=":"; tmp = strtok(tmp, delim); *cs = atoi(tmp); return ret; } int print_cx_pminfo(int xc_handle, int cpu) { int i, ret = 0; int max_cx_num; struct xc_cx_stat cxstatinfo, *cxstat = &cxstatinfo; int cs_num = 0; ret = changeset_check(xc_handle, &cs_num); if ( ret ) return ret; printf("==cpu %d==\n", cpu); /******* get max cx number ************/ ret = xc_pm_get_max_cx(xc_handle, cpu, &max_cx_num); if(ret) { printf("get_max_cx error(%d)\n", ret); return ret; } //printf("max cx num = %d\n", max_cx_num); /******* get cx statistic *************/ cxstat->triggers = malloc(max_cx_num * sizeof(uint64_t)); cxstat->residencies = malloc(max_cx_num * sizeof(uint64_t)); ret = xc_pm_get_cxstat(xc_handle, cpu, cxstat); if(ret) { printf("get_max_cxstat error(%d)\n", ret); return ret; } printf("nr = %d last = C%d\n", cxstat->nr, cxstat->last); printf("idle_time %-15ld\n", cxstat->idle_time/1000000UL); printf(" trigger residency\n"); if ( cs_num >= 18935 ) { for(i=0; itriggers[i], cxstat->residencies[i]/1000000UL); } else { for(i=0; itriggers[i], (cxstat->residencies[i]*1000000UL/3579)/1000000UL); } free(cxstat->triggers); free(cxstat->residencies); /********* reset cx statistic *********/ //ret = xc_pm_reset_cxstat(xc_handle, 0); //if(ret) // return ret; return ret; } static int get_cxstat_by_cpuid(int xc_fd, int cpuid, struct xc_cx_stat *cxstat) { int ret = 0; int max_cx_num = 0; ret = xc_pm_get_max_cx(xc_fd, cpuid, &max_cx_num); if ( ret ) return errno; if ( !cxstat ) return -EINVAL; cxstat->triggers = malloc(max_cx_num * sizeof(uint64_t)); if ( !cxstat->triggers ) return -ENOMEM; cxstat->residencies = malloc(max_cx_num * sizeof(uint64_t)); if ( !cxstat->residencies ) { free(cxstat->triggers); return -ENOMEM; } ret = xc_pm_get_cxstat(xc_fd, cpuid, cxstat); if( ret ) { int temp = errno; free(cxstat->triggers); free(cxstat->residencies); cxstat->triggers = NULL; cxstat->residencies = NULL; return temp; } return 0; } static int get_pxstat_by_cpuid(int xc_fd, int cpuid, struct xc_px_stat *pxstat) { int ret = 0; int max_px_num = 0; ret = xc_pm_get_max_px(xc_fd, cpuid, &max_px_num); if ( ret ) return errno; if ( !pxstat) return -EINVAL; pxstat->trans_pt = malloc(max_px_num * max_px_num * sizeof(uint64_t)); if ( !pxstat->trans_pt ) return -ENOMEM; pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val)); if ( !pxstat->pt ) { free(pxstat->trans_pt); return -ENOMEM; } ret = xc_pm_get_pxstat(xc_fd, cpuid, pxstat); if( ret ) { int temp = errno; free(pxstat->trans_pt); free(pxstat->pt); pxstat->trans_pt = NULL; pxstat->pt = NULL; return temp; } return 0; } int percentage_gather_func(int xc_handle, int cpu_num, unsigned int wait_tm, int c_flag, int p_flag) { int i, j; uint64_t usec_start, usec_end, elapsed_tm; struct timeval tv; struct xc_cx_stat *cxstat, *cxstat_start, *cxstat_end; struct xc_px_stat *pxstat, *pxstat_start, *pxstat_end; uint64_t *sum, *sum_cx, *sum_px; int ret = 0; int cs_num = 0; ret = changeset_check(xc_handle, &cs_num); if ( ret ) return ret; if ( gettimeofday(&tv, NULL) == -1 ) { fprintf(stderr, "failed to get timeofday\n"); return ; } usec_start = tv.tv_sec * 1000000UL + tv.tv_usec; sum = malloc(sizeof(uint64_t) * 2 * cpu_num); if ( sum == NULL ) return ; cxstat = malloc(sizeof(struct xc_cx_stat) * 2 * cpu_num); if ( cxstat == NULL ) { free(sum); return ; } pxstat = malloc(sizeof(struct xc_px_stat) * 2 * cpu_num); if ( pxstat == NULL ) { free(sum); free(cxstat); return ; } memset(sum, 0, sizeof(uint64_t) * 2 * cpu_num); memset(cxstat, 0, sizeof(struct xc_cx_stat) * 2 * cpu_num); memset(pxstat, 0, sizeof(struct xc_px_stat) * 2 * cpu_num); sum_cx = sum; sum_px = sum + cpu_num; cxstat_start = cxstat; cxstat_end = cxstat + cpu_num; pxstat_start = pxstat; pxstat_end = pxstat + cpu_num; if ( get_cxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV && c_flag == 1) { fprintf(stderr, "Xen cpu idle is disabled!\n"); return ; } if( get_pxstat_by_cpuid(xc_handle, 0, NULL) == -ENODEV && p_flag == 1) { fprintf(stderr, "Xen frequency is disabled!\n"); return ; } for ( i = 0; i < cpu_num; i++ ) { if ( c_flag == 1 ) get_cxstat_by_cpuid(xc_handle, i, &cxstat_start[i]); if ( p_flag == 1 ) get_pxstat_by_cpuid(xc_handle, i, &pxstat_start[i]); } sleep(wait_tm); if ( gettimeofday(&tv, NULL) == -1 ) { fprintf(stderr, "failed to get timeofday\n"); return ; } usec_end = tv.tv_sec * 1000000UL + tv.tv_usec; for ( i = 0; i < cpu_num; i++ ) { if ( c_flag == 1 ) get_cxstat_by_cpuid(xc_handle, i, &cxstat_end[i]); if ( p_flag == 1 ) get_pxstat_by_cpuid(xc_handle, i, &pxstat_end[i]); } elapsed_tm = (usec_end - usec_start); for ( i = 0; i < cpu_num; i++ ) { uint64_t temp; uint64_t trigger; printf("CPU%d:\n\tresidency\tpercentage\tave_residency\n", i); if ( c_flag == 1 ) { for ( j = 0; j < cxstat_end[i].nr; j++ ) { temp = cxstat_end[i].residencies[j] - cxstat_start[i].residencies[j]; trigger = cxstat_end[i].triggers[j] - cxstat_start[i].triggers[j]; if ( trigger == 0 ) trigger = 1; if ( cs_num >= 18935 ) printf(" C%d\t%"PRIu64"ms\t%.2f%%\t%"PRIu64"us\n", j, temp / 1000000UL, temp * 100UL / ((double)elapsed_tm * 1000UL), (temp / 1000UL) / trigger ); else printf(" C%d\t%"PRIu64"ms\t%.2f%%\t%"PRIu64"us\n", j, (temp * 1000000UL / 3579) / 1000000UL, ((temp * 1000000000UL / 3579) / 1000000UL) / ((double)elapsed_tm / 1000UL), ((temp * 1000000UL / 3579) / 1000UL) / trigger ); } } if ( p_flag == 1 ) { for ( j = 0; j < pxstat_end[i].total; j++ ) { temp = pxstat_end[i].pt[j].residency - pxstat_start[i].pt[j].residency; trigger = pxstat_end[i].pt[j].count - pxstat_start[i].pt[j].count; if ( trigger == 0 ) trigger = 1; printf(" P%d\t%"PRIu64"ms\t%.2f%%\t%"PRIu64"us\n", j, temp / 1000000UL, temp * 100UL / ((double)elapsed_tm * 1000UL), (temp / 1000UL) / trigger ); } } } for ( i = 0; i < 2 * cpu_num; i++ ) { free(cxstat[i].triggers); free(cxstat[i].residencies); free(pxstat[i].trans_pt); free(pxstat[i].pt); } free(cxstat); free(pxstat); free(sum); xc_interface_close(xc_handle); exit(0); } int print_px_pminfo(int xc_handle, int cpu) { int max_px_num; int i, ret = 0; struct xc_px_stat pxstatinfo, *pxstat = &pxstatinfo; printf("==cpu %d==\n", cpu); ret = xc_pm_get_max_px(xc_handle, cpu, &max_px_num); if(ret) { printf("get_max_px error(%d)\n", ret); return ret; } printf("max px num = %d\n", max_px_num); pxstat->trans_pt = malloc(max_px_num * max_px_num * sizeof(uint64_t)); pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val)); ret = xc_pm_get_pxstat(xc_handle, cpu, pxstat); if(ret) { printf("get_max_pxstat error(%d)\n", ret); return ret; } printf("total = %d, usable = %d, last = %d, cur = %d\n", pxstat->total, pxstat->usable, pxstat->last, pxstat->cur); printf(" freq residency count\n"); for(i=0; ipt[i].freq, pxstat->pt[i].residency/1000000UL, pxstat->pt[i].count); /*for(i=0; itrans_pt[i]); } printf("\n");*/ free(pxstat->trans_pt); free(pxstat->pt); return ret; } int main(int argc, char **argv) { int c; extern char *optarg; extern int optind; int cpu_num = 1; int p_policy = 0; int c_policy = 0; int percentage = 0; int cpu; int ret = 0; int reset = 0; int wait_tm = 0; xc_physinfo_t physinfo = { 0 }; while ((c = getopt(argc, argv, "rcpn:s:")) != -1) { switch (c) { case 'n': cpu_num = atoi(optarg); break; case 'p': p_policy = 1; break; case 'c': c_policy = 1; break; case 'r': reset = 1; break; case 's': percentage = 1; wait_tm = atoi(optarg); break; default: printf("You should set CPU num\n"); exit(1); } } xc_interface *xc_handle = xc_interface_open(0,0,0); if (!xc_handle) { fprintf(stderr, "failed to get the handler\n"); return 0; } ret = xc_physinfo(xc_handle, &physinfo); if ( ret ) { fprintf(stderr, "failed to get the processor information\n"); xc_interface_close(xc_handle); return 0; } if ( cpu_num == 1 ) cpu_num = physinfo.nr_cpus; if ( reset == 1 ) { printf("Reset statistic data\n"); for ( cpu = 0; cpu < cpu_num; cpu++ ) { if ( p_policy == 1 ) { ret = xc_pm_reset_pxstat(xc_handle, cpu); if (ret) { printf("reset px statistic info error(%d)\n", ret); exit(ret); } } if ( c_policy == 1 ) { ret = xc_pm_reset_cxstat(xc_handle, cpu); if (ret) { printf("reset cx statistic info error(%d)\n", ret); exit(ret); } } } return xc_interface_close(xc_handle); } if ( percentage == 1 ) { return percentage_gather_func(xc_handle, cpu_num, wait_tm, c_policy, p_policy); } printf("=====begin to collect statistic collection=====\n"); for ( cpu = 0; cpu < cpu_num; cpu++ ) { if ( p_policy == 1 ) { ret = print_px_pminfo(xc_handle, cpu); if (ret) { printf("get px statistic info error(%d)\n", ret); exit(ret); } } if ( c_policy == 1 ) ret = print_cx_pminfo(xc_handle, cpu); if (ret) { printf("get cx statistic info error(%d)\n", ret); exit(ret); } } printf("=====end of statistic data collecton=====\n"); return xc_interface_close(xc_handle); }