2 * Copyright (c) 2014-2015 Netflix, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer,
9 * in this position and unchanged.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/types.h>
33 #include <sys/errno.h>
37 #include "eval_expr.h"
38 static int max_pmc_counters = 1;
39 static int run_all = 0;
41 #define MAX_COUNTER_SLOTS 1024
44 static int verbose = 0;
46 extern char **environ;
47 extern struct expression *master_exp;
48 struct expression *master_exp=NULL;
50 #define PMC_INITIAL_ALLOC 512
51 extern char **valid_pmcs;
52 char **valid_pmcs = NULL;
53 extern int valid_pmc_cnt;
55 extern int pmc_allocated_cnt;
56 int pmc_allocated_cnt=0;
59 * The following two varients on popen and pclose with
60 * the cavet that they get you the PID so that you
61 * can supply it to pclose so it can send a SIGTERM
65 my_popen(const char *command, const char *dir, pid_t *p_pid)
68 int pdesin[2], pdesout[2];
75 if ((strcmp(dir, "r") != 0) &&
76 (strcmp(dir, "w") != 0)) {
83 if (pipe(pdesout) < 0) {
84 (void)close(pdesin[0]);
85 (void)close(pdesin[1]);
90 strcpy(cmd2, command);
96 switch (pid = fork()) {
98 (void)close(pdesin[0]);
99 (void)close(pdesin[1]);
100 (void)close(pdesout[0]);
101 (void)close(pdesout[1]);
105 /* Close out un-used sides */
106 (void)close(pdesin[1]);
107 (void)close(pdesout[0]);
108 /* Now prepare the stdin of the process */
110 (void)dup(pdesin[0]);
111 (void)close(pdesin[0]);
112 /* Now prepare the stdout of the process */
114 (void)dup(pdesout[1]);
115 /* And lets do stderr just in case */
117 (void)dup(pdesout[1]);
118 (void)close(pdesout[1]);
120 execve("/bin/sh", argv, environ);
124 /* Parent; assume fdopen can't fail. */
127 if (strcmp(dir, "r") != 0) {
128 io_out = fdopen(pdesin[1], "w");
129 (void)close(pdesin[0]);
130 (void)close(pdesout[0]);
131 (void)close(pdesout[1]);
134 /* Prepare the input stream */
135 io_in = fdopen(pdesout[0], "r");
136 (void)close(pdesout[1]);
137 (void)close(pdesin[0]);
138 (void)close(pdesin[1]);
145 * Pclose returns -1 if stream is not associated with a `popened' command,
146 * if already `pclosed', or waitpid returns an error.
149 my_pclose(FILE *io, pid_t the_pid)
155 * Find the appropriate file pointer and remove it from the list.
158 /* Die if you are not dead! */
159 kill(the_pid, SIGTERM);
161 pid = wait4(the_pid, &pstat, 0, (struct rusage *)0);
162 } while (pid == -1 && errno == EINTR);
166 struct counters *next_cpu;
167 char counter_name[MAX_NLEN]; /* Name of counter */
168 int cpu; /* CPU we are on */
169 int pos; /* Index we are filling to. */
170 uint64_t vals[MAX_COUNTER_SLOTS]; /* Last 64 entries */
171 uint64_t sum; /* Summary of entries */
174 extern struct counters *glob_cpu[MAX_CPU];
175 struct counters *glob_cpu[MAX_CPU];
177 extern struct counters *cnts;
178 struct counters *cnts=NULL;
183 extern int (*expression)(struct counters *, int);
184 int (*expression)(struct counters *, int);
186 static const char *threshold=NULL;
187 static const char *command;
193 int (*func)(struct counters *, int);
194 int counters_required;
200 struct cpu_entry *ents;
201 void (*explain)(const char *name);
203 extern struct cpu_type the_cpu;
204 struct cpu_type the_cpu;
207 explain_name_sb(const char *name)
209 const char *mythresh;
210 if (strcmp(name, "allocstall1") == 0) {
211 printf("Examine PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW / CPU_CLK_UNHALTED.THREAD_P\n");
212 mythresh = "thresh > .05";
213 } else if (strcmp(name, "allocstall2") == 0) {
214 printf("Examine PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES/CPU_CLK_UNHALTED.THREAD_P\n");
215 mythresh = "thresh > .05";
216 } else if (strcmp(name, "br_miss") == 0) {
217 printf("Examine (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD_P\n");
218 mythresh = "thresh >= .2";
219 } else if (strcmp(name, "splitload") == 0) {
220 printf("Examine MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
221 mythresh = "thresh >= .1";
222 } else if (strcmp(name, "splitstore") == 0) {
223 printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
224 mythresh = "thresh >= .01";
225 } else if (strcmp(name, "contested") == 0) {
226 printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P\n");
227 mythresh = "thresh >= .05";
228 } else if (strcmp(name, "blockstorefwd") == 0) {
229 printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
230 mythresh = "thresh >= .05";
231 } else if (strcmp(name, "cache2") == 0) {
232 printf("Examine ((MEM_LOAD_RETIRED.L3_HIT * 26) + \n");
233 printf(" (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 43) + \n");
234 printf(" (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60)) / CPU_CLK_UNHALTED.THREAD_P\n");
235 printf("**Note we have it labeled MEM_LOAD_UOPS_RETIRED.LLC_HIT not MEM_LOAD_RETIRED.L3_HIT\n");
236 mythresh = "thresh >= .2";
237 } else if (strcmp(name, "cache1") == 0) {
238 printf("Examine (MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
239 mythresh = "thresh >= .2";
240 } else if (strcmp(name, "dtlbmissload") == 0) {
241 printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
242 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
243 mythresh = "thresh >= .1";
244 } else if (strcmp(name, "frontendstall") == 0) {
245 printf("Examine IDQ_UOPS_NOT_DELIVERED.CORE / (CPU_CLK_UNHALTED.THREAD_P * 4)\n");
246 mythresh = "thresh >= .15";
247 } else if (strcmp(name, "clears") == 0) {
248 printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
249 printf(" MACHINE_CLEARS.SMC + \n");
250 printf(" MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
251 mythresh = "thresh >= .02";
252 } else if (strcmp(name, "microassist") == 0) {
253 printf("Examine IDQ.MS_CYCLES / (CPU_CLK_UNHALTED.THREAD_P * 4)\n");
254 printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
255 mythresh = "thresh >= .05";
256 } else if (strcmp(name, "aliasing_4k") == 0) {
257 printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
258 mythresh = "thresh >= .1";
259 } else if (strcmp(name, "fpassist") == 0) {
260 printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
261 mythresh = "look for a excessive value";
262 } else if (strcmp(name, "otherassistavx") == 0) {
263 printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
264 mythresh = "look for a excessive value";
265 } else if (strcmp(name, "otherassistsse") == 0) {
266 printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
267 mythresh = "look for a excessive value";
268 } else if (strcmp(name, "eff1") == 0) {
269 printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
270 mythresh = "thresh < .9";
271 } else if (strcmp(name, "eff2") == 0) {
272 printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
273 mythresh = "thresh > 1.0";
274 } else if (strcmp(name, "dtlbmissstore") == 0) {
275 printf("Examine (((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION)\n");
276 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
277 mythresh = "thresh >= .05";
279 printf("Unknown name:%s\n", name);
280 mythresh = "unknown entry";
282 printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
286 explain_name_ib(const char *name)
288 const char *mythresh;
289 if (strcmp(name, "br_miss") == 0) {
290 printf("Examine ((BR_MISP_RETIRED.ALL_BRANCHES /(BR_MISP_RETIRED.ALL_BRANCHES +\n");
291 printf(" MACHINE_CLEAR.COUNT) * ((UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES)\n");
292 printf("/ (4 * CPU_CLK_UNHALTED.THREAD))))\n");
293 mythresh = "thresh >= .2";
294 } else if (strcmp(name, "eff1") == 0) {
295 printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
296 mythresh = "thresh < .9";
297 } else if (strcmp(name, "eff2") == 0) {
298 printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
299 mythresh = "thresh > 1.0";
300 } else if (strcmp(name, "cache1") == 0) {
301 printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
302 mythresh = "thresh >= .2";
303 } else if (strcmp(name, "cache2") == 0) {
304 printf("Examine (MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P\n");
305 mythresh = "thresh >= .2";
306 } else if (strcmp(name, "itlbmiss") == 0) {
307 printf("Examine ITLB_MISSES.WALK_DURATION / CPU_CLK_UNHALTED.THREAD_P\n");
308 mythresh = "thresh > .05";
309 } else if (strcmp(name, "icachemiss") == 0) {
310 printf("Examine (ICACHE.IFETCH_STALL - ITLB_MISSES.WALK_DURATION)/ CPU_CLK_UNHALTED.THREAD_P\n");
311 mythresh = "thresh > .05";
312 } else if (strcmp(name, "lcpstall") == 0) {
313 printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
314 mythresh = "thresh > .05";
315 } else if (strcmp(name, "datashare") == 0) {
316 printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/CPU_CLK_UNHALTED.THREAD_P\n");
317 mythresh = "thresh > .05";
318 } else if (strcmp(name, "blockstorefwd") == 0) {
319 printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
320 mythresh = "thresh >= .05";
321 } else if (strcmp(name, "splitload") == 0) {
322 printf("Examine ((L1D_PEND_MISS.PENDING / MEM_LOAD_UOPS_RETIRED.L1_MISS) *\n");
323 printf(" LD_BLOCKS.NO_SR)/CPU_CLK_UNHALTED.THREAD_P\n");
324 mythresh = "thresh >= .1";
325 } else if (strcmp(name, "splitstore") == 0) {
326 printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
327 mythresh = "thresh >= .01";
328 } else if (strcmp(name, "aliasing_4k") == 0) {
329 printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
330 mythresh = "thresh >= .1";
331 } else if (strcmp(name, "dtlbmissload") == 0) {
332 printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
333 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
334 mythresh = "thresh >= .1";
335 } else if (strcmp(name, "dtlbmissstore") == 0) {
336 printf("Examine (((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION)\n");
337 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
338 mythresh = "thresh >= .05";
339 } else if (strcmp(name, "contested") == 0) {
340 printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P\n");
341 mythresh = "thresh >= .05";
342 } else if (strcmp(name, "clears") == 0) {
343 printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
344 printf(" MACHINE_CLEARS.SMC + \n");
345 printf(" MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
346 mythresh = "thresh >= .02";
347 } else if (strcmp(name, "microassist") == 0) {
348 printf("Examine IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
349 printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
350 mythresh = "thresh >= .05";
351 } else if (strcmp(name, "fpassist") == 0) {
352 printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
353 mythresh = "look for a excessive value";
354 } else if (strcmp(name, "otherassistavx") == 0) {
355 printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
356 mythresh = "look for a excessive value";
357 } else if (strcmp(name, "otherassistsse") == 0) {
358 printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
359 mythresh = "look for a excessive value";
361 printf("Unknown name:%s\n", name);
362 mythresh = "unknown entry";
364 printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
369 explain_name_has(const char *name)
371 const char *mythresh;
372 if (strcmp(name, "eff1") == 0) {
373 printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
374 mythresh = "thresh < .75";
375 } else if (strcmp(name, "eff2") == 0) {
376 printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
377 mythresh = "thresh > 1.0";
378 } else if (strcmp(name, "itlbmiss") == 0) {
379 printf("Examine ITLB_MISSES.WALK_DURATION / CPU_CLK_UNHALTED.THREAD_P\n");
380 mythresh = "thresh > .05";
381 } else if (strcmp(name, "icachemiss") == 0) {
382 printf("Examine (36 * ICACHE.MISSES)/ CPU_CLK_UNHALTED.THREAD_P\n");
383 mythresh = "thresh > .05";
384 } else if (strcmp(name, "lcpstall") == 0) {
385 printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
386 mythresh = "thresh > .05";
387 } else if (strcmp(name, "cache1") == 0) {
388 printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
389 mythresh = "thresh >= .2";
390 } else if (strcmp(name, "cache2") == 0) {
391 printf("Examine ((MEM_LOAD_UOPS_RETIRED.LLC_HIT * 36) + \n");
392 printf(" (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 72) + \n");
393 printf(" (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84))\n");
394 printf(" / CPU_CLK_UNHALTED.THREAD_P\n");
395 mythresh = "thresh >= .2";
396 } else if (strcmp(name, "contested") == 0) {
397 printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P\n");
398 mythresh = "thresh >= .05";
399 } else if (strcmp(name, "datashare") == 0) {
400 printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 72)/CPU_CLK_UNHALTED.THREAD_P\n");
401 mythresh = "thresh > .05";
402 } else if (strcmp(name, "blockstorefwd") == 0) {
403 printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
404 mythresh = "thresh >= .05";
405 } else if (strcmp(name, "splitload") == 0) {
406 printf("Examine (MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
407 mythresh = "thresh >= .1";
408 } else if (strcmp(name, "splitstore") == 0) {
409 printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
410 mythresh = "thresh >= .01";
411 } else if (strcmp(name, "aliasing_4k") == 0) {
412 printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
413 mythresh = "thresh >= .1";
414 } else if (strcmp(name, "dtlbmissload") == 0) {
415 printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
416 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
417 mythresh = "thresh >= .1";
418 } else if (strcmp(name, "br_miss") == 0) {
419 printf("Examine (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD\n");
420 mythresh = "thresh >= .2";
421 } else if (strcmp(name, "clears") == 0) {
422 printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
423 printf(" MACHINE_CLEARS.SMC + \n");
424 printf(" MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
425 mythresh = "thresh >= .02";
426 } else if (strcmp(name, "microassist") == 0) {
427 printf("Examine IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
428 printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
429 mythresh = "thresh >= .05";
430 } else if (strcmp(name, "fpassist") == 0) {
431 printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
432 mythresh = "look for a excessive value";
433 } else if (strcmp(name, "otherassistavx") == 0) {
434 printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
435 mythresh = "look for a excessive value";
436 } else if (strcmp(name, "otherassistsse") == 0) {
437 printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
438 mythresh = "look for a excessive value";
440 printf("Unknown name:%s\n", name);
441 mythresh = "unknown entry";
443 printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
448 static struct counters *
449 find_counter(struct counters *base, const char *name)
457 if (strncmp(at->counter_name, name, len) == 0) {
462 printf("Can't find counter %s\n", name);
463 printf("We have:\n");
466 printf("- %s\n", at->counter_name);
473 allocstall1(struct counters *cpu, int pos)
475 /* 1 - PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW/CPU_CLK_UNHALTED.THREAD_P (thresh > .05)*/
477 struct counters *partial;
478 struct counters *unhalt;
480 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
481 partial = find_counter(cpu, "PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW");
483 par = partial->vals[pos] * 1.0;
484 un = unhalt->vals[pos] * 1.0;
486 par = partial->sum * 1.0;
487 un = unhalt->sum * 1.0;
490 ret = printf("%1.3f", res);
495 allocstall2(struct counters *cpu, int pos)
497 /* 2 - PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES/CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
499 struct counters *partial;
500 struct counters *unhalt;
502 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
503 partial = find_counter(cpu, "PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP");
505 par = partial->vals[pos] * 1.0;
506 un = unhalt->vals[pos] * 1.0;
508 par = partial->sum * 1.0;
509 un = unhalt->sum * 1.0;
512 ret = printf("%1.3f", res);
517 br_mispredict(struct counters *cpu, int pos)
519 struct counters *brctr;
520 struct counters *unhalt;
522 /* 3 - (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
523 double br, un, con, res;
526 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
527 brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
529 br = brctr->vals[pos] * 1.0;
530 un = unhalt->vals[pos] * 1.0;
532 br = brctr->sum * 1.0;
533 un = unhalt->sum * 1.0;
536 ret = printf("%1.3f", res);
541 br_mispredictib(struct counters *cpu, int pos)
543 struct counters *brctr;
544 struct counters *unhalt;
545 struct counters *clear, *clear2, *clear3;
546 struct counters *uops;
547 struct counters *recv;
548 struct counters *iss;
549 /* "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",*/
552 * (BR_MISP_RETIRED.ALL_BRANCHES /
553 * (BR_MISP_RETIRED.ALL_BRANCHES +
554 * MACHINE_CLEAR.COUNT) *
555 * ((UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) / (4 * CPU_CLK_UNHALTED.THREAD)))
558 double br, cl, cl2, cl3, uo, re, un, con, res, is;
561 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
562 brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
563 clear = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
564 clear2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
565 clear3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
566 uops = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
567 iss = find_counter(cpu, "UOPS_ISSUED.ANY");
568 recv = find_counter(cpu, "INT_MISC.RECOVERY_CYCLES");
570 br = brctr->vals[pos] * 1.0;
571 cl = clear->vals[pos] * 1.0;
572 cl2 = clear2->vals[pos] * 1.0;
573 cl3 = clear3->vals[pos] * 1.0;
574 uo = uops->vals[pos] * 1.0;
575 re = recv->vals[pos] * 1.0;
576 is = iss->vals[pos] * 1.0;
577 un = unhalt->vals[pos] * 1.0;
579 br = brctr->sum * 1.0;
580 cl = clear->sum * 1.0;
581 cl2 = clear2->sum * 1.0;
582 cl3 = clear3->sum * 1.0;
583 uo = uops->sum * 1.0;
584 re = recv->sum * 1.0;
586 un = unhalt->sum * 1.0;
588 res = (br/(br + cl + cl2 + cl3) * ((is - uo + con * re) / (con * un)));
589 ret = printf("%1.3f", res);
595 br_mispredict_broad(struct counters *cpu, int pos)
597 struct counters *brctr;
598 struct counters *unhalt;
599 struct counters *clear;
600 struct counters *uops;
601 struct counters *uops_ret;
602 struct counters *recv;
604 double br, cl, uo, uo_r, re, con, un, res;
608 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
609 brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
610 clear = find_counter(cpu, "MACHINE_CLEARS.CYCLES");
611 uops = find_counter(cpu, "UOPS_ISSUED.ANY");
612 uops_ret = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
613 recv = find_counter(cpu, "INT_MISC.RECOVERY_CYCLES");
616 un = unhalt->vals[pos] * 1.0;
617 br = brctr->vals[pos] * 1.0;
618 cl = clear->vals[pos] * 1.0;
619 uo = uops->vals[pos] * 1.0;
620 uo_r = uops_ret->vals[pos] * 1.0;
621 re = recv->vals[pos] * 1.0;
623 un = unhalt->sum * 1.0;
624 br = brctr->sum * 1.0;
625 cl = clear->sum * 1.0;
626 uo = uops->sum * 1.0;
627 uo_r = uops_ret->sum * 1.0;
628 re = recv->sum * 1.0;
630 res = br / (br + cl) * (uo - uo_r + con * re) / (un * con);
631 ret = printf("%1.3f", res);
636 splitloadib(struct counters *cpu, int pos)
639 struct counters *mem;
640 struct counters *l1d, *ldblock;
641 struct counters *unhalt;
642 double un, memd, res, l1, ldb;
644 * ((L1D_PEND_MISS.PENDING / MEM_LOAD_UOPS_RETIRED.L1_MISS) * LD_BLOCKS.NO_SR) / CPU_CLK_UNHALTED.THREAD_P
645 * "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s L1D_PEND_MISS.PENDING -s MEM_LOAD_UOPS_RETIRED.L1_MISS -s LD_BLOCKS.NO_SR -w 1",
648 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
649 mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L1_MISS");
650 l1d = find_counter(cpu, "L1D_PEND_MISS.PENDING");
651 ldblock = find_counter(cpu, "LD_BLOCKS.NO_SR");
653 memd = mem->vals[pos] * 1.0;
654 l1 = l1d->vals[pos] * 1.0;
655 ldb = ldblock->vals[pos] * 1.0;
656 un = unhalt->vals[pos] * 1.0;
658 memd = mem->sum * 1.0;
660 ldb = ldblock->sum * 1.0;
661 un = unhalt->sum * 1.0;
663 res = ((l1 / memd) * ldb)/un;
664 ret = printf("%1.3f", res);
670 splitload(struct counters *cpu, int pos)
673 struct counters *mem;
674 struct counters *unhalt;
675 double con, un, memd, res;
676 /* 4 - (MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .1)*/
679 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
680 mem = find_counter(cpu, "MEM_UOPS_RETIRED.SPLIT_LOADS");
682 memd = mem->vals[pos] * 1.0;
683 un = unhalt->vals[pos] * 1.0;
685 memd = mem->sum * 1.0;
686 un = unhalt->sum * 1.0;
688 res = (memd * con)/un;
689 ret = printf("%1.3f", res);
695 splitload_sb(struct counters *cpu, int pos)
698 struct counters *mem;
699 struct counters *unhalt;
700 double con, un, memd, res;
701 /* 4 - (MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .1)*/
704 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
705 mem = find_counter(cpu, "MEM_UOP_RETIRED.SPLIT_LOADS");
707 memd = mem->vals[pos] * 1.0;
708 un = unhalt->vals[pos] * 1.0;
710 memd = mem->sum * 1.0;
711 un = unhalt->sum * 1.0;
713 res = (memd * con)/un;
714 ret = printf("%1.3f", res);
720 splitstore_sb(struct counters *cpu, int pos)
722 /* 5 - MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES (thresh > 0.01) */
724 struct counters *mem_split;
725 struct counters *mem_stores;
726 double memsplit, memstore, res;
727 mem_split = find_counter(cpu, "MEM_UOP_RETIRED.SPLIT_STORES");
728 mem_stores = find_counter(cpu, "MEM_UOP_RETIRED.ALL_STORES");
730 memsplit = mem_split->vals[pos] * 1.0;
731 memstore = mem_stores->vals[pos] * 1.0;
733 memsplit = mem_split->sum * 1.0;
734 memstore = mem_stores->sum * 1.0;
736 res = memsplit/memstore;
737 ret = printf("%1.3f", res);
744 splitstore(struct counters *cpu, int pos)
746 /* 5 - MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES (thresh > 0.01) */
748 struct counters *mem_split;
749 struct counters *mem_stores;
750 double memsplit, memstore, res;
751 mem_split = find_counter(cpu, "MEM_UOPS_RETIRED.SPLIT_STORES");
752 mem_stores = find_counter(cpu, "MEM_UOPS_RETIRED.ALL_STORES");
754 memsplit = mem_split->vals[pos] * 1.0;
755 memstore = mem_stores->vals[pos] * 1.0;
757 memsplit = mem_split->sum * 1.0;
758 memstore = mem_stores->sum * 1.0;
760 res = memsplit/memstore;
761 ret = printf("%1.3f", res);
767 contested(struct counters *cpu, int pos)
769 /* 6 - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
771 struct counters *mem;
772 struct counters *unhalt;
773 double con, un, memd, res;
776 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
777 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
779 memd = mem->vals[pos] * 1.0;
780 un = unhalt->vals[pos] * 1.0;
782 memd = mem->sum * 1.0;
783 un = unhalt->sum * 1.0;
785 res = (memd * con)/un;
786 ret = printf("%1.3f", res);
791 contested_has(struct counters *cpu, int pos)
793 /* 6 - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
795 struct counters *mem;
796 struct counters *unhalt;
797 double con, un, memd, res;
800 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
801 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
803 memd = mem->vals[pos] * 1.0;
804 un = unhalt->vals[pos] * 1.0;
806 memd = mem->sum * 1.0;
807 un = unhalt->sum * 1.0;
809 res = (memd * con)/un;
810 ret = printf("%1.3f", res);
815 contestedbroad(struct counters *cpu, int pos)
817 /* 6 - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
819 struct counters *mem;
820 struct counters *mem2;
821 struct counters *unhalt;
822 double con, un, memd, memtoo, res;
825 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
826 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
827 mem2 = find_counter(cpu,"MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS");
830 memd = mem->vals[pos] * 1.0;
831 memtoo = mem2->vals[pos] * 1.0;
832 un = unhalt->vals[pos] * 1.0;
834 memd = mem->sum * 1.0;
835 memtoo = mem2->sum * 1.0;
836 un = unhalt->sum * 1.0;
838 res = ((memd * con) + memtoo)/un;
839 ret = printf("%1.3f", res);
845 blockstoreforward(struct counters *cpu, int pos)
847 /* 7 - (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .05)*/
849 struct counters *ldb;
850 struct counters *unhalt;
851 double con, un, ld, res;
854 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
855 ldb = find_counter(cpu, "LD_BLOCKS_STORE_FORWARD");
857 ld = ldb->vals[pos] * 1.0;
858 un = unhalt->vals[pos] * 1.0;
861 un = unhalt->sum * 1.0;
864 ret = printf("%1.3f", res);
869 cache2(struct counters *cpu, int pos)
872 * 8 - ((MEM_LOAD_RETIRED.L3_HIT * 26) + (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 43) +
873 * (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60)) / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
876 struct counters *mem1, *mem2, *mem3;
877 struct counters *unhalt;
878 double con1, con2, con3, un, me_1, me_2, me_3, res;
883 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
884 /* Call for MEM_LOAD_RETIRED.L3_HIT possibly MEM_LOAD_UOPS_RETIRED.LLC_HIT ?*/
885 mem1 = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
886 mem2 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
887 mem3 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
889 me_1 = mem1->vals[pos] * 1.0;
890 me_2 = mem2->vals[pos] * 1.0;
891 me_3 = mem3->vals[pos] * 1.0;
892 un = unhalt->vals[pos] * 1.0;
894 me_1 = mem1->sum * 1.0;
895 me_2 = mem2->sum * 1.0;
896 me_3 = mem3->sum * 1.0;
897 un = unhalt->sum * 1.0;
899 res = ((me_1 * con1) + (me_2 * con2) + (me_3 * con3))/un;
900 ret = printf("%1.3f", res);
905 datasharing(struct counters *cpu, int pos)
908 * (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/ CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
911 struct counters *mem;
912 struct counters *unhalt;
913 double con, res, me, un;
916 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
917 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
919 me = mem->vals[pos] * 1.0;
920 un = unhalt->vals[pos] * 1.0;
923 un = unhalt->sum * 1.0;
926 ret = printf("%1.3f", res);
933 datasharing_has(struct counters *cpu, int pos)
936 * (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/ CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
939 struct counters *mem;
940 struct counters *unhalt;
941 double con, res, me, un;
944 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
945 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
947 me = mem->vals[pos] * 1.0;
948 un = unhalt->vals[pos] * 1.0;
951 un = unhalt->sum * 1.0;
954 ret = printf("%1.3f", res);
961 cache2ib(struct counters *cpu, int pos)
964 * (29 * MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
967 struct counters *mem;
968 struct counters *unhalt;
969 double con, un, me, res;
972 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
973 mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
975 me = mem->vals[pos] * 1.0;
976 un = unhalt->vals[pos] * 1.0;
979 un = unhalt->sum * 1.0;
982 ret = printf("%1.3f", res);
987 cache2has(struct counters *cpu, int pos)
990 * Examine ((MEM_LOAD_UOPS_RETIRED.LLC_HIT * 36) + \
991 * (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 72) +
992 * (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84))
993 * / CPU_CLK_UNHALTED.THREAD_P
996 struct counters *mem1, *mem2, *mem3;
997 struct counters *unhalt;
998 double con1, con2, con3, un, me1, me2, me3, res;
1003 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1004 mem1 = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
1005 mem2 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
1006 mem3 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
1008 me1 = mem1->vals[pos] * 1.0;
1009 me2 = mem2->vals[pos] * 1.0;
1010 me3 = mem3->vals[pos] * 1.0;
1011 un = unhalt->vals[pos] * 1.0;
1013 me1 = mem1->sum * 1.0;
1014 me2 = mem2->sum * 1.0;
1015 me3 = mem3->sum * 1.0;
1016 un = unhalt->sum * 1.0;
1018 res = ((me1 * con1) + (me2 * con2) + (me3 * con3))/un;
1019 ret = printf("%1.3f", res);
1025 cache2broad(struct counters *cpu, int pos)
1028 * (29 * MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
1031 struct counters *mem;
1032 struct counters *unhalt;
1033 double con, un, me, res;
1036 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1037 mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L3_HIT");
1039 me = mem->vals[pos] * 1.0;
1040 un = unhalt->vals[pos] * 1.0;
1042 me = mem->sum * 1.0;
1043 un = unhalt->sum * 1.0;
1045 res = (con * me)/un;
1046 ret = printf("%1.3f", res);
1052 cache1(struct counters *cpu, int pos)
1054 /* 9 - (MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
1056 struct counters *mem;
1057 struct counters *unhalt;
1058 double con, un, me, res;
1061 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1062 mem = find_counter(cpu, "MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS");
1064 me = mem->vals[pos] * 1.0;
1065 un = unhalt->vals[pos] * 1.0;
1067 me = mem->sum * 1.0;
1068 un = unhalt->sum * 1.0;
1070 res = (me * con)/un;
1071 ret = printf("%1.3f", res);
1076 cache1ib(struct counters *cpu, int pos)
1078 /* 9 - (MEM_LOAD_UOPS_L3_MISS_RETIRED.LCOAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
1080 struct counters *mem;
1081 struct counters *unhalt;
1082 double con, un, me, res;
1085 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1086 mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM");
1088 me = mem->vals[pos] * 1.0;
1089 un = unhalt->vals[pos] * 1.0;
1091 me = mem->sum * 1.0;
1092 un = unhalt->sum * 1.0;
1094 res = (me * con)/un;
1095 ret = printf("%1.3f", res);
1101 cache1broad(struct counters *cpu, int pos)
1103 /* 9 - (MEM_LOAD_UOPS_L3_MISS_RETIRED.LCOAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
1105 struct counters *mem;
1106 struct counters *unhalt;
1107 double con, un, me, res;
1110 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1111 mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L3_MISS");
1113 me = mem->vals[pos] * 1.0;
1114 un = unhalt->vals[pos] * 1.0;
1116 me = mem->sum * 1.0;
1117 un = unhalt->sum * 1.0;
1119 res = (me * con)/un;
1120 ret = printf("%1.3f", res);
1126 dtlb_missload(struct counters *cpu, int pos)
1128 /* 10 - ((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION) / CPU_CLK_UNHALTED.THREAD_P (t >=.1) */
1130 struct counters *dtlb_m, *dtlb_d;
1131 struct counters *unhalt;
1132 double con, un, d1, d2, res;
1135 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1136 dtlb_m = find_counter(cpu, "DTLB_LOAD_MISSES.STLB_HIT");
1137 dtlb_d = find_counter(cpu, "DTLB_LOAD_MISSES.WALK_DURATION");
1139 d1 = dtlb_m->vals[pos] * 1.0;
1140 d2 = dtlb_d->vals[pos] * 1.0;
1141 un = unhalt->vals[pos] * 1.0;
1143 d1 = dtlb_m->sum * 1.0;
1144 d2 = dtlb_d->sum * 1.0;
1145 un = unhalt->sum * 1.0;
1147 res = ((d1 * con) + d2)/un;
1148 ret = printf("%1.3f", res);
1153 dtlb_missstore(struct counters *cpu, int pos)
1156 * ((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION) /
1157 * CPU_CLK_UNHALTED.THREAD_P (t >= .1)
1160 struct counters *dtsb_m, *dtsb_d;
1161 struct counters *unhalt;
1162 double con, un, d1, d2, res;
1165 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1166 dtsb_m = find_counter(cpu, "DTLB_STORE_MISSES.STLB_HIT");
1167 dtsb_d = find_counter(cpu, "DTLB_STORE_MISSES.WALK_DURATION");
1169 d1 = dtsb_m->vals[pos] * 1.0;
1170 d2 = dtsb_d->vals[pos] * 1.0;
1171 un = unhalt->vals[pos] * 1.0;
1173 d1 = dtsb_m->sum * 1.0;
1174 d2 = dtsb_d->sum * 1.0;
1175 un = unhalt->sum * 1.0;
1177 res = ((d1 * con) + d2)/un;
1178 ret = printf("%1.3f", res);
1183 itlb_miss(struct counters *cpu, int pos)
1185 /* ITLB_MISSES.WALK_DURATION / CPU_CLK_UNTHREAD_P IB */
1187 struct counters *itlb;
1188 struct counters *unhalt;
1191 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1192 itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
1194 d1 = itlb->vals[pos] * 1.0;
1195 un = unhalt->vals[pos] * 1.0;
1197 d1 = itlb->sum * 1.0;
1198 un = unhalt->sum * 1.0;
1201 ret = printf("%1.3f", res);
1207 itlb_miss_broad(struct counters *cpu, int pos)
1209 /* (7 * ITLB_MISSES.STLB_HIT_4K + ITLB_MISSES.WALK_DURATION) / CPU_CLK_UNTHREAD_P */
1211 struct counters *itlb;
1212 struct counters *unhalt;
1213 struct counters *four_k;
1214 double un, d1, res, k;
1216 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1217 itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
1218 four_k = find_counter(cpu, "ITLB_MISSES.STLB_HIT_4K");
1220 d1 = itlb->vals[pos] * 1.0;
1221 un = unhalt->vals[pos] * 1.0;
1222 k = four_k->vals[pos] * 1.0;
1224 d1 = itlb->sum * 1.0;
1225 un = unhalt->sum * 1.0;
1226 k = four_k->sum * 1.0;
1228 res = (7.0 * k + d1)/un;
1229 ret = printf("%1.3f", res);
1235 icache_miss(struct counters *cpu, int pos)
1237 /* (ICACHE.IFETCH_STALL - ITLB_MISSES.WALK_DURATION) / CPU_CLK_UNHALTED.THREAD_P IB */
1240 struct counters *itlb, *icache;
1241 struct counters *unhalt;
1242 double un, d1, ic, res;
1244 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1245 itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
1246 icache = find_counter(cpu, "ICACHE.IFETCH_STALL");
1248 d1 = itlb->vals[pos] * 1.0;
1249 ic = icache->vals[pos] * 1.0;
1250 un = unhalt->vals[pos] * 1.0;
1252 d1 = itlb->sum * 1.0;
1253 ic = icache->sum * 1.0;
1254 un = unhalt->sum * 1.0;
1257 ret = printf("%1.3f", res);
1263 icache_miss_has(struct counters *cpu, int pos)
1265 /* (36 * ICACHE.MISSES) / CPU_CLK_UNHALTED.THREAD_P */
1268 struct counters *icache;
1269 struct counters *unhalt;
1270 double un, con, ic, res;
1272 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1273 icache = find_counter(cpu, "ICACHE.MISSES");
1276 ic = icache->vals[pos] * 1.0;
1277 un = unhalt->vals[pos] * 1.0;
1279 ic = icache->sum * 1.0;
1280 un = unhalt->sum * 1.0;
1282 res = (con * ic)/un;
1283 ret = printf("%1.3f", res);
1289 lcp_stall(struct counters *cpu, int pos)
1291 /* ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P IB */
1293 struct counters *ild;
1294 struct counters *unhalt;
1297 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1298 ild = find_counter(cpu, "ILD_STALL.LCP");
1300 d1 = ild->vals[pos] * 1.0;
1301 un = unhalt->vals[pos] * 1.0;
1303 d1 = ild->sum * 1.0;
1304 un = unhalt->sum * 1.0;
1307 ret = printf("%1.3f", res);
1314 frontendstall(struct counters *cpu, int pos)
1316 /* 12 - IDQ_UOPS_NOT_DELIVERED.CORE / (CPU_CLK_UNHALTED.THREAD_P * 4) (thresh >= .15) */
1318 struct counters *idq;
1319 struct counters *unhalt;
1320 double con, un, id, res;
1323 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1324 idq = find_counter(cpu, "IDQ_UOPS_NOT_DELIVERED.CORE");
1326 id = idq->vals[pos] * 1.0;
1327 un = unhalt->vals[pos] * 1.0;
1329 id = idq->sum * 1.0;
1330 un = unhalt->sum * 1.0;
1332 res = id/(un * con);
1333 ret = printf("%1.3f", res);
1338 clears(struct counters *cpu, int pos)
1340 /* 13 - ((MACHINE_CLEARS.MEMORY_ORDERING + MACHINE_CLEARS.SMC + MACHINE_CLEARS.MASKMOV ) * 100 )
1341 * / CPU_CLK_UNHALTED.THREAD_P (thresh >= .02)*/
1344 struct counters *clr1, *clr2, *clr3;
1345 struct counters *unhalt;
1346 double con, un, cl1, cl2, cl3, res;
1349 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1350 clr1 = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
1351 clr2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
1352 clr3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
1355 cl1 = clr1->vals[pos] * 1.0;
1356 cl2 = clr2->vals[pos] * 1.0;
1357 cl3 = clr3->vals[pos] * 1.0;
1358 un = unhalt->vals[pos] * 1.0;
1360 cl1 = clr1->sum * 1.0;
1361 cl2 = clr2->sum * 1.0;
1362 cl3 = clr3->sum * 1.0;
1363 un = unhalt->sum * 1.0;
1365 res = ((cl1 + cl2 + cl3) * con)/un;
1366 ret = printf("%1.3f", res);
1373 clears_broad(struct counters *cpu, int pos)
1376 struct counters *clr1, *clr2, *clr3, *cyc;
1377 struct counters *unhalt;
1378 double con, un, cl1, cl2, cl3, cy, res;
1381 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1382 clr1 = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
1383 clr2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
1384 clr3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
1385 cyc = find_counter(cpu, "MACHINE_CLEARS.CYCLES");
1387 cl1 = clr1->vals[pos] * 1.0;
1388 cl2 = clr2->vals[pos] * 1.0;
1389 cl3 = clr3->vals[pos] * 1.0;
1390 cy = cyc->vals[pos] * 1.0;
1391 un = unhalt->vals[pos] * 1.0;
1393 cl1 = clr1->sum * 1.0;
1394 cl2 = clr2->sum * 1.0;
1395 cl3 = clr3->sum * 1.0;
1396 cy = cyc->sum * 1.0;
1397 un = unhalt->sum * 1.0;
1399 /* Formula not listed but extrapulated to add the cy ?? */
1400 res = ((cl1 + cl2 + cl3 + cy) * con)/un;
1401 ret = printf("%1.3f", res);
1410 microassist(struct counters *cpu, int pos)
1412 /* 14 - IDQ.MS_CYCLES / CPU_CLK_UNHALTED.THREAD_P (thresh > .05) */
1414 struct counters *idq;
1415 struct counters *unhalt;
1416 double un, id, res, con;
1419 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1420 idq = find_counter(cpu, "IDQ.MS_UOPS");
1422 id = idq->vals[pos] * 1.0;
1423 un = unhalt->vals[pos] * 1.0;
1425 id = idq->sum * 1.0;
1426 un = unhalt->sum * 1.0;
1428 res = id/(un * con);
1429 ret = printf("%1.3f", res);
1435 microassist_broad(struct counters *cpu, int pos)
1438 struct counters *idq;
1439 struct counters *unhalt;
1440 struct counters *uopiss;
1441 struct counters *uopret;
1442 double un, id, res, con, uoi, uor;
1445 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1446 idq = find_counter(cpu, "IDQ.MS_UOPS");
1447 uopiss = find_counter(cpu, "UOPS_ISSUED.ANY");
1448 uopret = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
1450 id = idq->vals[pos] * 1.0;
1451 un = unhalt->vals[pos] * 1.0;
1452 uoi = uopiss->vals[pos] * 1.0;
1453 uor = uopret->vals[pos] * 1.0;
1455 id = idq->sum * 1.0;
1456 un = unhalt->sum * 1.0;
1457 uoi = uopiss->sum * 1.0;
1458 uor = uopret->sum * 1.0;
1460 res = (uor/uoi) * (id/(un * con));
1461 ret = printf("%1.3f", res);
1467 aliasing(struct counters *cpu, int pos)
1469 /* 15 - (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh > .1) */
1471 struct counters *ld;
1472 struct counters *unhalt;
1473 double un, lds, con, res;
1476 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1477 ld = find_counter(cpu, "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS");
1479 lds = ld->vals[pos] * 1.0;
1480 un = unhalt->vals[pos] * 1.0;
1482 lds = ld->sum * 1.0;
1483 un = unhalt->sum * 1.0;
1485 res = (lds * con)/un;
1486 ret = printf("%1.3f", res);
1491 aliasing_broad(struct counters *cpu, int pos)
1493 /* 15 - (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh > .1) */
1495 struct counters *ld;
1496 struct counters *unhalt;
1497 double un, lds, con, res;
1500 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1501 ld = find_counter(cpu, "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS");
1503 lds = ld->vals[pos] * 1.0;
1504 un = unhalt->vals[pos] * 1.0;
1506 lds = ld->sum * 1.0;
1507 un = unhalt->sum * 1.0;
1509 res = (lds * con)/un;
1510 ret = printf("%1.3f", res);
1516 fpassists(struct counters *cpu, int pos)
1518 /* 16 - FP_ASSIST.ANY/INST_RETIRED.ANY_P */
1520 struct counters *fp;
1521 struct counters *inst;
1522 double un, fpd, res;
1524 inst = find_counter(cpu, "INST_RETIRED.ANY_P");
1525 fp = find_counter(cpu, "FP_ASSIST.ANY");
1527 fpd = fp->vals[pos] * 1.0;
1528 un = inst->vals[pos] * 1.0;
1530 fpd = fp->sum * 1.0;
1531 un = inst->sum * 1.0;
1534 ret = printf("%1.3f", res);
1539 otherassistavx(struct counters *cpu, int pos)
1541 /* 17 - (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P thresh .1*/
1543 struct counters *oth;
1544 struct counters *unhalt;
1545 double un, ot, con, res;
1548 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1549 oth = find_counter(cpu, "OTHER_ASSISTS.AVX_TO_SSE");
1551 ot = oth->vals[pos] * 1.0;
1552 un = unhalt->vals[pos] * 1.0;
1554 ot = oth->sum * 1.0;
1555 un = unhalt->sum * 1.0;
1557 res = (ot * con)/un;
1558 ret = printf("%1.3f", res);
1563 otherassistsse(struct counters *cpu, int pos)
1567 struct counters *oth;
1568 struct counters *unhalt;
1569 double un, ot, con, res;
1571 /* 18 (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P thresh .1*/
1573 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1574 oth = find_counter(cpu, "OTHER_ASSISTS.SSE_TO_AVX");
1576 ot = oth->vals[pos] * 1.0;
1577 un = unhalt->vals[pos] * 1.0;
1579 ot = oth->sum * 1.0;
1580 un = unhalt->sum * 1.0;
1582 res = (ot * con)/un;
1583 ret = printf("%1.3f", res);
1588 efficiency1(struct counters *cpu, int pos)
1592 struct counters *uops;
1593 struct counters *unhalt;
1594 double un, ot, con, res;
1596 /* 19 (UOPS_RETIRED.RETIRE_SLOTS/(4*CPU_CLK_UNHALTED.THREAD_P) look if thresh < .9*/
1598 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1599 uops = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
1601 ot = uops->vals[pos] * 1.0;
1602 un = unhalt->vals[pos] * 1.0;
1604 ot = uops->sum * 1.0;
1605 un = unhalt->sum * 1.0;
1607 res = ot/(con * un);
1608 ret = printf("%1.3f", res);
1613 efficiency2(struct counters *cpu, int pos)
1617 struct counters *uops;
1618 struct counters *unhalt;
1621 /* 20 - CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P good if > 1. (comp factor)*/
1622 unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
1623 uops = find_counter(cpu, "INST_RETIRED.ANY_P");
1625 ot = uops->vals[pos] * 1.0;
1626 un = unhalt->vals[pos] * 1.0;
1628 ot = uops->sum * 1.0;
1629 un = unhalt->sum * 1.0;
1632 ret = printf("%1.3f", res);
1636 #define SANDY_BRIDGE_COUNT 20
1637 static struct cpu_entry sandy_bridge[SANDY_BRIDGE_COUNT] = {
1638 /*01*/ { "allocstall1", "thresh > .05",
1639 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW -w 1",
1641 /* -- not defined for SB right (partial-rat_stalls) 02*/
1642 { "allocstall2", "thresh > .05",
1643 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP -w 1",
1645 /*03*/ { "br_miss", "thresh >= .2",
1646 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
1648 /*04*/ { "splitload", "thresh >= .1",
1649 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOP_RETIRED.SPLIT_LOADS -w 1",
1651 /* 05*/ { "splitstore", "thresh >= .01",
1652 "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
1654 /*06*/ { "contested", "thresh >= .05",
1655 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1657 /*07*/ { "blockstorefwd", "thresh >= .05",
1658 "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1659 blockstoreforward, 2 },
1660 /*08*/ { "cache2", "thresh >= .2",
1661 "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1663 /*09*/ { "cache1", "thresh >= .2",
1664 "pmcstat -s MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1666 /*10*/ { "dtlbmissload", "thresh >= .1",
1667 "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1669 /*11*/ { "dtlbmissstore", "thresh >= .05",
1670 "pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1671 dtlb_missstore, 3 },
1672 /*12*/ { "frontendstall", "thresh >= .15",
1673 "pmcstat -s IDQ_UOPS_NOT_DELIVERED.CORE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1675 /*13*/ { "clears", "thresh >= .02",
1676 "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1678 /*14*/ { "microassist", "thresh >= .05",
1679 "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1681 /*15*/ { "aliasing_4k", "thresh >= .1",
1682 "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1684 /*16*/ { "fpassist", "look for a excessive value",
1685 "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
1687 /*17*/ { "otherassistavx", "look for a excessive value",
1688 "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1690 /*18*/ { "otherassistsse", "look for a excessive value",
1691 "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1692 otherassistsse, 2 },
1693 /*19*/ { "eff1", "thresh < .9",
1694 "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1696 /*20*/ { "eff2", "thresh > 1.0",
1697 "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1702 #define IVY_BRIDGE_COUNT 21
1703 static struct cpu_entry ivy_bridge[IVY_BRIDGE_COUNT] = {
1704 /*1*/ { "eff1", "thresh < .75",
1705 "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1707 /*2*/ { "eff2", "thresh > 1.0",
1708 "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1710 /*3*/ { "itlbmiss", "thresh > .05",
1711 "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1713 /*4*/ { "icachemiss", "thresh > .05",
1714 "pmcstat -s ICACHE.IFETCH_STALL -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1716 /*5*/ { "lcpstall", "thresh > .05",
1717 "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1719 /*6*/ { "cache1", "thresh >= .2",
1720 "pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1722 /*7*/ { "cache2", "thresh >= .2",
1723 "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1725 /*8*/ { "contested", "thresh >= .05",
1726 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1728 /*9*/ { "datashare", "thresh >= .05",
1729 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1731 /*10*/ { "blockstorefwd", "thresh >= .05",
1732 "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1733 blockstoreforward, 2 },
1734 /*11*/ { "splitload", "thresh >= .1",
1735 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s L1D_PEND_MISS.PENDING -s MEM_LOAD_UOPS_RETIRED.L1_MISS -s LD_BLOCKS.NO_SR -w 1",
1737 /*12*/ { "splitstore", "thresh >= .01",
1738 "pmcstat -s MEM_UOPS_RETIRED.SPLIT_STORES -s MEM_UOPS_RETIRED.ALL_STORES -w 1",
1740 /*13*/ { "aliasing_4k", "thresh >= .1",
1741 "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1743 /*14*/ { "dtlbmissload", "thresh >= .1",
1744 "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1746 /*15*/ { "dtlbmissstore", "thresh >= .05",
1747 "pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1748 dtlb_missstore, 3 },
1749 /*16*/ { "br_miss", "thresh >= .2",
1750 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",
1751 br_mispredictib, 8 },
1752 /*17*/ { "clears", "thresh >= .02",
1753 "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1755 /*18*/ { "microassist", "thresh >= .05",
1756 "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1758 /*19*/ { "fpassist", "look for a excessive value",
1759 "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
1761 /*20*/ { "otherassistavx", "look for a excessive value",
1762 "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1763 otherassistavx , 2},
1764 /*21*/ { "otherassistsse", "look for a excessive value",
1765 "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1766 otherassistsse, 2 },
1769 #define HASWELL_COUNT 20
1770 static struct cpu_entry haswell[HASWELL_COUNT] = {
1771 /*1*/ { "eff1", "thresh < .75",
1772 "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1774 /*2*/ { "eff2", "thresh > 1.0",
1775 "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1777 /*3*/ { "itlbmiss", "thresh > .05",
1778 "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1780 /*4*/ { "icachemiss", "thresh > .05",
1781 "pmcstat -s ICACHE.MISSES -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1782 icache_miss_has, 2 },
1783 /*5*/ { "lcpstall", "thresh > .05",
1784 "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1786 /*6*/ { "cache1", "thresh >= .2",
1787 "pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1789 /*7*/ { "cache2", "thresh >= .2",
1790 "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1792 /*8*/ { "contested", "thresh >= .05",
1793 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1795 /*9*/ { "datashare", "thresh >= .05",
1796 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1797 datasharing_has, 2 },
1798 /*10*/ { "blockstorefwd", "thresh >= .05",
1799 "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1800 blockstoreforward, 2 },
1801 /*11*/ { "splitload", "thresh >= .1",
1802 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOPS_RETIRED.SPLIT_LOADS -w 1",
1804 /*12*/ { "splitstore", "thresh >= .01",
1805 "pmcstat -s MEM_UOPS_RETIRED.SPLIT_STORES -s MEM_UOPS_RETIRED.ALL_STORES -w 1",
1807 /*13*/ { "aliasing_4k", "thresh >= .1",
1808 "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1810 /*14*/ { "dtlbmissload", "thresh >= .1",
1811 "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1813 /*15*/ { "br_miss", "thresh >= .2",
1814 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
1816 /*16*/ { "clears", "thresh >= .02",
1817 "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1819 /*17*/ { "microassist", "thresh >= .05",
1820 "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1822 /*18*/ { "fpassist", "look for a excessive value",
1823 "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
1825 /*19*/ { "otherassistavx", "look for a excessive value",
1826 "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1827 otherassistavx, 2 },
1828 /*20*/ { "otherassistsse", "look for a excessive value",
1829 "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1830 otherassistsse, 2 },
1835 explain_name_broad(const char *name)
1837 const char *mythresh;
1838 if (strcmp(name, "eff1") == 0) {
1839 printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
1840 mythresh = "thresh < .75";
1841 } else if (strcmp(name, "eff2") == 0) {
1842 printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
1843 mythresh = "thresh > 1.0";
1844 } else if (strcmp(name, "itlbmiss") == 0) {
1845 printf("Examine (7 * ITLB_MISSES_STLB_HIT_4K + ITLB_MISSES.WALK_DURATION)/ CPU_CLK_UNHALTED.THREAD_P\n");
1846 mythresh = "thresh > .05";
1847 } else if (strcmp(name, "icachemiss") == 0) {
1848 printf("Examine ( 36.0 * ICACHE.MISSES)/ CPU_CLK_UNHALTED.THREAD_P ??? may not be right \n");
1849 mythresh = "thresh > .05";
1850 } else if (strcmp(name, "lcpstall") == 0) {
1851 printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
1852 mythresh = "thresh > .05";
1853 } else if (strcmp(name, "cache1") == 0) {
1854 printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
1855 mythresh = "thresh >= .1";
1856 } else if (strcmp(name, "cache2") == 0) {
1857 printf("Examine (36.0 * MEM_LOAD_UOPS_RETIRED.L3_HIT / CPU_CLK_UNHALTED.THREAD_P)\n");
1858 mythresh = "thresh >= .2";
1859 } else if (strcmp(name, "contested") == 0) {
1860 printf("Examine ((MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS)/ CPU_CLK_UNHALTED.THREAD_P\n");
1861 mythresh = "thresh >= .05";
1862 } else if (strcmp(name, "datashare") == 0) {
1863 printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 72)/CPU_CLK_UNHALTED.THREAD_P\n");
1864 mythresh = "thresh > .05";
1865 } else if (strcmp(name, "blockstorefwd") == 0) {
1866 printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
1867 mythresh = "thresh >= .05";
1868 } else if (strcmp(name, "aliasing_4k") == 0) {
1869 printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 7) / CPU_CLK_UNHALTED.THREAD_P\n");
1870 mythresh = "thresh >= .1";
1871 } else if (strcmp(name, "dtlbmissload") == 0) {
1872 printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
1873 printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
1874 mythresh = "thresh >= .1";
1876 } else if (strcmp(name, "br_miss") == 0) {
1877 printf("Examine BR_MISP_RETIRED.ALL_BRANCHS_PS / (BR_MISP_RETIED.ALL_BRANCHES_PS + MACHINE_CLEARS.COUNT) *\n");
1878 printf(" (UOPS_ISSUEDF.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) /\n");
1879 printf("CPU_CLK_UNHALTED.THREAD * 4)\n");
1880 mythresh = "thresh >= .2";
1881 } else if (strcmp(name, "clears") == 0) {
1882 printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
1883 printf(" MACHINE_CLEARS.SMC + \n");
1884 printf(" MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
1885 mythresh = "thresh >= .02";
1886 } else if (strcmp(name, "fpassist") == 0) {
1887 printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
1888 mythresh = "look for a excessive value";
1889 } else if (strcmp(name, "otherassistavx") == 0) {
1890 printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
1891 mythresh = "look for a excessive value";
1892 } else if (strcmp(name, "microassist") == 0) {
1893 printf("Examine (UOPS_RETIRED.RETIRE_SLOTS/UOPS_ISSUED.ANY) * (IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
1894 printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
1895 mythresh = "thresh >= .05";
1897 printf("Unknown name:%s\n", name);
1898 mythresh = "unknown entry";
1900 printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
1904 #define BROADWELL_COUNT 17
1905 static struct cpu_entry broadwell[BROADWELL_COUNT] = {
1906 /*1*/ { "eff1", "thresh < .75",
1907 "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1909 /*2*/ { "eff2", "thresh > 1.0",
1910 "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1912 /*3*/ { "itlbmiss", "thresh > .05",
1913 "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -s ITLB_MISSES.STLB_HIT_4K -w 1",
1914 itlb_miss_broad, 3 },
1915 /*4*/ { "icachemiss", "thresh > .05",
1916 "pmcstat -s ICACHE.MISSES -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1917 icache_miss_has, 2 },
1918 /*5*/ { "lcpstall", "thresh > .05",
1919 "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1921 /*6*/ { "cache1", "thresh >= .1",
1922 "pmcstat -s MEM_LOAD_UOPS_RETIRED.L3_MISS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1924 /*7*/ { "cache2", "thresh >= .2",
1925 "pmcstat -s MEM_LOAD_UOPS_RETIRED.L3_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1927 /*8*/ { "contested", "thresh >= .05",
1928 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS -w 1",
1929 contestedbroad, 2 },
1930 /*9*/ { "datashare", "thresh >= .05",
1931 "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1932 datasharing_has, 2 },
1933 /*10*/ { "blockstorefwd", "thresh >= .05",
1934 "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1935 blockstoreforward, 2 },
1936 /*11*/ { "aliasing_4k", "thresh >= .1",
1937 "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1938 aliasing_broad, 2 },
1939 /*12*/ { "dtlbmissload", "thresh >= .1",
1940 "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT_4K -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1942 /*13*/ { "br_miss", "thresh >= .2",
1943 "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.CYCLES -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",
1944 br_mispredict_broad, 7 },
1945 /*14*/ { "clears", "thresh >= .02",
1946 "pmcstat -s MACHINE_CLEARS.CYCLES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1948 /*15*/ { "fpassist", "look for a excessive value",
1949 "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
1951 /*16*/ { "otherassistavx", "look for a excessive value",
1952 "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
1953 otherassistavx, 2 },
1954 /*17*/ { "microassist", "thresh >= .2",
1955 "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -w 1",
1956 microassist_broad, 4 },
1961 set_sandybridge(void)
1963 strcpy(the_cpu.cputype, "SandyBridge PMC");
1964 the_cpu.number = SANDY_BRIDGE_COUNT;
1965 the_cpu.ents = sandy_bridge;
1966 the_cpu.explain = explain_name_sb;
1972 strcpy(the_cpu.cputype, "IvyBridge PMC");
1973 the_cpu.number = IVY_BRIDGE_COUNT;
1974 the_cpu.ents = ivy_bridge;
1975 the_cpu.explain = explain_name_ib;
1982 strcpy(the_cpu.cputype, "HASWELL PMC");
1983 the_cpu.number = HASWELL_COUNT;
1984 the_cpu.ents = haswell;
1985 the_cpu.explain = explain_name_has;
1992 strcpy(the_cpu.cputype, "HASWELL PMC");
1993 the_cpu.number = BROADWELL_COUNT;
1994 the_cpu.ents = broadwell;
1995 the_cpu.explain = explain_name_broad;
2000 set_expression(const char *name)
2003 for(i=0 ; i< the_cpu.number; i++) {
2004 if (strcmp(name, the_cpu.ents[i].name) == 0) {
2006 expression = the_cpu.ents[i].func;
2007 command = the_cpu.ents[i].command;
2008 threshold = the_cpu.ents[i].thresh;
2009 if (the_cpu.ents[i].counters_required > max_pmc_counters) {
2010 printf("Test %s requires that the CPU have %d counters and this CPU has only %d\n",
2011 the_cpu.ents[i].name,
2012 the_cpu.ents[i].counters_required, max_pmc_counters);
2013 printf("Sorry this test can not be run\n");
2024 printf("For CPU type %s we have no expression:%s\n",
2025 the_cpu.cputype, name);
2036 validate_expression(char *name)
2041 for(i=0 ; i< the_cpu.number; i++) {
2042 if (strcmp(name, the_cpu.ents[i].name) == 0) {
2054 do_expression(struct counters *cpu, int pos)
2056 if (expression == NULL)
2058 (*expression)(cpu, pos);
2062 process_header(int idx, char *p)
2064 struct counters *up;
2067 * Given header element idx, at p in
2068 * form 's/NN/nameof'
2069 * process the entry to pull out the name and
2072 if (strncmp(p, "s/", 2)) {
2073 printf("Check -- invalid header no s/ in %s\n",
2078 up->cpu = strtol(&p[2], NULL, 10);
2080 for (i=2; i<len; i++) {
2082 nlen = strlen(&p[(i+1)]);
2083 if (nlen < (MAX_NLEN-1)) {
2084 strcpy(up->counter_name, &p[(i+1)]);
2086 strncpy(up->counter_name, &p[(i+1)], (MAX_NLEN-1));
2093 build_counters_from_header(FILE *io)
2095 char buffer[8192], *p;
2099 /* We have a new start, lets
2100 * setup our headers and cpus.
2102 if (fgets(buffer, sizeof(buffer), io) == NULL) {
2103 printf("First line can't be read from file err:%d\n", errno);
2107 * Ok output is an array of counters. Once
2108 * we start to read the values in we must
2109 * put them in there slot to match there CPU and
2110 * counter being updated. We create a mass array
2111 * of the counters, filling in the CPU and
2114 /* How many do we get? */
2115 len = strlen(buffer);
2116 for (i=0, cnt=0; i<len; i++) {
2117 if (strncmp(&buffer[i], "s/", 2) == 0) {
2120 if (buffer[i] == ' ')
2125 mlen = sizeof(struct counters) * cnt;
2126 cnts = malloc(mlen);
2129 printf("No memory err:%d\n", errno);
2132 memset(cnts, 0, mlen);
2133 for (i=0, cnt=0; i<len; i++) {
2134 if (strncmp(&buffer[i], "s/", 2) == 0) {
2137 if (buffer[i] == ' ') {
2142 process_header(cnt, p);
2147 printf("We have %d entries\n", cnt);
2149 extern int max_to_collect;
2150 int max_to_collect = MAX_COUNTER_SLOTS;
2153 read_a_line(FILE *io)
2155 char buffer[8192], *p, *stop;
2158 if (fgets(buffer, sizeof(buffer), io) == NULL) {
2162 for (i=0; i<ncnts; i++) {
2164 cnts[i].vals[pos] = strtol(p, &stop, 0);
2166 cnts[i].sum += cnts[i].vals[pos];
2172 extern int cpu_count_out;
2173 int cpu_count_out=0;
2178 int i, cnt, printed_cnt;
2180 printf("*********************************\n");
2181 for(i=0, cnt=0; i<MAX_CPU; i++) {
2186 cpu_count_out = cnt;
2187 for(i=0, printed_cnt=0; i<MAX_CPU; i++) {
2192 if (printed_cnt == cnt) {
2202 lace_cpus_together(void)
2205 struct counters *cpat, *at;
2207 for(i=0; i<ncnts; i++) {
2209 if (cpat->next_cpu) {
2210 /* Already laced in */
2213 lace_cpu = cpat->cpu;
2214 if (lace_cpu >= MAX_CPU) {
2215 printf("CPU %d to big\n", lace_cpu);
2218 if (glob_cpu[lace_cpu] == NULL) {
2219 glob_cpu[lace_cpu] = cpat;
2221 /* Already processed this cpu */
2224 /* Ok look forward for cpu->cpu and link in */
2225 for(j=(i+1); j<ncnts; j++) {
2230 if (at->cpu == lace_cpu) {
2232 cpat->next_cpu = at;
2241 process_file(char *filename)
2245 int line_at, not_done;
2246 pid_t pid_of_command=0;
2248 if (filename == NULL) {
2249 io = my_popen(command, "r", &pid_of_command);
2251 printf("Can't popen the command %s\n", command);
2255 io = fopen(filename, "r");
2257 printf("Can't process file %s err:%d\n",
2262 build_counters_from_header(io);
2264 /* Nothing we can do */
2265 printf("Nothing to do -- no counters built\n");
2269 my_pclose(io, pid_of_command);
2273 lace_cpus_together();
2276 for (i=0; i<ncnts; i++) {
2277 printf("Counter:%s cpu:%d index:%d\n",
2278 cnts[i].counter_name,
2285 if (read_a_line(io)) {
2290 if (line_at >= max_to_collect) {
2293 if (filename == NULL) {
2295 /* For the ones we dynamically open we print now */
2296 for(i=0, cnt=0; i<MAX_CPU; i++) {
2297 do_expression(glob_cpu[i], (line_at-1));
2299 if (cnt == cpu_count_out) {
2311 my_pclose(io, pid_of_command);
2314 #if defined(__amd64__)
2315 #define cpuid(in,a,b,c,d)\
2316 asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
2318 static __inline void
2319 do_cpuid(u_int ax, u_int cx, u_int *p)
2321 __asm __volatile("cpuid"
2322 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
2323 : "0" (ax), "c" (cx) );
2327 #define cpuid(in, a, b, c, d)
2328 #define do_cpuid(ax, cx, p)
2334 unsigned long eax, ebx, ecx, edx;
2336 pid_t pid_of_command=0;
2339 char linebuf[1024], *str;
2342 eax = ebx = ecx = edx = 0;
2344 cpuid(0, eax, ebx, ecx, edx);
2345 if (ebx == 0x68747541) {
2346 printf("AMD processors are not supported by this program\n");
2349 } else if (ebx == 0x6972794) {
2350 printf("Cyrix processors are not supported by this program\n");
2353 } else if (ebx == 0x756e6547) {
2354 printf("Genuine Intel\n");
2356 printf("Unknown processor type 0x%lx Only Intel AMD64 types are supported by this routine!\n", ebx);
2359 cpuid(1, eax, ebx, ecx, edx);
2360 model = (((eax & 0xF0000) >> 12) | ((eax & 0xF0) >> 4));
2361 printf("CPU model is 0x%x id:0x%lx\n", model, eax);
2362 switch (eax & 0xF00) {
2363 case 0x500: /* Pentium family processors */
2364 printf("Intel Pentium P5\n");
2367 case 0x600: /* Pentium Pro, Celeron, Pentium II & III */
2370 printf("Intel Pentium P6\n");
2375 printf("Intel PII\n");
2378 case 0x6: case 0x16:
2379 printf("Intel CL\n");
2382 case 0x7: case 0x8: case 0xA: case 0xB:
2383 printf("Intel PIII\n");
2387 printf("Intel PM\n");
2391 printf("Intel CORE\n");
2395 printf("Intel CORE2\n");
2399 printf("Intel CORE2EXTREME\n");
2402 case 0x1C: /* Per Intel document 320047-002. */
2403 printf("Intel ATOM\n");
2408 * Per Intel document 253669-032 9/2009,
2409 * pages A-2 and A-57
2412 * Per Intel document 253669-032 9/2009,
2413 * pages A-2 and A-57
2415 printf("Intel COREI7\n");
2419 printf("Intel NEHALEM\n");
2422 case 0x25: /* Per Intel document 253669-033US 12/2009. */
2423 case 0x2C: /* Per Intel document 253669-033US 12/2009. */
2424 printf("Intel WESTMERE\n");
2427 case 0x2F: /* Westmere-EX, seen in wild */
2428 printf("Intel WESTMERE\n");
2431 case 0x2A: /* Per Intel document 253669-039US 05/2011. */
2432 printf("Intel SANDYBRIDGE\n");
2435 case 0x2D: /* Per Intel document 253669-044US 08/2012. */
2436 printf("Intel SANDYBRIDGE_XEON\n");
2439 case 0x3A: /* Per Intel document 253669-043US 05/2012. */
2440 printf("Intel IVYBRIDGE\n");
2443 case 0x3E: /* Per Intel document 325462-045US 01/2013. */
2444 printf("Intel IVYBRIDGE_XEON\n");
2447 case 0x3F: /* Per Intel document 325462-045US 09/2014. */
2448 printf("Intel HASWELL (Xeon)\n");
2451 case 0x3C: /* Per Intel document 325462-045US 01/2013. */
2454 printf("Intel HASWELL\n");
2460 printf("Intel SKY-LAKE\n");
2465 printf("Intel BROADWELL\n");
2470 printf("Intel BROADWEL (Xeon)\n");
2475 /* Per Intel document 330061-001 01/2014. */
2476 printf("Intel ATOM_SILVERMONT\n");
2480 printf("Intel model 0x%x is not known -- sorry\n",
2486 case 0xF00: /* P4 */
2487 printf("Intel unknown model %d\n", model);
2491 do_cpuid(0xa, 0, reg);
2492 max_pmc_counters = (reg[3] & 0x0000000f) + 1;
2493 printf("We have %d PMC counters to work with\n", max_pmc_counters);
2494 /* Ok lets load the list of all known PMC's */
2495 io = my_popen("/usr/sbin/pmccontrol -L", "r", &pid_of_command);
2496 if (valid_pmcs == NULL) {
2498 pmc_allocated_cnt = PMC_INITIAL_ALLOC;
2499 sz = sizeof(char *) * pmc_allocated_cnt;
2500 valid_pmcs = malloc(sz);
2501 if (valid_pmcs == NULL) {
2502 printf("No memory allocation fails at startup?\n");
2505 memset(valid_pmcs, 0, sz);
2508 while (fgets(linebuf, sizeof(linebuf), io) != NULL) {
2509 if (linebuf[0] != '\t') {
2510 /* sometimes headers ;-) */
2513 len = strlen(linebuf);
2514 if (linebuf[(len-1)] == '\n') {
2516 linebuf[(len-1)] = 0;
2519 len = strlen(str) + 1;
2520 valid_pmcs[valid_pmc_cnt] = malloc(len);
2521 if (valid_pmcs[valid_pmc_cnt] == NULL) {
2522 printf("No memory2 allocation fails at startup?\n");
2525 memset(valid_pmcs[valid_pmc_cnt], 0, len);
2526 strcpy(valid_pmcs[valid_pmc_cnt], str);
2528 if (valid_pmc_cnt >= pmc_allocated_cnt) {
2529 /* Got to expand -- unlikely */
2532 sz = sizeof(char *) * (pmc_allocated_cnt * 2);
2535 printf("No memory3 allocation fails at startup?\n");
2538 memset(more, 0, sz);
2539 memcpy(more, valid_pmcs, sz);
2540 pmc_allocated_cnt *= 2;
2545 my_pclose(io, pid_of_command);
2548 printf("Not supported\n");
2556 printf("For CPU's of type %s the following expressions are available:\n",the_cpu.cputype);
2557 printf("-------------------------------------------------------------\n");
2558 for(i=0; i<the_cpu.number; i++){
2559 printf("For -e %s ", the_cpu.ents[i].name);
2560 (*the_cpu.explain)(the_cpu.ents[i].name);
2561 printf("----------------------------\n");
2566 test_for_a_pmc(const char *pmc, int out_so_far)
2569 pid_t pid_of_command=0;
2570 char my_command[1024];
2575 if (out_so_far < 50) {
2576 len = 50 - out_so_far;
2577 for(i=0; i<len; i++) {
2581 sprintf(my_command, "/usr/sbin/pmcstat -w .25 -c 0 -s %s", pmc);
2582 io = my_popen(my_command, "r", &pid_of_command);
2584 printf("Failed -- popen fails\n");
2587 /* Setup what we expect */
2588 len = sprintf(resp, "%s", pmc);
2589 if (fgets(line, sizeof(line), io) == NULL) {
2590 printf("Failed -- no output from pmstat\n");
2593 llen = strlen(line);
2594 if (line[(llen-1)] == '\n') {
2598 for(i=2; i<(llen-len); i++) {
2599 if (strncmp(&line[i], "ERROR", 5) == 0) {
2600 printf("Failed %s\n", line);
2602 } else if (strncmp(&line[i], resp, len) == 0) {
2605 if (fgets(line, sizeof(line), io) == NULL) {
2606 printf("Failed -- no second output from pmstat\n");
2610 for (j=0; j<len; j++) {
2611 if (line[j] == ' ') {
2618 len = strlen(&line[j]);
2620 for(k=0; k<(20-len); k++) {
2625 printf("%s", &line[j]);
2632 printf("Failed -- '%s' not '%s'\n", line, resp);
2634 my_pclose(io, pid_of_command);
2639 add_it_to(char **vars, int cur_cnt, char *name)
2643 for(i=0; i<cur_cnt; i++) {
2644 if (strcmp(vars[i], name) == 0) {
2649 if (vars[cur_cnt] != NULL) {
2650 printf("Cur_cnt:%d filled with %s??\n",
2651 cur_cnt, vars[cur_cnt]);
2655 len = strlen(name) + 1;
2656 vars[cur_cnt] = malloc(len);
2657 if (vars[cur_cnt] == NULL) {
2658 printf("No memory %s\n", __FUNCTION__);
2661 memset(vars[cur_cnt], 0, len);
2662 strcpy(vars[cur_cnt], name);
2667 build_command_for_exp(struct expression *exp)
2670 * Build the pmcstat command to handle
2671 * the passed in expression.
2672 * /usr/sbin/pmcstat -w 1 -s NNN -s QQQ
2673 * where NNN and QQQ represent the PMC's in the expression
2677 int cnt_pmc, alloced_pmcs, i;
2678 struct expression *at;
2682 alloced_pmcs = cnt_pmc = 0;
2683 /* first how many do we have */
2686 if (at->type == TYPE_VALUE_PMC) {
2692 printf("No PMC's in your expression -- nothing to do!!\n");
2695 mal = cnt_pmc * sizeof(char *);
2698 printf("No memory\n");
2701 memset(vars, 0, mal);
2704 if (at->type == TYPE_VALUE_PMC) {
2705 if(add_it_to(vars, alloced_pmcs, at->name)) {
2711 /* Now we have a unique list in vars so create our command */
2712 mal = 23; /* "/usr/sbin/pmcstat -w 1" + \0 */
2713 for(i=0; i<alloced_pmcs; i++) {
2714 mal += strlen(vars[i]) + 4; /* var + " -s " */
2716 cmd = malloc((mal+2));
2718 printf("%s out of mem\n", __FUNCTION__);
2721 memset(cmd, 0, (mal+2));
2722 strcpy(cmd, "/usr/sbin/pmcstat -w 1");
2724 for(i=0; i<alloced_pmcs; i++) {
2725 sprintf(forming, " -s %s", vars[i]);
2726 strcat(cmd, forming);
2735 user_expr(struct counters *cpu, int pos)
2739 struct counters *var;
2740 struct expression *at;
2744 if (at->type == TYPE_VALUE_PMC) {
2745 var = find_counter(cpu, at->name);
2747 printf("%s:Can't find counter %s?\n", __FUNCTION__, at->name);
2751 at->value = var->vals[pos] * 1.0;
2753 at->value = var->sum * 1.0;
2758 res = run_expr(master_exp, 1, NULL);
2759 ret = printf("%1.3f", res);
2765 set_manual_exp(struct expression *exp)
2767 expression = user_expr;
2768 command = build_command_for_exp(exp);
2769 threshold = "User defined threshold";
2776 printf("Running tests on %d PMC's this may take some time\n", valid_pmc_cnt);
2777 printf("------------------------------------------------------------------------\n");
2778 for(i=0; i<valid_pmc_cnt; i++) {
2779 lenout = printf("%s", valid_pmcs[i]);
2781 test_for_a_pmc(valid_pmcs[i], lenout);
2788 printf("PMC Abbreviation\n");
2789 printf("--------------------------------------------------------------\n");
2790 for(i=0; i<valid_pmc_cnt; i++) {
2791 cnt = printf("%s", valid_pmcs[i]);
2792 for(j=cnt; j<52; j++) {
2795 printf("%%%d\n", i);
2801 main(int argc, char **argv)
2804 char *filename=NULL;
2805 const char *name=NULL;
2811 memset(glob_cpu, 0, sizeof(glob_cpu));
2812 while ((i = getopt(argc, argv, "ALHhvm:i:?e:TE:")) != -1) {
2821 printf("**********************************\n");
2823 printf("**********************************\n");
2830 master_exp = parse_expression(optarg);
2832 set_manual_exp(master_exp);
2836 if (validate_expression(optarg)) {
2837 printf("Unknown expression %s\n", optarg);
2841 set_expression(optarg);
2844 max_to_collect = strtol(optarg, NULL, 0);
2845 if (max_to_collect > MAX_COUNTER_SLOTS) {
2846 /* You can't collect more than max in array */
2847 max_to_collect = MAX_COUNTER_SLOTS;
2862 printf("Use %s [ -i inputfile -v -m max_to_collect -e expr -E -h -? -H]\n",
2864 printf("-i inputfile -- use source as inputfile not stdin (if stdin collect)\n");
2865 printf("-v -- verbose dump debug type things -- you don't want this\n");
2866 printf("-m N -- maximum to collect is N measurements\n");
2867 printf("-e expr-name -- Do expression expr-name\n");
2868 printf("-E 'your expression' -- Do your expression\n");
2869 printf("-h -- Don't do the expression I put in -e xxx just explain what it does and exit\n");
2870 printf("-H -- Don't run anything, just explain all canned expressions\n");
2871 printf("-T -- Test all PMC's defined by this processor\n");
2872 printf("-A -- Run all canned tests\n");
2877 if ((run_all == 0) && (name == NULL) && (filename == NULL) &&
2878 (test_mode == 0) && (master_exp == NULL)) {
2879 printf("Without setting an expression we cannot dynamically gather information\n");
2880 printf("you must supply a filename (and you probably want verbosity)\n");
2883 if (run_all && max_to_collect > 10) {
2890 printf("*********************************\n");
2891 if ((master_exp == NULL) && name) {
2892 (*the_cpu.explain)(name);
2893 } else if (master_exp) {
2894 printf("Examine your expression ");
2895 print_exp(master_exp);
2896 printf("User defined threshold\n");
2903 name = the_cpu.ents[test_at].name;
2904 printf("***Test %s (threshold %s)****\n", name, the_cpu.ents[test_at].thresh);
2906 if (set_expression(name) == -1) {
2907 if (test_at >= the_cpu.number) {
2914 process_file(filename);
2916 for (i=0; i<ncnts; i++) {
2917 printf("Counter:%s cpu:%d index:%d\n",
2918 cnts[i].counter_name,
2920 for(j=0; j<cnts[i].pos; j++) {
2921 printf(" val - %ld\n", (long int)cnts[i].vals[j]);
2923 printf(" sum - %ld\n", (long int)cnts[i].sum);
2926 if (expression == NULL) {
2929 if (max_to_collect > 1) {
2930 for(i=0, cnt=0; i<MAX_CPU; i++) {
2932 do_expression(glob_cpu[i], -1);
2934 if (cnt == cpu_count_out) {
2943 if (run_all && (test_at < the_cpu.number)) {
2944 memset(glob_cpu, 0, sizeof(glob_cpu));
2946 printf("*********************************\n");
2948 } else if (run_all) {
2950 printf("*********************************\n");