debuggers.hg

annotate tools/misc/gtraceview.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 857d7b2dd8c7
children
rev   line source
keir@19906 1 /*
keir@19906 2 * gtraceview.c: list Cx events in a ncurse way to help find abnormal behaviour.
keir@19906 3 * Copyright (c) 2009, Intel Corporation.
keir@19906 4 *
keir@19906 5 * This program is free software; you can redistribute it and/or modify it
keir@19906 6 * under the terms and conditions of the GNU General Public License,
keir@19906 7 * version 2, as published by the Free Software Foundation.
keir@19906 8 *
keir@19906 9 * This program is distributed in the hope it will be useful, but WITHOUT
keir@19906 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
keir@19906 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
keir@19906 12 * more details.
keir@19906 13 *
keir@19906 14 * You should have received a copy of the GNU General Public License along with
keir@19906 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
keir@19906 16 * Place - Suite 330, Boston, MA 02111-1307 USA.
keir@19906 17 */
keir@19906 18
keir@19906 19 #include <stdio.h>
keir@19906 20 #include <stdlib.h>
keir@19906 21 #include <string.h>
keir@19922 22 #include <stdarg.h>
keir@19906 23 #include <unistd.h>
keir@19906 24 #include <fcntl.h>
keir@19906 25 #include <inttypes.h>
keir@19906 26 #include <sys/time.h>
keir@19906 27 #include <sys/types.h>
keir@19906 28 #include <sys/stat.h>
keir@19906 29
keir@19906 30 #include <xenctrl.h>
keir@19906 31 #include <xen/trace.h>
keir@19906 32
keir@19925 33 #ifdef __linux__
keir@19906 34 #include <ncurses.h>
keir@19922 35 #endif
keir@19922 36 #ifdef __NetBSD__
keir@19922 37 #include <curses.h>
keir@19922 38 #endif
keir@19906 39
keir@19906 40 /********** MACROS **********/
keir@19906 41 #define MAX_CPU_NR 32
keir@19906 42 #define MAX_MODE_NR 16
keir@19906 43 #define MAX_STRING_LEN 1024
keir@19906 44
keir@19906 45 /********** STRUCTURE DEFINITIONS **********/
keir@19906 46 enum {
keir@19906 47 FLAG_FUZZY = 0,
keir@19906 48 FLAG_LEVEL,
keir@19906 49 FLAG_EDGE,
keir@19906 50 FLAG_UNKNOWN,
keir@19906 51 NR_FLAGS
keir@19906 52 };
keir@19906 53
keir@19906 54 struct string {
keir@19906 55 int len;
keir@19906 56 char str[MAX_STRING_LEN+1];
keir@19906 57 };
keir@19906 58
keir@19906 59 int num_of_cpus(void);
keir@19906 60 void string_nr_addch(struct string *str, int nr, char ch)
keir@19906 61 {
keir@19906 62 int i;
keir@19906 63 for (i = 0; i < nr; i++)
keir@19906 64 str->str[str->len++] = ch;
keir@19906 65 str->str[str->len] = '\0';
keir@19906 66 }
keir@19906 67
keir@19906 68 int string_print(struct string *str, char *fmt, ...)
keir@19906 69 {
keir@19906 70 va_list ap;
keir@19906 71 int l = 0;
keir@19906 72
keir@19906 73 va_start(ap, fmt);
keir@19906 74 l = vsprintf(str->str + str->len, fmt, ap);
keir@19906 75 va_end(ap);
keir@19906 76 str->len += l;
keir@19906 77 str->str[str->len] = '\0';
keir@19906 78 return l;
keir@19906 79 }
keir@19906 80
keir@19906 81 struct cpu {
keir@19906 82 unsigned char cx;
keir@19906 83 // unsigned char cx_prev;
keir@19906 84 unsigned char flag;
keir@19906 85 unsigned char irqs[4];
keir@19906 86 unsigned int expected;
keir@19906 87 unsigned int predicted;
keir@19906 88 };
keir@19906 89
keir@19906 90 struct state {
keir@19906 91 uint64_t tsc;
keir@19906 92 struct cpu cpu[MAX_CPU_NR];
keir@19906 93 };
keir@19906 94
keir@19906 95 struct mode {
keir@19906 96 const char *name;
keir@19906 97 int offset;
keir@19906 98 int width;
keir@19906 99 int row;
keir@19906 100 int scroll_h;
keir@19906 101 struct state *state;
keir@19906 102 int state_nr;
keir@19906 103 uint64_t time_scale;
keir@19906 104 uint64_t start_time;
keir@19906 105 int cpu_bitmap[MAX_CPU_NR];
keir@19906 106 int initialized;
keir@19906 107 int (*init)(void);
keir@19906 108 void (*show)(void);
keir@19906 109 void (*exit)(void);
keir@19906 110 };
keir@19906 111
keir@19906 112 /* simplified xentrace record */
keir@19906 113 struct rec {
keir@19906 114 uint64_t tsc;
keir@19906 115 int cpu;
keir@19906 116 unsigned int expected;
keir@19906 117 unsigned int predicted;
keir@19906 118 unsigned char cx;
keir@19906 119 unsigned char irqs[4];
keir@19906 120 };
keir@19906 121
keir@19906 122 /********** FORWARD DECLARATION **********/
keir@19906 123 void show_help(void);
keir@19906 124 void show_version(void);
keir@19906 125 int load_file(char *fname);
keir@19906 126 void crt_init(void);
keir@19906 127 int mode_init(void);
keir@19906 128 void mode_show(void);
keir@19906 129
keir@19906 130 /* event mode handler */
keir@19906 131 int event_mode_init(void);
keir@19906 132 void event_mode_show(void);
keir@19906 133 void event_mode_exit(void);
keir@19906 134
keir@19906 135 /* time mode handler */
keir@19906 136 int time_mode_init(void);
keir@19906 137 int time_mode_rebuild(uint64_t start_time, uint64_t time_scale);
keir@19906 138
keir@19906 139 /********** GLOBAL VARIABLES **********/
keir@19906 140 /* store simplified xentrace data */
keir@19906 141 struct rec *data;
keir@19906 142 int64_t data_nr, data_cur;
keir@19906 143 /* store max cx state number and cpu number */
keir@19906 144 int max_cx_num = -1, max_cpu_num = -1;
keir@19906 145 int is_irq_enabled = -1;
keir@19906 146 int is_menu_gov_enabled = -1;
keir@19906 147 int is_link = 0;
keir@19906 148 uint64_t tsc2us = 2793UL;
keir@19906 149
keir@19906 150 struct rec *data_evt;
keir@19906 151 struct rec *evt[MAX_CPU_NR];
keir@19906 152 int evt_len[MAX_CPU_NR];
keir@19906 153
keir@19906 154 int cur_row = 0;
keir@19906 155 struct mode modes[] = {
keir@19906 156 {
keir@19906 157 .name = "Event",
keir@19906 158 .init = event_mode_init,
keir@19906 159 .show = event_mode_show,
keir@19906 160 .exit = event_mode_exit,
keir@19906 161 },
keir@19906 162 {
keir@19906 163 .name = "Time",
keir@19906 164 .init = time_mode_init,
keir@19906 165 /* use the same show and exit with event mode */
keir@19906 166 .show = event_mode_show,
keir@19906 167 .exit = event_mode_exit,
keir@19906 168 },
keir@19906 169 };
keir@19906 170 struct mode *this = NULL;
keir@19906 171
keir@19906 172 /* hand-crafted min() */
keir@19906 173 static inline int min(int a, int b)
keir@19906 174 {
keir@19906 175 return a < b ? a : b;
keir@19906 176 }
keir@19906 177
keir@19906 178 #define MIN(a, b) ((a) < (b) ? (a) : (b))
keir@19906 179
keir@19906 180 void choose_cpus(void);
keir@19906 181 void help_screen(void);
keir@19906 182 int main(int argc, char *argv[])
keir@19906 183 {
keir@19906 184 char *fname = NULL;
keir@19906 185 int arg;
keir@19906 186 int quit = 0;
keir@19906 187 uint64_t s_time = 0;
keir@19906 188 uint64_t last_tsc = 0;
keir@19906 189
keir@19906 190 for (arg = 1; arg < argc; arg++) {
keir@19906 191 if (!strcmp(argv[arg], "--version")) {
keir@19906 192 show_version();
keir@19906 193 exit(EXIT_SUCCESS);
keir@19906 194 } else if (!strcmp(argv[arg], "--help")) {
keir@19906 195 show_help();
keir@19906 196 exit(EXIT_SUCCESS);
keir@19906 197 } else {
keir@19906 198 /* assume it's a file */
keir@19906 199 fname = argv[arg];
keir@19906 200 break;
keir@19906 201 }
keir@19906 202 }
keir@19906 203
keir@19906 204 if (!fname) {
keir@19906 205 show_help();
keir@19906 206 exit(EXIT_FAILURE);
keir@19906 207 }
keir@19906 208
keir@19906 209 if (load_file(fname))
keir@19906 210 exit(EXIT_FAILURE);
keir@19906 211
keir@20919 212 if (!data_cur) {
keir@20919 213 fprintf(stderr, "file %s doesn't contain any valid record\n", fname);
keir@20919 214 exit(EXIT_FAILURE);
keir@20919 215 }
keir@20919 216
keir@19906 217 if (mode_init())
keir@19906 218 exit(EXIT_FAILURE);
keir@19906 219
keir@19906 220 crt_init();
keir@19906 221
keir@19906 222 cur_row = 1;
keir@19906 223 this = &modes[0];
keir@19906 224 while (!quit) {
keir@19906 225 int ch;
keir@19906 226
keir@19906 227 clear();
keir@19906 228 this->show();
keir@19906 229 ch = getch();
keir@19906 230 switch (ch) {
keir@19906 231 case '!':
keir@19906 232 is_link = !is_link;
keir@19906 233 break;
keir@19906 234 case 'u':
keir@19906 235 move(LINES-1, 0);
keir@19906 236 clrtoeol();
keir@19906 237 printw("us = ? TSCs (default: 2793):");
keir@19906 238 echo();
keir@19906 239 curs_set(1);
keir@19906 240 scanw("%"PRIu64, &tsc2us);
keir@19906 241 curs_set(0);
keir@19906 242 noecho();
keir@19906 243 if (tsc2us <= 0)
keir@19906 244 tsc2us = 2793UL;
keir@19906 245 break;
keir@19906 246 case '/':
keir@19906 247 move(LINES-1, 0);
keir@19906 248 clrtoeol();
keir@19906 249 printw("Input start time:");
keir@19906 250 echo();
keir@19906 251 curs_set(1);
keir@19906 252 scanw("%"PRIu64, &s_time);
keir@19906 253 curs_set(0);
keir@19906 254 noecho();
keir@19906 255 if (s_time >= this->state[0].tsc &&
keir@19906 256 s_time <= this->state[this->state_nr-1].tsc) {
keir@19906 257 int i = 0;
keir@19906 258 while (i < this->state_nr &&
keir@19906 259 this->state[i].tsc < s_time)
keir@19906 260 i++;
keir@19906 261 this->row = i;
keir@19906 262 cur_row = 1;
keir@19906 263 }
keir@19906 264 break;
keir@19906 265 case '+':
keir@19906 266 if (!strcmp(this->name, "Time")) {
keir@19906 267 this->time_scale -= this->time_scale/10;
keir@19906 268 this->start_time = this->state[this->row+cur_row-1].tsc - (cur_row-1)*this->time_scale;
keir@19906 269 if (this->start_time < data[0].tsc)
keir@19906 270 this->start_time = data[0].tsc;
keir@19906 271 time_mode_rebuild(this->start_time, this->time_scale);
keir@19906 272 }
keir@19906 273 break;
keir@19906 274 case '-':
keir@19906 275 if (!strcmp(this->name, "Time")) {
keir@19906 276 this->time_scale += this->time_scale/10;
keir@19906 277 this->start_time = this->state[this->row+cur_row-1].tsc - (cur_row-1)*this->time_scale;
keir@19906 278 if (this->start_time < data[0].tsc)
keir@19906 279 this->start_time = data[0].tsc;
keir@19906 280 time_mode_rebuild(this->start_time, this->time_scale);
keir@19906 281 }
keir@19906 282 break;
keir@19906 283 case KEY_RESIZE:
keir@19906 284 break;
keir@19906 285 case KEY_UP:
keir@19906 286 if (--cur_row < 1) {
keir@19906 287 cur_row = 1;
keir@19906 288 if (--this->row < 0)
keir@19906 289 this->row = 0;
keir@19906 290 }
keir@19906 291 break;
keir@19906 292 case KEY_DOWN:
keir@19906 293 if (++cur_row > LINES-2) {
keir@19906 294 cur_row = LINES-2;
keir@19906 295 this->row = min(this->state_nr-LINES+2, this->row+1);
keir@19906 296 }
keir@19906 297 break;
keir@19906 298 case KEY_LEFT:
keir@19906 299 this->scroll_h -= 3;
keir@19906 300 if (this->scroll_h < 0)
keir@19906 301 this->scroll_h = 0;
keir@19906 302 break;
keir@19906 303 case KEY_RIGHT:
keir@19906 304 this->scroll_h += 3;
keir@19906 305 if (this->scroll_h >= this->width*num_of_cpus())
keir@19906 306 this->scroll_h = this->width*num_of_cpus();
keir@19906 307 break;
keir@19906 308 case KEY_HOME:
keir@19906 309 cur_row = 1;
keir@19906 310 this->row = 0;
keir@19906 311 break;
keir@19906 312 case KEY_END:
keir@19906 313 cur_row = LINES-2;
keir@19906 314 this->row = this->state_nr-LINES+2;
keir@19906 315 break;
keir@19906 316 case KEY_NPAGE:
keir@19906 317 this->row = min(this->state_nr-LINES+2, this->row+20);
keir@19906 318 break;
keir@19906 319 case KEY_PPAGE:
keir@19906 320 if (this->row >= 20)
keir@19906 321 this->row -= 20;
keir@19906 322 break;
keir@19906 323 case KEY_F(2):
keir@19906 324 /* change to another mode */
keir@19906 325 if (is_link)
keir@19906 326 last_tsc = this->state[this->row+cur_row-1].tsc;
keir@19906 327
keir@19906 328 if (this == &modes[sizeof(modes)/sizeof(modes[0])-1])
keir@19906 329 this = &modes[0];
keir@19906 330 else
keir@19906 331 this++;
keir@19906 332 clear();
keir@19906 333 if (is_link) {
keir@19906 334 if (!strcmp(this->name, "Time")) {
keir@19906 335 this->start_time = last_tsc - (cur_row-1)*this->time_scale;
keir@19906 336 if (this->start_time < data[0].tsc)
keir@19906 337 this->start_time = data[0].tsc;
keir@19906 338 time_mode_rebuild(this->start_time, this->time_scale);
keir@19906 339 } else if (!strcmp(this->name, "Event")) {
keir@19906 340 int x;
keir@19906 341 for (x = 0; x < this->state_nr && this->state[x].tsc < last_tsc; x++)
keir@19906 342 ;
keir@19906 343 this->row = x-(cur_row-1);
keir@19906 344 }
keir@19906 345 }
keir@19906 346 break;
keir@19906 347 case KEY_F(3):
keir@19906 348 if (!strcmp(this->name, "Time")) {
keir@19906 349 /* only meaningful in Time mode */
keir@19906 350 move(LINES-1, 0);
keir@19906 351 clrtoeol();
keir@19906 352 printw("Input time scale and start time:");
keir@19906 353 echo();
keir@19906 354 curs_set(1);
keir@19906 355 scanw("%"PRIu64" %"PRIu64,
keir@19906 356 &this->time_scale, &this->start_time);
keir@19906 357 curs_set(0);
keir@19906 358 noecho();
keir@19906 359 time_mode_rebuild(this->start_time,
keir@19906 360 this->time_scale);
keir@19906 361 }
keir@19906 362 break;
keir@19906 363 case KEY_F(4):
keir@19906 364 /* quit */
keir@19906 365 quit = 1;
keir@19906 366 break;
keir@19906 367 case KEY_F(5):
keir@19906 368 /* choose which CPUs to display */
keir@19906 369 choose_cpus();
keir@19906 370 break;
keir@19906 371 case 'h':
keir@19906 372 help_screen();
keir@19906 373 break;
keir@19906 374 }
keir@19906 375 }
keir@19906 376
keir@19906 377 exit(EXIT_SUCCESS);
keir@19906 378 }
keir@19906 379 /* used for qsort() */
keir@19906 380 static int evt_data_cmp(const void *_a, const void *_b)
keir@19906 381 {
keir@19906 382 struct rec *a = (struct rec *)_a;
keir@19906 383 struct rec *b = (struct rec *)_b;
keir@19906 384 if (a->cpu == b->cpu)
keir@19906 385 return a->tsc > b->tsc ? 1 : -1;
keir@19906 386 return a->cpu > b->cpu ? 1 : -1;
keir@19906 387 }
keir@19906 388
keir@19906 389 static int data_cmp(const void *_a, const void *_b)
keir@19906 390 {
keir@19906 391 struct rec *a = (struct rec *)_a;
keir@19906 392 struct rec *b = (struct rec *)_b;
keir@19906 393 return a->tsc > b->tsc ? 1 : -1;
keir@19906 394 }
keir@19906 395
keir@19906 396 /* load file and make them a list of records
keir@19906 397 * update these following variables:
keir@19906 398 * data, data_cur, data_nr
keir@19906 399 * max_cpu_num, max_cx_num
keir@19906 400 */
keir@19906 401 int load_file(char *fname)
keir@19906 402 {
keir@19906 403 /* file descriptor for raw xentrace file */
keir@19906 404 int fd;
keir@19906 405 /* current cpu during xentrace data parse */
keir@19906 406 int cur_cpu = -1;
keir@19906 407 int i;
keir@19906 408
keir@19906 409 fd = open(fname, O_RDONLY);
keir@19906 410 if (fd < 0) {
keir@19906 411 fprintf(stderr, "file %s cannot open\n", fname);
keir@19906 412 return 1;
keir@19906 413 }
keir@19906 414
keir@19906 415 /* the initial number is 1024,
keir@19906 416 * and when it overflows, this number doubles.
keir@19906 417 */
keir@19906 418 data_nr = 1024;
keir@19906 419 data_cur = 0;
keir@19906 420 data = malloc(sizeof(struct rec) * data_nr);
keir@19906 421 if (!data) {
keir@19906 422 fprintf(stderr, "not enough memory\n");
keir@19906 423 close(fd);
keir@19906 424 return 1;
keir@19906 425 }
keir@19906 426
keir@19906 427 while (1) {
keir@19906 428 struct t_rec rec;
keir@19906 429 ssize_t ret, size;
keir@19906 430
keir@19906 431 ret = read(fd, &rec, sizeof(uint32_t));
keir@19906 432 if (!ret)
keir@19906 433 break;
keir@19906 434 if (ret != sizeof(uint32_t)) {
keir@19906 435 fprintf(stderr, "reading header error\n");
keir@19906 436 break;
keir@19906 437 }
keir@19906 438
keir@19906 439 size = 0;
keir@19906 440 if (rec.cycles_included)
keir@19906 441 size += sizeof(uint64_t);
keir@19906 442 size += sizeof(uint32_t) * rec.extra_u32;
keir@19906 443
keir@19906 444 ret = read(fd, (char *)&rec + sizeof(uint32_t), size);
keir@19906 445 if (!ret && size)
keir@19906 446 break;
keir@19906 447 if (ret != size) {
keir@19906 448 fprintf(stderr, "reading data error\n");
keir@19906 449 break;
keir@19906 450 }
keir@19906 451
keir@19906 452 if (rec.event == 0x1f003) {
keir@19906 453 /* cpu change event */
keir@19906 454 cur_cpu = 0;
keir@19906 455 if (rec.extra_u32 > 0)
keir@19906 456 cur_cpu = rec.u.nocycles.extra_u32[0];
keir@19906 457 continue;
keir@19906 458 } else if (!rec.cycles_included ||
keir@19906 459 (rec.event != TRC_PM_IDLE_ENTRY &&
keir@19906 460 rec.event != TRC_PM_IDLE_EXIT &&
keir@19906 461 rec.event != TRC_PM_FREQ_CHANGE)) {
keir@19906 462 continue;
keir@19906 463 }
keir@19906 464
keir@19906 465 /* add one record */
keir@19906 466 if (data_cur == data_nr) {
keir@19906 467 data_nr <<= 1;
keir@19906 468 if (data_nr < 0) {
keir@19906 469 fprintf(stderr, "too many entries\n");
keir@19906 470 close(fd);
keir@19906 471 return 1;
keir@19906 472 }
keir@19906 473 data = realloc(data, sizeof(struct rec) * data_nr);
keir@19906 474 if (!data) {
keir@19906 475 fprintf(stderr, "not enough memory\n");
keir@19906 476 close(fd);
keir@19906 477 return 1;
keir@19906 478 }
keir@19906 479 }
keir@19906 480 data[data_cur].tsc = rec.u.cycles.cycles_hi;
keir@19906 481 data[data_cur].tsc <<= 32;
keir@19906 482 data[data_cur].tsc |= rec.u.cycles.cycles_lo;
keir@19906 483 data[data_cur].cpu = cur_cpu;
keir@19906 484 /* extra_u32[1] is omitted, as it's pm ticks. */
keir@19906 485 if (rec.event == TRC_PM_IDLE_ENTRY) {
keir@19906 486 data[data_cur].cx = rec.u.cycles.extra_u32[0];
keir@19906 487 if (rec.extra_u32 >= 4) {
keir@19906 488 data[data_cur].expected = rec.u.cycles.extra_u32[2];
keir@19906 489 data[data_cur].predicted = rec.u.cycles.extra_u32[3];
keir@19906 490 is_menu_gov_enabled = 1;
keir@19906 491 } else
keir@19906 492 is_menu_gov_enabled = 0;
keir@19906 493 } else if (rec.event == TRC_PM_IDLE_EXIT) {
keir@19906 494 /* IDLE_EXIT default to C0 */
keir@19906 495 data[data_cur].cx = 0;
keir@19906 496 /* store the reasons why it exits */
keir@19906 497 if (rec.extra_u32 == 6) {
keir@19906 498 data[data_cur].irqs[0] = rec.u.cycles.extra_u32[2];
keir@19906 499 data[data_cur].irqs[1] = rec.u.cycles.extra_u32[3];
keir@19906 500 data[data_cur].irqs[2] = rec.u.cycles.extra_u32[4];
keir@19906 501 data[data_cur].irqs[3] = rec.u.cycles.extra_u32[5];
keir@19906 502 is_irq_enabled = 1;
keir@19906 503 } else
keir@19906 504 is_irq_enabled = 0;
keir@19906 505 } else {
keir@19906 506 /* FREQ CHANGE */
keir@19906 507 }
keir@19906 508
keir@19906 509 /* update max info */
keir@19906 510 if (data[data_cur].cx > max_cx_num)
keir@19906 511 max_cx_num = data[data_cur].cx;
keir@19906 512 if (data[data_cur].cpu > max_cpu_num)
keir@19906 513 max_cpu_num = data[data_cur].cpu;
keir@19906 514
keir@19906 515 data_cur++;
keir@19906 516 }
keir@19906 517 close(fd);
keir@19906 518
keir@19906 519 data_evt = malloc(sizeof(struct rec) * data_cur);
keir@19906 520 memcpy(data_evt, data, sizeof(struct rec) * data_cur);
keir@19906 521
keir@19906 522 qsort(data_evt, data_cur, sizeof(struct rec), evt_data_cmp);
keir@19906 523 for (i = 0; i < max_cpu_num; i++) {
keir@19906 524 evt_len[i] = 0;
keir@19906 525 evt[i] = NULL;
keir@19906 526 }
keir@19906 527 for (i = data_cur-1; i >= 0; i--) {
keir@19906 528 evt[data_evt[i].cpu] = data_evt+i;
keir@19906 529 evt_len[data_evt[i].cpu]++;
keir@19906 530 }
keir@19906 531
keir@19906 532 /* sort data array according to TSC time line */
keir@19906 533 qsort(data, data_cur, sizeof(struct rec), data_cmp);
keir@19906 534
keir@19906 535 max_cpu_num++;
keir@19906 536 max_cx_num++;
keir@19906 537
keir@19906 538 return 0;
keir@19906 539 }
keir@19906 540
keir@19906 541 void show_version(void)
keir@19906 542 {
keir@19906 543 printf("gtraceview - (C) 2009 Intel Corporation\n");
keir@19906 544 }
keir@19906 545
keir@19906 546 void show_help(void)
keir@19906 547 {
keir@19906 548 show_version();
keir@19906 549 printf("gtraceview <trace.data> [--version] [--help]\n");
keir@20121 550 printf(" trace.data raw data got by "
keir@20121 551 "'xentrace -e 0x80f000 trace.dat'\n");
keir@19906 552 printf(" --version show version information\n");
keir@19906 553 printf(" --help show this message\n");
keir@19906 554 printf("For more help messages, please press 'h' in the window\n");
keir@19906 555 }
keir@19906 556
keir@19906 557 void crt_done(void)
keir@19906 558 {
keir@19906 559 curs_set(1);
keir@19906 560 endwin();
keir@19906 561 }
keir@19906 562
keir@19906 563 void help_screen(void)
keir@19906 564 {
keir@19906 565 clear();
keir@19906 566 mvprintw(0, 0, " HELP SCREEN");
keir@19906 567 mvprintw(1, 0, "1. LEFT and RIGHT arrow key to move off-screen outputs");
keir@19906 568 mvprintw(2, 0, "2. UP and DOWN arrow key to move the highlighted line");
keir@19906 569 mvprintw(3, 0, "3. F2 to switch between Event and Time mode");
keir@19906 570 mvprintw(4, 0, "4. '/' to search the TSC stamp");
keir@19906 571 mvprintw(5, 0, "5. '+' to zoom in and '-' to zoom out");
keir@19906 572 mvprintw(6, 0, "6. F3 to set start time and time manually");
keir@19906 573 mvprintw(7, 0, "7. F4 to quit");
keir@19906 574 mvprintw(8, 0, "8. F5 to select which CPUs we want to see");
keir@19906 575 mvprintw(9, 0, "9. Irq exit reason shown on Cx exit record (patch needed)");
keir@19906 576 mvprintw(10, 0, "10. Menu governor criteria shown on bottom line (patch needed)");
keir@19906 577 mvprintw(11, 0, "11. PAGEDOWN, PAGEUP, HOME and END to navigate");
keir@19906 578 mvprintw(12, 0, "12. 'h' to show this screen");
keir@19906 579 mvprintw(13, 0, "13. 'u' to edit how many TSCs is a us unit");
keir@19906 580
keir@19906 581 mvprintw(LINES-1, 0, "Press any key to continue...");
keir@19906 582 getch();
keir@19906 583 }
keir@19906 584
keir@19906 585 void crt_init(void)
keir@19906 586 {
keir@19906 587 char *term;
keir@19906 588
keir@19906 589 initscr();
keir@19906 590 noecho();
keir@19906 591 nonl();
keir@19906 592 intrflush(stdscr, false);
keir@19906 593 keypad(stdscr, true);
keir@19906 594 curs_set(0);
keir@19906 595 /* hook exit() */
keir@19906 596 atexit(crt_done);
keir@19906 597 /* we love colorful screens :-) */
keir@19906 598 start_color();
keir@19906 599 init_pair(1, COLOR_BLACK, COLOR_CYAN);
keir@19906 600 init_pair(2, COLOR_BLACK, COLOR_GREEN);
keir@19906 601 init_pair(3, COLOR_BLACK, COLOR_RED);
keir@19906 602
keir@19906 603 /* some term tunings */
keir@19906 604 term = getenv("TERM");
keir@19906 605 if (!strcmp(term, "xterm") ||
keir@19906 606 !strcmp(term, "xterm-color") ||
keir@19906 607 !strcmp(term, "vt220")) {
keir@19906 608 define_key("\033[1~", KEY_HOME);
keir@19906 609 define_key("\033[4~", KEY_END);
keir@19906 610 define_key("\033OP", KEY_F(1));
keir@19906 611 define_key("\033OQ", KEY_F(2));
keir@19906 612 define_key("\033OR", KEY_F(3));
keir@19906 613 define_key("\033OS", KEY_F(4));
keir@19906 614 define_key("\033[11~", KEY_F(1));
keir@19906 615 define_key("\033[12~", KEY_F(2));
keir@19906 616 define_key("\033[13~", KEY_F(3));
keir@19906 617 define_key("\033[14~", KEY_F(4));
keir@19906 618 define_key("\033[[D", KEY_LEFT);
keir@19906 619 }
keir@19906 620 }
keir@19906 621
keir@19906 622 void nr_addch(int nr, int ch)
keir@19906 623 {
keir@19906 624 int i;
keir@19906 625 int y, x;
keir@19906 626 getyx(stdscr, y, x);
keir@19906 627 for (i = 0; i < nr; i++) {
keir@19906 628 if (x == COLS-1)
keir@19906 629 break;
keir@19906 630 addch(ch);
keir@19906 631 }
keir@19906 632 }
keir@19906 633
keir@19906 634 int event_mode_init(void)
keir@19906 635 {
keir@19906 636 int i, j;
keir@19906 637 struct state *state;
keir@19906 638 int index;
keir@19906 639 struct cpu cur_state[MAX_CPU_NR];
keir@19906 640
keir@19906 641 if (this->initialized)
keir@19906 642 free(this->state);
keir@19906 643 state = malloc(sizeof(struct state) * data_cur);
keir@19906 644 if (!state)
keir@19906 645 return 1;
keir@19906 646 this->state = state;
keir@19906 647 this->row = 0;
keir@19906 648 this->width = 9;
keir@19906 649 this->offset = 33;
keir@19906 650 this->scroll_h = 0;
keir@19906 651
keir@19906 652 /* otherwise, respect cpu_bitmap[] */
keir@19906 653 if (!this->initialized) {
keir@19906 654 this->initialized = 1;
keir@19906 655 for (i = 0; i < max_cpu_num; i++)
keir@19906 656 this->cpu_bitmap[i] = 1;
keir@19906 657 }
keir@19906 658
keir@19906 659 for (i = 0; i < max_cpu_num; i++)
keir@19906 660 if (this->cpu_bitmap[i])
keir@19906 661 cur_state[i].flag = FLAG_UNKNOWN;
keir@19906 662
keir@19906 663 for (i = 0, index = 0; i < data_cur; i++) {
keir@19906 664 /* data[i] */
keir@19906 665 int cpu = data[i].cpu;
keir@19906 666 if (cpu < 0)
keir@19906 667 continue;
keir@19906 668 if (!this->cpu_bitmap[cpu])
keir@19906 669 continue;
keir@19906 670
keir@19906 671 /* TODO: use the same structure */
keir@19906 672 /* copy cx, expected, predicted and irqs */
keir@19906 673 cur_state[cpu].cx = data[i].cx;
keir@19906 674 cur_state[cpu].expected = data[i].expected;
keir@19906 675 cur_state[cpu].predicted = data[i].predicted;
keir@19906 676 memcpy(cur_state[cpu].irqs, data[i].irqs,
keir@19906 677 sizeof(unsigned char) * 4);
keir@19906 678 /* as long as it comes here,
keir@19906 679 * it means that we have an event.
keir@19906 680 */
keir@19906 681 cur_state[cpu].flag = FLAG_EDGE;
keir@19906 682
keir@19906 683 state[index].tsc = data[i].tsc;
keir@19906 684 for (j = 0; j < max_cpu_num; j++) {
keir@19906 685 if (!this->cpu_bitmap[j])
keir@19906 686 continue;
keir@19906 687
keir@19906 688 /* copy cx, irqs and flags */
keir@19906 689 state[index].cpu[j].cx = cur_state[j].cx;
keir@19906 690 state[index].cpu[j].expected = cur_state[j].expected;
keir@19906 691 state[index].cpu[j].predicted = cur_state[j].predicted;
keir@19906 692 memcpy(state[index].cpu[j].irqs, cur_state[j].irqs,
keir@19906 693 sizeof(unsigned char) * 4);
keir@19906 694 state[index].cpu[j].flag = cur_state[j].flag;
keir@19906 695
keir@19906 696 /* chage flag in cur_state accordingly */
keir@19906 697 if (cur_state[j].flag == FLAG_EDGE)
keir@19906 698 cur_state[j].flag = FLAG_LEVEL;
keir@19906 699 }
keir@19906 700 index++;
keir@19906 701 }
keir@19906 702
keir@19906 703 this->state_nr = index;
keir@19906 704 return 0;
keir@19906 705 }
keir@19906 706
keir@19906 707 static inline int len_of_number(uint64_t n)
keir@19906 708 {
keir@19906 709 int l = 0;
keir@19906 710 if (!n)
keir@19906 711 return 1;
keir@19906 712 do {
keir@19906 713 l++;
keir@19906 714 n /= 10;
keir@19906 715 } while (n);
keir@19906 716 return l;
keir@19906 717 }
keir@19906 718
keir@19906 719 static inline void display_number(uint64_t n, int l)
keir@19906 720 {
keir@19906 721 static char sym[] = { ' ', 'K', 'M', 'G', 'T' };
keir@19906 722 int nr = 0;
keir@19906 723
keir@19906 724 if (len_of_number(n) <= l) {
keir@19906 725 nr_addch(l-len_of_number(n), ' ');
keir@19906 726 printw("%"PRIu64, n);
keir@19906 727 return;
keir@19906 728 }
keir@19906 729 do {
keir@19906 730 n /= 1000UL;
keir@19906 731 nr++;
keir@19906 732 } while (len_of_number(n) > l-1);
keir@19906 733 nr_addch(l-1-len_of_number(n), ' ');
keir@19906 734 printw("%"PRIu64, n);
keir@19906 735 nr_addch(1, sym[nr]);
keir@19906 736 }
keir@19906 737
keir@19906 738 void draw_cpu_state(struct string *s, struct cpu *c, int width)
keir@19906 739 {
keir@19906 740 int cx = c->cx;
keir@19906 741 int flag = c->flag;
keir@19906 742
keir@19906 743 switch (flag) {
keir@19906 744 case FLAG_FUZZY:
keir@19906 745 string_nr_addch(s, max_cx_num, '#');
keir@19906 746 string_nr_addch(s, width-max_cx_num, ' ');
keir@19906 747 break;
keir@19906 748 case FLAG_UNKNOWN:
keir@19906 749 string_nr_addch(s, 1, '?');
keir@19906 750 string_nr_addch(s, width-1, ' ');
keir@19906 751 break;
keir@19906 752 case FLAG_LEVEL:
keir@19906 753 string_nr_addch(s, cx, ' ');
keir@19906 754 string_nr_addch(s, 1, '|');
keir@19906 755 string_nr_addch(s, width-1-cx, ' ');
keir@19906 756 break;
keir@19906 757 case FLAG_EDGE:
keir@19906 758 if (cx > 0) {
keir@19906 759 /* ENTRY */
keir@19906 760 string_nr_addch(s, 1, '>');
keir@19906 761 string_nr_addch(s, cx-1, '-');
keir@19906 762 string_nr_addch(s, 1, '+');
keir@19906 763 string_nr_addch(s, width-cx-1, ' ');
keir@19906 764 } else {
keir@19906 765 /* EXIT */
keir@19906 766 string_nr_addch(s, 1, '<');
keir@19906 767 if (is_irq_enabled == 1) {
keir@19906 768 int k, len = 0;
keir@19906 769 for (k = 0; k < 4; k++) {
keir@19906 770 unsigned char irq = c->irqs[k];
keir@19906 771 if (irq) {
keir@19906 772 string_print(s, "%02x", irq);
keir@19906 773 len += 2;
keir@19906 774 }
keir@19906 775 }
keir@19906 776 if (len > 0)
keir@19906 777 string_nr_addch(s, width-len-1, ' ');
keir@19906 778 else {
keir@19906 779 string_print(s, "noirq");
keir@19906 780 string_nr_addch(s, width-1-5, ' ');
keir@19906 781 }
keir@19906 782 } else {
keir@19906 783 string_nr_addch(s, 1, '-');
keir@19906 784 string_nr_addch(s, width-2, ' ');
keir@19906 785 }
keir@19906 786 }
keir@19906 787 break;
keir@19906 788 }
keir@19906 789 }
keir@19906 790
keir@19906 791 void event_mode_show(void)
keir@19906 792 {
keir@19906 793 struct state *state = this->state;
keir@19906 794 struct string s;
keir@19906 795 int idx = this->row;
keir@19906 796 int idx_hl = 0;
keir@19906 797 int i, j, l;
keir@19906 798
keir@19906 799 /* draw headline */
keir@19906 800 s.len = 0;
keir@19906 801 move(0, 0);
keir@19906 802 attron(COLOR_PAIR(2));
keir@19906 803 nr_addch(this->offset, ' ');
keir@19906 804 for (i = 0; i < max_cpu_num; i++) {
keir@19906 805 if (this->cpu_bitmap[i]) {
keir@19906 806 string_print(&s, "CPU%d", i);
keir@19906 807 string_nr_addch(&s, this->width-len_of_number(i)-3, ' ');
keir@19906 808 }
keir@19906 809 }
keir@19906 810 mvaddnstr(0, this->offset, s.str+this->scroll_h,
keir@19906 811 MIN(s.len-this->scroll_h, this->width*num_of_cpus()));
keir@19906 812 attroff(COLOR_PAIR(2));
keir@19906 813
keir@19906 814 /* draw body */
keir@19906 815 for (i = 1; i < LINES-1; i++, idx++) {
keir@19906 816 move(i, 0);
keir@19906 817 /* highlight the current row */
keir@19906 818 if (i == cur_row) {
keir@19906 819 attron(COLOR_PAIR(1));
keir@19906 820 idx_hl = idx;
keir@19906 821 }
keir@19906 822
keir@19906 823 if (idx >= this->state_nr) {
keir@19906 824 /* do not show this line */
keir@19906 825 nr_addch(this->offset+this->width*num_of_cpus(), ' ');
keir@19906 826 } else {
keir@19906 827 if (!strcmp(this->name, "Event")) {
keir@19906 828 uint64_t delta = 0;
keir@19906 829 if (idx)
keir@19906 830 delta = (state[idx].tsc - state[idx-1].tsc)/tsc2us;
keir@19906 831 printw("%20"PRIu64"(", state[idx].tsc);
keir@19906 832 display_number(delta, 8);
keir@19906 833 printw("us) ");
keir@19906 834 } else if (!strcmp(this->name, "Time")) {
keir@19906 835 printw("%20"PRIu64" ", state[idx].tsc);
keir@19906 836 }
keir@19906 837
keir@19906 838 s.len = 0;
keir@19906 839 for (j = 0; j < max_cpu_num; j++) {
keir@19906 840 /* draw cpu state */
keir@19906 841 if (this->cpu_bitmap[j])
keir@19906 842 draw_cpu_state(&s, &state[idx].cpu[j], this->width);
keir@19906 843 }
keir@19906 844 /* draw the line accordingly */
keir@19906 845 mvaddnstr(i, this->offset, s.str+this->scroll_h,
keir@19906 846 MIN(s.len-this->scroll_h, this->width*num_of_cpus()));
keir@19906 847 }
keir@19906 848 /* pair of the highlight logics */
keir@19906 849 if (i == cur_row)
keir@19906 850 attroff(COLOR_PAIR(1));
keir@19906 851 }
keir@19906 852
keir@19906 853 /* draw tail line */
keir@19906 854 attron(COLOR_PAIR(2));
keir@19906 855 s.len = 0;
keir@19906 856 l = 0;
keir@19906 857 l += string_print(&s, "%s Mode [%sLINKED]", this->name, is_link ? "" : "NOT ");
keir@19906 858 if (!strcmp(this->name, "Time")) {
keir@19906 859 #if 0
keir@19906 860 l += string_print(&s, " [%"PRIu64":%"PRIu64"]",
keir@19906 861 this->start_time, this->time_scale);
keir@19906 862 #endif
keir@19906 863 l += string_print(&s, " [%"PRIu64"]",
keir@19906 864 this->time_scale);
keir@19906 865 }
keir@19906 866 if (is_menu_gov_enabled == 1) {
keir@19906 867 for (i = 0; i < max_cpu_num; i++) {
keir@19906 868 if (this->cpu_bitmap[i] &&
keir@19906 869 state[idx_hl].cpu[i].flag == FLAG_EDGE &&
keir@19906 870 state[idx_hl].cpu[i].cx > 0)
keir@19906 871 l += string_print(&s, " (CPU%d,%lu,%lu)",
keir@19906 872 i,
keir@19906 873 state[idx_hl].cpu[i].expected,
keir@19906 874 state[idx_hl].cpu[i].predicted);
keir@19906 875 }
keir@19906 876 }
keir@19906 877 /* add cx exit residency info */
keir@19906 878 for (i = 0; i < max_cpu_num; i++) {
keir@19906 879 if (this->cpu_bitmap[i] &&
keir@19906 880 state[idx_hl].cpu[i].flag == FLAG_EDGE &&
keir@19906 881 state[idx_hl].cpu[i].cx == 0) {
keir@19906 882 uint64_t tsc = state[idx_hl].tsc;
keir@19906 883 int k;
keir@19906 884
keir@19906 885 k = 0;
keir@19906 886 while (k < evt_len[i] &&
keir@19906 887 evt[i][k].tsc < tsc)
keir@19906 888 k++;
keir@19906 889 k--;
keir@19906 890 if (k >= 0 && k+1 < evt_len[i] && evt[i][k].cx > 0) {
keir@19906 891 l += string_print(&s, " (CPU%d, %"PRIu64"us)",
keir@19906 892 i,
keir@19906 893 (evt[i][k+1].tsc - evt[i][k].tsc)/tsc2us);
keir@19906 894 }
keir@19906 895 }
keir@19906 896 }
keir@19906 897
keir@19906 898 string_nr_addch(&s, this->offset+this->width*num_of_cpus()-l, ' ');
keir@19906 899 mvaddstr(LINES-1, 0, s.str);
keir@19906 900 attroff(COLOR_PAIR(2));
keir@19906 901 refresh();
keir@19906 902 }
keir@19906 903
keir@19906 904 void event_mode_exit(void)
keir@19906 905 {
keir@19906 906 free(this->state);
keir@19906 907 this->initialized = 0;
keir@19906 908 }
keir@19906 909
keir@19906 910 void mode_exit(void)
keir@19906 911 {
keir@19906 912 int nr = sizeof(modes)/sizeof(modes[0]);
keir@19906 913 int i;
keir@19906 914
keir@19906 915 for (i = 0; i < nr; i++) {
keir@19906 916 this = &modes[i];
keir@19906 917 if (this->initialized)
keir@19906 918 this->exit();
keir@19906 919 }
keir@19906 920 }
keir@19906 921
keir@19906 922 int mode_init(void)
keir@19906 923 {
keir@19906 924 int nr = sizeof(modes)/sizeof(modes[0]);
keir@19906 925 int i, r = 0;
keir@19906 926
keir@19906 927 for (i = 0; i < nr; i++) {
keir@19906 928 this = &modes[i];
keir@19906 929 this->initialized = 0;
keir@19906 930 r += this->init();
keir@19906 931 }
keir@19906 932
keir@19906 933 this = &modes[0];
keir@19906 934
keir@19906 935 /* hook into exit */
keir@19906 936 atexit(mode_exit);
keir@19906 937
keir@19906 938 return r;
keir@19906 939 }
keir@19906 940
keir@19906 941 int time_mode_rebuild(uint64_t start_time, uint64_t time_scale)
keir@19906 942 {
keir@19906 943 int i, j;
keir@19906 944 struct cpu cur_state[MAX_CPU_NR];
keir@19906 945 uint64_t tsc = start_time;
keir@19906 946 struct state *state;
keir@20919 947 uint64_t number, temp = 0;
keir@19906 948 int state_cur = 0;
keir@19906 949
keir@19906 950 for (i = 0; i < max_cpu_num; i++)
keir@19906 951 cur_state[i].flag = FLAG_UNKNOWN;
keir@19906 952
keir@19906 953 /* allocate spaces, it may be huge... */
keir@20919 954 if (time_scale)
keir@20919 955 temp = (data[data_cur-1].tsc - start_time)/time_scale;
keir@19906 956 number = 10000UL;
keir@19906 957 if (temp < number)
keir@19906 958 number = temp;
keir@19906 959 number += 2;
keir@19906 960 state = malloc(sizeof(struct state) * number);
keir@19906 961 if (!state)
keir@19906 962 return 1;
keir@19906 963 if (this->state)
keir@19906 964 free(this->state);
keir@19906 965 this->state = state;
keir@19906 966 this->width = 9;
keir@19906 967 this->row = 0;
keir@19906 968
keir@19906 969 /* determine the current Cx state */
keir@19906 970 /* check [data[0].tsc, tsc) */
keir@19906 971 i = 0;
keir@19906 972 while (i < data_cur && data[i].tsc < tsc) {
keir@19906 973 int cpu = data[i].cpu;
keir@19906 974 cur_state[cpu].cx = data[i].cx;
keir@19906 975 cur_state[cpu].flag = FLAG_LEVEL;
keir@19906 976 i++;
keir@19906 977 }
keir@19906 978 while (i < data_cur && state_cur < number) {
keir@19906 979 int num[MAX_CPU_NR];
keir@19906 980 int last_idx[MAX_CPU_NR];
keir@19906 981
keir@19906 982 #if 0
keir@19906 983 printf("XXXXX %d tsc: %"PRIu64" data[i].tsc: %"PRIu64"\n",
keir@19906 984 i, tsc, data[i].tsc);
keir@19906 985 #endif
keir@19906 986 /* ensure they are zero */
keir@19906 987 memset(num, 0, sizeof(int) * MAX_CPU_NR);
keir@19906 988 memset(last_idx, 0, sizeof(int) * MAX_CPU_NR);
keir@19906 989
keir@19906 990 /* check [tsc, tsc+time_scale) */
keir@19906 991 while (i < data_cur && data[i].tsc < tsc+time_scale) {
keir@19906 992 int cpu = data[i].cpu;
keir@19906 993 num[cpu]++;
keir@19906 994 last_idx[cpu] = i;
keir@19906 995 i++;
keir@19906 996 }
keir@19906 997 /* TODO */
keir@19906 998 if (i >= data_cur)
keir@19906 999 break;
keir@19906 1000 for (j = 0; j < max_cpu_num; j++) {
keir@19906 1001 if (num[j] == 1) {
keir@19906 1002 /* only one event, it's an edge*/
keir@19906 1003 cur_state[j].cx = data[last_idx[j]].cx;
keir@19906 1004 cur_state[j].flag = FLAG_EDGE;
keir@19906 1005 } else if (num[j] > 1) {
keir@19906 1006 /* more than one event, it's fuzzy */
keir@19906 1007 cur_state[j].cx = data[last_idx[j]].cx;
keir@19906 1008 cur_state[j].flag = FLAG_FUZZY;
keir@19906 1009 } else if (cur_state[j].flag == FLAG_FUZZY) {
keir@19906 1010 /* no event, fuzzy state can't be passed down
keir@19906 1011 * notice that cx is set in the fuzzy state,
keir@19906 1012 * it's not changed here afterwards.
keir@19906 1013 */
keir@19906 1014 cur_state[j].flag = FLAG_LEVEL;
keir@19906 1015 }
keir@19906 1016 }
keir@19906 1017
keir@19906 1018 /* copy tsc */
keir@19906 1019 state[state_cur].tsc = tsc;
keir@19906 1020 for (j = 0; j < max_cpu_num; j++) {
keir@19906 1021 /* copy cx and flag */
keir@19906 1022 state[state_cur].cpu[j].cx = cur_state[j].cx;
keir@19906 1023 state[state_cur].cpu[j].flag = cur_state[j].flag;
keir@19906 1024
keir@19906 1025 /* update flag in cur_state */
keir@19906 1026 if (cur_state[j].flag == FLAG_EDGE) {
keir@19906 1027 cur_state[j].flag = FLAG_LEVEL;
keir@19906 1028 if (cur_state[j].cx == 0) {
keir@19906 1029 /* EXIT */
keir@19906 1030 /* copy irqs conditionally */
keir@19906 1031 memcpy(state[state_cur].cpu[j].irqs,
keir@19906 1032 data[last_idx[j]].irqs,
keir@19906 1033 sizeof(unsigned char) * 4);
keir@19906 1034 } else {
keir@19906 1035 /* ENTRY */
keir@19906 1036 state[state_cur].cpu[j].expected =
keir@19906 1037 data[last_idx[j]].expected;
keir@19906 1038 state[state_cur].cpu[j].predicted =
keir@19906 1039 data[last_idx[j]].predicted;
keir@19906 1040 }
keir@19906 1041 }
keir@19906 1042 }
keir@19906 1043 state_cur++;
keir@19906 1044 tsc += time_scale;
keir@19906 1045 }
keir@19906 1046 this->state_nr = state_cur;
keir@19906 1047 this->row = 0;
keir@19906 1048
keir@19906 1049 return 0;
keir@19906 1050 }
keir@19906 1051
keir@19906 1052 int time_mode_init(void)
keir@19906 1053 {
keir@19906 1054 int i;
keir@19906 1055 this->offset = 21;
keir@19906 1056 this->scroll_h = 0;
keir@19906 1057 this->time_scale = (data[data_cur-1].tsc -data[0].tsc)/10000UL;
keir@19906 1058 this->start_time = data[0].tsc;
keir@19906 1059 for (i = 0; i < max_cpu_num; i++)
keir@19906 1060 this->cpu_bitmap[i] = 1;
keir@19906 1061 return time_mode_rebuild(this->start_time,
keir@19906 1062 this->time_scale);
keir@19906 1063 }
keir@19906 1064
keir@19906 1065 void choose_cpus(void)
keir@19906 1066 {
keir@19906 1067 int i;
keir@19906 1068 int temp_row = 1;
keir@19906 1069 int ch;
keir@19906 1070
keir@19906 1071 clear();
keir@19906 1072 mvprintw(0, 0, "How many CPUs to track? Press space to toggle. Press 'q' or 'Q' to quit.");
keir@19906 1073
keir@19906 1074 while (1) {
keir@19906 1075 for (i = 0; i < max_cpu_num; i++) {
keir@19906 1076 if (temp_row == i+1)
keir@19906 1077 attron(COLOR_PAIR(2));
keir@19906 1078 mvprintw(i+1, 0, "[%s] CPU%d", this->cpu_bitmap[i] ? "x" : " ", i);
keir@19906 1079 if (temp_row == i+1)
keir@19906 1080 attroff(COLOR_PAIR(2));
keir@19906 1081 }
keir@19906 1082 ch = getch();
keir@19906 1083 switch (ch) {
keir@19906 1084 case KEY_UP:
keir@19906 1085 if (--temp_row < 1)
keir@19906 1086 temp_row = 1;
keir@19906 1087 break;
keir@19906 1088 case KEY_DOWN:
keir@19906 1089 if (++temp_row > max_cpu_num)
keir@19906 1090 temp_row = max_cpu_num;
keir@19906 1091 break;
keir@19906 1092 case ' ':
keir@19906 1093 this->cpu_bitmap[temp_row-1] = !this->cpu_bitmap[temp_row-1];
keir@19906 1094 break;
keir@19906 1095 case 'q':
keir@19906 1096 case 'Q':
keir@19906 1097 if (num_of_cpus() >= 1) {
keir@19906 1098 if (!strcmp(this->name, "Event"))
keir@19906 1099 this->init();
keir@19906 1100 return;
keir@19906 1101 }
keir@19906 1102 case KEY_F(4):
keir@19906 1103 exit(EXIT_SUCCESS);
keir@19906 1104 }
keir@19906 1105 }
keir@19906 1106 }
keir@19906 1107
keir@19906 1108 int num_of_cpus(void)
keir@19906 1109 {
keir@19906 1110 int i, nr = 0;
keir@19906 1111 for (i = 0; i < max_cpu_num; i++)
keir@19906 1112 if (this->cpu_bitmap[i])
keir@19906 1113 nr++;
keir@19906 1114 return nr;
keir@19906 1115 }
keir@19906 1116