197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
/* clock.c
|
|
* Retrofitted to use thread-specific timers
|
|
* and to get clock information from /proc/cpuinfo
|
|
* (C) R. E. Bryant, 2010
|
|
* Modified for cross-platform compatibility
|
|
*/
|
|
|
|
#define _GNU_SOURCE // For sched_setaffinity on Linux
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <intrin.h>
|
|
#include <windows.h>
|
|
#else
|
|
#include <sched.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <x86intrin.h>
|
|
typedef struct {
|
|
uint64_t QuadPart;
|
|
} LARGE_INTEGER;
|
|
typedef void *HANDLE;
|
|
#define __int64 long long
|
|
#define Sleep(ms) usleep((ms) * 1000)
|
|
#endif
|
|
|
|
#include "clock.h"
|
|
|
|
/* Use x86 cycle counter */
|
|
static unsigned cyc_hi = 0;
|
|
static unsigned cyc_lo = 0;
|
|
|
|
void access_counter(unsigned *hi, unsigned *lo) {
|
|
uint64_t counter = __rdtsc();
|
|
*hi = (unsigned)(counter >> 32);
|
|
*lo = (unsigned)counter;
|
|
}
|
|
|
|
void start_counter() { access_counter(&cyc_hi, &cyc_lo); }
|
|
|
|
double get_counter() {
|
|
unsigned ncyc_hi, ncyc_lo;
|
|
access_counter(&ncyc_hi, &ncyc_lo);
|
|
uint64_t start = ((uint64_t)cyc_hi << 32) | cyc_lo;
|
|
uint64_t end = ((uint64_t)ncyc_hi << 32) | ncyc_lo;
|
|
return (double)(end - start);
|
|
}
|
|
|
|
void make_CPU_busy(void) {
|
|
volatile double old_tick = get_counter();
|
|
volatile double new_tick;
|
|
while ((new_tick - old_tick) < 1000000000) {
|
|
new_tick = get_counter();
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#define GET_TIME(dest) QueryPerformanceCounter(dest)
|
|
#else
|
|
static inline void GET_TIME(LARGE_INTEGER *dest) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
dest->QuadPart = (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
|
|
}
|
|
#define QueryPerformanceFrequency(freq) ((freq)->QuadPart = 1000000000)
|
|
#endif
|
|
|
|
double mhz(int verbose) {
|
|
LARGE_INTEGER lFrequency;
|
|
LARGE_INTEGER lPerformanceCount_Start;
|
|
LARGE_INTEGER lPerformanceCount_End;
|
|
double mhz;
|
|
double fTime;
|
|
__int64 _i64StartCpuCounter;
|
|
__int64 _i64EndCpuCounter;
|
|
|
|
#ifdef _WIN32
|
|
HANDLE hThread = GetCurrentThread();
|
|
SetThreadAffinityMask(hThread, 0x1);
|
|
#else
|
|
cpu_set_t cpuset;
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(0, &cpuset);
|
|
sched_setaffinity(0, sizeof(cpuset), &cpuset);
|
|
#endif
|
|
|
|
QueryPerformanceFrequency(&lFrequency);
|
|
GET_TIME(&lPerformanceCount_Start);
|
|
_i64StartCpuCounter = __rdtsc();
|
|
Sleep(200);
|
|
GET_TIME(&lPerformanceCount_End);
|
|
_i64EndCpuCounter = __rdtsc();
|
|
|
|
fTime = (lPerformanceCount_End.QuadPart - lPerformanceCount_Start.QuadPart) /
|
|
(double)lFrequency.QuadPart;
|
|
mhz = (_i64EndCpuCounter - _i64StartCpuCounter) / (fTime * 1000000.0);
|
|
|
|
if (verbose > 0) {
|
|
printf("CPU频率为: %.6fMHz.\n", mhz);
|
|
}
|
|
return mhz;
|
|
}
|
|
|
|
double CPU_Factor1(void) {
|
|
double result;
|
|
int i, j, k;
|
|
LARGE_INTEGER lStart, lEnd;
|
|
LARGE_INTEGER lFrequency;
|
|
double fTime;
|
|
|
|
#ifdef _WIN32
|
|
HANDLE hThread = GetCurrentThread();
|
|
SetThreadAffinityMask(hThread, 0x1);
|
|
#else
|
|
cpu_set_t cpuset;
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(0, &cpuset);
|
|
sched_setaffinity(0, sizeof(cpuset), &cpuset);
|
|
#endif
|
|
|
|
QueryPerformanceFrequency(&lFrequency);
|
|
GET_TIME(&lStart);
|
|
start_counter();
|
|
|
|
for (i = 0; i < 100; i++)
|
|
for (j = 0; j < 1000; j++)
|
|
for (k = 0; k < 1000; k++)
|
|
;
|
|
|
|
result = get_counter();
|
|
GET_TIME(&lEnd);
|
|
|
|
fTime = (lEnd.QuadPart - lStart.QuadPart) / (double)lFrequency.QuadPart;
|
|
printf("CPU计算时长为: %f", result);
|
|
printf("\t %f\n", fTime);
|
|
return result;
|
|
}
|
|
|
|
double CPU_Factor(void) {
|
|
double frequency;
|
|
double multiplier = 1000 * 1000 * 1000; // nano
|
|
LARGE_INTEGER lFrequency;
|
|
LARGE_INTEGER start, stop;
|
|
int i;
|
|
const int known_instructions_per_loop = 27317;
|
|
int iterations = 100000000;
|
|
int g = 0;
|
|
double normal_ticks_per_second;
|
|
double ticks;
|
|
double time;
|
|
double loops_per_sec;
|
|
double instructions_per_loop;
|
|
double ratio;
|
|
double actual_freq;
|
|
|
|
#ifdef _WIN32
|
|
HANDLE hThread = GetCurrentThread();
|
|
SetThreadAffinityMask(hThread, 0x1);
|
|
#else
|
|
cpu_set_t cpuset;
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(0, &cpuset);
|
|
sched_setaffinity(0, sizeof(cpuset), &cpuset);
|
|
#endif
|
|
|
|
QueryPerformanceFrequency(&lFrequency);
|
|
frequency = (double)lFrequency.QuadPart;
|
|
GET_TIME(&start);
|
|
|
|
for (i = 0; i < iterations; i++) {
|
|
g++;
|
|
g++;
|
|
g++;
|
|
g++;
|
|
}
|
|
|
|
GET_TIME(&stop);
|
|
normal_ticks_per_second = frequency * 1000;
|
|
ticks = (double)(stop.QuadPart - start.QuadPart);
|
|
time = (ticks * multiplier) / frequency;
|
|
loops_per_sec = iterations / (time / multiplier);
|
|
instructions_per_loop = normal_ticks_per_second / loops_per_sec;
|
|
ratio = instructions_per_loop / known_instructions_per_loop;
|
|
actual_freq = normal_ticks_per_second / ratio;
|
|
|
|
printf("Perf counter freq: %f\n", normal_ticks_per_second);
|
|
printf("Loops per sec: %f\n", loops_per_sec);
|
|
printf("Perf counter freq div loops per sec: %f\n", instructions_per_loop);
|
|
printf("Presumed freq: %f\n", actual_freq);
|
|
printf("ratio: %f\n", ratio);
|
|
printf("time=%f\n", time);
|
|
return ratio;
|
|
}
|