fix NowNanos overflow (#5062)
Summary: The original implementation of WinEnvIO::NowNanos() has a constant data overflow by: li.QuadPart *= std::nano::den; As a result, the api provides a incorrect result. e.g.: li.QuadPart=13477844301545 std::nano::den=1e9 The fix uses pre-computed nano_seconds_per_period_ to present the nano seconds per performance counter period, in the case if nano::den is divisible by perf_counter_frequency_. Otherwise it falls back to use high_resolution_clock. siying ajkr Pull Request resolved: https://github.com/facebook/rocksdb/pull/5062 Differential Revision: D14426842 Pulled By: anand1976 fbshipit-source-id: 127f1daf423dd4b30edd0dcf8ea0466f468bec12
This commit is contained in:
parent
c84fad7a19
commit
88d85b6820
@ -73,6 +73,7 @@ WinEnvIO::WinEnvIO(Env* hosted_env)
|
|||||||
page_size_(4 * 1024),
|
page_size_(4 * 1024),
|
||||||
allocation_granularity_(page_size_),
|
allocation_granularity_(page_size_),
|
||||||
perf_counter_frequency_(0),
|
perf_counter_frequency_(0),
|
||||||
|
nano_seconds_per_period_(0),
|
||||||
GetSystemTimePreciseAsFileTime_(NULL) {
|
GetSystemTimePreciseAsFileTime_(NULL) {
|
||||||
|
|
||||||
SYSTEM_INFO sinfo;
|
SYSTEM_INFO sinfo;
|
||||||
@ -87,6 +88,10 @@ WinEnvIO::WinEnvIO(Env* hosted_env)
|
|||||||
ret = QueryPerformanceFrequency(&qpf);
|
ret = QueryPerformanceFrequency(&qpf);
|
||||||
assert(ret == TRUE);
|
assert(ret == TRUE);
|
||||||
perf_counter_frequency_ = qpf.QuadPart;
|
perf_counter_frequency_ = qpf.QuadPart;
|
||||||
|
|
||||||
|
if (std::nano::den % perf_counter_frequency_ == 0) {
|
||||||
|
nano_seconds_per_period_ = std::nano::den / perf_counter_frequency_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HMODULE module = GetModuleHandle("kernel32.dll");
|
HMODULE module = GetModuleHandle("kernel32.dll");
|
||||||
@ -955,21 +960,29 @@ uint64_t WinEnvIO::NowMicros() {
|
|||||||
return li.QuadPart;
|
return li.QuadPart;
|
||||||
}
|
}
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
|
return duration_cast<microseconds>(
|
||||||
|
high_resolution_clock::now().time_since_epoch()).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t WinEnvIO::NowNanos() {
|
uint64_t WinEnvIO::NowNanos() {
|
||||||
// all std::chrono clocks on windows have the same resolution that is only
|
if (nano_seconds_per_period_ != 0) {
|
||||||
// good enough for microseconds but not nanoseconds
|
// all std::chrono clocks on windows have the same resolution that is only
|
||||||
// On Windows 8 and Windows 2012 Server
|
// good enough for microseconds but not nanoseconds
|
||||||
// GetSystemTimePreciseAsFileTime(¤t_time) can be used
|
// On Windows 8 and Windows 2012 Server
|
||||||
LARGE_INTEGER li;
|
// GetSystemTimePreciseAsFileTime(¤t_time) can be used
|
||||||
QueryPerformanceCounter(&li);
|
LARGE_INTEGER li;
|
||||||
// Convert to nanoseconds first to avoid loss of precision
|
QueryPerformanceCounter(&li);
|
||||||
// and divide by frequency
|
// Convert performance counter to nanoseconds by precomputed ratio.
|
||||||
li.QuadPart *= std::nano::den;
|
// Directly multiply nano::den with li.QuadPart causes overflow.
|
||||||
li.QuadPart /= perf_counter_frequency_;
|
// Only do this when nano::den is divisible by perf_counter_frequency_,
|
||||||
return li.QuadPart;
|
// which most likely is the case in reality. If it's not, fall back to
|
||||||
|
// high_resolution_clock, which may be less precise under old compilers.
|
||||||
|
li.QuadPart *= nano_seconds_per_period_;
|
||||||
|
return li.QuadPart;
|
||||||
|
}
|
||||||
|
using namespace std::chrono;
|
||||||
|
return duration_cast<nanoseconds>(
|
||||||
|
high_resolution_clock::now().time_since_epoch()).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WinEnvIO::GetHostName(char* name, uint64_t len) {
|
Status WinEnvIO::GetHostName(char* name, uint64_t len) {
|
||||||
|
@ -198,6 +198,7 @@ private:
|
|||||||
size_t page_size_;
|
size_t page_size_;
|
||||||
size_t allocation_granularity_;
|
size_t allocation_granularity_;
|
||||||
uint64_t perf_counter_frequency_;
|
uint64_t perf_counter_frequency_;
|
||||||
|
uint64_t nano_seconds_per_period_;
|
||||||
FnGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTime_;
|
FnGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTime_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user