diff options
author | Milosz Wasilewski <milosz.wasilewski@hackbox.linaro.org> | 2014-10-02 10:16:18 +0100 |
---|---|---|
committer | Milosz Wasilewski <milosz.wasilewski@hackbox.linaro.org> | 2014-10-02 10:16:18 +0100 |
commit | 8b27a74bc734d860958941b1a331aa7b38bc2af4 (patch) | |
tree | 90f368cfd48a916aa52ddbd3356a7ef2224384a8 /powerpc/pmu | |
parent | e14eb051ff73ab8692770762adf44045ba092398 (diff) |
Update to 54cd4bea5a18f7bd5921a76d31eef4c61a68d8e7 from repo http://git.linaro.org/kernel/linux-linaro-stable.git branch linux-linaro-lsk-v3.10f6e46ae658e4443e765f87702603deca167f2b57f1326e0892329b0d58dec467f71f5d94c4d5d5a9d266af7f712dc494727b6a18e26fb123911884d5ceafc84623c8ef94c13a87363277a595988b2b79c810fcb930d9c705774427bb6eb551b2e1108adbc293f79246d7cdaf6e75b40aa1f957eb8d195835bbba26b2fc88c77239ebcd45d7fb669018511dfeba0bfedf4c9cad58f56a7038d1462ffc21cd33dfb94eedf4bb47fe789e3947875beb24f558ebd11988720d8b842c59efcc0c4dc17e2107f4dae502f580124ed1ec12ae83dfdcae3ca15e491a813c1729709d22822886bfb105a1c498c14ab6647d0f1284692d96aa22dea8bb80018c6a76556ad6afd464a654cd4bea5a18f7bd5921a76d31eef4c61a68d8e743e7406efd7822d75c64310461d2cbca0ece19f02eb736d6b425cb932b038fd555243b9b0e59c0362156eda2aafa0b0f660656246a11d7c2a9947ff91874098820e8269fe88d67bc08c908134dd8710215f82fce54b86e159fe5a1d41dcdc89e12b264590bde84f40232e0f81bb9fa79d7953fed4a32811clinux-linaro-stable-3.10
Diffstat (limited to 'powerpc/pmu')
40 files changed, 0 insertions, 4587 deletions
diff --git a/powerpc/pmu/Makefile b/powerpc/pmu/Makefile deleted file mode 100644 index c9f4263..0000000 --- a/powerpc/pmu/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -noarg: - $(MAKE) -C ../ - -PROGS := count_instructions l3_bank_test per_event_excludes -EXTRA_SOURCES := ../harness.c event.c lib.c - -SUB_TARGETS = ebb - -all: $(PROGS) $(SUB_TARGETS) - -$(PROGS): $(EXTRA_SOURCES) - -# loop.S can only be built 64-bit -count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) - $(CC) $(CFLAGS) -m64 -o $@ $^ - -run_tests: all sub_run_tests - @-for PROG in $(PROGS); do \ - ./$$PROG; \ - done; - -clean: sub_clean - rm -f $(PROGS) loop.o - -$(SUB_TARGETS): - $(MAKE) -k -C $@ all - -sub_run_tests: all - @for TARGET in $(SUB_TARGETS); do \ - $(MAKE) -C $$TARGET run_tests; \ - done; - -sub_clean: - @for TARGET in $(SUB_TARGETS); do \ - $(MAKE) -C $$TARGET clean; \ - done; - -.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS) diff --git a/powerpc/pmu/count_instructions.c b/powerpc/pmu/count_instructions.c deleted file mode 100644 index 4622117..0000000 --- a/powerpc/pmu/count_instructions.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdbool.h> -#include <string.h> -#include <sys/prctl.h> - -#include "event.h" -#include "utils.h" -#include "lib.h" - -extern void thirty_two_instruction_loop(u64 loops); - -static void setup_event(struct event *e, u64 config, char *name) -{ - event_init_opts(e, config, PERF_TYPE_HARDWARE, name); - - e->attr.disabled = 1; - e->attr.exclude_kernel = 1; - e->attr.exclude_hv = 1; - e->attr.exclude_idle = 1; -} - -static int do_count_loop(struct event *events, u64 instructions, - u64 overhead, bool report) -{ - s64 difference, expected; - double percentage; - - prctl(PR_TASK_PERF_EVENTS_ENABLE); - - /* Run for 1M instructions */ - thirty_two_instruction_loop(instructions >> 5); - - prctl(PR_TASK_PERF_EVENTS_DISABLE); - - event_read(&events[0]); - event_read(&events[1]); - - expected = instructions + overhead; - difference = events[0].result.value - expected; - percentage = (double)difference / events[0].result.value * 100; - - if (report) { - event_report(&events[0]); - event_report(&events[1]); - - printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead); - printf("Expected %llu\n", expected); - printf("Actual %llu\n", events[0].result.value); - printf("Delta %lld, %f%%\n", difference, percentage); - } - - event_reset(&events[0]); - event_reset(&events[1]); - - if (difference < 0) - difference = -difference; - - /* Tolerate a difference below 0.0001 % */ - difference *= 10000 * 100; - if (difference / events[0].result.value) - return -1; - - return 0; -} - -/* Count how many instructions it takes to do a null loop */ -static u64 determine_overhead(struct event *events) -{ - u64 current, overhead; - int i; - - do_count_loop(events, 0, 0, false); - overhead = events[0].result.value; - - for (i = 0; i < 100; i++) { - do_count_loop(events, 0, 0, false); - current = events[0].result.value; - if (current < overhead) { - printf("Replacing overhead %llu with %llu\n", overhead, current); - overhead = current; - } - } - - return overhead; -} - -static int test_body(void) -{ - struct event events[2]; - u64 overhead; - - setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles"); - - if (event_open(&events[0])) { - perror("perf_event_open"); - return -1; - } - - if (event_open_with_group(&events[1], events[0].fd)) { - perror("perf_event_open"); - return -1; - } - - overhead = determine_overhead(events); - printf("Overhead of null loop: %llu instructions\n", overhead); - - /* Run for 1Mi instructions */ - FAIL_IF(do_count_loop(events, 1000000, overhead, true)); - - /* Run for 10Mi instructions */ - FAIL_IF(do_count_loop(events, 10000000, overhead, true)); - - /* Run for 100Mi instructions */ - FAIL_IF(do_count_loop(events, 100000000, overhead, true)); - - /* Run for 1Bi instructions */ - FAIL_IF(do_count_loop(events, 1000000000, overhead, true)); - - /* Run for 16Bi instructions */ - FAIL_IF(do_count_loop(events, 16000000000, overhead, true)); - - /* Run for 64Bi instructions */ - FAIL_IF(do_count_loop(events, 64000000000, overhead, true)); - - event_close(&events[0]); - event_close(&events[1]); - - return 0; -} - -static int count_instructions(void) -{ - return eat_cpu(test_body); -} - -int main(void) -{ - return test_harness(count_instructions, "count_instructions"); -} diff --git a/powerpc/pmu/ebb/Makefile b/powerpc/pmu/ebb/Makefile deleted file mode 100644 index 3dc4332..0000000 --- a/powerpc/pmu/ebb/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -noarg: - $(MAKE) -C ../../ - -# The EBB handler is 64-bit code and everything links against it -CFLAGS += -m64 - -PROGS := reg_access_test event_attributes_test cycles_test \ - cycles_with_freeze_test pmc56_overflow_test \ - ebb_vs_cpu_event_test cpu_event_vs_ebb_test \ - cpu_event_pinned_vs_ebb_test task_event_vs_ebb_test \ - task_event_pinned_vs_ebb_test multi_ebb_procs_test \ - multi_counter_test pmae_handling_test \ - close_clears_pmcc_test instruction_count_test \ - fork_cleanup_test ebb_on_child_test \ - ebb_on_willing_child_test back_to_back_ebbs_test \ - lost_exception_test no_handler_test \ - cycles_with_mmcr2_test - -all: $(PROGS) - -$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S - -instruction_count_test: ../loop.S - -lost_exception_test: ../lib.c - -run_tests: all - @-for PROG in $(PROGS); do \ - ./$$PROG; \ - done; - -clean: - rm -f $(PROGS) diff --git a/powerpc/pmu/ebb/back_to_back_ebbs_test.c b/powerpc/pmu/ebb/back_to_back_ebbs_test.c deleted file mode 100644 index 66ea765..0000000 --- a/powerpc/pmu/ebb/back_to_back_ebbs_test.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" - - -#define NUMBER_OF_EBBS 50 - -/* - * Test that if we overflow the counter while in the EBB handler, we take - * another EBB on exiting from the handler. - * - * We do this by counting with a stupidly low sample period, causing us to - * overflow the PMU while we're still in the EBB handler, leading to another - * EBB. - * - * We get out of what would otherwise be an infinite loop by leaving the - * counter frozen once we've taken enough EBBs. - */ - -static void ebb_callee(void) -{ - uint64_t siar, 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); - - /* Resets the PMC */ - count_pmc(1, sample_period); - -out: - if (ebb_state.stats.ebb_count == NUMBER_OF_EBBS) - /* Reset but leave counters frozen */ - reset_ebb_with_clear_mask(MMCR0_PMAO); - else - /* Unfreezes */ - reset_ebb(); - - /* Do some stuff to chew some cycles and pop the counter */ - siar = mfspr(SPRN_SIAR); - trace_log_reg(ebb_state.trace, SPRN_SIAR, siar); - - val = mfspr(SPRN_PMC1); - trace_log_reg(ebb_state.trace, SPRN_PMC1, val); - - val = mfspr(SPRN_MMCR0); - trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); -} - -int back_to_back_ebbs(void) -{ - struct event event; - - 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)); - - setup_ebb_handler(ebb_callee); - - FAIL_IF(ebb_event_enable(&event)); - - sample_period = 5; - - ebb_freeze_pmcs(); - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - ebb_global_enable(); - ebb_unfreeze_pmcs(); - - while (ebb_state.stats.ebb_count < NUMBER_OF_EBBS) - FAIL_IF(core_busy_loop()); - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - - dump_ebb_state(); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count != NUMBER_OF_EBBS); - - return 0; -} - -int main(void) -{ - return test_harness(back_to_back_ebbs, "back_to_back_ebbs"); -} diff --git a/powerpc/pmu/ebb/busy_loop.S b/powerpc/pmu/ebb/busy_loop.S deleted file mode 100644 index c7e4093..0000000 --- a/powerpc/pmu/ebb/busy_loop.S +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <ppc-asm.h> - - .text - -FUNC_START(core_busy_loop) - stdu %r1, -168(%r1) - std r14, 160(%r1) - std r15, 152(%r1) - std r16, 144(%r1) - std r17, 136(%r1) - std r18, 128(%r1) - std r19, 120(%r1) - std r20, 112(%r1) - std r21, 104(%r1) - std r22, 96(%r1) - std r23, 88(%r1) - std r24, 80(%r1) - std r25, 72(%r1) - std r26, 64(%r1) - std r27, 56(%r1) - std r28, 48(%r1) - std r29, 40(%r1) - std r30, 32(%r1) - std r31, 24(%r1) - - li r3, 0x3030 - std r3, -96(%r1) - li r4, 0x4040 - std r4, -104(%r1) - li r5, 0x5050 - std r5, -112(%r1) - li r6, 0x6060 - std r6, -120(%r1) - li r7, 0x7070 - std r7, -128(%r1) - li r8, 0x0808 - std r8, -136(%r1) - li r9, 0x0909 - std r9, -144(%r1) - li r10, 0x1010 - std r10, -152(%r1) - li r11, 0x1111 - std r11, -160(%r1) - li r14, 0x1414 - std r14, -168(%r1) - li r15, 0x1515 - std r15, -176(%r1) - li r16, 0x1616 - std r16, -184(%r1) - li r17, 0x1717 - std r17, -192(%r1) - li r18, 0x1818 - std r18, -200(%r1) - li r19, 0x1919 - std r19, -208(%r1) - li r20, 0x2020 - std r20, -216(%r1) - li r21, 0x2121 - std r21, -224(%r1) - li r22, 0x2222 - std r22, -232(%r1) - li r23, 0x2323 - std r23, -240(%r1) - li r24, 0x2424 - std r24, -248(%r1) - li r25, 0x2525 - std r25, -256(%r1) - li r26, 0x2626 - std r26, -264(%r1) - li r27, 0x2727 - std r27, -272(%r1) - li r28, 0x2828 - std r28, -280(%r1) - li r29, 0x2929 - std r29, -288(%r1) - li r30, 0x3030 - li r31, 0x3131 - - li r3, 0 -0: addi r3, r3, 1 - cmpwi r3, 100 - blt 0b - - /* Return 1 (fail) unless we get through all the checks */ - li r3, 1 - - /* Check none of our registers have been corrupted */ - cmpwi r4, 0x4040 - bne 1f - cmpwi r5, 0x5050 - bne 1f - cmpwi r6, 0x6060 - bne 1f - cmpwi r7, 0x7070 - bne 1f - cmpwi r8, 0x0808 - bne 1f - cmpwi r9, 0x0909 - bne 1f - cmpwi r10, 0x1010 - bne 1f - cmpwi r11, 0x1111 - bne 1f - cmpwi r14, 0x1414 - bne 1f - cmpwi r15, 0x1515 - bne 1f - cmpwi r16, 0x1616 - bne 1f - cmpwi r17, 0x1717 - bne 1f - cmpwi r18, 0x1818 - bne 1f - cmpwi r19, 0x1919 - bne 1f - cmpwi r20, 0x2020 - bne 1f - cmpwi r21, 0x2121 - bne 1f - cmpwi r22, 0x2222 - bne 1f - cmpwi r23, 0x2323 - bne 1f - cmpwi r24, 0x2424 - bne 1f - cmpwi r25, 0x2525 - bne 1f - cmpwi r26, 0x2626 - bne 1f - cmpwi r27, 0x2727 - bne 1f - cmpwi r28, 0x2828 - bne 1f - cmpwi r29, 0x2929 - bne 1f - cmpwi r30, 0x3030 - bne 1f - cmpwi r31, 0x3131 - bne 1f - - /* Load junk into all our registers before we reload them from the stack. */ - li r3, 0xde - li r4, 0xad - li r5, 0xbe - li r6, 0xef - li r7, 0xde - li r8, 0xad - li r9, 0xbe - li r10, 0xef - li r11, 0xde - li r14, 0xad - li r15, 0xbe - li r16, 0xef - li r17, 0xde - li r18, 0xad - li r19, 0xbe - li r20, 0xef - li r21, 0xde - li r22, 0xad - li r23, 0xbe - li r24, 0xef - li r25, 0xde - li r26, 0xad - li r27, 0xbe - li r28, 0xef - li r29, 0xdd - - ld r3, -96(%r1) - cmpwi r3, 0x3030 - bne 1f - ld r4, -104(%r1) - cmpwi r4, 0x4040 - bne 1f - ld r5, -112(%r1) - cmpwi r5, 0x5050 - bne 1f - ld r6, -120(%r1) - cmpwi r6, 0x6060 - bne 1f - ld r7, -128(%r1) - cmpwi r7, 0x7070 - bne 1f - ld r8, -136(%r1) - cmpwi r8, 0x0808 - bne 1f - ld r9, -144(%r1) - cmpwi r9, 0x0909 - bne 1f - ld r10, -152(%r1) - cmpwi r10, 0x1010 - bne 1f - ld r11, -160(%r1) - cmpwi r11, 0x1111 - bne 1f - ld r14, -168(%r1) - cmpwi r14, 0x1414 - bne 1f - ld r15, -176(%r1) - cmpwi r15, 0x1515 - bne 1f - ld r16, -184(%r1) - cmpwi r16, 0x1616 - bne 1f - ld r17, -192(%r1) - cmpwi r17, 0x1717 - bne 1f - ld r18, -200(%r1) - cmpwi r18, 0x1818 - bne 1f - ld r19, -208(%r1) - cmpwi r19, 0x1919 - bne 1f - ld r20, -216(%r1) - cmpwi r20, 0x2020 - bne 1f - ld r21, -224(%r1) - cmpwi r21, 0x2121 - bne 1f - ld r22, -232(%r1) - cmpwi r22, 0x2222 - bne 1f - ld r23, -240(%r1) - cmpwi r23, 0x2323 - bne 1f - ld r24, -248(%r1) - cmpwi r24, 0x2424 - bne 1f - ld r25, -256(%r1) - cmpwi r25, 0x2525 - bne 1f - ld r26, -264(%r1) - cmpwi r26, 0x2626 - bne 1f - ld r27, -272(%r1) - cmpwi r27, 0x2727 - bne 1f - ld r28, -280(%r1) - cmpwi r28, 0x2828 - bne 1f - ld r29, -288(%r1) - cmpwi r29, 0x2929 - bne 1f - - /* Load 0 (success) to return */ - li r3, 0 - -1: ld r14, 160(%r1) - ld r15, 152(%r1) - ld r16, 144(%r1) - ld r17, 136(%r1) - ld r18, 128(%r1) - ld r19, 120(%r1) - ld r20, 112(%r1) - ld r21, 104(%r1) - ld r22, 96(%r1) - ld r23, 88(%r1) - ld r24, 80(%r1) - ld r25, 72(%r1) - ld r26, 64(%r1) - ld r27, 56(%r1) - ld r28, 48(%r1) - ld r29, 40(%r1) - ld r30, 32(%r1) - ld r31, 24(%r1) - addi %r1, %r1, 168 - blr diff --git a/powerpc/pmu/ebb/close_clears_pmcc_test.c b/powerpc/pmu/ebb/close_clears_pmcc_test.c deleted file mode 100644 index 0f0423d..0000000 --- a/powerpc/pmu/ebb/close_clears_pmcc_test.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <setjmp.h> -#include <signal.h> - -#include "ebb.h" - - -/* - * Test that closing the EBB event clears MMCR0_PMCC, preventing further access - * by userspace to the PMU hardware. - */ - -int close_clears_pmcc(void) -{ - struct event event; - - event_init_named(&event, 0x1001e, "cycles"); - event_leader_ebb_init(&event); - - FAIL_IF(event_open(&event)); - - ebb_enable_pmc_counting(1); - setup_ebb_handler(standard_ebb_callee); - ebb_global_enable(); - FAIL_IF(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - while (ebb_state.stats.ebb_count < 1) - FAIL_IF(core_busy_loop()); - - ebb_global_disable(); - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - - /* The real test is here, do we take a SIGILL when writing PMU regs now - * that we have closed the event. We expect that we will. */ - - FAIL_IF(catch_sigill(write_pmc1)); - - /* We should still be able to read EBB regs though */ - mfspr(SPRN_EBBHR); - mfspr(SPRN_EBBRR); - mfspr(SPRN_BESCR); - - return 0; -} - -int main(void) -{ - return test_harness(close_clears_pmcc, "close_clears_pmcc"); -} diff --git a/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c b/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c deleted file mode 100644 index d3ed64d..0000000 --- a/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests a pinned cpu event vs an EBB - in that order. The pinned cpu event - * should remain and the EBB event should fail to enable. - */ - -static int setup_cpu_event(struct event *event, int cpu) -{ - event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); - - event->attr.pinned = 1; - - event->attr.exclude_kernel = 1; - event->attr.exclude_hv = 1; - event->attr.exclude_idle = 1; - - SKIP_IF(require_paranoia_below(1)); - FAIL_IF(event_open_with_cpu(event, cpu)); - FAIL_IF(event_enable(event)); - - return 0; -} - -int cpu_event_pinned_vs_ebb(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - int cpu, rc; - pid_t pid; - - cpu = pick_online_cpu(); - FAIL_IF(cpu < 0); - FAIL_IF(bind_to_cpu(cpu)); - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(ebb_child(write_pipe, read_pipe)); - } - - /* We setup the cpu event first */ - rc = setup_cpu_event(&event, cpu); - if (rc) { - kill_child_and_wait(pid); - return rc; - } - - /* Signal the child to install its EBB event and wait */ - if (sync_with_child(read_pipe, write_pipe)) - /* If it fails, wait for it to exit */ - goto wait; - - /* Signal the child to run */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - -wait: - /* We expect it to fail to read the event */ - FAIL_IF(wait_for_child(pid) != 2); - - FAIL_IF(event_disable(&event)); - FAIL_IF(event_read(&event)); - - event_report(&event); - - /* The cpu event should have run */ - FAIL_IF(event.result.value == 0); - FAIL_IF(event.result.enabled != event.result.running); - - return 0; -} - -int main(void) -{ - return test_harness(cpu_event_pinned_vs_ebb, "cpu_event_pinned_vs_ebb"); -} diff --git a/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c b/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c deleted file mode 100644 index 8b972c2..0000000 --- a/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests a cpu event vs an EBB - in that order. The EBB should force the cpu - * event off the PMU. - */ - -static int setup_cpu_event(struct event *event, int cpu) -{ - event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); - - event->attr.exclude_kernel = 1; - event->attr.exclude_hv = 1; - event->attr.exclude_idle = 1; - - SKIP_IF(require_paranoia_below(1)); - FAIL_IF(event_open_with_cpu(event, cpu)); - FAIL_IF(event_enable(event)); - - return 0; -} - -int cpu_event_vs_ebb(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - int cpu, rc; - pid_t pid; - - cpu = pick_online_cpu(); - FAIL_IF(cpu < 0); - FAIL_IF(bind_to_cpu(cpu)); - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(ebb_child(write_pipe, read_pipe)); - } - - /* We setup the cpu event first */ - rc = setup_cpu_event(&event, cpu); - if (rc) { - kill_child_and_wait(pid); - return rc; - } - - /* Signal the child to install its EBB event and wait */ - if (sync_with_child(read_pipe, write_pipe)) - /* If it fails, wait for it to exit */ - goto wait; - - /* Signal the child to run */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - -wait: - /* We expect the child to succeed */ - FAIL_IF(wait_for_child(pid)); - - FAIL_IF(event_disable(&event)); - FAIL_IF(event_read(&event)); - - event_report(&event); - - /* The cpu event may have run */ - - return 0; -} - -int main(void) -{ - return test_harness(cpu_event_vs_ebb, "cpu_event_vs_ebb"); -} diff --git a/powerpc/pmu/ebb/cycles_test.c b/powerpc/pmu/ebb/cycles_test.c deleted file mode 100644 index 8590fc1..0000000 --- a/powerpc/pmu/ebb/cycles_test.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" - - -/* - * Basic test that counts user cycles and takes EBBs. - */ -int cycles(void) -{ - struct event event; - - 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(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - while (ebb_state.stats.ebb_count < 10) { - FAIL_IF(core_busy_loop()); - FAIL_IF(ebb_check_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); - FAIL_IF(!ebb_check_count(1, sample_period, 100)); - - return 0; -} - -int main(void) -{ - return test_harness(cycles, "cycles"); -} diff --git a/powerpc/pmu/ebb/cycles_with_freeze_test.c b/powerpc/pmu/ebb/cycles_with_freeze_test.c deleted file mode 100644 index 754b3f2..0000000 --- a/powerpc/pmu/ebb/cycles_with_freeze_test.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> - -#include "ebb.h" - - -/* - * Test of counting cycles while using MMCR0_FC (freeze counters) to only count - * parts of the code. This is complicated by the fact that FC is set by the - * hardware when the event overflows. We may take the EBB after we have set FC, - * so we have to be careful about whether we clear FC at the end of the EBB - * handler or not. - */ - -static bool counters_frozen = false; -static int ebbs_while_frozen = 0; - -static void ebb_callee(void) -{ - uint64_t mask, val; - - mask = MMCR0_PMAO | MMCR0_FC; - - 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); - - if (counters_frozen) { - trace_log_string(ebb_state.trace, "frozen"); - ebbs_while_frozen++; - mask &= ~MMCR0_FC; - } - - count_pmc(1, sample_period); -out: - reset_ebb_with_clear_mask(mask); -} - -int cycles_with_freeze(void) -{ - struct event event; - uint64_t val; - bool fc_cleared; - - 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)); - - setup_ebb_handler(ebb_callee); - ebb_global_enable(); - FAIL_IF(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - fc_cleared = false; - - /* Make sure we loop until we take at least one EBB */ - while ((ebb_state.stats.ebb_count < 20 && !fc_cleared) || - ebb_state.stats.ebb_count < 1) - { - counters_frozen = false; - mb(); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); - - FAIL_IF(core_busy_loop()); - - counters_frozen = true; - mb(); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); - - val = mfspr(SPRN_MMCR0); - if (! (val & MMCR0_FC)) { - printf("Outside of loop, FC NOT set MMCR0 0x%lx\n", val); - fc_cleared = true; - } - } - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - - dump_ebb_state(); - - printf("EBBs while frozen %d\n", ebbs_while_frozen); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - FAIL_IF(fc_cleared); - - return 0; -} - -int main(void) -{ - return test_harness(cycles_with_freeze, "cycles_with_freeze"); -} diff --git a/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/powerpc/pmu/ebb/cycles_with_mmcr2_test.c deleted file mode 100644 index d43029b..0000000 --- a/powerpc/pmu/ebb/cycles_with_mmcr2_test.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> - -#include "ebb.h" - - -/* - * Test of counting cycles while manipulating the user accessible bits in MMCR2. - */ - -/* We use two values because the first freezes PMC1 and so we would get no EBBs */ -#define MMCR2_EXPECTED_1 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */ -#define MMCR2_EXPECTED_2 0x0020100804020000UL /* ( FC2P|FC3P|FC4P|FC5P|FC6P) */ - - -int cycles_with_mmcr2(void) -{ - struct event event; - uint64_t val, expected[2], actual; - int i; - bool bad_mmcr2; - - 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(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - /* XXX Set of MMCR2 must be after enable */ - expected[0] = MMCR2_EXPECTED_1; - expected[1] = MMCR2_EXPECTED_2; - i = 0; - bad_mmcr2 = false; - - /* Make sure we loop until we take at least one EBB */ - while ((ebb_state.stats.ebb_count < 20 && !bad_mmcr2) || - ebb_state.stats.ebb_count < 1) - { - mtspr(SPRN_MMCR2, expected[i % 2]); - - FAIL_IF(core_busy_loop()); - - val = mfspr(SPRN_MMCR2); - if (val != expected[i % 2]) { - bad_mmcr2 = true; - actual = val; - } - - i++; - } - - 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); - - if (bad_mmcr2) - printf("Bad MMCR2 value seen is 0x%lx\n", actual); - - FAIL_IF(bad_mmcr2); - - return 0; -} - -int main(void) -{ - return test_harness(cycles_with_mmcr2, "cycles_with_mmcr2"); -} 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); -} diff --git a/powerpc/pmu/ebb/ebb.h b/powerpc/pmu/ebb/ebb.h deleted file mode 100644 index e44eee5..0000000 --- a/powerpc/pmu/ebb/ebb.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#ifndef _SELFTESTS_POWERPC_PMU_EBB_EBB_H -#define _SELFTESTS_POWERPC_PMU_EBB_EBB_H - -#include "../event.h" -#include "../lib.h" -#include "trace.h" -#include "reg.h" - -#define PMC_INDEX(pmc) ((pmc)-1) - -#define NUM_PMC_VALUES 128 - -struct ebb_state -{ - struct { - u64 pmc_count[6]; - volatile int ebb_count; - int spurious; - int negative; - int no_overflow; - } stats; - - bool pmc_enable[6]; - struct trace_buffer *trace; -}; - -extern struct ebb_state ebb_state; - -#define COUNTER_OVERFLOW 0x80000000ull - -static inline uint32_t pmc_sample_period(uint32_t value) -{ - return COUNTER_OVERFLOW - value; -} - -static inline void ebb_enable_pmc_counting(int pmc) -{ - ebb_state.pmc_enable[PMC_INDEX(pmc)] = true; -} - -bool ebb_check_count(int pmc, u64 sample_period, int fudge); -void event_leader_ebb_init(struct event *e); -void event_ebb_init(struct event *e); -void event_bhrb_init(struct event *e, unsigned ifm); -void setup_ebb_handler(void (*callee)(void)); -void standard_ebb_callee(void); -int ebb_event_enable(struct event *e); -void ebb_global_enable(void); -void ebb_global_disable(void); -void ebb_freeze_pmcs(void); -void ebb_unfreeze_pmcs(void); -void event_ebb_init(struct event *e); -void event_leader_ebb_init(struct event *e); -int count_pmc(int pmc, uint32_t sample_period); -void dump_ebb_state(void); -void dump_summary_ebb_state(void); -void dump_ebb_hw_state(void); -void clear_ebb_stats(void); -void write_pmc(int pmc, u64 value); -u64 read_pmc(int pmc); -void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask); -void reset_ebb(void); -int ebb_check_mmcr0(void); - -extern u64 sample_period; - -int core_busy_loop(void); -int ebb_child(union pipe read_pipe, union pipe write_pipe); -int catch_sigill(void (*func)(void)); -void write_pmc1(void); - -#endif /* _SELFTESTS_POWERPC_PMU_EBB_EBB_H */ diff --git a/powerpc/pmu/ebb/ebb_handler.S b/powerpc/pmu/ebb/ebb_handler.S deleted file mode 100644 index 14274ea..0000000 --- a/powerpc/pmu/ebb/ebb_handler.S +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <ppc-asm.h> -#include "reg.h" - - -/* ppc-asm.h defines most of the reg aliases, but not r1/r2. */ -#define r1 1 -#define r2 2 - -#define RFEBB .long 0x4c000924 - -/* Stack layout: - * - * ^ - * User stack | - * Back chain ------+ <- r1 <-------+ - * ... | - * Red zone / ABI Gap | - * ... | - * vr63 <+ | - * vr0 | | - * VSCR | | - * FSCR | | - * r31 | Save area | - * r0 | | - * XER | | - * CTR | | - * LR | | - * CCR <+ | - * ... <+ | - * LR | Caller frame | - * CCR | | - * Back chain <+ <- updated r1 --------+ - * - */ - -#if defined(_CALL_ELF) && _CALL_ELF == 2 -#define ABIGAP 512 -#else -#define ABIGAP 288 -#endif - -#define NR_GPR 32 -#define NR_SPR 6 -#define NR_VSR 64 - -#define SAVE_AREA ((NR_GPR + NR_SPR) * 8 + (NR_VSR * 16)) -#define CALLER_FRAME 112 - -#define STACK_FRAME (ABIGAP + SAVE_AREA + CALLER_FRAME) - -#define CCR_SAVE (CALLER_FRAME) -#define LR_SAVE (CCR_SAVE + 8) -#define CTR_SAVE (LR_SAVE + 8) -#define XER_SAVE (CTR_SAVE + 8) -#define GPR_SAVE(n) (XER_SAVE + 8 + (8 * n)) -#define FSCR_SAVE (GPR_SAVE(31) + 8) -#define VSCR_SAVE (FSCR_SAVE + 8) -#define VSR_SAVE(n) (VSCR_SAVE + 8 + (16 * n)) - -#define SAVE_GPR(n) std n,GPR_SAVE(n)(r1) -#define REST_GPR(n) ld n,GPR_SAVE(n)(r1) -#define TRASH_GPR(n) lis n,0xaaaa - -#define SAVE_VSR(n, b) li b, VSR_SAVE(n); stxvd2x n,b,r1 -#define LOAD_VSR(n, b) li b, VSR_SAVE(n); lxvd2x n,b,r1 - -#define LOAD_REG_IMMEDIATE(reg,expr) \ - lis reg,(expr)@highest; \ - ori reg,reg,(expr)@higher; \ - rldicr reg,reg,32,31; \ - oris reg,reg,(expr)@h; \ - ori reg,reg,(expr)@l; - - -#if defined(_CALL_ELF) && _CALL_ELF == 2 -#define ENTRY_POINT(name) \ - .type FUNC_NAME(name),@function; \ - .globl FUNC_NAME(name); \ - FUNC_NAME(name): - -#define RESTORE_TOC(name) \ - /* Restore our TOC pointer using our entry point */ \ - LOAD_REG_IMMEDIATE(r12, name) \ -0: addis r2,r12,(.TOC.-0b)@ha; \ - addi r2,r2,(.TOC.-0b)@l; - -#else -#define ENTRY_POINT(name) FUNC_START(name) -#define RESTORE_TOC(name) \ - /* Restore our TOC pointer via our opd entry */ \ - LOAD_REG_IMMEDIATE(r2, name) \ - ld r2,8(r2); -#endif - - .text - -ENTRY_POINT(ebb_handler) - stdu r1,-STACK_FRAME(r1) - SAVE_GPR(0) - mflr r0 - std r0,LR_SAVE(r1) - mfcr r0 - std r0,CCR_SAVE(r1) - mfctr r0 - std r0,CTR_SAVE(r1) - mfxer r0 - std r0,XER_SAVE(r1) - SAVE_GPR(2) - SAVE_GPR(3) - SAVE_GPR(4) - SAVE_GPR(5) - SAVE_GPR(6) - SAVE_GPR(7) - SAVE_GPR(8) - SAVE_GPR(9) - SAVE_GPR(10) - SAVE_GPR(11) - SAVE_GPR(12) - SAVE_GPR(13) - SAVE_GPR(14) - SAVE_GPR(15) - SAVE_GPR(16) - SAVE_GPR(17) - SAVE_GPR(18) - SAVE_GPR(19) - SAVE_GPR(20) - SAVE_GPR(21) - SAVE_GPR(22) - SAVE_GPR(23) - SAVE_GPR(24) - SAVE_GPR(25) - SAVE_GPR(26) - SAVE_GPR(27) - SAVE_GPR(28) - SAVE_GPR(29) - SAVE_GPR(30) - SAVE_GPR(31) - SAVE_VSR(0, r3) - mffs f0 - stfd f0, FSCR_SAVE(r1) - mfvscr f0 - stfd f0, VSCR_SAVE(r1) - SAVE_VSR(1, r3) - SAVE_VSR(2, r3) - SAVE_VSR(3, r3) - SAVE_VSR(4, r3) - SAVE_VSR(5, r3) - SAVE_VSR(6, r3) - SAVE_VSR(7, r3) - SAVE_VSR(8, r3) - SAVE_VSR(9, r3) - SAVE_VSR(10, r3) - SAVE_VSR(11, r3) - SAVE_VSR(12, r3) - SAVE_VSR(13, r3) - SAVE_VSR(14, r3) - SAVE_VSR(15, r3) - SAVE_VSR(16, r3) - SAVE_VSR(17, r3) - SAVE_VSR(18, r3) - SAVE_VSR(19, r3) - SAVE_VSR(20, r3) - SAVE_VSR(21, r3) - SAVE_VSR(22, r3) - SAVE_VSR(23, r3) - SAVE_VSR(24, r3) - SAVE_VSR(25, r3) - SAVE_VSR(26, r3) - SAVE_VSR(27, r3) - SAVE_VSR(28, r3) - SAVE_VSR(29, r3) - SAVE_VSR(30, r3) - SAVE_VSR(31, r3) - SAVE_VSR(32, r3) - SAVE_VSR(33, r3) - SAVE_VSR(34, r3) - SAVE_VSR(35, r3) - SAVE_VSR(36, r3) - SAVE_VSR(37, r3) - SAVE_VSR(38, r3) - SAVE_VSR(39, r3) - SAVE_VSR(40, r3) - SAVE_VSR(41, r3) - SAVE_VSR(42, r3) - SAVE_VSR(43, r3) - SAVE_VSR(44, r3) - SAVE_VSR(45, r3) - SAVE_VSR(46, r3) - SAVE_VSR(47, r3) - SAVE_VSR(48, r3) - SAVE_VSR(49, r3) - SAVE_VSR(50, r3) - SAVE_VSR(51, r3) - SAVE_VSR(52, r3) - SAVE_VSR(53, r3) - SAVE_VSR(54, r3) - SAVE_VSR(55, r3) - SAVE_VSR(56, r3) - SAVE_VSR(57, r3) - SAVE_VSR(58, r3) - SAVE_VSR(59, r3) - SAVE_VSR(60, r3) - SAVE_VSR(61, r3) - SAVE_VSR(62, r3) - SAVE_VSR(63, r3) - - TRASH_GPR(2) - TRASH_GPR(3) - TRASH_GPR(4) - TRASH_GPR(5) - TRASH_GPR(6) - TRASH_GPR(7) - TRASH_GPR(8) - TRASH_GPR(9) - TRASH_GPR(10) - TRASH_GPR(11) - TRASH_GPR(12) - TRASH_GPR(14) - TRASH_GPR(15) - TRASH_GPR(16) - TRASH_GPR(17) - TRASH_GPR(18) - TRASH_GPR(19) - TRASH_GPR(20) - TRASH_GPR(21) - TRASH_GPR(22) - TRASH_GPR(23) - TRASH_GPR(24) - TRASH_GPR(25) - TRASH_GPR(26) - TRASH_GPR(27) - TRASH_GPR(28) - TRASH_GPR(29) - TRASH_GPR(30) - TRASH_GPR(31) - - RESTORE_TOC(ebb_handler) - - /* - * r13 is our TLS pointer. We leave whatever value was in there when the - * EBB fired. That seems to be OK because once set the TLS pointer is not - * changed - but presumably that could change in future. - */ - - bl ebb_hook - nop - - /* r2 may be changed here but we don't care */ - - lfd f0, FSCR_SAVE(r1) - mtfsf 0xff,f0 - lfd f0, VSCR_SAVE(r1) - mtvscr f0 - LOAD_VSR(0, r3) - LOAD_VSR(1, r3) - LOAD_VSR(2, r3) - LOAD_VSR(3, r3) - LOAD_VSR(4, r3) - LOAD_VSR(5, r3) - LOAD_VSR(6, r3) - LOAD_VSR(7, r3) - LOAD_VSR(8, r3) - LOAD_VSR(9, r3) - LOAD_VSR(10, r3) - LOAD_VSR(11, r3) - LOAD_VSR(12, r3) - LOAD_VSR(13, r3) - LOAD_VSR(14, r3) - LOAD_VSR(15, r3) - LOAD_VSR(16, r3) - LOAD_VSR(17, r3) - LOAD_VSR(18, r3) - LOAD_VSR(19, r3) - LOAD_VSR(20, r3) - LOAD_VSR(21, r3) - LOAD_VSR(22, r3) - LOAD_VSR(23, r3) - LOAD_VSR(24, r3) - LOAD_VSR(25, r3) - LOAD_VSR(26, r3) - LOAD_VSR(27, r3) - LOAD_VSR(28, r3) - LOAD_VSR(29, r3) - LOAD_VSR(30, r3) - LOAD_VSR(31, r3) - LOAD_VSR(32, r3) - LOAD_VSR(33, r3) - LOAD_VSR(34, r3) - LOAD_VSR(35, r3) - LOAD_VSR(36, r3) - LOAD_VSR(37, r3) - LOAD_VSR(38, r3) - LOAD_VSR(39, r3) - LOAD_VSR(40, r3) - LOAD_VSR(41, r3) - LOAD_VSR(42, r3) - LOAD_VSR(43, r3) - LOAD_VSR(44, r3) - LOAD_VSR(45, r3) - LOAD_VSR(46, r3) - LOAD_VSR(47, r3) - LOAD_VSR(48, r3) - LOAD_VSR(49, r3) - LOAD_VSR(50, r3) - LOAD_VSR(51, r3) - LOAD_VSR(52, r3) - LOAD_VSR(53, r3) - LOAD_VSR(54, r3) - LOAD_VSR(55, r3) - LOAD_VSR(56, r3) - LOAD_VSR(57, r3) - LOAD_VSR(58, r3) - LOAD_VSR(59, r3) - LOAD_VSR(60, r3) - LOAD_VSR(61, r3) - LOAD_VSR(62, r3) - LOAD_VSR(63, r3) - - ld r0,XER_SAVE(r1) - mtxer r0 - ld r0,CTR_SAVE(r1) - mtctr r0 - ld r0,LR_SAVE(r1) - mtlr r0 - ld r0,CCR_SAVE(r1) - mtcr r0 - REST_GPR(0) - REST_GPR(2) - REST_GPR(3) - REST_GPR(4) - REST_GPR(5) - REST_GPR(6) - REST_GPR(7) - REST_GPR(8) - REST_GPR(9) - REST_GPR(10) - REST_GPR(11) - REST_GPR(12) - REST_GPR(13) - REST_GPR(14) - REST_GPR(15) - REST_GPR(16) - REST_GPR(17) - REST_GPR(18) - REST_GPR(19) - REST_GPR(20) - REST_GPR(21) - REST_GPR(22) - REST_GPR(23) - REST_GPR(24) - REST_GPR(25) - REST_GPR(26) - REST_GPR(27) - REST_GPR(28) - REST_GPR(29) - REST_GPR(30) - REST_GPR(31) - addi r1,r1,STACK_FRAME - RFEBB -FUNC_END(ebb_handler) diff --git a/powerpc/pmu/ebb/ebb_on_child_test.c b/powerpc/pmu/ebb/ebb_on_child_test.c deleted file mode 100644 index c45f948..0000000 --- a/powerpc/pmu/ebb/ebb_on_child_test.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests we can setup an EBB on our child. Nothing interesting happens, because - * even though the event is enabled and running the child hasn't enabled the - * actual delivery of the EBBs. - */ - -static int victim_child(union pipe read_pipe, union pipe write_pipe) -{ - int i; - - FAIL_IF(wait_for_parent(read_pipe)); - FAIL_IF(notify_parent(write_pipe)); - - /* Parent creates EBB event */ - - FAIL_IF(wait_for_parent(read_pipe)); - FAIL_IF(notify_parent(write_pipe)); - - /* Check the EBB is enabled by writing PMC1 */ - write_pmc1(); - - /* EBB event is enabled here */ - for (i = 0; i < 1000000; i++) ; - - return 0; -} - -int ebb_on_child(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - pid_t pid; - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(victim_child(write_pipe, read_pipe)); - } - - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - - /* Child is running now */ - - 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_with_pid(&event, pid)); - FAIL_IF(ebb_event_enable(&event)); - - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - - /* Child should just exit happily */ - FAIL_IF(wait_for_child(pid)); - - event_close(&event); - - return 0; -} - -int main(void) -{ - return test_harness(ebb_on_child, "ebb_on_child"); -} diff --git a/powerpc/pmu/ebb/ebb_on_willing_child_test.c b/powerpc/pmu/ebb/ebb_on_willing_child_test.c deleted file mode 100644 index 11acf1d..0000000 --- a/powerpc/pmu/ebb/ebb_on_willing_child_test.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests we can setup an EBB on our child. The child expects this and enables - * EBBs, which are then delivered to the child, even though the event is - * created by the parent. - */ - -static int victim_child(union pipe read_pipe, union pipe write_pipe) -{ - FAIL_IF(wait_for_parent(read_pipe)); - - /* Setup our EBB handler, before the EBB event is created */ - ebb_enable_pmc_counting(1); - setup_ebb_handler(standard_ebb_callee); - ebb_global_enable(); - - FAIL_IF(notify_parent(write_pipe)); - - while (ebb_state.stats.ebb_count < 20) { - FAIL_IF(core_busy_loop()); - } - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - - dump_ebb_state(); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - - return 0; -} - -/* Tests we can setup an EBB on our child - if it's expecting it */ -int ebb_on_willing_child(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - pid_t pid; - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(victim_child(write_pipe, read_pipe)); - } - - /* Signal the child to setup its EBB handler */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - - /* Child is running now */ - - 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_with_pid(&event, pid)); - FAIL_IF(ebb_event_enable(&event)); - - /* Child show now take EBBs and then exit */ - FAIL_IF(wait_for_child(pid)); - - event_close(&event); - - return 0; -} - -int main(void) -{ - return test_harness(ebb_on_willing_child, "ebb_on_willing_child"); -} diff --git a/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c b/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c deleted file mode 100644 index be4dd5a..0000000 --- a/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests an EBB vs a cpu event - in that order. The EBB should force the cpu - * event off the PMU. - */ - -static int setup_cpu_event(struct event *event, int cpu) -{ - event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); - - event->attr.exclude_kernel = 1; - event->attr.exclude_hv = 1; - event->attr.exclude_idle = 1; - - SKIP_IF(require_paranoia_below(1)); - FAIL_IF(event_open_with_cpu(event, cpu)); - FAIL_IF(event_enable(event)); - - return 0; -} - -int ebb_vs_cpu_event(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - int cpu, rc; - pid_t pid; - - cpu = pick_online_cpu(); - FAIL_IF(cpu < 0); - FAIL_IF(bind_to_cpu(cpu)); - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(ebb_child(write_pipe, read_pipe)); - } - - /* Signal the child to install its EBB event and wait */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - - /* Now try to install our CPU event */ - rc = setup_cpu_event(&event, cpu); - if (rc) { - kill_child_and_wait(pid); - return rc; - } - - /* Signal the child to run */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - - /* .. and wait for it to complete */ - FAIL_IF(wait_for_child(pid)); - FAIL_IF(event_disable(&event)); - FAIL_IF(event_read(&event)); - - event_report(&event); - - /* The cpu event may have run, but we don't expect 100% */ - FAIL_IF(event.result.enabled >= event.result.running); - - return 0; -} - -int main(void) -{ - return test_harness(ebb_vs_cpu_event, "ebb_vs_cpu_event"); -} diff --git a/powerpc/pmu/ebb/event_attributes_test.c b/powerpc/pmu/ebb/event_attributes_test.c deleted file mode 100644 index 7e78153..0000000 --- a/powerpc/pmu/ebb/event_attributes_test.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" - - -/* - * Test various attributes of the EBB event are enforced. - */ -int event_attributes(void) -{ - struct event event, leader; - - event_init(&event, 0x1001e); - event_leader_ebb_init(&event); - /* Expected to succeed */ - FAIL_IF(event_open(&event)); - event_close(&event); - - - event_init(&event, 0x001e); /* CYCLES - no PMC specified */ - event_leader_ebb_init(&event); - /* Expected to fail, no PMC specified */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&event, 0x2001e); - event_leader_ebb_init(&event); - event.attr.exclusive = 0; - /* Expected to fail, not exclusive */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&event, 0x3001e); - event_leader_ebb_init(&event); - event.attr.freq = 1; - /* Expected to fail, sets freq */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&event, 0x4001e); - event_leader_ebb_init(&event); - event.attr.sample_period = 1; - /* Expected to fail, sets sample_period */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&event, 0x1001e); - event_leader_ebb_init(&event); - event.attr.enable_on_exec = 1; - /* Expected to fail, sets enable_on_exec */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&event, 0x1001e); - event_leader_ebb_init(&event); - event.attr.inherit = 1; - /* Expected to fail, sets inherit */ - FAIL_IF(event_open(&event) == 0); - - - event_init(&leader, 0x1001e); - event_leader_ebb_init(&leader); - FAIL_IF(event_open(&leader)); - - event_init(&event, 0x20002); - event_ebb_init(&event); - - /* Expected to succeed */ - FAIL_IF(event_open_with_group(&event, leader.fd)); - event_close(&leader); - event_close(&event); - - - event_init(&leader, 0x1001e); - event_leader_ebb_init(&leader); - FAIL_IF(event_open(&leader)); - - event_init(&event, 0x20002); - - /* Expected to fail, event doesn't request EBB, leader does */ - FAIL_IF(event_open_with_group(&event, leader.fd) == 0); - event_close(&leader); - - - event_init(&leader, 0x1001e); - event_leader_ebb_init(&leader); - /* Clear the EBB flag */ - leader.attr.config &= ~(1ull << 63); - - FAIL_IF(event_open(&leader)); - - event_init(&event, 0x20002); - event_ebb_init(&event); - - /* Expected to fail, leader doesn't request EBB */ - FAIL_IF(event_open_with_group(&event, leader.fd) == 0); - event_close(&leader); - - - event_init(&leader, 0x1001e); - event_leader_ebb_init(&leader); - leader.attr.exclusive = 0; - /* Expected to fail, leader isn't exclusive */ - FAIL_IF(event_open(&leader) == 0); - - - event_init(&leader, 0x1001e); - event_leader_ebb_init(&leader); - leader.attr.pinned = 0; - /* Expected to fail, leader isn't pinned */ - FAIL_IF(event_open(&leader) == 0); - - event_init(&event, 0x1001e); - event_leader_ebb_init(&event); - /* Expected to fail, not a task event */ - SKIP_IF(require_paranoia_below(1)); - FAIL_IF(event_open_with_cpu(&event, 0) == 0); - - return 0; -} - -int main(void) -{ - return test_harness(event_attributes, "event_attributes"); -} diff --git a/powerpc/pmu/ebb/fixed_instruction_loop.S b/powerpc/pmu/ebb/fixed_instruction_loop.S deleted file mode 100644 index b866a05..0000000 --- a/powerpc/pmu/ebb/fixed_instruction_loop.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <ppc-asm.h> - - .text - -FUNC_START(thirty_two_instruction_loop) - cmpwi r3,0 - beqlr - addi r4,r3,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 # 28 addi's - subi r3,r3,1 - b FUNC_NAME(thirty_two_instruction_loop) -FUNC_END(thirty_two_instruction_loop) diff --git a/powerpc/pmu/ebb/fork_cleanup_test.c b/powerpc/pmu/ebb/fork_cleanup_test.c deleted file mode 100644 index 9e7af6e..0000000 --- a/powerpc/pmu/ebb/fork_cleanup_test.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <setjmp.h> -#include <signal.h> - -#include "ebb.h" - - -/* - * Test that a fork clears the PMU state of the child. eg. BESCR/EBBHR/EBBRR - * are cleared, and MMCR0_PMCC is reset, preventing the child from accessing - * the PMU. - */ - -static struct event event; - -static int child(void) -{ - /* Even though we have EBE=0 we can still see the EBB regs */ - FAIL_IF(mfspr(SPRN_BESCR) != 0); - FAIL_IF(mfspr(SPRN_EBBHR) != 0); - FAIL_IF(mfspr(SPRN_EBBRR) != 0); - - FAIL_IF(catch_sigill(write_pmc1)); - - /* We can still read from the event, though it is on our parent */ - FAIL_IF(event_read(&event)); - - return 0; -} - -/* Tests that fork clears EBB state */ -int fork_cleanup(void) -{ - pid_t pid; - - event_init_named(&event, 0x1001e, "cycles"); - event_leader_ebb_init(&event); - - FAIL_IF(event_open(&event)); - - ebb_enable_pmc_counting(1); - setup_ebb_handler(standard_ebb_callee); - ebb_global_enable(); - - FAIL_IF(ebb_event_enable(&event)); - - mtspr(SPRN_MMCR0, MMCR0_FC); - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - /* Don't need to actually take any EBBs */ - - pid = fork(); - if (pid == 0) - exit(child()); - - /* Child does the actual testing */ - FAIL_IF(wait_for_child(pid)); - - /* After fork */ - event_close(&event); - - return 0; -} - -int main(void) -{ - return test_harness(fork_cleanup, "fork_cleanup"); -} diff --git a/powerpc/pmu/ebb/instruction_count_test.c b/powerpc/pmu/ebb/instruction_count_test.c deleted file mode 100644 index f8190fa..0000000 --- a/powerpc/pmu/ebb/instruction_count_test.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdbool.h> -#include <string.h> -#include <sys/prctl.h> - -#include "ebb.h" - - -/* - * Run a calibrated instruction loop and count instructions executed using - * EBBs. Make sure the counts look right. - */ - -extern void thirty_two_instruction_loop(uint64_t loops); - -static bool counters_frozen = true; - -static int do_count_loop(struct event *event, uint64_t instructions, - uint64_t overhead, bool report) -{ - int64_t difference, expected; - double percentage; - - clear_ebb_stats(); - - counters_frozen = false; - mb(); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); - - thirty_two_instruction_loop(instructions >> 5); - - counters_frozen = true; - mb(); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); - - count_pmc(4, sample_period); - - event->result.value = ebb_state.stats.pmc_count[4-1]; - expected = instructions + overhead; - difference = event->result.value - expected; - percentage = (double)difference / event->result.value * 100; - - if (report) { - printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead); - printf("Expected %lu\n", expected); - printf("Actual %llu\n", event->result.value); - printf("Error %ld, %f%%\n", difference, percentage); - printf("Took %d EBBs\n", ebb_state.stats.ebb_count); - } - - if (difference < 0) - difference = -difference; - - /* Tolerate a difference of up to 0.0001 % */ - difference *= 10000 * 100; - if (difference / event->result.value) - return -1; - - return 0; -} - -/* Count how many instructions it takes to do a null loop */ -static uint64_t determine_overhead(struct event *event) -{ - uint64_t current, overhead; - int i; - - do_count_loop(event, 0, 0, false); - overhead = event->result.value; - - for (i = 0; i < 100; i++) { - do_count_loop(event, 0, 0, false); - current = event->result.value; - if (current < overhead) { - printf("Replacing overhead %lu with %lu\n", overhead, current); - overhead = current; - } - } - - return overhead; -} - -static void pmc4_ebb_callee(void) -{ - uint64_t val; - - val = mfspr(SPRN_BESCR); - if (!(val & BESCR_PMEO)) { - ebb_state.stats.spurious++; - goto out; - } - - ebb_state.stats.ebb_count++; - count_pmc(4, sample_period); -out: - if (counters_frozen) - reset_ebb_with_clear_mask(MMCR0_PMAO); - else - reset_ebb(); -} - -int instruction_count(void) -{ - struct event event; - uint64_t overhead; - - event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL"); - 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)); - FAIL_IF(ebb_event_enable(&event)); - - sample_period = COUNTER_OVERFLOW; - - setup_ebb_handler(pmc4_ebb_callee); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); - ebb_global_enable(); - - overhead = determine_overhead(&event); - printf("Overhead of null loop: %lu instructions\n", overhead); - - /* Run for 1M instructions */ - FAIL_IF(do_count_loop(&event, 0x100000, overhead, true)); - - /* Run for 10M instructions */ - FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true)); - - /* Run for 100M instructions */ - FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true)); - - /* Run for 1G instructions */ - FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true)); - - /* Run for 16G instructions */ - FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true)); - - /* Run for 64G instructions */ - FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true)); - - /* Run for 128G instructions */ - FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true)); - - ebb_global_disable(); - event_close(&event); - - printf("Finished OK\n"); - - return 0; -} - -int main(void) -{ - return test_harness(instruction_count, "instruction_count"); -} diff --git a/powerpc/pmu/ebb/lost_exception_test.c b/powerpc/pmu/ebb/lost_exception_test.c deleted file mode 100644 index 0c9dd9b..0000000 --- a/powerpc/pmu/ebb/lost_exception_test.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <sched.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> - -#include "ebb.h" - - -/* - * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect - * where an exception triggers but we context switch before it is delivered and - * lose the exception. - */ - -static int test_body(void) -{ - int i, orig_period, max_period; - struct event event; - - /* We use PMC4 to make sure the kernel switches all counters correctly */ - event_init_named(&event, 0x40002, "instructions"); - 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(4); - setup_ebb_handler(standard_ebb_callee); - ebb_global_enable(); - FAIL_IF(ebb_event_enable(&event)); - - /* - * We want a low sample period, but we also want to get out of the EBB - * handler without tripping up again. - * - * This value picked after much experimentation. - */ - orig_period = max_period = sample_period = 400; - - mtspr(SPRN_PMC4, pmc_sample_period(sample_period)); - - while (ebb_state.stats.ebb_count < 1000000) { - /* - * We are trying to get the EBB exception to race exactly with - * us entering the kernel to do the syscall. We then need the - * kernel to decide our timeslice is up and context switch to - * the other thread. When we come back our EBB will have been - * lost and we'll spin in this while loop forever. - */ - - for (i = 0; i < 100000; i++) - sched_yield(); - - /* Change the sample period slightly to try and hit the race */ - if (sample_period >= (orig_period + 200)) - sample_period = orig_period; - else - sample_period++; - - if (sample_period > max_period) - max_period = sample_period; - } - - ebb_freeze_pmcs(); - ebb_global_disable(); - - count_pmc(4, sample_period); - mtspr(SPRN_PMC4, 0xdead); - - dump_summary_ebb_state(); - dump_ebb_hw_state(); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - - /* We vary our sample period so we need extra fudge here */ - FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period))); - - return 0; -} - -static int lost_exception(void) -{ - return eat_cpu(test_body); -} - -int main(void) -{ - return test_harness(lost_exception, "lost_exception"); -} diff --git a/powerpc/pmu/ebb/multi_counter_test.c b/powerpc/pmu/ebb/multi_counter_test.c deleted file mode 100644 index 67d78af..0000000 --- a/powerpc/pmu/ebb/multi_counter_test.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> - -#include "ebb.h" - - -/* - * Test counting multiple events using EBBs. - */ -int multi_counter(void) -{ - struct event events[6]; - int i, group_fd; - - event_init_named(&events[0], 0x1001C, "PM_CMPLU_STALL_THRD"); - event_init_named(&events[1], 0x2D016, "PM_CMPLU_STALL_FXU"); - event_init_named(&events[2], 0x30006, "PM_CMPLU_STALL_OTHER_CMPL"); - event_init_named(&events[3], 0x4000A, "PM_CMPLU_STALL"); - event_init_named(&events[4], 0x600f4, "PM_RUN_CYC"); - event_init_named(&events[5], 0x500fa, "PM_RUN_INST_CMPL"); - - event_leader_ebb_init(&events[0]); - for (i = 1; i < 6; i++) - event_ebb_init(&events[i]); - - group_fd = -1; - for (i = 0; i < 6; i++) { - events[i].attr.exclude_kernel = 1; - events[i].attr.exclude_hv = 1; - events[i].attr.exclude_idle = 1; - - FAIL_IF(event_open_with_group(&events[i], group_fd)); - if (group_fd == -1) - group_fd = events[0].fd; - } - - ebb_enable_pmc_counting(1); - ebb_enable_pmc_counting(2); - ebb_enable_pmc_counting(3); - ebb_enable_pmc_counting(4); - ebb_enable_pmc_counting(5); - ebb_enable_pmc_counting(6); - setup_ebb_handler(standard_ebb_callee); - - FAIL_IF(ioctl(events[0].fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP)); - FAIL_IF(event_read(&events[0])); - - ebb_global_enable(); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC2, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC3, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC4, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC5, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC6, pmc_sample_period(sample_period)); - - while (ebb_state.stats.ebb_count < 50) { - FAIL_IF(core_busy_loop()); - FAIL_IF(ebb_check_mmcr0()); - } - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - count_pmc(2, sample_period); - count_pmc(3, sample_period); - count_pmc(4, sample_period); - count_pmc(5, sample_period); - count_pmc(6, sample_period); - - dump_ebb_state(); - - for (i = 0; i < 6; i++) - event_close(&events[i]); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - - return 0; -} - -int main(void) -{ - return test_harness(multi_counter, "multi_counter"); -} diff --git a/powerpc/pmu/ebb/multi_ebb_procs_test.c b/powerpc/pmu/ebb/multi_ebb_procs_test.c deleted file mode 100644 index b8dc371..0000000 --- a/powerpc/pmu/ebb/multi_ebb_procs_test.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> - -#include "ebb.h" - - -/* - * Test running multiple EBB using processes at once on a single CPU. They - * should all run happily without interfering with each other. - */ - -static bool child_should_exit; - -static void sigint_handler(int signal) -{ - child_should_exit = true; -} - -struct sigaction sigint_action = { - .sa_handler = sigint_handler, -}; - -static int cycles_child(void) -{ - struct event event; - - if (sigaction(SIGINT, &sigint_action, NULL)) { - perror("sigaction"); - return 1; - } - - 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(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - while (!child_should_exit) { - FAIL_IF(core_busy_loop()); - FAIL_IF(ebb_check_mmcr0()); - } - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - - dump_summary_ebb_state(); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - - return 0; -} - -#define NR_CHILDREN 4 - -int multi_ebb_procs(void) -{ - pid_t pids[NR_CHILDREN]; - int cpu, rc, i; - - cpu = pick_online_cpu(); - FAIL_IF(cpu < 0); - FAIL_IF(bind_to_cpu(cpu)); - - for (i = 0; i < NR_CHILDREN; i++) { - pids[i] = fork(); - if (pids[i] == 0) - exit(cycles_child()); - } - - /* Have them all run for "a while" */ - sleep(10); - - rc = 0; - for (i = 0; i < NR_CHILDREN; i++) { - /* Tell them to stop */ - kill(pids[i], SIGINT); - /* And wait */ - rc |= wait_for_child(pids[i]); - } - - return rc; -} - -int main(void) -{ - return test_harness(multi_ebb_procs, "multi_ebb_procs"); -} diff --git a/powerpc/pmu/ebb/no_handler_test.c b/powerpc/pmu/ebb/no_handler_test.c deleted file mode 100644 index 2f9bf8e..0000000 --- a/powerpc/pmu/ebb/no_handler_test.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <setjmp.h> -#include <signal.h> - -#include "ebb.h" - - -/* Test that things work sanely if we have no handler */ - -static int no_handler_test(void) -{ - struct event event; - u64 val; - int i; - - 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)); - FAIL_IF(ebb_event_enable(&event)); - - val = mfspr(SPRN_EBBHR); - FAIL_IF(val != 0); - - /* Make sure it overflows quickly */ - sample_period = 1000; - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - /* Spin to make sure the event has time to overflow */ - for (i = 0; i < 1000; i++) - mb(); - - dump_ebb_state(); - - /* We expect to see the PMU frozen & PMAO set */ - val = mfspr(SPRN_MMCR0); - FAIL_IF(val != 0x0000000080000080); - - event_close(&event); - - dump_ebb_state(); - - /* The real test is that we never took an EBB at 0x0 */ - - return 0; -} - -int main(void) -{ - return test_harness(no_handler_test,"no_handler_test"); -} diff --git a/powerpc/pmu/ebb/pmae_handling_test.c b/powerpc/pmu/ebb/pmae_handling_test.c deleted file mode 100644 index 986500f..0000000 --- a/powerpc/pmu/ebb/pmae_handling_test.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <sched.h> -#include <signal.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" - - -/* - * Test that the kernel properly handles PMAE across context switches. - * - * We test this by calling into the kernel inside our EBB handler, where PMAE - * is clear. A cpu eater companion thread is running on the same CPU as us to - * encourage the scheduler to switch us. - * - * The kernel must make sure that when it context switches us back in, it - * honours the fact that we had PMAE clear. - * - * Observed to hit the failing case on the first EBB with a broken kernel. - */ - -static bool mmcr0_mismatch; -static uint64_t before, after; - -static void syscall_ebb_callee(void) -{ - uint64_t val; - - val = mfspr(SPRN_BESCR); - if (!(val & BESCR_PMEO)) { - ebb_state.stats.spurious++; - goto out; - } - - ebb_state.stats.ebb_count++; - count_pmc(1, sample_period); - - before = mfspr(SPRN_MMCR0); - - /* Try and get ourselves scheduled, to force a PMU context switch */ - sched_yield(); - - after = mfspr(SPRN_MMCR0); - if (before != after) - mmcr0_mismatch = true; - -out: - reset_ebb(); -} - -static int test_body(void) -{ - struct event event; - - 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)); - - setup_ebb_handler(syscall_ebb_callee); - ebb_global_enable(); - - FAIL_IF(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - - while (ebb_state.stats.ebb_count < 20 && !mmcr0_mismatch) - FAIL_IF(core_busy_loop()); - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(1, sample_period); - - dump_ebb_state(); - - if (mmcr0_mismatch) - printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0); - FAIL_IF(mmcr0_mismatch); - - return 0; -} - -int pmae_handling(void) -{ - return eat_cpu(test_body); -} - -int main(void) -{ - return test_harness(pmae_handling, "pmae_handling"); -} diff --git a/powerpc/pmu/ebb/pmc56_overflow_test.c b/powerpc/pmu/ebb/pmc56_overflow_test.c deleted file mode 100644 index a503fa7..0000000 --- a/powerpc/pmu/ebb/pmc56_overflow_test.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" - - -/* - * Test that PMC5 & 6 are frozen (ie. don't overflow) when they are not being - * used. Tests the MMCR0_FC56 logic in the kernel. - */ - -static int pmc56_overflowed; - -static void ebb_callee(void) -{ - uint64_t val; - - val = mfspr(SPRN_BESCR); - if (!(val & BESCR_PMEO)) { - ebb_state.stats.spurious++; - goto out; - } - - ebb_state.stats.ebb_count++; - count_pmc(2, sample_period); - - val = mfspr(SPRN_PMC5); - if (val >= COUNTER_OVERFLOW) - pmc56_overflowed++; - - count_pmc(5, COUNTER_OVERFLOW); - - val = mfspr(SPRN_PMC6); - if (val >= COUNTER_OVERFLOW) - pmc56_overflowed++; - - count_pmc(6, COUNTER_OVERFLOW); - -out: - reset_ebb(); -} - -int pmc56_overflow(void) -{ - struct event event; - - /* Use PMC2 so we set PMCjCE, which enables PMC5/6 */ - event_init(&event, 0x2001e); - 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)); - - setup_ebb_handler(ebb_callee); - ebb_global_enable(); - - FAIL_IF(ebb_event_enable(&event)); - - mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); - mtspr(SPRN_PMC5, 0); - mtspr(SPRN_PMC6, 0); - - while (ebb_state.stats.ebb_count < 10) - FAIL_IF(core_busy_loop()); - - ebb_global_disable(); - ebb_freeze_pmcs(); - - count_pmc(2, sample_period); - - dump_ebb_state(); - - printf("PMC5/6 overflow %d\n", pmc56_overflowed); - - event_close(&event); - - FAIL_IF(ebb_state.stats.ebb_count == 0 || pmc56_overflowed != 0); - - return 0; -} - -int main(void) -{ - return test_harness(pmc56_overflow, "pmc56_overflow"); -} diff --git a/powerpc/pmu/ebb/reg.h b/powerpc/pmu/ebb/reg.h deleted file mode 100644 index 5921b0d..0000000 --- a/powerpc/pmu/ebb/reg.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#ifndef _SELFTESTS_POWERPC_REG_H -#define _SELFTESTS_POWERPC_REG_H - -#define __stringify_1(x) #x -#define __stringify(x) __stringify_1(x) - -#define mfspr(rn) ({unsigned long rval; \ - asm volatile("mfspr %0," __stringify(rn) \ - : "=r" (rval)); rval; }) -#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : \ - : "r" ((unsigned long)(v)) \ - : "memory") - -#define mb() asm volatile("sync" : : : "memory"); - -#define SPRN_MMCR2 769 -#define SPRN_MMCRA 770 -#define SPRN_MMCR0 779 -#define MMCR0_PMAO 0x00000080 -#define MMCR0_PMAE 0x04000000 -#define MMCR0_FC 0x80000000 -#define SPRN_EBBHR 804 -#define SPRN_EBBRR 805 -#define SPRN_BESCR 806 /* Branch event status & control register */ -#define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */ -#define SPRN_BESCRSU 801 /* Branch event status & control set upper */ -#define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */ -#define SPRN_BESCRRU 803 /* Branch event status & control REset upper */ - -#define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */ -#define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */ - -#define SPRN_PMC1 771 -#define SPRN_PMC2 772 -#define SPRN_PMC3 773 -#define SPRN_PMC4 774 -#define SPRN_PMC5 775 -#define SPRN_PMC6 776 - -#define SPRN_SIAR 780 -#define SPRN_SDAR 781 -#define SPRN_SIER 768 - -#endif /* _SELFTESTS_POWERPC_REG_H */ diff --git a/powerpc/pmu/ebb/reg_access_test.c b/powerpc/pmu/ebb/reg_access_test.c deleted file mode 100644 index 0cae66f..0000000 --- a/powerpc/pmu/ebb/reg_access_test.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "ebb.h" -#include "reg.h" - - -/* - * Test basic access to the EBB regs, they should be user accessible with no - * kernel interaction required. - */ -int reg_access(void) -{ - uint64_t val, expected; - - expected = 0x8000000100000000ull; - mtspr(SPRN_BESCR, expected); - val = mfspr(SPRN_BESCR); - - FAIL_IF(val != expected); - - expected = 0x0000000001000000ull; - mtspr(SPRN_EBBHR, expected); - val = mfspr(SPRN_EBBHR); - - FAIL_IF(val != expected); - - return 0; -} - -int main(void) -{ - return test_harness(reg_access, "reg_access"); -} diff --git a/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c b/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c deleted file mode 100644 index d56607e..0000000 --- a/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests a pinned per-task event vs an EBB - in that order. The pinned per-task - * event should prevent the EBB event from being enabled. - */ - -static int setup_child_event(struct event *event, pid_t child_pid) -{ - event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); - - event->attr.pinned = 1; - - event->attr.exclude_kernel = 1; - event->attr.exclude_hv = 1; - event->attr.exclude_idle = 1; - - FAIL_IF(event_open_with_pid(event, child_pid)); - FAIL_IF(event_enable(event)); - - return 0; -} - -int task_event_pinned_vs_ebb(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - pid_t pid; - int rc; - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(ebb_child(write_pipe, read_pipe)); - } - - /* We setup the task event first */ - rc = setup_child_event(&event, pid); - if (rc) { - kill_child_and_wait(pid); - return rc; - } - - /* Signal the child to install its EBB event and wait */ - if (sync_with_child(read_pipe, write_pipe)) - /* If it fails, wait for it to exit */ - goto wait; - - /* Signal the child to run */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - -wait: - /* We expect it to fail to read the event */ - FAIL_IF(wait_for_child(pid) != 2); - FAIL_IF(event_disable(&event)); - FAIL_IF(event_read(&event)); - - event_report(&event); - - FAIL_IF(event.result.value == 0); - /* - * For reasons I don't understand enabled is usually just slightly - * lower than running. Would be good to confirm why. - */ - FAIL_IF(event.result.enabled == 0); - FAIL_IF(event.result.running == 0); - - return 0; -} - -int main(void) -{ - return test_harness(task_event_pinned_vs_ebb, "task_event_pinned_vs_ebb"); -} diff --git a/powerpc/pmu/ebb/task_event_vs_ebb_test.c b/powerpc/pmu/ebb/task_event_vs_ebb_test.c deleted file mode 100644 index eba3219..0000000 --- a/powerpc/pmu/ebb/task_event_vs_ebb_test.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "ebb.h" - - -/* - * Tests a per-task event vs an EBB - in that order. The EBB should push the - * per-task event off the PMU. - */ - -static int setup_child_event(struct event *event, pid_t child_pid) -{ - event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); - - event->attr.exclude_kernel = 1; - event->attr.exclude_hv = 1; - event->attr.exclude_idle = 1; - - FAIL_IF(event_open_with_pid(event, child_pid)); - FAIL_IF(event_enable(event)); - - return 0; -} - -int task_event_vs_ebb(void) -{ - union pipe read_pipe, write_pipe; - struct event event; - pid_t pid; - int rc; - - FAIL_IF(pipe(read_pipe.fds) == -1); - FAIL_IF(pipe(write_pipe.fds) == -1); - - pid = fork(); - if (pid == 0) { - /* NB order of pipes looks reversed */ - exit(ebb_child(write_pipe, read_pipe)); - } - - /* We setup the task event first */ - rc = setup_child_event(&event, pid); - if (rc) { - kill_child_and_wait(pid); - return rc; - } - - /* Signal the child to install its EBB event and wait */ - if (sync_with_child(read_pipe, write_pipe)) - /* If it fails, wait for it to exit */ - goto wait; - - /* Signal the child to run */ - FAIL_IF(sync_with_child(read_pipe, write_pipe)); - -wait: - /* The EBB event should push the task event off so the child should succeed */ - FAIL_IF(wait_for_child(pid)); - FAIL_IF(event_disable(&event)); - FAIL_IF(event_read(&event)); - - event_report(&event); - - /* The task event may have run, or not so we can't assert anything about it */ - - return 0; -} - -int main(void) -{ - return test_harness(task_event_vs_ebb, "task_event_vs_ebb"); -} diff --git a/powerpc/pmu/ebb/trace.c b/powerpc/pmu/ebb/trace.c deleted file mode 100644 index 251e66a..0000000 --- a/powerpc/pmu/ebb/trace.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> - -#include "trace.h" - - -struct trace_buffer *trace_buffer_allocate(u64 size) -{ - struct trace_buffer *tb; - - if (size < sizeof(*tb)) { - fprintf(stderr, "Error: trace buffer too small\n"); - return NULL; - } - - tb = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (tb == MAP_FAILED) { - perror("mmap"); - return NULL; - } - - tb->size = size; - tb->tail = tb->data; - tb->overflow = false; - - return tb; -} - -static bool trace_check_bounds(struct trace_buffer *tb, void *p) -{ - return p < ((void *)tb + tb->size); -} - -static bool trace_check_alloc(struct trace_buffer *tb, void *p) -{ - /* - * If we ever overflowed don't allow any more input. This prevents us - * from dropping a large item and then later logging a small one. The - * buffer should just stop when overflow happened, not be patchy. If - * you're overflowing, make your buffer bigger. - */ - if (tb->overflow) - return false; - - if (!trace_check_bounds(tb, p)) { - tb->overflow = true; - return false; - } - - return true; -} - -static void *trace_alloc(struct trace_buffer *tb, int bytes) -{ - void *p, *newtail; - - p = tb->tail; - newtail = tb->tail + bytes; - if (!trace_check_alloc(tb, newtail)) - return NULL; - - tb->tail = newtail; - - return p; -} - -static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size) -{ - struct trace_entry *e; - - e = trace_alloc(tb, sizeof(*e) + payload_size); - if (e) - e->length = payload_size; - - return e; -} - -int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value) -{ - struct trace_entry *e; - u64 *p; - - e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value)); - if (!e) - return -ENOSPC; - - e->type = TRACE_TYPE_REG; - p = (u64 *)e->data; - *p++ = reg; - *p++ = value; - - return 0; -} - -int trace_log_counter(struct trace_buffer *tb, u64 value) -{ - struct trace_entry *e; - u64 *p; - - e = trace_alloc_entry(tb, sizeof(value)); - if (!e) - return -ENOSPC; - - e->type = TRACE_TYPE_COUNTER; - p = (u64 *)e->data; - *p++ = value; - - return 0; -} - -int trace_log_string(struct trace_buffer *tb, char *str) -{ - struct trace_entry *e; - char *p; - int len; - - len = strlen(str); - - /* We NULL terminate to make printing easier */ - e = trace_alloc_entry(tb, len + 1); - if (!e) - return -ENOSPC; - - e->type = TRACE_TYPE_STRING; - p = (char *)e->data; - memcpy(p, str, len); - p += len; - *p = '\0'; - - return 0; -} - -int trace_log_indent(struct trace_buffer *tb) -{ - struct trace_entry *e; - - e = trace_alloc_entry(tb, 0); - if (!e) - return -ENOSPC; - - e->type = TRACE_TYPE_INDENT; - - return 0; -} - -int trace_log_outdent(struct trace_buffer *tb) -{ - struct trace_entry *e; - - e = trace_alloc_entry(tb, 0); - if (!e) - return -ENOSPC; - - e->type = TRACE_TYPE_OUTDENT; - - return 0; -} - -static void trace_print_header(int seq, int prefix) -{ - printf("%*s[%d]: ", prefix, "", seq); -} - -static char *trace_decode_reg(int reg) -{ - switch (reg) { - case 769: return "SPRN_MMCR2"; break; - case 770: return "SPRN_MMCRA"; break; - case 779: return "SPRN_MMCR0"; break; - case 804: return "SPRN_EBBHR"; break; - case 805: return "SPRN_EBBRR"; break; - case 806: return "SPRN_BESCR"; break; - case 800: return "SPRN_BESCRS"; break; - case 801: return "SPRN_BESCRSU"; break; - case 802: return "SPRN_BESCRR"; break; - case 803: return "SPRN_BESCRRU"; break; - case 771: return "SPRN_PMC1"; break; - case 772: return "SPRN_PMC2"; break; - case 773: return "SPRN_PMC3"; break; - case 774: return "SPRN_PMC4"; break; - case 775: return "SPRN_PMC5"; break; - case 776: return "SPRN_PMC6"; break; - case 780: return "SPRN_SIAR"; break; - case 781: return "SPRN_SDAR"; break; - case 768: return "SPRN_SIER"; break; - } - - return NULL; -} - -static void trace_print_reg(struct trace_entry *e) -{ - u64 *p, *reg, *value; - char *name; - - p = (u64 *)e->data; - reg = p++; - value = p; - - name = trace_decode_reg(*reg); - if (name) - printf("register %-10s = 0x%016llx\n", name, *value); - else - printf("register %lld = 0x%016llx\n", *reg, *value); -} - -static void trace_print_counter(struct trace_entry *e) -{ - u64 *value; - - value = (u64 *)e->data; - printf("counter = %lld\n", *value); -} - -static void trace_print_string(struct trace_entry *e) -{ - char *str; - - str = (char *)e->data; - puts(str); -} - -#define BASE_PREFIX 2 -#define PREFIX_DELTA 8 - -static void trace_print_entry(struct trace_entry *e, int seq, int *prefix) -{ - switch (e->type) { - case TRACE_TYPE_REG: - trace_print_header(seq, *prefix); - trace_print_reg(e); - break; - case TRACE_TYPE_COUNTER: - trace_print_header(seq, *prefix); - trace_print_counter(e); - break; - case TRACE_TYPE_STRING: - trace_print_header(seq, *prefix); - trace_print_string(e); - break; - case TRACE_TYPE_INDENT: - trace_print_header(seq, *prefix); - puts("{"); - *prefix += PREFIX_DELTA; - break; - case TRACE_TYPE_OUTDENT: - *prefix -= PREFIX_DELTA; - if (*prefix < BASE_PREFIX) - *prefix = BASE_PREFIX; - trace_print_header(seq, *prefix); - puts("}"); - break; - default: - trace_print_header(seq, *prefix); - printf("entry @ %p type %d\n", e, e->type); - break; - } -} - -void trace_buffer_print(struct trace_buffer *tb) -{ - struct trace_entry *e; - int i, prefix; - void *p; - - printf("Trace buffer dump:\n"); - printf(" address %p \n", tb); - printf(" tail %p\n", tb->tail); - printf(" size %llu\n", tb->size); - printf(" overflow %s\n", tb->overflow ? "TRUE" : "false"); - printf(" Content:\n"); - - p = tb->data; - - i = 0; - prefix = BASE_PREFIX; - - while (trace_check_bounds(tb, p) && p < tb->tail) { - e = p; - - trace_print_entry(e, i, &prefix); - - i++; - p = (void *)e + sizeof(*e) + e->length; - } -} - -void trace_print_location(struct trace_buffer *tb) -{ - printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb); -} diff --git a/powerpc/pmu/ebb/trace.h b/powerpc/pmu/ebb/trace.h deleted file mode 100644 index 926458e..0000000 --- a/powerpc/pmu/ebb/trace.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#ifndef _SELFTESTS_POWERPC_PMU_EBB_TRACE_H -#define _SELFTESTS_POWERPC_PMU_EBB_TRACE_H - -#include "utils.h" - -#define TRACE_TYPE_REG 1 -#define TRACE_TYPE_COUNTER 2 -#define TRACE_TYPE_STRING 3 -#define TRACE_TYPE_INDENT 4 -#define TRACE_TYPE_OUTDENT 5 - -struct trace_entry -{ - u8 type; - u8 length; - u8 data[0]; -}; - -struct trace_buffer -{ - u64 size; - bool overflow; - void *tail; - u8 data[0]; -}; - -struct trace_buffer *trace_buffer_allocate(u64 size); -int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value); -int trace_log_counter(struct trace_buffer *tb, u64 value); -int trace_log_string(struct trace_buffer *tb, char *str); -int trace_log_indent(struct trace_buffer *tb); -int trace_log_outdent(struct trace_buffer *tb); -void trace_buffer_print(struct trace_buffer *tb); -void trace_print_location(struct trace_buffer *tb); - -#endif /* _SELFTESTS_POWERPC_PMU_EBB_TRACE_H */ diff --git a/powerpc/pmu/event.c b/powerpc/pmu/event.c deleted file mode 100644 index 184b368..0000000 --- a/powerpc/pmu/event.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2013, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#define _GNU_SOURCE -#include <unistd.h> -#include <sys/syscall.h> -#include <string.h> -#include <stdio.h> -#include <sys/ioctl.h> - -#include "event.h" - - -int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, - int group_fd, unsigned long flags) -{ - return syscall(__NR_perf_event_open, attr, pid, cpu, - group_fd, flags); -} - -void event_init_opts(struct event *e, u64 config, int type, char *name) -{ - memset(e, 0, sizeof(*e)); - - e->name = name; - - e->attr.type = type; - e->attr.config = config; - e->attr.size = sizeof(e->attr); - /* This has to match the structure layout in the header */ - e->attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | \ - PERF_FORMAT_TOTAL_TIME_RUNNING; -} - -void event_init_named(struct event *e, u64 config, char *name) -{ - event_init_opts(e, config, PERF_TYPE_RAW, name); -} - -void event_init(struct event *e, u64 config) -{ - event_init_opts(e, config, PERF_TYPE_RAW, "event"); -} - -#define PERF_CURRENT_PID 0 -#define PERF_NO_PID -1 -#define PERF_NO_CPU -1 -#define PERF_NO_GROUP -1 - -int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd) -{ - e->fd = perf_event_open(&e->attr, pid, cpu, group_fd, 0); - if (e->fd == -1) { - perror("perf_event_open"); - return -1; - } - - return 0; -} - -int event_open_with_group(struct event *e, int group_fd) -{ - return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd); -} - -int event_open_with_pid(struct event *e, pid_t pid) -{ - return event_open_with_options(e, pid, PERF_NO_CPU, PERF_NO_GROUP); -} - -int event_open_with_cpu(struct event *e, int cpu) -{ - return event_open_with_options(e, PERF_NO_PID, cpu, PERF_NO_GROUP); -} - -int event_open(struct event *e) -{ - return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP); -} - -void event_close(struct event *e) -{ - close(e->fd); -} - -int event_enable(struct event *e) -{ - return ioctl(e->fd, PERF_EVENT_IOC_ENABLE); -} - -int event_disable(struct event *e) -{ - return ioctl(e->fd, PERF_EVENT_IOC_DISABLE); -} - -int event_reset(struct event *e) -{ - return ioctl(e->fd, PERF_EVENT_IOC_RESET); -} - -int event_read(struct event *e) -{ - int rc; - - rc = read(e->fd, &e->result, sizeof(e->result)); - if (rc != sizeof(e->result)) { - fprintf(stderr, "read error on event %p!\n", e); - return -1; - } - - return 0; -} - -void event_report_justified(struct event *e, int name_width, int result_width) -{ - printf("%*s: result %*llu ", name_width, e->name, result_width, - e->result.value); - - if (e->result.running == e->result.enabled) - printf("running/enabled %llu\n", e->result.running); - else - printf("running %llu enabled %llu\n", e->result.running, - e->result.enabled); -} - -void event_report(struct event *e) -{ - event_report_justified(e, 0, 0); -} diff --git a/powerpc/pmu/event.h b/powerpc/pmu/event.h deleted file mode 100644 index a0ea6b1..0000000 --- a/powerpc/pmu/event.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#ifndef _SELFTESTS_POWERPC_PMU_EVENT_H -#define _SELFTESTS_POWERPC_PMU_EVENT_H - -#include <unistd.h> -#include <linux/perf_event.h> - -#include "utils.h" - - -struct event { - struct perf_event_attr attr; - char *name; - int fd; - /* This must match the read_format we use */ - struct { - u64 value; - u64 running; - u64 enabled; - } result; -}; - -void event_init(struct event *e, u64 config); -void event_init_named(struct event *e, u64 config, char *name); -void event_init_opts(struct event *e, u64 config, int type, char *name); -int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd); -int event_open_with_group(struct event *e, int group_fd); -int event_open_with_pid(struct event *e, pid_t pid); -int event_open_with_cpu(struct event *e, int cpu); -int event_open(struct event *e); -void event_close(struct event *e); -int event_enable(struct event *e); -int event_disable(struct event *e); -int event_reset(struct event *e); -int event_read(struct event *e); -void event_report_justified(struct event *e, int name_width, int result_width); -void event_report(struct event *e); - -#endif /* _SELFTESTS_POWERPC_PMU_EVENT_H */ diff --git a/powerpc/pmu/l3_bank_test.c b/powerpc/pmu/l3_bank_test.c deleted file mode 100644 index 77472f3..0000000 --- a/powerpc/pmu/l3_bank_test.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "event.h" -#include "utils.h" - -#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */ - -/* - * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1. - */ -static int l3_bank_test(void) -{ - struct event event; - char *p; - int i; - - p = malloc(MALLOC_SIZE); - FAIL_IF(!p); - - event_init(&event, 0x84918F); - - FAIL_IF(event_open(&event)); - - for (i = 0; i < MALLOC_SIZE; i += 0x10000) - p[i] = i; - - event_read(&event); - event_report(&event); - - FAIL_IF(event.result.running == 0); - FAIL_IF(event.result.enabled == 0); - - event_close(&event); - free(p); - - return 0; -} - -int main(void) -{ - return test_harness(l3_bank_test, "l3_bank_test"); -} diff --git a/powerpc/pmu/lib.c b/powerpc/pmu/lib.c deleted file mode 100644 index 9768dea..0000000 --- a/powerpc/pmu/lib.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#define _GNU_SOURCE /* For CPU_ZERO etc. */ - -#include <elf.h> -#include <errno.h> -#include <fcntl.h> -#include <link.h> -#include <sched.h> -#include <setjmp.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "utils.h" -#include "lib.h" - - -int pick_online_cpu(void) -{ - cpu_set_t mask; - int cpu; - - CPU_ZERO(&mask); - - if (sched_getaffinity(0, sizeof(mask), &mask)) { - perror("sched_getaffinity"); - return -1; - } - - /* We prefer a primary thread, but skip 0 */ - for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) - if (CPU_ISSET(cpu, &mask)) - return cpu; - - /* Search for anything, but in reverse */ - for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) - if (CPU_ISSET(cpu, &mask)) - return cpu; - - printf("No cpus in affinity mask?!\n"); - return -1; -} - -int bind_to_cpu(int cpu) -{ - cpu_set_t mask; - - printf("Binding to cpu %d\n", cpu); - - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - - return sched_setaffinity(0, sizeof(mask), &mask); -} - -#define PARENT_TOKEN 0xAA -#define CHILD_TOKEN 0x55 - -int sync_with_child(union pipe read_pipe, union pipe write_pipe) -{ - char c = PARENT_TOKEN; - - FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); - FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); - if (c != CHILD_TOKEN) /* sometimes expected */ - return 1; - - return 0; -} - -int wait_for_parent(union pipe read_pipe) -{ - char c; - - FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); - FAIL_IF(c != PARENT_TOKEN); - - return 0; -} - -int notify_parent(union pipe write_pipe) -{ - char c = CHILD_TOKEN; - - FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); - - return 0; -} - -int notify_parent_of_error(union pipe write_pipe) -{ - char c = ~CHILD_TOKEN; - - FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); - - return 0; -} - -int wait_for_child(pid_t child_pid) -{ - int rc; - - if (waitpid(child_pid, &rc, 0) == -1) { - perror("waitpid"); - return 1; - } - - if (WIFEXITED(rc)) - rc = WEXITSTATUS(rc); - else - rc = 1; /* Signal or other */ - - return rc; -} - -int kill_child_and_wait(pid_t child_pid) -{ - kill(child_pid, SIGTERM); - - return wait_for_child(child_pid); -} - -static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe) -{ - volatile int i = 0; - - /* - * We are just here to eat cpu and die. So make sure we can be killed, - * and also don't do any custom SIGTERM handling. - */ - signal(SIGTERM, SIG_DFL); - - notify_parent(write_pipe); - wait_for_parent(read_pipe); - - /* Soak up cpu forever */ - while (1) i++; - - return 0; -} - -pid_t eat_cpu(int (test_function)(void)) -{ - union pipe read_pipe, write_pipe; - int cpu, rc; - pid_t pid; - - cpu = pick_online_cpu(); - FAIL_IF(cpu < 0); - FAIL_IF(bind_to_cpu(cpu)); - - if (pipe(read_pipe.fds) == -1) - return -1; - - if (pipe(write_pipe.fds) == -1) - return -1; - - pid = fork(); - if (pid == 0) - exit(eat_cpu_child(write_pipe, read_pipe)); - - if (sync_with_child(read_pipe, write_pipe)) { - rc = -1; - goto out; - } - - printf("main test running as pid %d\n", getpid()); - - rc = test_function(); -out: - kill(pid, SIGKILL); - - return rc; -} - -struct addr_range libc, vdso; - -int parse_proc_maps(void) -{ - unsigned long start, end; - char execute, name[128]; - FILE *f; - int rc; - - f = fopen("/proc/self/maps", "r"); - if (!f) { - perror("fopen"); - return -1; - } - - do { - /* This skips line with no executable which is what we want */ - rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n", - &start, &end, &execute, name); - if (rc <= 0) - break; - - if (execute != 'x') - continue; - - if (strstr(name, "libc")) { - libc.first = start; - libc.last = end - 1; - } else if (strstr(name, "[vdso]")) { - vdso.first = start; - vdso.last = end - 1; - } - } while(1); - - fclose(f); - - return 0; -} - -#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid" - -bool require_paranoia_below(int level) -{ - unsigned long current; - char *end, buf[16]; - FILE *f; - int rc; - - rc = -1; - - f = fopen(PARANOID_PATH, "r"); - if (!f) { - perror("fopen"); - goto out; - } - - if (!fgets(buf, sizeof(buf), f)) { - printf("Couldn't read " PARANOID_PATH "?\n"); - goto out_close; - } - - current = strtoul(buf, &end, 10); - - if (end == buf) { - printf("Couldn't parse " PARANOID_PATH "?\n"); - goto out_close; - } - - if (current >= level) - goto out; - - rc = 0; -out_close: - fclose(f); -out: - return rc; -} - -static char auxv[4096]; - -void *get_auxv_entry(int type) -{ - ElfW(auxv_t) *p; - void *result; - ssize_t num; - int fd; - - fd = open("/proc/self/auxv", O_RDONLY); - if (fd == -1) { - perror("open"); - return NULL; - } - - result = NULL; - - num = read(fd, auxv, sizeof(auxv)); - if (num < 0) { - perror("read"); - goto out; - } - - if (num > sizeof(auxv)) { - printf("Overflowed auxv buffer\n"); - goto out; - } - - p = (ElfW(auxv_t) *)auxv; - - while (p->a_type != AT_NULL) { - if (p->a_type == type) { - result = (void *)p->a_un.a_val; - break; - } - - p++; - } -out: - close(fd); - return result; -} diff --git a/powerpc/pmu/lib.h b/powerpc/pmu/lib.h deleted file mode 100644 index 0f0339c..0000000 --- a/powerpc/pmu/lib.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#ifndef __SELFTESTS_POWERPC_PMU_LIB_H -#define __SELFTESTS_POWERPC_PMU_LIB_H - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -union pipe { - struct { - int read_fd; - int write_fd; - }; - int fds[2]; -}; - -extern int pick_online_cpu(void); -extern int bind_to_cpu(int cpu); -extern int kill_child_and_wait(pid_t child_pid); -extern int wait_for_child(pid_t child_pid); -extern int sync_with_child(union pipe read_pipe, union pipe write_pipe); -extern int wait_for_parent(union pipe read_pipe); -extern int notify_parent(union pipe write_pipe); -extern int notify_parent_of_error(union pipe write_pipe); -extern pid_t eat_cpu(int (test_function)(void)); -extern bool require_paranoia_below(int level); -extern void *get_auxv_entry(int type); - -struct addr_range { - uint64_t first, last; -}; - -extern struct addr_range libc, vdso; - -int parse_proc_maps(void); - -#endif /* __SELFTESTS_POWERPC_PMU_LIB_H */ diff --git a/powerpc/pmu/loop.S b/powerpc/pmu/loop.S deleted file mode 100644 index 20c1f08..0000000 --- a/powerpc/pmu/loop.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#include <ppc-asm.h> - - .text - -FUNC_START(thirty_two_instruction_loop) - cmpdi r3,0 - beqlr - addi r4,r3,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 - addi r4,r4,1 # 28 addi's - subi r3,r3,1 - b FUNC_NAME(thirty_two_instruction_loop) -FUNC_END(thirty_two_instruction_loop) diff --git a/powerpc/pmu/per_event_excludes.c b/powerpc/pmu/per_event_excludes.c deleted file mode 100644 index fddbbc9..0000000 --- a/powerpc/pmu/per_event_excludes.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2014, Michael Ellerman, IBM Corp. - * Licensed under GPLv2. - */ - -#define _GNU_SOURCE - -#include <elf.h> -#include <limits.h> -#include <stdio.h> -#include <stdbool.h> -#include <string.h> -#include <sys/prctl.h> - -#include "event.h" -#include "lib.h" -#include "utils.h" - -/* - * Test that per-event excludes work. - */ - -static int per_event_excludes(void) -{ - struct event *e, events[4]; - char *platform; - int i; - - platform = (char *)get_auxv_entry(AT_BASE_PLATFORM); - FAIL_IF(!platform); - SKIP_IF(strcmp(platform, "power8") != 0); - - /* - * We need to create the events disabled, otherwise the running/enabled - * counts don't match up. - */ - e = &events[0]; - event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, - PERF_TYPE_HARDWARE, "instructions"); - e->attr.disabled = 1; - - e = &events[1]; - event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, - PERF_TYPE_HARDWARE, "instructions(k)"); - e->attr.disabled = 1; - e->attr.exclude_user = 1; - e->attr.exclude_hv = 1; - - e = &events[2]; - event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, - PERF_TYPE_HARDWARE, "instructions(h)"); - e->attr.disabled = 1; - e->attr.exclude_user = 1; - e->attr.exclude_kernel = 1; - - e = &events[3]; - event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, - PERF_TYPE_HARDWARE, "instructions(u)"); - e->attr.disabled = 1; - e->attr.exclude_hv = 1; - e->attr.exclude_kernel = 1; - - FAIL_IF(event_open(&events[0])); - - /* - * The open here will fail if we don't have per event exclude support, - * because the second event has an incompatible set of exclude settings - * and we're asking for the events to be in a group. - */ - for (i = 1; i < 4; i++) - FAIL_IF(event_open_with_group(&events[i], events[0].fd)); - - /* - * Even though the above will fail without per-event excludes we keep - * testing in order to be thorough. - */ - prctl(PR_TASK_PERF_EVENTS_ENABLE); - - /* Spin for a while */ - for (i = 0; i < INT_MAX; i++) - asm volatile("" : : : "memory"); - - prctl(PR_TASK_PERF_EVENTS_DISABLE); - - for (i = 0; i < 4; i++) { - FAIL_IF(event_read(&events[i])); - event_report(&events[i]); - } - - /* - * We should see that all events have enabled == running. That - * shows that they were all on the PMU at once. - */ - for (i = 0; i < 4; i++) - FAIL_IF(events[i].result.running != events[i].result.enabled); - - /* - * We can also check that the result for instructions is >= all the - * other counts. That's because it is counting all instructions while - * the others are counting a subset. - */ - for (i = 1; i < 4; i++) - FAIL_IF(events[0].result.value < events[i].result.value); - - for (i = 0; i < 4; i++) - event_close(&events[i]); - - return 0; -} - -int main(void) -{ - return test_harness(per_event_excludes, "per_event_excludes"); -} |