Created
September 19, 2011 11:48
-
-
Save olbat/1226351 to your computer and use it in GitHub Desktop.
CPU Benchmark that try to get guess precisely the number of loop that can be performed in a specified amount of time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2011 Sarzyniec Luc <mail@olbat.net> | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* see the COPYING file for more informations */ | |
/* | |
options: | |
-p <number>: the number of process to launch (fork) | |
-r <number>: the number of repeat (result = mean) | |
-t <number>: the time (seconds) of a benchmark cycle | |
-d : debug | |
*/ | |
#include <sys/types.h> | |
#include <sys/time.h> | |
#include <sys/wait.h> | |
#include <sys/resource.h> | |
#include <unistd.h> | |
#include <getopt.h> | |
#include "cpubench.h" | |
/* Function's source: http://www.gnu.org/s/hello/manual/libc/Elapsed-Time.html */ | |
int timeval_subtract (result, x, y) | |
struct timeval *result, *x, *y; | |
{ | |
/* Perform the carry for the later subtraction by updating y. */ | |
if (x->tv_usec < y->tv_usec) { | |
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; | |
y->tv_usec -= 1000000 * nsec; | |
y->tv_sec += nsec; | |
} | |
if (x->tv_usec - y->tv_usec > 1000000) { | |
int nsec = (x->tv_usec - y->tv_usec) / 1000000; | |
y->tv_usec += 1000000 * nsec; | |
y->tv_sec -= nsec; | |
} | |
/* Compute the time remaining to wait. | |
tv_usec is certainly positive. */ | |
result->tv_sec = x->tv_sec - y->tv_sec; | |
result->tv_usec = x->tv_usec - y->tv_usec; | |
/* Return 1 if result is negative. */ | |
return x->tv_sec < y->tv_sec; | |
} | |
__inline__ void | |
loop() | |
{ | |
register int i, j, x; | |
x = LOOP_SEED; | |
for (i=0; i < 1000; i++) | |
for (j=0; j < 100; j++) | |
x ^= x + (i & j); | |
} | |
__inline__ void | |
loops(unsigned int times) | |
{ | |
while (times--) | |
loop(); | |
} | |
__inline__ unsigned long long int | |
calibrate() | |
{ | |
struct timeval time_start, time_end, time_diff; | |
double walltime; | |
unsigned long long int loopnb, prevloopnb; | |
unsigned int reloop,chdirnb, samedirnb, pitch; | |
char dir; | |
walltime = 0.0f; | |
loopnb = 1; | |
while (walltime < CALIB_THRESHOLD) | |
{ | |
gettimeofday(&time_start, NULL); | |
loops(loopnb); | |
gettimeofday(&time_end, NULL); | |
timeval_subtract(&time_diff,&time_end,&time_start); | |
walltime = TIMEVAL2DOUBLE(time_diff); | |
loopnb <<= 1; | |
} | |
prevloopnb = 0; | |
chdirnb = 0; | |
samedirnb = 0; | |
reloop = 0; | |
dir = 0; | |
pitch = (loopnb - (loopnb>>1))/8; | |
while ( | |
(reloop < CALIB_MAX_RELOOP) | |
&& ((loopnb-prevloopnb) > 1) | |
&& ((prevloopnb-loopnb) > 1) | |
&& ((loopnb != prevloopnb) | |
|| (walltime > (CALIB_THRESHOLD + (CALIB_THRESHOLD/10))) | |
|| (walltime < (CALIB_THRESHOLD - (CALIB_THRESHOLD/10)))) | |
) | |
{ | |
gettimeofday(&time_start, NULL); | |
loops(loopnb); | |
gettimeofday(&time_end, NULL); | |
timeval_subtract(&time_diff,&time_end,&time_start); | |
walltime = TIMEVAL2DOUBLE(time_diff); | |
prevloopnb = loopnb; | |
if (walltime > CALIB_THRESHOLD) | |
{ | |
loopnb -= pitch; | |
if (dir > 0) | |
chdirnb++; | |
else | |
samedirnb++; | |
dir = -1; | |
} | |
else | |
{ | |
loopnb += pitch; | |
if (dir < 0) | |
chdirnb++; | |
else | |
samedirnb++; | |
dir = 1; | |
} | |
if (chdirnb > CALIB_MAX_CHDIR) | |
{ | |
pitch /= 2; | |
chdirnb = 0; | |
} | |
if (samedirnb > CALIB_MAX_SAMEDIR) | |
{ | |
pitch *= 2; | |
samedirnb = 0; | |
} | |
reloop++; | |
} | |
DEBUG("calibloop: %lld\ncalibwall:%lf\n",loopnb,walltime); | |
return (unsigned long long int) (loopnb / walltime); | |
} | |
double bench(unsigned int procnb, unsigned long long loopbase) | |
{ | |
int status, pids[MAX_PROCNB]; | |
double walltime; | |
unsigned int tmp; | |
struct timeval time_start, time_end, time_diff; | |
if (procnb > 1) | |
{ | |
tmp = procnb; | |
gettimeofday(&time_start,NULL); | |
while (tmp--) | |
{ | |
if (!(pids[tmp] = fork())) | |
{ | |
loops(loopbase); | |
exit(0); | |
} | |
} | |
while (procnb--) | |
waitpid(pids[procnb],&status,0); | |
gettimeofday(&time_end,NULL); | |
} | |
else | |
{ | |
gettimeofday(&time_start,NULL); | |
loops(loopbase); | |
gettimeofday(&time_end,NULL); | |
} | |
timeval_subtract(&time_diff,&time_end,&time_start); | |
walltime = TIMEVAL2DOUBLE(time_diff); | |
DEBUG("walltime: %.5f\nresult:%lf\n",walltime,(loopbase / walltime)); | |
return (loopbase / walltime); | |
} | |
int main(int argc, char **argv) | |
{ | |
int tmp; | |
unsigned int procnb, repeat; | |
unsigned long long int loopbase; | |
double result; | |
float time_base; | |
time_base = DEFAULT_TIME; | |
procnb = DEFAULT_PROCNB; | |
repeat = DEFAULT_REPEAT; | |
while ((tmp = getopt (argc, argv, "dn:p:t:")) != -1) | |
{ | |
switch(tmp) | |
{ | |
case 'd': | |
options |= OPT_DEBUG; | |
break; | |
case 'p': | |
procnb = strtol(optarg,0,10); | |
break; | |
case 'n': | |
repeat = strtol(optarg,0,10); | |
break; | |
case 't': | |
time_base = strtof(optarg,0); | |
break; | |
case '?': | |
if ((optopt == 'c') || (optopt == 'p') || (optopt == 'n')) | |
fprintf (stderr, "Option -%c requires an argument.\n", optopt); | |
else | |
fprintf (stderr, "Unknown option '-%c'.\n", optopt); | |
default: | |
abort(); | |
} | |
} | |
DEBUG("procs: %d\n",procnb); | |
loopbase = calibrate(); | |
loopbase = (__typeof__(loopbase)) (loopbase * time_base); | |
DEBUG("loopbase: %lld\ntimebase: %.2f\n",loopbase,time_base); | |
tmp = repeat; | |
result = 0.0; | |
while (tmp--) | |
{ | |
DEBUG("Repeat #%d\n",(repeat-tmp)); | |
result += (bench(procnb,loopbase) / repeat); | |
} | |
fprintf(stdout,"%lf\n", result); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2011 Sarzyniec Luc <mail@olbat.net> | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* see the COPYING file for more informations */ | |
#ifndef _CPUBENCH_H | |
#define _CPUBENCH_H | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/time.h> | |
char options = 0; | |
#define CALIB_THRESHOLD 0.1f | |
#define CALIB_MAX_RELOOP 64 | |
#define CALIB_MAX_CHDIR 3 | |
#define CALIB_MAX_SAMEDIR 3 | |
#define LOOP_SEED ~0 | |
#define DEFAULT_TIME 2.0f | |
#define DEFAULT_PROCNB 2 | |
#define DEFAULT_REPEAT 3 | |
#define MAX_PROCNB 128 | |
#define TIMEVAL2DOUBLE(T) (((double) (T).tv_sec) + (((double) (T).tv_usec) * 1e-6)) | |
enum options_val | |
{ | |
OPT_DEBUG = 1 | |
}; | |
#define DEBUG(format,...) \ | |
do { \ | |
if (options & OPT_DEBUG) \ | |
fprintf(stdout,format,##__VA_ARGS__); \ | |
} while(0); | |
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y); | |
void loop(); | |
void loops(unsigned int times); | |
unsigned long long int calibrate(); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment