brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · a3984ef Raw
148 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2013, Michael Ellerman, IBM Corp.4 */5 6#define _GNU_SOURCE7 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(u64 loops);18 19static void setup_event(struct event *e, u64 config, char *name)20{21	event_init_opts(e, config, PERF_TYPE_HARDWARE, 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 35	prctl(PR_TASK_PERF_EVENTS_ENABLE);36 37	/* Run for 1M instructions */38	thirty_two_instruction_loop(instructions >> 5);39 40	prctl(PR_TASK_PERF_EVENTS_DISABLE);41 42	event_read(&events[0]);43	event_read(&events[1]);44 45	expected = instructions + overhead;46	difference = events[0].result.value - expected;47	percentage = (double)difference / events[0].result.value * 100;48 49	if (report) {50		event_report(&events[0]);51		event_report(&events[1]);52 53		printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);54		printf("Expected %llu\n", expected);55		printf("Actual   %llu\n", events[0].result.value);56		printf("Delta    %lld, %f%%\n", difference, percentage);57	}58 59	event_reset(&events[0]);60	event_reset(&events[1]);61 62	if (difference < 0)63		difference = -difference;64 65	/* Tolerate a difference below 0.0001 % */66	difference *= 10000 * 100;67	if (difference / events[0].result.value)68		return -1;69 70	return 0;71}72 73/* Count how many instructions it takes to do a null loop */74static u64 determine_overhead(struct event *events)75{76	u64 current, overhead;77	int i;78 79	do_count_loop(events, 0, 0, false);80	overhead = events[0].result.value;81 82	for (i = 0; i < 100; i++) {83		do_count_loop(events, 0, 0, false);84		current = events[0].result.value;85		if (current < overhead) {86			printf("Replacing overhead %llu with %llu\n", overhead, current);87			overhead = current;88		}89	}90 91	return overhead;92}93 94static int test_body(void)95{96	struct event events[2];97	u64 overhead;98 99	setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");100	setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");101 102	if (event_open(&events[0])) {103		perror("perf_event_open");104		return -1;105	}106 107	if (event_open_with_group(&events[1], events[0].fd)) {108		perror("perf_event_open");109		return -1;110	}111 112	overhead = determine_overhead(events);113	printf("Overhead of null loop: %llu instructions\n", overhead);114 115	/* Run for 1Mi instructions */116	FAIL_IF(do_count_loop(events, 1000000, overhead, true));117 118	/* Run for 10Mi instructions */119	FAIL_IF(do_count_loop(events, 10000000, overhead, true));120 121	/* Run for 100Mi instructions */122	FAIL_IF(do_count_loop(events, 100000000, overhead, true));123 124	/* Run for 1Bi instructions */125	FAIL_IF(do_count_loop(events, 1000000000, overhead, true));126 127	/* Run for 16Bi instructions */128	FAIL_IF(do_count_loop(events, 16000000000, overhead, true));129 130	/* Run for 64Bi instructions */131	FAIL_IF(do_count_loop(events, 64000000000, overhead, true));132 133	event_close(&events[0]);134	event_close(&events[1]);135 136	return 0;137}138 139static int count_instructions(void)140{141	return eat_cpu(test_body);142}143 144int main(void)145{146	return test_harness(count_instructions, "count_instructions");147}148