Files
csapp2025/perflab/matrix/clock.c
2025-04-12 11:37:07 +08:00

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;
}