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