aboutsummaryrefslogtreecommitdiff
path: root/powerpc/pmu/ebb/ebb.c
diff options
context:
space:
mode:
Diffstat (limited to 'powerpc/pmu/ebb/ebb.c')
-rw-r--r--powerpc/pmu/ebb/ebb.c478
1 files changed, 0 insertions, 478 deletions
diff --git a/powerpc/pmu/ebb/ebb.c b/powerpc/pmu/ebb/ebb.c
deleted file mode 100644
index d7a72ce..0000000
--- a/powerpc/pmu/ebb/ebb.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright 2014, Michael Ellerman, IBM Corp.
- * Licensed under GPLv2.
- */
-
-#define _GNU_SOURCE /* For CPU_ZERO etc. */
-
-#include <sched.h>
-#include <sys/wait.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-
-#include "trace.h"
-#include "reg.h"
-#include "ebb.h"
-
-
-void (*ebb_user_func)(void);
-
-void ebb_hook(void)
-{
- if (ebb_user_func)
- ebb_user_func();
-}
-
-struct ebb_state ebb_state;
-
-u64 sample_period = 0x40000000ull;
-
-void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
-{
- u64 val;
-
- /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
- /* 3) set MMCR0[PMAE] - docs say BESCR[PME] should do this */
- val = mfspr(SPRN_MMCR0);
- mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
-
- /* 4) clear BESCR[PMEO] */
- mtspr(SPRN_BESCRR, BESCR_PMEO);
-
- /* 5) set BESCR[PME] */
- mtspr(SPRN_BESCRS, BESCR_PME);
-
- /* 6) rfebb 1 - done in our caller */
-}
-
-void reset_ebb(void)
-{
- reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
-}
-
-/* Called outside of the EBB handler to check MMCR0 is sane */
-int ebb_check_mmcr0(void)
-{
- u64 val;
-
- val = mfspr(SPRN_MMCR0);
- if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) {
- /* It's OK if we see FC & PMAO, but not FC by itself */
- printf("Outside of loop, only FC set 0x%llx\n", val);
- return 1;
- }
-
- return 0;
-}
-
-bool ebb_check_count(int pmc, u64 sample_period, int fudge)
-{
- u64 count, upper, lower;
-
- count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)];
-
- lower = ebb_state.stats.ebb_count * (sample_period - fudge);
-
- if (count < lower) {
- printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n",
- pmc, count, lower, lower - count);
- return false;
- }
-
- upper = ebb_state.stats.ebb_count * (sample_period + fudge);
-
- if (count > upper) {
- printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n",
- pmc, count, upper, count - upper);
- return false;
- }
-
- printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n",
- pmc, count, lower, upper, count - lower, upper - count);
-
- return true;
-}
-
-void standard_ebb_callee(void)
-{
- int found, i;
- u64 val;
-
- val = mfspr(SPRN_BESCR);
- if (!(val & BESCR_PMEO)) {
- ebb_state.stats.spurious++;
- goto out;
- }
-
- ebb_state.stats.ebb_count++;
- trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
-
- val = mfspr(SPRN_MMCR0);
- trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
-
- found = 0;
- for (i = 1; i <= 6; i++) {
- if (ebb_state.pmc_enable[PMC_INDEX(i)])
- found += count_pmc(i, sample_period);
- }
-
- if (!found)
- ebb_state.stats.no_overflow++;
-
-out:
- reset_ebb();
-}
-
-extern void ebb_handler(void);
-
-void setup_ebb_handler(void (*callee)(void))
-{
- u64 entry;
-
-#if defined(_CALL_ELF) && _CALL_ELF == 2
- entry = (u64)ebb_handler;
-#else
- struct opd
- {
- u64 entry;
- u64 toc;
- } *opd;
-
- opd = (struct opd *)ebb_handler;
- entry = opd->entry;
-#endif
- printf("EBB Handler is at %#llx\n", entry);
-
- ebb_user_func = callee;
-
- /* Ensure ebb_user_func is set before we set the handler */
- mb();
- mtspr(SPRN_EBBHR, entry);
-
- /* Make sure the handler is set before we return */
- mb();
-}
-
-void clear_ebb_stats(void)
-{
- memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
-}
-
-void dump_summary_ebb_state(void)
-{
- printf("ebb_state:\n" \
- " ebb_count = %d\n" \
- " spurious = %d\n" \
- " negative = %d\n" \
- " no_overflow = %d\n" \
- " pmc[1] count = 0x%llx\n" \
- " pmc[2] count = 0x%llx\n" \
- " pmc[3] count = 0x%llx\n" \
- " pmc[4] count = 0x%llx\n" \
- " pmc[5] count = 0x%llx\n" \
- " pmc[6] count = 0x%llx\n",
- ebb_state.stats.ebb_count, ebb_state.stats.spurious,
- ebb_state.stats.negative, ebb_state.stats.no_overflow,
- ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1],
- ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3],
- ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]);
-}
-
-static char *decode_mmcr0(u32 value)
-{
- static char buf[16];
-
- buf[0] = '\0';
-
- if (value & (1 << 31))
- strcat(buf, "FC ");
- if (value & (1 << 26))
- strcat(buf, "PMAE ");
- if (value & (1 << 7))
- strcat(buf, "PMAO ");
-
- return buf;
-}
-
-static char *decode_bescr(u64 value)
-{
- static char buf[16];
-
- buf[0] = '\0';
-
- if (value & (1ull << 63))
- strcat(buf, "GE ");
- if (value & (1ull << 32))
- strcat(buf, "PMAE ");
- if (value & 1)
- strcat(buf, "PMAO ");
-
- return buf;
-}
-
-void dump_ebb_hw_state(void)
-{
- u64 bescr;
- u32 mmcr0;
-
- mmcr0 = mfspr(SPRN_MMCR0);
- bescr = mfspr(SPRN_BESCR);
-
- printf("HW state:\n" \
- "MMCR0 0x%016x %s\n" \
- "MMCR2 0x%016lx\n" \
- "EBBHR 0x%016lx\n" \
- "BESCR 0x%016llx %s\n" \
- "PMC1 0x%016lx\n" \
- "PMC2 0x%016lx\n" \
- "PMC3 0x%016lx\n" \
- "PMC4 0x%016lx\n" \
- "PMC5 0x%016lx\n" \
- "PMC6 0x%016lx\n" \
- "SIAR 0x%016lx\n",
- mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
- mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
- mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
- mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
- mfspr(SPRN_SIAR));
-}
-
-void dump_ebb_state(void)
-{
- dump_summary_ebb_state();
-
- dump_ebb_hw_state();
-
- trace_buffer_print(ebb_state.trace);
-}
-
-int count_pmc(int pmc, uint32_t sample_period)
-{
- uint32_t start_value;
- u64 val;
-
- /* 0) Read PMC */
- start_value = pmc_sample_period(sample_period);
-
- val = read_pmc(pmc);
- if (val < start_value)
- ebb_state.stats.negative++;
- else
- ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value;
-
- trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val);
-
- /* 1) Reset PMC */
- write_pmc(pmc, start_value);
-
- /* Report if we overflowed */
- return val >= COUNTER_OVERFLOW;
-}
-
-int ebb_event_enable(struct event *e)
-{
- int rc;
-
- /* Ensure any SPR writes are ordered vs us */
- mb();
-
- rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
- if (rc)
- return rc;
-
- rc = event_read(e);
-
- /* Ditto */
- mb();
-
- return rc;
-}
-
-void ebb_freeze_pmcs(void)
-{
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
- mb();
-}
-
-void ebb_unfreeze_pmcs(void)
-{
- /* Unfreeze counters */
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
- mb();
-}
-
-void ebb_global_enable(void)
-{
- /* Enable EBBs globally and PMU EBBs */
- mtspr(SPRN_BESCR, 0x8000000100000000ull);
- mb();
-}
-
-void ebb_global_disable(void)
-{
- /* Disable EBBs & freeze counters, events are still scheduled */
- mtspr(SPRN_BESCRR, BESCR_PME);
- mb();
-}
-
-void event_ebb_init(struct event *e)
-{
- e->attr.config |= (1ull << 63);
-}
-
-void event_bhrb_init(struct event *e, unsigned ifm)
-{
- e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
-}
-
-void event_leader_ebb_init(struct event *e)
-{
- event_ebb_init(e);
-
- e->attr.exclusive = 1;
- e->attr.pinned = 1;
-}
-
-int ebb_child(union pipe read_pipe, union pipe write_pipe)
-{
- struct event event;
- uint64_t val;
-
- FAIL_IF(wait_for_parent(read_pipe));
-
- event_init_named(&event, 0x1001e, "cycles");
- event_leader_ebb_init(&event);
-
- event.attr.exclude_kernel = 1;
- event.attr.exclude_hv = 1;
- event.attr.exclude_idle = 1;
-
- FAIL_IF(event_open(&event));
-
- ebb_enable_pmc_counting(1);
- setup_ebb_handler(standard_ebb_callee);
- ebb_global_enable();
-
- FAIL_IF(event_enable(&event));
-
- if (event_read(&event)) {
- /*
- * Some tests expect to fail here, so don't report an error on
- * this line, and return a distinguisable error code. Tell the
- * parent an error happened.
- */
- notify_parent_of_error(write_pipe);
- return 2;
- }
-
- mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
-
- FAIL_IF(notify_parent(write_pipe));
- FAIL_IF(wait_for_parent(read_pipe));
- FAIL_IF(notify_parent(write_pipe));
-
- while (ebb_state.stats.ebb_count < 20) {
- FAIL_IF(core_busy_loop());
-
- /* To try and hit SIGILL case */
- val = mfspr(SPRN_MMCRA);
- val |= mfspr(SPRN_MMCR2);
- val |= mfspr(SPRN_MMCR0);
- }
-
- ebb_global_disable();
- ebb_freeze_pmcs();
-
- count_pmc(1, sample_period);
-
- dump_ebb_state();
-
- event_close(&event);
-
- FAIL_IF(ebb_state.stats.ebb_count == 0);
-
- return 0;
-}
-
-static jmp_buf setjmp_env;
-
-static void sigill_handler(int signal)
-{
- printf("Took sigill\n");
- longjmp(setjmp_env, 1);
-}
-
-static struct sigaction sigill_action = {
- .sa_handler = sigill_handler,
-};
-
-int catch_sigill(void (*func)(void))
-{
- if (sigaction(SIGILL, &sigill_action, NULL)) {
- perror("sigaction");
- return 1;
- }
-
- if (setjmp(setjmp_env) == 0) {
- func();
- return 1;
- }
-
- return 0;
-}
-
-void write_pmc1(void)
-{
- mtspr(SPRN_PMC1, 0);
-}
-
-void write_pmc(int pmc, u64 value)
-{
- switch (pmc) {
- case 1: mtspr(SPRN_PMC1, value); break;
- case 2: mtspr(SPRN_PMC2, value); break;
- case 3: mtspr(SPRN_PMC3, value); break;
- case 4: mtspr(SPRN_PMC4, value); break;
- case 5: mtspr(SPRN_PMC5, value); break;
- case 6: mtspr(SPRN_PMC6, value); break;
- }
-}
-
-u64 read_pmc(int pmc)
-{
- switch (pmc) {
- case 1: return mfspr(SPRN_PMC1);
- case 2: return mfspr(SPRN_PMC2);
- case 3: return mfspr(SPRN_PMC3);
- case 4: return mfspr(SPRN_PMC4);
- case 5: return mfspr(SPRN_PMC5);
- case 6: return mfspr(SPRN_PMC6);
- }
-
- return 0;
-}
-
-static void term_handler(int signal)
-{
- dump_summary_ebb_state();
- dump_ebb_hw_state();
- abort();
-}
-
-struct sigaction term_action = {
- .sa_handler = term_handler,
-};
-
-static void __attribute__((constructor)) ebb_init(void)
-{
- clear_ebb_stats();
-
- if (sigaction(SIGTERM, &term_action, NULL))
- perror("sigaction");
-
- ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024);
-}