forked from Freescale/linux-fslc
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/powerpc: Add tests of PMU EBBs
The Power8 Performance Monitor Unit (PMU) has a new feature called Event Based Branches (EBB). This commit adds tests of the kernel API for using EBBs. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Loading branch information
Showing
34 changed files
with
3,913 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
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 | ||
|
||
all: $(PROGS) | ||
|
||
$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c | ||
|
||
instruction_count_test: ../loop.S | ||
|
||
lost_exception_test: ../lib.c | ||
|
||
run_tests: all | ||
@-for PROG in $(PROGS); do \ | ||
./$$PROG; \ | ||
done; | ||
|
||
clean: | ||
rm -f $(PROGS) |
106 changes: 106 additions & 0 deletions
106
tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* 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"); | ||
} |
59 changes: 59 additions & 0 deletions
59
tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* 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"); | ||
} |
93 changes: 93 additions & 0 deletions
93
tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* 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"); | ||
} |
Oops, something went wrong.