-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4368aa6
commit ba7ee0f
Showing
7 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Ignore CMake-related files | ||
CMakeLists.txt.user | ||
CMakeCache.txt | ||
CMakeFiles/ | ||
CMakeScripts/ | ||
Testing/ | ||
Makefile | ||
cmake_install.cmake | ||
install_manifest.txt | ||
compile_commands.json | ||
CTestTestfile.cmake | ||
_deps/ | ||
CMakePresets.json | ||
CMakeUserPresets.json | ||
|
||
# Ignore Visual Studio files | ||
.vs/ | ||
.vs2019/ | ||
.vs2022/ | ||
.idea/ | ||
|
||
# Ignore build directories | ||
build/ | ||
out/ | ||
|
||
# Ignore Visual Studio configuration files | ||
*.user | ||
*.userosscache | ||
*.suo | ||
*.sdf | ||
*.opensdf | ||
*.vssscc | ||
*.vsscc | ||
|
||
# Ignore temporary files and backups | ||
*.log | ||
*.tmp | ||
*.bak | ||
*.swp | ||
*~ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
cmake_minimum_required (VERSION 3.8) | ||
|
||
if (POLICY CMP0141) | ||
cmake_policy(SET CMP0141 NEW) | ||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>") | ||
endif() | ||
|
||
project ("TimerResolutionMeasure" LANGUAGES CXX) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
|
||
add_subdirectory ("TimerResolutionMeasure") |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
add_executable (TimerResolutionMeasure "main.cpp" "pch.h" "utils.cpp" "utils.h") | ||
|
||
if (CMAKE_VERSION VERSION_GREATER 3.12) | ||
set_property(TARGET TimerResolutionMeasure PROPERTY CXX_STANDARD 20) | ||
endif() | ||
|
||
target_precompile_headers(TimerResolutionMeasure PRIVATE pch.h) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#include "pch.h" | ||
#include "utils.h" | ||
#include "conio.h" | ||
|
||
typedef NTSTATUS(NTAPI* NtQueryTimerResolution_t)(PULONG MinimumResolution, PULONG MaximumResolution, PULONG CurrentResolution); | ||
|
||
int main() { | ||
#ifndef _DEBUG | ||
if (!IsAdmin()) { | ||
std::cerr << "Administrator privileges are required. The program will not function correctly and will now exit.\n"; | ||
std::cout << "Press Enter to continue...\n"; | ||
std::cin.get(); | ||
return 0; | ||
} | ||
#else | ||
std::cout << "[DEBUG] Administrator privilege check is skipped in debug mode.\n" | ||
<< " Note: Some functionality might not work correctly without elevated permissions.\n\n"; | ||
#endif | ||
|
||
int sleep_duration = 1; | ||
|
||
AutoLibrary ntdll(L"ntdll.dll"); | ||
NtQueryTimerResolution_t NtQueryTimerResolution = (NtQueryTimerResolution_t)GetProcAddress(ntdll.get(), "NtQueryTimerResolution"); | ||
if (!NtQueryTimerResolution) { | ||
std::cerr << "Failed to get address of NtQueryTimerResolution\n"; | ||
return 1; | ||
} | ||
|
||
ULONG minimum_resolution, maximum_resolution, current_resolution; | ||
LARGE_INTEGER start, end, freq; | ||
std::vector<double> sleep_delays; | ||
|
||
if (!QueryPerformanceFrequency(&freq)) { | ||
std::cerr << "QueryPerformanceFrequency failed\n"; | ||
return 1; | ||
} | ||
|
||
if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { | ||
std::cerr << "SetPriorityClass failed\n"; | ||
return 1; | ||
} | ||
|
||
std::cout << "Press Enter to stop the cycle and calculate results...\n"; | ||
|
||
while (!_kbhit()) { | ||
NTSTATUS status = NtQueryTimerResolution(&minimum_resolution, &maximum_resolution, ¤t_resolution); | ||
if (!NT_SUCCESS(status)) { | ||
std::cerr << "NtQueryTimerResolution failed\n"; | ||
return 1; | ||
} | ||
|
||
QueryPerformanceCounter(&start); | ||
Sleep(sleep_duration); | ||
QueryPerformanceCounter(&end); | ||
|
||
double delta_s = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart; | ||
double delta_ms = delta_s * 1000; | ||
double delta_from_sleep = delta_ms - sleep_duration; | ||
|
||
std::cout << std::fixed << std::setprecision(4) | ||
<< "Resolution: " << (current_resolution / 10000.0) << "ms, " | ||
<< "Sleep(n=" << sleep_duration << ") slept " << delta_ms << "ms " | ||
<< "(delta: " << delta_from_sleep << ")\n"; | ||
|
||
sleep_delays.push_back(delta_from_sleep); | ||
Sleep(1000); | ||
} | ||
|
||
std::cin.get(); | ||
sleep_delays.erase(sleep_delays.begin()); | ||
|
||
std::nth_element(sleep_delays.begin(), sleep_delays.begin() + sleep_delays.size() / 2, sleep_delays.end()); | ||
std::sort(sleep_delays.begin(), sleep_delays.end()); | ||
|
||
size_t size = sleep_delays.size(); | ||
|
||
double sum = 0.0; | ||
for (double delay : sleep_delays) { | ||
sum += delay; | ||
} | ||
|
||
double average = sum / size; | ||
|
||
double standard_deviation = 0.0; | ||
for (double delay : sleep_delays) { | ||
standard_deviation += pow(delay - average, 2); | ||
} | ||
|
||
double stdev = sqrt(standard_deviation / (size - 1)); | ||
|
||
std::cout << "Results from " << size << " samples (excluding the first sample, which is often inaccurate)\n"; | ||
std::cout << "Max: " << std::setw(10) << std::fixed << std::setprecision(4) << sleep_delays.back() << " ms\n"; | ||
std::cout << "Avg: " << std::setw(10) << std::fixed << std::setprecision(4) << average << " ms\n"; | ||
std::cout << "Min: " << std::setw(10) << std::fixed << std::setprecision(4) << sleep_delays.front() << " ms\n"; | ||
std::cout << "STDEV: " << std::setw(10) << std::fixed << std::setprecision(4) << stdev << " ms\n"; | ||
|
||
std::cout << "\nPress Enter to exit..."; | ||
std::cin.get(); | ||
|
||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#ifndef PCH_H | ||
#define PCH_H | ||
|
||
#include <iostream> | ||
#include <iomanip> | ||
#include <vector> | ||
#include <Windows.h> | ||
#include <cmath> | ||
#include <numeric> | ||
#include <algorithm> | ||
#include <winternl.h> | ||
|
||
#endif //PCH_H |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include "pch.h" | ||
#include "utils.h" | ||
|
||
bool IsAdmin() { | ||
bool admin = false; | ||
HANDLE hToken = NULL; | ||
|
||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { | ||
TOKEN_ELEVATION elevation{}; | ||
DWORD size; | ||
if (GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &size)) { | ||
admin = elevation.TokenIsElevated; | ||
} | ||
CloseHandle(hToken); | ||
} | ||
|
||
return admin; | ||
} | ||
|
||
AutoLibrary::AutoLibrary(const wchar_t* libName) { | ||
handle = LoadLibraryW(libName); | ||
if (!handle) { | ||
DWORD error = GetLastError(); | ||
std::wcerr << L"Failed to load library " << libName << L". Error code: " << error << std::endl; | ||
throw std::runtime_error("Failed to load library"); | ||
} | ||
} | ||
|
||
AutoLibrary::~AutoLibrary() { | ||
if (handle) { | ||
FreeLibrary(handle); | ||
} | ||
} | ||
|
||
HMODULE AutoLibrary::get() const { | ||
return handle; | ||
} | ||
|
||
void calculateStatistics(const std::vector<double>& delays, double& average, double& stdev) { | ||
size_t size = delays.size(); | ||
|
||
double sum = std::accumulate(delays.begin(), delays.end(), 0.0); | ||
double sq_sum = std::accumulate(delays.begin(), delays.end(), 0.0, [](double acc, double val) { | ||
return acc + val * val; | ||
}); | ||
|
||
average = sum / size; | ||
stdev = std::sqrt(sq_sum / (size - 1) - average * average); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#pragma once | ||
|
||
#include "pch.h" | ||
|
||
bool IsAdmin(); | ||
|
||
class AutoLibrary { | ||
public: | ||
AutoLibrary(const wchar_t* libName); | ||
~AutoLibrary(); | ||
HMODULE get() const; | ||
|
||
operator HMODULE() const { return handle; } | ||
|
||
private: | ||
HMODULE handle; | ||
}; | ||
|
||
void calculateStatistics(const std::vector<double>& delays, double& average, double& stdev); |