cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

instruction_count_test.c (3800B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2014, Michael Ellerman, IBM Corp.
      4 */
      5
      6#define _GNU_SOURCE
      7
      8#include <stdio.h>
      9#include <stdbool.h>
     10#include <string.h>
     11#include <sys/prctl.h>
     12
     13#include "ebb.h"
     14
     15
     16/*
     17 * Run a calibrated instruction loop and count instructions executed using
     18 * EBBs. Make sure the counts look right.
     19 */
     20
     21extern void thirty_two_instruction_loop(uint64_t loops);
     22
     23static bool counters_frozen = true;
     24
     25static int do_count_loop(struct event *event, uint64_t instructions,
     26			 uint64_t overhead, bool report)
     27{
     28	int64_t difference, expected;
     29	double percentage;
     30
     31	clear_ebb_stats();
     32
     33	counters_frozen = false;
     34	mb();
     35	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
     36
     37	thirty_two_instruction_loop(instructions >> 5);
     38
     39	counters_frozen = true;
     40	mb();
     41	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
     42
     43	count_pmc(4, sample_period);
     44
     45	event->result.value = ebb_state.stats.pmc_count[4-1];
     46	expected = instructions + overhead;
     47	difference = event->result.value - expected;
     48	percentage = (double)difference / event->result.value * 100;
     49
     50	if (report) {
     51		printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead);
     52		printf("Expected %lu\n", expected);
     53		printf("Actual   %llu\n", event->result.value);
     54		printf("Delta    %ld, %f%%\n", difference, percentage);
     55		printf("Took %d EBBs\n", ebb_state.stats.ebb_count);
     56	}
     57
     58	if (difference < 0)
     59		difference = -difference;
     60
     61	/* Tolerate a difference of up to 0.0001 % */
     62	difference *= 10000 * 100;
     63	if (difference / event->result.value)
     64		return -1;
     65
     66	return 0;
     67}
     68
     69/* Count how many instructions it takes to do a null loop */
     70static uint64_t determine_overhead(struct event *event)
     71{
     72	uint64_t current, overhead;
     73	int i;
     74
     75	do_count_loop(event, 0, 0, false);
     76	overhead = event->result.value;
     77
     78	for (i = 0; i < 100; i++) {
     79		do_count_loop(event, 0, 0, false);
     80		current = event->result.value;
     81		if (current < overhead) {
     82			printf("Replacing overhead %lu with %lu\n", overhead, current);
     83			overhead = current;
     84		}
     85	}
     86
     87	return overhead;
     88}
     89
     90static void pmc4_ebb_callee(void)
     91{
     92	uint64_t val;
     93
     94	val = mfspr(SPRN_BESCR);
     95	if (!(val & BESCR_PMEO)) {
     96		ebb_state.stats.spurious++;
     97		goto out;
     98	}
     99
    100	ebb_state.stats.ebb_count++;
    101	count_pmc(4, sample_period);
    102out:
    103	if (counters_frozen)
    104		reset_ebb_with_clear_mask(MMCR0_PMAO);
    105	else
    106		reset_ebb();
    107}
    108
    109int instruction_count(void)
    110{
    111	struct event event;
    112	uint64_t overhead;
    113
    114	SKIP_IF(!ebb_is_supported());
    115
    116	event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL");
    117	event_leader_ebb_init(&event);
    118	event.attr.exclude_kernel = 1;
    119	event.attr.exclude_hv = 1;
    120	event.attr.exclude_idle = 1;
    121
    122	FAIL_IF(event_open(&event));
    123	FAIL_IF(ebb_event_enable(&event));
    124
    125	sample_period = COUNTER_OVERFLOW;
    126
    127	setup_ebb_handler(pmc4_ebb_callee);
    128	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
    129	ebb_global_enable();
    130
    131	overhead = determine_overhead(&event);
    132	printf("Overhead of null loop: %lu instructions\n", overhead);
    133
    134	/* Run for 1M instructions */
    135	FAIL_IF(do_count_loop(&event, 0x100000, overhead, true));
    136
    137	/* Run for 10M instructions */
    138	FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true));
    139
    140	/* Run for 100M instructions */
    141	FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true));
    142
    143	/* Run for 1G instructions */
    144	FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true));
    145
    146	/* Run for 16G instructions */
    147	FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true));
    148
    149	/* Run for 64G instructions */
    150	FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true));
    151
    152	/* Run for 128G instructions */
    153	FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true));
    154
    155	ebb_global_disable();
    156	event_close(&event);
    157
    158	printf("Finished OK\n");
    159
    160	return 0;
    161}
    162
    163int main(void)
    164{
    165	test_harness_set_timeout(300);
    166	return test_harness(instruction_count, "instruction_count");
    167}