Implement TSC calibration

Try to get rough TSC frequency by sampling it.
This commit is contained in:
Nekotekina 2020-04-06 18:23:45 +03:00
parent b6e52ad975
commit 15f01a1bf6

View file

@ -131,13 +131,9 @@ std::string utils::get_system_info()
fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024));
if (!has_invariant_tsc())
if (const ullong tsc_freq = get_tsc_freq())
{
fmt::append(result, " | TSC: Bad");
}
else if (const ullong tsc_freq = get_tsc_freq())
{
fmt::append(result, " | TSC: %.02fGHz", tsc_freq / 1000000000.);
fmt::append(result, " | TSC: %.06fGHz", tsc_freq / 1000000000.);
}
else
{
@ -167,7 +163,7 @@ std::string utils::get_system_info()
if (has_fma3() || has_fma4())
{
result += " | FMA";
if (has_fma3() && has_fma4())
{
result += "3+4";
@ -268,15 +264,67 @@ std::string utils::get_OS_version()
ullong utils::get_tsc_freq()
{
const ullong cal_tsc = []() -> ullong
{
if (!has_invariant_tsc())
return 0;
#ifdef _WIN32
LARGE_INTEGER freq;
if (!QueryPerformanceFrequency(&freq) || freq.QuadPart > 9'999'999)
return 0;
return freq.QuadPart * 1024;
LARGE_INTEGER freq;
if (!QueryPerformanceFrequency(&freq))
return 0;
if (freq.QuadPart <= 9'999'999)
return freq.QuadPart * 1024;
const ullong timer_freq = freq.QuadPart;
Sleep(1);
#else
// TODO
return 0;
const ullong timer_freq = 1'000'000'000;
ullong sec_base = 0;
usleep(200);
#endif
// Calibrate TSC
constexpr int samples = 40;
ullong rdtsc_data[samples];
ullong timer_data[samples];
ullong rdtsc_diff[samples - 1];
ullong timer_diff[samples - 1];
for (int i = 0; i < samples; i++)
{
rdtsc_data[i] = __rdtsc();
if (i > 0)
rdtsc_diff[i - 1] = rdtsc_data[i] - rdtsc_data[i - 1];
#ifdef _WIN32
LARGE_INTEGER ctr;
QueryPerformanceCounter(&ctr);
timer_data[i] = ctr.QuadPart;
Sleep(1);
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (i == 0)
sec_base = ts.tv_sec;
timer_data[i] = ts.tv_nsec + (ts.tv_sec - sec_base) * 1'000'000'000;
usleep(200);
#endif
if (i > 0)
timer_diff[i - 1] = timer_data[i] - timer_data[i - 1];
}
// Compute average TSC
ullong acc = 0;
for (int i = 0; i < samples - 1; i++)
{
acc += rdtsc_diff[i] * timer_freq / timer_diff[i];
}
// Rounding
return acc / (samples - 1);
}();
return cal_tsc;
}
u64 utils::get_total_memory()