1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2014, Michael Ellerman, IBM Corp. |
4 | */ |
5 | |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
8 | #include <stdbool.h> |
9 | |
10 | #include "ebb.h" |
11 | |
12 | |
13 | /* |
14 | * Test of counting cycles while using MMCR0_FC (freeze counters) to only count |
15 | * parts of the code. This is complicated by the fact that FC is set by the |
16 | * hardware when the event overflows. We may take the EBB after we have set FC, |
17 | * so we have to be careful about whether we clear FC at the end of the EBB |
18 | * handler or not. |
19 | */ |
20 | |
21 | static bool counters_frozen = false; |
22 | static int ebbs_while_frozen = 0; |
23 | |
24 | static void ebb_callee(void) |
25 | { |
26 | uint64_t mask, val; |
27 | |
28 | mask = MMCR0_PMAO | MMCR0_FC; |
29 | |
30 | val = mfspr(SPRN_BESCR); |
31 | if (!(val & BESCR_PMEO)) { |
32 | ebb_state.stats.spurious++; |
33 | goto out; |
34 | } |
35 | |
36 | ebb_state.stats.ebb_count++; |
37 | trace_log_counter(tb: ebb_state.trace, value: ebb_state.stats.ebb_count); |
38 | |
39 | val = mfspr(SPRN_MMCR0); |
40 | trace_log_reg(tb: ebb_state.trace, reg: SPRN_MMCR0, value: val); |
41 | |
42 | if (counters_frozen) { |
43 | trace_log_string(tb: ebb_state.trace, str: "frozen" ); |
44 | ebbs_while_frozen++; |
45 | mask &= ~MMCR0_FC; |
46 | } |
47 | |
48 | count_pmc(pmc: 1, sample_period); |
49 | out: |
50 | reset_ebb_with_clear_mask(mmcr0_clear_mask: mask); |
51 | } |
52 | |
53 | int cycles_with_freeze(void) |
54 | { |
55 | struct event event; |
56 | uint64_t val; |
57 | bool fc_cleared; |
58 | |
59 | SKIP_IF(!ebb_is_supported()); |
60 | |
61 | event_init_named(e: &event, config: 0x1001e, name: "cycles" ); |
62 | event_leader_ebb_init(e: &event); |
63 | |
64 | event.attr.exclude_kernel = 1; |
65 | event.attr.exclude_hv = 1; |
66 | event.attr.exclude_idle = 1; |
67 | |
68 | FAIL_IF(event_open(e: &event)); |
69 | |
70 | setup_ebb_handler(ebb_callee); |
71 | ebb_global_enable(); |
72 | FAIL_IF(ebb_event_enable(e: &event)); |
73 | |
74 | mtspr(SPRN_PMC1, pmc_sample_period(value: sample_period)); |
75 | |
76 | fc_cleared = false; |
77 | |
78 | /* Make sure we loop until we take at least one EBB */ |
79 | while ((ebb_state.stats.ebb_count < 20 && !fc_cleared) || |
80 | ebb_state.stats.ebb_count < 1) |
81 | { |
82 | counters_frozen = false; |
83 | mb(); |
84 | mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); |
85 | |
86 | FAIL_IF(core_busy_loop()); |
87 | |
88 | counters_frozen = true; |
89 | mb(); |
90 | mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); |
91 | |
92 | val = mfspr(SPRN_MMCR0); |
93 | if (! (val & MMCR0_FC)) { |
94 | printf("Outside of loop, FC NOT set MMCR0 0x%lx\n" , val); |
95 | fc_cleared = true; |
96 | } |
97 | } |
98 | |
99 | ebb_global_disable(); |
100 | ebb_freeze_pmcs(); |
101 | |
102 | dump_ebb_state(); |
103 | |
104 | printf("EBBs while frozen %d\n" , ebbs_while_frozen); |
105 | |
106 | event_close(e: &event); |
107 | |
108 | FAIL_IF(ebb_state.stats.ebb_count == 0); |
109 | FAIL_IF(fc_cleared); |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | int main(void) |
115 | { |
116 | return test_harness(cycles_with_freeze, "cycles_with_freeze" ); |
117 | } |
118 | |