18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Strictly speaking, this is not a test. But it can report during test
38c2ecf20Sopenharmony_ci * runs so relative performace can be measured.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#define _GNU_SOURCE
68c2ecf20Sopenharmony_ci#include <assert.h>
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <stdlib.h>
98c2ecf20Sopenharmony_ci#include <time.h>
108c2ecf20Sopenharmony_ci#include <unistd.h>
118c2ecf20Sopenharmony_ci#include <linux/filter.h>
128c2ecf20Sopenharmony_ci#include <linux/seccomp.h>
138c2ecf20Sopenharmony_ci#include <sys/prctl.h>
148c2ecf20Sopenharmony_ci#include <sys/syscall.h>
158c2ecf20Sopenharmony_ci#include <sys/types.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define ARRAY_SIZE(a)    (sizeof(a) / sizeof(a[0]))
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciunsigned long long timing(clockid_t clk_id, unsigned long long samples)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct timespec start, finish;
228c2ecf20Sopenharmony_ci	unsigned long long i;
238c2ecf20Sopenharmony_ci	pid_t pid, ret;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	pid = getpid();
268c2ecf20Sopenharmony_ci	assert(clock_gettime(clk_id, &start) == 0);
278c2ecf20Sopenharmony_ci	for (i = 0; i < samples; i++) {
288c2ecf20Sopenharmony_ci		ret = syscall(__NR_getpid);
298c2ecf20Sopenharmony_ci		assert(pid == ret);
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci	assert(clock_gettime(clk_id, &finish) == 0);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	i = finish.tv_sec - start.tv_sec;
348c2ecf20Sopenharmony_ci	i *= 1000000000ULL;
358c2ecf20Sopenharmony_ci	i += finish.tv_nsec - start.tv_nsec;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	printf("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n",
388c2ecf20Sopenharmony_ci		finish.tv_sec, finish.tv_nsec,
398c2ecf20Sopenharmony_ci		start.tv_sec, start.tv_nsec,
408c2ecf20Sopenharmony_ci		i, (double)i / 1000000000.0);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return i;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciunsigned long long calibrate(void)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct timespec start, finish;
488c2ecf20Sopenharmony_ci	unsigned long long i, samples, step = 9973;
498c2ecf20Sopenharmony_ci	pid_t pid, ret;
508c2ecf20Sopenharmony_ci	int seconds = 15;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	printf("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	samples = 0;
558c2ecf20Sopenharmony_ci	pid = getpid();
568c2ecf20Sopenharmony_ci	assert(clock_gettime(CLOCK_MONOTONIC, &start) == 0);
578c2ecf20Sopenharmony_ci	do {
588c2ecf20Sopenharmony_ci		for (i = 0; i < step; i++) {
598c2ecf20Sopenharmony_ci			ret = syscall(__NR_getpid);
608c2ecf20Sopenharmony_ci			assert(pid == ret);
618c2ecf20Sopenharmony_ci		}
628c2ecf20Sopenharmony_ci		assert(clock_gettime(CLOCK_MONOTONIC, &finish) == 0);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		samples += step;
658c2ecf20Sopenharmony_ci		i = finish.tv_sec - start.tv_sec;
668c2ecf20Sopenharmony_ci		i *= 1000000000ULL;
678c2ecf20Sopenharmony_ci		i += finish.tv_nsec - start.tv_nsec;
688c2ecf20Sopenharmony_ci	} while (i < 1000000000ULL);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return samples * seconds;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct sock_filter filter[] = {
768c2ecf20Sopenharmony_ci		BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
778c2ecf20Sopenharmony_ci	};
788c2ecf20Sopenharmony_ci	struct sock_fprog prog = {
798c2ecf20Sopenharmony_ci		.len = (unsigned short)ARRAY_SIZE(filter),
808c2ecf20Sopenharmony_ci		.filter = filter,
818c2ecf20Sopenharmony_ci	};
828c2ecf20Sopenharmony_ci	long ret;
838c2ecf20Sopenharmony_ci	unsigned long long samples;
848c2ecf20Sopenharmony_ci	unsigned long long native, filter1, filter2;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	printf("Current BPF sysctl settings:\n");
878c2ecf20Sopenharmony_ci	system("sysctl net.core.bpf_jit_enable");
888c2ecf20Sopenharmony_ci	system("sysctl net.core.bpf_jit_harden");
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (argc > 1)
918c2ecf20Sopenharmony_ci		samples = strtoull(argv[1], NULL, 0);
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		samples = calibrate();
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	printf("Benchmarking %llu syscalls...\n", samples);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* Native call */
988c2ecf20Sopenharmony_ci	native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
998c2ecf20Sopenharmony_ci	printf("getpid native: %llu ns\n", native);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1028c2ecf20Sopenharmony_ci	assert(ret == 0);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* One filter */
1058c2ecf20Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
1068c2ecf20Sopenharmony_ci	assert(ret == 0);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
1098c2ecf20Sopenharmony_ci	printf("getpid RET_ALLOW 1 filter: %llu ns\n", filter1);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (filter1 == native)
1128c2ecf20Sopenharmony_ci		printf("No overhead measured!? Try running again with more samples.\n");
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* Two filters */
1158c2ecf20Sopenharmony_ci	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
1168c2ecf20Sopenharmony_ci	assert(ret == 0);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
1198c2ecf20Sopenharmony_ci	printf("getpid RET_ALLOW 2 filters: %llu ns\n", filter2);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Calculations */
1228c2ecf20Sopenharmony_ci	printf("Estimated total seccomp overhead for 1 filter: %llu ns\n",
1238c2ecf20Sopenharmony_ci		filter1 - native);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	printf("Estimated total seccomp overhead for 2 filters: %llu ns\n",
1268c2ecf20Sopenharmony_ci		filter2 - native);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	printf("Estimated seccomp per-filter overhead: %llu ns\n",
1298c2ecf20Sopenharmony_ci		filter2 - filter1);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	printf("Estimated seccomp entry overhead: %llu ns\n",
1328c2ecf20Sopenharmony_ci		filter1 - native - (filter2 - filter1));
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
136