1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-23 00:00:05 +01:00
libhermit/usr/benchmarks/ib/get_clock.c

234 lines
5.6 KiB
C
Executable file

/*
* Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* $Id$
*
* Author: Michael S. Tsirkin <mst@mellanox.co.il>
*/
/* #define DEBUG 1 */
/* #define DEBUG_DATA 1 */
/* #define GET_CPU_MHZ_FROM_PROC 1 */
/* For gettimeofday */
#define _BSD_SOURCE
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "get_clock.h"
#ifndef DEBUG
#define DEBUG 0
#endif
#ifndef DEBUG_DATA
#define DEBUG_DATA 0
#endif
#define MEASUREMENTS 200
#define USECSTEP 10
#define USECSTART 100
/*
Use linear regression to calculate cycles per microsecond.
http://en.wikipedia.org/wiki/Linear_regression#Parameter_estimation
*/
static double sample_get_cpu_mhz(void)
{
struct timeval tv1, tv2;
cycles_t start;
double sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0;
double tx, ty;
int i;
/* Regression: y = a + b x */
long x[MEASUREMENTS];
cycles_t y[MEASUREMENTS];
double a; /* system call overhead in cycles */
double b; /* cycles per microsecond */
double r_2;
for (i = 0; i < MEASUREMENTS; ++i) {
start = get_cycles();
if (gettimeofday(&tv1, NULL)) {
fprintf(stderr, "gettimeofday failed.\n");
return 0;
}
do {
if (gettimeofday(&tv2, NULL)) {
fprintf(stderr, "gettimeofday failed.\n");
return 0;
}
} while ((tv2.tv_sec - tv1.tv_sec) * 1000000 +
(tv2.tv_usec - tv1.tv_usec) < USECSTART + i * USECSTEP);
x[i] = (tv2.tv_sec - tv1.tv_sec) * 1000000 +
tv2.tv_usec - tv1.tv_usec;
y[i] = get_cycles() - start;
if (DEBUG_DATA)
fprintf(stderr, "x=%ld y=%Ld\n", x[i], (long long)y[i]);
}
for (i = 0; i < MEASUREMENTS; ++i) {
tx = x[i];
ty = y[i];
sx += tx;
sy += ty;
sxx += tx * tx;
syy += ty * ty;
sxy += tx * ty;
}
b = (MEASUREMENTS * sxy - sx * sy) / (MEASUREMENTS * sxx - sx * sx);
a = (sy - b * sx) / MEASUREMENTS;
if (DEBUG)
fprintf(stderr, "a = %g\n", a);
if (DEBUG)
fprintf(stderr, "b = %g\n", b);
if (DEBUG)
fprintf(stderr, "a / b = %g\n", a / b);
r_2 = (MEASUREMENTS * sxy - sx * sy) * (MEASUREMENTS * sxy - sx * sy) /
(MEASUREMENTS * sxx - sx * sx) /
(MEASUREMENTS * syy - sy * sy);
if (DEBUG)
fprintf(stderr, "r^2 = %g\n", r_2);
if (r_2 < 0.9) {
fprintf(stderr,"Correlation coefficient r^2: %g < 0.9\n", r_2);
return 0;
}
return b;
}
#if !defined(__s390x__) && !defined(__s390__)
static double proc_get_cpu_mhz(int no_cpu_freq_warn)
{
FILE* f;
char buf[256];
double mhz = 0.0;
int print_flag = 0;
double delta;
#if defined(__FreeBSD__)
f = popen("/sbin/sysctl hw.clockrate","r");
#else
f = fopen("/proc/cpuinfo","r");
#endif
if (!f)
return 0.0;
while(fgets(buf, sizeof(buf), f)) {
double m;
int rc;
#if defined (__ia64__)
/* Use the ITC frequency on IA64 */
rc = sscanf(buf, "itc MHz : %lf", &m);
#elif defined (__PPC__) || defined (__PPC64__)
/* PPC has a different format as well */
rc = sscanf(buf, "clock : %lf", &m);
#elif defined (__sparc__) && defined (__arch64__)
/*
* on sparc the /proc/cpuinfo lines that hold
* the cpu freq in HZ are as follow:
* Cpu{cpu-num}ClkTck : 00000000a9beeee4
*/
char *s;
s = strstr(buf, "ClkTck\t: ");
if (!s)
continue;
s += (strlen("ClkTck\t: ") - strlen("0x"));
strncpy(s, "0x", strlen("0x"));
rc = sscanf(s, "%lf", &m);
m /= 1000000;
#else
#if defined (__FreeBSD__)
rc = sscanf(buf, "hw.clockrate: %lf", &m);
#else
rc = sscanf(buf, "cpu MHz : %lf", &m);
#endif
#endif
if (rc != 1)
continue;
if (mhz == 0.0) {
mhz = m;
continue;
}
delta = mhz > m ? mhz - m : m - mhz;
if ((delta / mhz > 0.02) && (print_flag ==0)) {
print_flag = 1;
if (!no_cpu_freq_warn) {
fprintf(stderr, "Conflicting CPU frequency values"
" detected: %lf != %lf. CPU Frequency is not max.\n", mhz, m);
}
continue;
}
}
#if defined(__FreeBSD__)
pclose(f);
#else
fclose(f);
#endif
return mhz;
}
#endif
double get_cpu_mhz(int no_cpu_freq_warn)
{
#if defined(__s390x__) || defined(__s390__)
return sample_get_cpu_mhz();
#else
double sample, proc, delta;
sample = sample_get_cpu_mhz();
proc = proc_get_cpu_mhz(no_cpu_freq_warn);
#ifdef __aarch64__
if (proc < 1)
proc = sample;
#endif
if (!proc || !sample)
return 0;
delta = proc > sample ? proc - sample : sample - proc;
if (delta / proc > 0.02) {
return sample;
}
return proc;
#endif
}