PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/misc/gtracestat.c

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