diff --git a/.gitignore b/.gitignore index a061f4a430..43c6f934ba 100644 --- a/.gitignore +++ b/.gitignore @@ -193,8 +193,6 @@ tools/misc/xen-livepatch tools/misc/xenperf tools/misc/xenpm tools/misc/xen-hvmctx -tools/misc/gtraceview -tools/misc/gtracestat tools/misc/xenlockprof tools/misc/lowmemd tools/misc/xencov diff --git a/.hgignore b/.hgignore index 0bd29a1061..8342f36982 100644 --- a/.hgignore +++ b/.hgignore @@ -205,8 +205,6 @@ ^tools/misc/xenpm$ ^tools/misc/xen-hvmctx$ ^tools/misc/xen-lowmemd$ -^tools/misc/gtraceview$ -^tools/misc/gtracestat$ ^tools/misc/xenlockprof$ ^tools/misc/xencov$ ^tools/pygrub/build/.*$ diff --git a/tools/misc/Makefile b/tools/misc/Makefile index cee2b99339..8152f7bfb5 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -17,8 +17,6 @@ INSTALL_BIN += xencov_split INSTALL_BIN += $(INSTALL_BIN-y) # Everything to be installed in regular sbin/ -INSTALL_SBIN += gtracestat -INSTALL_SBIN += gtraceview INSTALL_SBIN += xen-bugtool INSTALL_SBIN-$(CONFIG_MIGRATE) += xen-hptool INSTALL_SBIN-$(CONFIG_X86) += xen-hvmcrash @@ -85,9 +83,6 @@ xenperf: xenperf.o xenpm: xenpm.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) -gtracestat: gtracestat.o - $(CC) $(LDFLAGS) -o $@ $< $(APPEND_LDFLAGS) - xenlockprof: xenlockprof.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) @@ -110,9 +105,6 @@ xen-livepatch: xen-livepatch.o xen-lowmemd: xen-lowmemd.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenevtchn) $(LDLIBS_libxenctrl) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS) -gtraceview: gtraceview.o - $(CC) $(LDFLAGS) -o $@ $< $(CURSES_LIBS) $(TINFO_LIBS) $(APPEND_LDFLAGS) - xencov: xencov.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) diff --git a/tools/misc/gtracestat.c b/tools/misc/gtracestat.c deleted file mode 100644 index 67cb003084..0000000000 --- a/tools/misc/gtracestat.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* - * 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, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 **********/ -static void show_help(void); -static void show_version(void); -static int load_file(char *fname); -static void do_digest(uint64_t start, uint64_t end, uint64_t scale); -static void do_breakevents(void); -static void do_count(void); -static void do_px_count(void); -static void do_maxmin(void); -static void do_average(void); -static void do_exp_ratio(void); -static void do_exp_pred(void); - -/********** GLOBAL VARIABLES **********/ -/* store simplified xentrace data */ -static struct rec *data; -static int64_t data_nr, data_cur; -/* store max cx state number and cpu number */ -static int max_cx_num = -1, max_cpu_num = -1; -static int px_freq_table[MAX_PX_NR]; -static int max_px_num = 0; - -static int is_menu_gov_enabled = 0; - -/* user specified translation unit */ -static uint64_t tsc2ms = 2793000UL; -static uint64_t tsc2us = 2793UL; -static uint64_t tsc2phase = 55800000UL; - -/* each cpu column width */ -static int width = 0; - -/* digest mode variables */ -static struct rec *evt[MAX_CPU_NR]; -static 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 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 }, - }; - - if ( argc == 1 ) { - show_help(); - exit(EXIT_SUCCESS); - } - while (1) { - int ch, opt_idx; - ch = getopt_long(argc, argv, "vhds:e:l:bcmau:pn:zx", - 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; - break; - 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 -static 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; -} - -static void show_version(void) -{ - printf("gtracestat - (C) 2009-2011 Intel Corporation\n"); -} - -static void show_help(void) -{ - show_version(); - printf("gtracestat [-vhdselbcmau]\n"); - printf(" trace.data raw data got by 'xentrace -e 0x80f000 trace.dat'\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 specify start time (only in digest mode)\n"); - printf(" -e / --end specify end time (only in digest mode)\n"); - printf(" -l / --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. - */ -static 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 - */ -static 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; -} - -static 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) */ -static 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'); - } -} - -static 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; -}; - -static 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 - */ -static 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++; - } -} - -static 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; -} - -static uint64_t max_res[MAX_CPU_NR][MAX_CX_NR]; -static uint64_t min_res[MAX_CPU_NR][MAX_CX_NR]; -static uint64_t max_tm[MAX_CPU_NR][MAX_CX_NR]; -static uint64_t min_tm[MAX_CPU_NR][MAX_CX_NR]; - -static 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++; - } -} - -static 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"); - } -} - -static void do_count(void) -{ - uint64_t scale[100] = { 50UL, 100UL, 200UL, 400UL, 800UL, 1000UL }; - int a; - int scale_len = 6; - int len = 0; - int i, j; - - printf("Please input the period: (Ctrl+D to quit)\n"); - printf("The default is: 50 100 200 400 800 1000\n" - "(unit is us, DO NOT specify ZERO as any entry, keep entries in INCREASING order.)\n"); - while (scanf("%d", &a) == 1) { - scale[len++] = a; - scale_len = len; - } - for (i = 0; i < scale_len; i++) - scale[i] = scale[i] * tsc2us; - - 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++; - } -} - -static 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"); - } -} - -static 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"); - } - } -} - -static 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"); -} - -static 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]); - } -} - -static 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]); - } -} - -static 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 --git a/tools/misc/gtraceview.c b/tools/misc/gtraceview.c deleted file mode 100644 index 52190a5ac6..0000000000 --- a/tools/misc/gtraceview.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* - * 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, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* get curses header from configure */ -#include INCLUDE_CURSES_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 (!data_cur) { - fprintf(stderr, "file %s doesn't contain any valid record\n", 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 [--version] [--help]\n"); - printf(" trace.data raw data got by " - "'xentrace -e 0x80f000 trace.dat'\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 = 0; - int state_cur = 0; - - for (i = 0; i < max_cpu_num; i++) - cur_state[i].flag = FLAG_UNKNOWN; - - /* allocate spaces, it may be huge... */ - if (time_scale) - 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; - 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; - } - /* fallthrough */ - 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; -} -