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
^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/.*$
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
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)
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)
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#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 **********/
-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 <trace.data> [-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 <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 <tsc-per-us> specify how many tsc is a us unit\n");
- printf(" -p / --px operate on Px entries\n");
- printf(" -n / --tsc2phase <tsc-per-phase> 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);
-}
-
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.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>
-
-/* 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 <trace.data> [--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;
-}
-