From 14b4d72d8aae8aaac2b6bdd3eb8238635fe96f56 Mon Sep 17 00:00:00 2001 From: Hane Date: Mon, 24 Jul 2023 20:00:22 +0200 Subject: [PATCH] how do u mix da heat --- buildlib.bat | 2 +- buildtest.bat | 3 + src/test/test.cpp | 41 +++++++++ src/tmrtsc.cpp | 207 +++++++++++++++++++++++++++++++++++++++++++ src/tmrtsc.hpp | 218 ++++++---------------------------------------- 5 files changed, 280 insertions(+), 191 deletions(-) create mode 100644 buildtest.bat create mode 100644 src/test/test.cpp create mode 100644 src/tmrtsc.cpp diff --git a/buildlib.bat b/buildlib.bat index 9397441..38e72f6 100644 --- a/buildlib.bat +++ b/buildlib.bat @@ -1 +1 @@ -clang++ -D DEBUG src\tmrtsc.hpp -Wall -Wextra -Wpedantic -std=c++11 -g -gcodeview -Wl,-pdb= -L C:\capybara\libclang\x86_64-w64-mingw32\bin -l c++ -l unwind --verbose +clang++ -DDEBUG -shared src\tmrtsc.cpp -o build\libtmrtsc.dll -Wall -Wextra -Wpedantic -std=c++11 -g -gcodeview -Wl,-pdb= -L C:\capybara\libclang\x86_64-w64-mingw32\bin -l c++ -l unwind --verbose diff --git a/buildtest.bat b/buildtest.bat new file mode 100644 index 0000000..b2222a0 --- /dev/null +++ b/buildtest.bat @@ -0,0 +1,3 @@ +clang++ src\test\test.cpp -o build\test.exe -Wall -Wextra -Wpedantic -std=c++11 -g -gcodeview -Wl,-pdb= -L C:\capybara\libclang\x86_64-w64-mingw32\bin -l c++ -l unwind -L D:\Contenido\Capybara\Cositas\tmr\build -l tmrtsc --verbose + +REM -fms-runtime-lib dll_dbg diff --git a/src/test/test.cpp b/src/test/test.cpp new file mode 100644 index 0000000..0c0152e --- /dev/null +++ b/src/test/test.cpp @@ -0,0 +1,41 @@ +#ifdef _WIN64 + #define UNICODE + #define WIN32_LEAN_AND_MEAN + //#define DllImport __declspec( dllimport ) + #include + #include +#endif + +#include "../debug.h" +#include "../tmrtsc.hpp" + +using namespace tmr; + +#ifdef _WIN64 +int main(int argc, char** argv){ + HMODULE dell; + DWORD fracaso; + int sleep = 1000; + + dell = LoadLibraryExW(TEXT("libtmrtsc.dll"), NULL, NULL); + if (dell == NULL) { + fracaso = GetLastError(); + return -1; + } + TSCTimer* timer = nullptr; + fracaso = TSCTimer::getTimer(timer); + if(fracaso != OPERATION_SUCCESSFUL) + return -2; + uint64_t t1 = timer->getTimeStamp(); + Sleep(sleep); + uint64_t t2 = timer->getTimeStamp(); + uint64_t fr = timer->getBaseFrequency(); + std::cout << "Windows Momento: \nt1: " << t1 << " t2: " << " fr: " << fr << std::endl; + return 0; +} + +#else +int main(int argc, char** argv){ + return -9; +} +#endif diff --git a/src/tmrtsc.cpp b/src/tmrtsc.cpp new file mode 100644 index 0000000..054611d --- /dev/null +++ b/src/tmrtsc.cpp @@ -0,0 +1,207 @@ +#include "tmrtsc.hpp" + +#if _WIN64 + extern "C" { +#endif + +namespace tmr { + + TSCTimer::TSCTimer(char* vendorName, int64_t baseFreq) { + this->vendorName = vendorName; + this->baseFreq = baseFreq; + this->availableRDTSCP = (checkRDTSCP()) ? true : false; + } + + TSCTimer::~TSCTimer () { + free(vendorName); + } + + bool TSCTimer::checkInvariantTSC() { + uint64_t rdx; + asm volatile (".intel_syntax noprefix\t\n" \ + "mov eax, 0x80000007\t\n" \ + "cpuid\t\n" : "=d" (rdx) ); + bool iTSC = rdx & (1<<8); + return iTSC; + } + + + char* TSCTimer::readVendorName () { + char* palabritas = (char*)malloc(sizeof(char) * 13); + uint8_t siguienteLetra = 0; + uint64_t regs[3]; + asm volatile ( ".intel_syntax noprefix\t\n" \ + "mov eax, 0x0\t\n" \ + "cpuid\t\n" : "=b" (regs[0]), "=c" (regs[2]), "=d" (regs[1]) ); + int byte = 0; + for (int reg = 0; reg < 3; reg++, byte = 0){ + char* charifiedReg = (char*)®s[reg]; + for(; byte < 4; byte++, siguienteLetra++ ){ + palabritas[siguienteLetra] = charifiedReg[byte]; + } + } + palabritas[siguienteLetra] = '\0'; + return palabritas; + } + + int64_t TSCTimer::intelRetrieveART(){ + //TODO: Find a valid Intel CPU to debug ART route + //if (freq == nullptr) return - + + uint64_t raxde, rbxnum, rcxhz; + asm volatile ( ".intel_syntax noprefix\t\n" \ + "mov eax, 0x15\t\n" \ + "cpuid\t\n" : "=a" (raxde), "=b" (rbxnum), "=c" (rcxhz) ); + log_debugcpp("hmm " << raxde << " " << rbxnum << " " << rcxhz); + if (rbxnum == 0 || rcxhz == 0) return ART_NOT_REPORTED; + int64_t TSCFreq = (rcxhz * rbxnum)/raxde; + //*freq = TSCFreq; + log_debugcpp("raxo " << TSCFreq << " " << TSCFreq); + return TSCFreq; + } + + #ifdef _WIN64 + + int64_t TSCTimer::getFreqFromSystem(){ + //TODO: close opened key + const WORD STRING_SIZE = 4; + const WCHAR COMPARE_TARGET[STRING_SIZE + 1] = L"~MHz"; + DWORD longestDataSize; + + LSTATUS status; + HKEY key; + DWORD numValues; + + WCHAR valName[MAX_VALUE_NAME]; //uint32_t wtf + DWORD valLen = MAX_VALUE_NAME; + + LPBYTE dataContent = nullptr; + DWORD dataLen; + + status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, + KEY_QUERY_VALUE, &key); + if(status != ERROR_SUCCESS) return CANT_OPEN_KEY; + + status = RegQueryInfoKey( + key, // key handle + NULL, // buffer for class name + NULL, // size of class string + NULL, // reserved + NULL, // num of subkeys + NULL, // longest subkey size + NULL, // longest class string + &numValues, // num of values for this key + NULL, // longest value name + &longestDataSize, // longest value data + NULL, // security descriptor + NULL); // last write time + if(status != ERROR_SUCCESS) return CANT_RETRIEVE_KEY_INFO; + + dataLen = sizeof(REG_QWORD) * (longestDataSize); + dataContent = (LPBYTE)malloc(dataLen); + for (DWORD i = 0; i < numValues; i++){ + valLen = MAX_VALUE_NAME; + dataLen = sizeof(REG_QWORD) * (longestDataSize); + status = RegEnumValueW(key, + i, + valName, + &valLen, + NULL, + NULL, + dataContent, + &dataLen + ); + + if(status != ERROR_SUCCESS) return CANT_READ_DATA_FROM_VALUE; + + if (CSTR_EQUAL == CompareStringEx( + LOCALE_NAME_INVARIANT, + NORM_LINGUISTIC_CASING, + valName, + valLen, + COMPARE_TARGET, + STRING_SIZE, + NULL, + NULL, + 0 + ) + ) { + LPDWORD PMHz = (LPDWORD)dataContent; + DWORD MHz = *PMHz; + free(dataContent); + return MHz * 1000000; + } + } + return CANT_READ_DATA_FROM_VALUE; + } + + #endif + + bool TSCTimer::checkRDTSCP(){ //Generic + uint64_t rdx; + asm volatile (".intel_syntax noprefix\t\n" \ + "mov eax, 0x80000001\t\n" \ + // 080000007h\t\n" + "cpuid\t\n" : "=d" (rdx) ); + bool RDTSCP = rdx & (1<<27); + //"and edx, 10000000\n") + return RDTSCP; + } + + uint64_t TSCTimer::readRDTSC() { + uint64_t raxlo,rdxho; + asm volatile ( ".intel_syntax noprefix\t\n" + "lfence\n" \ + "rdtsc\n" \ + "lfence\n" : "=a" (raxlo), "=d" (rdxho)); + return (rdxho << 32) + raxlo; //| + } + + uint64_t TSCTimer::readRDTSCP(uint64_t* logicore) { + uint64_t raxlo,rdxho, rcx; + asm volatile ( ".intel_syntax noprefix\t\n" + "rdtscp\t\n" + "lfence\t\n": "=a" (raxlo), "=d" (rdxho), "=c" (rcx) ); + if (logicore != nullptr) *logicore = rcx; + return (rdxho << 32) + raxlo; //| + } + + int TSCTimer::getTimer(TSCTimer* timer) { + if (!checkInvariantTSC()) return INVARIANT_TSC_NOT_SUPPORTED; + //TODO debug dis + const char vendorNames[2][13] = { + {"AuthenticAMD"}, + {"GenuineIntel"} + }; + char* vendorName = readVendorName(); + int64_t baseFreq; + + if (strcmp(vendorName, vendorNames[1])) + baseFreq = intelRetrieveART(); + if (baseFreq == ART_NOT_REPORTED) + baseFreq = getFreqFromSystem(); + if (baseFreq < OPERATION_SUCCESSFUL) + return CANT_READ_FREQUENCY_FROM_SYSTEM; + + timer = new TSCTimer(vendorName, baseFreq); + return OPERATION_SUCCESSFUL; + } + + uint64_t TSCTimer::getTimeStamp(){ + if (availableRDTSCP) + return readRDTSCP(); + else + return readRDTSC(); + } + + uint64_t TSCTimer::getBaseFrequency(){ + return baseFreq; + } + +} + + +#ifdef _WIN64 +} +#endif + diff --git a/src/tmrtsc.hpp b/src/tmrtsc.hpp index 051e85c..3c07bca 100644 --- a/src/tmrtsc.hpp +++ b/src/tmrtsc.hpp @@ -1,4 +1,5 @@ //TODO It's threadin' time +#pragma once #ifdef _WIN64 #define LIB_EXPORT __declspec(dllexport) @@ -20,22 +21,22 @@ #include #include "debug.h" -/* - * #if _WIN64 - * extern "C" {) - * #endif - */ + +#if _WIN64 + extern "C" { +#endif + namespace tmr { #ifdef _WIN64 - enum LIB_EXPORT winReturnValues{ + enum winReturnValues{ CANT_OPEN_KEY = -1, CANT_RETRIEVE_KEY_INFO = -2, CANT_READ_DATA_FROM_VALUE = -3, CANT_RETRIEVE_FREQUENCY = -4 }; #endif - enum LIB_EXPORT ReturnValues { + enum ReturnValues { OPERATION_SUCCESSFUL = 0, INVARIANT_TSC_NOT_SUPPORTED = -1, UNSUPPORTED_CPU = -2, @@ -46,211 +47,48 @@ namespace tmr { class LIB_EXPORT TSCTimer { private: - static TSCTimer timer; + //static TSCTimer timer; char* vendorName; int64_t baseFreq = ART_NOT_REPORTED; - bool availableRDTSCP; + bool availableRDTSCP = false; int64_t art; //reserved - TSCTimer (char* vendorName, int64_t baseFreq) { - this->vendorName = vendorName; - this->baseFreq = baseFreq; - availableRDTSCP = (checkRDTSCP()) ? true : false; - } + TSCTimer(char* vendorName, int64_t baseFreq); - ~TSCTimer () { - free(vendorName); - } + ~TSCTimer(); - static bool checkInvariantTSC() { - uint64_t rdx; - asm volatile (".intel_syntax noprefix\t\n" \ - "mov eax, 0x80000007\t\n" \ - "cpuid\t\n" : "=d" (rdx) ); - bool iTSC = rdx & (1<<8); - return iTSC; - } + static bool checkInvariantTSC(); - - static char* readVendorName () { - char* palabritas = (char*)malloc(sizeof(char) * 13); - uint8_t siguienteLetra = 0; - uint64_t regs[3]; - asm volatile ( ".intel_syntax noprefix\t\n" \ - "mov eax, 0x0\t\n" \ - "cpuid\t\n" : "=b" (regs[0]), "=c" (regs[2]), "=d" (regs[1]) ); - int byte = 0; - for (int reg = 0; reg < 3; reg++, byte = 0){ - char* charifiedReg = (char*)®s[reg]; - for(; byte < 4; byte++, siguienteLetra++ ){ - palabritas[siguienteLetra] = charifiedReg[byte]; - } - } - palabritas[siguienteLetra] = '\0'; - return palabritas; - } + static char* readVendorName (); - static int64_t intelRetrieveART(){ - //TODO: Find a valid Intel CPU to debug ART route - //if (freq == nullptr) return - - - uint64_t raxde, rbxnum, rcxhz; - asm volatile ( ".intel_syntax noprefix\t\n" \ - "mov eax, 0x15\t\n" \ - "cpuid\t\n" : "=a" (raxde), "=b" (rbxnum), "=c" (rcxhz) ); - log_debugcpp("hmm " << raxde << " " << rbxnum << " " << rcxhz); - if (rbxnum == 0 || rcxhz == 0) return ART_NOT_REPORTED; - int64_t TSCFreq = (rcxhz * rbxnum)/raxde; - //*freq = TSCFreq; - log_debugcpp("raxo " << TSCFreq << " " << TSCFreq); - return TSCFreq; - } + static int64_t intelRetrieveART(); #ifdef _WIN64 - static int64_t getFreqFromSystem(){ - //TODO: close opened key - const WORD STRING_SIZE = 4; - const WCHAR COMPARE_TARGET[STRING_SIZE + 1] = L"~MHz"; - DWORD longestDataSize; - - LSTATUS status; - HKEY key; - DWORD numValues; - - WCHAR valName[MAX_VALUE_NAME]; //uint32_t wtf - DWORD valLen = MAX_VALUE_NAME; - - LPBYTE dataContent = nullptr; - DWORD dataLen; - - status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, - KEY_QUERY_VALUE, &key); - if(status != ERROR_SUCCESS) return CANT_OPEN_KEY; - - status = RegQueryInfoKey( - key, // key handle - NULL, // buffer for class name - NULL, // size of class string - NULL, // reserved - NULL, // num of subkeys - NULL, // longest subkey size - NULL, // longest class string - &numValues, // num of values for this key - NULL, // longest value name - &longestDataSize, // longest value data - NULL, // security descriptor - NULL); // last write time - if(status != ERROR_SUCCESS) return CANT_RETRIEVE_KEY_INFO; - - dataLen = sizeof(REG_QWORD) * (longestDataSize); - dataContent = (LPBYTE)malloc(dataLen); - for (DWORD i = 0; i < numValues; i++){ - valLen = MAX_VALUE_NAME; - dataLen = sizeof(REG_QWORD) * (longestDataSize); - status = RegEnumValueW(key, - i, - valName, - &valLen, - NULL, - NULL, - dataContent, - &dataLen - ); - - if(status != ERROR_SUCCESS) return CANT_READ_DATA_FROM_VALUE; - - if (CSTR_EQUAL == CompareStringEx( - LOCALE_NAME_INVARIANT, - NORM_LINGUISTIC_CASING, - valName, - valLen, - COMPARE_TARGET, - STRING_SIZE, - NULL, - NULL, - 0 - ) - ) { - LPDWORD PMHz = (LPDWORD)dataContent; - DWORD MHz = *PMHz; - free(dataContent); - return MHz * 1000000; - } - } - return CANT_READ_DATA_FROM_VALUE; - } + static int64_t getFreqFromSystem(); #endif - bool checkRDTSCP(){ //Generic - uint64_t rdx; - asm volatile (".intel_syntax noprefix\t\n" \ - "mov eax, 0x80000001\t\n" \ - // 080000007h\t\n" - "cpuid\t\n" : "=d" (rdx) ); - bool RDTSCP = rdx & (1<<27); - //"and edx, 10000000\n") - return RDTSCP; - } + bool checkRDTSCP(); - uint64_t readRDTSC() { - uint64_t raxlo,rdxho; - asm volatile ( ".intel_syntax noprefix\t\n" - "lfence\n" \ - "rdtsc\n" \ - "lfence\n" : "=a" (raxlo), "=d" (rdxho)); - return (rdxho << 32) + raxlo; //| - } + uint64_t readRDTSC(); - uint64_t readRDTSCP(uint64_t* logicore = nullptr ) { - uint64_t raxlo,rdxho, rcx; - asm volatile ( ".intel_syntax noprefix\t\n" - "rdtscp\t\n" - "lfence\t\n": "=a" (raxlo), "=d" (rdxho), "=c" (rcx) ); - if (logicore != nullptr) *logicore = rcx; - return (rdxho << 32) + raxlo; //| - } + uint64_t readRDTSCP(uint64_t* logicore = nullptr ); public: - static int getTimer(TSCTimer* timer = nullptr) { - if (!checkInvariantTSC()) return INVARIANT_TSC_NOT_SUPPORTED; - //TODO debug dis - const char vendorNames[2][13] = { - {"AuthenticAMD"}, - {"GenuineIntel"} - }; - char* vendorName = readVendorName(); - int64_t baseFreq; - - if (strcmp(vendorName, vendorNames[1])) - baseFreq = intelRetrieveART(); - if (baseFreq == ART_NOT_REPORTED) - baseFreq = getFreqFromSystem(); - if (baseFreq < OPERATION_SUCCESSFUL) - return CANT_READ_FREQUENCY_FROM_SYSTEM; + static int getTimer(TSCTimer* timer = nullptr); - timer = new TSCTimer(vendorName, baseFreq); - return OPERATION_SUCCESSFUL; - } + uint64_t getTimeStamp(); - uint64_t getTimeStamp(){ - if (availableRDTSCP) - return readRDTSCP(); - else - return readRDTSC(); - } - - uint64_t getBaseFrequency(){ - return baseFreq; - } + uint64_t getBaseFrequency(); + }; } -/* - * #ifdef _WIN64 - * } - * #endif - */ + +#ifdef _WIN64 +} +#endif +