Release 4.18 tools/testing/selftests/powerpc/pmu/ebb/ebb.c
  
  
  
/*
 * 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 "ebb.h"
void (*ebb_user_func)(void);
void ebb_hook(void)
{
	if (ebb_user_func)
		ebb_user_func();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 14 | 100.00% | 1 | 100.00% | 
| Total | 14 | 100.00% | 1 | 100.00% | 
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 */
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 52 | 100.00% | 1 | 100.00% | 
| Total | 52 | 100.00% | 1 | 100.00% | 
void reset_ebb(void)
{
	reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 14 | 100.00% | 1 | 100.00% | 
| Total | 14 | 100.00% | 1 | 100.00% | 
/* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 47 | 100.00% | 1 | 100.00% | 
| Total | 47 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 139 | 100.00% | 1 | 100.00% | 
| Total | 139 | 100.00% | 1 | 100.00% | 
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();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 138 | 100.00% | 1 | 100.00% | 
| Total | 138 | 100.00% | 1 | 100.00% | 
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();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 92 | 100.00% | 1 | 100.00% | 
| Total | 92 | 100.00% | 1 | 100.00% | 
void clear_ebb_stats(void)
{
	memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 24 | 100.00% | 1 | 100.00% | 
| Total | 24 | 100.00% | 1 | 100.00% | 
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]);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 110 | 100.00% | 1 | 100.00% | 
| Total | 110 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 78 | 100.00% | 1 | 100.00% | 
| Total | 78 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 74 | 100.00% | 1 | 100.00% | 
| Total | 74 | 100.00% | 1 | 100.00% | 
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));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 113 | 100.00% | 2 | 100.00% | 
| Total | 113 | 100.00% | 2 | 100.00% | 
void dump_ebb_state(void)
{
	dump_summary_ebb_state();
	dump_ebb_hw_state();
	trace_buffer_print(ebb_state.trace);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 20 | 100.00% | 1 | 100.00% | 
| Total | 20 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 91 | 100.00% | 1 | 100.00% | 
| Total | 91 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 49 | 100.00% | 1 | 100.00% | 
| Total | 49 | 100.00% | 1 | 100.00% | 
void ebb_freeze_pmcs(void)
{
	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
	mb();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 22 | 100.00% | 1 | 100.00% | 
| Total | 22 | 100.00% | 1 | 100.00% | 
void ebb_unfreeze_pmcs(void)
{
	/* Unfreeze counters */
	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
	mb();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 24 | 100.00% | 1 | 100.00% | 
| Total | 24 | 100.00% | 1 | 100.00% | 
void ebb_global_enable(void)
{
	/* Enable EBBs globally and PMU EBBs */
	mtspr(SPRN_BESCR, 0x8000000100000000ull);
	mb();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 18 | 100.00% | 1 | 100.00% | 
| Total | 18 | 100.00% | 1 | 100.00% | 
void ebb_global_disable(void)
{
	/* Disable EBBs & freeze counters, events are still scheduled */
	mtspr(SPRN_BESCRR, BESCR_PME);
	mb();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 18 | 100.00% | 1 | 100.00% | 
| Total | 18 | 100.00% | 1 | 100.00% | 
bool ebb_is_supported(void)
{
#ifdef PPC_FEATURE2_EBB
	/* EBB requires at least POWER8 */
	return have_hwcap2(PPC_FEATURE2_EBB);
#else
	return false;
#endif
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Denis Kirjanov | 22 | 91.67% | 1 | 50.00% | 
| Michael Ellerman | 2 | 8.33% | 1 | 50.00% | 
| Total | 24 | 100.00% | 2 | 100.00% | 
void event_ebb_init(struct event *e)
{
	e->attr.config |= (1ull << 63);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 22 | 100.00% | 1 | 100.00% | 
| Total | 22 | 100.00% | 1 | 100.00% | 
void event_bhrb_init(struct event *e, unsigned ifm)
{
	e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 34 | 100.00% | 1 | 100.00% | 
| Total | 34 | 100.00% | 1 | 100.00% | 
void event_leader_ebb_init(struct event *e)
{
	event_ebb_init(e);
	e->attr.exclusive = 1;
	e->attr.pinned = 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 31 | 100.00% | 1 | 100.00% | 
| Total | 31 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 228 | 100.00% | 1 | 100.00% | 
| Total | 228 | 100.00% | 1 | 100.00% | 
static jmp_buf setjmp_env;
static void sigill_handler(int signal)
{
	printf("Took sigill\n");
	longjmp(setjmp_env, 1);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 21 | 100.00% | 1 | 100.00% | 
| Total | 21 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 56 | 100.00% | 1 | 100.00% | 
| Total | 56 | 100.00% | 1 | 100.00% | 
void write_pmc1(void)
{
	mtspr(SPRN_PMC1, 0);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 14 | 100.00% | 1 | 100.00% | 
| Total | 14 | 100.00% | 1 | 100.00% | 
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;
	}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 83 | 100.00% | 1 | 100.00% | 
| Total | 83 | 100.00% | 1 | 100.00% | 
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 71 | 100.00% | 1 | 100.00% | 
| Total | 71 | 100.00% | 1 | 100.00% | 
static void term_handler(int signal)
{
	dump_summary_ebb_state();
	dump_ebb_hw_state();
	abort();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 18 | 100.00% | 1 | 100.00% | 
| Total | 18 | 100.00% | 1 | 100.00% | 
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);
}
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Michael Ellerman | 1852 | 98.83% | 3 | 75.00% | 
| Denis Kirjanov | 22 | 1.17% | 1 | 25.00% | 
| Total | 1874 | 100.00% | 4 | 100.00% | 
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.