PageRenderTime 213ms CodeModel.GetById 40ms app.highlight 122ms RepoModel.GetById 39ms app.codeStats 0ms

/tools/misc/gtracestat.c

https://bitbucket.org/sp/xen-4.0-testing-sp
C | 1209 lines | 984 code | 114 blank | 111 comment | 236 complexity | fa9d8d493e2484b87fc66935f6b0929a MD5 | raw file
   1/*
   2 * gtracestat.c: list the statistics information for a dumped xentrace file.
   3 * Copyright (c) 2009, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  16 * Place - Suite 330, Boston, MA 02111-1307 USA.
  17 */
  18
  19#include <stdio.h>
  20#include <stdlib.h>
  21#include <string.h>
  22#include <unistd.h>
  23#include <fcntl.h>
  24#include <getopt.h>
  25#include <inttypes.h>
  26#include <sys/time.h>
  27#include <sys/types.h>
  28#include <sys/stat.h>
  29
  30#include <xenctrl.h>
  31#include <xen/trace.h>
  32
  33#define CHECK_DUP_CX 0
  34
  35/********** MACROS **********/
  36#define MAX_CPU_NR  32
  37#define MAX_CX_NR   8
  38#define MAX_MODE_NR 16
  39#define MAX_PX_NR	100
  40
  41/* simplified xentrace record */
  42struct rec {
  43    uint64_t tsc;
  44    int cpu;
  45    unsigned char cx;
  46    unsigned char irqs[4];
  47    unsigned int predicted;
  48    unsigned int expected;
  49    int px;
  50};
  51
  52/********** FORWARD DECLARATION **********/
  53void show_help(void);
  54void show_version(void);
  55int load_file(char *fname);
  56void do_digest(uint64_t start, uint64_t end, uint64_t scale);
  57void do_breakevents(void);
  58void do_count(void);
  59void do_px_count(void);
  60void do_maxmin(void);
  61void do_average(void);
  62void do_cstate(uint64_t start, uint64_t end);
  63void do_exp_ratio(void);
  64void do_exp_pred(void);
  65
  66/********** GLOBAL VARIABLES **********/
  67/* store simplified xentrace data */
  68struct rec *data;
  69int64_t data_nr, data_cur;
  70/* store max cx state number and cpu number */
  71int max_cx_num = -1, max_cpu_num = -1;
  72int px_freq_table[MAX_PX_NR];
  73int max_px_num = 0;
  74
  75int is_menu_gov_enabled = 0;
  76
  77/* user specified translation unit */
  78uint64_t tsc2ms = 2793000UL;
  79uint64_t tsc2us = 2793UL;
  80uint64_t tsc2phase = 55800000UL;
  81
  82/* each cpu column width */
  83int width = 0;
  84
  85/* digest mode variables */
  86struct rec *evt[MAX_CPU_NR];
  87int evt_len[MAX_CPU_NR];
  88
  89/* hand-crafted min() */
  90static inline uint64_t min(uint64_t a, uint64_t b)
  91{
  92    return a < b ? a : b;
  93}
  94static inline uint64_t max(uint64_t a, uint64_t b)
  95{
  96    return a > b ? a : b;
  97}
  98
  99int is_px = 0;
 100
 101int main(int argc, char *argv[])
 102{
 103    char *fname = NULL;
 104    /* operation flags */
 105    int is_breakevents = 0;
 106    int is_count = 0;
 107    int is_maxmin = 0;
 108    int is_average = 0;
 109    int is_digest = 0;
 110    int is_exp_ratio = 0;
 111    int is_exp = 0;
 112    uint64_t start_time = 0;
 113    uint64_t time_scale = 0;
 114    uint64_t end_time = 0;
 115
 116    struct option  long_options [] = {
 117        /* short options are listed correspondingly */
 118        { "version", 0, NULL, 'v' },
 119        { "help", 0, NULL, 'h' },
 120        /* list Cx entires one by one */
 121        { "digest", 0, NULL, 'd' },
 122        /* ignored when digest is disabled */
 123        { "start", 1, NULL, 's' },
 124        { "end", 1, NULL, 'e' },
 125        { "scale", 1, NULL, 'l' },
 126        /* give summary about breakevents info */
 127        { "breakevents", 0, NULL, 'b' },
 128        { "count", 0, NULL, 'c' },
 129        { "average", 0, NULL, 'a' },
 130        /* list max/min residency for each Cx */
 131        { "maxmin", 0, NULL, 'm' },
 132        { "tsc2us", 1, NULL, 'u' },
 133        { "px", 0, NULL, 'p' },
 134        { "tsc2phase", 1, NULL, 'n' },
 135        { "exp-ratio", 0, NULL, 'z' },
 136        { "exp-pred", 0, NULL, 'x' },
 137        { NULL, 0, NULL, 0 },
 138    };
 139
 140    while (1) {
 141        int ch, opt_idx;
 142        ch = getopt_long(argc, argv, "vhds:e:l:bcmaupnzx",
 143                         long_options, &opt_idx);
 144        if (ch == -1)
 145            break;
 146        switch (ch) {
 147        case 'v':
 148            show_version();
 149            exit(EXIT_SUCCESS);
 150        case 'h':
 151            show_help();
 152            exit(EXIT_SUCCESS);
 153        case 'p':
 154            is_px = 1;
 155            break;
 156        case 'x':
 157            is_exp = 1;
 158            break;
 159        case 'z':
 160            is_exp_ratio = 1;
 161            break;
 162        case 'n':
 163            tsc2phase = atoll(optarg);
 164            if (tsc2phase <= 0)
 165                tsc2phase = 55800000UL;
 166        case 'd':
 167            is_digest = 1;
 168            break;
 169        case 's':
 170            start_time = atoll(optarg);
 171            break;
 172        case 'e':
 173            end_time = atoll(optarg);
 174            break;
 175        case 'l':
 176            time_scale = atoll(optarg);
 177            break;
 178        case 'b':
 179            is_breakevents = 1;
 180            break;
 181        case 'c':
 182            is_count = 1;
 183            break;
 184        case 'm':
 185            is_maxmin = 1;
 186            break;
 187        case 'a':
 188            is_average = 1;
 189            break;
 190        case 'u':
 191            tsc2us = atoll(optarg);
 192            tsc2ms = tsc2us * 1000UL;
 193            break;
 194        case '?':
 195        default:
 196            show_help();
 197            exit(EXIT_FAILURE);
 198        }
 199    }
 200
 201    if (argc - optind > 1) {
 202        printf("Multiple file specified?\n");
 203        show_help();
 204        exit(EXIT_FAILURE);
 205    }
 206    fname = argv[optind];
 207
 208    if (load_file(fname))
 209        exit(EXIT_FAILURE);
 210
 211    width = 10;
 212    if (is_digest) {
 213        /* if people not specify the time related number,
 214         * use the default one from the record.
 215         */
 216        if (!start_time)
 217            start_time = data[0].tsc;
 218        if (!end_time)
 219            end_time = data[data_cur-1].tsc;
 220        if (!time_scale)
 221            time_scale = 10UL * tsc2ms;	/* default: 10 ms */
 222        do_digest(start_time, end_time, time_scale);
 223    }
 224
 225    if (is_breakevents)
 226        do_breakevents();
 227
 228    if (is_count && !is_px)
 229        do_count();
 230    if (is_count && is_px)
 231        do_px_count();
 232
 233    if (is_maxmin)
 234        do_maxmin();
 235
 236    if (is_average)
 237        do_average();
 238
 239    if (is_exp_ratio)
 240        do_exp_ratio();
 241
 242    if (is_exp)
 243        do_exp_pred();
 244
 245    exit(EXIT_SUCCESS);
 246}
 247
 248/* used for qsort() */
 249/* sort by cpu first, then by tsc */
 250static int data_cmp(const void *_a, const void *_b)
 251{
 252    struct rec *a = (struct rec *)_a;
 253    struct rec *b = (struct rec *)_b;
 254    if (a->cpu == b->cpu)
 255        return a->tsc > b->tsc ? 1 : -1;
 256    return a->cpu > b->cpu ? 1 : -1;
 257}
 258
 259/* load file and make them a list of records
 260 * update these following variables:
 261 *   data, data_cur, data_nr
 262 *   max_cpu_num, max_cx_num
 263 */
 264#define LIST_PX 0
 265int load_file(char *fname)
 266{
 267    /* file descriptor for raw xentrace file */
 268    int fd;
 269    /* current cpu during xentrace data parse */
 270    int cur_cpu = -1;
 271    int i;
 272
 273    fd = open(fname, O_RDONLY);
 274    if (fd < 0) {
 275        fprintf(stderr, "file %s cannot open\n", fname);
 276        return 1;
 277    }
 278
 279    /* the initial number is 1024,
 280     * and when it overflows, this number doubles.
 281     */
 282    data_nr = 1024;
 283    data_cur = 0;
 284    data = malloc(sizeof(struct rec) * data_nr);
 285    if (!data) {
 286        fprintf(stderr, "not enough memory\n");
 287        close(fd);
 288        return 1;
 289    }
 290
 291    while (1) {
 292        struct t_rec rec;
 293        ssize_t ret, size;
 294
 295        ret = read(fd, &rec, sizeof(uint32_t));
 296        if (!ret)
 297            break;
 298        if (ret != sizeof(uint32_t)) {
 299            fprintf(stderr, "reading header error\n");
 300            break;
 301        }
 302
 303        size = 0;
 304        if (rec.cycles_included)
 305            size += sizeof(uint64_t);
 306        size += sizeof(uint32_t) * rec.extra_u32;
 307
 308        ret = read(fd, (char *)&rec + sizeof(uint32_t), size);
 309        if (!ret && size)
 310            break;
 311        if (ret != size) {
 312            fprintf(stderr, "reading data error\n");
 313            break;
 314        }
 315
 316        if (rec.event == 0x1f003) {
 317            /* cpu change event */
 318            cur_cpu = 0;
 319            if (rec.extra_u32 > 0)
 320                cur_cpu = rec.u.nocycles.extra_u32[0];
 321            continue;
 322        } else if (!rec.cycles_included ||
 323                   (rec.event != TRC_PM_IDLE_ENTRY &&
 324                    rec.event != TRC_PM_IDLE_EXIT &&
 325                    rec.event != TRC_PM_FREQ_CHANGE)) {
 326            /* we care about only idle events now */
 327            continue;
 328        }
 329
 330        /* add one record */
 331        if (data_cur == data_nr) {
 332            data_nr <<= 1;
 333            if (data_nr < 0) {
 334                fprintf(stderr, "too many entries\n");
 335                close(fd);
 336                return 1;
 337            }
 338            data = realloc(data, sizeof(struct rec) * data_nr);
 339            if (!data) {
 340                fprintf(stderr, "not enough memory\n");
 341                close(fd);
 342                return 1;
 343            }
 344        }
 345        data[data_cur].tsc = rec.u.cycles.cycles_hi;
 346        data[data_cur].tsc <<= 32;
 347        data[data_cur].tsc |= rec.u.cycles.cycles_lo;
 348        data[data_cur].cpu = cur_cpu;
 349        if (is_px) {
 350            if (rec.event != TRC_PM_FREQ_CHANGE)
 351                continue;
 352            /* FREQ_CHANGE */
 353            if (rec.u.cycles.extra_u32[0] ==
 354                rec.u.cycles.extra_u32[1])
 355                continue;
 356            data[data_cur].px = rec.u.cycles.extra_u32[1];
 357            for (i = 0; i < max_px_num; i++)
 358                if (px_freq_table[i] == data[data_cur].px)
 359                    break;
 360            if (i == max_px_num)
 361                px_freq_table[max_px_num++] = data[data_cur].px;
 362        } else {
 363            if (rec.event == TRC_PM_IDLE_ENTRY) {
 364                data[data_cur].cx = rec.u.cycles.extra_u32[0];
 365                if (rec.extra_u32 >= 4) {
 366                    data[data_cur].expected = rec.u.cycles.extra_u32[2];
 367                    data[data_cur].predicted = rec.u.cycles.extra_u32[3];
 368                    is_menu_gov_enabled = 1;
 369                } else
 370                    is_menu_gov_enabled = 0;
 371            } else if (rec.event == TRC_PM_IDLE_EXIT) {
 372                /* IDLE_EXIT default to C0 */
 373                data[data_cur].cx = 0;
 374                /* store the reasons why it exits */
 375                data[data_cur].irqs[0] = rec.u.cycles.extra_u32[2];
 376                data[data_cur].irqs[1] = rec.u.cycles.extra_u32[3];
 377                data[data_cur].irqs[2] = rec.u.cycles.extra_u32[4];
 378                data[data_cur].irqs[3] = rec.u.cycles.extra_u32[5];
 379            } else
 380                continue;
 381            /* update max info */
 382            if (data[data_cur].cx > max_cx_num)
 383                max_cx_num = data[data_cur].cx;
 384        }
 385
 386        if (data[data_cur].cpu > max_cpu_num)
 387            max_cpu_num = data[data_cur].cpu;
 388
 389        data_cur++;
 390    }
 391    close(fd);
 392
 393    /* sort data array according to TSC time line */
 394    qsort(data, data_cur, sizeof(struct rec), data_cmp);
 395
 396    max_cpu_num++;
 397    max_cx_num++;
 398
 399    for (i = 0; i < max_cpu_num; i++) {
 400        evt_len[i] = 0;
 401        evt[i] = NULL;
 402    }
 403    for (i = data_cur-1; i >= 0; i--) {
 404        evt[data[i].cpu] = data+i;
 405        evt_len[data[i].cpu]++;
 406    }
 407#if CHECK_DUP_CX
 408    int xx, yy;
 409    int err = 0;
 410    printf("Checking %s...\n", fname);
 411    for (xx = 0; xx < max_cpu_num; xx++) {
 412        //	printf("............ CPU %d .............\n", xx);
 413        for (yy = 0; yy+1 < evt_len[xx]; yy++)
 414            if ( evt[xx][yy].cx > 0 && evt[xx][yy+1].cx > 0) {
 415                printf("same witht next one %"PRIu64" %d %d\n",
 416                       evt[xx][yy].tsc, evt[xx][yy].cpu, evt[xx][yy].cx);
 417                err++;
 418            }
 419    }
 420    exit(err);
 421#endif
 422#if LIST_PX
 423    int x, y;
 424    for (x = 0; x < max_cpu_num; x++) {
 425        printf("CPU%d**************************************\n", x);
 426        for (y = 0; y+1 < evt_len[x]; y++) {
 427            printf("[%dHz]: phase: %d\n",
 428                   evt[x][y].px,
 429                   (int)((evt[x][y+1].tsc - evt[x][y].tsc)/tsc2phase));
 430        }
 431    }
 432#endif
 433    return 0;
 434}
 435
 436void show_version(void)
 437{
 438    printf("gtracestat - (C) 2009 Intel Corporation\n");
 439}
 440
 441void show_help(void)
 442{
 443    show_version();
 444    printf("tracestat <trace.data> [-vhdselbcmau]\n");
 445    printf("  trace.data       raw data got by 'xentrace -e 0x80f000 trace.dat'\n");
 446    printf("  -v / --version   show version message\n");
 447    printf("  -h / --help      show this message\n");
 448    printf("  -d / --digest    digest mode, more variables to specify.\n");
 449    printf("  -s / --start <start_time> specify start time (only in digest mode)\n");
 450    printf("  -e / --end <end_time>     specify end time (only in digest mode)\n");
 451    printf("  -l / --scale <scale>      specify time scale (only in digest mode)\n");
 452    printf("  -b / --breakevents give breakevents summary info\n");
 453    printf("  -c / --count       give count summary info\n");
 454    printf("  -a / --average     give total/average residency info\n");
 455    printf("  -m / --maxmin      show man/min residency summary info\n");
 456    printf("  -u / --tsc2us      specify how many tsc is a us unit\n");
 457    printf("  -p / --px          operate on Px entries\n");
 458    printf("  -n / --tsc2phase   specify how many tsc is a phase unit (only in px)\n");
 459    printf("  -z / --exp-ratio   show the ratio of early break events\n");
 460    printf("  -x / --exp-pred    show the ratio of expected / predicted in Cx entry\n");
 461}
 462
 463static inline int len_of_number(uint64_t n)
 464{
 465    int l = 0;
 466    do {
 467        l++;
 468        n /= 10;
 469    } while (n);
 470    return l;
 471}
 472
 473/* determine the cx at time t
 474 * take advantage of evt and evt_len.
 475 */
 476int determine_cx(int c, uint64_t t)
 477{
 478    int i;
 479
 480    i = 0;
 481    while (i < evt_len[c] && evt[c][i].tsc <= t)
 482        i++;
 483    /* if there are any events happening,
 484     * it must be in a Cx state now.
 485     */
 486    if (i)
 487        return evt[c][i-1].cx;
 488    /* look forward to see whether it will enter
 489     * a Cx state, if so, it must be in C0 state.
 490     * we can't determine a Cx state from exit event.
 491     */
 492    if (i < evt_len[c] && evt[c][i].cx > 0)
 493        return 0;
 494    return -1;
 495}
 496
 497/* c - cpu
 498 * t - start time
 499 * s - scale
 500 * cx_i - number of cx index
 501 * cx_r - residency of each cx entry
 502 */
 503int process(int c, uint64_t t, uint64_t s, int *cx_i, uint64_t *cx_r)
 504{
 505    int cx;
 506    uint64_t len;
 507    int i, n;
 508
 509    cx = determine_cx(c, t);
 510    i = 0;
 511    while (i < evt_len[c] && evt[c][i].tsc < t)
 512        i++;
 513    n = 0;
 514    if (cx >= 0 && i < evt_len[c]) {
 515        cx_i[n] = cx;
 516        cx_r[n] = evt[c][i].tsc - t;
 517        if (cx_r[n])
 518            n++;
 519    }
 520    while (i < evt_len[c] && evt[c][i].tsc < t+s) {
 521        /* we are now at [t, t+s) */
 522        cx = evt[c][i].cx;
 523        len = min((i+1 < evt_len[c] ? evt[c][i+1].tsc : t+s), t+s)
 524            - evt[c][i].tsc;
 525
 526        cx_i[n] = cx;
 527        cx_r[n] = len;
 528        n++;
 529
 530        i++;
 531    }
 532
 533    return n;
 534}
 535
 536void nr_putchar(int nr, int ch)
 537{
 538    int i;
 539    for (i = 0; i < nr; i++)
 540        putchar(ch);
 541}
 542
 543#define MAX_INTERVAL_ENTRY	1000
 544/* process period [start_time, start_time + time_scale) */
 545void single_digest(uint64_t start_time, uint64_t time_scale)
 546{
 547    int cpu;
 548    int cx_i[MAX_CPU_NR][MAX_INTERVAL_ENTRY];
 549    uint64_t cx_r[MAX_CPU_NR][MAX_INTERVAL_ENTRY];
 550    int cx_n[MAX_CPU_NR];
 551    int max_n;
 552
 553    memset(cx_i, 0, sizeof(int) * MAX_CPU_NR * MAX_INTERVAL_ENTRY);
 554    memset(cx_r, 0, sizeof(uint64_t) * MAX_CPU_NR * MAX_INTERVAL_ENTRY);
 555    memset(cx_n, 0, sizeof(int) * MAX_CPU_NR);
 556
 557    max_n = 0;
 558    for (cpu = 0; cpu < max_cpu_num; cpu++) {
 559        cx_n[cpu] = process(cpu, start_time, time_scale, cx_i[cpu], cx_r[cpu]);
 560        if (cx_n[cpu] > max_n)
 561            max_n = cx_n[cpu];
 562    }
 563
 564    /* means how many lines will be consumed */
 565    while (--max_n >= 0) {
 566        for (cpu = 0; cpu < max_cpu_num; cpu++) {
 567            if (cx_n[cpu] > 0) {
 568                int i;
 569                /* find the available cx index */
 570                for (i = 0; i < MAX_INTERVAL_ENTRY && cx_i[cpu][i] == -1; i++)
 571                    ;
 572                if (i < MAX_INTERVAL_ENTRY) {
 573                    int len;
 574                    /* print it */
 575                    len= printf("C%d,%"PRIu64".%d", cx_i[cpu][i],
 576                                cx_r[cpu][i]/tsc2ms,
 577                                (unsigned int)(cx_r[cpu][i]/(tsc2ms/10))%10);
 578                    nr_putchar(width-len, ' ');
 579
 580                    cx_i[cpu][i] = -1;
 581                } else
 582                    nr_putchar(width, ' ');
 583
 584                cx_n[cpu]--;
 585            } else
 586                nr_putchar(width, ' ');
 587        }
 588        nr_putchar(1, '\n');
 589    }
 590}
 591
 592void do_digest(uint64_t start, uint64_t end, uint64_t scale)
 593{
 594    int i;
 595    uint64_t ms = 0;
 596    uint64_t delta_ms = scale / tsc2ms;
 597
 598    for (i = 0; i < max_cpu_num; i++) {
 599        int len = 0;
 600        len = printf("CPU%d", i);
 601        nr_putchar(width-len, ' ');
 602    }
 603    nr_putchar(1, '\n');
 604    while (start < end) {
 605        /* print --- xxx ms --- line */
 606        int off = (max_cpu_num * width - len_of_number(ms) - 2)/2;
 607        nr_putchar(off, '-');
 608        off += printf("%"PRIu64"ms", ms);
 609        off += printf(" (%"PRIu64")", start);
 610        nr_putchar(max_cpu_num * width-off, '-');
 611        nr_putchar(1, '\n');
 612        /* print each digest entries */
 613        single_digest(start, scale);
 614
 615        start += scale;
 616        ms += delta_ms;
 617    }
 618}
 619
 620/* [min, max) */
 621struct cond_rec {
 622    uint64_t min;
 623    uint64_t max;
 624    uint64_t cnt;
 625    uint64_t res;
 626};
 627
 628void cond_rec_init(struct cond_rec *r, uint64_t min, uint64_t max)
 629{
 630    r->min = min;
 631    r->max = max;
 632    r->cnt = 0;
 633}
 634
 635void cond_rec_inc(uint64_t cur, struct cond_rec *r)
 636{
 637    if (r->min <= cur && cur < r->max) {
 638        r->cnt++;
 639        r->res += cur;
 640    }
 641}
 642
 643/* c	- current cpu to scan
 644 * cx	- cx state to track
 645 * a	- conditonal array
 646 * n	- how many entries there are
 647 */
 648void do_count_per_cpu(int c, int cx, struct cond_rec *a, int n)
 649{
 650    int i;
 651    /* find Cx entry first */
 652    i = 0;
 653    while (i < evt_len[c] && evt[c][i].cx == 0)
 654        i++;
 655    /* check evt[c][i] and evt[c][i+1] */
 656    while (i + 1 < evt_len[c]) {
 657        if (evt[c][i].cx == cx) {
 658            uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
 659            int j;
 660            /* check for each condition */
 661            for (j = 0; j < n; j++)
 662                cond_rec_inc(len, a+j);
 663        }
 664        i++;
 665    }
 666}
 667
 668struct cond_rec *make_cond_rec(uint64_t *a, int n)
 669{
 670    int i;
 671    struct cond_rec *t = malloc(sizeof(struct cond_rec) * (n+1));
 672    if (!t)
 673        return NULL;
 674    for (i = 0; i < n; i++) {
 675        t[i].max = a[i];
 676        t[i+1].min = a[i];
 677        t[i].cnt = 0;
 678        t[i].res = 0;
 679    }
 680    t[0].min = 0;
 681    t[n].max = (uint64_t) -1;
 682    t[n].cnt = 0;
 683    t[n].res = 0;
 684
 685    return t;
 686}
 687
 688uint64_t max_res[MAX_CPU_NR][MAX_CX_NR];
 689uint64_t min_res[MAX_CPU_NR][MAX_CX_NR];
 690uint64_t max_tm[MAX_CPU_NR][MAX_CX_NR];
 691uint64_t min_tm[MAX_CPU_NR][MAX_CX_NR];
 692
 693void do_maxmin_per_cpu(int c)
 694{
 695    int i;
 696    /* find Cx entry first */
 697    i = 0;
 698    while (i < evt_len[c] && evt[c][i].cx == 0)
 699        i++;
 700    /* check evt[c][i] and evt[c][i+1] */
 701    while (i + 1 < evt_len[c]) {
 702        int cx = evt[c][i].cx;
 703        uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
 704        if (len > max_res[c][cx]) {
 705            max_res[c][cx] = len;
 706            max_tm[c][cx] = evt[c][i].tsc;
 707        }
 708        if (len < min_res[c][cx]) {
 709            min_res[c][cx] = len;
 710            min_tm[c][cx] = evt[c][i].tsc;
 711        }
 712        i++;
 713    }
 714}
 715
 716void do_maxmin(void)
 717{
 718    int i, j;
 719    /* init */
 720    for (i = 0; i < max_cpu_num; i++)
 721        for (j = 0; j < max_cx_num; j++) {
 722            max_res[i][j] = 0;
 723            min_res[i][j] = (uint64_t) -1;
 724        }
 725
 726    for (i = 0; i < max_cpu_num; i++)
 727        do_maxmin_per_cpu(i);
 728
 729    for (i = 0; i < max_cpu_num; i++) {
 730        printf("********* CPU%d *********\n", i);
 731        for (j = 0; j < max_cx_num; j++)
 732            if (max_res[i][j] == 0)
 733                printf("     not found                 ");
 734            else
 735                printf("%7"PRIu64"us (%15"PRIu64")    ", max_res[i][j]/tsc2us, max_tm[i][j]);
 736        printf("\n");
 737        for (j = 0; j < max_cx_num; j++)
 738            if (max_res[i][j] == 0)
 739                printf("     not found                 ");
 740            else
 741                printf("%7"PRIu64"us (%15"PRIu64")    ", min_res[i][j]/tsc2us, min_tm[i][j]);
 742        printf("\n\n");
 743    }
 744}
 745
 746void do_count(void)
 747{
 748    uint64_t scale[100] = { 50000UL, 100000UL, 200000UL, 400000UL, 800000UL, 1000000UL };
 749    int a[100];
 750    int scale_len = 6;
 751    int len = 0;
 752    int i, j;
 753
 754    printf("Please input the period:  (Ctrl+D to quit)\n");
 755    printf("The default is 50us, 100us, 200us, 400us, 800us, 1000us.\n(unit is us, you DO NOT need to add us and specify ZERO us and please be in INCREASING order.)\n");
 756    while (scanf("%d", &a[len]) == 1)
 757        len++;
 758    if (len) {
 759        for (i = 0; i < len; i++)
 760            scale[i] = a[i] * tsc2us;
 761        scale_len = len;
 762    }
 763    for (i = 0; i < max_cpu_num; i++) {
 764        struct cond_rec *r[MAX_CX_NR];
 765        uint64_t sum[MAX_CX_NR];
 766        int k;
 767
 768        printf("********** CPU%d *********\n", i);
 769        for (j = 0; j < max_cx_num; j++) {
 770            r[j] = make_cond_rec(scale, scale_len);
 771            if (!r[j])
 772                continue;
 773            do_count_per_cpu(i, j, r[j], scale_len+1);
 774
 775            /* print */
 776            sum[j] = 0;
 777            for (k = 0; k < scale_len+1; k++)
 778                sum[j] += r[j][k].cnt;
 779            if (sum[j] == 0)
 780                sum[j] = 1;
 781        }
 782        printf("                              ");
 783        for (j = 0; j < max_cx_num; j++)
 784            printf("         C%d          ", j);
 785        printf("\n");
 786        for (k = 0; k < scale_len+1; k++) {
 787            if (k == scale_len)
 788                printf("%5"PRIu64" us ->   MAX us:", r[0][k].min/tsc2us);
 789            else
 790                printf("%5"PRIu64" us -> %5"PRIu64" us:",
 791                       r[0][k].min/tsc2us, r[0][k].max/tsc2us);
 792            for (j = 0; j < max_cx_num; j++)
 793                printf("    %10"PRIu64" (%5.2f%%)",
 794                       r[j][k].cnt, 100.0 * (double) r[j][k].cnt / (double)sum[j]);
 795            printf("\n");
 796        }
 797        for (j = 0; j < max_cx_num; j++)
 798            free(r[j]);
 799    }
 800}
 801
 802static void do_px_count_per_cpu(int c, int px, struct cond_rec *cond, int n)
 803{
 804    int i, j;
 805    uint64_t len;
 806
 807    i = 0;
 808    while (i+1 < evt_len[c]) {
 809        if (evt[c][i].px == px) {
 810            len = evt[c][i+1].tsc - evt[c][i].tsc;
 811            /* check each condition */
 812            for (j = 0; j < n; j++)
 813                cond_rec_inc(len, cond+j);
 814        }
 815        i++;
 816    }
 817}
 818
 819void do_px_count(void)
 820{
 821    int a[100];
 822    uint64_t scale[100];
 823    int n, i, c, j;
 824
 825    printf("Please input phases series: (Ctrl+D to quit)\n");
 826    printf("The default is 1, 2, 4, 8, 16, 32.\n");
 827    printf("Please be in increasing order.\n");
 828    scale[0] = tsc2phase;
 829    scale[1] = 2 * tsc2phase;
 830    scale[2] = 4 * tsc2phase;
 831    scale[3] = 8 * tsc2phase;
 832    scale[4] = 16 * tsc2phase;
 833    scale[5] = 32 * tsc2phase;
 834    n = 0;
 835    while (scanf("%d", &a[n]) == 1)
 836        n++;
 837    if (n) {
 838        for (i = 0; i < n; i++)
 839            scale[i] = a[i] * tsc2phase;
 840    } else
 841        n = 6;
 842    for (c = 0; c < max_cpu_num; c++) {
 843        struct cond_rec *p[MAX_PX_NR];
 844        int k;
 845
 846        printf("***** CPU%d *****\n", c);
 847        for (i = 0; i < max_px_num; i++) {
 848            p[i] = make_cond_rec(scale, n);
 849            if (!p[i])
 850                continue;
 851            do_px_count_per_cpu(c, px_freq_table[i], p[i], n+1);
 852        }
 853        /* print */
 854        nr_putchar(16, ' ');
 855        for (j = 0; j < max_px_num; j++)
 856            printf("P%d\t", px_freq_table[j]);
 857        printf("\n");
 858        for (k = 0; k < n+1; k++) {
 859            if (k == n)
 860                printf("%5"PRIu64" ->  MAX : ", p[0][k].min/tsc2phase);
 861            else
 862                printf("%5"PRIu64" -> %5"PRIu64": ",
 863                       p[0][k].min/tsc2phase, p[0][k].max/tsc2phase);
 864            for (j = 0; j < max_px_num; j++) {
 865                printf("%"PRIu64"\t", p[j][k].cnt);
 866            }
 867            printf("\n");
 868        }
 869        printf("---\n");
 870        printf("Count:          ");
 871        for (j = 0; j < max_px_num; j++) {
 872            int sum = 0;
 873            for (k = 0; k < n+1; k++) {
 874                sum += (int)p[j][k].cnt;
 875            }
 876            /* print count */
 877            printf("%d\t", sum);
 878        }
 879        printf("\nAverage:        ");
 880        for (j = 0; j < max_px_num; j++) {
 881            int sum = 0;
 882            int s_res = 0;
 883            for (k = 0; k < n+1; k++) {
 884                sum += (int)p[j][k].cnt;
 885                s_res += (int)(p[j][k].res/tsc2phase);
 886            }
 887            /* print average */
 888            if (sum == 0)
 889                sum = 1;
 890            printf("%.1f\t", (double)s_res/(double)sum);
 891        }
 892        printf("\nTotal:          ");
 893        for (j = 0; j < max_px_num; j++) {
 894            int s_res = 0;
 895            for (k = 0; k < n+1; k++) {
 896                s_res += (int)(p[j][k].res/tsc2phase);
 897            }
 898            /* print total */
 899            printf("%d\t", s_res);
 900        }
 901        printf("\n");
 902    }
 903}
 904
 905void do_breakevents(void)
 906{
 907    int br[MAX_CPU_NR][257];
 908    float pc[MAX_CPU_NR][257];
 909    int i, j, k, l;
 910
 911    memset(br, 0, sizeof(int) * MAX_CPU_NR * 257);
 912    memset(pc, 0, sizeof(int) * MAX_CPU_NR * 257);
 913
 914    for (i = 0; i < max_cpu_num; i++) {
 915        int sum = 0;
 916        for (j = 0; j < evt_len[i]; j++) {
 917            if (evt[i][j].cx == 0) {
 918                /* EXIT */
 919                /* collect breakevents information */
 920                int xx = 0;
 921                for (k = 0; k < 4; k++) {
 922                    int irq = evt[i][j].irqs[k];
 923                    if (irq) {
 924                        br[i][irq]++;
 925                        sum++;
 926                        xx++;
 927                    }
 928                }
 929                if (!xx) {
 930                    br[i][256]++;
 931                    sum++;
 932                }
 933            }
 934        }
 935        for (j = 0; j < 257; j++)
 936            pc[i][j] = 100.0 * br[i][j]/sum;
 937    }
 938    /* print the results */
 939    width = 13;
 940    printf("      ");
 941    for (i = 0; i < max_cpu_num; i++) {
 942        l = 0;
 943        l += printf("CPU%d", i);
 944        nr_putchar(width-l, ' ');
 945    }
 946    printf("\n");
 947
 948    for (j = 0; j < 257; j++) {
 949        int n = 0;
 950        for (i = 0; i < max_cpu_num; i++)
 951            if (br[i][j])
 952                n++;
 953        if (n) {
 954            if (j == 256)
 955                printf("[N/A] ");
 956            else
 957                printf("[%03x] ", j);
 958            for (i = 0; i < max_cpu_num; i++) {
 959                if (br[i][j]) {
 960                    l = 0;
 961                    l += printf("%.1f%%,%d ", pc[i][j], br[i][j]);
 962                    nr_putchar(width-l, ' ');
 963                } else {
 964                    nr_putchar(width, ' ');
 965                }
 966            }
 967            printf("\n");
 968        }
 969    }
 970}
 971
 972void single_cstate(int c, uint64_t t, uint64_t e,
 973                   uint64_t *a,
 974                   uint64_t *max_res,
 975                   uint64_t *min_res,
 976                   uint64_t *num);
 977void do_cstate(uint64_t start, uint64_t end)
 978{
 979    uint64_t cxtime[MAX_CX_NR];
 980    uint64_t max_res[MAX_CX_NR];
 981    uint64_t min_res[MAX_CX_NR];
 982    uint64_t num[MAX_CX_NR];
 983    int i, j;
 984
 985    width = 20;
 986    printf("       ");
 987    for (i = 0; i < max_cx_num; i++) {
 988        int l = printf("C%d", i);
 989        nr_putchar(width-l, ' ');
 990    }
 991    printf("\n");
 992
 993    for (i = 0; i < max_cpu_num; i++) {
 994        uint64_t sum = 0;
 995        single_cstate(i, start, end, cxtime, max_res, min_res, num);
 996        printf("CPU%2d ", i);
 997        for (j = 0; j < max_cx_num; j++)
 998            sum += cxtime[i];
 999        for (j = 0; j < max_cx_num; j++) {
1000            int l = printf("%.1f%%, %"PRIu64".%d, %"PRIu64".%d, %"PRIu64,
1001                           100.0 * cxtime[j]/sum,
1002                           max_res[j]/tsc2ms,
1003                           (unsigned int)(max_res[j]/(tsc2ms/10))%10,
1004                           min_res[j]/tsc2ms,
1005                           (unsigned int)(min_res[j]/(tsc2ms/10))%10,
1006                           cxtime[j]/num[j]/tsc2ms);
1007            nr_putchar(width - l, ' ');
1008        }
1009    }
1010}
1011
1012void single_cstate(int c, uint64_t t, uint64_t e,
1013                   uint64_t *a,
1014                   uint64_t *max_res,
1015                   uint64_t *min_res,
1016                   uint64_t *num)
1017{
1018    int cx;
1019    int i;
1020    int first = 1;
1021
1022    for (i = 0; i < max_cx_num; i++) {
1023        a[i] = 0;
1024        max_res[i] = 0;
1025        min_res[i] = (uint64_t) -1;
1026        num[i] = 0;
1027    }
1028
1029    cx = determine_cx(c, t);
1030    i = 0;
1031    while (i < evt_len[c] && evt[c][i].tsc <= t)
1032        i++;
1033    for (; i+1 < evt_len[c] && evt[c][i].tsc <= e; i++) {
1034        int cxidx = evt[c][i].cx;
1035        uint64_t delta;
1036
1037        if (first && cx >= 0) {
1038            /* Partial Cx, only once */
1039            first = 0;
1040
1041            cxidx = cx;
1042            delta = evt[c][i].tsc - max(evt[c][i-1].tsc, t);
1043            a[cxidx] += delta;
1044            num[cxidx]++;
1045
1046            /* update min and max residency */
1047            if (delta > max_res[cxidx])
1048                max_res[cxidx] = delta;
1049            if (delta < min_res[cxidx])
1050                min_res[cxidx] = delta;
1051        }
1052        delta = evt[c][i+1].tsc - evt[c][i].tsc;
1053        a[cxidx] += delta;
1054        num[cxidx]++;
1055
1056        /* update min and max residency */
1057        if (delta > max_res[cxidx])
1058            max_res[cxidx] = delta;
1059        if (delta < min_res[cxidx])
1060            min_res[cxidx] = delta;
1061    }
1062}
1063
1064void do_average_per_cpu(int c)
1065{
1066    int i;
1067    uint64_t tot[MAX_CX_NR] = { 0 };
1068    uint64_t cnt[MAX_CX_NR] = { 0 };
1069    uint64_t sum = 0;
1070
1071    /* find Cx entry first */
1072    i = 0;
1073    while (i < evt_len[c] && evt[c][i].cx == 0)
1074        i++;
1075    /* check evt[c][i] and evt[c][i+1] */
1076    while (i + 1 < evt_len[c]) {
1077        uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
1078        int cx = evt[c][i].cx;
1079        tot[cx] += len;
1080        cnt[cx]++;
1081        sum += len;
1082        i++;
1083    }
1084    /* prevent divide zero error */
1085    if (!sum)
1086        sum = 1;
1087    /* print */
1088    printf("CPU%d:\tResidency(ms)\t\tAvg Res(ms)\n", c);
1089    for (i = 0; i < max_cx_num; i++) {
1090        /* prevent divide zero error */
1091        if (!cnt[i])
1092            cnt[i] = 1;
1093        printf("  C%d\t%"PRIu64"\t(%6.2f%%)\t%.2f\n", i,
1094               tot[i]/tsc2ms, 100.0 * tot[i] / (double)sum,
1095               (double)tot[i]/cnt[i]/tsc2ms );
1096    }
1097    printf("\n");
1098}
1099
1100void do_average(void)
1101{
1102    int i;
1103
1104    for (i = 0; i < max_cpu_num; i++)
1105        do_average_per_cpu(i);
1106}
1107
1108static void do_exp_ratio_per_cpu(int c)
1109{
1110    int i;
1111    uint64_t expected[MAX_CX_NR] = { 0 }, sum[MAX_CX_NR] = { 0 };
1112
1113    i = 0;
1114    while (i < evt_len[c] && evt[c][i].cx == 0)
1115        i++;
1116    /* check evt[c][i] and evt[c][i+1] */
1117    while (i + 1 < evt_len[c]) {
1118        uint64_t len;
1119        int cx;
1120
1121        if ((evt[c][i].cx == 0 && evt[c][i+1].cx == 0) ||
1122            (evt[c][i].cx > 0 && evt[c][i+1].cx > 0)) {
1123            i++;
1124            continue;
1125        }
1126        len = evt[c][i+1].tsc - evt[c][i].tsc;
1127        cx = evt[c][i].cx;
1128        if (cx > 0) {
1129            if ((len/tsc2us) <= evt[c][i].expected)
1130                expected[cx]++;
1131            sum[cx]++;
1132        }
1133
1134        i++;
1135    }
1136    printf("********** CPU%d **********\n", c);
1137    for (i = 1; i < max_cx_num; i++) {
1138        if (sum[i] == 0)
1139            printf("C%d\t0\t0\t00.00%%\n", i);
1140        else
1141            printf("C%d\t%"PRIu64"\t%"PRIu64"\t%4.2f%%\n",
1142                   i, expected[i], sum[i], 100.0 * (double)expected[i]/(double)sum[i]);
1143    }
1144}
1145
1146void do_exp_ratio(void)
1147{
1148    int i;
1149
1150    if (!is_menu_gov_enabled) {
1151        printf("The file seems doesn't consists the expected/predicted information.\n");
1152        return;
1153    }
1154
1155    printf("Cx\tearly\ttot\tratio(%%)\n");
1156    for (i = 0; i < max_cpu_num; i++)
1157        do_exp_ratio_per_cpu(i);
1158}
1159
1160static void do_exp_pred_per_cpu(int c)
1161{
1162    int i;
1163    uint64_t expected[MAX_CX_NR] = { 0 }, sum[MAX_CX_NR] = { 0 };
1164
1165    i = 0;
1166    while (i < evt_len[c] && evt[c][i].cx == 0)
1167        i++;
1168    /* check evt[c][i] and evt[c][i+1] */
1169    while (i + 1 < evt_len[c]) {
1170        int cx;
1171
1172        if ((evt[c][i].cx == 0 && evt[c][i+1].cx == 0) ||
1173            (evt[c][i].cx > 0 && evt[c][i+1].cx > 0)) {
1174            i++;
1175            continue;
1176        }
1177        cx = evt[c][i].cx;
1178        if (cx > 0) {
1179            if (evt[c][i].expected <= evt[c][i].predicted)
1180                expected[cx]++;
1181            sum[cx]++;
1182        }
1183
1184        i++;
1185    }
1186    printf("********** CPU%d **********\n", c);
1187    for (i = 1; i < max_cx_num; i++) {
1188        if (sum[i] == 0)
1189            printf("C%d\t0\t0\t00.00%%\n", i);
1190        else
1191            printf("C%d\t%"PRIu64"\t%"PRIu64"\t%4.2f%%\n",
1192                   i, expected[i], sum[i], 100.0 * (double)expected[i]/(double)sum[i]);
1193    }
1194}
1195
1196void do_exp_pred(void)
1197{
1198    int i;
1199
1200    if (!is_menu_gov_enabled) {
1201        printf("The file seems doesn't consists the expected/predicted information.\n");
1202        return;
1203    }
1204
1205    printf("Cx\texp\ttot\tratio(%%)\n");
1206    for (i = 0; i < max_cpu_num; i++)
1207        do_exp_pred_per_cpu(i);
1208}
1209