From 8b9e1a38cb280b7f3b7d9c6042efc48caef97824 Mon Sep 17 00:00:00 2001 From: Hane Date: Fri, 21 Jul 2023 22:39:43 +0200 Subject: [PATCH] sketch. time to thread --- src/main.cpp | 9 +- src/tmrtsc.hpp | 233 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/tmrtsc.hpp diff --git a/src/main.cpp b/src/main.cpp index 087209a..fadb30e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,10 @@ +/* + * THREADIN THE LINUS: https://linux.die.net/man/2/sched_setaffinity + */ +/* + *THREADIN THE WINDOS: https://learn.microsoft.com/en-us/windows/win32/procthread/process-and-thread-functions + */ + //clangbug: https://bugs.llvm.org/show_bug.cgi?id=24232 //tsc synced across cpu intel: https://community.intel.com/t5/Software-Tuning-Performance/TSCs-per-logical-processor-Per-socket/m-p/1121318 //lfence: https://hadibrais.wordpress.com/2018/05/14/the-significance-of-the-x86-lfence-instruction/ @@ -28,7 +35,7 @@ Intel(R) 64 and IA-32 Architectures Software Developer's Manual Volume 3 (3A, 3B #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT _WIN32_WINNT_WIN10 //0x0A00 #define MAX_KEY_LENGTH 255 - #define MAX_VALUE_NAME 32768 + #define MAX_VALUE_NAME 32767 #include #include #include diff --git a/src/tmrtsc.hpp b/src/tmrtsc.hpp new file mode 100644 index 0000000..6ff7632 --- /dev/null +++ b/src/tmrtsc.hpp @@ -0,0 +1,233 @@ +//TODO It's threadin' time + +#ifdef _WIN64 + //TODO mirame esta + #ifndef DEBUG + #define DEBUG + #endif + #define UNICODE + #define WIN32_LEAN_AND_MEAN + #define _WIN32_WINNT _WIN32_WINNT_WIN10 //0x0A00 + #define MAX_KEY_LENGTH 255 + #define MAX_VALUE_NAME 32767 + #include + #include + #include + #include +#endif + +#include +#include +#include "debug.h" + +namespace tmr { + + #ifdef _WIN64 + enum winReturnValues{ + CANT_OPEN_KEY = -1, + CANT_RETRIEVE_KEY_INFO = -2, + CANT_READ_DATA_FROM_VALUE = -3, + CANT_RETRIEVE_FREQUENCY = -4 + }; + #endif + enum ReturnValues { + OPERATION_SUCCESSFUL = 0, + INVARIANT_TSC_NOT_AVAILABLE = -1, + UNSUPPORTED_CPU = -2, + CANT_READ_FREQUENCY_FROM_SYSTEM = -3, + ART_NOT_REPORTED = -4 + }; + + class TSCTimer { + + private: + static TSCTimer timer; + static char* vendorName; + static int64_t baseFreq = ART_NOT_REPORTED; + + bool availableRDTSCP; + int64_t art; //reserved + + TSCtimer () { + availableRDTSCP = (checkRDTSCP()) ? true : false; + } + + #ifdef _WIN64 + + 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; + } + + #endif + + 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; + } + + 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; + } + + 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; + } + + int64_t intelCheckART(){ + //TODO: Find a valid Intel CPU to debug ART route + //if (freq == nullptr) return - + + uint64_t 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 << " " << *freq); + return TSCFreq; + } + + 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 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; //| + } + + public: + static int getTimer(TSCTimer* timer = nullptr) { + if (!checkInvariantTSC) return INVARIANT_TSC_NOT_SUPPORTED; + + const char vendorNames[2][13] = { + {"AuthenticAMD\0"}, + {"GenuineIntel\0"} + }; + vendorName = readVendorName(); + + 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(); + return OPERATION_SUCCESSFUL; + } + + uint64_t getTimeStamp(){ + if (availableRDTSCP) + return readRDTSCP(); + else + return readRDTSC(); + } + + } +}