Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
gettimeofday
context_switch
fork
exec_target
mmap_bench
futex_bench
null_syscall
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
TEST_GEN_PROGS := gettimeofday context_switch fork mmap_bench futex_bench null_syscall
TEST_GEN_FILES := exec_target
TEST_FILES := settings
top_srcdir = ../../../../..
include ../../lib.mk
include ../flags.mk
CFLAGS += -O2
$(TEST_GEN_PROGS): ../harness.c
$(OUTPUT)/context_switch: ../utils.c
$(OUTPUT)/context_switch: CFLAGS += -maltivec -mvsx -mabi=altivec
$(OUTPUT)/context_switch: LDLIBS += -lpthread
$(OUTPUT)/fork: LDLIBS += -lpthread
$(OUTPUT)/exec_target: CFLAGS += -nostartfiles
@@ -0,0 +1,508 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Context switch microbenchmark.
*
* Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
*/
#define _GNU_SOURCE
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>
#include <assert.h>
#include <pthread.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <linux/futex.h>
#ifdef __powerpc__
#include <altivec.h>
#endif
#include "utils.h"
static unsigned int timeout = 30;
static int touch_vdso;
struct timeval tv;
static int touch_fp = 1;
double fp;
static int touch_vector = 1;
vector int a, b, c;
#ifdef __powerpc__
static int touch_altivec = 1;
/*
* Note: LTO (Link Time Optimisation) doesn't play well with this function
* attribute. Be very careful enabling LTO for this test.
*/
static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
{
c = a + b;
}
#endif
static void touch(void)
{
if (touch_vdso)
gettimeofday(&tv, NULL);
if (touch_fp)
fp += 0.1;
#ifdef __powerpc__
if (touch_altivec)
altivec_touch_fn();
#endif
if (touch_vector)
c = a + b;
asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c));
}
static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu)
{
int rc;
pthread_t tid;
cpu_set_t cpuset;
pthread_attr_t attr;
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
rc = pthread_attr_init(&attr);
if (rc) {
errno = rc;
perror("pthread_attr_init");
exit(1);
}
rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
if (rc) {
errno = rc;
perror("pthread_attr_setaffinity_np");
exit(1);
}
rc = pthread_create(&tid, &attr, fn, arg);
if (rc) {
errno = rc;
perror("pthread_create");
exit(1);
}
}
static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu)
{
int pid, ncpus;
cpu_set_t *cpuset;
size_t size;
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid)
return;
ncpus = get_nprocs();
size = CPU_ALLOC_SIZE(ncpus);
cpuset = CPU_ALLOC(ncpus);
if (!cpuset) {
perror("malloc");
exit(1);
}
CPU_ZERO_S(size, cpuset);
CPU_SET_S(cpu, size, cpuset);
if (sched_setaffinity(0, size, cpuset)) {
perror("sched_setaffinity");
CPU_FREE(cpuset);
exit(1);
}
CPU_FREE(cpuset);
fn(arg);
exit(0);
}
static unsigned long iterations;
static unsigned long iterations_prev;
static void sigalrm_handler(int junk)
{
unsigned long i = iterations;
printf("%ld\n", i - iterations_prev);
iterations_prev = i;
if (--timeout == 0)
kill(0, SIGUSR1);
alarm(1);
}
static void sigusr1_handler(int junk)
{
exit(0);
}
struct actions {
void (*setup)(int, int);
void *(*thread1)(void *);
void *(*thread2)(void *);
};
#define READ 0
#define WRITE 1
static int pipe_fd1[2];
static int pipe_fd2[2];
static void pipe_setup(int cpu1, int cpu2)
{
if (pipe(pipe_fd1) || pipe(pipe_fd2))
exit(1);
}
static void *pipe_thread1(void *arg)
{
signal(SIGALRM, sigalrm_handler);
alarm(1);
while (1) {
assert(read(pipe_fd1[READ], &c, 1) == 1);
touch();
assert(write(pipe_fd2[WRITE], &c, 1) == 1);
touch();
iterations += 2;
}
return NULL;
}
static void *pipe_thread2(void *arg)
{
while (1) {
assert(write(pipe_fd1[WRITE], &c, 1) == 1);
touch();
assert(read(pipe_fd2[READ], &c, 1) == 1);
touch();
}
return NULL;
}
static struct actions pipe_actions = {
.setup = pipe_setup,
.thread1 = pipe_thread1,
.thread2 = pipe_thread2,
};
static void yield_setup(int cpu1, int cpu2)
{
if (cpu1 != cpu2) {
fprintf(stderr, "Both threads must be on the same CPU for yield test\n");
exit(1);
}
}
static void *yield_thread1(void *arg)
{
signal(SIGALRM, sigalrm_handler);
alarm(1);
while (1) {
sched_yield();
touch();
iterations += 2;
}
return NULL;
}
static void *yield_thread2(void *arg)
{
while (1) {
sched_yield();
touch();
}
return NULL;
}
static struct actions yield_actions = {
.setup = yield_setup,
.thread1 = yield_thread1,
.thread2 = yield_thread2,
};
static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
void *addr2, int val3)
{
return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}
static unsigned long cmpxchg(unsigned long *p, unsigned long expected,
unsigned long desired)
{
unsigned long exp = expected;
__atomic_compare_exchange_n(p, &exp, desired, 0,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return exp;
}
static unsigned long xchg(unsigned long *p, unsigned long val)
{
return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);
}
static int processes;
static int mutex_lock(unsigned long *m)
{
int c;
int flags = FUTEX_WAIT;
if (!processes)
flags |= FUTEX_PRIVATE_FLAG;
c = cmpxchg(m, 0, 1);
if (!c)
return 0;
if (c == 1)
c = xchg(m, 2);
while (c) {
sys_futex(m, flags, 2, NULL, NULL, 0);
c = xchg(m, 2);
}
return 0;
}
static int mutex_unlock(unsigned long *m)
{
int flags = FUTEX_WAKE;
if (!processes)
flags |= FUTEX_PRIVATE_FLAG;
if (*m == 2)
*m = 0;
else if (xchg(m, 0) == 1)
return 0;
sys_futex(m, flags, 1, NULL, NULL, 0);
return 0;
}
static unsigned long *m1, *m2;
static void futex_setup(int cpu1, int cpu2)
{
if (!processes) {
static unsigned long _m1, _m2;
m1 = &_m1;
m2 = &_m2;
} else {
int shmid;
void *shmaddr;
shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W);
if (shmid < 0) {
perror("shmget");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0);
if (shmaddr == (char *)-1) {
perror("shmat");
shmctl(shmid, IPC_RMID, NULL);
exit(1);
}
shmctl(shmid, IPC_RMID, NULL);
m1 = shmaddr;
m2 = shmaddr + sizeof(*m1);
}
*m1 = 0;
*m2 = 0;
mutex_lock(m1);
mutex_lock(m2);
}
static void *futex_thread1(void *arg)
{
signal(SIGALRM, sigalrm_handler);
alarm(1);
while (1) {
mutex_lock(m2);
mutex_unlock(m1);
iterations += 2;
}
return NULL;
}
static void *futex_thread2(void *arg)
{
while (1) {
mutex_unlock(m2);
mutex_lock(m1);
}
return NULL;
}
static struct actions futex_actions = {
.setup = futex_setup,
.thread1 = futex_thread1,
.thread2 = futex_thread2,
};
static struct option options[] = {
{ "test", required_argument, 0, 't' },
{ "process", no_argument, &processes, 1 },
{ "timeout", required_argument, 0, 's' },
{ "vdso", no_argument, &touch_vdso, 1 },
{ "no-fp", no_argument, &touch_fp, 0 },
#ifdef __powerpc__
{ "no-altivec", no_argument, &touch_altivec, 0 },
#endif
{ "no-vector", no_argument, &touch_vector, 0 },
{ 0, },
};
static void usage(void)
{
fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n");
fprintf(stderr, "\t\t--process\tUse processes (default threads)\n");
fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n");
fprintf(stderr, "\t\t--no-fp\t\tDon't touch FP\n");
#ifdef __powerpc__
fprintf(stderr, "\t\t--no-altivec\tDon't touch altivec\n");
#endif
fprintf(stderr, "\t\t--no-vector\tDon't touch vector\n");
}
int main(int argc, char *argv[])
{
signed char c;
struct actions *actions = &yield_actions;
int cpu1;
int cpu2;
static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu);
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
if (options[option_index].flag != 0)
break;
usage();
exit(1);
break;
case 't':
if (!strcmp(optarg, "pipe")) {
actions = &pipe_actions;
} else if (!strcmp(optarg, "yield")) {
actions = &yield_actions;
} else if (!strcmp(optarg, "futex")) {
actions = &futex_actions;
} else {
usage();
exit(1);
}
break;
case 's':
timeout = atoi(optarg);
break;
default:
usage();
exit(1);
}
}
if (processes)
start_fn = start_process_on;
else
start_fn = start_thread_on;
if (((argc - optind) != 2)) {
cpu1 = cpu2 = pick_online_cpu();
} else {
cpu1 = atoi(argv[optind++]);
cpu2 = atoi(argv[optind++]);
}
printf("Using %s with ", processes ? "processes" : "threads");
if (actions == &pipe_actions)
printf("pipe");
else if (actions == &yield_actions)
printf("yield");
else
printf("futex");
if (!have_hwcap(PPC_FEATURE_HAS_ALTIVEC))
touch_altivec = 0;
if (!have_hwcap(PPC_FEATURE_HAS_VSX))
touch_vector = 0;
printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
cpu1, cpu2, touch_fp ? "yes" : "no", touch_altivec ? "yes" : "no",
touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
/* Create a new process group so we can signal everyone for exit */
setpgid(getpid(), getpid());
signal(SIGUSR1, sigusr1_handler);
actions->setup(cpu1, cpu2);
start_fn(actions->thread1, NULL, cpu1);
start_fn(actions->thread2, NULL, cpu2);
while (1)
sleep(3600);
return 0;
}
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Part of fork context switch microbenchmark.
*
* Copyright 2018, Anton Blanchard, IBM Corp.
*/
#define _GNU_SOURCE
#include <sys/syscall.h>
void _start(void)
{
asm volatile (
"li %%r0, %[sys_exit];"
"li %%r3, 0;"
"sc;"
:
: [sys_exit] "i" (SYS_exit)
/*
* "sc" will clobber r0, r3-r13, cr0, ctr, xer and memory.
* Even though sys_exit never returns, handle clobber
* registers.
*/
: "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
"r11", "r12", "r13", "cr0", "ctr", "xer", "memory"
);
}
@@ -0,0 +1,325 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Context switch microbenchmark.
*
* Copyright 2018, Anton Blanchard, IBM Corp.
*/
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <linux/futex.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static unsigned int timeout = 30;
static void set_cpu(int cpu)
{
cpu_set_t cpuset;
if (cpu == -1)
return;
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {
perror("sched_setaffinity");
exit(1);
}
}
static void start_process_on(void *(*fn)(void *), void *arg, int cpu)
{
int pid;
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid)
return;
set_cpu(cpu);
fn(arg);
exit(0);
}
static int cpu;
static int do_fork = 0;
static int do_vfork = 0;
static int do_exec = 0;
static char *exec_file;
static int exec_target = 0;
static unsigned long iterations;
static unsigned long iterations_prev;
static void run_exec(void)
{
char *const argv[] = { "./exec_target", NULL };
if (execve("./exec_target", argv, NULL) == -1) {
perror("execve");
exit(1);
}
}
static void bench_fork(void)
{
while (1) {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
if (do_exec)
run_exec();
_exit(0);
}
pid = waitpid(pid, NULL, 0);
if (pid == -1) {
perror("waitpid");
exit(1);
}
iterations++;
}
}
static void bench_vfork(void)
{
while (1) {
pid_t pid = vfork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
if (do_exec)
run_exec();
_exit(0);
}
pid = waitpid(pid, NULL, 0);
if (pid == -1) {
perror("waitpid");
exit(1);
}
iterations++;
}
}
static void *null_fn(void *arg)
{
pthread_exit(NULL);
}
static void bench_thread(void)
{
pthread_t tid;
cpu_set_t cpuset;
pthread_attr_t attr;
int rc;
rc = pthread_attr_init(&attr);
if (rc) {
errno = rc;
perror("pthread_attr_init");
exit(1);
}
if (cpu != -1) {
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
if (rc) {
errno = rc;
perror("pthread_attr_setaffinity_np");
exit(1);
}
}
while (1) {
rc = pthread_create(&tid, &attr, null_fn, NULL);
if (rc) {
errno = rc;
perror("pthread_create");
exit(1);
}
rc = pthread_join(tid, NULL);
if (rc) {
errno = rc;
perror("pthread_join");
exit(1);
}
iterations++;
}
}
static void sigalrm_handler(int junk)
{
unsigned long i = iterations;
printf("%ld\n", i - iterations_prev);
iterations_prev = i;
if (--timeout == 0)
kill(0, SIGUSR1);
alarm(1);
}
static void sigusr1_handler(int junk)
{
exit(0);
}
static void *bench_proc(void *arg)
{
signal(SIGALRM, sigalrm_handler);
alarm(1);
if (do_fork)
bench_fork();
else if (do_vfork)
bench_vfork();
else
bench_thread();
return NULL;
}
static struct option options[] = {
{ "fork", no_argument, &do_fork, 1 },
{ "vfork", no_argument, &do_vfork, 1 },
{ "exec", no_argument, &do_exec, 1 },
{ "timeout", required_argument, 0, 's' },
{ "exec-target", no_argument, &exec_target, 1 },
{ NULL },
};
static void usage(void)
{
fprintf(stderr, "Usage: fork <options> CPU\n\n");
fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n");
fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n");
fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n");
fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n");
}
int main(int argc, char *argv[])
{
signed char c;
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
if (options[option_index].flag != 0)
break;
usage();
exit(1);
break;
case 's':
timeout = atoi(optarg);
break;
default:
usage();
exit(1);
}
}
if (do_fork && do_vfork) {
usage();
exit(1);
}
if (do_exec && !do_fork && !do_vfork) {
usage();
exit(1);
}
if (do_exec) {
char *dirname = strdup(argv[0]);
int i;
i = strlen(dirname) - 1;
while (i) {
if (dirname[i] == '/') {
dirname[i] = '\0';
if (chdir(dirname) == -1) {
perror("chdir");
exit(1);
}
break;
}
i--;
}
}
if (exec_target) {
exit(0);
}
if (((argc - optind) != 1)) {
cpu = -1;
} else {
cpu = atoi(argv[optind++]);
}
if (do_exec)
exec_file = argv[0];
set_cpu(cpu);
printf("Using ");
if (do_fork)
printf("fork");
else if (do_vfork)
printf("vfork");
else
printf("clone");
if (do_exec)
printf(" + exec");
printf(" on cpu %d\n", cpu);
/* Create a new process group so we can signal everyone for exit */
setpgid(getpid(), getpid());
signal(SIGUSR1, sigusr1_handler);
start_process_on(bench_proc, NULL, cpu);
while (1)
sleep(3600);
return 0;
}
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016, Anton Blanchard, Michael Ellerman, IBM Corp.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
#include <linux/futex.h>
#include "utils.h"
#define ITERATIONS 100000000
#define futex(A, B, C, D, E, F) syscall(__NR_futex, A, B, C, D, E, F)
int test_futex(void)
{
struct timespec ts_start, ts_end;
unsigned long i = ITERATIONS;
clock_gettime(CLOCK_MONOTONIC, &ts_start);
while (i--) {
unsigned int addr = 0;
futex(&addr, FUTEX_WAKE, 1, NULL, NULL, 0);
}
clock_gettime(CLOCK_MONOTONIC, &ts_end);
printf("time = %.6f\n", ts_end.tv_sec - ts_start.tv_sec + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9);
return 0;
}
int main(void)
{
test_harness_set_timeout(300);
return test_harness(test_futex, "futex_bench");
}
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2015, Anton Blanchard, IBM Corp.
*/
#include <sys/time.h>
#include <stdio.h>
#include "utils.h"
static int test_gettimeofday(void)
{
int i;
struct timeval tv_start, tv_end, tv_diff;
gettimeofday(&tv_start, NULL);
for(i = 0; i < 100000000; i++) {
gettimeofday(&tv_end, NULL);
}
timersub(&tv_end, &tv_start, &tv_diff);
printf("time = %.6f\n", tv_diff.tv_sec + (tv_diff.tv_usec) * 1e-6);
return 0;
}
int main(void)
{
return test_harness(test_gettimeofday, "gettimeofday");
}
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016, Anton Blanchard, Michael Ellerman, IBM Corp.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <getopt.h>
#include "utils.h"
#define ITERATIONS 5000000
#define MEMSIZE (1UL << 27)
#define PAGE_SIZE (1UL << 16)
#define CHUNK_COUNT (MEMSIZE/PAGE_SIZE)
static int pg_fault;
static int iterations = ITERATIONS;
static struct option options[] = {
{ "pgfault", no_argument, &pg_fault, 1 },
{ "iterations", required_argument, 0, 'i' },
{ 0, },
};
static void usage(void)
{
printf("mmap_bench <--pgfault> <--iterations count>\n");
}
int test_mmap(void)
{
struct timespec ts_start, ts_end;
unsigned long i = iterations;
clock_gettime(CLOCK_MONOTONIC, &ts_start);
while (i--) {
char *c = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
FAIL_IF(c == MAP_FAILED);
if (pg_fault) {
int count;
for (count = 0; count < CHUNK_COUNT; count++)
c[count << 16] = 'c';
}
munmap(c, MEMSIZE);
}
clock_gettime(CLOCK_MONOTONIC, &ts_end);
printf("time = %.6f\n", ts_end.tv_sec - ts_start.tv_sec + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9);
return 0;
}
int main(int argc, char *argv[])
{
signed char c;
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
if (options[option_index].flag != 0)
break;
usage();
exit(1);
break;
case 'i':
iterations = atoi(optarg);
break;
default:
usage();
exit(1);
}
}
test_harness_set_timeout(300);
return test_harness(test_mmap, "mmap_bench");
}
@@ -0,0 +1,154 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Test null syscall performance
*
* Copyright (C) 2009-2015 Anton Blanchard, IBM
*/
#define NR_LOOPS 10000000
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <signal.h>
static volatile int soak_done;
unsigned long long clock_frequency;
unsigned long long timebase_frequency;
double timebase_multiplier;
static inline unsigned long mftb(void)
{
unsigned long low;
asm volatile("mftb %0" : "=r" (low));
return low;
}
static void sigalrm_handler(int unused)
{
soak_done = 1;
}
/*
* Use a timer instead of busy looping on clock_gettime() so we don't
* pollute profiles with glibc and VDSO hits.
*/
static void cpu_soak_usecs(unsigned long usecs)
{
struct itimerval val;
memset(&val, 0, sizeof(val));
val.it_value.tv_usec = usecs;
signal(SIGALRM, sigalrm_handler);
setitimer(ITIMER_REAL, &val, NULL);
while (1) {
if (soak_done)
break;
}
signal(SIGALRM, SIG_DFL);
}
/*
* This only works with recent kernels where cpufreq modifies
* /proc/cpuinfo dynamically.
*/
static void get_proc_frequency(void)
{
FILE *f;
char line[128];
char *p, *end;
unsigned long v;
double d;
char *override;
/* Try to get out of low power/low frequency mode */
cpu_soak_usecs(0.25 * 1000000);
f = fopen("/proc/cpuinfo", "r");
if (f == NULL)
return;
timebase_frequency = 0;
while (fgets(line, sizeof(line), f) != NULL) {
if (strncmp(line, "timebase", 8) == 0) {
p = strchr(line, ':');
if (p != NULL) {
v = strtoull(p + 1, &end, 0);
if (end != p + 1)
timebase_frequency = v;
}
}
if (((strncmp(line, "clock", 5) == 0) ||
(strncmp(line, "cpu MHz", 7) == 0))) {
p = strchr(line, ':');
if (p != NULL) {
d = strtod(p + 1, &end);
if (end != p + 1) {
/* Find fastest clock frequency */
if ((d * 1000000ULL) > clock_frequency)
clock_frequency = d * 1000000ULL;
}
}
}
}
fclose(f);
override = getenv("FREQUENCY");
if (override)
clock_frequency = strtoull(override, NULL, 10);
if (timebase_frequency)
timebase_multiplier = (double)clock_frequency
/ timebase_frequency;
else
timebase_multiplier = 1;
}
static void do_null_syscall(unsigned long nr)
{
unsigned long i;
for (i = 0; i < nr; i++)
syscall(__NR_gettid);
}
#define TIME(A, STR) \
int main(void)
{
unsigned long tb_start, tb_now;
struct timespec tv_start, tv_now;
unsigned long long elapsed_ns, elapsed_tb;
get_proc_frequency();
clock_gettime(CLOCK_MONOTONIC, &tv_start);
tb_start = mftb();
do_null_syscall(NR_LOOPS);
clock_gettime(CLOCK_MONOTONIC, &tv_now);
tb_now = mftb();
elapsed_ns = (tv_now.tv_sec - tv_start.tv_sec) * 1000000000ULL +
(tv_now.tv_nsec - tv_start.tv_nsec);
elapsed_tb = tb_now - tb_start;
printf("%10.2f ns %10.2f cycles\n", (float)elapsed_ns / NR_LOOPS,
(float)elapsed_tb * timebase_multiplier / NR_LOOPS);
return 0;
}
@@ -0,0 +1 @@
timeout=0