2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
11 #include <sys/prctl.h>
17 * Run a calibrated instruction loop and count instructions executed using
18 * EBBs. Make sure the counts look right.
21 extern void thirty_two_instruction_loop(uint64_t loops
);
23 static bool counters_frozen
= true;
25 static int do_count_loop(struct event
*event
, uint64_t instructions
,
26 uint64_t overhead
, bool report
)
28 int64_t difference
, expected
;
33 counters_frozen
= false;
35 mtspr(SPRN_MMCR0
, mfspr(SPRN_MMCR0
) & ~MMCR0_FC
);
37 thirty_two_instruction_loop(instructions
>> 5);
39 counters_frozen
= true;
41 mtspr(SPRN_MMCR0
, mfspr(SPRN_MMCR0
) | MMCR0_FC
);
43 count_pmc(4, sample_period
);
45 event
->result
.value
= ebb_state
.stats
.pmc_count
[4-1];
46 expected
= instructions
+ overhead
;
47 difference
= event
->result
.value
- expected
;
48 percentage
= (double)difference
/ event
->result
.value
* 100;
51 printf("Looped for %lu instructions, overhead %lu\n", instructions
, overhead
);
52 printf("Expected %lu\n", expected
);
53 printf("Actual %llu\n", event
->result
.value
);
54 printf("Delta %ld, %f%%\n", difference
, percentage
);
55 printf("Took %d EBBs\n", ebb_state
.stats
.ebb_count
);
59 difference
= -difference
;
61 /* Tolerate a difference of up to 0.0001 % */
62 difference
*= 10000 * 100;
63 if (difference
/ event
->result
.value
)
69 /* Count how many instructions it takes to do a null loop */
70 static uint64_t determine_overhead(struct event
*event
)
72 uint64_t current
, overhead
;
75 do_count_loop(event
, 0, 0, false);
76 overhead
= event
->result
.value
;
78 for (i
= 0; i
< 100; i
++) {
79 do_count_loop(event
, 0, 0, false);
80 current
= event
->result
.value
;
81 if (current
< overhead
) {
82 printf("Replacing overhead %lu with %lu\n", overhead
, current
);
90 static void pmc4_ebb_callee(void)
94 val
= mfspr(SPRN_BESCR
);
95 if (!(val
& BESCR_PMEO
)) {
96 ebb_state
.stats
.spurious
++;
100 ebb_state
.stats
.ebb_count
++;
101 count_pmc(4, sample_period
);
104 reset_ebb_with_clear_mask(MMCR0_PMAO
);
109 int instruction_count(void)
114 SKIP_IF(!ebb_is_supported());
116 event_init_named(&event
, 0x400FA, "PM_RUN_INST_CMPL");
117 event_leader_ebb_init(&event
);
118 event
.attr
.exclude_kernel
= 1;
119 event
.attr
.exclude_hv
= 1;
120 event
.attr
.exclude_idle
= 1;
122 FAIL_IF(event_open(&event
));
123 FAIL_IF(ebb_event_enable(&event
));
125 sample_period
= COUNTER_OVERFLOW
;
127 setup_ebb_handler(pmc4_ebb_callee
);
128 mtspr(SPRN_MMCR0
, mfspr(SPRN_MMCR0
) & ~MMCR0_FC
);
131 overhead
= determine_overhead(&event
);
132 printf("Overhead of null loop: %lu instructions\n", overhead
);
134 /* Run for 1M instructions */
135 FAIL_IF(do_count_loop(&event
, 0x100000, overhead
, true));
137 /* Run for 10M instructions */
138 FAIL_IF(do_count_loop(&event
, 0xa00000, overhead
, true));
140 /* Run for 100M instructions */
141 FAIL_IF(do_count_loop(&event
, 0x6400000, overhead
, true));
143 /* Run for 1G instructions */
144 FAIL_IF(do_count_loop(&event
, 0x40000000, overhead
, true));
146 /* Run for 16G instructions */
147 FAIL_IF(do_count_loop(&event
, 0x400000000, overhead
, true));
149 /* Run for 64G instructions */
150 FAIL_IF(do_count_loop(&event
, 0x1000000000, overhead
, true));
152 /* Run for 128G instructions */
153 FAIL_IF(do_count_loop(&event
, 0x2000000000, overhead
, true));
155 ebb_global_disable();
158 printf("Finished OK\n");
165 return test_harness(instruction_count
, "instruction_count");
This page took 0.044181 seconds and 5 git commands to generate.