File Index
Files and directories
Sign in
FILE

count_stcx_fail.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/powerpc/pmu/count_stcx_fail.c C
  1/*
  2 * Copyright 2013, Michael Ellerman, IBM Corp.
  3 * Licensed under GPLv2.
  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 "event.h"
 14#include "utils.h"
 15#include "lib.h"
 16
 17extern void thirty_two_instruction_loop_with_ll_sc(u64 loops, u64 *ll_sc_target);
 18
 19static void setup_event(struct event *e, u64 config, int type, char *name)
 20{
 21	event_init_opts(e, config, type, name);
 22
 23	e->attr.disabled = 1;
 24	e->attr.exclude_kernel = 1;
 25	e->attr.exclude_hv = 1;
 26	e->attr.exclude_idle = 1;
 27}
 28
 29static int do_count_loop(struct event *events, u64 instructions,
 30			 u64 overhead, bool report)
 31{
 32	s64 difference, expected;
 33	double percentage;
 34	u64 dummy;
 35
 36	prctl(PR_TASK_PERF_EVENTS_ENABLE);
 37
 38	/* Run for 1M instructions */
 39	thirty_two_instruction_loop_with_ll_sc(instructions >> 5, &dummy);
 40
 41	prctl(PR_TASK_PERF_EVENTS_DISABLE);
 42
 43	event_read(&events[0]);
 44	event_read(&events[1]);
 45	event_read(&events[2]);
 46
 47	expected = instructions + overhead + (events[2].result.value * 10);
 48	difference = events[0].result.value - expected;
 49	percentage = (double)difference / events[0].result.value * 100;
 50
 51	if (report) {
 52		printf("-----\n");
 53		event_report(&events[0]);
 54		event_report(&events[1]);
 55		event_report(&events[2]);
 56
 57		printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
 58		printf("Expected %llu\n", expected);
 59		printf("Actual   %llu\n", events[0].result.value);
 60		printf("Delta    %lld, %f%%\n", difference, percentage);
 61	}
 62
 63	event_reset(&events[0]);
 64	event_reset(&events[1]);
 65	event_reset(&events[2]);
 66
 67	if (difference < 0)
 68		difference = -difference;
 69
 70	/* Tolerate a difference below 0.0001 % */
 71	difference *= 10000 * 100;
 72	if (difference / events[0].result.value)
 73		return -1;
 74
 75	return 0;
 76}
 77
 78/* Count how many instructions it takes to do a null loop */
 79static u64 determine_overhead(struct event *events)
 80{
 81	u64 current, overhead;
 82	int i;
 83
 84	do_count_loop(events, 0, 0, false);
 85	overhead = events[0].result.value;
 86
 87	for (i = 0; i < 100; i++) {
 88		do_count_loop(events, 0, 0, false);
 89		current = events[0].result.value;
 90		if (current < overhead) {
 91			printf("Replacing overhead %llu with %llu\n", overhead, current);
 92			overhead = current;
 93		}
 94	}
 95
 96	return overhead;
 97}
 98
 99#define	PM_MRK_STCX_FAIL	0x03e158
100#define PM_STCX_FAIL	0x01e058
101
102static int test_body(void)
103{
104	struct event events[3];
105	u64 overhead;
106
107	// The STCX_FAIL event we use works on Power8 or later
108	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
109
110	setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, PERF_TYPE_HARDWARE, "instructions");
111	setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, PERF_TYPE_HARDWARE, "cycles");
112	setup_event(&events[2], PM_STCX_FAIL, PERF_TYPE_RAW, "stcx_fail");
113
114	if (event_open(&events[0])) {
115		perror("perf_event_open");
116		return -1;
117	}
118
119	if (event_open_with_group(&events[1], events[0].fd)) {
120		perror("perf_event_open");
121		return -1;
122	}
123
124	if (event_open_with_group(&events[2], events[0].fd)) {
125		perror("perf_event_open");
126		return -1;
127	}
128
129	overhead = determine_overhead(events);
130	printf("Overhead of null loop: %llu instructions\n", overhead);
131
132	/* Run for 1Mi instructions */
133	FAIL_IF(do_count_loop(events, 1000000, overhead, true));
134
135	/* Run for 10Mi instructions */
136	FAIL_IF(do_count_loop(events, 10000000, overhead, true));
137
138	/* Run for 100Mi instructions */
139	FAIL_IF(do_count_loop(events, 100000000, overhead, true));
140
141	/* Run for 1Bi instructions */
142	FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
143
144	/* Run for 16Bi instructions */
145	FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
146
147	event_close(&events[0]);
148	event_close(&events[1]);
149
150	return 0;
151}
152
153static int count_ll_sc(void)
154{
155	return eat_cpu(test_body);
156}
157
158int main(void)
159{
160	return test_harness(count_ll_sc, "count_ll_sc");
161}
~/ Read-only file preview.