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