Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
aksueikava authored Dec 8, 2024
1 parent 4368aa6 commit ba7ee0f
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 0 deletions.
40 changes: 40 additions & 0 deletions .gitignore
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
*~
13 changes: 13 additions & 0 deletions CMakeLists.txt
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")
7 changes: 7 additions & 0 deletions TimerResolutionMeasure/CMakeLists.txt
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)
101 changes: 101 additions & 0 deletions TimerResolutionMeasure/main.cpp
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, &current_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;
}
13 changes: 13 additions & 0 deletions TimerResolutionMeasure/pch.h
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
49 changes: 49 additions & 0 deletions TimerResolutionMeasure/utils.cpp
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);
}
19 changes: 19 additions & 0 deletions TimerResolutionMeasure/utils.h
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);

0 comments on commit ba7ee0f

Please sign in to comment.