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

null_syscall.c (3018B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Test null syscall performance
      4 *
      5 * Copyright (C) 2009-2015 Anton Blanchard, IBM
      6 */
      7
      8#define NR_LOOPS 10000000
      9
     10#include <string.h>
     11#include <stdio.h>
     12#include <stdlib.h>
     13#include <unistd.h>
     14#include <time.h>
     15#include <sys/types.h>
     16#include <sys/time.h>
     17#include <sys/syscall.h>
     18#include <signal.h>
     19
     20static volatile int soak_done;
     21unsigned long long clock_frequency;
     22unsigned long long timebase_frequency;
     23double timebase_multiplier;
     24
     25static inline unsigned long mftb(void)
     26{
     27	unsigned long low;
     28
     29	asm volatile("mftb %0" : "=r" (low));
     30
     31	return low;
     32}
     33
     34static void sigalrm_handler(int unused)
     35{
     36	soak_done = 1;
     37}
     38
     39/*
     40 * Use a timer instead of busy looping on clock_gettime() so we don't
     41 * pollute profiles with glibc and VDSO hits.
     42 */
     43static void cpu_soak_usecs(unsigned long usecs)
     44{
     45	struct itimerval val;
     46
     47	memset(&val, 0, sizeof(val));
     48	val.it_value.tv_usec = usecs;
     49
     50	signal(SIGALRM, sigalrm_handler);
     51	setitimer(ITIMER_REAL, &val, NULL);
     52
     53	while (1) {
     54		if (soak_done)
     55			break;
     56	}
     57
     58	signal(SIGALRM, SIG_DFL);
     59}
     60
     61/*
     62 * This only works with recent kernels where cpufreq modifies
     63 * /proc/cpuinfo dynamically.
     64 */
     65static void get_proc_frequency(void)
     66{
     67	FILE *f;
     68	char line[128];
     69	char *p, *end;
     70	unsigned long v;
     71	double d;
     72	char *override;
     73
     74	/* Try to get out of low power/low frequency mode */
     75	cpu_soak_usecs(0.25 * 1000000);
     76
     77	f = fopen("/proc/cpuinfo", "r");
     78	if (f == NULL)
     79		return;
     80
     81	timebase_frequency = 0;
     82
     83	while (fgets(line, sizeof(line), f) != NULL) {
     84		if (strncmp(line, "timebase", 8) == 0) {
     85			p = strchr(line, ':');
     86			if (p != NULL) {
     87				v = strtoull(p + 1, &end, 0);
     88				if (end != p + 1)
     89					timebase_frequency = v;
     90			}
     91		}
     92
     93		if (((strncmp(line, "clock", 5) == 0) ||
     94		     (strncmp(line, "cpu MHz", 7) == 0))) {
     95			p = strchr(line, ':');
     96			if (p != NULL) {
     97				d = strtod(p + 1, &end);
     98				if (end != p + 1) {
     99					/* Find fastest clock frequency */
    100					if ((d * 1000000ULL) > clock_frequency)
    101						clock_frequency = d * 1000000ULL;
    102				}
    103			}
    104		}
    105	}
    106
    107	fclose(f);
    108
    109	override = getenv("FREQUENCY");
    110	if (override)
    111		clock_frequency = strtoull(override, NULL, 10);
    112
    113	if (timebase_frequency)
    114		timebase_multiplier = (double)clock_frequency
    115					/ timebase_frequency;
    116	else
    117		timebase_multiplier = 1;
    118}
    119
    120static void do_null_syscall(unsigned long nr)
    121{
    122	unsigned long i;
    123
    124	for (i = 0; i < nr; i++)
    125		syscall(__NR_gettid);
    126}
    127
    128#define TIME(A, STR) \
    129
    130int main(void)
    131{
    132	unsigned long tb_start, tb_now;
    133	struct timespec tv_start, tv_now;
    134	unsigned long long elapsed_ns, elapsed_tb;
    135
    136	get_proc_frequency();
    137
    138	clock_gettime(CLOCK_MONOTONIC, &tv_start);
    139	tb_start = mftb();
    140
    141	do_null_syscall(NR_LOOPS);
    142
    143	clock_gettime(CLOCK_MONOTONIC, &tv_now);
    144	tb_now = mftb();
    145
    146	elapsed_ns = (tv_now.tv_sec - tv_start.tv_sec) * 1000000000ULL +
    147			(tv_now.tv_nsec - tv_start.tv_nsec);
    148	elapsed_tb = tb_now - tb_start;
    149
    150	printf("%10.2f ns %10.2f cycles\n", (float)elapsed_ns / NR_LOOPS,
    151			(float)elapsed_tb * timebase_multiplier / NR_LOOPS);
    152
    153	return 0;
    154}