[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86 Cx tracing: adds gtraceview & gtracestat utilities



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1246269804 -3600
# Node ID 388578e1626e78f50b1d9ca377ba38d592610cc1
# Parent  41317562d3329826ad1fadca16b519af335e7e72
x86 Cx tracing: adds gtraceview & gtracestat utilities

Signed-off-by: Lu Guanqun <guanqun.lu@xxxxxxxxx>
---
 .hgignore               |    2 
 tools/misc/Makefile     |    9 
 tools/misc/gtracestat.c | 1209 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/misc/gtraceview.c | 1103 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2320 insertions(+), 3 deletions(-)

diff -r 41317562d332 -r 388578e1626e .hgignore
--- a/.hgignore Mon Jun 29 11:01:50 2009 +0100
+++ b/.hgignore Mon Jun 29 11:03:24 2009 +0100
@@ -197,6 +197,8 @@
 ^tools/misc/xen-tmem-list-parse$
 ^tools/misc/xenperf$
 ^tools/misc/xenpm$
+^tools/misc/gtraceview$
+^tools/misc/gtracestat$
 ^tools/pygrub/build/.*$
 ^tools/python/build/.*$
 ^tools/python/xen/util/path\.py$
diff -r 41317562d332 -r 388578e1626e tools/misc/Makefile
--- a/tools/misc/Makefile       Mon Jun 29 11:01:50 2009 +0100
+++ b/tools/misc/Makefile       Mon Jun 29 11:03:24 2009 +0100
@@ -10,7 +10,7 @@ CFLAGS   += $(INCLUDES)
 
 HDRS     = $(wildcard *.h)
 
-TARGETS-y := xenperf xenpm xen-tmem-list-parse
+TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat
 TARGETS-$(CONFIG_X86) += xen-detect
 TARGETS := $(TARGETS-y)
 
@@ -22,7 +22,7 @@ INSTALL_BIN-$(CONFIG_X86) += xen-detect
 INSTALL_BIN-$(CONFIG_X86) += xen-detect
 INSTALL_BIN := $(INSTALL_BIN-y)
 
-INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm 
xen-tmem-list-parse
+INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm 
xen-tmem-list-parse gtraceview gtracestat
 INSTALL_SBIN := $(INSTALL_SBIN-y)
 
 DEFAULT_PYTHON_PATH := $(shell $(XEN_ROOT)/tools/python/get-path)
@@ -53,7 +53,10 @@ clean:
 %.o: %.c $(HDRS) Makefile
        $(CC) -c $(CFLAGS) -o $@ $<
 
-xenperf xenpm: %: %.o Makefile
+xenperf xenpm gtracestat: %: %.o Makefile
        $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDFLAGS_libxenctrl)
 
+gtraceview: %: %.o Makefile
+       $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -lncurses
+
 -include $(DEPS)
