|
@@ -0,0 +1,727 @@
|
|
|
+/*
|
|
|
+ * 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" \
|
|
|
+ "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_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 core_busy_loop(void)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ asm volatile (
|
|
|
+ "li 3, 0x3030\n"
|
|
|
+ "std 3, -96(1)\n"
|
|
|
+ "li 4, 0x4040\n"
|
|
|
+ "std 4, -104(1)\n"
|
|
|
+ "li 5, 0x5050\n"
|
|
|
+ "std 5, -112(1)\n"
|
|
|
+ "li 6, 0x6060\n"
|
|
|
+ "std 6, -120(1)\n"
|
|
|
+ "li 7, 0x7070\n"
|
|
|
+ "std 7, -128(1)\n"
|
|
|
+ "li 8, 0x0808\n"
|
|
|
+ "std 8, -136(1)\n"
|
|
|
+ "li 9, 0x0909\n"
|
|
|
+ "std 9, -144(1)\n"
|
|
|
+ "li 10, 0x1010\n"
|
|
|
+ "std 10, -152(1)\n"
|
|
|
+ "li 11, 0x1111\n"
|
|
|
+ "std 11, -160(1)\n"
|
|
|
+ "li 14, 0x1414\n"
|
|
|
+ "std 14, -168(1)\n"
|
|
|
+ "li 15, 0x1515\n"
|
|
|
+ "std 15, -176(1)\n"
|
|
|
+ "li 16, 0x1616\n"
|
|
|
+ "std 16, -184(1)\n"
|
|
|
+ "li 17, 0x1717\n"
|
|
|
+ "std 17, -192(1)\n"
|
|
|
+ "li 18, 0x1818\n"
|
|
|
+ "std 18, -200(1)\n"
|
|
|
+ "li 19, 0x1919\n"
|
|
|
+ "std 19, -208(1)\n"
|
|
|
+ "li 20, 0x2020\n"
|
|
|
+ "std 20, -216(1)\n"
|
|
|
+ "li 21, 0x2121\n"
|
|
|
+ "std 21, -224(1)\n"
|
|
|
+ "li 22, 0x2222\n"
|
|
|
+ "std 22, -232(1)\n"
|
|
|
+ "li 23, 0x2323\n"
|
|
|
+ "std 23, -240(1)\n"
|
|
|
+ "li 24, 0x2424\n"
|
|
|
+ "std 24, -248(1)\n"
|
|
|
+ "li 25, 0x2525\n"
|
|
|
+ "std 25, -256(1)\n"
|
|
|
+ "li 26, 0x2626\n"
|
|
|
+ "std 26, -264(1)\n"
|
|
|
+ "li 27, 0x2727\n"
|
|
|
+ "std 27, -272(1)\n"
|
|
|
+ "li 28, 0x2828\n"
|
|
|
+ "std 28, -280(1)\n"
|
|
|
+ "li 29, 0x2929\n"
|
|
|
+ "std 29, -288(1)\n"
|
|
|
+ "li 30, 0x3030\n"
|
|
|
+ "li 31, 0x3131\n"
|
|
|
+
|
|
|
+ "li 3, 0\n"
|
|
|
+ "0: "
|
|
|
+ "addi 3, 3, 1\n"
|
|
|
+ "cmpwi 3, 100\n"
|
|
|
+ "blt 0b\n"
|
|
|
+
|
|
|
+ /* Return 1 (fail) unless we get through all the checks */
|
|
|
+ "li 0, 1\n"
|
|
|
+
|
|
|
+ /* Check none of our registers have been corrupted */
|
|
|
+ "cmpwi 4, 0x4040\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 5, 0x5050\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 6, 0x6060\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 7, 0x7070\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 8, 0x0808\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 9, 0x0909\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 10, 0x1010\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 11, 0x1111\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 14, 0x1414\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 15, 0x1515\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 16, 0x1616\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 17, 0x1717\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 18, 0x1818\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 19, 0x1919\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 20, 0x2020\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 21, 0x2121\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 22, 0x2222\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 23, 0x2323\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 24, 0x2424\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 25, 0x2525\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 26, 0x2626\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 27, 0x2727\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 28, 0x2828\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 29, 0x2929\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 30, 0x3030\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "cmpwi 31, 0x3131\n"
|
|
|
+ "bne 1f\n"
|
|
|
+
|
|
|
+ /* Load junk into all our registers before we reload them from the stack. */
|
|
|
+ "li 3, 0xde\n"
|
|
|
+ "li 4, 0xad\n"
|
|
|
+ "li 5, 0xbe\n"
|
|
|
+ "li 6, 0xef\n"
|
|
|
+ "li 7, 0xde\n"
|
|
|
+ "li 8, 0xad\n"
|
|
|
+ "li 9, 0xbe\n"
|
|
|
+ "li 10, 0xef\n"
|
|
|
+ "li 11, 0xde\n"
|
|
|
+ "li 14, 0xad\n"
|
|
|
+ "li 15, 0xbe\n"
|
|
|
+ "li 16, 0xef\n"
|
|
|
+ "li 17, 0xde\n"
|
|
|
+ "li 18, 0xad\n"
|
|
|
+ "li 19, 0xbe\n"
|
|
|
+ "li 20, 0xef\n"
|
|
|
+ "li 21, 0xde\n"
|
|
|
+ "li 22, 0xad\n"
|
|
|
+ "li 23, 0xbe\n"
|
|
|
+ "li 24, 0xef\n"
|
|
|
+ "li 25, 0xde\n"
|
|
|
+ "li 26, 0xad\n"
|
|
|
+ "li 27, 0xbe\n"
|
|
|
+ "li 28, 0xef\n"
|
|
|
+ "li 29, 0xdd\n"
|
|
|
+
|
|
|
+ "ld 3, -96(1)\n"
|
|
|
+ "cmpwi 3, 0x3030\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 4, -104(1)\n"
|
|
|
+ "cmpwi 4, 0x4040\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 5, -112(1)\n"
|
|
|
+ "cmpwi 5, 0x5050\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 6, -120(1)\n"
|
|
|
+ "cmpwi 6, 0x6060\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 7, -128(1)\n"
|
|
|
+ "cmpwi 7, 0x7070\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 8, -136(1)\n"
|
|
|
+ "cmpwi 8, 0x0808\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 9, -144(1)\n"
|
|
|
+ "cmpwi 9, 0x0909\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 10, -152(1)\n"
|
|
|
+ "cmpwi 10, 0x1010\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 11, -160(1)\n"
|
|
|
+ "cmpwi 11, 0x1111\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 14, -168(1)\n"
|
|
|
+ "cmpwi 14, 0x1414\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 15, -176(1)\n"
|
|
|
+ "cmpwi 15, 0x1515\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 16, -184(1)\n"
|
|
|
+ "cmpwi 16, 0x1616\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 17, -192(1)\n"
|
|
|
+ "cmpwi 17, 0x1717\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 18, -200(1)\n"
|
|
|
+ "cmpwi 18, 0x1818\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 19, -208(1)\n"
|
|
|
+ "cmpwi 19, 0x1919\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 20, -216(1)\n"
|
|
|
+ "cmpwi 20, 0x2020\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 21, -224(1)\n"
|
|
|
+ "cmpwi 21, 0x2121\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 22, -232(1)\n"
|
|
|
+ "cmpwi 22, 0x2222\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 23, -240(1)\n"
|
|
|
+ "cmpwi 23, 0x2323\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 24, -248(1)\n"
|
|
|
+ "cmpwi 24, 0x2424\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 25, -256(1)\n"
|
|
|
+ "cmpwi 25, 0x2525\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 26, -264(1)\n"
|
|
|
+ "cmpwi 26, 0x2626\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 27, -272(1)\n"
|
|
|
+ "cmpwi 27, 0x2727\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 28, -280(1)\n"
|
|
|
+ "cmpwi 28, 0x2828\n"
|
|
|
+ "bne 1f\n"
|
|
|
+ "ld 29, -288(1)\n"
|
|
|
+ "cmpwi 29, 0x2929\n"
|
|
|
+ "bne 1f\n"
|
|
|
+
|
|
|
+ /* Load 0 (success) to return */
|
|
|
+ "li 0, 0\n"
|
|
|
+
|
|
|
+ "1: mr %0, 0\n"
|
|
|
+
|
|
|
+ : "=r" (rc)
|
|
|
+ : /* no inputs */
|
|
|
+ : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14",
|
|
|
+ "15", "16", "17", "18", "19", "20", "21", "22", "23",
|
|
|
+ "24", "25", "26", "27", "28", "29", "30", "31",
|
|
|
+ "memory"
|
|
|
+ );
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+int core_busy_loop_with_freeze(void)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
|
|
|
+ rc = core_busy_loop();
|
|
|
+ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+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);
|
|
|
+}
|