diff -r 41317562d332 -r 388578e1626e tools/misc/gtracestat.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/misc/gtracestat.c   Mon Jun 29 11:03:24 2009 +0100
@@ -0,0 +1,1209 @@
+/*
+ * gtracestat.c: list the statistics information for a dumped xentrace file.
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <xenctrl.h>
+#include <xen/trace.h>
+
+#define CHECK_DUP_CX 0
+
+/********** MACROS **********/
+#define MAX_CPU_NR  32
+#define MAX_CX_NR   8
+#define MAX_MODE_NR 16
+#define MAX_PX_NR      100
+
+/* simplified xentrace record */
+struct rec {
+    uint64_t tsc;
+    int cpu;
+    unsigned char cx;
+    unsigned char irqs[4];
+    unsigned int predicted;
+    unsigned int expected;
+    int px;
+};
+
+/********** FORWARD DECLARATION **********/
+void show_help(void);
+void show_version(void);
+int load_file(char *fname);
+void do_digest(uint64_t start, uint64_t end, uint64_t scale);
+void do_breakevents(void);
+void do_count(void);
+void do_px_count(void);
+void do_maxmin(void);
+void do_average(void);
+void do_cstate(uint64_t start, uint64_t end);
+void do_exp_ratio(void);
+void do_exp_pred(void);
+
+/********** GLOBAL VARIABLES **********/
+/* store simplified xentrace data */
+struct rec *data;
+int64_t data_nr, data_cur;
+/* store max cx state number and cpu number */
+int max_cx_num = -1, max_cpu_num = -1;
+int px_freq_table[MAX_PX_NR];
+int max_px_num = 0;
+
+int is_menu_gov_enabled = 0;
+
+/* user specified translation unit */
+uint64_t tsc2ms = 2793000UL;
+uint64_t tsc2us = 2793UL;
+uint64_t tsc2phase = 55800000UL;
+
+/* each cpu column width */
+int width = 0;
+
+/* digest mode variables */
+struct rec *evt[MAX_CPU_NR];
+int evt_len[MAX_CPU_NR];
+
+/* hand-crafted min() */
+static inline uint64_t min(uint64_t a, uint64_t b)
+{
+    return a < b ? a : b;
+}
+static inline uint64_t max(uint64_t a, uint64_t b)
+{
+    return a > b ? a : b;
+}
+
+int is_px = 0;
+
+int main(int argc, char *argv[])
+{
+    char *fname = NULL;
+    /* operation flags */
+    int is_breakevents = 0;
+    int is_count = 0;
+    int is_maxmin = 0;
+    int is_average = 0;
+    int is_digest = 0;
+    int is_exp_ratio = 0;
+    int is_exp = 0;
+    uint64_t start_time = 0;
+    uint64_t time_scale = 0;
+    uint64_t end_time = 0;
+
+    struct option  long_options [] = {
+        /* short options are listed correspondingly */
+        { "version", 0, NULL, 'v' },
+        { "help", 0, NULL, 'h' },
+        /* list Cx entires one by one */
+        { "digest", 0, NULL, 'd' },
+        /* ignored when digest is disabled */
+        { "start", 1, NULL, 's' },
+        { "end", 1, NULL, 'e' },
+        { "scale", 1, NULL, 'l' },
+        /* give summary about breakevents info */
+        { "breakevents", 0, NULL, 'b' },
+        { "count", 0, NULL, 'c' },
+        { "average", 0, NULL, 'a' },
+        /* list max/min residency for each Cx */
+        { "maxmin", 0, NULL, 'm' },
+        { "tsc2us", 1, NULL, 'u' },
+        { "px", 0, NULL, 'p' },
+        { "tsc2phase", 1, NULL, 'n' },
+        { "exp-ratio", 0, NULL, 'z' },
+        { "exp-pred", 0, NULL, 'x' },
+        { NULL, 0, NULL, 0 },
+    };
+
+    while (1) {
+        int ch, opt_idx;
+        ch = getopt_long(argc, argv, "vhds:e:l:bcmaupnzx",
+                         long_options, &opt_idx);
+        if (ch == -1)
+            break;
+        switch (ch) {
+        case 'v':
+            show_version();
+            exit(EXIT_SUCCESS);
+        case 'h':
+            show_help();
+            exit(EXIT_SUCCESS);
+        case 'p':
+            is_px = 1;
+            break;
+        case 'x':
+            is_exp = 1;
+            break;
+        case 'z':
+            is_exp_ratio = 1;
+            break;
+        case 'n':
+            tsc2phase = atoll(optarg);
+            if (tsc2phase <= 0)
+                tsc2phase = 55800000UL;
+        case 'd':
+            is_digest = 1;
+            break;
+        case 's':
+            start_time = atoll(optarg);
+            break;
+        case 'e':
+            end_time = atoll(optarg);
+            break;
+        case 'l':
+            time_scale = atoll(optarg);
+            break;
+        case 'b':
+            is_breakevents = 1;
+            break;
+        case 'c':
+            is_count = 1;
+            break;
+        case 'm':
+            is_maxmin = 1;
+            break;
+        case 'a':
+            is_average = 1;
+            break;
+        case 'u':
+            tsc2us = atoll(optarg);
+            tsc2ms = tsc2us * 1000UL;
+            break;
+        case '?':
+        default:
+            show_help();
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (argc - optind > 1) {
+        printf("Multiple file specified?\n");
+        show_help();
+        exit(EXIT_FAILURE);
+    }
+    fname = argv[optind];
+
+    if (load_file(fname))
+        exit(EXIT_FAILURE);
+
+    width = 10;
+    if (is_digest) {
+        /* if people not specify the time related number,
+         * use the default one from the record.
+         */
+        if (!start_time)
+            start_time = data[0].tsc;
+        if (!end_time)
+            end_time = data[data_cur-1].tsc;
+        if (!time_scale)
+            time_scale = 10UL * tsc2ms;        /* default: 10 ms */
+        do_digest(start_time, end_time, time_scale);
+    }
+
+    if (is_breakevents)
+        do_breakevents();
+
+    if (is_count && !is_px)
+        do_count();
+    if (is_count && is_px)
+        do_px_count();
+
+    if (is_maxmin)
+        do_maxmin();
+
+    if (is_average)
+        do_average();
+
+    if (is_exp_ratio)
+        do_exp_ratio();
+
+    if (is_exp)
+        do_exp_pred();
+
+    exit(EXIT_SUCCESS);
+}
+
+/* used for qsort() */
+/* sort by cpu first, then by tsc */
+static int data_cmp(const void *_a, const void *_b)
+{
+    struct rec *a = (struct rec *)_a;
+    struct rec *b = (struct rec *)_b;
+    if (a->cpu == b->cpu)
+        return a->tsc > b->tsc ? 1 : -1;
+    return a->cpu > b->cpu ? 1 : -1;
+}
+
+/* load file and make them a list of records
+ * update these following variables:
+ *   data, data_cur, data_nr
+ *   max_cpu_num, max_cx_num
+ */
+#define LIST_PX 0
+int load_file(char *fname)
+{
+    /* file descriptor for raw xentrace file */
+    int fd;
+    /* current cpu during xentrace data parse */
+    int cur_cpu = -1;
+    int i;
+
+    fd = open(fname, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "file %s cannot open\n", fname);
+        return 1;
+    }
+
+    /* the initial number is 1024,
+     * and when it overflows, this number doubles.
+     */
+    data_nr = 1024;
+    data_cur = 0;
+    data = malloc(sizeof(struct rec) * data_nr);
+    if (!data) {
+        fprintf(stderr, "not enough memory\n");
+        close(fd);
+        return 1;
+    }
+
+    while (1) {
+        struct t_rec rec;
+        ssize_t ret, size;
+
+        ret = read(fd, &rec, sizeof(uint32_t));
+        if (!ret)
+            break;
+        if (ret != sizeof(uint32_t)) {
+            fprintf(stderr, "reading header error\n");
+            break;
+        }
+
+        size = 0;
+        if (rec.cycles_included)
+            size += sizeof(uint64_t);
+        size += sizeof(uint32_t) * rec.extra_u32;
+
+        ret = read(fd, (char *)&rec + sizeof(uint32_t), size);
+        if (!ret && size)
+            break;
+        if (ret != size) {
+            fprintf(stderr, "reading data error\n");
+            break;
+        }
+
+        if (rec.event == 0x1f003) {
+            /* cpu change event */
+            cur_cpu = 0;
+            if (rec.extra_u32 > 0)
+                cur_cpu = rec.u.nocycles.extra_u32[0];
+            continue;
+        } else if (!rec.cycles_included ||
+                   (rec.event != TRC_PM_IDLE_ENTRY &&
+                    rec.event != TRC_PM_IDLE_EXIT &&
+                    rec.event != TRC_PM_FREQ_CHANGE)) {
+            /* we care about only idle events now */
+            continue;
+        }
+
+        /* add one record */
+        if (data_cur == data_nr) {
+            data_nr <<= 1;
+            if (data_nr < 0) {
+                fprintf(stderr, "too many entries\n");
+                close(fd);
+                return 1;
+            }
+            data = realloc(data, sizeof(struct rec) * data_nr);
+            if (!data) {
+                fprintf(stderr, "not enough memory\n");
+                close(fd);
+                return 1;
+            }
+        }
+        data[data_cur].tsc = rec.u.cycles.cycles_hi;
+        data[data_cur].tsc <<= 32;
+        data[data_cur].tsc |= rec.u.cycles.cycles_lo;
+        data[data_cur].cpu = cur_cpu;
+        if (is_px) {
+            if (rec.event != TRC_PM_FREQ_CHANGE)
+                continue;
+            /* FREQ_CHANGE */
+            if (rec.u.cycles.extra_u32[0] ==
+                rec.u.cycles.extra_u32[1])
+                continue;
+            data[data_cur].px = rec.u.cycles.extra_u32[1];
+            for (i = 0; i < max_px_num; i++)
+                if (px_freq_table[i] == data[data_cur].px)
+                    break;
+            if (i == max_px_num)
+                px_freq_table[max_px_num++] = data[data_cur].px;
+        } else {
+            if (rec.event == TRC_PM_IDLE_ENTRY) {
+                data[data_cur].cx = rec.u.cycles.extra_u32[0];
+                if (rec.extra_u32 >= 4) {
+                    data[data_cur].expected = rec.u.cycles.extra_u32[2];
+                    data[data_cur].predicted = rec.u.cycles.extra_u32[3];
+                    is_menu_gov_enabled = 1;
+                } else
+                    is_menu_gov_enabled = 0;
+            } else if (rec.event == TRC_PM_IDLE_EXIT) {
+                /* IDLE_EXIT default to C0 */
+                data[data_cur].cx = 0;
+                /* store the reasons why it exits */
+                data[data_cur].irqs[0] = rec.u.cycles.extra_u32[2];
+                data[data_cur].irqs[1] = rec.u.cycles.extra_u32[3];
+                data[data_cur].irqs[2] = rec.u.cycles.extra_u32[4];
+                data[data_cur].irqs[3] = rec.u.cycles.extra_u32[5];
+            } else
+                continue;
+            /* update max info */
+            if (data[data_cur].cx > max_cx_num)
+                max_cx_num = data[data_cur].cx;
+        }
+
+        if (data[data_cur].cpu > max_cpu_num)
+            max_cpu_num = data[data_cur].cpu;
+
+        data_cur++;
+    }
+    close(fd);
+
+    /* sort data array according to TSC time line */
+    qsort(data, data_cur, sizeof(struct rec), data_cmp);
+
+    max_cpu_num++;
+    max_cx_num++;
+
+    for (i = 0; i < max_cpu_num; i++) {
+        evt_len[i] = 0;
+        evt[i] = NULL;
+    }
+    for (i = data_cur-1; i >= 0; i--) {
+        evt[data[i].cpu] = data+i;
+        evt_len[data[i].cpu]++;
+    }
+#if CHECK_DUP_CX
+    int xx, yy;
+    int err = 0;
+    printf("Checking %s...\n", fname);
+    for (xx = 0; xx < max_cpu_num; xx++) {
+        //     printf("............ CPU %d .............\n", xx);
+        for (yy = 0; yy+1 < evt_len[xx]; yy++)
+            if ( evt[xx][yy].cx > 0 && evt[xx][yy+1].cx > 0) {
+                printf("same witht next one %"PRIu64" %d %d\n",
+                       evt[xx][yy].tsc, evt[xx][yy].cpu, evt[xx][yy].cx);
+                err++;
+            }
+    }
+    exit(err);
+#endif
+#if LIST_PX
+    int x, y;
+    for (x = 0; x < max_cpu_num; x++) {
+        printf("CPU%d**************************************\n", x);
+        for (y = 0; y+1 < evt_len[x]; y++) {
+            printf("[%dHz]: phase: %d\n",
+                   evt[x][y].px,
+                   (int)((evt[x][y+1].tsc - evt[x][y].tsc)/tsc2phase));
+        }
+    }
+#endif
+    return 0;
+}
+
+void show_version(void)
+{
+    printf("gtracestat - (C) 2009 Intel Corporation\n");
+}
+
+void show_help(void)
+{
+    show_version();
+    printf("tracestat <trace.data> [-vhdselbcmau]\n");
+    printf("  trace.data       raw data from xentrace\n");
+    printf("  -v / --version   show version message\n");
+    printf("  -h / --help      show this message\n");
+    printf("  -d / --digest    digest mode, more variables to specify.\n");
+    printf("  -s / --start <start_time> specify start time (only in digest 
mode)\n");
+    printf("  -e / --end <end_time>     specify end time (only in digest 
mode)\n");
+    printf("  -l / --scale <scale>      specify time scale (only in digest 
mode)\n");
+    printf("  -b / --breakevents give breakevents summary info\n");
+    printf("  -c / --count       give count summary info\n");
+    printf("  -a / --average     give total/average residency info\n");
+    printf("  -m / --maxmin      show man/min residency summary info\n");
+    printf("  -u / --tsc2us      specify how many tsc is a us unit\n");
+    printf("  -p / --px          operate on Px entries\n");
+    printf("  -n / --tsc2phase   specify how many tsc is a phase unit (only in 
px)\n");
+    printf("  -z / --exp-ratio   show the ratio of early break events\n");
+    printf("  -x / --exp-pred    show the ratio of expected / predicted in Cx 
entry\n");
+}
+
+static inline int len_of_number(uint64_t n)
+{
+    int l = 0;
+    do {
+        l++;
+        n /= 10;
+    } while (n);
+    return l;
+}
+
+/* determine the cx at time t
+ * take advantage of evt and evt_len.
+ */
+int determine_cx(int c, uint64_t t)
+{
+    int i;
+
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].tsc <= t)
+        i++;
+    /* if there are any events happening,
+     * it must be in a Cx state now.
+     */
+    if (i)
+        return evt[c][i-1].cx;
+    /* look forward to see whether it will enter
+     * a Cx state, if so, it must be in C0 state.
+     * we can't determine a Cx state from exit event.
+     */
+    if (i < evt_len[c] && evt[c][i].cx > 0)
+        return 0;
+    return -1;
+}
+
+/* c - cpu
+ * t - start time
+ * s - scale
+ * cx_i - number of cx index
+ * cx_r - residency of each cx entry
+ */
+int process(int c, uint64_t t, uint64_t s, int *cx_i, uint64_t *cx_r)
+{
+    int cx;
+    uint64_t len;
+    int i, n;
+
+    cx = determine_cx(c, t);
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].tsc < t)
+        i++;
+    n = 0;
+    if (cx >= 0 && i < evt_len[c]) {
+        cx_i[n] = cx;
+        cx_r[n] = evt[c][i].tsc - t;
+        if (cx_r[n])
+            n++;
+    }
+    while (i < evt_len[c] && evt[c][i].tsc < t+s) {
+        /* we are now at [t, t+s) */
+        cx = evt[c][i].cx;
+        len = min((i+1 < evt_len[c] ? evt[c][i+1].tsc : t+s), t+s)
+            - evt[c][i].tsc;
+
+        cx_i[n] = cx;
+        cx_r[n] = len;
+        n++;
+
+        i++;
+    }
+
+    return n;
+}
+
+void nr_putchar(int nr, int ch)
+{
+    int i;
+    for (i = 0; i < nr; i++)
+        putchar(ch);
+}
+
+#define MAX_INTERVAL_ENTRY     1000
+/* process period [start_time, start_time + time_scale) */
+void single_digest(uint64_t start_time, uint64_t time_scale)
+{
+    int cpu;
+    int cx_i[MAX_CPU_NR][MAX_INTERVAL_ENTRY];
+    uint64_t cx_r[MAX_CPU_NR][MAX_INTERVAL_ENTRY];
+    int cx_n[MAX_CPU_NR];
+    int max_n;
+
+    memset(cx_i, 0, sizeof(int) * MAX_CPU_NR * MAX_INTERVAL_ENTRY);
+    memset(cx_r, 0, sizeof(uint64_t) * MAX_CPU_NR * MAX_INTERVAL_ENTRY);
+    memset(cx_n, 0, sizeof(int) * MAX_CPU_NR);
+
+    max_n = 0;
+    for (cpu = 0; cpu < max_cpu_num; cpu++) {
+        cx_n[cpu] = process(cpu, start_time, time_scale, cx_i[cpu], cx_r[cpu]);
+        if (cx_n[cpu] > max_n)
+            max_n = cx_n[cpu];
+    }
+
+    /* means how many lines will be consumed */
+    while (--max_n >= 0) {
+        for (cpu = 0; cpu < max_cpu_num; cpu++) {
+            if (cx_n[cpu] > 0) {
+                int i;
+                /* find the available cx index */
+                for (i = 0; i < MAX_INTERVAL_ENTRY && cx_i[cpu][i] == -1; i++)
+                    ;
+                if (i < MAX_INTERVAL_ENTRY) {
+                    int len;
+                    /* print it */
+                    len= printf("C%d,%"PRIu64".%d", cx_i[cpu][i],
+                                cx_r[cpu][i]/tsc2ms,
+                                (unsigned int)(cx_r[cpu][i]/(tsc2ms/10))%10);
+                    nr_putchar(width-len, ' ');
+
+                    cx_i[cpu][i] = -1;
+                } else
+                    nr_putchar(width, ' ');
+
+                cx_n[cpu]--;
+            } else
+                nr_putchar(width, ' ');
+        }
+        nr_putchar(1, '\n');
+    }
+}
+
+void do_digest(uint64_t start, uint64_t end, uint64_t scale)
+{
+    int i;
+    uint64_t ms = 0;
+    uint64_t delta_ms = scale / tsc2ms;
+
+    for (i = 0; i < max_cpu_num; i++) {
+        int len = 0;
+        len = printf("CPU%d", i);
+        nr_putchar(width-len, ' ');
+    }
+    nr_putchar(1, '\n');
+    while (start < end) {
+        /* print --- xxx ms --- line */
+        int off = (max_cpu_num * width - len_of_number(ms) - 2)/2;
+        nr_putchar(off, '-');
+        off += printf("%"PRIu64"ms", ms);
+        off += printf(" (%"PRIu64")", start);
+        nr_putchar(max_cpu_num * width-off, '-');
+        nr_putchar(1, '\n');
+        /* print each digest entries */
+        single_digest(start, scale);
+
+        start += scale;
+        ms += delta_ms;
+    }
+}
+
+/* [min, max) */
+struct cond_rec {
+    uint64_t min;
+    uint64_t max;
+    uint64_t cnt;
+    uint64_t res;
+};
+
+void cond_rec_init(struct cond_rec *r, uint64_t min, uint64_t max)
+{
+    r->min = min;
+    r->max = max;
+    r->cnt = 0;
+}
+
+void cond_rec_inc(uint64_t cur, struct cond_rec *r)
+{
+    if (r->min <= cur && cur < r->max) {
+        r->cnt++;
+        r->res += cur;
+    }
+}
+
+/* c   - current cpu to scan
+ * cx  - cx state to track
+ * a   - conditonal array
+ * n   - how many entries there are
+ */
+void do_count_per_cpu(int c, int cx, struct cond_rec *a, int n)
+{
+    int i;
+    /* find Cx entry first */
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].cx == 0)
+        i++;
+    /* check evt[c][i] and evt[c][i+1] */
+    while (i + 1 < evt_len[c]) {
+        if (evt[c][i].cx == cx) {
+            uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
+            int j;
+            /* check for each condition */
+            for (j = 0; j < n; j++)
+                cond_rec_inc(len, a+j);
+        }
+        i++;
+    }
+}
+
+struct cond_rec *make_cond_rec(uint64_t *a, int n)
+{
+    int i;
+    struct cond_rec *t = malloc(sizeof(struct cond_rec) * (n+1));
+    if (!t)
+        return NULL;
+    for (i = 0; i < n; i++) {
+        t[i].max = a[i];
+        t[i+1].min = a[i];
+        t[i].cnt = 0;
+        t[i].res = 0;
+    }
+    t[0].min = 0;
+    t[n].max = (uint64_t) -1;
+    t[n].cnt = 0;
+    t[n].res = 0;
+
+    return t;
+}
+
+uint64_t max_res[MAX_CPU_NR][MAX_CX_NR];
+uint64_t min_res[MAX_CPU_NR][MAX_CX_NR];
+uint64_t max_tm[MAX_CPU_NR][MAX_CX_NR];
+uint64_t min_tm[MAX_CPU_NR][MAX_CX_NR];
+
+void do_maxmin_per_cpu(int c)
+{
+    int i;
+    /* find Cx entry first */
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].cx == 0)
+        i++;
+    /* check evt[c][i] and evt[c][i+1] */
+    while (i + 1 < evt_len[c]) {
+        int cx = evt[c][i].cx;
+        uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
+        if (len > max_res[c][cx]) {
+            max_res[c][cx] = len;
+            max_tm[c][cx] = evt[c][i].tsc;
+        }
+        if (len < min_res[c][cx]) {
+            min_res[c][cx] = len;
+            min_tm[c][cx] = evt[c][i].tsc;
+        }
+        i++;
+    }
+}
+
+void do_maxmin(void)
+{
+    int i, j;
+    /* init */
+    for (i = 0; i < max_cpu_num; i++)
+        for (j = 0; j < max_cx_num; j++) {
+            max_res[i][j] = 0;
+            min_res[i][j] = (uint64_t) -1;
+        }
+
+    for (i = 0; i < max_cpu_num; i++)
+        do_maxmin_per_cpu(i);
+
+    for (i = 0; i < max_cpu_num; i++) {
+        printf("********* CPU%d *********\n", i);
+        for (j = 0; j < max_cx_num; j++)
+            if (max_res[i][j] == 0)
+                printf("     not found                 ");
+            else
+                printf("%7"PRIu64"us (%15"PRIu64")    ", max_res[i][j]/tsc2us, 
max_tm[i][j]);
+        printf("\n");
+        for (j = 0; j < max_cx_num; j++)
+            if (max_res[i][j] == 0)
+                printf("     not found                 ");
+            else
+                printf("%7"PRIu64"us (%15"PRIu64")    ", min_res[i][j]/tsc2us, 
min_tm[i][j]);
+        printf("\n\n");
+    }
+}
+
+void do_count(void)
+{
+    uint64_t scale[100] = { 50000UL, 100000UL, 200000UL, 400000UL, 800000UL, 
1000000UL };
+    int a[100];
+    int scale_len = 6;
+    int len = 0;
+    int i, j;
+
+    printf("Please input the period:  (Ctrl+D to quit)\n");
+    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");
+    while (scanf("%d", &a[len]) == 1)
+        len++;
+    if (len) {
+        for (i = 0; i < len; i++)
+            scale[i] = a[i] * tsc2us;
+        scale_len = len;
+    }
+    for (i = 0; i < max_cpu_num; i++) {
+        struct cond_rec *r[MAX_CX_NR];
+        uint64_t sum[MAX_CX_NR];
+        int k;
+
+        printf("********** CPU%d *********\n", i);
+        for (j = 0; j < max_cx_num; j++) {
+            r[j] = make_cond_rec(scale, scale_len);
+            if (!r[j])
+                continue;
+            do_count_per_cpu(i, j, r[j], scale_len+1);
+
+            /* print */
+            sum[j] = 0;
+            for (k = 0; k < scale_len+1; k++)
+                sum[j] += r[j][k].cnt;
+            if (sum[j] == 0)
+                sum[j] = 1;
+        }
+        printf("                              ");
+        for (j = 0; j < max_cx_num; j++)
+            printf("         C%d          ", j);
+        printf("\n");
+        for (k = 0; k < scale_len+1; k++) {
+            if (k == scale_len)
+                printf("%5"PRIu64" us ->   MAX us:", r[0][k].min/tsc2us);
+            else
+                printf("%5"PRIu64" us -> %5"PRIu64" us:",
+                       r[0][k].min/tsc2us, r[0][k].max/tsc2us);
+            for (j = 0; j < max_cx_num; j++)
+                printf("    %10"PRIu64" (%5.2f%%)",
+                       r[j][k].cnt, 100.0 * (double) r[j][k].cnt / 
(double)sum[j]);
+            printf("\n");
+        }
+        for (j = 0; j < max_cx_num; j++)
+            free(r[j]);
+    }
+}
+
+static void do_px_count_per_cpu(int c, int px, struct cond_rec *cond, int n)
+{
+    int i, j;
+    uint64_t len;
+
+    i = 0;
+    while (i+1 < evt_len[c]) {
+        if (evt[c][i].px == px) {
+            len = evt[c][i+1].tsc - evt[c][i].tsc;
+            /* check each condition */
+            for (j = 0; j < n; j++)
+                cond_rec_inc(len, cond+j);
+        }
+        i++;
+    }
+}
+
+void do_px_count(void)
+{
+    int a[100];
+    uint64_t scale[100];
+    int n, i, c, j;
+
+    printf("Please input phases series: (Ctrl+D to quit)\n");
+    printf("The default is 1, 2, 4, 8, 16, 32.\n");
+    printf("Please be in increasing order.\n");
+    scale[0] = tsc2phase;
+    scale[1] = 2 * tsc2phase;
+    scale[2] = 4 * tsc2phase;
+    scale[3] = 8 * tsc2phase;
+    scale[4] = 16 * tsc2phase;
+    scale[5] = 32 * tsc2phase;
+    n = 0;
+    while (scanf("%d", &a[n]) == 1)
+        n++;
+    if (n) {
+        for (i = 0; i < n; i++)
+            scale[i] = a[i] * tsc2phase;
+    } else
+        n = 6;
+    for (c = 0; c < max_cpu_num; c++) {
+        struct cond_rec *p[MAX_PX_NR];
+        int k;
+
+        printf("***** CPU%d *****\n", c);
+        for (i = 0; i < max_px_num; i++) {
+            p[i] = make_cond_rec(scale, n);
+            if (!p[i])
+                continue;
+            do_px_count_per_cpu(c, px_freq_table[i], p[i], n+1);
+        }
+        /* print */
+        nr_putchar(16, ' ');
+        for (j = 0; j < max_px_num; j++)
+            printf("P%d\t", px_freq_table[j]);
+        printf("\n");
+        for (k = 0; k < n+1; k++) {
+            if (k == n)
+                printf("%5"PRIu64" ->  MAX : ", p[0][k].min/tsc2phase);
+            else
+                printf("%5"PRIu64" -> %5"PRIu64": ",
+                       p[0][k].min/tsc2phase, p[0][k].max/tsc2phase);
+            for (j = 0; j < max_px_num; j++) {
+                printf("%"PRIu64"\t", p[j][k].cnt);
+            }
+            printf("\n");
+        }
+        printf("---\n");
+        printf("Count:          ");
+        for (j = 0; j < max_px_num; j++) {
+            int sum = 0;
+            for (k = 0; k < n+1; k++) {
+                sum += (int)p[j][k].cnt;
+            }
+            /* print count */
+            printf("%d\t", sum);
+        }
+        printf("\nAverage:        ");
+        for (j = 0; j < max_px_num; j++) {
+            int sum = 0;
+            int s_res = 0;
+            for (k = 0; k < n+1; k++) {
+                sum += (int)p[j][k].cnt;
+                s_res += (int)(p[j][k].res/tsc2phase);
+            }
+            /* print average */
+            if (sum == 0)
+                sum = 1;
+            printf("%.1f\t", (double)s_res/(double)sum);
+        }
+        printf("\nTotal:          ");
+        for (j = 0; j < max_px_num; j++) {
+            int s_res = 0;
+            for (k = 0; k < n+1; k++) {
+                s_res += (int)(p[j][k].res/tsc2phase);
+            }
+            /* print total */
+            printf("%d\t", s_res);
+        }
+        printf("\n");
+    }
+}
+
+void do_breakevents(void)
+{
+    int br[MAX_CPU_NR][257];
+    float pc[MAX_CPU_NR][257];
+    int i, j, k, l;
+
+    memset(br, 0, sizeof(int) * MAX_CPU_NR * 257);
+    memset(pc, 0, sizeof(int) * MAX_CPU_NR * 257);
+
+    for (i = 0; i < max_cpu_num; i++) {
+        int sum = 0;
+        for (j = 0; j < evt_len[i]; j++) {
+            if (evt[i][j].cx == 0) {
+                /* EXIT */
+                /* collect breakevents information */
+                int xx = 0;
+                for (k = 0; k < 4; k++) {
+                    int irq = evt[i][j].irqs[k];
+                    if (irq) {
+                        br[i][irq]++;
+                        sum++;
+                        xx++;
+                    }
+                }
+                if (!xx) {
+                    br[i][256]++;
+                    sum++;
+                }
+            }
+        }
+        for (j = 0; j < 257; j++)
+            pc[i][j] = 100.0 * br[i][j]/sum;
+    }
+    /* print the results */
+    width = 13;
+    printf("      ");
+    for (i = 0; i < max_cpu_num; i++) {
+        l = 0;
+        l += printf("CPU%d", i);
+        nr_putchar(width-l, ' ');
+    }
+    printf("\n");
+
+    for (j = 0; j < 257; j++) {
+        int n = 0;
+        for (i = 0; i < max_cpu_num; i++)
+            if (br[i][j])
+                n++;
+        if (n) {
+            if (j == 256)
+                printf("[N/A] ");
+            else
+                printf("[%03x] ", j);
+            for (i = 0; i < max_cpu_num; i++) {
+                if (br[i][j]) {
+                    l = 0;
+                    l += printf("%.1f%%,%d ", pc[i][j], br[i][j]);
+                    nr_putchar(width-l, ' ');
+                } else {
+                    nr_putchar(width, ' ');
+                }
+            }
+            printf("\n");
+        }
+    }
+}
+
+void single_cstate(int c, uint64_t t, uint64_t e,
+                   uint64_t *a,
+                   uint64_t *max_res,
+                   uint64_t *min_res,
+                   uint64_t *num);
+void do_cstate(uint64_t start, uint64_t end)
+{
+    uint64_t cxtime[MAX_CX_NR];
+    uint64_t max_res[MAX_CX_NR];
+    uint64_t min_res[MAX_CX_NR];
+    uint64_t num[MAX_CX_NR];
+    int i, j;
+
+    width = 20;
+    printf("       ");
+    for (i = 0; i < max_cx_num; i++) {
+        int l = printf("C%d", i);
+        nr_putchar(width-l, ' ');
+    }
+    printf("\n");
+
+    for (i = 0; i < max_cpu_num; i++) {
+        uint64_t sum = 0;
+        single_cstate(i, start, end, cxtime, max_res, min_res, num);
+        printf("CPU%2d ", i);
+        for (j = 0; j < max_cx_num; j++)
+            sum += cxtime[i];
+        for (j = 0; j < max_cx_num; j++) {
+            int l = printf("%.1f%%, %"PRIu64".%d, %"PRIu64".%d, %"PRIu64,
+                           100.0 * cxtime[j]/sum,
+                           max_res[j]/tsc2ms,
+                           (unsigned int)(max_res[j]/(tsc2ms/10))%10,
+                           min_res[j]/tsc2ms,
+                           (unsigned int)(min_res[j]/(tsc2ms/10))%10,
+                           cxtime[j]/num[j]/tsc2ms);
+            nr_putchar(width - l, ' ');
+        }
+    }
+}
+
+void single_cstate(int c, uint64_t t, uint64_t e,
+                   uint64_t *a,
+                   uint64_t *max_res,
+                   uint64_t *min_res,
+                   uint64_t *num)
+{
+    int cx;
+    int i;
+    int first = 1;
+
+    for (i = 0; i < max_cx_num; i++) {
+        a[i] = 0;
+        max_res[i] = 0;
+        min_res[i] = (uint64_t) -1;
+        num[i] = 0;
+    }
+
+    cx = determine_cx(c, t);
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].tsc <= t)
+        i++;
+    for (; i+1 < evt_len[c] && evt[c][i].tsc <= e; i++) {
+        int cxidx = evt[c][i].cx;
+        uint64_t delta;
+
+        if (first && cx >= 0) {
+            /* Partial Cx, only once */
+            first = 0;
+
+            cxidx = cx;
+            delta = evt[c][i].tsc - max(evt[c][i-1].tsc, t);
+            a[cxidx] += delta;
+            num[cxidx]++;
+
+            /* update min and max residency */
+            if (delta > max_res[cxidx])
+                max_res[cxidx] = delta;
+            if (delta < min_res[cxidx])
+                min_res[cxidx] = delta;
+        }
+        delta = evt[c][i+1].tsc - evt[c][i].tsc;
+        a[cxidx] += delta;
+        num[cxidx]++;
+
+        /* update min and max residency */
+        if (delta > max_res[cxidx])
+            max_res[cxidx] = delta;
+        if (delta < min_res[cxidx])
+            min_res[cxidx] = delta;
+    }
+}
+
+void do_average_per_cpu(int c)
+{
+    int i;
+    uint64_t tot[MAX_CX_NR] = { 0 };
+    uint64_t cnt[MAX_CX_NR] = { 0 };
+    uint64_t sum = 0;
+
+    /* find Cx entry first */
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].cx == 0)
+        i++;
+    /* check evt[c][i] and evt[c][i+1] */
+    while (i + 1 < evt_len[c]) {
+        uint64_t len = evt[c][i+1].tsc - evt[c][i].tsc;
+        int cx = evt[c][i].cx;
+        tot[cx] += len;
+        cnt[cx]++;
+        sum += len;
+        i++;
+    }
+    /* prevent divide zero error */
+    if (!sum)
+        sum = 1;
+    /* print */
+    printf("CPU%d:\tResidency(ms)\t\tAvg Res(ms)\n", c);
+    for (i = 0; i < max_cx_num; i++) {
+        /* prevent divide zero error */
+        if (!cnt[i])
+            cnt[i] = 1;
+        printf("  C%d\t%"PRIu64"\t(%6.2f%%)\t%.2f\n", i,
+               tot[i]/tsc2ms, 100.0 * tot[i] / (double)sum,
+               (double)tot[i]/cnt[i]/tsc2ms );
+    }
+    printf("\n");
+}
+
+void do_average(void)
+{
+    int i;
+
+    for (i = 0; i < max_cpu_num; i++)
+        do_average_per_cpu(i);
+}
+
+static void do_exp_ratio_per_cpu(int c)
+{
+    int i;
+    uint64_t expected[MAX_CX_NR] = { 0 }, sum[MAX_CX_NR] = { 0 };
+
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].cx == 0)
+        i++;
+    /* check evt[c][i] and evt[c][i+1] */
+    while (i + 1 < evt_len[c]) {
+        uint64_t len;
+        int cx;
+
+        if ((evt[c][i].cx == 0 && evt[c][i+1].cx == 0) ||
+            (evt[c][i].cx > 0 && evt[c][i+1].cx > 0)) {
+            i++;
+            continue;
+        }
+        len = evt[c][i+1].tsc - evt[c][i].tsc;
+        cx = evt[c][i].cx;
+        if (cx > 0) {
+            if ((len/tsc2us) <= evt[c][i].expected)
+                expected[cx]++;
+            sum[cx]++;
+        }
+
+        i++;
+    }
+    printf("********** CPU%d **********\n", c);
+    for (i = 1; i < max_cx_num; i++) {
+        if (sum[i] == 0)
+            printf("C%d\t0\t0\t00.00%%\n", i);
+        else
+            printf("C%d\t%"PRIu64"\t%"PRIu64"\t%4.2f%%\n",
+                   i, expected[i], sum[i], 100.0 * 
(double)expected[i]/(double)sum[i]);
+    }
+}
+
+void do_exp_ratio(void)
+{
+    int i;
+
+    if (!is_menu_gov_enabled) {
+        printf("The file seems doesn't consists the expected/predicted 
information.\n");
+        return;
+    }
+
+    printf("Cx\tearly\ttot\tratio(%%)\n");
+    for (i = 0; i < max_cpu_num; i++)
+        do_exp_ratio_per_cpu(i);
+}
+
+static void do_exp_pred_per_cpu(int c)
+{
+    int i;
+    uint64_t expected[MAX_CX_NR] = { 0 }, sum[MAX_CX_NR] = { 0 };
+
+    i = 0;
+    while (i < evt_len[c] && evt[c][i].cx == 0)
+        i++;
+    /* check evt[c][i] and evt[c][i+1] */
+    while (i + 1 < evt_len[c]) {
+        int cx;
+
+        if ((evt[c][i].cx == 0 && evt[c][i+1].cx == 0) ||
+            (evt[c][i].cx > 0 && evt[c][i+1].cx > 0)) {
+            i++;
+            continue;
+        }
+        cx = evt[c][i].cx;
+        if (cx > 0) {
+            if (evt[c][i].expected <= evt[c][i].predicted)
+                expected[cx]++;
+            sum[cx]++;
+        }
+
+        i++;
+    }
+    printf("********** CPU%d **********\n", c);
+    for (i = 1; i < max_cx_num; i++) {
+        if (sum[i] == 0)
+            printf("C%d\t0\t0\t00.00%%\n", i);
+        else
+            printf("C%d\t%"PRIu64"\t%"PRIu64"\t%4.2f%%\n",
+                   i, expected[i], sum[i], 100.0 * 
(double)expected[i]/(double)sum[i]);
+    }
+}
+
+void do_exp_pred(void)
+{
+    int i;
+
+    if (!is_menu_gov_enabled) {
+        printf("The file seems doesn't consists the expected/predicted 
information.\n");
+        return;
+    }
+
+    printf("Cx\texp\ttot\tratio(%%)\n");
+    for (i = 0; i < max_cpu_num; i++)
+        do_exp_pred_per_cpu(i);
+}
+
diff -r 41317562d332 -r 388578e1626e tools/misc/gtraceview.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/misc/gtraceview.c   Mon Jun 29 11:03:24 2009 +0100
@@ -0,0 +1,1103 @@
+/*
+ * gtraceview.c: list Cx events in a ncurse way to help find abnormal 
behaviour.
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <xenctrl.h>
+#include <xen/trace.h>
+
+#include <ncurses.h>
+
+/********** MACROS **********/
+#define MAX_CPU_NR  32
+#define MAX_MODE_NR 16
+#define MAX_STRING_LEN 1024
+
+/********** STRUCTURE DEFINITIONS **********/
+enum {
+    FLAG_FUZZY = 0,
+    FLAG_LEVEL,
+    FLAG_EDGE,
+    FLAG_UNKNOWN,
+    NR_FLAGS
+};
+
+struct string {
+    int len;
+    char str[MAX_STRING_LEN+1];
+};
+
+int num_of_cpus(void);
+void string_nr_addch(struct string *str, int nr, char ch)
+{
+    int i;
+    for (i = 0; i < nr; i++)
+        str->str[str->len++] = ch;
+    str->str[str->len] = '\0';
+}
+
+int string_print(struct string *str, char *fmt, ...)
+{
+    va_list ap;
+    int l = 0;
+
+    va_start(ap, fmt);
+    l = vsprintf(str->str + str->len, fmt, ap);
+    va_end(ap);
+    str->len += l;
+    str->str[str->len] = '\0';
+    return l;
+}
+
+struct cpu {
+    unsigned char cx;
+    // unsigned char cx_prev;
+    unsigned char flag;
+    unsigned char irqs[4];
+    unsigned int expected;
+    unsigned int predicted;
+};
+
+struct state {
+    uint64_t tsc;
+    struct cpu cpu[MAX_CPU_NR];
+};
+
+struct mode {
+    const char *name;
+    int offset;
+    int width;
+    int row;
+    int scroll_h;
+    struct state *state;
+    int state_nr;
+    uint64_t time_scale;
+    uint64_t start_time;
+    int cpu_bitmap[MAX_CPU_NR];
+    int initialized;
+    int (*init)(void);
+    void (*show)(void);
+    void (*exit)(void);
+};
+
+/* simplified xentrace record */
+struct rec {
+    uint64_t tsc;
+    int cpu;
+    unsigned int expected;
+    unsigned int predicted;
+    unsigned char cx;
+    unsigned char irqs[4];
+};
+
+/********** FORWARD DECLARATION **********/
+void show_help(void);
+void show_version(void);
+int load_file(char *fname);
+void crt_init(void);
+int mode_init(void);
+void mode_show(void);
+
+/* event mode handler */
+int event_mode_init(void);
+void event_mode_show(void);
+void event_mode_exit(void);
+
+/* time mode handler */
+int time_mode_init(void);
+int time_mode_rebuild(uint64_t start_time, uint64_t time_scale);
+
+/********** GLOBAL VARIABLES **********/
+/* store simplified xentrace data */
+struct rec *data;
+int64_t data_nr, data_cur;
+/* store max cx state number and cpu number */
+int max_cx_num = -1, max_cpu_num = -1;
+int is_irq_enabled = -1;
+int is_menu_gov_enabled = -1;
+int is_link = 0;
+uint64_t tsc2us = 2793UL;
+
+struct rec *data_evt;
+struct rec *evt[MAX_CPU_NR];
+int evt_len[MAX_CPU_NR];
+
+int cur_row = 0;
+struct mode modes[] = {
+    {
+        .name = "Event",
+        .init = event_mode_init,
+        .show = event_mode_show,
+        .exit = event_mode_exit,
+    },
+    {
+        .name = "Time",
+        .init = time_mode_init,
+        /* use the same show and exit with event mode */
+        .show = event_mode_show,
+        .exit = event_mode_exit,
+    },
+};
+struct mode *this = NULL;
+
+/* hand-crafted min() */
+static inline int min(int a, int b)
+{
+    return a < b ? a : b;
+}
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+void choose_cpus(void);
+void help_screen(void);
+int main(int argc, char *argv[])
+{
+    char *fname = NULL;
+    int arg;
+    int quit = 0;
+    uint64_t s_time = 0;
+    uint64_t last_tsc = 0;
+
+    for (arg = 1; arg < argc; arg++) {
+        if (!strcmp(argv[arg], "--version")) {
+            show_version();
+            exit(EXIT_SUCCESS);
+        } else if (!strcmp(argv[arg], "--help")) {
+            show_help();
+            exit(EXIT_SUCCESS);
+        } else {
+            /* assume it's a file */
+            fname = argv[arg];
+            break;
+        }
+    }
+
+    if (!fname) {
+        show_help();
+        exit(EXIT_FAILURE);
+    }
+
+    if (load_file(fname))
+        exit(EXIT_FAILURE);
+
+    if (mode_init())
+        exit(EXIT_FAILURE);
+
+    crt_init();
+
+    cur_row = 1;
+    this = &modes[0];
+    while (!quit) {
+        int ch;
+
+        clear();
+        this->show();
+        ch = getch();
+        switch (ch) {
+        case '!':
+            is_link = !is_link;
+            break;
+        case 'u':
+            move(LINES-1, 0);
+            clrtoeol();
+            printw("us = ? TSCs (default: 2793):");
+            echo();
+            curs_set(1);
+            scanw("%"PRIu64, &tsc2us);
+            curs_set(0);
+            noecho();
+            if (tsc2us <= 0)
+                tsc2us = 2793UL;
+            break;
+        case '/':
+            move(LINES-1, 0);
+            clrtoeol();
+            printw("Input start time:");
+            echo();
+            curs_set(1);
+            scanw("%"PRIu64, &s_time);
+            curs_set(0);
+            noecho();
+            if (s_time >= this->state[0].tsc &&
+                s_time <= this->state[this->state_nr-1].tsc) {
+                int i = 0;
+                while (i < this->state_nr &&
+                       this->state[i].tsc < s_time)
+                    i++;
+                this->row = i;
+                cur_row = 1;
+            }
+            break;
+        case '+':
+            if (!strcmp(this->name, "Time")) {
+                this->time_scale -= this->time_scale/10;
+                this->start_time = this->state[this->row+cur_row-1].tsc - 
(cur_row-1)*this->time_scale;
+                if (this->start_time < data[0].tsc)
+                    this->start_time = data[0].tsc;
+                time_mode_rebuild(this->start_time, this->time_scale);
+            }
+            break;
+        case '-':
+            if (!strcmp(this->name, "Time")) {
+                this->time_scale += this->time_scale/10;
+                this->start_time = this->state[this->row+cur_row-1].tsc - 
(cur_row-1)*this->time_scale;
+                if (this->start_time < data[0].tsc)
+                    this->start_time = data[0].tsc;
+                time_mode_rebuild(this->start_time, this->time_scale);
+            }
+            break;
+        case KEY_RESIZE:
+            break;
+        case KEY_UP:
+            if (--cur_row < 1) {
+                cur_row = 1;
+                if (--this->row < 0)
+                    this->row = 0;
+            }
+            break;
+        case KEY_DOWN:
+            if (++cur_row > LINES-2) {
+                cur_row = LINES-2;
+                this->row = min(this->state_nr-LINES+2, this->row+1);
+            }
+            break;
+        case KEY_LEFT:
+            this->scroll_h -= 3;
+            if (this->scroll_h < 0)
+                this->scroll_h = 0;
+            break;
+        case KEY_RIGHT:
+            this->scroll_h += 3;
+            if (this->scroll_h >= this->width*num_of_cpus())
+                this->scroll_h = this->width*num_of_cpus();
+            break;
+        case KEY_HOME:
+            cur_row = 1;
+            this->row = 0;
+            break;
+        case KEY_END:
+            cur_row = LINES-2;
+            this->row = this->state_nr-LINES+2;
+            break;
+        case KEY_NPAGE:
+            this->row = min(this->state_nr-LINES+2, this->row+20);
+            break;
+        case KEY_PPAGE:
+            if (this->row >= 20)
+                this->row -= 20;
+            break;
+        case KEY_F(2):
+            /* change to another mode */
+            if (is_link)
+            last_tsc = this->state[this->row+cur_row-1].tsc;
+
+            if (this == &modes[sizeof(modes)/sizeof(modes[0])-1])
+                this = &modes[0];
+            else
+                this++;
+            clear();
+            if (is_link) {
+                if (!strcmp(this->name, "Time")) {
+                    this->start_time = last_tsc - (cur_row-1)*this->time_scale;
+                    if (this->start_time < data[0].tsc)
+                        this->start_time = data[0].tsc;
+                    time_mode_rebuild(this->start_time, this->time_scale);
+                } else if (!strcmp(this->name, "Event")) {
+                    int x;
+                    for (x = 0; x < this->state_nr && this->state[x].tsc < 
last_tsc; x++)
+                        ;
+                    this->row = x-(cur_row-1);
+                }
+            }
+            break;
+        case KEY_F(3):
+            if (!strcmp(this->name, "Time")) {
+                /* only meaningful in Time mode */
+                move(LINES-1, 0);
+                clrtoeol();
+                printw("Input time scale and start time:");
+                echo();
+                curs_set(1);
+                scanw("%"PRIu64" %"PRIu64,
+                      &this->time_scale, &this->start_time);
+                curs_set(0);
+                noecho();
+                time_mode_rebuild(this->start_time,
+                                  this->time_scale);
+            }
+            break;
+        case KEY_F(4):
+            /* quit */
+            quit = 1;
+            break;
+        case KEY_F(5):
+            /* choose which CPUs to display */
+            choose_cpus();
+            break;
+        case 'h':
+            help_screen();
+            break;
+        }
+    }
+
+    exit(EXIT_SUCCESS);
+}
+/* used for qsort() */
+static int evt_data_cmp(const void *_a, const void *_b)
+{
+    struct rec *a = (struct rec *)_a;
+    struct rec *b = (struct rec *)_b;
+    if (a->cpu == b->cpu)
+        return a->tsc > b->tsc ? 1 : -1;
+    return a->cpu > b->cpu ? 1 : -1;
+}
+
+static int data_cmp(const void *_a, const void *_b)
+{
+    struct rec *a = (struct rec *)_a;
+    struct rec *b = (struct rec *)_b;
+    return a->tsc > b->tsc ? 1 : -1;
+}
+
+/* load file and make them a list of records
+ * update these following variables:
+ *   data, data_cur, data_nr
+ *   max_cpu_num, max_cx_num
+ */
+int load_file(char *fname)
+{
+    /* file descriptor for raw xentrace file */
+    int fd;
+    /* current cpu during xentrace data parse */
+    int cur_cpu = -1;
+    int i;
+
+    fd = open(fname, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "file %s cannot open\n", fname);
+        return 1;
+    }
+
+    /* the initial number is 1024,
+     * and when it overflows, this number doubles.
+     */
+    data_nr = 1024;
+    data_cur = 0;
+    data = malloc(sizeof(struct rec) * data_nr);
+    if (!data) {
+        fprintf(stderr, "not enough memory\n");
+        close(fd);
+        return 1;
+    }
+
+    while (1) {
+        struct t_rec rec;
+        ssize_t ret, size;
+
+        ret = read(fd, &rec, sizeof(uint32_t));
+        if (!ret)
+            break;
+        if (ret != sizeof(uint32_t)) {
+            fprintf(stderr, "reading header error\n");
+            break;
+        }
+
+        size = 0;
+        if (rec.cycles_included)
+            size += sizeof(uint64_t);
+        size += sizeof(uint32_t) * rec.extra_u32;
+
+        ret = read(fd, (char *)&rec + sizeof(uint32_t), size);
+        if (!ret && size)
+            break;
+        if (ret != size) {
+            fprintf(stderr, "reading data error\n");
+            break;
+        }
+
+        if (rec.event == 0x1f003) {
+            /* cpu change event */
+            cur_cpu = 0;
+            if (rec.extra_u32 > 0)
+                cur_cpu = rec.u.nocycles.extra_u32[0];
+            continue;
+        } else if (!rec.cycles_included ||
+                   (rec.event != TRC_PM_IDLE_ENTRY &&
+                    rec.event != TRC_PM_IDLE_EXIT &&
+                    rec.event != TRC_PM_FREQ_CHANGE)) {
+            continue;
+        }
+
+        /* add one record */
+        if (data_cur == data_nr) {
+            data_nr <<= 1;
+            if (data_nr < 0) {
+                fprintf(stderr, "too many entries\n");
+                close(fd);
+                return 1;
+            }
+            data = realloc(data, sizeof(struct rec) * data_nr);
+            if (!data) {
+                fprintf(stderr, "not enough memory\n");
+                close(fd);
+                return 1;
+            }
+        }
+        data[data_cur].tsc = rec.u.cycles.cycles_hi;
+        data[data_cur].tsc <<= 32;
+        data[data_cur].tsc |= rec.u.cycles.cycles_lo;
+        data[data_cur].cpu = cur_cpu;
+        /* extra_u32[1] is omitted, as it's pm ticks. */
+        if (rec.event == TRC_PM_IDLE_ENTRY) {
+            data[data_cur].cx = rec.u.cycles.extra_u32[0];
+            if (rec.extra_u32 >= 4) {
+                data[data_cur].expected = rec.u.cycles.extra_u32[2];
+                data[data_cur].predicted = rec.u.cycles.extra_u32[3];
+                is_menu_gov_enabled = 1;
+            } else
+                is_menu_gov_enabled = 0;
+        } else if (rec.event == TRC_PM_IDLE_EXIT) {
+            /* IDLE_EXIT default to C0 */
+            data[data_cur].cx = 0;
+            /* store the reasons why it exits */
+            if (rec.extra_u32 == 6) {
+                data[data_cur].irqs[0] = rec.u.cycles.extra_u32[2];
+                data[data_cur].irqs[1] = rec.u.cycles.extra_u32[3];
+                data[data_cur].irqs[2] = rec.u.cycles.extra_u32[4];
+                data[data_cur].irqs[3] = rec.u.cycles.extra_u32[5];
+                is_irq_enabled = 1;
+            } else
+                is_irq_enabled = 0;
+        } else {
+            /* FREQ CHANGE */
+        }
+
+        /* update max info */
+        if (data[data_cur].cx > max_cx_num)
+            max_cx_num = data[data_cur].cx;
+        if (data[data_cur].cpu > max_cpu_num)
+            max_cpu_num = data[data_cur].cpu;
+
+        data_cur++;
+    }
+    close(fd);
+
+    data_evt = malloc(sizeof(struct rec) * data_cur);
+    memcpy(data_evt, data, sizeof(struct rec) * data_cur);
+
+    qsort(data_evt, data_cur, sizeof(struct rec), evt_data_cmp);
+    for (i = 0; i < max_cpu_num; i++) {
+        evt_len[i] = 0;
+        evt[i] = NULL;
+    }
+    for (i = data_cur-1; i >= 0; i--) {
+        evt[data_evt[i].cpu] = data_evt+i;
+        evt_len[data_evt[i].cpu]++;
+    }
+
+    /* sort data array according to TSC time line */
+    qsort(data, data_cur, sizeof(struct rec), data_cmp);
+
+    max_cpu_num++;
+    max_cx_num++;
+
+    return 0;
+}
+
+void show_version(void)
+{
+    printf("gtraceview - (C) 2009 Intel Corporation\n");
+}
+
+void show_help(void)
+{
+    show_version();
+    printf("gtraceview <trace.data> [--version] [--help]\n");
+    printf("  trace.data   raw data from xentrace\n");
+    printf("  --version    show version information\n");
+    printf("  --help       show this message\n");
+    printf("For more help messages, please press 'h' in the window\n");
+}
+
+void crt_done(void)
+{
+    curs_set(1);
+    endwin();
+}
+
+void help_screen(void)
+{
+    clear();
+    mvprintw(0, 0, "    HELP SCREEN");
+    mvprintw(1, 0, "1. LEFT and RIGHT arrow key to move off-screen outputs");
+    mvprintw(2, 0, "2. UP and DOWN arrow key to move the highlighted line");
+    mvprintw(3, 0, "3. F2 to switch between Event and Time mode");
+    mvprintw(4, 0, "4. '/' to search the TSC stamp");
+    mvprintw(5, 0, "5. '+' to zoom in and '-' to zoom out");
+    mvprintw(6, 0, "6. F3 to set start time and time manually");
+    mvprintw(7, 0, "7. F4 to quit");
+    mvprintw(8, 0, "8. F5 to select which CPUs we want to see");
+    mvprintw(9, 0, "9. Irq exit reason shown on Cx exit record (patch 
needed)");
+    mvprintw(10, 0, "10. Menu governor criteria shown on bottom line (patch 
needed)");
+    mvprintw(11, 0, "11. PAGEDOWN, PAGEUP, HOME and END to navigate");
+    mvprintw(12, 0, "12. 'h' to show this screen");
+    mvprintw(13, 0, "13. 'u' to edit how many TSCs is a us unit");
+
+    mvprintw(LINES-1, 0, "Press any key to continue...");
+    getch();
+}
+
+void crt_init(void)
+{
+    char *term;
+
+    initscr();
+    noecho();
+    nonl();
+    intrflush(stdscr, false);
+    keypad(stdscr, true);
+    curs_set(0);
+    /* hook exit() */
+    atexit(crt_done);
+    /* we love colorful screens :-) */
+    start_color();
+    init_pair(1, COLOR_BLACK, COLOR_CYAN);
+    init_pair(2, COLOR_BLACK, COLOR_GREEN);
+    init_pair(3, COLOR_BLACK, COLOR_RED);
+
+    /* some term tunings */
+    term = getenv("TERM");
+    if (!strcmp(term, "xterm") ||
+        !strcmp(term, "xterm-color") ||
+        !strcmp(term, "vt220")) {
+        define_key("\033[1~", KEY_HOME);
+        define_key("\033[4~", KEY_END);
+        define_key("\033OP", KEY_F(1));
+        define_key("\033OQ", KEY_F(2));
+        define_key("\033OR", KEY_F(3));
+        define_key("\033OS", KEY_F(4));
+        define_key("\033[11~", KEY_F(1));
+        define_key("\033[12~", KEY_F(2));
+        define_key("\033[13~", KEY_F(3));
+        define_key("\033[14~", KEY_F(4));
+        define_key("\033[[D", KEY_LEFT);
+    }
+}
+
+void nr_addch(int nr, int ch)
+{
+    int i;
+    int y, x;
+    getyx(stdscr, y, x);
+    for (i = 0; i < nr; i++) {
+        if (x == COLS-1)
+            break;
+        addch(ch);
+    }
+}
+
+int event_mode_init(void)
+{
+    int i, j;
+    struct state *state;
+    int index;
+    struct cpu cur_state[MAX_CPU_NR];
+
+    if (this->initialized)
+        free(this->state);
+    state =  malloc(sizeof(struct state) * data_cur);
+    if (!state)
+        return 1;
+    this->state = state;
+    this->row = 0;
+    this->width = 9;
+    this->offset = 33;
+    this->scroll_h = 0;
+
+    /* otherwise, respect cpu_bitmap[] */
+    if (!this->initialized) {
+        this->initialized = 1;
+        for (i = 0; i < max_cpu_num; i++)
+            this->cpu_bitmap[i] = 1;
+    }
+
+    for (i = 0; i < max_cpu_num; i++)
+        if (this->cpu_bitmap[i])
+            cur_state[i].flag = FLAG_UNKNOWN;
+
+    for (i = 0, index = 0; i < data_cur; i++) {
+        /* data[i] */
+        int cpu = data[i].cpu;
+        if (cpu < 0)
+            continue;
+        if (!this->cpu_bitmap[cpu])
+            continue;
+
+        /* TODO: use the same structure */
+        /* copy cx, expected, predicted and irqs */
+        cur_state[cpu].cx = data[i].cx;
+        cur_state[cpu].expected = data[i].expected;
+        cur_state[cpu].predicted = data[i].predicted;
+        memcpy(cur_state[cpu].irqs, data[i].irqs,
+               sizeof(unsigned char) * 4);
+        /* as long as it comes here,
+         * it means that we have an event.
+         */
+        cur_state[cpu].flag = FLAG_EDGE;
+
+        state[index].tsc = data[i].tsc;
+        for (j = 0; j < max_cpu_num; j++) {
+            if (!this->cpu_bitmap[j])
+                continue;
+
+            /* copy cx, irqs and flags */
+            state[index].cpu[j].cx = cur_state[j].cx;
+            state[index].cpu[j].expected = cur_state[j].expected;
+            state[index].cpu[j].predicted = cur_state[j].predicted;
+            memcpy(state[index].cpu[j].irqs, cur_state[j].irqs,
+                   sizeof(unsigned char) * 4);
+            state[index].cpu[j].flag = cur_state[j].flag;
+
+            /* chage flag in cur_state accordingly */
+            if (cur_state[j].flag == FLAG_EDGE)
+                cur_state[j].flag = FLAG_LEVEL;
+        }
+        index++;
+    }
+
+    this->state_nr = index;
+    return 0;
+}
+
+static inline int len_of_number(uint64_t n)
+{
+    int l = 0;
+    if (!n)
+        return 1;
+    do {
+        l++;
+        n /= 10;
+    } while (n);
+    return l;
+}
+
+static inline void display_number(uint64_t n, int l)
+{
+    static char sym[] = { ' ', 'K', 'M', 'G', 'T' };
+    int nr = 0;
+
+    if (len_of_number(n) <= l) {
+        nr_addch(l-len_of_number(n), ' ');
+        printw("%"PRIu64, n);
+        return;
+    }
+    do {
+        n /= 1000UL;
+        nr++;
+    } while (len_of_number(n) > l-1);
+    nr_addch(l-1-len_of_number(n), ' ');
+    printw("%"PRIu64, n);
+    nr_addch(1, sym[nr]);
+}
+
+void draw_cpu_state(struct string *s, struct cpu *c, int width)
+{
+    int cx = c->cx;
+    int flag = c->flag;
+
+    switch (flag) {
+    case FLAG_FUZZY:
+        string_nr_addch(s, max_cx_num, '#');
+        string_nr_addch(s, width-max_cx_num, ' ');
+        break;
+    case FLAG_UNKNOWN:
+        string_nr_addch(s, 1, '?');
+        string_nr_addch(s, width-1, ' ');
+        break;
+    case FLAG_LEVEL:
+        string_nr_addch(s, cx, ' ');
+        string_nr_addch(s, 1, '|');
+        string_nr_addch(s, width-1-cx, ' ');
+        break;
+    case FLAG_EDGE:
+        if (cx > 0) {
+            /* ENTRY */
+            string_nr_addch(s, 1, '>');
+            string_nr_addch(s, cx-1, '-');
+            string_nr_addch(s, 1, '+');
+            string_nr_addch(s, width-cx-1, ' ');
+        } else {
+            /* EXIT */
+            string_nr_addch(s, 1, '<');
+            if (is_irq_enabled == 1) {
+                int k, len = 0;
+                for (k = 0; k < 4; k++) {
+                    unsigned char irq = c->irqs[k];
+                    if (irq) {
+                        string_print(s, "%02x", irq);
+                        len += 2;
+                    }
+                }
+                if (len > 0)
+                    string_nr_addch(s, width-len-1, ' ');
+                else {
+                    string_print(s, "noirq");
+                    string_nr_addch(s, width-1-5, ' ');
+                }
+            } else {
+                string_nr_addch(s, 1, '-');
+                string_nr_addch(s, width-2, ' ');
+            }
+        }
+        break;
+    }
+}
+
+void event_mode_show(void)
+{
+    struct state *state = this->state;
+    struct string s;
+    int idx = this->row;
+    int idx_hl = 0;
+    int i, j, l;
+
+    /* draw headline */
+    s.len = 0;
+    move(0, 0);
+    attron(COLOR_PAIR(2));
+    nr_addch(this->offset, ' ');
+    for (i = 0; i < max_cpu_num; i++) {
+        if (this->cpu_bitmap[i]) {
+            string_print(&s, "CPU%d", i);
+            string_nr_addch(&s, this->width-len_of_number(i)-3, ' ');
+        }
+    }
+    mvaddnstr(0, this->offset, s.str+this->scroll_h,
+              MIN(s.len-this->scroll_h, this->width*num_of_cpus()));
+    attroff(COLOR_PAIR(2));
+
+    /* draw body */
+    for (i = 1; i < LINES-1; i++, idx++) {
+        move(i, 0);
+        /* highlight the current row */
+        if (i == cur_row) {
+            attron(COLOR_PAIR(1));
+            idx_hl = idx;
+        }
+
+        if (idx >= this->state_nr) {
+            /* do not show this line */
+            nr_addch(this->offset+this->width*num_of_cpus(), ' ');
+        } else {
+            if (!strcmp(this->name, "Event")) {
+                uint64_t delta = 0;
+                if (idx)
+                    delta = (state[idx].tsc - state[idx-1].tsc)/tsc2us;
+                printw("%20"PRIu64"(", state[idx].tsc);
+                display_number(delta, 8);
+                printw("us) ");
+            } else if (!strcmp(this->name, "Time")) {
+                printw("%20"PRIu64" ", state[idx].tsc);
+            }
+
+            s.len = 0;
+            for (j = 0; j < max_cpu_num; j++) {
+                /* draw cpu state */
+                if (this->cpu_bitmap[j])
+                    draw_cpu_state(&s, &state[idx].cpu[j], this->width);
+            }
+            /* draw the line accordingly */
+            mvaddnstr(i, this->offset, s.str+this->scroll_h,
+                      MIN(s.len-this->scroll_h, this->width*num_of_cpus()));
+        }
+        /* pair of the highlight logics */
+        if (i == cur_row)
+            attroff(COLOR_PAIR(1));
+    }
+
+    /* draw tail line */
+    attron(COLOR_PAIR(2));
+    s.len = 0;
+    l = 0;
+    l += string_print(&s, "%s Mode [%sLINKED]", this->name, is_link ? "" : 
"NOT ");
+    if (!strcmp(this->name, "Time")) {
+#if 0
+        l += string_print(&s, " [%"PRIu64":%"PRIu64"]",
+                          this->start_time, this->time_scale);
+#endif
+        l += string_print(&s, " [%"PRIu64"]",
+                          this->time_scale);
+    }
+    if (is_menu_gov_enabled == 1) {
+        for (i = 0; i < max_cpu_num; i++) {
+            if (this->cpu_bitmap[i] &&
+                state[idx_hl].cpu[i].flag == FLAG_EDGE &&
+                state[idx_hl].cpu[i].cx > 0)
+                l += string_print(&s, " (CPU%d,%lu,%lu)",
+                                  i,
+                                  state[idx_hl].cpu[i].expected,
+                                  state[idx_hl].cpu[i].predicted);
+        }
+    }
+    /* add cx exit residency info */
+    for (i = 0; i < max_cpu_num; i++) {
+        if (this->cpu_bitmap[i] &&
+            state[idx_hl].cpu[i].flag == FLAG_EDGE &&
+            state[idx_hl].cpu[i].cx == 0) {
+            uint64_t tsc = state[idx_hl].tsc;
+            int k;
+
+            k = 0;
+            while (k < evt_len[i] &&
+                   evt[i][k].tsc < tsc)
+                k++;
+            k--;
+            if (k >= 0 && k+1 < evt_len[i] && evt[i][k].cx > 0) {
+                l += string_print(&s, " (CPU%d, %"PRIu64"us)",
+                                  i,
+                                  (evt[i][k+1].tsc - evt[i][k].tsc)/tsc2us);
+            }
+        }
+    }
+
+    string_nr_addch(&s, this->offset+this->width*num_of_cpus()-l, ' ');
+    mvaddstr(LINES-1, 0, s.str);
+    attroff(COLOR_PAIR(2));
+    refresh();
+}
+
+void event_mode_exit(void)
+{
+    free(this->state);
+    this->initialized = 0;
+}
+
+void mode_exit(void)
+{
+    int nr = sizeof(modes)/sizeof(modes[0]);
+    int i;
+
+    for (i = 0; i < nr; i++) {
+        this = &modes[i];
+        if (this->initialized)
+            this->exit();
+    }
+}
+
+int mode_init(void)
+{
+    int nr = sizeof(modes)/sizeof(modes[0]);
+    int i, r = 0;
+
+    for (i = 0; i < nr; i++) {
+        this = &modes[i];
+        this->initialized = 0;
+        r += this->init();
+    }
+
+    this = &modes[0];
+
+    /* hook into exit */
+    atexit(mode_exit);
+
+    return r;
+}
+
+int time_mode_rebuild(uint64_t start_time, uint64_t time_scale)
+{
+    int i, j;
+    struct cpu cur_state[MAX_CPU_NR];
+    uint64_t tsc = start_time;
+    struct state *state;
+    uint64_t number, temp;
+    int state_cur = 0;
+
+    for (i = 0; i < max_cpu_num; i++)
+        cur_state[i].flag = FLAG_UNKNOWN;
+
+    /* allocate spaces, it may be huge... */
+    temp = (data[data_cur-1].tsc - start_time)/time_scale;
+    number = 10000UL;
+    if (temp < number)
+        number = temp;
+    number += 2;
+    state = malloc(sizeof(struct state) * number);
+    if (!state)
+        return 1;
+    if (this->state)
+        free(this->state);
+    this->state = state;
+    this->width = 9;
+    this->row = 0;
+
+    /* determine the current Cx state */
+    /* check [data[0].tsc, tsc) */
+    i = 0;
+    while (i < data_cur && data[i].tsc < tsc) {
+        int cpu = data[i].cpu;
+        cur_state[cpu].cx = data[i].cx;
+        cur_state[cpu].flag = FLAG_LEVEL;
+        i++;
+    }
+    while (i < data_cur && state_cur < number) {
+        int num[MAX_CPU_NR];
+        int last_idx[MAX_CPU_NR];
+
+#if 0
+        printf("XXXXX %d tsc: %"PRIu64" data[i].tsc: %"PRIu64"\n",
+               i, tsc, data[i].tsc);
+#endif
+        /* ensure they are zero */
+        memset(num, 0, sizeof(int) * MAX_CPU_NR);
+        memset(last_idx, 0, sizeof(int) * MAX_CPU_NR);
+
+        /* check [tsc, tsc+time_scale) */
+        while (i < data_cur && data[i].tsc < tsc+time_scale) {
+            int cpu = data[i].cpu;
+            num[cpu]++;
+            last_idx[cpu] = i;
+            i++;
+        }
+        /* TODO */
+        if (i >= data_cur)
+            break;
+        for (j = 0; j < max_cpu_num; j++) {
+            if (num[j] == 1) {
+                /* only one event, it's an edge*/
+                cur_state[j].cx = data[last_idx[j]].cx;
+                cur_state[j].flag = FLAG_EDGE;
+            } else if (num[j] > 1) {
+                /* more than one event, it's fuzzy */
+                cur_state[j].cx = data[last_idx[j]].cx;
+                cur_state[j].flag = FLAG_FUZZY;
+            } else if (cur_state[j].flag == FLAG_FUZZY) {
+                /* no event, fuzzy state can't be passed down
+                 * notice that cx is set in the fuzzy state,
+                 * it's not changed here afterwards.
+                 */
+                cur_state[j].flag = FLAG_LEVEL;
+            }
+        }
+
+        /* copy tsc */
+        state[state_cur].tsc = tsc;
+        for (j = 0; j < max_cpu_num; j++) {
+            /* copy cx and flag */
+            state[state_cur].cpu[j].cx = cur_state[j].cx;
+            state[state_cur].cpu[j].flag = cur_state[j].flag;
+
+            /* update flag in cur_state */
+            if (cur_state[j].flag == FLAG_EDGE) {
+                cur_state[j].flag = FLAG_LEVEL;
+                if (cur_state[j].cx == 0) {
+                    /* EXIT */
+                    /* copy irqs conditionally */
+                    memcpy(state[state_cur].cpu[j].irqs,
+                           data[last_idx[j]].irqs,
+                           sizeof(unsigned char) * 4);
+                } else {
+                    /* ENTRY */
+                    state[state_cur].cpu[j].expected =
+                        data[last_idx[j]].expected;
+                    state[state_cur].cpu[j].predicted =
+                        data[last_idx[j]].predicted;
+                }
+            }
+        }
+        state_cur++;
+        tsc += time_scale;
+    }
+    this->state_nr = state_cur;
+    this->row = 0;
+
+    return 0;
+}
+
+int time_mode_init(void)
+{
+    int i;
+    this->offset = 21;
+    this->scroll_h = 0;
+    this->time_scale = (data[data_cur-1].tsc -data[0].tsc)/10000UL;
+    this->start_time = data[0].tsc;
+    for (i = 0; i < max_cpu_num; i++)
+        this->cpu_bitmap[i] = 1;
+    return time_mode_rebuild(this->start_time,
+                             this->time_scale);
+}
+
+void choose_cpus(void)
+{
+    int i;
+    int temp_row = 1;
+    int ch;
+
+    clear();
+    mvprintw(0, 0, "How many CPUs to track? Press space to toggle. Press 'q' 
or 'Q' to quit.");
+
+    while (1) {
+        for (i = 0; i < max_cpu_num; i++) {
+            if (temp_row == i+1)
+                attron(COLOR_PAIR(2));
+            mvprintw(i+1, 0, "[%s] CPU%d", this->cpu_bitmap[i] ? "x" : " ", i);
+            if (temp_row == i+1)
+                attroff(COLOR_PAIR(2));
+        }
+        ch = getch();
+        switch (ch) {
+        case KEY_UP:
+            if (--temp_row < 1)
+                temp_row = 1;
+            break;
+        case KEY_DOWN:
+            if (++temp_row > max_cpu_num)
+                temp_row = max_cpu_num;
+            break;
+        case ' ':
+            this->cpu_bitmap[temp_row-1] = !this->cpu_bitmap[temp_row-1];
+            break;
+        case 'q':
+        case 'Q':
+            if (num_of_cpus() >= 1) {
+                if (!strcmp(this->name, "Event"))
+                    this->init();
+                return;
+            }
+        case KEY_F(4):
+            exit(EXIT_SUCCESS);
+        }
+    }
+}
+
+int num_of_cpus(void)
+{
+    int i, nr = 0;
+    for (i = 0; i < max_cpu_num; i++)
+        if (this->cpu_bitmap[i])
+            nr++;
+    return nr;
+}
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.