Path: blob/a-new-beginning/SharedDependencies/Sources/microprofile/microprofile.cpp
2 views
#define MICROPROFILE_IMPL1#include "microprofile.h"2#if MICROPROFILE_ENABLED34#define BREAK_SKIP() __builtin_trap()56#ifdef _WIN327#if !defined(WIN32_LEAN_AND_MEAN)8#define WIN32_LEAN_AND_MEAN9#endif10#include <malloc.h>11#endif1213#ifdef _WIN3214#define MICROPROFILE_MAX_PATH MAX_PATH15#else16#define MICROPROFILE_MAX_PATH 102417#endif1819#include <atomic>20#include <ctype.h>21#include <mutex>22#include <stdarg.h>23#include <stdio.h>24#include <string.h>25#include <thread>2627#if defined(MICROPROFILE_SYSTEM_STB)28#include <stb_sprintf.h>29#else30#define STB_SPRINTF_IMPLEMENTATION31#include "stb_sprintf.h"32#endif3334#if defined(_WIN32) && _MSC_VER == 170035#define PRIx64 "llx"36#define PRIu64 "llu"37#define PRId64 "lld"38#else39#include <inttypes.h>40#endif4142#define MICROPROFILE_MAX_COUNTERS 51243#define MICROPROFILE_MAX_COUNTER_NAME_CHARS (MICROPROFILE_MAX_COUNTERS * 16)44#define MICROPROFILE_MAX_GROUP_INTS (MICROPROFILE_MAX_GROUPS / 32)45#define MICROPROFILE_MAX_CATEGORIES 1646#define MICROPROFILE_MAX_GRAPHS 547#define MICROPROFILE_GRAPH_HISTORY 12848#define MICROPROFILE_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_BUFFER_SIZE) / sizeof(MicroProfileLogEntry))49#define MICROPROFILE_GPU_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_GPU_BUFFER_SIZE) / sizeof(MicroProfileLogEntry))50#define MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS 25651#define MICROPROFILE_WEBSOCKET_BUFFER_SIZE (64 << 10)52#define MICROPROFILE_INVALID_TICK ((uint64_t) - 1)53#define MICROPROFILE_DROPPED_TICK ((uint64_t) - 2)54#define MICROPROFILE_INVALID_FRAME ((uint32_t) - 1)55#define MICROPROFILE_GROUP_MASK_ALL 0xffffffff56#define MICROPROFILE_MAX_PATCH_ERRORS 3257#define MICROPROFILE_MAX_MODULE_EXEC_REGIONS 165859#define MP_LOG_TICK_MASK 0x0000ffffffffffff60#define MP_LOG_INDEX_MASK 0x3fff00000000000061#define MP_LOG_BEGIN_MASK 0xc00000000000000062#define MP_LOG_CSTR_MASK 0xe00000000000000063#define MP_LOG_CSTR_BIT 0x200000000000000064#define MP_LOG_PAYLOAD_PTR_MASK (~(MP_LOG_BEGIN_MASK | MP_LOG_CSTR_BIT))6566#define MP_LOG_ENTER_LEAVE_MASK 0x80000000000000006768#define MP_LOG_LEAVE 0x069#define MP_LOG_ENTER 0x170#define MP_LOG_EXTENDED 0x271#define MP_LOG_EXTENDED_NO_DATA 0x37273#ifndef MICROPROFILE_SETTINGS_FILE74#define MICROPROFILE_SETTINGS_FILE "mppresets.cfg"75#endif76#ifndef MICROPROFILE_SETTINGS_FILE_BUILTIN77#define MICROPROFILE_SETTINGS_FILE_BUILTIN "mppresets.builtin.cfg"78#endif79#ifndef MICROPROFILE_SETTINGS_FILE_TEMP80#define MICROPROFILE_SETTINGS_FILE_TEMP ".tmp"81#endif8283// #define MP_LOG_EXTRA_DATA 0x38485static_assert(0 == (MICROPROFILE_MAX_GROUPS % 32), "MICROPROFILE_MAX_GROUPS must be divisible by 32");8687enum EMicroProfileTokenExtended88{89ETOKEN_GPU_CPU_TIMESTAMP = 0x3fff,90ETOKEN_GPU_CPU_SOURCE_THREAD = 0x3ffe,91ETOKEN_META_MARKER = 0x3ffd,92ETOKEN_CUSTOM_NAME = 0x3ffc,93ETOKEN_CUSTOM_COLOR = 0x3ffb,94ETOKEN_CUSTOM_ID = 0x3ffa,95ETOKEN_CSTR_PTR = 0x2000, // note, matches MP_LOG_CSTR_BIT96ETOKEN_MAX = 0x2000,97};9899enum100{101MICROPROFILE_WEBSOCKET_DIRTY_MENU,102MICROPROFILE_WEBSOCKET_DIRTY_ENABLED,103};104105#ifndef MICROPROFILE_ALLOC // redefine all if overriding106#define MICROPROFILE_ALLOC(nSize, nAlign) MicroProfileAllocAligned(nSize, nAlign);107#define MICROPROFILE_REALLOC(p, s) realloc(p, s)108#define MICROPROFILE_FREE(p) MicroProfileFreeAligned(p)109#define MICROPROFILE_FREE_NON_ALIGNED(p) free(p)110#endif111112#define MP_ALLOC(nSize, nAlign) MicroProfileAllocInternal(nSize, nAlign)113#define MP_REALLOC(p, s) MicroProfileReallocInternal(p, s)114#define MP_FREE(p) MicroProfileFreeInternal(p)115#define MP_ALLOC_OBJECT(T) (T*)MP_ALLOC(sizeof(T), alignof(T))116#define MP_ALLOC_OBJECT_ARRAY(T, Count) (T*)MP_ALLOC(sizeof(T) * Count, alignof(T))117118#ifndef MICROPROFILE_DEBUG119#define MICROPROFILE_DEBUG 0120#endif121122typedef uint64_t MicroProfileLogEntry;123124void MicroProfileSleep(uint32_t nMs);125template <typename T>126T MicroProfileMin(T a, T b);127template <typename T>128T MicroProfileMax(T a, T b);129template <typename T>130T MicroProfileClamp(T a, T min_, T max_);131int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond);132float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond);133uint32_t MicroProfileLogGetType(MicroProfileLogEntry Index);134uint64_t MicroProfileLogGetTimerIndex(MicroProfileLogEntry Index);135MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick);136int64_t MicroProfileLogTickDifference(MicroProfileLogEntry Start, MicroProfileLogEntry End);137int64_t MicroProfileLogSetTick(MicroProfileLogEntry e, int64_t nTick);138uint16_t MicroProfileGetTimerIndex(MicroProfileToken t);139uint32_t MicroProfileGetGroupMask(MicroProfileToken t);140MicroProfileToken MicroProfileMakeToken(uint64_t nGroupMask, uint32_t nGroupIndex, uint16_t nTimer);141bool MicroProfileAnyGroupActive();142void MicroProfileWriteFile(void* Handle, size_t nSize, const char* pData);143144// defer implementation145#define CONCAT_INTERNAL(x, y) x##y146#define CONCAT(x, y) CONCAT_INTERNAL(x, y)147void IntentionallyNotDefinedFunction__(); // DO NOT DEFINE THIS148template <typename T>149struct MicroProfileExitScope150{151T lambda;152MicroProfileExitScope(T lambda)153: lambda(lambda)154{155}156~MicroProfileExitScope()157{158lambda();159}160161MicroProfileExitScope(const MicroProfileExitScope& rhs)162: lambda(rhs.lambda)163{164IntentionallyNotDefinedFunction__(); // this is here to ensure the compiler does not create duplicate copies165}166167private:168MicroProfileExitScope& operator=(const MicroProfileExitScope&);169};170171class MicroProfileExitScopeHelp172{173public:174template <typename T>175MicroProfileExitScope<T> operator+(T t)176{177return t;178}179};180#define defer const auto& CONCAT(defer__, __LINE__) = MicroProfileExitScopeHelp() + [&]()181182//////////////////////////////////////////////////////////////////////////183// platform IMPL184void* MicroProfileAllocInternal(size_t nSize, size_t nAlign);185void MicroProfileFreeInternal(void* pPtr);186void* MicroProfileReallocInternal(void* pPtr, size_t nSize);187188void* MicroProfileAllocAligned(size_t nSize, size_t nAlign);189void MicroProfileFreeAligned(void* pMem);190191#if defined(__APPLE__)192#include <TargetConditionals.h>193#include <float.h>194#include <libkern/OSAtomic.h>195#include <mach/mach.h>196#include <mach/mach_time.h>197#include <unistd.h>198199#if TARGET_OS_IPHONE200#define MICROPROFILE_IOS201#endif202203#define MP_TICK() mach_absolute_time()204inline int64_t MicroProfileTicksPerSecondCpu_()205{206static int64_t nTicksPerSecond = 0;207if(nTicksPerSecond == 0)208{209mach_timebase_info_data_t sTimebaseInfo;210mach_timebase_info(&sTimebaseInfo);211nTicksPerSecond = 1000000000ll * sTimebaseInfo.denom / sTimebaseInfo.numer;212}213return nTicksPerSecond;214}215216int64_t MicroProfileTicksPerSecondCpu()217{218return MicroProfileTicksPerSecondCpu_();219}220#define MicroProfileTicksPerSecondCpu MicroProfileTicksPerSecondCpu_221222inline uint64_t MicroProfileGetCurrentThreadId()223{224uint64_t tid;225pthread_threadid_np(pthread_self(), &tid);226return tid;227}228229#include <stdlib.h>230231#define MP_BREAK() __builtin_trap()232#define MP_THREAD_LOCAL __thread233#define MP_STRCASECMP strcasecmp234#define MP_GETCURRENTTHREADID() MicroProfileGetCurrentThreadId()235#define MP_STRCASESTR strcasestr236#define MP_THREAD_LOCAL __thread237#define MP_NOINLINE __attribute__((noinline))238239void* MicroProfileAllocAligned(size_t nSize, size_t nAlign)240{241void* p;242int result = posix_memalign(&p, nAlign, nSize);243if(result != 0)244{245return nullptr;246}247return p;248}249250void MicroProfileFreeAligned(void* pMem)251{252free(pMem);253}254255#elif defined(_WIN32)256#include <Shlwapi.h>257#include <winsock2.h>258#include <ws2tcpip.h>259int64_t MicroProfileGetTick();260#define MP_TICK() MicroProfileGetTick()261#define MP_BREAK() __debugbreak()262#define MP_THREAD_LOCAL __declspec(thread)263#define MP_STRCASECMP _stricmp264#define MP_GETCURRENTTHREADID() GetCurrentThreadId()265#define MP_STRCASESTR StrStrI266#define MP_THREAD_LOCAL __declspec(thread)267#define MP_NOINLINE __declspec(noinline)268269#ifndef MICROPROFILE_WIN32_TRAP_ALLOCATOR270#define MICROPROFILE_WIN32_TRAP_ALLOCATOR 0271#endif272273#if MICROPROFILE_WIN32_TRAP_ALLOCATOR274// minimal trap allocator275#define PAGE_SIZE (4096)276void* MicroProfileAllocAligned(size_t nSize, size_t nAlign)277{278(void)nAlign;279size_t nAlignedSize = (nSize + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1));280size_t nDelta = nAlignedSize - nSize;281size_t nFullSize = nAlignedSize + 2 * PAGE_SIZE;282283void* ptr = VirtualAlloc(0, nFullSize, MEM_RESERVE, PAGE_READWRITE);284intptr_t intptr = (intptr_t)ptr;285286void* pResult = VirtualAlloc((void*)(intptr + PAGE_SIZE), nAlignedSize, MEM_COMMIT, PAGE_READWRITE);287memset(pResult, 0xf0, nAlignedSize);288289intptr_t page = (intptr_t)pResult;290//((char*)page)[-1] = 0x70; //trap test291page += nDelta;292pResult = (void*)page;293memset(pResult, 0xfe, nSize);294//((char*)page)[nSize] = 0x70; //trap test295return (void*)page;296}297298void MicroProfileFreeAligned(void* pMem)299{300intptr_t intptr = (intptr_t)pMem;301intptr = (intptr & (~(PAGE_SIZE - 1))) - PAGE_SIZE;302VirtualFree(pMem, 0, MEM_RELEASE);303}304#else305void* MicroProfileAllocAligned(size_t nSize, size_t nAlign)306{307return _aligned_malloc(nSize, nAlign);308}309310void MicroProfileFreeAligned(void* pMem)311{312_aligned_free(pMem);313}314#endif315316#else317318#ifndef MICROPROFILE_CUSTOM_PLATFORM319#include <float.h>320#include <malloc.h>321#include <stdlib.h>322#include <time.h>323#include <unistd.h>324325inline int64_t MicroProfileTicksPerSecondCpu_()326{327return 1000000000ll;328}329330int64_t MicroProfileTicksPerSecondCpu()331{332return MicroProfileTicksPerSecondCpu_();333}334#define MicroProfileTicksPerSecondCpu MicroProfileTicksPerSecondCpu_335336inline int64_t MicroProfileGetTick()337{338timespec ts;339clock_gettime(CLOCK_REALTIME, &ts);340return 1000000000ll * ts.tv_sec + ts.tv_nsec;341}342#define MP_TICK() MicroProfileGetTick()343#define MP_BREAK() __builtin_trap()344#define MP_THREAD_LOCAL __thread345#define MP_STRCASECMP strcasecmp346#define MP_GETCURRENTTHREADID() (uint64_t) pthread_self()347#define MP_STRCASESTR strcasestr348#define MP_THREAD_LOCAL __thread349#define MP_NOINLINE __attribute__((noinline))350351void* MicroProfileAllocAligned(size_t nSize, size_t nAlign)352{353#if defined(__linux__)354void* p;355int result = posix_memalign(&p, nAlign, nSize);356if(result != 0)357{358return nullptr;359}360return p;361#else362return memalign(nAlign, nSize);363#endif364}365void MicroProfileFreeAligned(void* pMem)366{367free(pMem);368}369#endif370371#endif372373#ifdef MICROPROFILE_PS4374#define MICROPROFILE_PS4_DECL375#include "microprofile_ps4.h"376#endif377378#ifdef MICROPROFILE_XBOXONE379#define MICROPROFILE_XBOXONE_DECL380#include "microprofile_xboxone.h"381#else382#ifdef _WIN32383#include <d3d11_1.h>384#endif385#endif386387#ifdef _WIN32388typedef uint32_t MicroProfileThreadIdType;389#else390#ifdef MICROPROFILE_THREADID_SIZE_4BYTE391typedef uint32_t MicroProfileThreadIdType;392#elif MICROPROFILE_THREADID_SIZE_8BYTE393typedef uint64_t MicroProfileThreadIdType;394#else395typedef uint64_t MicroProfileThreadIdType;396#endif397#endif398399#define MP_ASSERT(a) \400do \401{ \402if(!(a)) \403{ \404MP_BREAK(); \405} \406} while(0)407408#ifdef _WIN32409#include <basetsd.h>410typedef UINT_PTR MpSocket;411#else412typedef int MpSocket;413#endif414415#ifndef _WIN32416typedef pthread_t MicroProfileThread;417#elif defined(_WIN32)418#if _MSC_VER == 1900419typedef void* HANDLE;420#endif421422typedef HANDLE MicroProfileThread;423#else424typedef std::thread* MicroProfileThread;425#endif426427#if MICROPROFILE_DYNAMIC_INSTRUMENT428struct MicroProfileSymbolDesc;429430#define MICROPROFILE_SUSPEND_MAX (4 << 10)431struct MicroProfileSuspendState432{433uint32_t SuspendCounter = 0;434uint32_t NumSuspended = 0;435#ifdef _WIN32436HANDLE Suspended[MICROPROFILE_SUSPEND_MAX];437intptr_t SuspendedIP[MICROPROFILE_SUSPEND_MAX];438#endif439};440441void MicroProfileSymbolQueryFunctions(MpSocket Connection, const char* pFilter);442bool MicroProfileInstrumentFunction(void* pFunction, const char* pModuleName, const char* pFunctionName, uint32_t nColor);443bool MicroProfileSymbolInitialize(bool bStartLoad, const char* pModuleName = 0);444MicroProfileSymbolDesc* MicroProfileSymbolFindFuction(void* pAddress);445void MicroProfileInstrumentFunctionsCalled(void* pFunction, const char* pModuleName, const char* pFunctionName, int nMinBytes, int nMaxCalls);446void MicroProfileSymbolQuerySendResult(MpSocket Connection);447void MicroProfileSymbolSendFunctionNames(MpSocket Connection);448void MicroProfileSymbolSendErrors(MpSocket Connection);449const char* MicroProfileSymbolModuleGetString(uint32_t nIndex);450void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols);451void MicroProfileSymbolUpdateModuleList();452bool MicroProfileSymInit();453void MicroProfileSymCleanup();454#endif455456struct MicroProfileFunctionQuery;457458// hash table functions & declarations459struct MicroProfileHashTable;460struct MicroProfileHashTableIterator;461typedef bool (*MicroProfileHashCompareFunction)(uint64_t l, uint64_t r);462typedef uint64_t (*MicroProfileHashFunction)(uint64_t p);463uint64_t MicroProfileHashTableHashString(uint64_t pString);464bool MicroProfileHashTableCompareString(uint64_t L, uint64_t R);465uint64_t MicroProfileHashTableHashPtr(uint64_t pString);466bool MicroProfileHashTableComparePtr(uint64_t L, uint64_t R);467void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, uint32_t nSearchLimit, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc);468void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable);469uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K);470bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value);471MicroProfileHashTableIterator MicroProfileGetHashTableIteratorBegin(MicroProfileHashTable* HashTable);472MicroProfileHashTableIterator MicroProfileGetHashTableIteratorEnd(MicroProfileHashTable* HashTable);473474template <typename T>475struct MicroProfileArray476{477T* Data = nullptr;478uint32_t Size = 0;479uint32_t Capacity = 0;480T& operator[](const uint32_t Index);481const T& operator[](const uint32_t Index) const;482T* begin();483T* end();484};485486template <typename T>487void MicroProfileArrayInit(MicroProfileArray<T>& Array, uint32_t InitialCapacity);488template <typename T>489void MicroProfileArrayDestroy(MicroProfileArray<T>& Array, uint32_t InitialCapacity);490template <typename T>491void MicroProfileArrayClear(MicroProfileArray<T>& Array);492template <typename T>493void MicroProfileArrayPushBack(MicroProfileArray<T>& Array, const T& v);494495struct MicroProfileTimer496{497uint64_t nTicks;498uint32_t nCount;499};500501struct MicroProfileCategory502{503char pName[MICROPROFILE_NAME_MAX_LEN];504uint32_t nGroupMask[MICROPROFILE_MAX_GROUP_INTS];505};506507struct MicroProfileGroupInfo508{509char pName[MICROPROFILE_NAME_MAX_LEN];510uint32_t nNameLen;511uint32_t nGroupIndex;512uint32_t nNumTimers;513uint32_t nMaxTimerNameLen;514uint32_t nColor;515uint32_t nCategory;516MicroProfileTokenType Type;517int nWSNext;518};519520struct MicroProfileTimerInfo521{522MicroProfileToken nToken;523uint32_t nTimerIndex;524uint32_t nGroupIndex;525char pName[MICROPROFILE_NAME_MAX_LEN];526char pNameExt[MICROPROFILE_NAME_MAX_LEN];527uint32_t nNameLen;528uint32_t nColor;529int nWSNext;530bool bGraph;531MicroProfileTokenType Type;532uint32_t Flags;533};534535struct MicroProfileCounterInfo536{537int nParent;538int nSibling;539int nFirstChild;540uint16_t nNameLen;541uint8_t nLevel;542const char* pName;543uint32_t nFlags;544int64_t nLimit;545double dLimit;546int nWSNext;547MicroProfileCounterFormat eFormat;548std::atomic<int64_t> ExternalAtomic;549};550551struct MicroProfileCounterHistory552{553uint32_t nPut;554uint64_t nHistory[MICROPROFILE_GRAPH_HISTORY];555};556557struct MicroProfileCounterSource558{559void* pSource;560uint32_t nSourceSize;561};562563struct MicroProfileGraphState564{565int64_t nHistory[MICROPROFILE_GRAPH_HISTORY];566MicroProfileToken nToken;567int32_t nKey;568};569570struct MicroProfileContextSwitch571{572MicroProfileThreadIdType nThreadOut;573MicroProfileThreadIdType nThreadIn;574int64_t nCpu : 8;575int64_t nTicks : 56;576};577578struct MicroProfileFrameState579{580uint64_t nFrameStartCpu;581uint64_t nFrameStartGpu;582uint64_t nFrameId;583uint32_t nGpuPending;584uint32_t nLogStart[MICROPROFILE_MAX_THREADS];585uint32_t nLogStartTimeline;586uint32_t nTimelineFrameMax;587int32_t nHistoryTimeline;588};589590// All frame counter data stored. Used to store the time for all counters/groups for every frame.591// Must be enabled with MicroProfileEnableFrameCounterExtraData()592// Will allocate sizeof(MicroProfileFrameExtraCounterData) * MICROPROFILE_MAX_FRAME_HISTORY bytes593struct MicroProfileFrameExtraCounterData594{595uint16_t NumTimers;596uint16_t NumGroups;597uint64_t Timers[MICROPROFILE_MAX_TIMERS];598uint64_t Groups[MICROPROFILE_MAX_GROUPS];599};600601struct MicroProfileCsvConfig602{603enum CsvConfigState604{605INACTIVE = 0,606CONFIG,607ACTIVE,608};609CsvConfigState State;610uint32_t NumTimers;611uint32_t NumGroups;612uint32_t NumCounters;613uint32_t MaxTimers;614uint32_t MaxGroups;615uint32_t MaxCounters;616uint32_t TotalElements;617uint16_t* TimerIndices;618uint16_t* GroupIndices;619uint16_t* CounterIndices;620uint64_t* FrameData;621const char** pTimerNames;622const char** pGroupNames;623const char** pCounterNames;624uint32_t Flags;625};626627#ifdef _WIN32628#pragma warning(push)629#pragma warning(disable : 4200) // zero-sized struct630#pragma warning(disable : 4201) // nameless struct/union631#pragma warning(disable : 4244) // possible loss of data632#pragma warning(disable : 4100) // unreferenced formal parameter633#pragma warning(disable : 4091)634#pragma warning(disable : 4189) // local variable is initialized but not referenced. (for defer local variables)635#pragma warning(disable : 4456)636#pragma warning(disable : 4702)637#endif638639struct MicroProfileStringBlock640{641enum642{643DEFAULT_SIZE = 8192,644};645MicroProfileStringBlock* pNext;646uint32_t nUsed;647uint32_t nSize;648char Memory[];649};650651struct MicroProfileHashTableEntry652{653uint64_t Key;654uint64_t Hash;655uintptr_t Value;656};657658struct MicroProfileHashTable659{660MicroProfileHashTableEntry* pEntries;661uint32_t nUsed;662uint32_t nAllocated;663uint32_t nSearchLimit;664uint32_t nLim;665MicroProfileHashCompareFunction CompareFunc;666MicroProfileHashFunction HashFunc;667};668669struct MicroProfileHashTableIterator670{671MicroProfileHashTableIterator(uint32_t nIndex, MicroProfileHashTable* pTable)672: nIndex(nIndex)673, pTable(pTable)674{675}676MicroProfileHashTableIterator(const MicroProfileHashTableIterator& other)677: nIndex(other.nIndex)678, pTable(other.pTable)679{680}681682uint32_t nIndex;683MicroProfileHashTable* pTable;684685void AssertValid()686{687MP_ASSERT(nIndex < pTable->nAllocated);688}689690MicroProfileHashTableEntry& operator*()691{692AssertValid();693return pTable->pEntries[nIndex];694}695MicroProfileHashTableEntry* operator->()696{697AssertValid();698return &pTable->pEntries[nIndex];699}700bool operator==(const MicroProfileHashTableIterator& rhs)701{702return nIndex == rhs.nIndex && pTable == rhs.pTable;703}704bool operator!=(const MicroProfileHashTableIterator& rhs)705{706return nIndex != rhs.nIndex || pTable != rhs.pTable;707}708709void SkipInvalid()710{711while(nIndex < pTable->nAllocated && pTable->pEntries[nIndex].Hash == 0)712nIndex++;713}714MicroProfileHashTableIterator operator++()715{716AssertValid();717nIndex++;718SkipInvalid();719return *this;720}721MicroProfileHashTableIterator operator++(int)722{723MicroProfileHashTableIterator tmp = *this;724++(*this);725return tmp;726}727};728729struct MicroProfileStrings730{731MicroProfileHashTable HashTable;732MicroProfileStringBlock* pFirst;733MicroProfileStringBlock* pLast;734};735736struct MicroProfileThreadLog737{738739std::atomic<uint32_t> nPut;740std::atomic<uint32_t> nGet;741742MicroProfileLogEntry Log[MICROPROFILE_BUFFER_SIZE];743744uint32_t nStackPut;745uint32_t nStackScope;746#ifdef MICROPROFILE_VERIFY_BALANCED747uint64_t VerifyStack[MICROPROFILE_STACK_MAX];748#endif749MicroProfileScopeStateC ScopeState[MICROPROFILE_STACK_MAX];750751uint32_t nActive;752uint32_t nGpu;753MicroProfileThreadIdType nThreadId;754uint32_t nLogIndex;755uint32_t nCustomId;756uint32_t nIdleFrames;757758MicroProfileLogEntry nStackLogEntry[MICROPROFILE_STACK_MAX];759uint64_t nChildTickStack[MICROPROFILE_STACK_MAX + 1];760int32_t nStackPos;761762uint8_t nGroupStackPos[MICROPROFILE_MAX_GROUPS];763uint64_t nGroupTicks[MICROPROFILE_MAX_GROUPS];764uint64_t nAggregateGroupTicks[MICROPROFILE_MAX_GROUPS];765enum766{767THREAD_MAX_LEN = 64,768};769char ThreadName[64];770int nFreeListNext;771};772773struct MicroProfileWebSocketBuffer774{775char* pBufferAllocation;776char* pBuffer;777uint32_t nBufferSize;778uint32_t nPut;779MpSocket Socket;780781char SendBuffer[MICROPROFILE_WEBSOCKET_BUFFER_SIZE];782std::atomic<uint32_t> nSendPut;783std::atomic<uint32_t> nSendGet;784};785786typedef void (*MicroProfileHookFunc)(int x);787788struct MicroProfilePatchError789{790unsigned char Code[32];791char Message[256];792int AlreadyInstrumented;793int nCodeSize;794};795796// linear, per-frame per-thread gpu log797struct MicroProfileThreadLogGpu798{799MicroProfileLogEntry Log[MICROPROFILE_GPU_BUFFER_SIZE];800uint32_t nPut;801uint32_t nStart;802uint32_t nId;803void* pContext;804uint32_t nAllocated;805806uint32_t nStackScope;807MicroProfileScopeStateC ScopeState[MICROPROFILE_STACK_MAX];808};809810#if MICROPROFILE_GPU_TIMERS811static MicroProfileGpuInsertTimeStamp_CB MicroProfileGpuInsertTimeStamp_Callback = 0;812static MicroProfileGpuGetTimeStamp_CB MicroProfileGpuGetTimeStamp_Callback = 0;813static MicroProfileTicksPerSecondGpu_CB MicroProfileTicksPerSecondGpu_Callback = 0;814static MicroProfileGetGpuTickReference_CB MicroProfileGetGpuTickReference_Callback = 0;815static MicroProfileGpuFlip_CB MicroProfileGpuFlip_Callback = 0;816static MicroProfileGpuShutdown_CB MicroProfileGpuShutdown_Callback = 0;817818uint32_t MicroProfileGpuInsertTimeStamp(void* pContext)819{820return MicroProfileGpuInsertTimeStamp_Callback ? MicroProfileGpuInsertTimeStamp_Callback(pContext) : 0;821}822uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey)823{824return MicroProfileGpuGetTimeStamp_Callback ? MicroProfileGpuGetTimeStamp_Callback(nKey) : 1;825}826uint64_t MicroProfileTicksPerSecondGpu()827{828return MicroProfileTicksPerSecondGpu_Callback ? MicroProfileTicksPerSecondGpu_Callback() : 1;829}830int MicroProfileGetGpuTickReference(int64_t* pOutCPU, int64_t* pOutGpu)831{832return MicroProfileGetGpuTickReference_Callback ? MicroProfileGetGpuTickReference_Callback(pOutCPU, pOutGpu) : 0;833}834uint32_t MicroProfileGpuFlip(void* p)835{836return MicroProfileGpuFlip_Callback ? MicroProfileGpuFlip_Callback(p) : 0;837}838void MicroProfileGpuShutdown()839{840if(MicroProfileGpuShutdown_Callback)841MicroProfileGpuShutdown_Callback();842}843844#endif845846#if MICROPROFILE_GPU_TIMERS_D3D11847//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::::'##:::848//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####::::'####:::849// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##::::.. ##:::850// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##:::::: ##:::851// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::::: ##:::852// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##:::::: ##:::853//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######::'######:854//:......::::..::::::::::.......::::::........::::.......:::........::::......:::......::855856struct MicroProfileD3D11Frame857{858uint32_t m_nQueryStart;859uint32_t m_nQueryCountMax;860std::atomic<uint32_t> m_nQueryCount;861uint32_t m_nRateQueryStarted;862void* m_pRateQuery;863};864865struct MicroProfileGpuTimerStateD3D11 : public MicroProfileGpuTimerState866{867uint32_t bInitialized;868void* m_pDevice;869void* m_pImmediateContext;870void* m_pQueries[MICROPROFILE_D3D11_MAX_QUERIES];871int64_t m_nQueryResults[MICROPROFILE_D3D11_MAX_QUERIES];872873uint32_t m_nQueryPut;874uint32_t m_nQueryGet;875uint32_t m_nQueryFrame;876int64_t m_nQueryFrequency;877void* pSyncQuery;878879MicroProfileD3D11Frame m_QueryFrames[MICROPROFILE_GPU_FRAME_DELAY];880};881882uint32_t MicroProfileGpuInsertTimeStampD3D11(void* pContext_);883uint64_t MicroProfileGpuGetTimeStampD3D11(uint32_t nIndex);884bool MicroProfileGpuGetDataD3D11(void* pQuery, void* pData, uint32_t nDataSize);885uint64_t MicroProfileTicksPerSecondGpuD3D11();886uint32_t MicroProfileGpuFlipD3D11(void* pDeviceContext_);887void MicroProfileGpuInitD3D11(void* pDevice_, void* pImmediateContext);888void MicroProfileGpuShutdownD3D11();889int MicroProfileGetGpuTickReferenceD3D11(int64_t* pOutCPU, int64_t* pOutGpu);890MicroProfileGpuTimerStateD3D11* MicroProfileGetGpuTimerStateD3D11();891#endif892893#if MICROPROFILE_GPU_TIMERS_D3D12894//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::'#######::895//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####:::'##.... ##:896// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##:::..::::: ##:897// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##::::'#######::898// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::'##::::::::899// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##::: ##::::::::900//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######: #########:901//:......::::..::::::::::.......::::::........::::.......:::........::::......::.........::902903#include <d3d12.h>904905#ifndef MICROPROFILE_D3D12_MAX_QUERIES906#define MICROPROFILE_D3D12_MAX_QUERIES (32 << 10)907#endif908909#define MICROPROFILE_D3D_MAX_NODE_COUNT 4910#define MICROPROFILE_D3D_INTERNAL_DELAY 8911912#define MP_NODE_MASK_ALL(n) ((1u << (n)) - 1u)913#define MP_NODE_MASK_ONE(n) (1u << (n))914915struct MicroProfileGpuTimerStateD3D12;916917int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu);918uint32_t MicroProfileGpuInsertTimeStampD3D12(void* pContext);919uint64_t MicroProfileGpuGetTimeStampD3D12(uint32_t nIndex);920uint64_t MicroProfileTicksPerSecondGpuD3D12();921uint32_t MicroProfileGpuFlipD3D12(void* pContext);922void MicroProfileGpuInitD3D12(void* pDevice_, uint32_t nNodeCount, void** pCommandQueues_, void** pCommandQueuesCopy_);923void MicroProfileGpuShutdownD3D12();924void MicroProfileSetCurrentNodeD3D12(uint32_t nNode);925int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu);926MicroProfileGpuTimerStateD3D12* MicroProfileGetGpuTimerStateD3D12();927928struct MicroProfileFrameD3D12929{930uint32_t nTimeStampBegin;931uint32_t nTimeStampCount;932uint32_t nTimeStampBeginCopyQueue;933uint32_t nTimeStampCountCopyQueue;934uint32_t nNode;935ID3D12GraphicsCommandList* pCommandList[MICROPROFILE_D3D_MAX_NODE_COUNT];936ID3D12GraphicsCommandList* pCommandListCopy[MICROPROFILE_D3D_MAX_NODE_COUNT];937ID3D12CommandAllocator* pCommandAllocator;938ID3D12CommandAllocator* pCommandAllocatorCopy;939};940941struct MicroProfileGpuTimerStateD3D12 : public MicroProfileGpuTimerState942{943ID3D12Device* pDevice;944uint32_t nNodeCount;945uint32_t nCurrentNode;946947uint64_t nFrame;948uint64_t nPendingFrame;949950uint32_t nFrameStartTimeStamps;951uint32_t nFrameStartCopyQueueTimeStamps;952std::atomic<uint32_t> nFrameCountTimeStamps;953std::atomic<uint32_t> nFrameCountCopyQueueTimeStamps;954955int64_t nFrequency;956ID3D12Resource* pBuffer;957ID3D12Resource* pBufferCopy;958959struct960{961ID3D12CommandQueue* pCommandQueue;962ID3D12CommandQueue* pCommandQueueCopy;963ID3D12QueryHeap* pHeap;964ID3D12QueryHeap* pCopyQueueHeap;965ID3D12Fence* pFence;966ID3D12Fence* pFenceCopy;967} NodeState[MICROPROFILE_D3D_MAX_NODE_COUNT];968969uint16_t nQueryFrames[MICROPROFILE_D3D12_MAX_QUERIES];970int64_t nResults[MICROPROFILE_D3D12_MAX_QUERIES];971uint16_t nQueryFramesCopy[MICROPROFILE_D3D12_MAX_QUERIES];972int64_t nResultsCopy[MICROPROFILE_D3D12_MAX_QUERIES];973974MicroProfileFrameD3D12 Frames[MICROPROFILE_D3D_INTERNAL_DELAY];975};976#endif977978#if MICROPROFILE_GPU_TIMERS_GL979//:'######:::'########::'##::::'##:::::'######:::'##:::::::980//'##... ##:: ##.... ##: ##:::: ##::::'##... ##:: ##:::::::981// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::..::: ##:::::::982// ##::'####: ########:: ##:::: ##:::: ##::'####: ##:::::::983// ##::: ##:: ##.....::: ##:::: ##:::: ##::: ##:: ##:::::::984// ##::: ##:: ##:::::::: ##:::: ##:::: ##::: ##:: ##:::::::985//. ######::: ##::::::::. #######:::::. ######::: ########:986//:......::::..::::::::::.......:::::::......::::........::987struct MicroProfileGpuTimerStateGL : public MicroProfileGpuTimerState988{989uint32_t GLTimers[MICROPROFILE_GL_MAX_QUERIES];990uint32_t GLTimerPos;991};992993MicroProfileGpuTimerStateGL* MicroProfileGetGpuTimerStateGL();994uint32_t MicroProfileGpuInsertTimeStampGL(void* pContext);995uint64_t MicroProfileGpuGetTimeStampGL(uint32_t nKey);996uint64_t MicroProfileTicksPerSecondGpuGL();997int MicroProfileGetGpuTickReferenceGL(int64_t* pOutCpu, int64_t* pOutGpu);998uint32_t MicroProfileGpuFlipGL(void* pContext);999void MicroProfileGpuShutdownGL();1000#endif10011002#if MICROPROFILE_GPU_TIMERS_VULKAN10031004//:'######:::'########::'##::::'##::::'##::::'##:'##::::'##:'##:::::::'##:::'##::::'###::::'##::: ##:1005//'##... ##:: ##.... ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##::'##::::'## ##::: ###:: ##:1006// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##:'##::::'##:. ##:: ####: ##:1007// ##::'####: ########:: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: #####::::'##:::. ##: ## ## ##:1008// ##::: ##:: ##.....::: ##:::: ##::::. ##:: ##:: ##:::: ##: ##::::::: ##. ##::: #########: ##. ####:1009// ##::: ##:: ##:::::::: ##:::: ##:::::. ## ##::: ##:::: ##: ##::::::: ##:. ##:: ##.... ##: ##:. ###:1010//. ######::: ##::::::::. #######:::::::. ###::::. #######:: ########: ##::. ##: ##:::: ##: ##::. ##:1011//:......::::..::::::::::.......:::::::::...::::::.......:::........::..::::..::..:::::..::..::::..::10121013struct MicroProfileGpuTimerStateVulkan;1014MicroProfileGpuTimerStateVulkan* MicroProfileGetGpuTimerStateVulkan();1015uint32_t MicroProfileGpuInsertTimeStampVulkan(void* pContext);1016uint64_t MicroProfileGpuGetTimeStampVulkan(uint32_t nKey);1017uint64_t MicroProfileTicksPerSecondGpuVulkan();1018int MicroProfileGetGpuTickReferenceVulkan(int64_t* pOutCpu, int64_t* pOutGpu);1019uint32_t MicroProfileGpuFlipVulkan(void* pContext);1020void MicroProfileGpuShutdownVulkan();1021#endif10221023struct MicroProfileSymbolState1024{1025std::atomic<int> nModuleLoadsFinished;1026std::atomic<int> nModuleLoadsRequested;1027std::atomic<int64_t> nSymbolsLoaded;1028};10291030struct MicroProfileSymbolModuleRegion1031{1032intptr_t nBegin;1033intptr_t nEnd;1034};1035struct MicroProfileSymbolModule1036{1037uint64_t nModuleBase;1038uint32_t nMatchOffset;1039uint32_t nStringOffset;1040const char* pBaseString;1041const char* pTrimmedString;1042MicroProfileSymbolModuleRegion Regions[MICROPROFILE_MAX_MODULE_EXEC_REGIONS];1043int nNumExecutableRegions;10441045bool bDownloading;1046intptr_t nProgress;1047intptr_t nProgressTarget;1048struct MicroProfileSymbolBlock* pSymbolBlock;1049MicroProfileHashTable AddressToSymbol;10501051int64_t nSymbols;1052std::atomic<int64_t> nSymbolsLoaded;1053std::atomic<int> nModuleLoadRequested;1054std::atomic<int> nModuleLoadFinished;1055};10561057struct MicroProfileInstrumentMemoryRegion1058{1059intptr_t Start;1060intptr_t Size;1061uint32_t Protect;1062};10631064struct MicroProfile1065{1066uint32_t nTotalTimers;1067uint32_t nGroupCount;1068uint32_t nCategoryCount;1069uint32_t nAggregateClear;1070uint32_t nAggregateFlip;1071uint32_t nAggregateFlipCount;1072uint32_t nAggregateFrames;10731074uint64_t nFlipStartTick;1075uint64_t nAggregateFlipTick;10761077uint32_t nDisplay;1078uint32_t nBars;1079uint32_t nActiveGroups[MICROPROFILE_MAX_GROUP_INTS];1080bool AnyActive;1081uint32_t nFrozen;1082uint32_t nWasFrozen;1083uint32_t nPlatformMarkersEnabled;10841085uint32_t nForceEnable;10861087uint32_t nForceGroups[MICROPROFILE_MAX_GROUP_INTS];1088uint32_t nActiveGroupsWanted[MICROPROFILE_MAX_GROUP_INTS];1089uint32_t nGroupMask[MICROPROFILE_MAX_GROUP_INTS];10901091uint32_t nStartEnabled;1092uint32_t nAllThreadsWanted;10931094uint32_t nOverflow;10951096uint32_t nMaxGroupSize;1097uint32_t nDumpFileNextFrame;1098uint32_t nDumpFileCountDown;1099uint32_t nDumpSpikeMask;1100uint32_t nAutoClearFrames;11011102float fDumpCpuSpike;1103float fDumpGpuSpike;1104char HtmlDumpPath[512];1105char CsvDumpPath[512];1106uint32_t DumpFrameCount;11071108int64_t nPauseTicks;1109std::atomic<int64_t> nContextSwitchStalledTick;1110int64_t nContextSwitchLastPushed;1111int64_t nContextSwitchLastIndexPushed;11121113float fReferenceTime;1114float fRcpReferenceTime;11151116MicroProfileCategory CategoryInfo[MICROPROFILE_MAX_CATEGORIES];1117MicroProfileGroupInfo GroupInfo[MICROPROFILE_MAX_GROUPS];1118MicroProfileTimerInfo TimerInfo[MICROPROFILE_MAX_TIMERS];1119uint32_t TimerToGroup[MICROPROFILE_MAX_TIMERS];11201121MicroProfileTimer AccumTimers[MICROPROFILE_MAX_TIMERS];1122uint64_t AccumMaxTimers[MICROPROFILE_MAX_TIMERS];1123uint64_t AccumMinTimers[MICROPROFILE_MAX_TIMERS];1124uint64_t AccumTimersExclusive[MICROPROFILE_MAX_TIMERS];1125uint64_t AccumMaxTimersExclusive[MICROPROFILE_MAX_TIMERS];11261127MicroProfileTimer Frame[MICROPROFILE_MAX_TIMERS];1128uint64_t FrameExclusive[MICROPROFILE_MAX_TIMERS];11291130MicroProfileTimer Aggregate[MICROPROFILE_MAX_TIMERS];1131uint64_t AggregateMax[MICROPROFILE_MAX_TIMERS];1132uint64_t AggregateMin[MICROPROFILE_MAX_TIMERS];1133uint64_t AggregateExclusive[MICROPROFILE_MAX_TIMERS];1134uint64_t AggregateMaxExclusive[MICROPROFILE_MAX_TIMERS];11351136uint32_t FrameGroupThreadValid[MICROPROFILE_MAX_THREADS / 32 + 1];1137struct GroupTime1138{1139uint64_t nTicks;1140uint64_t nTicksExclusive;1141uint32_t nCount;1142};11431144GroupTime FrameGroupThread[MICROPROFILE_MAX_THREADS][MICROPROFILE_MAX_GROUPS];1145GroupTime FrameGroup[MICROPROFILE_MAX_GROUPS];1146uint64_t AccumGroup[MICROPROFILE_MAX_GROUPS];1147uint64_t AccumGroupMax[MICROPROFILE_MAX_GROUPS];11481149uint64_t AggregateGroup[MICROPROFILE_MAX_GROUPS];1150uint64_t AggregateGroupMax[MICROPROFILE_MAX_GROUPS];11511152MicroProfileGraphState Graph[MICROPROFILE_MAX_GRAPHS];1153uint32_t nGraphPut;11541155uint32_t nThreadActive[MICROPROFILE_MAX_THREADS];1156MicroProfileThreadLog* Pool[MICROPROFILE_MAX_THREADS];1157MicroProfileThreadLogGpu* PoolGpu[MICROPROFILE_MAX_THREADS];11581159MicroProfileThreadLog TimelineLog;1160uint32_t TimelineTokenFrameEnter[MICROPROFILE_TIMELINE_MAX_TOKENS];1161uint32_t TimelineTokenFrameLeave[MICROPROFILE_TIMELINE_MAX_TOKENS];1162uint32_t TimelineToken[MICROPROFILE_TIMELINE_MAX_TOKENS];1163const char* TimelineTokenStaticString[MICROPROFILE_TIMELINE_MAX_TOKENS];11641165uint32_t nTimelineFrameMax;1166MicroProfileFrameExtraCounterData* FrameExtraCounterData;1167MicroProfileCsvConfig CsvConfig;1168const char* pSettings;1169const char* pSettingsReadOnly;1170const char* pSettingsTemp;11711172uint32_t nNumLogs;1173uint32_t nNumLogsGpu;1174uint32_t nMemUsage;1175int nFreeListHead;11761177uint32_t nFrameCurrent;1178uint32_t nFrameCurrentIndex;1179uint32_t nFramePut;1180uint32_t nFrameNext;1181uint64_t nFramePutIndex;11821183MicroProfileFrameState Frames[MICROPROFILE_MAX_FRAME_HISTORY];11841185uint64_t nFlipTicks;1186uint64_t nFlipAggregate;1187uint64_t nFlipMax;1188uint64_t nFlipAggregateDisplay;1189uint64_t nFlipMaxDisplay;11901191MicroProfileThread ContextSwitchThread;1192bool bContextSwitchRunning;1193bool bContextSwitchStop;1194bool bContextSwitchAllThreads;1195bool bContextSwitchNoBars;1196uint32_t nContextSwitchUsage;1197uint32_t nContextSwitchLastPut;11981199int64_t nContextSwitchHoverTickIn;1200int64_t nContextSwitchHoverTickOut;1201uint32_t nContextSwitchHoverThread;1202uint32_t nContextSwitchHoverThreadBefore;1203uint32_t nContextSwitchHoverThreadAfter;1204uint8_t nContextSwitchHoverCpu;1205uint8_t nContextSwitchHoverCpuNext;12061207uint32_t CoreCount;1208uint8_t CoreEfficiencyClass[MICROPROFILE_MAX_CPU_CORES];12091210uint32_t nContextSwitchPut;1211MicroProfileContextSwitch ContextSwitch[MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE];12121213MpSocket ListenerSocket;1214uint32_t nWebServerPort;12151216char WebServerBuffer[MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE];1217uint32_t WebServerPut;12181219uint64_t nWebServerDataSent;12201221int WebSocketTimers;1222int WebSocketCounters;1223int WebSocketGroups;1224uint32_t nWebSocketDirty;1225MpSocket WebSockets[1];1226int64_t WebSocketFrameLast[1];1227uint32_t nNumWebSockets;1228uint32_t nSocketFail; // for error propagation.12291230MicroProfileThread WebSocketSendThread;1231bool WebSocketThreadRunning;1232bool WebSocketThreadJoined;12331234uint32_t WSCategoriesSent;1235uint32_t WSGroupsSent;1236uint32_t WSTimersSent;1237uint32_t WSCountersSent;1238MicroProfileWebSocketBuffer WSBuf;1239char* pJsonSettings;1240const char* pJsonSettingsName;1241bool bJsonSettingsReadOnly;1242uint32_t nJsonSettingsPending;1243uint32_t nJsonSettingsBufferSize;1244uint32_t nWSWasConnected;1245uint32_t nMicroProfileShutdown;1246uint32_t nWSViewMode;12471248char CounterNames[MICROPROFILE_MAX_COUNTER_NAME_CHARS];1249MicroProfileCounterInfo CounterInfo[MICROPROFILE_MAX_COUNTERS];1250MicroProfileCounterSource CounterSource[MICROPROFILE_MAX_COUNTERS];1251uint32_t nNumCounters;1252uint32_t nCounterNamePos;1253std::atomic<int64_t> Counters[MICROPROFILE_MAX_COUNTERS];1254std::atomic<double>* CountersDouble;1255#if MICROPROFILE_COUNTER_HISTORY // uses 1kb per allocated counter. 512kb for default counter count1256uint32_t nCounterHistoryPut;1257int64_t nCounterHistory[MICROPROFILE_GRAPH_HISTORY][MICROPROFILE_MAX_COUNTERS]; // flipped to make swapping cheap, drawing more expensive.1258int64_t nCounterMax[MICROPROFILE_MAX_COUNTERS];1259int64_t nCounterMin[MICROPROFILE_MAX_COUNTERS];1260double* dCounterHistory;1261double* dCounterMax;1262double* dCounterMin;1263#endif12641265MicroProfileThread AutoFlipThread;1266std::atomic<uint32_t> nAutoFlipDelay;1267std::atomic<uint32_t> nAutoFlipStop;12681269MicroProfileStrings Strings;1270MicroProfileToken CounterToken_MicroProfile;1271MicroProfileToken CounterToken_StringBlock;1272MicroProfileToken CounterToken_StringBlock_Count;1273MicroProfileToken CounterToken_StringBlock_Waste;1274MicroProfileToken CounterToken_StringBlock_Strings;1275MicroProfileToken CounterToken_StringBlock_Memory;12761277MicroProfileToken CounterToken_Alloc;1278MicroProfileToken CounterToken_Alloc_Memory;1279MicroProfileToken CounterToken_Alloc_Count;12801281#if MICROPROFILE_DYNAMIC_INSTRUMENT1282uint32_t DynamicTokenIndex;1283MicroProfileToken DynamicTokens[MICROPROFILE_MAX_DYNAMIC_TOKENS];1284void* FunctionsInstrumented[MICROPROFILE_MAX_DYNAMIC_TOKENS];1285const char* FunctionsInstrumentedName[MICROPROFILE_MAX_DYNAMIC_TOKENS];1286const char* FunctionsInstrumentedModuleNames[MICROPROFILE_MAX_DYNAMIC_TOKENS];1287// const char* FunctionsInstrumentedUnmangled[MICROPROFILE_MAX_DYNAMIC_TOKENS];1288uint32_t WSFunctionsInstrumentedSent;1289MicroProfileSymbolState SymbolState;12901291MicroProfileSymbolModule SymbolModules[MICROPROFILE_INSTRUMENT_MAX_MODULES];1292char SymbolModuleNameBuffer[MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS];1293int SymbolModuleNameOffset;1294int SymbolNumModules;1295int WSSymbolModulesSent;1296std::atomic<int> nSymbolsDirty;12971298MicroProfileFunctionQuery* pPendingQuery;1299MicroProfileFunctionQuery* pFinishedQuery;1300MicroProfileFunctionQuery* pQueryFreeList;1301uint32_t nQueryProcessed;1302uint32_t nNumQueryFree;1303uint32_t nNumQueryAllocated;13041305int SymbolThreadRunning;1306int SymbolThreadFinished;1307MicroProfileThread SymbolThread;1308int nNumPatchErrors;1309MicroProfilePatchError PatchErrors[MICROPROFILE_MAX_PATCH_ERRORS];1310int nNumPatchErrorFunctions;1311const char* PatchErrorFunctionNames[MICROPROFILE_MAX_PATCH_ERRORS];1312MicroProfileSuspendState SuspendState;1313MicroProfileArray<MicroProfileInstrumentMemoryRegion> MemoryRegions;1314#endif13151316int GpuQueue;1317MicroProfileThreadLogGpu* pGpuGlobal;1318MicroProfileGpuTimerState* pGPU;1319};13201321inline uint32_t MicroProfileLogGetType(MicroProfileLogEntry Index)1322{1323return ((MP_LOG_BEGIN_MASK & Index) >> 62) & 0x3;1324}13251326inline uint64_t MicroProfileLogGetTimerIndex(MicroProfileLogEntry Index)1327{1328return (0x3fff & (Index >> 48));1329}1330uint32_t MicroProfileLogGetDataSize(MicroProfileLogEntry Index)1331{1332if(MicroProfileLogGetType(Index) == MP_LOG_EXTENDED)1333return 0xffff & (Index >> 32);1334else1335return 0;1336}13371338inline EMicroProfileTokenExtended MicroProfileLogGetExtendedToken(MicroProfileLogEntry Index)1339{1340return (EMicroProfileTokenExtended)(0x3fff & (Index >> 48));1341}13421343inline uint32_t MicroProfileLogGetExtendedDataSize(MicroProfileLogEntry Index)1344{1345return (uint32_t)(0xffff & (Index >> 32));1346}13471348inline uint32_t MicroProfileLogGetExtendedPayload(MicroProfileLogEntry Index)1349{1350return (uint32_t)(0xffffffff & Index);1351}13521353inline uint64_t MicroProfileLogGetExtendedPayloadNoData(MicroProfileLogEntry Index)1354{1355return (uint64_t)(MP_LOG_TICK_MASK & Index);1356}13571358inline void* MicroProfileLogGetExtendedPayloadNoDataPtr(MicroProfileLogEntry Index)1359{1360return (void*)(MP_LOG_PAYLOAD_PTR_MASK & Index);1361}13621363MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick);1364MicroProfileLogEntry MicroProfileMakeLogExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload);1365MicroProfileLogEntry MicroProfileMakeLogExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nTick);13661367inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick)1368{1369MicroProfileLogEntry Entry = (nBegin << 62) | ((0x3fff & nToken) << 48) | (MP_LOG_TICK_MASK & nTick);1370uint32_t t = MicroProfileLogGetType(Entry);1371uint64_t nTimerIndex = MicroProfileLogGetTimerIndex(Entry);1372MP_ASSERT(t == nBegin);1373MP_ASSERT(nTimerIndex == (nToken & 0x3fff));1374return Entry;1375}13761377// extended data, with the option to store 0xfffe * 8 bytes after1378inline MicroProfileLogEntry MicroProfileMakeLogExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload)1379{1380MP_ASSERT(nDataSizeQWords < 0xffff);1381MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED) << 62) | ((0x3fff & (uint64_t)eTokenExt) << 48) | ((0xffff & (uint64_t)nDataSizeQWords) << 32) | nPayload;13821383MP_ASSERT(MicroProfileLogGetExtendedToken(Entry) == eTokenExt);1384MP_ASSERT(MicroProfileLogGetExtendedDataSize(Entry) == nDataSizeQWords);1385MP_ASSERT(MicroProfileLogGetExtendedPayload(Entry) == nPayload);13861387return Entry;1388}1389// extended with no data, but instead 48 bits payload1390inline MicroProfileLogEntry MicroProfileMakeLogExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nPayload)1391{1392MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED_NO_DATA) << 62) | ((0x3fff & (uint64_t)eTokenExt) << 48) | (MP_LOG_TICK_MASK & nPayload);13931394MP_ASSERT(MicroProfileLogGetExtendedToken(Entry) == eTokenExt);1395MP_ASSERT(MicroProfileLogGetExtendedPayloadNoData(Entry) == nPayload);13961397return Entry;1398}13991400// extended with no data, but instead 61 bits payload. used to store a pointer.1401inline MicroProfileLogEntry MicroProfileMakeLogExtendedNoDataPtr(uint64_t nPayload)1402{1403uint64_t hest = ETOKEN_CSTR_PTR;1404MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED_NO_DATA) << 62) | (hest << 48) | (MP_LOG_PAYLOAD_PTR_MASK & nPayload);1405uint64_t v0 = (MP_LOG_PAYLOAD_PTR_MASK & nPayload);1406uint64_t v1 = (uint64_t)MicroProfileLogGetExtendedPayloadNoDataPtr(Entry);14071408MP_ASSERT(v0 == v1);1409return Entry;1410}14111412inline uint32_t MicroProfileGetQWordSize(uint32_t nDataSize)1413{1414uint32_t nSize = (nDataSize + 7) / 8;1415MP_ASSERT(nSize < 0xffff); // won't pack...1416return nSize;1417}14181419namespace1420{1421struct MicroProfilePayloadPack1422{1423union1424{1425struct1426{1427#if MICROPROFILE_BIG_ENDIAN /// NOT implemented.1428char h;1429char message[7];1430#else1431char message[7];1432char h;1433#endif1434};1435uint64_t LogEntry;1436};1437};1438}; // namespace14391440inline int64_t MicroProfileLogTickDifference(MicroProfileLogEntry Start, MicroProfileLogEntry End)1441{1442int64_t nStart = Start;1443int64_t nEnd = End;1444int64_t nDifference = ((nEnd << 16) - (nStart << 16));1445return nDifference >> 16;1446}1447inline int64_t MicroProfileLogTickMax(MicroProfileLogEntry A, MicroProfileLogEntry B)1448{1449int64_t Diff = MicroProfileLogTickDifference(A, B);1450if(Diff < 0)1451{1452return A;1453}1454else1455{1456return B;1457}1458}14591460inline int64_t MicroProfileLogTickMin(MicroProfileLogEntry A, MicroProfileLogEntry B)1461{1462int64_t Diff = MicroProfileLogTickDifference(A, B);1463if(Diff < 0)1464{1465return B;1466}1467else1468{1469return A;1470}1471}1472inline int64_t MicroProfileLogTickClamp(uint64_t T, uint64_t min, uint64_t max)1473{1474return MicroProfileLogTickMin(MicroProfileLogTickMax(T, min), max);1475}14761477inline int64_t MicroProfileLogGetTick(MicroProfileLogEntry e)1478{1479return MP_LOG_TICK_MASK & e;1480}14811482inline int64_t MicroProfileLogSetTick(MicroProfileLogEntry e, int64_t nTick)1483{1484return (MP_LOG_TICK_MASK & nTick) | (e & ~MP_LOG_TICK_MASK);1485}14861487inline uint16_t MicroProfileGetTimerIndex(MicroProfileToken t)1488{1489return (t & 0xffff);1490}1491inline uint32_t MicroProfileGetGroupMask(MicroProfileToken t)1492{1493return (uint32_t)((t >> 16) & MICROPROFILE_GROUP_MASK_ALL);1494}1495inline uint32_t MicroProfileGetGroupMaskIndex(MicroProfileToken t)1496{1497return (uint32_t)(t >> 48);1498}14991500inline MicroProfileToken MicroProfileMakeToken(uint32_t nGroupMask, uint16_t nGroupIndex, uint16_t nTimer)1501{1502uint64_t token = ((uint64_t)nGroupIndex << 48llu) | ((uint64_t)nGroupMask << 16llu) | nTimer;1503if(0 != (token & MP_LOG_CSTR_MASK))1504{1505MP_BREAK(); // should never happen1506}1507return token;1508}15091510template <typename T>1511T MicroProfileMin(T a, T b)1512{1513return a < b ? a : b;1514}15151516template <typename T>1517T MicroProfileMax(T a, T b)1518{1519return a > b ? a : b;1520}1521template <typename T>1522T MicroProfileClamp(T a, T min_, T max_)1523{1524return MicroProfileMin(max_, MicroProfileMax(min_, a));1525}15261527inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond)1528{1529return (int64_t)(fMs * 0.001f * nTicksPerSecond);1530}15311532inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond)1533{1534return 1000.f / (nTicksPerSecond ? nTicksPerSecond : 1);1535}1536float MicroProfileTickToMsMultiplierCpu()1537{1538return MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());1539}15401541float MicroProfileTickToMsMultiplierGpu()1542{1543return MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());1544}1545uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)1546{1547return (uint16_t)MicroProfileGet()->TimerToGroup[MicroProfileGetTimerIndex(t)];1548}15491550uint64_t MicroProfileTick()1551{1552return MP_TICK();1553}15541555#ifdef _WIN321556#include <windows.h>1557#define fopen microprofile_fopen_helper15581559FILE* microprofile_fopen_helper(const char* filename, const char* mode)1560{1561FILE* F = 0;1562if(0 == fopen_s(&F, filename, mode))1563{1564return F;1565}1566return 0;1567}15681569int64_t MicroProfileTicksPerSecondCpu()1570{1571static int64_t nTicksPerSecond = 0;1572if(nTicksPerSecond == 0)1573{1574QueryPerformanceFrequency((LARGE_INTEGER*)&nTicksPerSecond);1575}1576return nTicksPerSecond;1577}1578int64_t MicroProfileGetTick()1579{1580int64_t ticks;1581QueryPerformanceCounter((LARGE_INTEGER*)&ticks);1582return ticks;1583}15841585#endif15861587#if 115881589typedef void* (*MicroProfileThreadFunc)(void*);15901591#ifndef _WIN321592typedef pthread_t MicroProfileThread;1593void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)1594{1595pthread_attr_t Attr;1596int r = pthread_attr_init(&Attr);1597MP_ASSERT(r == 0);1598pthread_create(pThread, &Attr, Func, 0);1599}1600void MicroProfileThreadJoin(MicroProfileThread* pThread)1601{1602int r = pthread_join(*pThread, 0);1603MP_ASSERT(r == 0);1604}1605#elif defined(_WIN32)1606typedef HANDLE MicroProfileThread;1607DWORD __stdcall ThreadTrampoline(void* pFunc)1608{1609MicroProfileThreadFunc F = (MicroProfileThreadFunc)pFunc;1610return (uint32_t)(uintptr_t)F(0);1611}16121613void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)1614{1615*pThread = CreateThread(0, 0, ThreadTrampoline, Func, 0, 0);1616}1617void MicroProfileThreadJoin(MicroProfileThread* pThread)1618{1619WaitForSingleObject(*pThread, INFINITE);1620CloseHandle(*pThread);1621}1622#else1623#include <thread>1624typedef std::thread* MicroProfileThread;1625inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)1626{1627*pThread = MP_ALLOC_OBJECT(std::thread);1628new(*pThread) std::thread(Func, nullptr);1629}1630inline void MicroProfileThreadJoin(MicroProfileThread* pThread)1631{1632(*pThread)->join();1633(*pThread)->~thread();1634MP_FREE(*pThread);1635*pThread = 0;1636}1637#endif1638#endif16391640#if MICROPROFILE_WEBSERVER16411642#ifdef _WIN321643#define MP_INVALID_SOCKET(f) (f == INVALID_SOCKET)1644#else1645#include <fcntl.h>1646#include <netinet/in.h>1647#include <sys/socket.h>1648#define MP_INVALID_SOCKET(f) (f < 0)1649#endif16501651void MicroProfileWebServerStart();1652void MicroProfileWebServerStop();1653void MicroProfileWebServerJoin();1654bool MicroProfileWebServerUpdate();1655void MicroProfileDumpToFile();16561657#else16581659#define MicroProfileWebServerStart() \1660do \1661{ \1662} while(0)1663#define MicroProfileWebServerStop() \1664do \1665{ \1666} while(0)1667#define MicroProfileWebServerJoin() \1668do \1669{ \1670} while(0)1671#define MicroProfileWebServerUpdate() false1672#define MicroProfileDumpToFile() \1673do \1674{ \1675} while(0)1676#endif16771678#include <algorithm>1679#include <math.h>1680#include <stdio.h>1681#include <stdlib.h>16821683#if MICROPROFILE_DEBUG1684#ifdef _WIN321685void uprintf(const char* fmt, ...)1686{1687va_list args;1688va_start(args, fmt);1689char buffer[1024];1690stbsp_vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);1691OutputDebugStringA(buffer);1692va_end(args);1693}1694#else1695#define uprintf(...) printf(__VA_ARGS__)1696#endif1697#else1698#define uprintf(...) \1699do \1700{ \1701sizeof(__VA_ARGS__); \1702} while(0)1703#endif17041705#define S g_MicroProfile17061707MicroProfile g_MicroProfile;1708#ifdef MICROPROFILE_IOS1709// iOS doesn't support __thread1710static pthread_key_t g_MicroProfileThreadLogKey;1711static pthread_once_t g_MicroProfileThreadLogKeyOnce = PTHREAD_ONCE_INIT;17121713static void MicroProfileCreateThreadLogKey()1714{1715pthread_key_create(&g_MicroProfileThreadLogKey, NULL);1716}1717#else1718MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLogThreadLocal = 0;1719#endif1720static bool g_bUseLock = false; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)17211722MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", MP_GREEN4);1723MICROPROFILE_DEFINE(g_MicroProfileThreadLoop, "MicroProfile", "ThreadLoop", MP_GREEN4);1724MICROPROFILE_DEFINE(g_MicroProfileClear, "MicroProfile", "Clear", MP_GREEN4);1725MICROPROFILE_DEFINE(g_MicroProfileAccumulate, "MicroProfile", "Accumulate", MP_GREEN4);1726MICROPROFILE_DEFINE(g_MicroProfileContextSwitchSearch, "MicroProfile", "ContextSwitchSearch", MP_GREEN4);1727MICROPROFILE_DEFINE(g_MicroProfileGpuSubmit, "MicroProfile", "MicroProfileGpuSubmit", MP_HOTPINK2);1728MICROPROFILE_DEFINE(g_MicroProfileSendLoop, "MicroProfile", "MicroProfileSocketSendLoop", MP_GREEN4);1729MICROPROFILE_DEFINE_LOCAL_ATOMIC_COUNTER(g_MicroProfileBytesPerFlip, "microprofile/bytesperflip");17301731// void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc);1732void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable);1733uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K);1734void MicroProfileHashTableGrow(MicroProfileHashTable* pTable);17351736bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value, uint64_t H, bool bAllowGrow);1737bool MicroProfileHashTableGet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t* pValue);1738bool MicroProfileHashTableRemove(MicroProfileHashTable* pTable, uint64_t Key);17391740bool MicroProfileHashTableSetString(MicroProfileHashTable* pTable, const char* pKey, const char* pValue);1741bool MicroProfileHashTableGetString(MicroProfileHashTable* pTable, const char* pKey, const char** pValue);1742bool MicroProfileHashTableRemoveString(MicroProfileHashTable* pTable, const char* pKey);17431744bool MicroProfileHashTableSetPtr(MicroProfileHashTable* pTable, const void* pKey, void* pValue);1745template <typename T = void>1746bool MicroProfileHashTableGetPtr(MicroProfileHashTable* pTable, const void* pKey, T** pValue = nullptr);1747bool MicroProfileHashTableRemovePtr(MicroProfileHashTable* pTable, const void* pKey);17481749enum1750{1751ESTRINGINTERN_LOWERCASE = 1,1752ESTRINGINTERN_FORCEFORWARDSLASH = 0x2,1753};1754const char* MicroProfileStringIntern(const char* pStr);1755const char* MicroProfileStringInternLower(const char* pStr);1756const char* MicroProfileStringInternSlash(const char* pStr);1757const char* MicroProfileStringIntern(const char* pStr, uint32_t nLen, uint32_t nInternalFlags = 0);17581759void MicroProfileStringsInit(MicroProfileStrings* pStrings);1760void MicroProfileStringsDestroy(MicroProfileStrings* pStrings);17611762MicroProfileToken MicroProfileCounterTokenInit(int nParent, uint32_t nFlags);1763void MicroProfileCounterTokenInitName(MicroProfileToken nToken, const char* pName);1764void MicroProfileCounterConfigToken(MicroProfileToken, uint32_t eFormat, int64_t nLimit, uint32_t nFlags);1765uint16_t MicroProfileFindGroup(const char* pGroup);17661767inline std::recursive_mutex& MicroProfileMutex()1768{1769static std::recursive_mutex Mutex;1770return Mutex;1771}1772std::recursive_mutex& MicroProfileGetMutex()1773{1774return MicroProfileMutex();1775}17761777inline std::recursive_mutex& MicroProfileTimelineMutex()1778{1779static std::recursive_mutex Mutex;1780return Mutex;1781}1782MICROPROFILE_API MicroProfile* MicroProfileGet()1783{1784return &g_MicroProfile;1785}17861787MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName);1788MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAllocInternal();1789void* MicroProfileSocketSenderThread(void*);17901791void MicroProfileInit()1792{1793static bool bOnce = true;1794if(!bOnce)1795{1796return;1797}17981799std::recursive_mutex& mutex = MicroProfileMutex();1800bool bUseLock = g_bUseLock;1801if(bUseLock)1802mutex.lock();1803if(bOnce)1804{1805bOnce = false;1806memset(&S, 0, sizeof(S));18071808MicroProfileStringsInit(&S.Strings);18091810// these strings are used for counter names inside the string1811S.CounterToken_MicroProfile = MicroProfileCounterTokenInit(-1, 0);1812S.CounterToken_StringBlock = MicroProfileCounterTokenInit(S.CounterToken_MicroProfile, 0);1813S.CounterToken_StringBlock_Count = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0);1814S.CounterToken_StringBlock_Waste = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0);1815S.CounterToken_StringBlock_Strings = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0);1816S.CounterToken_StringBlock_Memory = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0);18171818S.CounterToken_Alloc = MicroProfileCounterTokenInit(S.CounterToken_MicroProfile, 0);1819S.CounterToken_Alloc_Memory = MicroProfileCounterTokenInit(S.CounterToken_Alloc, 0);1820S.CounterToken_Alloc_Count = MicroProfileCounterTokenInit(S.CounterToken_Alloc, 0);18211822MicroProfileCounterTokenInitName(S.CounterToken_MicroProfile, "microprofile");1823MicroProfileCounterTokenInitName(S.CounterToken_StringBlock, "stringblock");1824MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Count, "count");1825MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Waste, "waste");1826MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Strings, "strings");1827MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Memory, "memory");18281829MicroProfileCounterTokenInitName(S.CounterToken_Alloc, "alloc");1830MicroProfileCounterTokenInitName(S.CounterToken_Alloc_Memory, "memory");1831MicroProfileCounterTokenInitName(S.CounterToken_Alloc_Count, "count");18321833S.nMemUsage += sizeof(S);1834for(int i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)1835{1836S.GroupInfo[i].pName[0] = '\0';1837}1838for(int i = 0; i < MICROPROFILE_MAX_CATEGORIES; ++i)1839{1840S.CategoryInfo[i].pName[0] = '\0';1841memset(S.CategoryInfo[i].nGroupMask, 0, sizeof(S.CategoryInfo[i].nGroupMask));1842}1843memcpy(&S.CategoryInfo[0].pName[0], "default", sizeof("default"));1844S.nCategoryCount = 1;1845for(int i = 0; i < MICROPROFILE_MAX_TIMERS; ++i)1846{1847S.TimerInfo[i].pName[0] = '\0';1848}1849S.nGroupCount = 0;1850S.nFlipStartTick = MP_TICK();1851S.nContextSwitchStalledTick = MP_TICK();1852S.nAggregateFlipTick = MP_TICK();1853memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups));1854S.nFrozen = 0;1855S.nWasFrozen = 0;1856memset(S.nForceGroups, 0, sizeof(S.nForceGroups));1857memset(S.nActiveGroupsWanted, 0, sizeof(S.nActiveGroupsWanted));1858S.nStartEnabled = 0;1859S.nAllThreadsWanted = 1;1860S.nAggregateFlip = 0;1861S.nTotalTimers = 0;1862for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)1863{1864S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;1865}1866S.fReferenceTime = 33.33f;1867S.fRcpReferenceTime = 1.f / S.fReferenceTime;1868S.nFreeListHead = -1;1869int64_t nTick = MP_TICK();1870for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)1871{1872S.Frames[i].nFrameStartCpu = nTick;1873S.Frames[i].nFrameStartGpu = MICROPROFILE_INVALID_TICK;1874}1875S.nWebServerPort = MICROPROFILE_WEBSERVER_PORT; // Use defined value as default port1876S.nWebServerDataSent = (uint64_t)-1;1877S.WebSocketTimers = -1;1878S.WebSocketCounters = -1;1879S.WebSocketGroups = -1;1880S.nSocketFail = 0;18811882S.DumpFrameCount = MICROPROFILE_WEBSERVER_DEFAULT_FRAMES;18831884#if MICROPROFILE_COUNTER_HISTORY1885S.nCounterHistoryPut = 0;1886for(uint32_t i = 0; i < MICROPROFILE_MAX_COUNTERS; ++i)1887{1888S.nCounterMin[i] = 0x7fffffffffffffff;1889S.nCounterMax[i] = 0x8000000000000000;1890}1891#endif1892S.GpuQueue = MICROPROFILE_GPU_INIT_QUEUE("GPU");1893S.pGpuGlobal = MicroProfileThreadLogGpuAllocInternal();1894MicroProfileGpuBegin(0, S.pGpuGlobal);18951896S.pJsonSettings = 0;1897S.pJsonSettingsName = nullptr;1898S.nJsonSettingsPending = 0;1899S.nJsonSettingsBufferSize = 0;1900S.nWSWasConnected = 0;19011902for(uint32_t i = 0; i < MICROPROFILE_TIMELINE_MAX_TOKENS; ++i)1903{1904S.TimelineTokenFrameEnter[i] = MICROPROFILE_INVALID_FRAME;1905S.TimelineTokenFrameLeave[i] = MICROPROFILE_INVALID_FRAME;1906S.TimelineTokenStaticString[i] = nullptr;1907S.TimelineToken[i] = 0;1908}1909memset(&S.AccumMinTimers[0], 0xFF, sizeof(S.AccumMinTimers));1910S.CountersDouble = (std::atomic<double>*)&S.Counters;1911#if MICROPROFILE_COUNTER_HISTORY1912S.dCounterHistory = (double*)S.nCounterHistory;1913S.dCounterMax = (double*)S.nCounterMax;1914S.dCounterMin = (double*)S.nCounterMin;1915#endif1916}1917MicroProfileUpdateSettingsPath();19181919#if MICROPROFILE_FRAME_EXTRA_DATA1920S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)1;1921#endif1922MicroProfileCounterConfigToken(S.CounterToken_Alloc_Memory, MICROPROFILE_COUNTER_FORMAT_BYTES, 0, MICROPROFILE_COUNTER_FLAG_DETAILED);1923MICROPROFILE_COUNTER_CONFIG("MicroProfile/ThreadLog/Memory", MICROPROFILE_COUNTER_FORMAT_BYTES, 0, MICROPROFILE_COUNTER_FLAG_DETAILED);19241925if(bUseLock)1926{1927mutex.unlock();1928}1929}1930void MicroProfileUpdateSettingsPath()1931{1932if(S.pSettings)1933{1934MicroProfileFreeInternal((void*)S.pSettings);1935S.pSettings = nullptr;1936}1937if(S.pSettingsReadOnly)1938{1939MicroProfileFreeInternal((void*)S.pSettingsReadOnly);1940S.pSettingsReadOnly = nullptr;1941}1942if(S.pSettingsTemp)1943{1944MicroProfileFreeInternal((void*)S.pSettingsTemp);1945S.pSettingsTemp = nullptr;1946}1947auto DupeString = [](const char* BasePath, const char* File) -> const char*1948{1949size_t BaseLen = strlen(BasePath);1950bool TrailingSlash = BaseLen > 1 && (BasePath[BaseLen - 1] == '\\' || BasePath[BaseLen - 1] == '/');1951size_t Len = BaseLen + strlen(File) + 2;1952char* Data = (char*)MicroProfileAllocInternal(Len + 1, 1);1953#ifdef _WIN321954char Slash = '\\';1955#else1956char Slash = '/';1957#endif1958if(TrailingSlash)1959snprintf(Data, Len, "%s%s", BasePath, File);1960else1961snprintf(Data, Len, "%s%c%s", BasePath, Slash, File);19621963return Data;1964};1965const char* pBaseSettingsPath = MICROPROFILE_GET_SETTINGS_FILE_PATH;1966S.pSettings = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE);1967S.pSettingsReadOnly = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE_BUILTIN);1968S.pSettingsTemp = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE MICROPROFILE_SETTINGS_FILE_TEMP);1969}19701971void MicroProfileJoinContextSwitchTrace();19721973void MicroProfileShutdown()1974{1975{1976std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());1977S.nMicroProfileShutdown = 1;1978MicroProfileStopContextSwitchTrace();1979}1980MicroProfileWebServerJoin();1981MicroProfileJoinContextSwitchTrace();1982{19831984std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());1985if(S.pJsonSettings)1986{1987MP_FREE(S.pJsonSettings);1988S.pJsonSettings = 0;1989S.pJsonSettingsName = 0;1990S.nJsonSettingsBufferSize = 0;1991}1992if(S.pGPU)1993{1994MicroProfileGpuShutdownPlatform();1995}1996MicroProfileHashTableDestroy(&S.Strings.HashTable);1997MicroProfileStringsDestroy(&S.Strings);1998MICROPROFILE_FREE_NON_ALIGNED(S.WSBuf.pBufferAllocation);19992000MicroProfileFreeGpuQueue(S.GpuQueue);2001MicroProfileThreadLogGpuFree(S.pGpuGlobal);20022003for(uint32_t i = 0; i < S.nNumLogs; ++i)2004{2005#if MICROPROFILE_ASSERT_LOG_FREED2006MP_ASSERT(S.Pool[i]->nActive != 1);2007#endif2008MP_FREE(S.Pool[i]);2009}20102011for(uint32_t i = 0; i < S.nNumLogsGpu; ++i)2012{2013#if MICROPROFILE_ASSERT_LOG_FREED2014MP_ASSERT(!S.PoolGpu[i]->nAllocated);2015#endif2016MP_FREE(S.PoolGpu[i]);2017}2018MicroProfileFreeInternal((void*)S.pSettings);2019S.pSettings = nullptr;2020MicroProfileFreeInternal((void*)S.pSettingsReadOnly);2021S.pSettingsReadOnly = nullptr;2022MicroProfileFreeInternal((void*)S.pSettingsTemp);2023S.pSettingsTemp = nullptr;2024}2025}20262027static void* MicroProfileAutoFlipThread(void*)2028{2029MicroProfileOnThreadCreate("AutoFlipThread");2030while(0 == S.nAutoFlipStop.load())2031{2032MICROPROFILE_SCOPEI("MICROPROFILE", "AutoFlipThread", 0);2033MicroProfileSleep(S.nAutoFlipDelay);2034MicroProfileFlip(0);2035}2036MicroProfileOnThreadExit();2037return 0;2038}20392040void MicroProfileStartAutoFlip(uint32_t nMsDelay)2041{2042S.nAutoFlipDelay = nMsDelay;2043S.nAutoFlipStop.store(0);2044MicroProfileThreadStart(&S.AutoFlipThread, MicroProfileAutoFlipThread);2045}2046void MicroProfileStopAutoFlip()2047{2048S.nAutoFlipStop.store(1);2049MicroProfileThreadJoin(&S.AutoFlipThread);2050}20512052void MicroProfileEnableFrameExtraCounterData()2053{2054// should not be called at the same time as MicroProfileFlip.2055if(!S.FrameExtraCounterData)2056{2057S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)1;2058}2059}20602061void MicroProfileCsvConfigEnd()2062{2063MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG);2064S.CsvConfig.State = MicroProfileCsvConfig::ACTIVE;2065}2066void MicroProfileCsvConfigBegin(uint32_t MaxTimers, uint32_t MaxGroups, uint32_t MaxCounters, uint32_t Flags)2067{2068MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::INACTIVE); // right now, only support being configured once.2069uint32_t TotalElements = MaxTimers + MaxGroups + MaxCounters;2070uint32_t BaseSize = (sizeof(MicroProfileCsvConfig) + 7) & 7;2071uint32_t TimerIndexSize = sizeof(uint16_t) * MaxTimers;2072uint32_t GroupIndexSize = sizeof(uint16_t) * MaxGroups;2073uint32_t CounterIndexSize = sizeof(uint16_t) * MaxCounters;2074uint32_t FrameBlockSize = TotalElements * sizeof(uint64_t);2075uint32_t FrameDataSize = FrameBlockSize * MICROPROFILE_MAX_FRAME_HISTORY;2076S.CsvConfig.NumTimers = 0;2077S.CsvConfig.NumGroups = 0;2078S.CsvConfig.NumCounters = 0;2079S.CsvConfig.MaxTimers = MaxTimers;2080S.CsvConfig.MaxGroups = MaxGroups;2081S.CsvConfig.MaxCounters = MaxCounters;2082S.CsvConfig.TotalElements = TotalElements;2083S.CsvConfig.TimerIndices = (uint16_t*)MicroProfileAllocInternal(TimerIndexSize, alignof(uint16_t));2084S.CsvConfig.pTimerNames = (const char**)MicroProfileAllocInternal(MaxTimers * sizeof(const char*), alignof(const char*));2085memset(S.CsvConfig.pTimerNames, 0, MaxTimers * sizeof(const char*));2086for(uint32_t i = 0; i < MaxTimers; ++i)2087S.CsvConfig.TimerIndices[i] = UINT16_MAX;2088S.CsvConfig.pGroupNames = (const char**)MicroProfileAllocInternal(MaxGroups * sizeof(const char*), alignof(const char*));2089memset(S.CsvConfig.pGroupNames, 0, MaxGroups * sizeof(const char*));2090S.CsvConfig.GroupIndices = (uint16_t*)MicroProfileAllocInternal(GroupIndexSize, alignof(uint16_t));2091for(uint32_t i = 0; i < MaxGroups; ++i)2092S.CsvConfig.GroupIndices[i] = UINT16_MAX;2093S.CsvConfig.pCounterNames = (const char**)MicroProfileAllocInternal(MaxCounters * sizeof(const char*), alignof(const char*));2094memset(S.CsvConfig.pCounterNames, 0, MaxCounters * sizeof(const char*));2095S.CsvConfig.CounterIndices = (uint16_t*)MicroProfileAllocInternal(CounterIndexSize, alignof(uint16_t));2096for(uint32_t i = 0; i < MaxCounters; ++i)2097S.CsvConfig.CounterIndices[i] = UINT16_MAX;2098S.CsvConfig.FrameData = (uint64_t*)MicroProfileAllocInternal(FrameDataSize, alignof(uint64_t));2099memset(S.CsvConfig.FrameData, 0, FrameDataSize);2100S.CsvConfig.State = MicroProfileCsvConfig::CONFIG;2101S.CsvConfig.Flags = Flags;2102}2103void MicroProfileCsvConfigAddTimer(const char* Group, const char* Timer, const char* Name, MicroProfileTokenType Type)2104{2105MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG);2106if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumTimers < S.CsvConfig.MaxTimers)2107{2108MicroProfileToken ret = MicroProfileGetToken(Group, Timer, MP_AUTO, Type, MICROPROFILE_TIMER_FLAG_PLACEHOLDER);2109if(ret != MICROPROFILE_INVALID_TOKEN)2110{2111MP_ASSERT(S.CsvConfig.NumTimers < S.CsvConfig.MaxTimers);2112uint16_t TimerIndex = MicroProfileGetTimerIndex(ret);2113for(uint32_t i = 0; i < S.CsvConfig.NumTimers; ++i)2114{2115if(S.CsvConfig.TimerIndices[i] == TimerIndex)2116return;2117}2118S.CsvConfig.pTimerNames[S.CsvConfig.NumTimers] = Name;2119S.CsvConfig.TimerIndices[S.CsvConfig.NumTimers++] = TimerIndex;2120}2121}2122}2123void MicroProfileCsvConfigAddGroup(const char* Group, const char* Name)2124{2125MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG);2126if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumGroups < S.CsvConfig.MaxGroups)2127{2128uint16_t Index = MicroProfileFindGroup(Group);2129MP_ASSERT(UINT16_MAX != Index);2130if(UINT16_MAX != Index)2131{2132MP_ASSERT(S.CsvConfig.NumGroups < S.CsvConfig.MaxGroups);2133for(uint32_t i = 0; i < S.CsvConfig.NumGroups; ++i)2134{2135if(S.CsvConfig.GroupIndices[i] == Index)2136return;2137}2138S.CsvConfig.pGroupNames[S.CsvConfig.NumGroups] = Name;2139S.CsvConfig.GroupIndices[S.CsvConfig.NumGroups++] = Index;2140}2141}2142}2143void MicroProfileCsvConfigAddCounter(const char* CounterName, const char* Name)2144{2145MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG);2146if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumCounters < S.CsvConfig.MaxCounters)2147{2148MicroProfileToken Token = MicroProfileGetCounterToken(CounterName, 0);2149if(MICROPROFILE_INVALID_TOKEN != Token)2150{2151MP_ASSERT(Token < UINT16_MAX);2152MP_ASSERT(S.CsvConfig.NumCounters < S.CsvConfig.MaxCounters);2153for(uint32_t i = 0; i < S.CsvConfig.NumCounters; ++i)2154{2155if(S.CsvConfig.CounterIndices[i] == (uint16_t)Token)2156return;2157}2158S.CsvConfig.pCounterNames[S.CsvConfig.NumCounters] = Name;2159S.CsvConfig.CounterIndices[S.CsvConfig.NumCounters++] = (uint16_t)Token;2160}2161}2162}21632164#ifdef MICROPROFILE_IOS2165inline MicroProfileThreadLog* MicroProfileGetThreadLog()2166{2167pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey);2168return (MicroProfileThreadLog*)pthread_getspecific(g_MicroProfileThreadLogKey);2169}21702171inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)2172{2173pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey);2174pthread_setspecific(g_MicroProfileThreadLogKey, pLog);2175}2176#else2177MicroProfileThreadLog* MicroProfileGetThreadLog()2178{2179return g_MicroProfileThreadLogThreadLocal;2180}2181void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)2182{2183g_MicroProfileThreadLogThreadLocal = pLog;2184}2185#endif21862187MicroProfileThreadLog* MicroProfileGetThreadLog2()2188{2189MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();2190if(!pLog)2191{2192MicroProfileInitThreadLog();2193pLog = MicroProfileGetThreadLog();2194}2195return pLog;2196}21972198struct MicroProfileScopeLock2199{2200bool bUseLock;2201int nUnlock;2202std::recursive_mutex& m;2203MicroProfileScopeLock(std::recursive_mutex& m)2204: bUseLock(g_bUseLock)2205, nUnlock(0)2206, m(m)2207{2208if(bUseLock)2209m.lock();2210}2211~MicroProfileScopeLock()2212{2213MP_ASSERT(nUnlock == 0);2214if(bUseLock)2215m.unlock();2216}2217void Unlock()2218{2219MP_ASSERT(bUseLock);2220m.unlock();2221nUnlock++;2222}2223void Lock()2224{2225m.lock();2226nUnlock--;2227}2228};22292230void MicroProfileLogReset(MicroProfileThreadLog* pLog);2231void MicroProfileLogClearInternal(MicroProfileThreadLog* pLog);22322233MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)2234{2235MicroProfileScopeLock L(MicroProfileMutex());22362237if(S.nNumLogs == MICROPROFILE_MAX_THREADS && S.nFreeListHead == -1)2238{2239uprintf("recycling thread logs\n");2240// reuse the oldest.2241MicroProfileThreadLog* pOldest = 0;2242uint32_t nIdleFrames = 0;2243for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)2244{2245MicroProfileThreadLog* pLog = S.Pool[i];2246uprintf("tlactive %p, %d. idle:%d\n", pLog, pLog->nActive, pLog->nIdleFrames);2247if(pLog->nActive == 2)2248{2249if(pLog->nIdleFrames >= nIdleFrames)2250{2251nIdleFrames = pLog->nIdleFrames;2252pOldest = pLog;2253}2254}2255}2256MP_ASSERT(pOldest);2257MicroProfileLogReset(pOldest);2258}22592260MicroProfileThreadLog* pLog = 0;2261if(S.nFreeListHead != -1)2262{2263pLog = S.Pool[S.nFreeListHead];2264MP_ASSERT(pLog->nPut.load() == 0);2265MP_ASSERT(pLog->nGet.load() == 0);2266S.nFreeListHead = S.Pool[S.nFreeListHead]->nFreeListNext;2267}2268else2269{2270MICROPROFILE_COUNTER_ADD("MicroProfile/ThreadLog/Allocated", 1);2271MICROPROFILE_COUNTER_ADD("MicroProfile/ThreadLog/Memory", sizeof(MicroProfileThreadLog));2272pLog = MP_ALLOC_OBJECT(MicroProfileThreadLog);2273MicroProfileLogClearInternal(pLog);2274S.nMemUsage += sizeof(MicroProfileThreadLog);2275pLog->nLogIndex = S.nNumLogs;2276MP_ASSERT(S.nNumLogs < MICROPROFILE_MAX_THREADS);2277S.Pool[S.nNumLogs++] = pLog;2278}2279int len = 0;2280if(pName)2281{2282len = (int)strlen(pName);2283int maxlen = sizeof(pLog->ThreadName) - 1;2284len = len < maxlen ? len : maxlen;2285memcpy(&pLog->ThreadName[0], pName, len);2286}2287else2288{2289len = snprintf(&pLog->ThreadName[0], sizeof(pLog->ThreadName) - 1, "TID:[%" PRId64 "]", (int64_t)MP_GETCURRENTTHREADID());2290}2291pLog->ThreadName[len] = '\0';2292pLog->nThreadId = MP_GETCURRENTTHREADID();2293pLog->nFreeListNext = -1;2294pLog->nActive = 1;2295return pLog;2296}22972298void MicroProfileOnThreadCreate(const char* pThreadName)2299{2300char Buffer[64];2301g_bUseLock = true;2302MicroProfileInit();2303MP_ASSERT(MicroProfileGetThreadLog() == 0);2304MicroProfileThreadLog* pLog = MicroProfileCreateThreadLog(pThreadName ? pThreadName : MicroProfileGetThreadName(Buffer));2305(void)Buffer;2306MP_ASSERT(pLog);2307MicroProfileSetThreadLog(pLog);2308}23092310void MicroProfileThreadLogGpuReset(MicroProfileThreadLogGpu* pLog)2311{2312MP_ASSERT(pLog->nAllocated);2313pLog->pContext = (void*)-1;2314pLog->nStart = (uint32_t)-1;2315pLog->nPut = 0;2316pLog->nStackScope = 0;2317}23182319MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAllocInternal()2320{2321MicroProfileThreadLogGpu* pLog = 0;2322for(uint32_t i = 0; i < S.nNumLogsGpu; ++i)2323{2324MicroProfileThreadLogGpu* pNextLog = S.PoolGpu[i];2325if(pNextLog && !pNextLog->nAllocated)2326{2327pLog = pNextLog;2328break;2329}2330}2331if(!pLog)2332{2333pLog = MP_ALLOC_OBJECT(MicroProfileThreadLogGpu);2334int nLogIndex = S.nNumLogsGpu++;2335MP_ASSERT(nLogIndex < MICROPROFILE_MAX_THREADS);2336pLog->nId = nLogIndex;2337S.PoolGpu[nLogIndex] = pLog;2338}2339pLog->nAllocated = 1;2340MicroProfileThreadLogGpuReset(pLog);2341return pLog;2342}23432344MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAlloc()2345{2346std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());2347return MicroProfileThreadLogGpuAllocInternal();2348}23492350void MicroProfileThreadLogGpuFree(MicroProfileThreadLogGpu* pLog)2351{2352MP_ASSERT(pLog->nAllocated);2353pLog->nAllocated = 0;2354}23552356int MicroProfileGetGpuQueue(const char* pQueueName)2357{2358for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; i++)2359{2360MicroProfileThreadLog* pLog = S.Pool[i];2361if(pLog && pLog->nGpu && pLog->nActive && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName))2362{2363return i;2364}2365}2366MP_ASSERT(0); // call MicroProfileInitGpuQueue2367return 0;2368}23692370MicroProfileThreadLog* MicroProfileGetGpuQueueLog(const char* pQueueName)2371{2372for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; i++)2373{2374MicroProfileThreadLog* pLog = S.Pool[i];2375if(pLog && pLog->nGpu && pLog->nActive && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName))2376{2377return pLog;2378}2379}2380MP_ASSERT(0); // call MicroProfileInitGpuQueue2381return 0;2382}23832384int MicroProfileInitGpuQueue(const char* pQueueName)2385{2386for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)2387{2388MicroProfileThreadLog* pLog = S.Pool[i];2389if(pLog && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName))2390{23912392MP_ASSERT(0); // call MicroProfileInitGpuQueue only once per CommandQueue. name must not clash with threadname2393}2394}2395MicroProfileThreadLog* pLog = MicroProfileCreateThreadLog(pQueueName);2396pLog->nGpu = 1;2397pLog->nThreadId = 0;2398for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)2399{2400if(S.Pool[i] == pLog)2401{2402return i;2403}2404}2405MP_BREAK();2406return 0;2407}24082409void MicroProfileFreeGpuQueue(int nQueue)2410{2411MicroProfileThreadLog* pLog = S.Pool[nQueue];2412if(pLog)2413{2414MP_ASSERT(pLog->nActive == 1);2415pLog->nActive = 2;2416}2417}24182419MicroProfileThreadLogGpu* MicroProfileGetGlobalGpuThreadLog()2420{2421return S.pGpuGlobal;2422}24232424MICROPROFILE_API int MicroProfileGetGlobalGpuQueue()2425{2426return S.GpuQueue;2427}2428void MicroProfileLogClearInternal(MicroProfileThreadLog* pLog)2429{2430// can't clear atomics..2431void* pStart = (void*)&pLog->Log[0];2432void* pEnd = (void*)(pLog + 1);2433memset(pStart, 0, (uintptr_t)pEnd - (uintptr_t)pStart);2434pLog->nPut.store(0);2435pLog->nGet.store(0);2436}2437void MicroProfileLogReset(MicroProfileThreadLog* pLog)2438{2439std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());24402441int32_t nLogIndex = -1;2442for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)2443{2444if(pLog == S.Pool[i])2445{2446nLogIndex = i;2447break;2448}2449}2450MP_ASSERT(nLogIndex < MICROPROFILE_MAX_THREADS && nLogIndex > 0);2451MicroProfileLogClearInternal(pLog);2452pLog->nFreeListNext = S.nFreeListHead;2453S.nFreeListHead = nLogIndex;2454for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)2455{2456S.Frames[i].nLogStart[nLogIndex] = 0;2457}2458}24592460void MicroProfileOnThreadExit()2461{2462MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();2463if(pLog)2464{2465MP_ASSERT(pLog->nActive == 1);2466pLog->nActive = 2;2467}2468}24692470void MicroProfileInitThreadLog()2471{2472MicroProfileOnThreadCreate(nullptr);2473}24742475MicroProfileToken MicroProfileFindTokenInternal(const char* pGroup, const char* pName)2476{2477MicroProfileInit();2478MicroProfileScopeLock L(MicroProfileMutex());2479for(uint32_t i = 0; i < S.nTotalTimers; ++i)2480{2481if(!MP_STRCASECMP(pName, S.TimerInfo[i].pName) && !MP_STRCASECMP(pGroup, S.GroupInfo[S.TimerToGroup[i]].pName))2482{2483return S.TimerInfo[i].nToken;2484}2485}2486return MICROPROFILE_INVALID_TOKEN;2487}2488MicroProfileToken MicroProfileFindToken(const char* pGroup, const char* pName)2489{2490return MicroProfileGetToken(pGroup, pName, MP_AUTO, MicroProfileTokenTypeCpu, MICROPROFILE_TIMER_FLAG_PLACEHOLDER);2491}24922493uint16_t MicroProfileFindGroup(const char* pGroup)2494{2495for(uint32_t i = 0; i < S.nGroupCount; ++i)2496{2497if(!MP_STRCASECMP(pGroup, S.GroupInfo[i].pName))2498{2499return i;2500}2501}2502return UINT16_MAX;2503}25042505uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)2506{2507for(uint32_t i = 0; i < S.nGroupCount; ++i)2508{2509if(!MP_STRCASECMP(pGroup, S.GroupInfo[i].pName))2510{2511return i;2512}2513}2514uint16_t nGroupIndex = 0xffff;2515uint32_t nLen = (uint32_t)strlen(pGroup);2516if(nLen > MICROPROFILE_NAME_MAX_LEN - 1)2517nLen = MICROPROFILE_NAME_MAX_LEN - 1;2518memcpy(&S.GroupInfo[S.nGroupCount].pName[0], pGroup, nLen);2519S.GroupInfo[S.nGroupCount].pName[nLen] = '\0';2520S.GroupInfo[S.nGroupCount].nNameLen = nLen;2521S.GroupInfo[S.nGroupCount].nNumTimers = 0;2522S.GroupInfo[S.nGroupCount].nGroupIndex = S.nGroupCount;2523S.GroupInfo[S.nGroupCount].Type = Type;2524S.GroupInfo[S.nGroupCount].nMaxTimerNameLen = 0;2525S.GroupInfo[S.nGroupCount].nColor = 0x42;2526S.GroupInfo[S.nGroupCount].nCategory = 0;2527S.GroupInfo[S.nGroupCount].nWSNext = -2;25282529uint32_t nIndex = S.nGroupCount / 32;2530uint32_t nBit = S.nGroupCount % 32;2531{2532S.CategoryInfo[0].nGroupMask[nIndex] |= (1 << nBit);2533}2534if(S.nStartEnabled)2535{2536S.nActiveGroupsWanted[nIndex] |= (1ll << nBit);2537S.nActiveGroups[nIndex] |= (1ll << nBit);2538S.AnyActive = true;2539}2540nGroupIndex = S.nGroupCount++;2541S.nGroupMask[nIndex] |= (1 << nBit);2542MP_ASSERT(S.nGroupCount < MICROPROFILE_MAX_GROUPS);2543return nGroupIndex;2544}25452546void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)2547{2548MicroProfileScopeLock L(MicroProfileMutex());25492550int nCategoryIndex = -1;2551for(uint32_t i = 0; i < S.nCategoryCount; ++i)2552{2553if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName))2554{2555nCategoryIndex = (int)i;2556break;2557}2558}2559if(-1 == nCategoryIndex && S.nCategoryCount < MICROPROFILE_MAX_CATEGORIES)2560{2561MP_ASSERT(S.CategoryInfo[S.nCategoryCount].pName[0] == '\0');2562nCategoryIndex = (int)S.nCategoryCount++;2563uint32_t nLen = (uint32_t)strlen(pCategory);2564if(nLen > MICROPROFILE_NAME_MAX_LEN - 1)2565nLen = MICROPROFILE_NAME_MAX_LEN - 1;2566memcpy(&S.CategoryInfo[nCategoryIndex].pName[0], pCategory, nLen);2567S.CategoryInfo[nCategoryIndex].pName[nLen] = '\0';2568}2569uint16_t nGroup = MicroProfileGetGroup(pGroup, 0 != MP_STRCASECMP(pGroup, "gpu") ? MicroProfileTokenTypeCpu : MicroProfileTokenTypeGpu);2570S.GroupInfo[nGroup].nColor = nColor;2571if(nCategoryIndex >= 0)2572{2573uint32_t nIndex = nGroup / 32;2574uint32_t nBit = nGroup % 32;2575nBit = (1 << nBit);2576uint32_t nOldCategory = S.GroupInfo[nGroup].nCategory;2577S.CategoryInfo[nOldCategory].nGroupMask[nIndex] &= ~nBit;2578S.CategoryInfo[nCategoryIndex].nGroupMask[nIndex] |= nBit;2579S.GroupInfo[nGroup].nCategory = nCategoryIndex;2580}2581}25822583MicroProfileToken MicroProfileGetToken(const char* pGroup, const char* pName, uint32_t nColor, MicroProfileTokenType Type, uint32_t Flags)2584{2585MicroProfileInit();2586MicroProfileScopeLock L(MicroProfileMutex());2587MicroProfileToken ret = MicroProfileFindTokenInternal(pGroup, pName);2588if(ret != MICROPROFILE_INVALID_TOKEN)2589{2590int idx = MicroProfileGetTimerIndex(ret);2591if(S.TimerInfo[idx].Flags & MICROPROFILE_TIMER_FLAG_PLACEHOLDER)2592{2593S.TimerInfo[idx].nColor = nColor & 0xffffff;2594S.TimerInfo[idx].Flags = Flags;2595S.TimerInfo[idx].Type = Type;2596}2597MP_ASSERT(S.TimerInfo[idx].Flags == Flags || (Flags & MICROPROFILE_TIMER_FLAG_PLACEHOLDER));2598return ret;2599}2600uint16_t nGroupIndex = MicroProfileGetGroup(pGroup, Type);2601uint16_t nTimerIndex = (uint16_t)(S.nTotalTimers++);2602MP_ASSERT(nTimerIndex < MICROPROFILE_MAX_TIMERS);26032604uint32_t nBitIndex = nGroupIndex / 32;2605uint32_t nBit = nGroupIndex % 32;2606uint32_t nGroupMask = 1ll << nBit;2607MicroProfileToken nToken = MicroProfileMakeToken(nGroupMask, (uint16_t)nBitIndex, nTimerIndex);2608S.GroupInfo[nGroupIndex].nNumTimers++;2609S.GroupInfo[nGroupIndex].nMaxTimerNameLen = MicroProfileMax(S.GroupInfo[nGroupIndex].nMaxTimerNameLen, (uint32_t)strlen(pName));2610MP_ASSERT(S.GroupInfo[nGroupIndex].Type == Type); // dont mix cpu & gpu timers in the same group2611S.nMaxGroupSize = MicroProfileMax(S.nMaxGroupSize, S.GroupInfo[nGroupIndex].nNumTimers);2612S.TimerInfo[nTimerIndex].nToken = nToken;2613uint32_t nLen = (uint32_t)strlen(pName);2614if(nLen > MICROPROFILE_NAME_MAX_LEN - 1)2615nLen = MICROPROFILE_NAME_MAX_LEN - 1;2616memcpy(&S.TimerInfo[nTimerIndex].pName, pName, nLen);2617snprintf(&S.TimerInfo[nTimerIndex].pNameExt[0], sizeof(S.TimerInfo[nTimerIndex].pNameExt) - 1, "%s %s", S.GroupInfo[nGroupIndex].pName, pName);2618S.TimerInfo[nTimerIndex].pName[nLen] = '\0';2619S.TimerInfo[nTimerIndex].nNameLen = nLen;2620S.TimerInfo[nTimerIndex].nColor = nColor & 0xffffff;2621S.TimerInfo[nTimerIndex].nGroupIndex = nGroupIndex;2622S.TimerInfo[nTimerIndex].nTimerIndex = nTimerIndex;2623S.TimerInfo[nTimerIndex].nWSNext = -2;2624S.TimerInfo[nTimerIndex].Type = Type;2625S.TimerInfo[nTimerIndex].Flags = Flags;2626// printf("*** TOKEN %08d %s\\%s .. flags %08x\n", nTimerIndex, pGroup, pName, Flags);2627S.TimerToGroup[nTimerIndex] = nGroupIndex;2628return nToken;2629}26302631void MicroProfileGetTokenC(MicroProfileToken* pToken, const char* pGroup, const char* pName, uint32_t nColor, MicroProfileTokenType Type, uint32_t flags)2632{2633if(*pToken == MICROPROFILE_INVALID_TOKEN)2634{2635MicroProfileInit();2636MicroProfileScopeLock L(MicroProfileMutex());2637if(*pToken == MICROPROFILE_INVALID_TOKEN)2638{2639*pToken = MicroProfileGetToken(pGroup, pName, nColor, Type, flags);2640}2641}2642}26432644const char* MicroProfileNextName(const char* pName, char* pNameOut, uint32_t* nSubNameLen)2645{2646int nMaxLen = MICROPROFILE_NAME_MAX_LEN - 1;2647const char* pRet = 0;2648bool bDone = false;2649uint32_t nChars = 0;2650for(int i = 0; i < nMaxLen && !bDone; ++i)2651{2652char c = *pName++;2653switch(c)2654{2655case 0:2656bDone = true;2657break;2658case '\\':2659case '/':2660if(nChars)2661{2662bDone = true;2663pRet = pName;2664}2665break;2666default:2667nChars++;2668*pNameOut++ = c;2669}2670}2671*nSubNameLen = nChars;2672*pNameOut = '\0';2673return pRet;2674}26752676const char* MicroProfileCounterFullName(int nCounter)2677{2678static char Buffer[1024];2679int nNodes[32];2680int nIndex = 0;2681do2682{2683nNodes[nIndex++] = nCounter;2684nCounter = S.CounterInfo[nCounter].nParent;2685} while(nCounter >= 0);2686int nOffset = 0;2687while(nIndex >= 0 && nOffset < (int)sizeof(Buffer) - 2)2688{2689uint32_t nLen = S.CounterInfo[nNodes[nIndex]].nNameLen + nOffset; // < sizeof(Buffer)-12690nLen = MicroProfileMin((uint32_t)(sizeof(Buffer) - 2 - nOffset), nLen);2691memcpy(&Buffer[nOffset], S.CounterInfo[nNodes[nIndex]].pName, nLen);26922693nOffset += S.CounterInfo[nNodes[nIndex]].nNameLen + 1;2694if(nIndex)2695{2696Buffer[nOffset++] = '/';2697}2698nIndex--;2699}2700return &Buffer[0];2701}27022703MicroProfileToken MicroProfileCounterTokenInit(int nParent, uint32_t nFlags)2704{2705MP_ASSERT(0 == (nFlags & (~MICROPROFILE_COUNTER_FLAG_TYPE_MASK)));2706MicroProfileToken nResult = S.nNumCounters++;2707S.CounterInfo[nResult].nParent = nParent;2708S.CounterInfo[nResult].nSibling = -1;2709S.CounterInfo[nResult].nFirstChild = -1;2710S.CounterInfo[nResult].nFlags = nFlags;2711S.CounterInfo[nResult].eFormat = MICROPROFILE_COUNTER_FORMAT_DEFAULT;2712S.CounterInfo[nResult].nLimit = 0;2713S.CounterInfo[nResult].ExternalAtomic = 0;2714S.CounterSource[nResult].pSource = 0;2715S.CounterSource[nResult].nSourceSize = 0;2716S.CounterInfo[nResult].nNameLen = 0;2717S.CounterInfo[nResult].pName = nullptr;2718S.CounterInfo[nResult].nWSNext = -2;2719if(nParent >= 0)2720{2721MP_ASSERT(nParent < (int)S.nNumCounters);2722S.CounterInfo[nResult].nSibling = S.CounterInfo[nParent].nFirstChild;2723S.CounterInfo[nResult].nLevel = S.CounterInfo[nParent].nLevel + 1;2724S.CounterInfo[nParent].nFirstChild = nResult;2725}2726else2727{2728S.CounterInfo[nResult].nLevel = 0;2729}2730return nResult;2731}2732void MicroProfileCounterTokenInitName(MicroProfileToken nToken, const char* pName)2733{2734MP_ASSERT(0 == S.CounterInfo[nToken].pName);2735S.CounterInfo[nToken].nNameLen = (uint16_t)strlen(pName);2736S.CounterInfo[nToken].pName = MicroProfileStringInternLower(pName);2737}27382739MicroProfileToken MicroProfileGetCounterTokenByParent(int nParent, const char* pName, uint32_t nFlags)2740{2741for(uint32_t i = 0; i < S.nNumCounters; ++i)2742{2743if(nParent == S.CounterInfo[i].nParent && S.CounterInfo[i].pName == pName)2744{2745return i;2746}2747}2748if(0 != (MICROPROFILE_COUNTER_FLAG_TOKEN_DONT_CREATE & nFlags))2749return MICROPROFILE_INVALID_TOKEN;2750MicroProfileToken nResult = MicroProfileCounterTokenInit(nParent, nFlags);2751MicroProfileCounterTokenInitName(nResult, pName);2752return nResult;2753}27542755// by passing in last token/parent, and a non-changing static string,2756// we can quickly return in case the parent is the same as before.2757// Note that this doesn't support paths, but instead must be called once per level in the tree2758// String must be preinterned.2759MicroProfileToken MicroProfileCounterTokenTree(MicroProfileToken* LastToken, MicroProfileToken CurrentParent, const char* pString)2760{2761MicroProfileToken Token = *LastToken;2762if(Token != MICROPROFILE_INVALID_TOKEN)2763{2764if(S.CounterInfo[Token].pName == pString && S.CounterInfo[Token].nParent == CurrentParent)2765{2766return Token;2767}2768}2769MicroProfileInit();2770MicroProfileScopeLock L(MicroProfileMutex());2771Token = MicroProfileGetCounterTokenByParent(CurrentParent, pString, 0);2772*LastToken = Token;2773return Token;2774}27752776const char* MicroProfileCounterString(const char* pString)2777{2778MicroProfileInit();2779MicroProfileScopeLock L(MicroProfileMutex());2780return MicroProfileStringInternLower(pString);2781}27822783// Same as above, but works with non-static strings. always takes a lock, and does a search, so expect this to be not cheap2784MicroProfileToken MicroProfileCounterTokenTreeDynamic(MicroProfileToken* LastToken, MicroProfileToken Parent, const char* pString)2785{2786(void)LastToken;2787MicroProfileInit();2788MicroProfileScopeLock L(MicroProfileMutex());2789const char* pSubNameLower = MicroProfileStringInternLower(pString);2790return MicroProfileGetCounterTokenByParent(Parent, pSubNameLower, 0);2791}27922793MicroProfileToken MicroProfileGetCounterToken(const char* pName, uint32_t CounterFlag)2794{2795MicroProfileInit();2796MicroProfileScopeLock L(MicroProfileMutex());2797char SubName[MICROPROFILE_NAME_MAX_LEN];2798MicroProfileToken nResult = MICROPROFILE_INVALID_TOKEN;2799do2800{2801uint32_t nLen = 0;2802pName = MicroProfileNextName(pName, &SubName[0], &nLen);2803if(0 == nLen)2804{2805break;2806}2807const char* pSubNameLower = MicroProfileStringInternLower(SubName);2808nResult = MicroProfileGetCounterTokenByParent(nResult, pSubNameLower, 0);2809if(MICROPROFILE_INVALID_TOKEN == nResult)2810return nResult;28112812} while(pName != 0);2813S.CounterInfo[nResult].nFlags |= MICROPROFILE_COUNTER_FLAG_LEAF;28142815#if MICROPROFILE_COUNTER_HISTORY2816if(CounterFlag & MICROPROFILE_COUNTER_FLAG_DOUBLE)2817{2818S.CounterInfo[nResult].nFlags |= MICROPROFILE_COUNTER_FLAG_DOUBLE;2819S.dCounterMax[nResult] = -DBL_MAX;2820S.dCounterMin[nResult] = DBL_MAX;2821}2822#endif28232824MP_ASSERT((int)nResult >= 0);2825return nResult;2826}28272828MicroProfileToken MicroProfileGetChildCounterToken(MicroProfileToken Parent, const char* pName)2829{2830MP_ASSERT(NULL == strpbrk(pName, "\\/")); // delimiters not supported when manually building the tree.2831return MicroProfileCounterTokenTreeDynamic(nullptr, Parent, pName);2832}28332834inline void MicroProfileLogPut(MicroProfileLogEntry LE, MicroProfileThreadLog* pLog)2835{2836MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called2837MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit2838uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed);2839uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE;2840uint32_t nGet = pLog->nGet.load(std::memory_order_relaxed);2841uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE;2842MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE);2843uint32_t nStackPut = pLog->nStackPut;2844if(nDistance < nStackPut + 2)2845{2846S.nOverflow = 100;2847}2848else2849{2850pLog->Log[nPut] = LE;2851pLog->nPut.store(nNextPos, std::memory_order_release);2852}2853}28542855inline uint64_t MicroProfileLogPutEnter(MicroProfileToken nToken_, uint64_t nTick, MicroProfileThreadLog* pLog)2856{2857MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called2858MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit2859uint32_t nStackPut = pLog->nStackPut;2860if(nStackPut < MICROPROFILE_STACK_MAX)2861{2862uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_ENTER, nToken_, nTick);2863uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed);2864uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE;2865uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);2866uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE;2867MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE);2868if(nDistance < nStackPut + 4) // 2 for ring buffer, 2 for the actual entries2869{2870S.nOverflow = 100;2871return MICROPROFILE_INVALID_TICK;2872}2873else2874{2875#ifdef MICROPROFILE_VERIFY_BALANCED2876pLog->VerifyStack[nStackPut] = LE;2877#endif2878pLog->nStackPut = nStackPut + 1;2879pLog->Log[nPut] = LE;2880pLog->nPut.store(nNextPos, std::memory_order_release);2881return nTick;2882}2883}2884else2885{2886S.nOverflow = 100;2887pLog->nStackPut = nStackPut + 1;2888return MICROPROFILE_DROPPED_TICK;2889}2890}28912892inline uint64_t MicroProfileLogPutEnterCStr(const char* pStr, uint64_t nTick, MicroProfileThreadLog* pLog)2893{2894MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called2895MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit2896uint32_t nStackPut = pLog->nStackPut;2897if(nStackPut < MICROPROFILE_STACK_MAX)2898{2899uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_ENTER, ETOKEN_CSTR_PTR, nTick);2900uint64_t LEStr = MicroProfileMakeLogExtendedNoDataPtr((uint64_t)pStr);29012902MP_ASSERT(ETOKEN_CSTR_PTR == MicroProfileLogGetTimerIndex(LE));29032904uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed);2905uint32_t nNextPos = (nPut + 2) % MICROPROFILE_BUFFER_SIZE;2906uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);2907uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE;2908MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE);2909if(nDistance < nStackPut + 6) // 2 for ring buffer, 4 for the actual entries2910{2911S.nOverflow = 100;2912return MICROPROFILE_INVALID_TICK;2913}2914else2915{2916pLog->nStackPut = nStackPut + 1;2917pLog->Log[nPut + 0] = LE;2918pLog->Log[(nPut + 1) % MICROPROFILE_BUFFER_SIZE] = LEStr;2919pLog->nPut.store(nNextPos, std::memory_order_release);2920return nTick;2921}2922}2923else2924{2925S.nOverflow = 100;2926pLog->nStackPut = nStackPut + 1;2927return MICROPROFILE_DROPPED_TICK;2928}2929}2930inline void MicroProfileLogPutLeaveCStr(const char* pStr, uint64_t nTick, MicroProfileThreadLog* pLog)2931{2932MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called2933MP_ASSERT(pLog->nActive);2934MP_ASSERT(pLog->nStackPut != 0);2935uint32_t nStackPut = --(pLog->nStackPut);2936MP_ASSERT(nStackPut < 0xf0000000);2937if(nStackPut < MICROPROFILE_STACK_MAX)2938{2939uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_LEAVE, ETOKEN_CSTR_PTR, nTick);2940uint64_t LEStr = MicroProfileMakeLogExtendedNoDataPtr((uint64_t)pStr);2941MP_ASSERT(ETOKEN_CSTR_PTR == MicroProfileLogGetTimerIndex(LE));29422943uint32_t nPos = pLog->nPut.load(std::memory_order_relaxed);2944uint32_t nNextPos = (nPos + 2) % MICROPROFILE_BUFFER_SIZE;29452946uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);2947MP_ASSERT(nStackPut < MICROPROFILE_STACK_MAX);2948MP_ASSERT(nNextPos != nGet); // should never happen2949pLog->Log[nPos + 0] = LE;2950pLog->Log[(nPos + 1) % MICROPROFILE_BUFFER_SIZE] = LEStr;29512952pLog->nPut.store(nNextPos, std::memory_order_release);2953}2954}29552956inline void MicroProfileLogPutLeave(MicroProfileToken nToken_, uint64_t nTick, MicroProfileThreadLog* pLog)2957{2958MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called2959MP_ASSERT(pLog->nActive);2960MP_ASSERT(pLog->nStackPut != 0);2961uint32_t nStackPut = --(pLog->nStackPut);2962if(nStackPut < MICROPROFILE_STACK_MAX)2963{2964uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_LEAVE, nToken_, nTick);2965uint32_t nPos = pLog->nPut.load(std::memory_order_relaxed);2966uint32_t nNextPos = (nPos + 1) % MICROPROFILE_BUFFER_SIZE;29672968uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);2969MP_ASSERT(nStackPut < MICROPROFILE_STACK_MAX);2970MP_ASSERT(nNextPos != nGet); // should never happen29712972#ifdef MICROPROFILE_VERIFY_BALANCED2973// verify what we pop is what we push.2974uint64_t Pushed = pLog->VerifyStack[nStackPut];2975uint64_t TimerPopped = MicroProfileLogGetTimerIndex(LE);2976uint64_t TimerOnStack = MicroProfileLogGetTimerIndex(Pushed);2977if(TimerPopped != TimerOnStack)2978{2979uprintf("Push/Pop Mismatch %s vs %s\n", S.TimerInfo[TimerPopped].pName, S.TimerInfo[TimerOnStack].pName);2980MP_ASSERT(0);2981}2982#endif29832984pLog->Log[nPos] = LE;2985pLog->nPut.store(nNextPos, std::memory_order_release);2986}2987}29882989inline void MicroProfileLogPut(MicroProfileToken nToken_, uint64_t nTick, uint64_t nBegin, MicroProfileThreadLog* pLog)2990{2991MicroProfileLogPut(MicroProfileMakeLogIndex(nBegin, nToken_, nTick), pLog);2992}29932994inline void MicroProfileLogPutGpu(MicroProfileLogEntry LE, MicroProfileThreadLogGpu* pLog)2995{2996uint32_t nPos = pLog->nPut;2997if(nPos < MICROPROFILE_GPU_BUFFER_SIZE)2998{2999pLog->Log[nPos] = LE;3000pLog->nPut = nPos + 1;3001}3002}30033004inline void MicroProfileLogPutGpuTimer(MicroProfileToken nToken_, uint64_t nTick, uint64_t nBegin, MicroProfileThreadLogGpu* pLog)3005{3006MicroProfileLogPutGpu(MicroProfileMakeLogIndex(nBegin, nToken_, nTick), pLog);3007}30083009inline void MicroProfileLogPutGpuExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload, MicroProfileThreadLogGpu* pLog)3010{3011MicroProfileLogEntry LE = MicroProfileMakeLogExtended(eTokenExt, nDataSizeQWords, nPayload);3012MicroProfileLogPutGpu(LE, pLog);3013}30143015inline void MicroProfileLogPutGpuExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nPayload, MicroProfileThreadLogGpu* pLog)3016{3017MicroProfileLogEntry LE = MicroProfileMakeLogExtendedNoData(eTokenExt, nPayload);3018MicroProfileLogPutGpu(LE, pLog);3019}30203021uint32_t MicroProfileGroupTokenActive(MicroProfileToken nToken_)3022{3023uint32_t nMask = MicroProfileGetGroupMask(nToken_);3024uint32_t nIndex = MicroProfileGetGroupMaskIndex(nToken_);3025return 0 != (S.nActiveGroups[nIndex] & nMask);3026}30273028uint64_t MicroProfileEnterInternal(MicroProfileToken nToken_)3029{3030if(MicroProfileGroupTokenActive(nToken_))3031{3032uint64_t nTick = MP_TICK();3033if(MICROPROFILE_PLATFORM_MARKERS_ENABLED)3034{3035uint32_t idx = MicroProfileGetTimerIndex(nToken_);3036MicroProfileTimerInfo& TI = S.TimerInfo[idx];3037MICROPROFILE_PLATFORM_MARKER_BEGIN(TI.nColor, TI.pNameExt);3038return nTick;3039}3040else3041{3042return MicroProfileLogPutEnter(nToken_, nTick, MicroProfileGetThreadLog2());3043}3044}3045return MICROPROFILE_INVALID_TICK;3046}30473048uint64_t MicroProfileEnterInternalCStr(const char* pStr)3049{3050if(S.AnyActive)3051{3052uint64_t nTick = MP_TICK();3053if(MICROPROFILE_PLATFORM_MARKERS_ENABLED)3054{3055MICROPROFILE_PLATFORM_MARKER_BEGIN(0, pStr);3056return nTick;3057}3058else3059{3060return MicroProfileLogPutEnterCStr(pStr, nTick, MicroProfileGetThreadLog2());3061}3062}3063return MICROPROFILE_INVALID_TICK;3064}30653066void MicroProfileTimelineLeave(uint32_t id)3067{3068if(!id)3069return;3070std::lock_guard<std::recursive_mutex> Lock(MicroProfileTimelineMutex());3071MicroProfileThreadLog* pLog = &S.TimelineLog;3072uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed);3073uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE;3074uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);3075uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE;30763077{3078uint32_t nFrameStart = S.TimelineTokenFrameEnter[id % MICROPROFILE_TIMELINE_MAX_TOKENS];3079uint32_t nFrameCurrent = S.nFrameCurrent;3080if(nFrameCurrent < nFrameStart)3081nFrameCurrent += MICROPROFILE_MAX_FRAME_HISTORY;3082uint32_t nFrameDistance = (nFrameCurrent - nFrameStart) % MICROPROFILE_MAX_FRAME_HISTORY;30833084S.TimelineTokenFrameEnter[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = MICROPROFILE_INVALID_FRAME;3085S.TimelineTokenFrameLeave[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = nFrameCurrent;30863087S.TimelineToken[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = 0;3088S.nTimelineFrameMax = MicroProfileMax(S.nTimelineFrameMax, nFrameDistance);3089}30903091if(nDistance < 2 + 4)3092{3093S.nOverflow = 100;3094}3095else3096{3097uint64_t LEEnter = MicroProfileMakeLogIndex(MP_LOG_LEAVE, ETOKEN_CUSTOM_NAME, MP_TICK());3098uint64_t LEId = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_ID, 0, id);30993100pLog->Log[nPut++] = LEEnter;3101nPut %= MICROPROFILE_BUFFER_SIZE;3102pLog->Log[nPut++] = LEId;3103nPut %= MICROPROFILE_BUFFER_SIZE;3104pLog->nPut.store(nPut);3105}3106}31073108void MicroProfileTimelineEnterStatic(uint32_t nColor, const char* pStr)3109{3110if(!S.AnyActive)3111return;3112uint32_t nToken = MicroProfileTimelineEnterInternal(nColor, pStr, (uint32_t)strlen(pStr), true);3113(void)nToken;3114}3115void MicroProfileTimelineLeaveStatic(const char* pStr)3116{3117if(!S.AnyActive)3118return;31193120for(uint32_t i = 0; i < MICROPROFILE_TIMELINE_MAX_TOKENS; ++i)3121{3122if(S.TimelineTokenStaticString[i] && 0 == MP_STRCASECMP(pStr, S.TimelineTokenStaticString[i]))3123{3124MicroProfileTimelineLeave(S.TimelineToken[i]);3125}3126}3127}31283129uint32_t MicroProfileTimelineEnterInternal(uint32_t nColor, const char* pStr, uint32_t nStrLen, int bIsStaticString)3130{3131if(!S.AnyActive)3132return 0;3133std::lock_guard<std::recursive_mutex> Lock(MicroProfileTimelineMutex());3134MicroProfileThreadLog* pLog = &S.TimelineLog;3135MP_ASSERT(pStr[nStrLen] == '\0');3136nStrLen += 1;3137uint32_t nStringQwords = MicroProfileGetQWordSize(nStrLen);3138uint32_t nNumMessages = nStringQwords;31393140uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed);3141uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE;3142uint32_t nGet = pLog->nGet.load(std::memory_order_acquire);3143uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE;31443145if(nDistance < nNumMessages + 7)3146{3147S.nOverflow = 100;3148return 0;3149}3150else3151{31523153uint32_t token = pLog->nCustomId;3154uint32_t nFrameLeave = S.TimelineTokenFrameLeave[token % MICROPROFILE_TIMELINE_MAX_TOKENS];3155uint32_t nFrameEnter = S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS];3156uint32_t nCounter = 0;3157uint32_t nFrameCurrent = S.nFrameCurrent;3158{31593160/// dont reuse tokens until their leave command has been dead for the maximum amount of frames we can generate a capture for.3161while(token == 0 || nFrameEnter != MICROPROFILE_INVALID_FRAME || (nFrameCurrent - nFrameLeave < MICROPROFILE_MAX_FRAME_HISTORY + 3 && nFrameLeave != MICROPROFILE_INVALID_FRAME))3162{3163token = (uint32_t)pLog->nCustomId++;3164nFrameLeave = S.TimelineTokenFrameLeave[token % MICROPROFILE_TIMELINE_MAX_TOKENS];3165nFrameEnter = S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS];3166if(++nCounter == MICROPROFILE_TIMELINE_MAX_TOKENS)3167{3168// MP_BREAK();3169return 0;3170}3171}3172S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = S.nFrameCurrent;3173}3174if(bIsStaticString)3175{3176S.TimelineTokenStaticString[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = pStr;3177}3178else3179{3180S.TimelineTokenStaticString[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = nullptr;3181}3182S.TimelineToken[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = token;31833184uint64_t LEEnter = MicroProfileMakeLogIndex(MP_LOG_ENTER, ETOKEN_CUSTOM_NAME, MP_TICK());3185uint64_t LEColor = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_COLOR, 0, nColor);3186uint64_t LEId = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_ID, nStringQwords, token);31873188pLog->Log[nPut++] = LEEnter;3189nPut %= MICROPROFILE_BUFFER_SIZE;3190pLog->Log[nPut++] = LEColor;3191nPut %= MICROPROFILE_BUFFER_SIZE;3192pLog->Log[nPut++] = LEId;3193nPut %= MICROPROFILE_BUFFER_SIZE;31943195// copy if we dont wrap3196if(nPut + nStringQwords <= MICROPROFILE_BUFFER_SIZE)3197{3198memcpy(&pLog->Log[nPut], pStr, nStrLen + 1);3199nPut += nStringQwords;3200}3201else3202{3203int nCharsLeft = (int)nStrLen;3204while(nCharsLeft > 0)3205{3206int nCount = MicroProfileMin(nCharsLeft, 8);3207memcpy(&pLog->Log[nPut++], pStr, nCount);3208// uint64_t LEPayload = MicroProfileMakeLogPayload(pStr, nCount);3209// pLog->Log[nPut++] = LEPayload; nPut %= MICROPROFILE_BUFFER_SIZE;3210pStr += nCount;3211nCharsLeft -= nCount;3212}3213}3214pLog->nPut.store(nPut);3215return token;3216}3217}32183219uint32_t MicroProfileTimelineEnter(uint32_t nColor, const char* pStr)3220{3221return MicroProfileTimelineEnterInternal(nColor, pStr, (uint32_t)strlen(pStr), false);3222}32233224uint32_t MicroProfileTimelineEnterf(uint32_t nColor, const char* pStr, ...)3225{3226if(!S.AnyActive)3227return 0;3228char buffer[MICROPROFILE_MAX_STRING + 1];3229va_list args;3230va_start(args, pStr);3231#ifdef _WIN323232size_t size = vsprintf_s(buffer, pStr, args);3233#else3234size_t size = vsnprintf(buffer, sizeof(buffer) - 1, pStr, args);3235#endif3236va_end(args);3237MP_ASSERT(size < sizeof(buffer));3238buffer[size] = '\0';3239return MicroProfileTimelineEnterInternal(nColor, buffer, (uint32_t)size, false);3240}32413242void MicroProfileLocalCounterAdd(int64_t* pCounter, int64_t nCount)3243{3244*pCounter += nCount;3245}3246int64_t MicroProfileLocalCounterSet(int64_t* pCounter, int64_t nCount)3247{3248int64_t r = *pCounter;3249*pCounter = nCount;3250return r;3251}32523253void MicroProfileLocalCounterAddAtomic(MicroProfileToken nToken, int64_t nCount)3254{3255std::atomic<int64_t>* pCounter = &S.CounterInfo[nToken].ExternalAtomic;3256pCounter->fetch_add(nCount);3257}3258int64_t MicroProfileLocalCounterSetAtomic(MicroProfileToken nToken, int64_t nCount)3259{32603261std::atomic<int64_t>* pCounter = &S.CounterInfo[nToken].ExternalAtomic;3262return pCounter->exchange(nCount);3263}32643265void MicroProfileCounterAdd(MicroProfileToken nToken, int64_t nCount)3266{3267MP_ASSERT(nToken < S.nNumCounters);3268S.Counters[nToken].fetch_add(nCount);3269}3270void MicroProfileCounterSet(MicroProfileToken nToken, int64_t nCount)3271{3272MP_ASSERT(nToken < S.nNumCounters);3273S.Counters[nToken].store(nCount);3274}3275int64_t MicroProfileCounterGet(MicroProfileToken nToken)3276{3277MP_ASSERT(nToken < S.nNumCounters);3278return S.Counters[nToken].load();3279}32803281void MicroProfileCounterSetDouble(MicroProfileToken nToken, double nCount)3282{3283MP_ASSERT(nToken < S.nNumCounters);3284MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE);3285S.CountersDouble[nToken].store(nCount);3286}3287double MicroProfileCounterGetDouble(MicroProfileToken nToken)3288{3289MP_ASSERT(nToken < S.nNumCounters);3290MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE);3291return S.CountersDouble[nToken].load();3292}3293void MicroProfileCounterSetLimit(MicroProfileToken nToken, int64_t nCount)3294{3295MP_ASSERT(nToken < S.nNumCounters);3296S.CounterInfo[nToken].nLimit = nCount;3297}32983299void MicroProfileCounterSetLimitDouble(MicroProfileToken nToken, double dCount)3300{3301MP_ASSERT(nToken < S.nNumCounters);3302MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE);3303S.CounterInfo[nToken].dLimit = dCount;3304}33053306void MicroProfileCounterConfigToken(MicroProfileToken nToken, uint32_t eFormat, int64_t nLimit, uint32_t nFlags)3307{3308S.CounterInfo[nToken].eFormat = (MicroProfileCounterFormat)eFormat;3309S.CounterInfo[nToken].nLimit = nLimit;3310S.CounterInfo[nToken].nFlags |= (nFlags & ~MICROPROFILE_COUNTER_FLAG_INTERNAL_MASK);3311}33123313void MicroProfileCounterConfig(const char* pName, uint32_t eFormat, int64_t nLimit, uint32_t nFlags)3314{3315MicroProfileToken nToken = MicroProfileGetCounterToken(pName, 0);3316MicroProfileCounterConfigToken(nToken, eFormat, nLimit, nFlags);3317}33183319void MicroProfileCounterSetPtr(const char* pCounterName, void* pSource, uint32_t nSize)3320{3321MicroProfileToken nToken = MicroProfileGetCounterToken(pCounterName, 0);3322S.CounterSource[nToken].pSource = pSource;3323S.CounterSource[nToken].nSourceSize = nSize;3324}33253326inline void MicroProfileFetchCounter(uint32_t i)3327{3328MP_ASSERT(0 == S.CounterSource[i].nSourceSize || (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE);3329switch(S.CounterSource[i].nSourceSize)3330{3331case sizeof(int32_t):3332S.Counters[i] = *(int32_t*)S.CounterSource[i].pSource;3333break;3334case sizeof(int64_t):3335S.Counters[i] = *(int64_t*)S.CounterSource[i].pSource;3336break;3337default:3338break;3339}3340}3341void MicroProfileCounterFetchCounters()3342{3343for(uint32_t i = 0; i < S.nNumCounters; ++i)3344{3345MicroProfileFetchCounter(i);3346}3347}33483349void MicroProfileLeaveInternal(MicroProfileToken nToken_, uint64_t nTickStart)3350{3351if(MICROPROFILE_INVALID_TICK != nTickStart)3352{3353if(MICROPROFILE_PLATFORM_MARKERS_ENABLED)3354{3355MICROPROFILE_PLATFORM_MARKER_END();3356}3357else3358{3359uint64_t nTick = MP_TICK();3360MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();3361MicroProfileLogPutLeave(nToken_, nTick, pLog);3362}3363}3364}33653366void MicroProfileLeaveInternalCStr(const char* pStr, uint64_t nTickStart)3367{3368if(MICROPROFILE_INVALID_TICK != nTickStart)3369{3370if(MICROPROFILE_PLATFORM_MARKERS_ENABLED)3371{3372MICROPROFILE_PLATFORM_MARKER_END();3373}3374else3375{3376uint64_t nTick = MP_TICK();3377MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();3378MicroProfileLogPutLeaveCStr(pStr, nTick, pLog);3379}3380}3381}33823383void MicroProfileEnter(MicroProfileToken nToken)3384{3385MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();3386MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers3387uint32_t nStackPos = pLog->nStackScope++;3388if(nStackPos < MICROPROFILE_STACK_MAX)3389{3390MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos];3391pScopeState->Token = nToken;3392pScopeState->nTick = MicroProfileEnterInternal(nToken);3393}3394else3395{3396S.nOverflow = 100;3397}3398}3399void MicroProfileLeave()3400{3401MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();3402MP_ASSERT(pLog->nStackScope > 0); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers3403uint32_t nStackPos = --pLog->nStackScope;3404if(nStackPos < MICROPROFILE_STACK_MAX)3405{3406MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos];3407MicroProfileLeaveInternal(pScopeState->Token, pScopeState->nTick);3408}3409else3410{3411S.nOverflow = 100;3412}3413}34143415void MicroProfileEnterGpu(MicroProfileToken nToken, MicroProfileThreadLogGpu* pLog)3416{3417// MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers3418uint32_t nStackPos = pLog->nStackScope++;3419if(nStackPos < MICROPROFILE_STACK_MAX)3420{3421MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos];3422pScopeState->Token = nToken;3423pScopeState->nTick = MicroProfileGpuEnterInternal(pLog, nToken);3424}3425else3426{3427S.nOverflow = 100;3428}3429}3430void MicroProfileLeaveGpu(MicroProfileThreadLogGpu* pLog)3431{3432uint32_t nStackPos = --pLog->nStackScope;3433if(nStackPos < MICROPROFILE_STACK_MAX)3434{3435MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos];3436MicroProfileGpuLeaveInternal(pLog, pScopeState->Token, pScopeState->nTick);3437}3438}34393440void MicroProfileGpuBegin(void* pContext, MicroProfileThreadLogGpu* pLog)3441{3442MP_ASSERT(pLog->pContext == (void*)-1); // dont call begin without calling end3443MP_ASSERT(pLog->nStart == (uint32_t)-1);3444MP_ASSERT(pContext != (void*)-1);34453446pLog->pContext = pContext;3447pLog->nStart = pLog->nPut;3448MicroProfileLogPutGpu(0, pLog);3449}34503451void MicroProfileGpuSetContext(void* pContext, MicroProfileThreadLogGpu* pLog)3452{3453MP_ASSERT(pLog->pContext != (void*)-1); // dont call begin without calling end3454MP_ASSERT(pLog->nStart != (uint32_t)-1);3455pLog->pContext = pContext;3456}34573458uint64_t MicroProfileGpuEnd(MicroProfileThreadLogGpu* pLog)3459{3460uint64_t nStart = pLog->nStart;3461uint32_t nEnd = pLog->nPut;3462uint64_t nId = pLog->nId;3463if(nStart < MICROPROFILE_GPU_BUFFER_SIZE)3464{3465pLog->Log[nStart] = nEnd - nStart - 1;3466}3467pLog->pContext = (void*)-1;3468pLog->nStart = (uint32_t)-1;3469return nStart | (nId << 32);3470}34713472void MicroProfileGpuSubmit(int nQueue, uint64_t nWork)3473{3474MP_ASSERT(nQueue >= 0 && nQueue < MICROPROFILE_MAX_THREADS);3475MICROPROFILE_SCOPE(g_MicroProfileGpuSubmit);3476uint32_t nStart = (uint32_t)nWork;3477uint32_t nThreadLog = uint32_t(nWork >> 32);34783479MicroProfileThreadLog* pQueueLog = S.Pool[nQueue];3480MP_ASSERT(nQueue < MICROPROFILE_MAX_THREADS);3481MicroProfileThreadLogGpu* pGpuLog = S.PoolGpu[nThreadLog];3482MP_ASSERT(pGpuLog);34833484int64_t nCount = 0;3485if(nStart < MICROPROFILE_GPU_BUFFER_SIZE)3486{3487nCount = pGpuLog->Log[nStart];3488}3489MP_ASSERT(nCount < (int64_t)MICROPROFILE_GPU_BUFFER_SIZE);3490nStart++;3491for(int32_t i = 0; i < nCount; ++i)3492{3493MP_ASSERT(nStart < MICROPROFILE_GPU_BUFFER_SIZE);3494MicroProfileLogEntry LE = pGpuLog->Log[nStart++];3495MicroProfileLogPut(LE, pQueueLog);3496}3497}34983499uint64_t MicroProfileGpuEnterInternal(MicroProfileThreadLogGpu* pGpuLog, MicroProfileToken nToken_)3500{3501if(MicroProfileGroupTokenActive(nToken_))3502{3503if(!MicroProfileGetThreadLog())3504{3505MicroProfileInitThreadLog();3506}35073508MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3509uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3510MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_ENTER, pGpuLog);3511MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();35123513MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog);3514MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog);3515// MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3516// uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3517// MicroProfileLogPutGpu(nToken_, nTimer, MP_LOG_ENTER, pGpuLog);3518// MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();3519// MicroProfileLogPutGpu(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), MP_LOG_EXTRA_DATA, pGpuLog);3520// MicroProfileLogPutGpu(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, MP_LOG_EXTRA_DATA, pGpuLog);35213522return 1;3523}3524return 0;3525}35263527uint64_t MicroProfileGpuEnterInternalCStr(MicroProfileThreadLogGpu* pGpuLog, const char* pStr)3528{3529MP_BREAK(); // not implemented3530return 0;3531// if(S.AnyGpuActive)3532// {3533// if(!MicroProfileGetThreadLog())3534// {3535// MicroProfileInitThreadLog();3536// }35373538// MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3539// uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3540// MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_ENTER, pGpuLog);3541// MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();35423543// MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog);3544// MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog);3545// // MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3546// // uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3547// // MicroProfileLogPutGpu(nToken_, nTimer, MP_LOG_ENTER, pGpuLog);3548// // MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();3549// // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), MP_LOG_EXTRA_DATA, pGpuLog);3550// // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, MP_LOG_EXTRA_DATA, pGpuLog);35513552// return 1;3553// }3554// return 0;3555}35563557void MicroProfileGpuLeaveInternal(MicroProfileThreadLogGpu* pGpuLog, MicroProfileToken nToken_, uint64_t nTickStart)3558{3559if(nTickStart)3560{3561if(!MicroProfileGetThreadLog())3562{3563MicroProfileInitThreadLog();3564}35653566MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3567uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3568MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_LEAVE, pGpuLog);3569MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();3570MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog);3571MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog);3572}3573}35743575void MicroProfileGpuLeaveInternalCStr(MicroProfileThreadLogGpu* pGpuLog, uint64_t nTickStart)3576{3577MP_BREAK(); // not implemented3578return;3579// if(nTickStart)3580// {3581// if(!MicroProfileGetThreadLog())3582// {3583// MicroProfileInitThreadLog();3584// }35853586// MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd3587// uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext);3588// MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_LEAVE, pGpuLog);3589// MicroProfileThreadLog* pLog = MicroProfileGetThreadLog();3590// MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog);3591// MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog);3592// }3593}35943595void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)3596{3597if(0 == S.nPauseTicks || (S.nPauseTicks - pContextSwitch->nTicks) > 0)3598{3599uint32_t nPut = S.nContextSwitchPut;3600S.ContextSwitch[nPut] = *pContextSwitch;3601S.nContextSwitchPut = (S.nContextSwitchPut + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;3602// if(S.nContextSwitchPut < nPut)3603//{3604// float fMsDelay = MicroProfileTickToMsMultiplierCpu() * ((int64_t)S.nFlipStartTick - pContextSwitch->nTicks);3605// uprintf("context switch wrap .. %7.3fms\n", fMsDelay);3606// }3607// if(S.nContextSwitchPut % 1024 == 0)3608//{3609// float fMsDelay = MicroProfileTickToMsMultiplierCpu() * ((int64_t)S.nFlipStartTick - pContextSwitch->nTicks);3610// uprintf("cswitch tick %x ... %7.3fms\n", S.nContextSwitchPut, fMsDelay);3611// }3612S.nContextSwitchLastPushed = pContextSwitch->nTicks;3613}3614else3615{3616S.nContextSwitchStalledTick = MP_TICK();3617}3618}36193620void MicroProfileGetRange(uint32_t nPut, uint32_t nGet, uint32_t nRange[2][2])3621{3622if(nPut > nGet)3623{3624nRange[0][0] = nGet;3625nRange[0][1] = nPut;3626nRange[1][0] = nRange[1][1] = 0;3627}3628else if(nPut != nGet)3629{3630MP_ASSERT(nGet != MICROPROFILE_BUFFER_SIZE);3631uint32_t nCountEnd = MICROPROFILE_BUFFER_SIZE - nGet;3632nRange[0][0] = nGet;3633nRange[0][1] = nGet + nCountEnd;3634nRange[1][0] = 0;3635nRange[1][1] = nPut;3636}3637}36383639void MicroProfileToggleFrozen()3640{3641S.nFrozen = !S.nFrozen;3642}36433644int MicroProfileIsFrozen()3645{3646return S.nFrozen != 0 ? 1 : 0;3647}3648int MicroProfileEnabled()3649{3650return MicroProfileAnyGroupActive();3651}3652void* MicroProfileAllocInternal(size_t nSize, size_t nAlign)3653{3654nAlign = MicroProfileMax(4 * sizeof(uint32_t), nAlign);3655nSize += nAlign;3656intptr_t nPtr = (intptr_t)MICROPROFILE_ALLOC(nSize, nAlign);3657nPtr += nAlign;3658uint32_t* pVal = (uint32_t*)nPtr;3659MP_ASSERT(nSize < 0xffffffff);3660MP_ASSERT(nAlign < 0xffffffff);3661pVal[-1] = (uint32_t)nSize;3662pVal[-2] = (uint32_t)nAlign;3663pVal[-3] = (uint32_t)0x28586813;3664MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize);3665MicroProfileCounterAdd(S.CounterToken_Alloc_Count, 1);3666return (void*)nPtr;3667}3668void MicroProfileFreeInternal(void* pPtr)3669{3670intptr_t p = (intptr_t)pPtr;3671uint32_t* p4 = (uint32_t*)pPtr;3672uint32_t nSize = p4[-1];3673uint32_t nAlign = p4[-2];3674uint32_t nMagic = p4[-3];3675MP_ASSERT(nMagic == 0x28586813);3676MICROPROFILE_FREE((void*)(p - nAlign));3677MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, -(int)nSize);3678MicroProfileCounterAdd(S.CounterToken_Alloc_Count, -1);3679}3680void* MicroProfileReallocInternal(void* pPtr, size_t nSize)3681{3682intptr_t p = (intptr_t)pPtr;3683uint32_t nAlignBase;36843685if(p)3686{3687uint32_t* p4 = (uint32_t*)pPtr;3688uint32_t nSizeBase = p4[-1];3689nAlignBase = p4[-2];3690uint32_t nMagicBase = p4[-3];3691MP_ASSERT(nMagicBase == 0x28586813);36923693MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize - nSizeBase);3694}3695else3696{3697nAlignBase = 4 * sizeof(uint32_t);3698MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize + nAlignBase);3699MicroProfileCounterAdd(S.CounterToken_Alloc_Count, 1);3700}37013702nSize += nAlignBase;3703MP_ASSERT(nAlignBase >= 4 * sizeof(uint32_t));3704if(p)3705{3706p = (intptr_t)MICROPROFILE_REALLOC((void*)(p - nAlignBase), nSize);3707}3708else3709{3710p = (intptr_t)MICROPROFILE_REALLOC((void*)(p), nSize);3711}3712p += nAlignBase;3713uint32_t* pVal = (uint32_t*)p;3714MP_ASSERT(nSize < 0xffffffff);3715MP_ASSERT(nAlignBase < 0xffffffff);3716pVal[-1] = (uint32_t)nSize;3717pVal[-2] = (uint32_t)nAlignBase;3718pVal[-3] = (uint32_t)0x28586813;3719return (void*)p;3720}37213722static void MicroProfileFlipEnabled()3723{3724if(S.nFrozen)3725{3726memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups));3727S.AnyActive = false;3728}3729else3730{3731bool AnyActive = false;3732for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)3733{3734uint32_t nNew = S.nActiveGroupsWanted[i];3735nNew |= S.nForceGroups[i];3736if(nNew)3737AnyActive = true;3738if(S.nActiveGroups[i] != nNew)3739{3740S.nActiveGroups[i] = nNew;3741}3742}3743S.AnyActive = AnyActive;3744}3745}37463747void MicroProfileFlip(void* pContext, uint32_t FlipFlag)3748{3749MicroProfileFlip_CB(pContext, nullptr, FlipFlag);3750}37513752#define MICROPROFILE_TICK_VALIDATE_FRAME_TIME 037533754void MicroProfileFlip_CB(void* pContext, MicroProfileOnFreeze FreezeCB, uint32_t FlipFlag)3755{3756MICROPROFILE_COUNTER_LOCAL_UPDATE_SET_ATOMIC(g_MicroProfileBytesPerFlip);3757#if 03758//verify LogEntry wraps correctly3759MicroProfileLogEntry c = MP_LOG_TICK_MASK-5000;3760for(int i = 0; i < 10000; ++i, c += 1)3761{3762MicroProfileLogEntry l2 = (c+2500) & MP_LOG_TICK_MASK;3763MP_ASSERT(2500 == MicroProfileLogTickDifference(c, l2));3764}3765#endif3766MICROPROFILE_SCOPE(g_MicroProfileFlip);3767std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());37683769if(S.nDumpFileNextFrame)3770{3771if(0 == S.nDumpFileCountDown)3772{3773MicroProfileDumpToFile();3774S.nDumpFileNextFrame = 0;3775S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; // hide spike from dumping webpage3776}3777else3778{3779S.nDumpFileCountDown--;3780}3781}3782#if MICROPROFILE_WEBSERVER3783if(MICROPROFILE_FLIP_FLAG_START_WEBSERVER == (MICROPROFILE_FLIP_FLAG_START_WEBSERVER & FlipFlag) && S.nWebServerDataSent == (uint64_t)-1)3784{3785MicroProfileWebServerStart();3786S.nWebServerDataSent = 0;3787if(!S.WebSocketThreadRunning)3788{3789S.WebSocketThreadRunning = 1;3790MicroProfileThreadStart(&S.WebSocketSendThread, MicroProfileSocketSenderThread);3791}3792}3793#endif37943795int nLoop = 0;3796do3797{3798#if MICROPROFILE_WEBSERVER3799if(MicroProfileWebServerUpdate())3800{3801S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; // hide spike from dumping webpage3802}3803#endif3804if(nLoop++)3805{3806MicroProfileSleep(100);3807if((nLoop % 10) == 0)3808{3809uprintf("microprofile frozen %d\n", nLoop);3810}3811}3812} while(S.nFrozen);38133814uint32_t nAggregateClear = S.nAggregateClear || S.nAutoClearFrames, nAggregateFlip = 0;38153816if(S.nAutoClearFrames)3817{3818nAggregateClear = 1;3819nAggregateFlip = 1;3820S.nAutoClearFrames -= 1;3821}38223823bool nRunning = MicroProfileAnyGroupActive();3824if(nRunning)3825{3826S.nFlipStartTick = MP_TICK();3827int64_t nGpuWork = MicroProfileGpuEnd(S.pGpuGlobal);3828MicroProfileGpuSubmit(S.GpuQueue, nGpuWork);3829MicroProfileThreadLogGpuReset(S.pGpuGlobal);3830for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)3831{3832if(S.PoolGpu[i])3833{3834S.PoolGpu[i]->nPut = 0;3835}3836}38373838MicroProfileGpuBegin(pContext, S.pGpuGlobal);38393840uint32_t nGpuTimeStamp = MicroProfileGpuFlip(pContext);38413842uint64_t nFrameIdx = S.nFramePutIndex++;3843S.nFramePut = (S.nFramePut + 1) % MICROPROFILE_MAX_FRAME_HISTORY;3844S.Frames[S.nFramePut].nFrameId = nFrameIdx;3845MP_ASSERT((S.nFramePutIndex % MICROPROFILE_MAX_FRAME_HISTORY) == S.nFramePut);3846S.nFrameCurrent = (S.nFramePut + MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 1) % MICROPROFILE_MAX_FRAME_HISTORY;3847S.nFrameCurrentIndex++;3848uint32_t nFrameNext = (S.nFrameCurrent + 1) % MICROPROFILE_MAX_FRAME_HISTORY;3849S.nFrameNext = nFrameNext;38503851uint32_t nContextSwitchPut = S.nContextSwitchPut;3852if(S.nContextSwitchLastPut < nContextSwitchPut)3853{3854S.nContextSwitchUsage = (nContextSwitchPut - S.nContextSwitchLastPut);3855}3856else3857{3858S.nContextSwitchUsage = MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - S.nContextSwitchLastPut + nContextSwitchPut;3859}3860S.nContextSwitchLastPut = nContextSwitchPut;38613862MicroProfileFrameState* pFramePut = &S.Frames[S.nFramePut];3863MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];3864MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];3865const int64_t nTickStartFrame = pFrameCurrent->nFrameStartCpu;3866const int64_t nTickEndFrame = pFrameNext->nFrameStartCpu;38673868pFrameCurrent->nGpuPending = 0;3869pFramePut->nGpuPending = 1;38703871pFramePut->nFrameStartCpu = MP_TICK();38723873pFramePut->nFrameStartGpu = nGpuTimeStamp;3874{3875const float fDumpTimeThreshold = 1000.f * 60 * 60 * 24 * 365.f; // if time above this, then we're handling uninitialized counters3876int nDumpNextFrame = 0;3877float fTimeGpu = 0.f;3878if(pFrameNext->nFrameStartGpu != MICROPROFILE_INVALID_TICK)3879{38803881uint64_t nTickCurrent = pFrameCurrent->nFrameStartGpu;3882uint64_t nTickNext = pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);3883nTickCurrent = MicroProfileLogTickMin(nTickCurrent, nTickNext);3884float fTime = 1000.f * (nTickNext - nTickCurrent) / (MicroProfileTicksPerSecondGpu());3885fTime = fTimeGpu;3886if(S.fDumpGpuSpike > 0.f && fTime > S.fDumpGpuSpike && fTime < fDumpTimeThreshold)3887{3888nDumpNextFrame = 1;3889}3890}3891float fTimeCpu = 1000.f * (pFrameNext->nFrameStartCpu - pFrameCurrent->nFrameStartCpu) / MicroProfileTicksPerSecondCpu();3892if(S.fDumpCpuSpike > 0.f && fTimeCpu > S.fDumpCpuSpike && fTimeCpu < fDumpTimeThreshold)3893{3894nDumpNextFrame = 1;3895}3896if(nDumpNextFrame)3897{3898S.nDumpFileNextFrame = S.nDumpSpikeMask;3899S.nDumpSpikeMask = 0;3900S.nDumpFileCountDown = 5;3901}3902}39033904const uint64_t nTickEndFrameGpu_ = pFrameNext->nFrameStartGpu;3905const uint64_t nTickStartFrameGpu_ = pFrameCurrent->nFrameStartGpu;3906const bool bGpuFrameInvalid = nTickEndFrameGpu_ == MICROPROFILE_INVALID_TICK || nTickStartFrameGpu_ == MICROPROFILE_INVALID_TICK;3907const uint64_t nTickEndFrameGpu = bGpuFrameInvalid ? 1 : nTickEndFrameGpu_;3908const uint64_t nTickStartFrameGpu = bGpuFrameInvalid ? 2 : nTickStartFrameGpu_;39093910MicroProfileFrameExtraCounterData* ExtraData = S.FrameExtraCounterData;3911bool UsingExtraData = false;3912if(ExtraData)3913{3914if((intptr_t)ExtraData == 1)3915{3916size_t Bytes = sizeof(MicroProfileFrameExtraCounterData) * MICROPROFILE_MAX_FRAME_HISTORY;3917printf(" allocating %d bytes %f\n", (int)Bytes, Bytes / (1024.0 * 1024.0));3918ExtraData = S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)MicroProfileAllocInternal(Bytes, alignof(uint64_t));3919memset(ExtraData, 0, Bytes);3920}3921ExtraData = ExtraData + S.nFrameCurrent;3922UsingExtraData = true;3923}3924#define MP_ASSERT_LE_WRAP(l, g) MP_ASSERT(uint64_t(g - l) < 0x8000000000000000)39253926{3927MP_ASSERT_LE_WRAP(nTickStartFrame, nTickEndFrame);3928uint64_t nTick = nTickEndFrame - nTickStartFrame;3929S.nFlipTicks = nTick;3930S.nFlipAggregate += nTick;3931S.nFlipMax = MicroProfileMax(S.nFlipMax, nTick);3932}39333934uint32_t* pTimerToGroup = &S.TimerToGroup[0];3935for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)3936{3937MicroProfileThreadLog* pLog = S.Pool[i];3938if(!pLog)3939{3940pFramePut->nLogStart[i] = 0;3941}3942else3943{3944uint32_t nPut = pLog->nPut.load(std::memory_order_acquire);3945pFramePut->nLogStart[i] = nPut;3946if(!pLog->nGpu)3947{3948uint32_t nStart = pFrameCurrent->nLogStart[i];3949while(nStart != nPut)3950{3951int64_t LE = pLog->Log[nStart];3952int64_t nDifference = MicroProfileLogTickDifference(LE, nTickEndFrame);3953uint32_t Ext = MicroProfileLogGetType(LE);3954if(nDifference > 0 || 0 != (0x2 & Ext))3955{3956nStart = (nStart + 1) % MICROPROFILE_BUFFER_SIZE;3957}3958else3959{3960break;3961}3962}3963pFrameNext->nLogStart[i] = nStart;3964}3965}3966}3967{3968pFramePut->nLogStartTimeline = S.TimelineLog.nPut.load(std::memory_order_acquire);39693970uint32_t nFrameCurrent = S.nFrameCurrent;3971uint32_t nTimelineFrameDeltaMax = S.nTimelineFrameMax;3972for(uint32_t i = 0; i != MICROPROFILE_TIMELINE_MAX_TOKENS; ++i)3973{3974uint32_t nFrameStart = S.TimelineTokenFrameEnter[i];3975if(nFrameStart != MICROPROFILE_INVALID_FRAME)3976{3977uint32_t nCur = nFrameCurrent;3978if(nCur < nFrameStart)3979nCur += MICROPROFILE_MAX_FRAME_HISTORY;3980if(nCur >= nFrameStart)3981{3982uint32_t D = nCur - nFrameStart;3983nTimelineFrameDeltaMax = MicroProfileMax(nTimelineFrameDeltaMax, D);3984}3985}3986}3987pFramePut->nTimelineFrameMax = nTimelineFrameDeltaMax;3988S.nTimelineFrameMax = 0;3989}3990{3991for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)3992{3993MicroProfileThreadLog* pLog = S.Pool[i];3994if(!pLog)3995continue;3996if(pLog->nGpu)3997{3998uint32_t nPut = pFrameNext->nLogStart[i];3999uint32_t nGet = pFrameCurrent->nLogStart[i];4000uint32_t nRange[2][2] = {4001{ 0, 0 },4002{ 0, 0 },4003};4004MicroProfileGetRange(nPut, nGet, nRange);4005for(uint32_t j = 0; j < 2; ++j)4006{4007uint32_t nStart = nRange[j][0];4008uint32_t nEnd = nRange[j][1];4009for(uint32_t k = nStart; k < nEnd; ++k)4010{4011MicroProfileLogEntry L = pLog->Log[k];4012if(MicroProfileLogGetType(L) < MP_LOG_EXTENDED)4013{4014pLog->Log[k] = MicroProfileLogSetTick(L, MicroProfileGpuGetTimeStamp((uint32_t)MicroProfileLogGetTick(L)));4015}4016k += MicroProfileLogGetDataSize(L);4017}4018}4019}4020}4021}40224023{4024MicroProfile::GroupTime* pFrameGroup = &S.FrameGroup[0];4025{4026MICROPROFILE_SCOPE(g_MicroProfileClear);4027for(uint32_t i = 0; i < S.nTotalTimers; ++i)4028{4029S.Frame[i].nTicks = 0;4030S.Frame[i].nCount = 0;4031S.FrameExclusive[i] = 0;4032}4033for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)4034{4035pFrameGroup[i].nTicks = 0;4036pFrameGroup[i].nTicksExclusive = 0;4037pFrameGroup[i].nCount = 0;4038}4039}4040{4041MICROPROFILE_SCOPE(g_MicroProfileThreadLoop);4042memset(S.FrameGroupThreadValid, 0, sizeof(S.FrameGroupThreadValid));40434044for(uint32_t idx_thread = 0; idx_thread < MICROPROFILE_MAX_THREADS; ++idx_thread)4045{4046MicroProfileThreadLog* pLog = S.Pool[idx_thread];4047if(!pLog)4048continue;4049bool bGpu = pLog->nGpu != 0;4050int64_t nTickStartLog = bGpu ? nTickStartFrameGpu : nTickStartFrame;4051int64_t nTickEndLog = bGpu ? nTickEndFrameGpu : nTickEndFrame;40524053float fToMs = bGpu ? MicroProfileTickToMsMultiplierGpu() : MicroProfileTickToMsMultiplierCpu();4054float fFrameTime = fToMs * (nTickEndLog - nTickStartLog);40554056MicroProfile::GroupTime* pFrameGroupThread = &S.FrameGroupThread[idx_thread][0];40574058uint32_t nPut = pFrameNext->nLogStart[idx_thread];4059uint32_t nGet = pFrameCurrent->nLogStart[idx_thread];4060uint32_t nRange[2][2] = {4061{ 0, 0 },4062{ 0, 0 },4063};4064MicroProfileGetRange(nPut, nGet, nRange);4065if(nPut != nGet)4066{4067S.FrameGroupThreadValid[idx_thread / 32] |= 1 << (idx_thread % 32);4068memset(pFrameGroupThread, 0, sizeof(S.FrameGroupThread[idx_thread]));4069}40704071uint64_t* pStackLog = &pLog->nStackLogEntry[0];4072uint64_t* pChildTickStack = &pLog->nChildTickStack[1];4073int32_t nStackPos = pLog->nStackPos;4074uint8_t TimerStackPos[MICROPROFILE_MAX_TIMERS];4075uint8_t GroupStackPos[MICROPROFILE_MAX_GROUPS];4076memset(TimerStackPos, 0, sizeof(TimerStackPos));4077memset(GroupStackPos, 0, sizeof(GroupStackPos));40784079// restore group and timer stack pos.4080for(int32_t i = 0; i < nStackPos; ++i)4081{4082uint64_t nTimer = MicroProfileLogGetTimerIndex(pStackLog[i]);4083uint32_t nGroup = pTimerToGroup[nTimer];4084MP_ASSERT(nTimer < MICROPROFILE_MAX_TIMERS);4085MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);4086TimerStackPos[nTimer]++;4087GroupStackPos[nGroup]++;4088}40894090for(uint32_t j = 0; j < 2; ++j)4091{4092uint32_t nStart = nRange[j][0];4093uint32_t nEnd = nRange[j][1];4094for(uint32_t k = nStart; k < nEnd; ++k)4095{4096MicroProfileLogEntry LE = pLog->Log[k];4097uint32_t nType = MicroProfileLogGetType(LE);40984099switch(nType)4100{4101case MP_LOG_ENTER:4102{4103uint64_t nTimer = MicroProfileLogGetTimerIndex(LE);4104if(nTimer != ETOKEN_CSTR_PTR)4105{4106MP_ASSERT(nTimer < S.nTotalTimers);4107uint32_t nGroup = pTimerToGroup[nTimer];4108MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);4109MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);41104111// When we aggretate the total time, we have to count if the timers & groups are layered, to avoid summing them twice when calculating the total time.4112// Averages become nonsense regardless.4113TimerStackPos[nTimer]++;4114GroupStackPos[nGroup]++;41154116pStackLog[nStackPos] = LE;41174118pChildTickStack[nStackPos] = 0;4119nStackPos++;4120}4121break;4122}4123case MP_LOG_LEAVE:4124{4125uint64_t nTimer = MicroProfileLogGetTimerIndex(LE);4126if(nTimer != ETOKEN_CSTR_PTR)4127{4128MP_ASSERT(nTimer < S.nTotalTimers);4129uint32_t nGroup = pTimerToGroup[nTimer];4130MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);4131MP_ASSERT(nStackPos);4132uint64_t nTicks;4133bool bGroupRoot = 0 == GroupStackPos[nGroup] || 0 == --GroupStackPos[nGroup];4134bool bTimerRoot = 0 == TimerStackPos[nTimer] || 0 == --TimerStackPos[nTimer];4135{4136nStackPos--;4137MicroProfileLogEntry LEStack = pStackLog[nStackPos];4138MP_ASSERT(MicroProfileLogGetTimerIndex(LEStack) == nTimer); // unbalanced timers are not supported4139uint64_t nTickStart = MicroProfileLogTickClamp(LEStack, nTickStartLog, nTickEndLog);4140uint64_t nClamped = MicroProfileLogTickClamp(LE, nTickStartLog, nTickEndLog);4141nTicks = MicroProfileLogTickDifference(nTickStart, nClamped);4142MP_ASSERT(nTicks < 0x8000000000000000);41434144uint64_t nChildTicks = pChildTickStack[nStackPos];41454146MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);4147if(nStackPos)4148{4149pChildTickStack[nStackPos - 1] += nTicks;4150}4151MP_ASSERT(nTicks >= nChildTicks);4152uint64_t nTicksExclusive = (nTicks - nChildTicks);4153S.FrameExclusive[nTimer] += nTicksExclusive;4154pFrameGroupThread[nGroup].nTicksExclusive += nTicksExclusive;4155if(bTimerRoot) // dont count this if its below another instance of the same timer.4156{4157S.Frame[nTimer].nTicks += nTicks;4158S.Frame[nTimer].nCount += 1;4159MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);4160if(bGroupRoot)4161{4162pFrameGroupThread[nGroup].nTicks += nTicks;4163pFrameGroupThread[nGroup].nCount += 1;4164}4165}4166}4167}4168break;4169}4170case MP_LOG_EXTENDED:4171{4172k += MicroProfileLogGetDataSize(LE);4173break;4174}4175case MP_LOG_EXTENDED_NO_DATA:4176break;4177}4178}4179}41804181for(int32_t i = nStackPos - 1; i >= 0; --i)4182{41834184MicroProfileLogEntry LE = pStackLog[i];4185uint64_t nTickStart = MicroProfileLogTickClamp(LE, nTickStartLog, nTickEndLog);4186uint64_t nTicks = MicroProfileLogTickDifference(nTickStart, nTickEndLog);4187int64_t nChildTicks = pChildTickStack[i];4188pChildTickStack[i] = 0; // consume..41894190MP_ASSERT(i < MICROPROFILE_STACK_MAX && i >= 0);4191if(i)4192{4193pChildTickStack[i - 1] += nTicks;4194}4195MP_ASSERT(nTicks >= (uint64_t)nChildTicks);41964197uint32_t nTimer = (uint32_t)MicroProfileLogGetTimerIndex(LE);4198uint32_t nGroup = pTimerToGroup[nTimer];41994200bool bGroupRoot = 0 == GroupStackPos[nGroup] || 0 == --GroupStackPos[nGroup];4201bool bTimerRoot = 0 == TimerStackPos[nTimer] || 0 == --TimerStackPos[nTimer];42024203uint64_t nTicksExclusive = (nTicks - nChildTicks);4204S.FrameExclusive[nTimer] += nTicksExclusive;4205pFrameGroupThread[nGroup].nTicksExclusive += nTicksExclusive;4206if(bTimerRoot)4207{4208S.Frame[nTimer].nTicks += nTicks;4209S.Frame[nTimer].nCount += 1;42104211MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);4212if(bGroupRoot)4213{4214pFrameGroupThread[nGroup].nTicks += nTicks;4215pFrameGroupThread[nGroup].nCount += 1;4216}4217}4218}4219#ifdef MP_ASSERT4220for(uint8_t& g : GroupStackPos)4221{4222MP_ASSERT(g == 0);4223}4224for(uint8_t& g : TimerStackPos)4225{4226MP_ASSERT(g == 0);4227}4228#endif42294230pLog->nStackPos = nStackPos;4231for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)4232{4233pLog->nGroupTicks[j] += pFrameGroupThread[j].nTicks;42344235if((S.FrameGroupThreadValid[idx_thread / 32] & (1 << (idx_thread % 32))) != 0)4236{4237pFrameGroup[j].nTicks += pFrameGroupThread[j].nTicks;4238pFrameGroup[j].nTicksExclusive += pFrameGroupThread[j].nTicksExclusive;4239pFrameGroup[j].nCount += pFrameGroupThread[j].nCount;4240}4241}42424243if(pLog->nPut == pLog->nGet && pLog->nActive == 2)4244{4245pLog->nIdleFrames++;4246}4247else4248{4249pLog->nIdleFrames = 0;4250}4251if(pLog->nActive == 2 && pLog->nIdleFrames > MICROPROFILE_THREAD_LOG_FRAMES_REUSE)4252{4253MicroProfileLogReset(pLog);4254}4255}4256}4257{4258MICROPROFILE_SCOPE(g_MicroProfileAccumulate);4259uint64_t* ExtraPut = nullptr;4260if(UsingExtraData)4261{4262ExtraPut = &ExtraData->Timers[0];4263ExtraData->NumTimers = S.nTotalTimers;4264}42654266for(uint32_t i = 0; i < S.nTotalTimers; ++i)4267{4268S.AccumTimers[i].nTicks += S.Frame[i].nTicks;4269S.AccumTimers[i].nCount += S.Frame[i].nCount;4270S.AccumMaxTimers[i] = MicroProfileMax(S.AccumMaxTimers[i], S.Frame[i].nTicks);4271S.AccumMinTimers[i] = MicroProfileMin(S.AccumMinTimers[i], S.Frame[i].nTicks);4272S.AccumTimersExclusive[i] += S.FrameExclusive[i];4273S.AccumMaxTimersExclusive[i] = MicroProfileMax(S.AccumMaxTimersExclusive[i], S.FrameExclusive[i]);4274if(ExtraPut)4275*ExtraPut++ = S.Frame[i].nTicks;4276}4277ExtraPut = nullptr;4278if(UsingExtraData)4279{4280ExtraPut = &ExtraData->Groups[0];4281ExtraData->NumGroups = S.nGroupCount;4282}42834284for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)4285{4286S.AccumGroup[i] += pFrameGroup[i].nTicks;4287S.AccumGroupMax[i] = MicroProfileMax(S.AccumGroupMax[i], pFrameGroup[i].nTicks);4288if(ExtraPut)4289*ExtraPut++ = pFrameGroup[i].nTicks;4290}4291#if MICROPROFILE_IMGUI4292void MicroProfileImguiGather();4293MicroProfileImguiGather();4294#endif4295if(S.CsvConfig.State == MicroProfileCsvConfig::ACTIVE)4296{4297uint32_t FrameIndex = S.nFrameCurrent % MICROPROFILE_MAX_FRAME_HISTORY;4298uint64_t* FrameData = S.CsvConfig.FrameData + S.CsvConfig.TotalElements * FrameIndex;4299{4300uint16_t* TimerIndices = S.CsvConfig.TimerIndices;4301for(uint32_t i = 0; i < S.CsvConfig.NumTimers; ++i)4302{4303uint16_t Index = TimerIndices[i];4304if(Index != UINT16_MAX)4305{4306*FrameData = S.Frame[Index].nTicks;4307}4308else4309{4310*FrameData = 0;4311}4312FrameData++;4313}4314}4315{4316uint16_t* GroupIndices = S.CsvConfig.GroupIndices;4317for(uint32_t i = 0; i < S.CsvConfig.NumGroups; ++i)4318{4319uint16_t Index = GroupIndices[i];4320if(Index != UINT16_MAX)4321{4322*FrameData = pFrameGroup[Index].nTicks;4323}4324else4325{4326*FrameData = 0;4327}4328FrameData++;4329}4330}4331{4332uint16_t* CounterIndices = S.CsvConfig.CounterIndices;4333for(uint32_t i = 0; i < S.CsvConfig.NumCounters; ++i)4334{4335uint16_t Index = CounterIndices[i];4336if(Index != UINT16_MAX)4337{4338if(S.CounterInfo[Index].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE)4339{4340double d = S.CountersDouble[Index].load();4341memcpy(FrameData, &d, sizeof(d));4342}4343else4344{4345*FrameData = S.Counters[Index].load();4346}4347}4348else4349{4350*FrameData = 0;4351}4352FrameData++;4353}4354}4355}4356}4357for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)4358{4359if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)4360{4361MicroProfileToken nToken = S.Graph[i].nToken;4362S.Graph[i].nHistory[S.nGraphPut] = S.Frame[MicroProfileGetTimerIndex(nToken)].nTicks;4363}4364}4365S.nGraphPut = (S.nGraphPut + 1) % MICROPROFILE_GRAPH_HISTORY;4366}43674368if(S.nAggregateFlip <= ++S.nAggregateFlipCount)4369{4370nAggregateFlip = 1;4371if(S.nAggregateFlip) // if 0 accumulate indefinitely4372{4373nAggregateClear = 1;4374}4375}43764377for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)4378{4379MicroProfileThreadLog* pLog = S.Pool[i];4380uint32_t nNewGet = pFrameNext->nLogStart[i];43814382if(pLog && nNewGet != (uint32_t)-1)4383{4384pLog->nGet.store(nNewGet);4385}4386}4387if(pFrameNext->nLogStartTimeline != (uint32_t)-1)4388{4389S.TimelineLog.nGet.store(pFrameNext->nLogStartTimeline);4390}4391}4392if(nAggregateFlip)4393{4394memcpy(&S.Aggregate[0], &S.AccumTimers[0], sizeof(S.Aggregate[0]) * S.nTotalTimers);4395memcpy(&S.AggregateMax[0], &S.AccumMaxTimers[0], sizeof(S.AggregateMax[0]) * S.nTotalTimers);4396memcpy(&S.AggregateMin[0], &S.AccumMinTimers[0], sizeof(S.AggregateMin[0]) * S.nTotalTimers);4397memcpy(&S.AggregateExclusive[0], &S.AccumTimersExclusive[0], sizeof(S.AggregateExclusive[0]) * S.nTotalTimers);4398memcpy(&S.AggregateMaxExclusive[0], &S.AccumMaxTimersExclusive[0], sizeof(S.AggregateMaxExclusive[0]) * S.nTotalTimers);43994400memcpy(&S.AggregateGroup[0], &S.AccumGroup[0], sizeof(S.AggregateGroup));4401memcpy(&S.AggregateGroupMax[0], &S.AccumGroupMax[0], sizeof(S.AggregateGroup));44024403for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)4404{4405MicroProfileThreadLog* pLog = S.Pool[i];4406if(!pLog)4407continue;44084409memcpy(&pLog->nAggregateGroupTicks[0], &pLog->nGroupTicks[0], sizeof(pLog->nAggregateGroupTicks));44104411if(nAggregateClear)4412{4413memset(&pLog->nGroupTicks[0], 0, sizeof(pLog->nGroupTicks));4414}4415}44164417S.nAggregateFrames = S.nAggregateFlipCount;4418S.nFlipAggregateDisplay = S.nFlipAggregate;4419S.nFlipMaxDisplay = S.nFlipMax;4420if(nAggregateClear)4421{4422memset(&S.AccumTimers[0], 0, sizeof(S.Aggregate[0]) * S.nTotalTimers);4423memset(&S.AccumMaxTimers[0], 0, sizeof(S.AccumMaxTimers[0]) * S.nTotalTimers);4424memset(&S.AccumMinTimers[0], 0xFF, sizeof(S.AccumMinTimers[0]) * S.nTotalTimers);4425memset(&S.AccumTimersExclusive[0], 0, sizeof(S.AggregateExclusive[0]) * S.nTotalTimers);4426memset(&S.AccumMaxTimersExclusive[0], 0, sizeof(S.AccumMaxTimersExclusive[0]) * S.nTotalTimers);4427memset(&S.AccumGroup[0], 0, sizeof(S.AggregateGroup));4428memset(&S.AccumGroupMax[0], 0, sizeof(S.AggregateGroup));44294430S.nAggregateFlipCount = 0;4431S.nFlipAggregate = 0;4432S.nFlipMax = 0;44334434S.nAggregateFlipTick = MP_TICK();4435}44364437#if MICROPROFILE_COUNTER_HISTORY4438int64_t* pDest = &S.nCounterHistory[S.nCounterHistoryPut][0];4439S.nCounterHistoryPut = (S.nCounterHistoryPut + 1) % MICROPROFILE_GRAPH_HISTORY;4440for(uint32_t i = 0; i < S.nNumCounters; ++i)4441{4442if(0 != (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DETAILED))4443{4444MicroProfileFetchCounter(i);4445bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0;4446if(IsDouble)4447{4448double dValue = S.CountersDouble[i].load(std::memory_order_relaxed);4449memcpy(&pDest[i], &dValue, sizeof(dValue));4450S.dCounterMin[i] = MicroProfileMin(S.dCounterMin[i], dValue);4451S.dCounterMax[i] = MicroProfileMax(S.dCounterMax[i], dValue);4452}4453else4454{4455uint64_t nValue = S.Counters[i].load(std::memory_order_relaxed);4456pDest[i] = nValue;4457S.nCounterMin[i] = MicroProfileMin(S.nCounterMin[i], (int64_t)nValue);4458S.nCounterMax[i] = MicroProfileMax(S.nCounterMax[i], (int64_t)nValue);4459}4460}4461}4462#endif4463}4464S.nAggregateClear = 0;44654466MicroProfileFlipEnabled();4467}44684469void MicroProfileSetEnableAllGroups(int bEnable)4470{4471if(bEnable)4472{4473for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4474{4475S.nActiveGroupsWanted[i] = S.nGroupMask[i];4476}4477S.nStartEnabled = 1;4478MicroProfileFlipEnabled();4479}4480else4481{4482for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4483{4484S.nActiveGroupsWanted[i] = 0;4485}4486S.nStartEnabled = 0;4487MicroProfileFlipEnabled();4488}4489}4490void MicroProfileEnableCategory(const char* pCategory, int bEnabled)4491{4492int nCategoryIndex = -1;4493for(uint32_t i = 0; i < S.nCategoryCount; ++i)4494{4495if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName))4496{4497nCategoryIndex = (int)i;4498break;4499}4500}4501if(nCategoryIndex >= 0)4502{4503if(bEnabled)4504{4505for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4506{4507S.nActiveGroupsWanted[i] |= S.CategoryInfo[nCategoryIndex].nGroupMask[i];4508}4509}4510else4511{4512for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4513{4514S.nActiveGroupsWanted[i] &= ~S.CategoryInfo[nCategoryIndex].nGroupMask[i];4515}4516}4517}4518}45194520void MicroProfileEnableCategory(const char* pCategory)4521{4522MicroProfileEnableCategory(pCategory, true);4523}4524void MicroProfileDisableCategory(const char* pCategory)4525{4526MicroProfileEnableCategory(pCategory, false);4527}45284529int MicroProfileGetEnableAllGroups()4530{4531return 0 == memcmp(S.nGroupMask, S.nActiveGroupsWanted, sizeof(S.nGroupMask));4532}45334534void MicroProfileSetForceMetaCounters(int bForce)4535{4536}45374538int MicroProfileGetForceMetaCounters()4539{45404541return 0;4542}45434544void MicroProfileEnableMetaCounter(const char* pMeta)4545{4546}45474548void MicroProfileDisableMetaCounter(const char* pMeta)4549{4550}45514552void MicroProfileSetAggregateFrames(int nFrames)4553{4554S.nAggregateFlip = (uint32_t)nFrames;4555if(0 == nFrames)4556{4557S.nAggregateClear = 1;4558}4559}45604561int MicroProfileGetAggregateFrames()4562{4563return S.nAggregateFlip;4564}45654566int MicroProfileGetCurrentAggregateFrames()4567{4568return int(S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount);4569}45704571void MicroProfileForceEnableGroup(const char* pGroup, MicroProfileTokenType Type)4572{4573MicroProfileInit();4574std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());4575uint16_t nGroup = MicroProfileGetGroup(pGroup, Type);4576uint32_t nIndex = nGroup / 32;4577uint32_t nBit = nGroup % 32;4578S.nForceGroups[nIndex] |= (1ll << nBit);4579}45804581void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Type)4582{4583MicroProfileInit();4584std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());4585uint16_t nGroup = MicroProfileGetGroup(pGroup, Type);4586uint32_t nIndex = nGroup / 32;4587uint32_t nBit = nGroup % 32;45884589S.nForceGroups[nIndex] &= ~(1ll << nBit);4590}45914592struct MicroProfileTimerValues4593{4594float TimeMs;4595float AverageMs;4596float MaxMs;4597float MinMs;4598float CallAverageMs;4599float ExclusiveMs;4600float AverageExclusiveMs;4601float MaxExclusiveMs;4602float TotalMs;4603uint32_t nCount;4604};46054606void MicroProfileCalcTimers(int nTimer, MicroProfileTimerValues& Out)4607{4608const uint32_t nGroupId = S.TimerInfo[nTimer].nGroupIndex;4609const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());4610uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;4611uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;4612Out.nCount = S.Aggregate[nTimer].nCount;46134614float fToPrc = S.fRcpReferenceTime;4615float fMs = fToMs * (S.Frame[nTimer].nTicks);46164617float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);4618float fMaxMs = fToMs * (S.AggregateMax[nTimer]);4619float fMinMs = fToMs * (S.AggregateMin[nTimer] != uint64_t(-1) ? S.AggregateMin[nTimer] : 0);4620float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);4621float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);4622float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);4623float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);4624float fTotalMs = fToMs * S.Aggregate[nTimer].nTicks;46254626Out.TimeMs = fMs;4627Out.AverageMs = fAverageMs;4628Out.MaxMs = fMaxMs;4629Out.MinMs = fMinMs;4630Out.CallAverageMs = fCallAverageMs;4631Out.ExclusiveMs = fMsExclusive;4632Out.AverageExclusiveMs = fAverageMsExclusive;4633Out.MaxExclusiveMs = fMaxMsExclusive;4634Out.TotalMs = fTotalMs;4635}46364637void MicroProfileCalcAllTimers(4638float* pTimers, float* pAverage, float* pMax, float* pMin, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)4639{4640for(uint32_t i = 0; i < S.nTotalTimers && i < nSize; ++i)4641{4642const uint32_t nGroupId = S.TimerInfo[i].nGroupIndex;4643const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());4644uint32_t nTimer = i;4645uint32_t nIdx = i * 2;4646uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;4647uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;4648float fToPrc = S.fRcpReferenceTime;4649float fMs = fToMs * (S.Frame[nTimer].nTicks);4650float fPrc = MicroProfileMin(fMs * fToPrc, 1.f);4651float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);4652float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f);4653float fMaxMs = fToMs * (S.AggregateMax[nTimer]);4654float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f);4655float fMinMs = fToMs * (S.AggregateMin[nTimer] != uint64_t(-1) ? S.AggregateMin[nTimer] : 0);4656float fMinPrc = MicroProfileMin(fMinMs * fToPrc, 1.f);4657float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);4658float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f);4659float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);4660float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f);4661float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);4662float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f);4663float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);4664float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f);4665float fTotalMs = fToMs * S.Aggregate[nTimer].nTicks;4666pTimers[nIdx] = fMs;4667pTimers[nIdx + 1] = fPrc;4668pAverage[nIdx] = fAverageMs;4669pAverage[nIdx + 1] = fAveragePrc;4670pMax[nIdx] = fMaxMs;4671pMax[nIdx + 1] = fMaxPrc;4672pMin[nIdx] = fMinMs;4673pMin[nIdx + 1] = fMinPrc;4674pCallAverage[nIdx] = fCallAverageMs;4675pCallAverage[nIdx + 1] = fCallAveragePrc;4676pExclusive[nIdx] = fMsExclusive;4677pExclusive[nIdx + 1] = fPrcExclusive;4678pAverageExclusive[nIdx] = fAverageMsExclusive;4679pAverageExclusive[nIdx + 1] = fAveragePrcExclusive;4680pMaxExclusive[nIdx] = fMaxMsExclusive;4681pMaxExclusive[nIdx + 1] = fMaxPrcExclusive;4682pTotal[nIdx] = fTotalMs;4683pTotal[nIdx + 1] = 0.f;4684}4685}46864687float MicroProfileGetTime(const char* pGroup, const char* pName)4688{4689MicroProfileToken nToken = MicroProfileFindTokenInternal(pGroup, pName);4690if(nToken == MICROPROFILE_INVALID_TOKEN)4691{4692return 0.f;4693}4694uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken);4695uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken);4696float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());4697return S.Frame[nTimerIndex].nTicks * fToMs;4698}46994700int MicroProfilePlatformMarkersGetEnabled()4701{4702return S.nPlatformMarkersEnabled != 0 ? 1 : 0;4703}4704void MicroProfilePlatformMarkersSetEnabled(int bEnabled)4705{4706S.nPlatformMarkersEnabled = bEnabled ? 1 : 0;4707}47084709#define MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG MICROPROFILE_DEBUG47104711void MicroProfileContextSwitchSearch(uint32_t* pContextSwitchStart, uint32_t* pContextSwitchEnd, uint64_t nBaseTicksCpu, uint64_t nBaseTicksEndCpu)4712{4713MICROPROFILE_SCOPE(g_MicroProfileContextSwitchSearch);4714uint32_t nContextSwitchPut = S.nContextSwitchPut;4715uint64_t nContextSwitchStart, nContextSwitchEnd;4716nContextSwitchStart = nContextSwitchEnd = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;4717int64_t nSearchEnd = nBaseTicksEndCpu + MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu());4718int64_t nSearchBegin = nBaseTicksCpu - MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu());47194720#if MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG4721int64_t lp = S.nContextSwitchLastPushed;4722uprintf("cswitch-search\n");4723uprintf("Begin %" PRId64 " End %" PRId64 " Last %" PRId64 "\n", nSearchBegin, nSearchEnd, lp);47244725float fToMs = MicroProfileTickToMsMultiplierCpu();4726uprintf("E %6.2fms\n", fToMs * (nSearchEnd - nSearchBegin));4727uprintf("LAST %6.2fms\n", fToMs * (lp - nSearchBegin));4728#endif47294730int64_t nMax = INT64_MIN;4731int64_t nMin = INT64_MAX;4732for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; ++i)4733{4734uint32_t nIndex = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - (i + 1)) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE;4735MicroProfileContextSwitch& CS = S.ContextSwitch[nIndex];4736if(nMax < CS.nTicks)4737nMax = CS.nTicks;4738if(nMin > CS.nTicks && CS.nTicks != 0)4739nMin = CS.nTicks;4740if(CS.nTicks > nSearchEnd)4741{4742nContextSwitchEnd = nIndex;4743}4744if(CS.nTicks > nSearchBegin)4745{4746nContextSwitchStart = nIndex;4747}4748}4749*pContextSwitchStart = nContextSwitchStart;4750*pContextSwitchEnd = nContextSwitchEnd;47514752#if MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG4753{4754uprintf("contextswitch start %" PRId64 " %" PRId64 "\n", nContextSwitchStart, nContextSwitchEnd);47554756MicroProfileContextSwitch& CS0 = S.ContextSwitch[0];4757int64_t nMax = CS0.nTicks;4758int64_t nMin = CS0.nTicks;4759int64_t nBegin = 0;4760int64_t nEnd = 0;4761int nRanges = 0;4762for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; i += 1024)4763{4764int64_t MinTick = INT64_MAX;4765int64_t MaxTick = INT64_MIN;4766for(int j = 0; j < 1024; ++j)4767{4768MicroProfileContextSwitch& CS = S.ContextSwitch[i + j];4769int64_t nTicks = CS.nTicks;4770MinTick = MicroProfileMin(nTicks, MinTick);4771MaxTick = MicroProfileMax(nTicks, MaxTick);4772}47734774uprintf("XX range [%5" PRIx64 ":%5" PRIx64 "] :: [%6.2f:%6.2f] [%p :: %p] .. ref %p\n",4775i,4776i + 1024,4777fToMs * (MinTick - nSearchBegin),4778fToMs * (MaxTick - nSearchBegin),4779(void*)MinTick,4780(void*)MaxTick,4781(void*)nSearchBegin47824783);4784}4785uprintf("\n\n");47864787for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; ++i)4788{4789MicroProfileContextSwitch& CS = S.ContextSwitch[i];4790int64_t nTicks = CS.nTicks;4791float fMs = (nTicks - nMax) * fToMs;4792if(fMs < 0 || fMs > 50)4793{4794// dump range here4795uprintf("range [%5" PRId64 ":%5" PRId64 "] :: [%6.2f:%6.2f] [%p :: %p] .. ref %p\n",4796nBegin,4797nEnd,4798fToMs * (nMin - nSearchBegin),4799fToMs * (nMax - nSearchBegin),4800(void*)nMin,4801(void*)nMax,4802(void*)nSearchBegin48034804);48054806nEnd = nBegin = i;4807nMax = nMin = CS.nTicks;4808nRanges++;4809}4810else4811{4812nEnd = i;4813nMax = MicroProfileMax(nTicks, nMax);4814}4815}4816}48174818lp = S.nContextSwitchLastPushed;4819uprintf("E %6.2fms\n", fToMs * (nSearchEnd - nSearchBegin));4820uprintf("LP2 %6.2fms\n", fToMs * (lp - nSearchBegin));4821#endif4822}48234824int MicroProfileFormatCounter(int eFormat, int64_t nCounter, char* pOut, uint32_t nBufferSize)4825{4826if(!nCounter)4827{4828pOut[0] = '0';4829pOut[1] = '\0';4830return 1;4831}4832int nLen = 0;4833char* pBase = pOut;4834char* pTmp = pOut;4835char* pEnd = pOut + nBufferSize;4836int nNegative = 0;4837if(nCounter < 0)4838{4839nCounter = -nCounter;4840nNegative = 1;4841if(nCounter < 0) // handle INT_MIN4842{4843nCounter = -(nCounter + 1);4844}4845}48464847switch(eFormat)4848{4849case MICROPROFILE_COUNTER_FORMAT_DEFAULT:4850{4851int nSeperate = 0;4852while(nCounter)4853{4854if(nSeperate)4855{4856*pTmp++ = '.';4857}4858nSeperate = 1;4859for(uint32_t i = 0; nCounter && i < 3; ++i)4860{4861int nDigit = nCounter % 10;4862nCounter /= 10;4863*pTmp++ = '0' + nDigit;4864}4865}4866if(nNegative)4867{4868*pTmp++ = '-';4869}4870nLen = pTmp - pOut;4871--pTmp;4872MP_ASSERT(pTmp <= pEnd);4873while(pTmp > pOut) // reverse string4874{4875char c = *pTmp;4876*pTmp = *pOut;4877*pOut = c;4878pTmp--;4879pOut++;4880}4881}4882break;4883case MICROPROFILE_COUNTER_FORMAT_BYTES:4884{4885const char* pExt[] = { "b", "kb", "mb", "gb", "tb", "pb", "eb", "zb", "yb" };4886size_t nNumExt = sizeof(pExt) / sizeof(pExt[0]);4887int64_t nShift = 0;4888int64_t nDivisor = 1;4889int64_t nCountShifted = nCounter >> 10;4890while(nCountShifted)4891{4892nDivisor <<= 10;4893nCountShifted >>= 10;4894nShift++;4895}4896MP_ASSERT(nShift < (int64_t)nNumExt);4897if(nShift)4898{4899nLen = snprintf(pOut, nBufferSize - 1, "%c%3.2f%s", nNegative ? '-' : ' ', (double)nCounter / nDivisor, pExt[nShift]);4900}4901else4902{4903nLen = snprintf(pOut, nBufferSize - 1, "%c%" PRId64 "%s", nNegative ? '-' : ' ', nCounter, pExt[nShift]);4904}4905}4906break;4907}4908pBase[nLen] = '\0';49094910return nLen;4911}49124913int MicroProfileFormatCounterDouble(int eFormat, double dCounter, char* pOut, uint32_t nBufferSize)4914{4915int nLen = 0;4916switch(eFormat)4917{4918case MICROPROFILE_COUNTER_FORMAT_DEFAULT:4919{4920nLen = stbsp_snprintf(pOut, nBufferSize - 1, "%f", dCounter);4921}4922break;4923case MICROPROFILE_COUNTER_FORMAT_BYTES:4924{4925const char* pExt[] = { "b", "kb", "mb", "gb", "tb", "pb", "eb", "zb", "yb" };4926double scale = 1.f;4927int offset = 0;4928int end = sizeof(pExt) / sizeof(pExt[0]);4929double d = dCounter;4930while(d / scale > 1024.f && offset + 1 < end)4931{4932scale *= 1024.f;4933offset += 1;4934}4935nLen = stbsp_snprintf(pOut, nBufferSize - 1, "%.3f%s", d / scale, pExt[offset]);4936}4937break;4938}4939pOut[nLen] = '\0';49404941return nLen;4942}49434944bool MicroProfileAnyGroupActive()4945{4946for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4947{4948if(S.nActiveGroups[i] != 0)4949return true;4950}4951return false;4952}4953bool MicroProfileGroupActive(uint32_t nGroupIndex)4954{4955MP_ASSERT(nGroupIndex < MICROPROFILE_MAX_GROUPS);4956uint32_t nIndex = nGroupIndex / 32;4957uint32_t nBit = nGroupIndex % 32;4958return ((S.nActiveGroups[nIndex] >> nBit) & 1) == 1;4959}49604961void MicroProfileToggleGroup(uint32_t nGroup)4962{4963if(nGroup < S.nGroupCount)4964{4965uint32_t nIndex = nGroup / 32;4966uint32_t nBit = nGroup % 32;4967S.nActiveGroupsWanted[nIndex] ^= (1ll << nBit);4968S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;4969}4970}4971void MicroProfileGroupSetEnabled(uint32_t nGroup)4972{4973if(nGroup < S.nGroupCount)4974{4975uint32_t nIndex = nGroup / 32;4976uint32_t nBit = nGroup % 32;4977S.nActiveGroupsWanted[nIndex] |= (1ll << nBit);4978S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;4979}4980}4981bool MicroProfileGroupEnabled(uint32_t nGroup)4982{4983if(nGroup < S.nGroupCount)4984{4985uint32_t nIndex = nGroup / 32;4986uint32_t nBit = nGroup % 32;4987return 0 != (S.nActiveGroupsWanted[nIndex] & (1ll << nBit));4988}4989return false;4990}4991bool MicroProfileCategoryEnabled(uint32_t nCategory)4992{4993if(nCategory < S.nCategoryCount)4994{4995for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)4996{4997if(S.CategoryInfo[nCategory].nGroupMask[i] != (S.CategoryInfo[nCategory].nGroupMask[i] & S.nActiveGroupsWanted[i]))4998{4999return false;5000}5001}5002return true;5003}5004return false;5005}50065007bool MicroProfileCategoryDisabled(uint32_t nCategory)5008{5009if(nCategory < S.nCategoryCount)5010{5011for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)5012{5013uint32_t ActiveMask = S.nActiveGroupsWanted[i];5014uint32_t CategoryMask = S.CategoryInfo[nCategory].nGroupMask[i];50155016if(0 != (ActiveMask & CategoryMask))5017{5018return false;5019}5020}5021return true;5022}5023return false;5024}50255026void MicroProfileToggleCategory(uint32_t nCategory)5027{5028if(nCategory < S.nCategoryCount)5029{5030bool bAllSet = true;5031for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)5032{5033bAllSet = bAllSet && S.CategoryInfo[nCategory].nGroupMask[i] == (S.CategoryInfo[nCategory].nGroupMask[i] & S.nActiveGroupsWanted[i]);5034}5035for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i)5036{5037if(bAllSet)5038{5039S.nActiveGroupsWanted[i] &= ~S.CategoryInfo[nCategory].nGroupMask[i];5040}5041else5042{5043S.nActiveGroupsWanted[i] |= S.CategoryInfo[nCategory].nGroupMask[i];5044}5045}5046S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;5047}5048}50495050void MicroProfileSleep(uint32_t nMs)5051{5052#ifdef _WIN325053Sleep(nMs);5054#else5055usleep(nMs * 1000);5056#endif5057}50585059#if MICROPROFILE_WEBSERVER50605061#define MICROPROFILE_EMBED_HTML50625063extern const char* g_MicroProfileHtml_begin[];5064extern size_t g_MicroProfileHtml_begin_sizes[];5065extern size_t g_MicroProfileHtml_begin_count;5066extern const char* g_MicroProfileHtml_end[];5067extern size_t g_MicroProfileHtml_end_sizes[];5068extern size_t g_MicroProfileHtml_end_count;50695070extern const char* g_MicroProfileHtmlLive_begin[];5071extern size_t g_MicroProfileHtmlLive_begin_sizes[];5072extern size_t g_MicroProfileHtmlLive_begin_count;5073extern const char* g_MicroProfileHtmlLive_end[];5074extern size_t g_MicroProfileHtmlLive_end_sizes[];5075extern size_t g_MicroProfileHtmlLive_end_count;50765077extern const uint32_t uprof_16[];5078extern const uint32_t uprof_16_len;5079extern const uint32_t uprof_32[];5080extern const uint32_t uprof_32_len;5081extern const uint32_t uprof_192[];5082extern const uint32_t uprof_192_len;5083extern const uint32_t uprof_512[];5084extern const uint32_t uprof_512_len;50855086typedef void (*MicroProfileWriteCallback)(void* Handle, size_t size, const char* pData);50875088uint32_t MicroProfileWebServerPort()5089{5090return S.nWebServerPort;5091}50925093void MicroProfileSetWebServerPort(uint32_t nPort)5094{5095if(S.nWebServerPort != nPort)5096{5097MicroProfileWebServerJoin();5098MicroProfileWebServerStop();5099S.nWebServerPort = nPort;5100S.nWebServerDataSent = (uint64_t)-1; // Will cause the web server and its thread to be restarted next time MicroProfileFlip() is called.5101}5102}51035104void MicroProfileDumpFileImmediately(const char* pHtml, const char* pCsv, void* pGpuContext, uint32_t FrameCount)5105{5106for(uint32_t i = 0; i < 2; ++i)5107{5108MicroProfileFlip(pGpuContext);5109}5110for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY + 1; ++i)5111{5112MicroProfileFlip(pGpuContext);5113}51145115uint32_t nDumpMask = 0;5116if(pHtml)5117{51185119size_t nLen = strlen(pHtml);5120if(nLen > sizeof(S.HtmlDumpPath) - 1)5121{5122return;5123}5124const size_t ExtSize = sizeof(".html") - 1;5125if(nLen > ExtSize && 0 == memcmp(".html", pHtml + nLen - ExtSize, ExtSize))5126nLen -= ExtSize;5127memcpy(S.HtmlDumpPath, pHtml, nLen);5128S.HtmlDumpPath[nLen] = '\0';51295130nDumpMask |= 1;5131}5132if(pCsv)5133{5134size_t nLen = strlen(pCsv);5135if(nLen > sizeof(S.CsvDumpPath) - 1)5136{5137return;5138}5139const size_t ExtSize = sizeof(".csv") - 1;5140if(nLen > ExtSize && 0 == memcmp(".csv", pCsv + nLen - ExtSize, ExtSize))5141nLen -= ExtSize;5142memcpy(S.CsvDumpPath, pCsv, nLen + 1);5143S.CsvDumpPath[nLen] = '\0';51445145nDumpMask |= 2;5146}5147std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());5148S.nDumpFileNextFrame = nDumpMask;5149S.nDumpSpikeMask = 0;5150S.nDumpFileCountDown = 0;5151S.DumpFrameCount = FrameCount;51525153MicroProfileDumpToFile();5154}5155void MicroProfileDumpFile(const char* pHtml, const char* pCsv, float fCpuSpike, float fGpuSpike, uint32_t FrameCount)5156{5157S.fDumpCpuSpike = fCpuSpike;5158S.fDumpGpuSpike = fGpuSpike;5159S.DumpFrameCount = FrameCount;5160uint32_t nDumpMask = 0;5161if(pHtml)5162{5163size_t nLen = strlen(pHtml);5164if(nLen > sizeof(S.HtmlDumpPath) - 1)5165{5166return;5167}5168const size_t ExtSize = sizeof(".html") - 1;5169if(nLen > ExtSize && 0 == memcmp(".html", pHtml + nLen - ExtSize, ExtSize))5170nLen -= ExtSize;5171memcpy(S.HtmlDumpPath, pHtml, nLen);5172S.HtmlDumpPath[nLen] = '\0';51735174nDumpMask |= 1;5175}5176if(pCsv)5177{5178size_t nLen = strlen(pCsv);5179if(nLen > sizeof(S.CsvDumpPath) - 1)5180{5181return;5182}5183const size_t ExtSize = sizeof(".csv") - 1;5184if(nLen > ExtSize && 0 == memcmp(".csv", pCsv + nLen - ExtSize, ExtSize))5185nLen -= ExtSize;5186memcpy(S.CsvDumpPath, pCsv, nLen);5187S.CsvDumpPath[nLen] = '\0';51885189nDumpMask |= 2;5190}5191if(fCpuSpike > 0.f || fGpuSpike > 0.f)5192{5193S.nDumpFileNextFrame = 0;5194S.nDumpSpikeMask = nDumpMask;5195}5196else5197{5198std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());5199S.nDumpFileNextFrame = nDumpMask;5200S.nDumpSpikeMask = 0;5201S.nDumpFileCountDown = 0;52025203MicroProfileDumpToFile();5204}5205}52065207struct MicroProfilePrintfArgs5208{5209MicroProfileWriteCallback CB;5210void* Handle;5211};52125213char* MicroProfilePrintfCallback(const char* buf, void* user, int len)5214{5215MicroProfilePrintfArgs* A = (MicroProfilePrintfArgs*)user;5216(A->CB)(A->Handle, len, buf);5217return const_cast<char*>(buf);5218};52195220void MicroProfilePrintf(MicroProfileWriteCallback CB, void* Handle, const char* pFmt, ...)5221{5222va_list args;5223va_start(args, pFmt);5224MicroProfilePrintfArgs A;5225A.CB = CB;5226A.Handle = Handle;5227char Buffer[STB_SPRINTF_MIN];5228int size = stbsp_vsprintfcb(MicroProfilePrintfCallback, (void*)&A, Buffer, pFmt, args);5229(void)size;5230va_end(args);5231}52325233void MicroProfileGetFramesToDump(uint64_t nStartFrameId, uint32_t nMaxFrames, uint32_t& nFirstFrame, uint32_t& nLastFrame, uint32_t& nNumFrames)5234{5235nFirstFrame = (uint32_t)-1;5236nNumFrames = 0;52375238if(nStartFrameId != (uint64_t)-1)5239{5240// search for the frane5241for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)5242{5243if(S.Frames[i].nFrameId == nStartFrameId)5244{5245nFirstFrame = i;5246break;5247}5248}5249if(nFirstFrame != (uint32_t)-1)5250{5251nLastFrame = S.nFrameCurrent;5252uint32_t nDistance = (MICROPROFILE_MAX_FRAME_HISTORY + nFirstFrame - nLastFrame) % MICROPROFILE_MAX_FRAME_HISTORY;5253nNumFrames = MicroProfileMin(nDistance, (uint32_t)nMaxFrames);5254}5255}52565257if(nNumFrames == 0)5258{5259nNumFrames = (MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3); // leave a few to not overwrite5260nNumFrames = MicroProfileMin(nNumFrames, (uint32_t)nMaxFrames);5261nFirstFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;5262}52635264nLastFrame = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;5265}52665267#define printf(...) MicroProfilePrintf(CB, Handle, __VA_ARGS__)52685269void MicroProfileDumpCsvWithConfig(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames)5270{5271uint32_t NumTimers = S.CsvConfig.NumTimers;5272uint32_t NumGroups = S.CsvConfig.NumGroups;5273uint32_t NumCounters = S.CsvConfig.NumCounters;5274uint16_t* TimerIndices = S.CsvConfig.TimerIndices;5275uint16_t* GroupIndices = S.CsvConfig.GroupIndices;5276uint64_t* FrameData = S.CsvConfig.FrameData;5277uint16_t* CounterIndices = S.CsvConfig.CounterIndices;5278uint32_t TotalElements = S.CsvConfig.TotalElements;5279uint32_t Offset = 0;5280bool UseFrameTime = 0 != (MICROPROFILE_CSV_FLAG_FRAME_TIME & S.CsvConfig.Flags);5281const char** pTimerNames = S.CsvConfig.pTimerNames;5282const char** pGroupNames = S.CsvConfig.pGroupNames;5283const char** pCounterNames = S.CsvConfig.pCounterNames;5284if(UseFrameTime)5285printf("Time");5286else5287printf("FrameNumber");5288for(uint32_t i = 0; i < NumTimers; ++i, ++Offset)5289printf(", %s", pTimerNames[i] ? pTimerNames[i] : S.TimerInfo[TimerIndices[i]].pName);52905291for(uint32_t i = 0; i < NumGroups; ++i, ++Offset)5292printf(", %s", pGroupNames[i] ? pGroupNames[i] : S.GroupInfo[GroupIndices[i]].pName);5293for(uint32_t i = 0; i < NumCounters; ++i, ++Offset)5294printf(", %s", pCounterNames[i] ? pCounterNames[i] : S.CounterInfo[CounterIndices[i]].pName);5295printf("\n");52965297float* fToMsTimer = (float*)alloca(sizeof(float) * NumTimers);5298float* fToMsGroup = (float*)alloca(sizeof(float) * NumGroups);5299float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());5300float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());53015302for(uint32_t i = 0; i < NumTimers; ++i)5303fToMsTimer[i] = S.TimerInfo[TimerIndices[i]].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;5304for(uint32_t i = 0; i < NumGroups; ++i)5305fToMsGroup[i] = S.GroupInfo[GroupIndices[i]].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;53065307uint64_t TickStart = S.Frames[nFirstFrame % MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;5308for(uint32_t i = 0; i < nNumFrames; ++i)5309{5310uint32_t FrameIndex = ((nFirstFrame + i) % MICROPROFILE_MAX_FRAME_HISTORY);5311uint64_t TickFrame = S.Frames[FrameIndex].nFrameStartCpu;5312uint64_t* Data = FrameData + TotalElements * FrameIndex;5313if(UseFrameTime)5314printf("%f", (TickFrame - TickStart) * fToMsCPU);5315else5316printf("%d", i);5317Offset = 0;5318for(uint32_t j = 0; j < NumTimers; ++j)5319printf(", %f", Data[Offset++] * fToMsTimer[j]);5320for(uint32_t j = 0; j < NumGroups; ++j)5321printf(", %f", Data[Offset++] * fToMsGroup[j]);5322for(uint32_t j = 0; j < NumCounters; ++j)5323{5324if(S.CounterInfo[CounterIndices[j]].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE)5325{5326printf(", %f", ((double*)Data)[Offset++]);5327}5328else5329{5330printf(", %lld", Data[Offset++]);5331}5332}5333printf("\n");5334}5335}5336void MicroProfileDumpCsvTimerFrames(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames)5337{5338MP_ASSERT(S.FrameExtraCounterData);5339uint32_t TotalTimers = S.nTotalTimers;5340float* fToMs = (float*)alloca(sizeof(float) * TotalTimers);5341float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());5342float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());53435344for(uint32_t i = 0; i < TotalTimers; ++i)5345fToMs[i] = S.TimerInfo[i].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;53465347for(uint32_t i = 0; i < TotalTimers; ++i)5348{5349printf(i == 0 ? "FrameNumber, \"%s\"" : ",\"%s\"", S.TimerInfo[i].pName);5350}5351printf("\n");53525353for(uint32_t i = 0; i < nNumFrames; ++i)5354{5355// printf("%d", i) MicroProfileFrame& F = S.Frames[(i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY];5356MicroProfileFrameExtraCounterData* Data = S.FrameExtraCounterData;5357uint32_t NumTimers = 0;5358uint32_t j;5359printf("%d", i);5360Data += ((i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY);5361NumTimers = MicroProfileMin(TotalTimers, (uint32_t)Data->NumTimers);5362for(j = 0; j < NumTimers; ++j)5363{5364printf(",%f", Data->Timers[j] * fToMs[j]);5365}5366for(; j < TotalTimers; ++j)5367printf(",0");5368printf("\n");5369}5370}53715372void MicroProfileDumpCsvGroupFrames(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames)5373{5374MP_ASSERT(S.FrameExtraCounterData);5375float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());5376float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());53775378uint32_t nGroupCount = S.nGroupCount;53795380float* fToMs = (float*)alloca(sizeof(float) * nGroupCount);5381for(uint32_t i = 0; i < nGroupCount; ++i)5382fToMs[i] = S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;53835384for(uint32_t i = 0; i < nGroupCount; ++i)5385{5386printf(i == 0 ? "FrameNumber, \"%s\"" : ",\"%s\"", S.GroupInfo[i].pName);5387}53885389printf("\n");5390for(uint32_t i = 0; i < nNumFrames; ++i)5391{5392MicroProfileFrameExtraCounterData* Data = S.FrameExtraCounterData;5393uint32_t NumGroups = 0;5394uint32_t j;5395printf("%d", i);5396Data += ((i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY);5397NumGroups = MicroProfileMin(nGroupCount, (uint32_t)Data->NumGroups);5398for(j = 0; j < NumGroups; ++j)5399{5400printf(",%f", Data->Groups[j] * fToMs[j]);5401}5402for(; j < nGroupCount; ++j)5403printf(",0");5404printf("\n");5405}5406}54075408void MicroProfileDumpCsv(uint32_t nDumpFrameCount)5409{5410uint32_t nNumFrames, nFirstFrame, nLastFrame;5411MicroProfileGetFramesToDump((uint64_t)-1, nDumpFrameCount, nFirstFrame, nLastFrame, nNumFrames);54125413char Path[MICROPROFILE_MAX_PATH];5414int Length;5415if(S.FrameExtraCounterData)5416{5417Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_timer_frames.csv", S.CsvDumpPath);5418if(Length > 0 && Length < MICROPROFILE_MAX_PATH)5419{5420FILE* F = fopen(Path, "w");5421if(F)5422{5423MicroProfileDumpCsvTimerFrames(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames);5424fclose(F);5425}5426}5427Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_group_frames.csv", S.CsvDumpPath);5428if(Length > 0 && Length < MICROPROFILE_MAX_PATH)5429{5430FILE* F = fopen(Path, "w");5431if(F)5432{5433MicroProfileDumpCsvGroupFrames(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames);5434fclose(F);5435}5436}5437}5438if(S.CsvConfig.State == MicroProfileCsvConfig::ACTIVE)5439{5440Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_custom.csv", S.CsvDumpPath);5441if(Length > 0 && Length < MICROPROFILE_MAX_PATH)5442{5443FILE* F = fopen(Path, "w");5444if(F)5445{5446MicroProfileDumpCsvWithConfig(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames);5447fclose(F);5448}5449}5450}5451}54525453void MicroProfileDumpCsvLegacy(MicroProfileWriteCallback CB, void* Handle)5454{5455uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;5456float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());5457float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());54585459printf("frames,%d\n", nAggregateFrames);5460printf("group,name,average,max,callaverage\n");54615462uint32_t nNumTimers = S.nTotalTimers;5463uint32_t nBlockSize = 2 * nNumTimers;5464float* pTimers = (float*)alloca(nBlockSize * 9 * sizeof(float));5465float* pAverage = pTimers + nBlockSize;5466float* pMax = pTimers + 2 * nBlockSize;5467float* pMin = pTimers + 3 * nBlockSize;5468float* pCallAverage = pTimers + 4 * nBlockSize;5469float* pTimersExclusive = pTimers + 5 * nBlockSize;5470float* pAverageExclusive = pTimers + 6 * nBlockSize;5471float* pMaxExclusive = pTimers + 7 * nBlockSize;5472float* pTotal = pTimers + 8 * nBlockSize;54735474MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pMin, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers);54755476for(uint32_t i = 0; i < S.nTotalTimers; ++i)5477{5478uint32_t nIdx = i * 2;5479printf("\"%s\",\"%s\",%f,%f,%f\n", S.TimerInfo[i].pName, S.GroupInfo[S.TimerInfo[i].nGroupIndex].pName, pAverage[nIdx], pMax[nIdx], pCallAverage[nIdx]);5480}54815482printf("\n\n");54835484printf("group,average,max,total\n");5485for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)5486{5487const char* pGroupName = S.GroupInfo[j].pName;5488float fToMs = S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU;5489if(pGroupName[0] != '\0')5490{5491printf("\"%s\",%.3f,%.3f,%.3f\n", pGroupName, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j]);5492}5493}54945495printf("\n\n");5496printf("group,thread,average,total\n");5497for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)5498{5499for(uint32_t i = 0; i < S.nNumLogs; ++i)5500{5501if(S.Pool[i])5502{5503const char* pThreadName = &S.Pool[i]->ThreadName[0];5504// MicroProfilePrintf(CB, Handle, "var ThreadGroupTime%d = [", i);5505float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;5506{5507uint64_t nTicks = S.Pool[i]->nAggregateGroupTicks[j];5508float fTime = nTicks / nAggregateFrames * fToMs;5509float fTimeTotal = nTicks * fToMs;5510if(fTimeTotal > 0.01f)5511{5512const char* pGroupName = S.GroupInfo[j].pName;5513printf("\"%s\",\"%s\",%.3f,%.3f\n", pGroupName, pThreadName, fTime, fTimeTotal);5514}5515}5516}5517}5518}55195520printf("\n\n");5521printf("frametimecpu\n");55225523const uint32_t nCount = MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3;5524const uint32_t nStart = S.nFrameCurrent;5525for(uint32_t i = nCount; i > 0; i--)5526{5527uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;5528uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY;5529uint64_t nTicks = S.Frames[nFrameNext].nFrameStartCpu - S.Frames[nFrame].nFrameStartCpu;5530printf("%f,", nTicks * fToMsCPU);5531}5532printf("\n");55335534printf("\n\n");5535printf("frametimegpu\n");55365537for(uint32_t i = nCount; i > 0; i--)5538{5539uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;5540uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY;5541uint64_t nTicks = S.Frames[nFrameNext].nFrameStartGpu - S.Frames[nFrame].nFrameStartGpu;5542printf("%f,", nTicks * fToMsGPU);5543}5544printf("\n\n");5545}5546#undef printf55475548void MicroProfileDumpCsvLegacy()5549{5550char Path[MICROPROFILE_MAX_PATH];5551int Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s.csv", S.CsvDumpPath);5552if(Length > 0 && Length < MICROPROFILE_MAX_PATH)5553{5554FILE* F = fopen(Path, "w");5555if(F)5556{5557MicroProfileDumpCsvLegacy(MicroProfileWriteFile, F);5558fclose(F);5559}5560}5561}55625563void MicroProfileDumpHtmlLive(MicroProfileWriteCallback CB, void* Handle)5564{5565for(size_t i = 0; i < g_MicroProfileHtmlLive_begin_count; ++i)5566{5567CB(Handle, g_MicroProfileHtmlLive_begin_sizes[i] - 1, g_MicroProfileHtmlLive_begin[i]);5568}5569for(size_t i = 0; i < g_MicroProfileHtmlLive_end_count; ++i)5570{5571CB(Handle, g_MicroProfileHtmlLive_end_sizes[i] - 1, g_MicroProfileHtmlLive_end[i]);5572}5573}5574void MicroProfileGetCoreInformation()5575{5576#ifdef _WIN325577unsigned long BufferSize;5578HANDLE Process = GetCurrentProcess();5579GetSystemCpuSetInformation(nullptr, 0, &BufferSize, Process, 0);5580char* Buffer = (char*)alloca(BufferSize);5581if(!GetSystemCpuSetInformation((PSYSTEM_CPU_SET_INFORMATION)Buffer, BufferSize, &BufferSize, Process, 0))5582{5583return;5584}5585for(ULONG Size = 0; Size < BufferSize;)5586{5587PSYSTEM_CPU_SET_INFORMATION CpuSet = reinterpret_cast<PSYSTEM_CPU_SET_INFORMATION>(Buffer);5588if(CpuSet->Type == CPU_SET_INFORMATION_TYPE::CpuSetInformation)5589{5590if(CpuSet->CpuSet.CoreIndex < MICROPROFILE_MAX_CPU_CORES)5591{5592S.CoreEfficiencyClass[CpuSet->CpuSet.LogicalProcessorIndex] = CpuSet->CpuSet.EfficiencyClass;5593}5594}5595Buffer += CpuSet->Size;5596Size += CpuSet->Size;5597}5598#endif5599}56005601void MicroProfileDumpHtml(MicroProfileWriteCallback CB, void* Handle, uint64_t nMaxFrames, const char* pHost, uint64_t nStartFrameId = (uint64_t)-1)5602{5603// Stall pushing of timers5604uint64_t nActiveGroup[MICROPROFILE_MAX_GROUP_INTS];5605memcpy(nActiveGroup, S.nActiveGroups, sizeof(S.nActiveGroups));5606memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups));5607bool AnyActive = S.AnyActive;5608S.AnyActive = false;56095610S.nPauseTicks = MP_TICK();56115612MicroProfileGetCoreInformation();56135614if(S.bContextSwitchRunning)5615{5616auto StallForContextSwitchThread = []()5617{5618int64_t nPauseTicks = S.nPauseTicks;5619int64_t nContextSwitchStalledTick = S.nContextSwitchStalledTick;5620return (nPauseTicks - nContextSwitchStalledTick) > 0;5621};5622int SleepMs = 1;5623while(S.bContextSwitchRunning && !S.bContextSwitchStop && StallForContextSwitchThread())5624{5625MicroProfileSleep(SleepMs);5626SleepMs = SleepMs * 2 / 3;5627SleepMs = MicroProfileMin(128, SleepMs);5628}5629int64_t TicksAfterStall = MP_TICK();5630uprintf("Stalled %7.2fms for context switch data\n", MicroProfileTickToMsMultiplierCpu() * (TicksAfterStall - S.nPauseTicks));5631}56325633MicroProfileHashTable StringsHashTable;5634MicroProfileHashTableInit(&StringsHashTable, 50, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString);56355636defer5637{5638MicroProfileHashTableDestroy(&StringsHashTable);5639};56405641MicroProfileCounterFetchCounters();5642for(size_t i = 0; i < g_MicroProfileHtml_begin_count; ++i)5643{5644CB(Handle, g_MicroProfileHtml_begin_sizes[i] - 1, g_MicroProfileHtml_begin[i]);5645}5646// dump info5647uint64_t nTicks = MP_TICK();56485649float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());5650float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());5651float fAggregateMs = fToMsCPU * (nTicks - S.nAggregateFlipTick);56525653uint32_t nNumFrames = 0;5654uint32_t nFirstFrame = (uint32_t)-1;5655if(nStartFrameId != (uint64_t)-1)5656{5657// search for the frane5658for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i)5659{5660if(S.Frames[i].nFrameId == nStartFrameId)5661{5662nFirstFrame = i;5663break;5664}5665}5666if(nFirstFrame != (uint32_t)-1)5667{5668uint32_t nLastFrame = S.nFrameCurrent;5669uint32_t nDistance = (MICROPROFILE_MAX_FRAME_HISTORY + nFirstFrame - nLastFrame) % MICROPROFILE_MAX_FRAME_HISTORY;5670nNumFrames = MicroProfileMin(nDistance, (uint32_t)nMaxFrames);5671}5672}56735674if(nNumFrames == 0)5675{5676nNumFrames = (MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3); // leave a few to not overwrite5677nNumFrames = MicroProfileMin(nNumFrames, (uint32_t)nMaxFrames);5678nFirstFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;5679}56805681uint32_t nLastFrame = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;5682MP_ASSERT(nFirstFrame < MICROPROFILE_MAX_FRAME_HISTORY);5683MP_ASSERT(nLastFrame < MICROPROFILE_MAX_FRAME_HISTORY);56845685MicroProfilePrintf(CB, Handle, "S.DumpHost = '%s';\n", pHost ? pHost : "");5686time_t CaptureTime;5687time(&CaptureTime);5688MicroProfilePrintf(CB, Handle, "S.DumpUtcCaptureTime = %ld;\n", CaptureTime);5689MicroProfilePrintf(CB, Handle, "S.AggregateInfo = {'Frames':%d, 'Time':%f};\n", S.nAggregateFrames, fAggregateMs);56905691// categories5692MicroProfilePrintf(CB, Handle, "S.CategoryInfo = Array(%d);\n", S.nCategoryCount);5693for(uint32_t i = 0; i < S.nCategoryCount; ++i)5694{5695MicroProfilePrintf(CB, Handle, "S.CategoryInfo[%d] = \"%s\";\n", i, S.CategoryInfo[i].pName);5696}56975698// groups5699MicroProfilePrintf(CB, Handle, "S.GroupInfo = Array(%d);\n\n", S.nGroupCount + 1);5700uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;5701float fRcpAggregateFrames = 1.f / nAggregateFrames;5702(void)fRcpAggregateFrames;5703char ColorString[32];5704for(uint32_t i = 0; i < S.nGroupCount; ++i)5705{5706MP_ASSERT(i == S.GroupInfo[i].nGroupIndex);5707float fToMs = S.GroupInfo[i].Type == MicroProfileTokenTypeCpu ? fToMsCPU : fToMsGPU;5708const char* pColorStr = "";5709if(S.GroupInfo[i].nColor != 0x42)5710{5711stbsp_snprintf(ColorString,5712sizeof(ColorString) - 1,5713"#%02x%02x%02x",5714MICROPROFILE_UNPACK_RED(S.GroupInfo[i].nColor) & 0xff,5715MICROPROFILE_UNPACK_GREEN(S.GroupInfo[i].nColor) & 0xff,5716MICROPROFILE_UNPACK_BLUE(S.GroupInfo[i].nColor) & 0xff);5717pColorStr = &ColorString[0];5718}5719MicroProfilePrintf(CB,5720Handle,5721"S.GroupInfo[%d] = MakeGroup(%d, \"%s\", %d, %d, %d, %f, %f, %f, '%s');\n",5722S.GroupInfo[i].nGroupIndex,5723S.GroupInfo[i].nGroupIndex,5724S.GroupInfo[i].pName,5725S.GroupInfo[i].nCategory,5726S.GroupInfo[i].nNumTimers,5727S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? 1 : 0,5728fToMs * S.AggregateGroup[i],5729fToMs * S.AggregateGroup[i] / nAggregateFrames,5730fToMs * S.AggregateGroupMax[i],5731pColorStr);5732}5733uint32_t nUncategorized = S.nGroupCount;57345735MicroProfilePrintf(CB,5736Handle,5737"S.GroupInfo[%d] = MakeGroup(%d, \"%s\", %d, %d, %d, %f, %f, %f, 'grey');\n",5738nUncategorized,5739nUncategorized,5740"Uncategorized",5741-1,57421,5743// S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? 1 :57440,57450,57460,57470);57485749// timers57505751uint32_t nNumTimers = S.nTotalTimers;5752uint32_t nBlockSize = 2 * nNumTimers;5753float* pTimers = (float*)alloca(nBlockSize * 9 * sizeof(float));5754float* pAverage = pTimers + nBlockSize;5755float* pMax = pTimers + 2 * nBlockSize;5756float* pMin = pTimers + 3 * nBlockSize;5757float* pCallAverage = pTimers + 4 * nBlockSize;5758float* pTimersExclusive = pTimers + 5 * nBlockSize;5759float* pAverageExclusive = pTimers + 6 * nBlockSize;5760float* pMaxExclusive = pTimers + 7 * nBlockSize;5761float* pTotal = pTimers + 8 * nBlockSize;57625763MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pMin, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers);57645765MicroProfilePrintf(CB, Handle, "\nS.TimerInfo = Array(%d);\n\n", S.nTotalTimers);5766for(uint32_t i = 0; i < S.nTotalTimers; ++i)5767{5768uint32_t nIdx = i * 2;5769MP_ASSERT(i == S.TimerInfo[i].nTimerIndex);5770MicroProfilePrintf(CB, Handle, "S.Meta%d = [];\n", i);5771MicroProfilePrintf(CB, Handle, "S.MetaAvg%d = [];\n", i);5772MicroProfilePrintf(CB, Handle, "S.MetaMax%d = [];\n", i);57735774uint32_t nColor = S.TimerInfo[i].nColor;5775uint32_t nColorDark = (nColor >> 1) & ~0x80808080;5776MicroProfilePrintf(CB,5777Handle,5778"S.TimerInfo[%d] = MakeTimer(%d, \"%s\", %d, '#%02x%02x%02x','#%02x%02x%02x', %f, %f, %f, %f, %f, %f, %d, %f, S.Meta%d, S.MetaAvg%d, S.MetaMax%d, %d);\n",5779S.TimerInfo[i].nTimerIndex,5780S.TimerInfo[i].nTimerIndex,5781S.TimerInfo[i].pName,5782S.TimerInfo[i].nGroupIndex,5783MICROPROFILE_UNPACK_RED(nColor) & 0xff,5784MICROPROFILE_UNPACK_GREEN(nColor) & 0xff,5785MICROPROFILE_UNPACK_BLUE(nColor) & 0xff,5786MICROPROFILE_UNPACK_RED(nColorDark) & 0xff,5787MICROPROFILE_UNPACK_GREEN(nColorDark) & 0xff,5788MICROPROFILE_UNPACK_BLUE(nColorDark) & 0xff,5789pAverage[nIdx],5790pMax[nIdx],5791pMin[nIdx],5792pAverageExclusive[nIdx],5793pMaxExclusive[nIdx],5794pCallAverage[nIdx],5795S.Aggregate[i].nCount,5796pTotal[nIdx],5797i,5798i,5799i,5800S.TimerInfo[i].Flags);5801}58025803uint32_t nTotalTimersExt = S.nTotalTimers;5804{5805for(uint32_t j = 0; j < S.nNumLogs; ++j)5806{5807MicroProfileThreadLog* pLog = S.Pool[j];5808uint32_t nLogStart = S.Frames[nFirstFrame].nLogStart[j];5809uint32_t nLogEnd = S.Frames[nLastFrame].nLogStart[j];5810uint64_t nLogType;5811if(nLogStart != nLogEnd)5812{5813for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)5814{5815uint64_t v = pLog->Log[k];5816nLogType = MicroProfileLogGetType(v);5817uint32_t tidx = MicroProfileLogGetTimerIndex(v);5818if((nLogType == MP_LOG_ENTER || nLogType == MP_LOG_LEAVE) && tidx == ETOKEN_CSTR_PTR)5819{5820MP_ASSERT(k + 1 != nLogEnd);5821uint64_t v1 = pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE];5822const char* pString = (const char*)MicroProfileLogGetExtendedPayloadNoDataPtr(v1);5823uintptr_t value;5824if(!MicroProfileHashTableGet(&StringsHashTable, (uint64_t)pString, &value))5825{5826uintptr_t nTimerIndex = nTotalTimersExt++;5827MicroProfileHashTableSet(&StringsHashTable, (uint64_t)pString, nTimerIndex);5828MicroProfilePrintf(5829CB, Handle, "S.TimerInfo.push(MakeTimer(%d, \"%s\", %d, '#000000','#000000', 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0));\n", nTimerIndex, pString, nUncategorized);5830}5831}5832}5833}5834}5835}58365837MicroProfilePrintf(CB, Handle, "\nS.ThreadNames = [");5838for(uint32_t i = 0; i < S.nNumLogs; ++i)5839{5840if(S.Pool[i])5841{5842MicroProfilePrintf(CB, Handle, "'%s',", S.Pool[i]->ThreadName);5843}5844else5845{5846MicroProfilePrintf(CB, Handle, "'Thread %d',", i);5847}5848}5849MicroProfilePrintf(CB, Handle, "];\n\n");5850MicroProfilePrintf(CB, Handle, "\nS.ISGPU = [");5851for(uint32_t i = 0; i < S.nNumLogs; ++i)5852{5853MicroProfilePrintf(CB, Handle, "%d,", (S.Pool[i] && S.Pool[i]->nGpu) ? 1 : 0);5854}5855MicroProfilePrintf(CB, Handle, "];\n\n");58565857for(uint32_t i = 0; i < S.nNumLogs; ++i)5858{5859if(S.Pool[i])5860{5861MicroProfilePrintf(CB, Handle, "S.ThreadGroupTime%d = [", i);5862float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;5863for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)5864{5865MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j] / nAggregateFrames * fToMs);5866}5867MicroProfilePrintf(CB, Handle, "];\n");5868}5869}5870MicroProfilePrintf(CB, Handle, "\nS.ThreadGroupTimeArray = [");5871for(uint32_t i = 0; i < S.nNumLogs; ++i)5872{5873if(S.Pool[i])5874{5875MicroProfilePrintf(CB, Handle, "S.ThreadGroupTime%d,", i);5876}5877}5878MicroProfilePrintf(CB, Handle, "];\n");58795880for(uint32_t i = 0; i < S.nNumLogs; ++i)5881{5882if(S.Pool[i])5883{5884MicroProfilePrintf(CB, Handle, "S.ThreadGroupTimeTotal%d = [", i);5885float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU;5886for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)5887{5888MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j] * fToMs);5889}5890MicroProfilePrintf(CB, Handle, "];\n");5891}5892}5893MicroProfilePrintf(CB, Handle, "\nS.ThreadGroupTimeTotalArray = [");5894for(uint32_t i = 0; i < S.nNumLogs; ++i)5895{5896if(S.Pool[i])5897{5898MicroProfilePrintf(CB, Handle, "S.ThreadGroupTimeTotal%d,", i);5899}5900}5901MicroProfilePrintf(CB, Handle, "];");59025903MicroProfilePrintf(CB, Handle, "\nS.ThreadIds = [");5904for(uint32_t i = 0; i < S.nNumLogs; ++i)5905{5906if(S.Pool[i])5907{5908MicroProfileThreadIdType ThreadId = S.Pool[i]->nThreadId;5909if(!ThreadId)5910{5911ThreadId = (MicroProfileThreadIdType)-1;5912}5913MicroProfilePrintf(CB, Handle, "%" PRIu64 ",", (uint64_t)ThreadId);5914}5915else5916{5917MicroProfilePrintf(CB, Handle, "-1,");5918}5919}5920MicroProfilePrintf(CB, Handle, "];\n\n");59215922for(int i = 0; i < (int)S.nNumCounters; ++i)5923{5924bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0;5925if(0 != (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DETAILED) && !IsDouble)5926{5927int64_t nCounterMax = S.nCounterMax[i];5928int64_t nCounterMin = S.nCounterMin[i];5929uint32_t nBaseIndex = S.nCounterHistoryPut;5930MicroProfilePrintf(CB, Handle, "\nS.CounterHistoryArray%d =[", i);5931for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j)5932{5933uint32_t nHistoryIndex = (nBaseIndex + j) % MICROPROFILE_GRAPH_HISTORY;5934int64_t nValue = MicroProfileClamp(S.nCounterHistory[nHistoryIndex][i], nCounterMin, nCounterMax);5935MicroProfilePrintf(CB, Handle, "%lld,", nValue);5936}5937MicroProfilePrintf(CB, Handle, "];\n");59385939int64_t nCounterHeightBase = nCounterMax;5940int64_t nCounterOffset = 0;5941if(nCounterMin < 0)5942{5943nCounterHeightBase = nCounterMax - nCounterMin;5944nCounterOffset = -nCounterMin;5945}5946double fRcp = nCounterHeightBase ? (1.0 / nCounterHeightBase) : 0;59475948MicroProfilePrintf(CB, Handle, "\nS.CounterHistoryArrayPrc%d =[", i);5949for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j)5950{5951uint32_t nHistoryIndex = (nBaseIndex + j) % MICROPROFILE_GRAPH_HISTORY;5952int64_t nValue = MicroProfileClamp(S.nCounterHistory[nHistoryIndex][i], nCounterMin, nCounterMax);5953float fPrc = (nValue + nCounterOffset) * fRcp;5954MicroProfilePrintf(CB, Handle, "%f,", fPrc);5955}5956MicroProfilePrintf(CB, Handle, "];\n");5957MicroProfilePrintf(CB, Handle, "S.CounterHistory%d = MakeCounterHistory(%d, S.CounterHistoryArray%d, S.CounterHistoryArrayPrc%d)\n", i, i, i, i);5958}5959else5960{5961MicroProfilePrintf(CB, Handle, "S.CounterHistory%d;\n", i);5962}5963}59645965MicroProfilePrintf(CB, Handle, "\nS.CounterInfo = [");59665967for(int i = 0; i < (int)S.nNumCounters; ++i)5968{5969bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0;5970float fCounterPrc = 0.f;5971float fBoxPrc = 1.f;5972double dCounter, dLimit, dMax, dMin;5973char Formatted[64];5974char FormattedLimit[64];59755976if(!IsDouble)5977{5978uint64_t nCounter = S.Counters[i].load();5979uint64_t nLimit = S.CounterInfo[i].nLimit;5980fCounterPrc = 0.f;5981if(nLimit)5982{5983fCounterPrc = (float)nCounter / nLimit;5984if(fCounterPrc > 1.f)5985{5986fBoxPrc = 1.f / fCounterPrc;5987fCounterPrc = 1.f;5988}5989}5990MicroProfileFormatCounter(S.CounterInfo[i].eFormat, nCounter, Formatted, sizeof(Formatted) - 1);5991MicroProfileFormatCounter(S.CounterInfo[i].eFormat, S.CounterInfo[i].nLimit, FormattedLimit, sizeof(FormattedLimit) - 1);59925993dCounter = (double)nCounter;5994dMin = (double)S.nCounterMin[i];5995dMax = (double)S.nCounterMax[i];5996dLimit = (double)nLimit;5997}5998else5999{6000dCounter = S.CountersDouble[i].load();6001dLimit = S.CounterInfo[i].dLimit;6002fCounterPrc = 0.f;6003if(dLimit > 0.f)6004{6005fCounterPrc = (float)(dCounter / dLimit);6006if(fCounterPrc > 1.f)6007{6008fBoxPrc = 1.f / fCounterPrc;6009fCounterPrc = 1.f;6010}6011}6012MicroProfileFormatCounterDouble(S.CounterInfo[i].eFormat, dCounter, Formatted, sizeof(Formatted) - 1);6013MicroProfileFormatCounterDouble(S.CounterInfo[i].eFormat, S.CounterInfo[i].dLimit, FormattedLimit, sizeof(FormattedLimit) - 1);6014dMin = (double)S.dCounterMin[i];6015dMax = (double)S.dCounterMax[i];6016}6017MicroProfilePrintf(CB,6018Handle,6019"MakeCounter(%d, %d, %d, %d, %d, '%s', %f, %f, %f, '%s', %f, '%s', %f, %f, %d, S.CounterHistory%d),",6020i,6021S.CounterInfo[i].nParent,6022S.CounterInfo[i].nSibling,6023S.CounterInfo[i].nFirstChild,6024S.CounterInfo[i].nLevel,6025S.CounterInfo[i].pName,6026dCounter,6027dMin,6028dMax,6029Formatted,6030dLimit,6031FormattedLimit,6032fCounterPrc,6033fBoxPrc,6034S.CounterInfo[i].eFormat == MICROPROFILE_COUNTER_FORMAT_BYTES ? 1 : 0,6035i);6036}6037MicroProfilePrintf(CB, Handle, "];\n\n");60386039const int64_t nTickStart = S.Frames[nFirstFrame].nFrameStartCpu;6040const int64_t nTickEnd = S.Frames[nLastFrame].nFrameStartCpu;6041int64_t nTickStartGpu = S.Frames[nFirstFrame].nFrameStartGpu;60426043int64_t nTickReferenceCpu, nTickReferenceGpu;6044int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();6045int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();6046int nTickReference = 0;6047if(MicroProfileGetGpuTickReference(&nTickReferenceCpu, &nTickReferenceGpu))6048{6049nTickStartGpu = (nTickStart - nTickReferenceCpu) * nTicksPerSecondGpu / nTicksPerSecondCpu + nTickReferenceGpu;6050nTickReference = 1;6051}60526053uprintf("dumping %d frames\n", nNumFrames);6054uprintf("dumping frame %d to %d\n", nFirstFrame, nLastFrame);60556056uint32_t* nTimerCounter = (uint32_t*)alloca(sizeof(uint32_t) * S.nTotalTimers);6057memset(nTimerCounter, 0, sizeof(uint32_t) * S.nTotalTimers);60586059{6060MicroProfilePrintf(CB, Handle, " //Timeline begin\n");6061MicroProfileThreadLog* pLog = &S.TimelineLog;6062uint32_t nFrameIndexFirst = (nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY;6063uint32_t nFrameIndexLast = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY;6064{6065// find the frame that has an active marker the furtest distance from the selected range6066int nDelta = 0;6067int nOffset = 0;6068for(uint32_t i = nFrameIndexFirst; i != nFrameIndexLast; i = (i + 1) % MICROPROFILE_MAX_FRAME_HISTORY)6069{6070int D = (int)S.Frames[i].nTimelineFrameMax - nOffset;6071nDelta = MicroProfileMax(D, nDelta);6072nOffset++;6073}6074nFrameIndexFirst = (nFirstFrame - nDelta) % MICROPROFILE_MAX_FRAME_HISTORY;6075}60766077uint32_t nLogStart = S.Frames[nFrameIndexFirst].nLogStartTimeline;6078uint32_t nLogEnd = S.Frames[nFrameIndexLast].nLogStartTimeline;6079float fToMs = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);60806081#define pp(...) MicroProfilePrintf(CB, Handle, __VA_ARGS__)60826083if(nLogStart != nLogEnd)6084{6085uint32_t nLogType;6086float fTime;6087int f = 0;60886089pp("S.TimelineColorArray=[");6090for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6091{6092uint64_t v = pLog->Log[k];6093uint64_t nIndex = MicroProfileLogGetTimerIndex(v);6094uint64_t nTick = MicroProfileLogGetTick(v);6095(void)nTick;6096nLogType = MicroProfileLogGetType(v);6097switch(nLogType)6098{6099case MP_LOG_ENTER:6100break;6101case MP_LOG_LEAVE:6102pp("%c'%s'", f++ ? ',' : ' ', "#ff8080");6103break;61046105case MP_LOG_EXTENDED:6106case MP_LOG_EXTENDED_NO_DATA:6107uint32_t payload = MicroProfileLogGetExtendedPayload(v);6108if(nIndex == ETOKEN_CUSTOM_COLOR)6109{6110uint32_t nColor = payload;6111pp("%c'#%02x%02x%02x'", f++ ? ',' : ' ', MICROPROFILE_UNPACK_RED(nColor) & 0xff, MICROPROFILE_UNPACK_GREEN(nColor) & 0xff, MICROPROFILE_UNPACK_BLUE(nColor) & 0xff);6112}6113k += MicroProfileLogGetDataSize(v);6114break;6115}6116}6117pp("];\n");61186119f = 0;6120pp("S.TimelineIdArray=[");6121for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6122{6123uint64_t v = pLog->Log[k];6124uint64_t nIndex = MicroProfileLogGetTimerIndex(v);6125uint64_t nTick = MicroProfileLogGetTick(v);6126(void)nTick;6127nLogType = MicroProfileLogGetType(v);6128switch(nLogType)6129{6130case MP_LOG_ENTER:6131case MP_LOG_LEAVE:6132case MP_LOG_EXTENDED_NO_DATA:61336134break;6135case MP_LOG_EXTENDED:6136if(nIndex == ETOKEN_CUSTOM_ID)6137{6138pp("%c%d", f++ ? ',' : ' ', (uint32_t)nTick);6139}6140k += MicroProfileLogGetDataSize(v);6141break;6142}6143}6144pp("];\n");61456146f = 0;61476148pp("S.TimelineArray=[");6149for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6150{6151uint64_t v = pLog->Log[k];6152nLogType = MicroProfileLogGetType(v);6153switch(nLogType)6154{6155case MP_LOG_ENTER:6156case MP_LOG_LEAVE:6157fTime = MicroProfileLogTickDifference(nTickStart, v) * fToMs;6158pp("%c%f", f++ ? ',' : ' ', fTime);6159break;6160case MP_LOG_EXTENDED:6161k += MicroProfileLogGetDataSize(v);6162break;6163case MP_LOG_EXTENDED_NO_DATA:6164break;6165}6166}6167pp("];\n");6168pp("S.TimelineNames=[");6169f = 0;6170char String[MICROPROFILE_MAX_STRING + 1];6171for(uint32_t k = nLogStart; k != nLogEnd;)6172{6173uint64_t v = pLog->Log[k];6174nLogType = MicroProfileLogGetType(v);6175uint64_t nIndex = MicroProfileLogGetTimerIndex(v);6176uint64_t nTick = MicroProfileLogGetTick(v);6177(void)nTick;6178switch(nLogType)6179{6180case MP_LOG_ENTER:6181case MP_LOG_LEAVE:6182if(nIndex == ETOKEN_CUSTOM_NAME && nLogType == MP_LOG_LEAVE)6183{6184// pp(f++ ? ",''" : "''");6185}6186k = (k + 1) % MICROPROFILE_BUFFER_SIZE;6187break;6188case MP_LOG_EXTENDED_NO_DATA:6189k = (k + 1) % MICROPROFILE_BUFFER_SIZE;6190break;6191case MP_LOG_EXTENDED:6192uint32_t nSize = MicroProfileLogGetDataSize(v);61936194if(nIndex == ETOKEN_CUSTOM_ID)6195{6196char* pSource = (char*)&pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE];6197const char* pOut = nullptr;6198if(nSize == 0)6199{6200pOut = "";6201}6202else if(k + nSize <= MICROPROFILE_BUFFER_SIZE)6203{6204pOut = pSource;6205}6206else6207{6208pOut = &String[0];6209char* pDest = &String[0];6210MP_ASSERT(nSize * 8 < sizeof(MICROPROFILE_MAX_STRING) + 1);6211uint32_t Index = (k + 1) % MICROPROFILE_BUFFER_SIZE;6212for(uint32_t l = 0; l < nSize; ++l)6213{6214memcpy(pDest, (char*)pLog->Log[Index], sizeof(uint64_t));6215Index = (Index + 1) % MICROPROFILE_BUFFER_SIZE;6216}6217}6218if(f++)6219{6220pp(",'%s'", pOut);6221}6222else6223{6224pp("'%s'", pOut);6225}6226}6227k = (k + 1 + nSize) % MICROPROFILE_BUFFER_SIZE;6228break;6229}6230}6231pp("];\n");6232}6233MicroProfilePrintf(CB, Handle, " //Timeline end\n");6234}62356236MicroProfilePrintf(CB, Handle, "S.Frames = Array(%d);\n", nNumFrames);6237for(uint32_t i = 0; i < nNumFrames; ++i)6238{6239uint32_t nFrameIndex = (nFirstFrame + i) % MICROPROFILE_MAX_FRAME_HISTORY;6240uint32_t nFrameIndexNext = (nFrameIndex + 1) % MICROPROFILE_MAX_FRAME_HISTORY;62416242for(uint32_t j = 0; j < S.nNumLogs; ++j)6243{6244MicroProfileThreadLog* pLog = S.Pool[j];6245int64_t nStartTickBase = pLog->nGpu ? nTickStartGpu : nTickStart;6246uint32_t nLogStart = S.Frames[nFrameIndex].nLogStart[j];6247uint32_t nLogEnd = S.Frames[nFrameIndexNext].nLogStart[j];6248uint32_t nLogType;6249float fToMs;6250uint64_t nStartTick;6251float fToMsCpu = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);6252float fToMsBase = MicroProfileTickToMsMultiplier(pLog->nGpu ? nTicksPerSecondGpu : nTicksPerSecondCpu);6253MicroProfilePrintf(CB, Handle, "S.ts_%d_%d = [", i, j);6254if(nLogStart != nLogEnd)6255{6256int f = 0;6257for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6258{6259float fTime;6260MicroProfileLogEntry v = pLog->Log[k];6261nLogType = MicroProfileLogGetType(v);6262fToMs = fToMsBase;6263nStartTick = nStartTickBase;6264switch(nLogType)6265{6266case MP_LOG_EXTENDED:6267{6268fTime = 0.f;6269k += MicroProfileLogGetDataSize(v);6270break;6271}6272case MP_LOG_EXTENDED_NO_DATA:6273{6274uint32_t nTimerIndex = (uint32_t)MicroProfileLogGetTimerIndex(v);6275if(nTimerIndex == ETOKEN_GPU_CPU_TIMESTAMP)6276{6277fToMs = fToMsCpu;6278nStartTick = nTickStart;6279fTime = MicroProfileLogTickDifference(nStartTick, v) * fToMs;6280}6281else6282{6283fTime = 0.f;6284}6285break;6286}6287default:6288fTime = MicroProfileLogTickDifference(nStartTick, pLog->Log[k]) * fToMs;6289}6290MicroProfilePrintf(CB, Handle, f++ ? ",%f" : "%f", fTime);6291}6292}6293MicroProfilePrintf(CB, Handle, "];\n");62946295MicroProfilePrintf(CB, Handle, "S.tt_%d_%d = [", i, j);6296if(nLogStart != nLogEnd)6297{6298uint32_t k = nLogStart;6299MicroProfilePrintf(CB, Handle, "%d", MicroProfileLogGetType(pLog->Log[k]));6300for(k = (k + 1) % MICROPROFILE_BUFFER_SIZE; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6301{6302uint64_t v = pLog->Log[k];6303uint32_t nLogType2 = MicroProfileLogGetType(v);63046305if(nLogType2 > MP_LOG_ENTER)6306nLogType2 |= (MicroProfileLogGetExtendedToken(v))6307<< 2; // pack extended token here.. this way all code can check agains ENTER/LEAVE, and only the ext code needs to care about the top bits.6308MicroProfilePrintf(CB, Handle, ",%d", nLogType2);6309if(nLogType2 == MP_LOG_EXTENDED)6310k += MicroProfileLogGetDataSize(v);6311}6312}6313MicroProfilePrintf(CB, Handle, "];\n");63146315MicroProfilePrintf(CB, Handle, "S.ti_%d_%d = [", i, j);6316if(nLogStart != nLogEnd)6317{6318for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE)6319{6320uint64_t v = pLog->Log[k];6321nLogType = MicroProfileLogGetType(v);6322const char* pFormat = k == nLogStart ? "%d" : ",%d";6323if(nLogType == MP_LOG_ENTER || nLogType == MP_LOG_LEAVE)6324{6325uint32_t nTimerIndex = (uint32_t)MicroProfileLogGetTimerIndex(pLog->Log[k]);6326if(ETOKEN_CSTR_PTR == nTimerIndex)6327{6328MP_ASSERT(k + 1 != nLogEnd);6329uint64_t v1 = pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE];63306331const char* pString = (const char*)MicroProfileLogGetExtendedPayloadNoDataPtr(v1);6332uintptr_t value;6333if(!MicroProfileHashTableGet(&StringsHashTable, (uint64_t)pString, &value))6334{6335MP_BREAK(); // should be covered earlier.6336}6337MicroProfilePrintf(CB, Handle, pFormat, value);6338}6339else6340{6341if(nTimerIndex < S.nTotalTimers)6342{6343nTimerCounter[nTimerIndex]++;6344}6345MicroProfilePrintf(CB, Handle, pFormat, nTimerIndex);6346}6347}6348else6349{6350uint64_t ExtendedToken = MicroProfileLogGetExtendedToken(v);6351uint64_t PayloadNoData = MicroProfileLogGetExtendedPayloadNoData(v);6352switch(ExtendedToken)6353{6354case ETOKEN_GPU_CPU_SOURCE_THREAD:6355MicroProfilePrintf(CB, Handle, pFormat, PayloadNoData);6356break;6357default:6358MicroProfilePrintf(CB, Handle, pFormat, -1);6359}63606361if(nLogType == MP_LOG_EXTENDED)6362k += MicroProfileLogGetDataSize(v);6363}6364}6365}6366MicroProfilePrintf(CB, Handle, "];\n");6367}63686369MicroProfilePrintf(CB, Handle, "S.ts%d = [", i);6370for(uint32_t j = 0; j < S.nNumLogs; ++j)6371{6372MicroProfilePrintf(CB, Handle, "S.ts_%d_%d,", i, j);6373}6374MicroProfilePrintf(CB, Handle, "];\n");6375MicroProfilePrintf(CB, Handle, "S.tt%d = [", i);6376for(uint32_t j = 0; j < S.nNumLogs; ++j)6377{6378MicroProfilePrintf(CB, Handle, "S.tt_%d_%d,", i, j);6379}6380MicroProfilePrintf(CB, Handle, "];\n");63816382MicroProfilePrintf(CB, Handle, "S.ti%d = [", i);6383for(uint32_t j = 0; j < S.nNumLogs; ++j)6384{6385MicroProfilePrintf(CB, Handle, "S.ti_%d_%d,", i, j);6386}6387MicroProfilePrintf(CB, Handle, "];\n");63886389int64_t nFrameStart = S.Frames[nFrameIndex].nFrameStartCpu;6390int64_t nFrameEnd = S.Frames[nFrameIndexNext].nFrameStartCpu;63916392float fToMs = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);6393float fFrameMs = MicroProfileLogTickDifference(nTickStart, nFrameStart) * fToMs;6394float fFrameEndMs = MicroProfileLogTickDifference(nTickStart, nFrameEnd) * fToMs;6395float fFrameGpuMs = 0;6396float fFrameGpuEndMs = 0;6397if(nTickReference)6398{6399fFrameGpuMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndex].nFrameStartGpu) * fToMsGPU;6400fFrameGpuEndMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndexNext].nFrameStartGpu) * fToMsGPU;6401}6402MicroProfilePrintf(CB, Handle, "S.Frames[%d] = MakeFrame(%d, %f, %f, %f, %f, S.ts%d, S.tt%d, S.ti%d);\n", i, 0, fFrameMs, fFrameEndMs, fFrameGpuMs, fFrameGpuEndMs, i, i, i);6403}64046405uint32_t nContextSwitchStart = 0;6406uint32_t nContextSwitchEnd = 0;6407MicroProfileContextSwitchSearch(&nContextSwitchStart, &nContextSwitchEnd, nTickStart, nTickEnd);64086409uprintf("CONTEXT SWITCH SEARCH .... %d %d %d .... %lld, %lld\n", nContextSwitchStart, nContextSwitchEnd, nContextSwitchEnd - nContextSwitchStart, nTickStart, nTickEnd);64106411uint32_t nWrittenBefore = S.nWebServerDataSent;6412MicroProfilePrintf(CB, Handle, "S.CSwitchThreadInOutCpu = [");6413for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)6414{6415MicroProfileContextSwitch CS = S.ContextSwitch[j];6416int nCpu = CS.nCpu;6417MicroProfilePrintf(CB, Handle, "%d,%d,%d,", CS.nThreadIn, CS.nThreadOut, nCpu);6418}6419MicroProfilePrintf(CB, Handle, "];\n");6420MicroProfilePrintf(CB, Handle, "S.CSwitchTime = [");6421float fToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());6422for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)6423{6424MicroProfileContextSwitch CS = S.ContextSwitch[j];6425float fTime = MicroProfileLogTickDifference(nTickStart, CS.nTicks) * fToMsCpu;6426MicroProfilePrintf(CB, Handle, "%f,", fTime);6427}6428MicroProfilePrintf(CB, Handle, "];\n");64296430MicroProfilePrintf(CB, Handle, "S.CSwitchThreads = {");64316432MicroProfileThreadInfo* pThreadInfo = nullptr;6433uint32_t nNumThreads = MicroProfileGetThreadInfoArray(&pThreadInfo);6434for(uint32_t i = 0; i < nNumThreads; ++i)6435{6436const char* p1 = pThreadInfo[i].pThreadModule ? pThreadInfo[i].pThreadModule : "?";6437const char* p2 = pThreadInfo[i].pProcessModule ? pThreadInfo[i].pProcessModule : "?";64386439MicroProfilePrintf(CB,6440Handle,6441"%" PRId64 ":{\'tid\':%" PRId64 ",\'pid\':%" PRId64 ",\'t\':\'%s\',\'p\':\'%s\'},",6442(uint64_t)pThreadInfo[i].tid,6443(uint64_t)pThreadInfo[i].tid,6444(uint64_t)pThreadInfo[i].pid,6445p1,6446p2);6447}64486449MicroProfilePrintf(CB, Handle, "};\n");6450MicroProfilePrintf(CB, Handle, "S.CoreEfficiencyClass = [");6451for(uint32_t i = 0; i < MICROPROFILE_MAX_CPU_CORES; ++i)6452{6453MicroProfilePrintf(CB, Handle, "%d,", S.CoreEfficiencyClass[i]);6454}6455MicroProfilePrintf(CB, Handle, "];\n");64566457{6458MicroProfilePrintf(CB, Handle, "//String Table\n");6459MicroProfilePrintf(CB, Handle, "S.StringTable = {}\n");6460// dump string table6461MicroProfileHashTableIterator beg = MicroProfileGetHashTableIteratorBegin(&StringsHashTable);6462MicroProfileHashTableIterator end = MicroProfileGetHashTableIteratorEnd(&StringsHashTable);6463while(beg != end)6464{6465uint64_t Key = beg->Key;6466uint64_t Value = beg->Value;6467MicroProfilePrintf(CB, Handle, "S.StringTable[%d] = '%s';\n", Value, (const char*)Key);6468beg++;6469}6470}64716472uint32_t nWrittenAfter = S.nWebServerDataSent;64736474MicroProfilePrintf(CB, Handle, "//CSwitch Size %d\n", nWrittenAfter - nWrittenBefore);64756476for(size_t i = 0; i < g_MicroProfileHtml_end_count; ++i)6477{6478CB(Handle, g_MicroProfileHtml_end_sizes[i] - 1, g_MicroProfileHtml_end[i]);6479}64806481uint32_t* nGroupCounter = (uint32_t*)alloca(sizeof(uint32_t) * S.nGroupCount);64826483memset(nGroupCounter, 0, sizeof(uint32_t) * S.nGroupCount);6484for(uint32_t i = 0; i < S.nTotalTimers; ++i)6485{6486uint32_t nGroupIndex = S.TimerInfo[i].nGroupIndex;6487nGroupCounter[nGroupIndex] += nTimerCounter[i];6488}64896490uint32_t* nGroupCounterSort = (uint32_t*)alloca(sizeof(uint32_t) * S.nGroupCount);6491uint32_t* nTimerCounterSort = (uint32_t*)alloca(sizeof(uint32_t) * S.nTotalTimers);6492for(uint32_t i = 0; i < S.nGroupCount; ++i)6493{6494nGroupCounterSort[i] = i;6495}6496for(uint32_t i = 0; i < S.nTotalTimers; ++i)6497{6498nTimerCounterSort[i] = i;6499}6500std::sort(nGroupCounterSort, nGroupCounterSort + S.nGroupCount, [nGroupCounter](const uint32_t l, const uint32_t r) { return nGroupCounter[l] > nGroupCounter[r]; });65016502std::sort(nTimerCounterSort, nTimerCounterSort + S.nTotalTimers, [nTimerCounter](const uint32_t l, const uint32_t r) { return nTimerCounter[l] > nTimerCounter[r]; });65036504MicroProfilePrintf(CB, Handle, "\n<!--\nMarker Per Group\n");6505for(uint32_t i = 0; i < S.nGroupCount; ++i)6506{6507uint32_t idx = nGroupCounterSort[i];6508MicroProfilePrintf(CB, Handle, "%8d:%s\n", nGroupCounter[idx], S.GroupInfo[idx].pName);6509}6510MicroProfilePrintf(CB, Handle, "Marker Per Timer\n");6511for(uint32_t i = 0; i < S.nTotalTimers; ++i)6512{6513uint32_t idx = nTimerCounterSort[i];6514MicroProfilePrintf(CB, Handle, "%8d:%s(%s)\n", nTimerCounter[idx], S.TimerInfo[idx].pName, S.GroupInfo[S.TimerInfo[idx].nGroupIndex].pName);6515}6516MicroProfilePrintf(CB, Handle, "\n-->\n");65176518memcpy(S.nActiveGroups, nActiveGroup, sizeof(S.nActiveGroups));6519S.AnyActive = AnyActive;6520#if MICROPROFILE_DEBUG6521int64_t nTicksEnd = MP_TICK();6522float fMs = fToMsCpu * (nTicksEnd - S.nPauseTicks);6523uprintf("html dump took %6.2fms\n", fMs);6524#endif65256526#undef pp65276528S.nPauseTicks = 0;6529}65306531void MicroProfileWriteFile(void* Handle, size_t nSize, const char* pData)6532{6533fwrite(pData, nSize, 1, (FILE*)Handle);6534}65356536void MicroProfileDumpToFile()6537{6538std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());6539if(S.nDumpFileNextFrame & 1)6540{6541char Path[MICROPROFILE_MAX_PATH];6542int Length = snprintf(Path, sizeof(S.HtmlDumpPath), "%s.html", S.HtmlDumpPath);6543if(Length > 0 && Length < MICROPROFILE_MAX_PATH)6544{6545FILE* F = fopen(Path, "w");6546if(F)6547{6548MicroProfileDumpHtml(MicroProfileWriteFile, F, S.DumpFrameCount, S.HtmlDumpPath);6549fclose(F);6550}6551}6552}6553if(S.nDumpFileNextFrame & 2)6554{6555#if MICROPROFILE_LEGACY_CSV6556MicroProfileDumpCsvLegacy();6557#else6558MicroProfileDumpCsv(S.DumpFrameCount);6559#endif6560}6561}65626563void MicroProfileFlushSocket(MpSocket Socket)6564{6565send(Socket, &S.WebServerBuffer[0], S.WebServerPut, 0);6566S.WebServerPut = 0;6567}65686569void MicroProfileWriteSocket(void* Handle, size_t nSize, const char* pData)6570{6571S.nWebServerDataSent += nSize;6572MpSocket Socket = *(MpSocket*)Handle;6573if(nSize > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE / 2)6574{6575MicroProfileFlushSocket(Socket);6576send(Socket, pData, (int)nSize, 0);6577}6578else6579{6580memcpy(&S.WebServerBuffer[S.WebServerPut], pData, nSize);6581S.WebServerPut += (uint32_t)nSize;6582if(S.WebServerPut > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE / 2)6583{6584MicroProfileFlushSocket(Socket);6585}6586}6587}65886589#if MICROPROFILE_MINIZ6590#ifndef MICROPROFILE_COMPRESS_BUFFER_SIZE6591#define MICROPROFILE_COMPRESS_BUFFER_SIZE (256 << 10)6592#endif65936594#define MICROPROFILE_COMPRESS_CHUNK (MICROPROFILE_COMPRESS_BUFFER_SIZE / 2)6595struct MicroProfileCompressedSocketState6596{6597unsigned char DeflateOut[MICROPROFILE_COMPRESS_CHUNK];6598unsigned char DeflateIn[MICROPROFILE_COMPRESS_CHUNK];6599mz_stream Stream;6600MpSocket Socket;6601uint32_t nSize;6602uint32_t nCompressedSize;6603uint32_t nFlushes;6604uint32_t nMemmoveBytes;6605};66066607void MicroProfileCompressedSocketFlush(MicroProfileCompressedSocketState* pState)6608{6609mz_stream& Stream = pState->Stream;6610unsigned char* pSendStart = &pState->DeflateOut[0];6611unsigned char* pSendEnd = &pState->DeflateOut[MICROPROFILE_COMPRESS_CHUNK - Stream.avail_out];6612if(pSendStart != pSendEnd)6613{6614send(pState->Socket, (const char*)pSendStart, pSendEnd - pSendStart, 0);6615pState->nCompressedSize += pSendEnd - pSendStart;6616}6617Stream.next_out = &pState->DeflateOut[0];6618Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK;6619}6620void MicroProfileCompressedSocketStart(MicroProfileCompressedSocketState* pState, MpSocket Socket)6621{6622mz_stream& Stream = pState->Stream;6623memset(&Stream, 0, sizeof(Stream));6624Stream.next_out = &pState->DeflateOut[0];6625Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK;6626Stream.next_in = &pState->DeflateIn[0];6627Stream.avail_in = 0;6628mz_deflateInit(&Stream, Z_DEFAULT_COMPRESSION);6629pState->Socket = Socket;6630pState->nSize = 0;6631pState->nCompressedSize = 0;6632pState->nFlushes = 0;6633pState->nMemmoveBytes = 0;6634}6635void MicroProfileCompressedSocketFinish(MicroProfileCompressedSocketState* pState)6636{6637mz_stream& Stream = pState->Stream;6638MicroProfileCompressedSocketFlush(pState);6639int r = mz_deflate(&Stream, MZ_FINISH);6640MP_ASSERT(r == MZ_STREAM_END);6641MicroProfileCompressedSocketFlush(pState);6642r = mz_deflateEnd(&Stream);6643MP_ASSERT(r == MZ_OK);6644}66456646void MicroProfileCompressedWriteSocket(void* Handle, size_t nSize, const char* pData)6647{6648MicroProfileCompressedSocketState* pState = (MicroProfileCompressedSocketState*)Handle;6649mz_stream& Stream = pState->Stream;6650const unsigned char* pDeflateInEnd = Stream.next_in + Stream.avail_in;6651const unsigned char* pDeflateInStart = &pState->DeflateIn[0];6652const unsigned char* pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK];6653pState->nSize += (uint32_t)nSize;6654if((ptrdiff_t)nSize <= pDeflateInRealEnd - pDeflateInEnd)6655{6656memcpy((void*)pDeflateInEnd, pData, nSize);6657Stream.avail_in += (uint32_t)nSize;6658MP_ASSERT(Stream.next_in + Stream.avail_in <= pDeflateInRealEnd);6659return;6660}6661int Flush = 0;6662while(nSize)6663{6664pDeflateInEnd = Stream.next_in + Stream.avail_in;6665if(Flush)6666{6667pState->nFlushes++;6668MicroProfileCompressedSocketFlush(pState);6669pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK];6670if(pDeflateInEnd == pDeflateInRealEnd)6671{6672if(Stream.avail_in)6673{6674MP_ASSERT(pDeflateInStart != Stream.next_in);6675memmove((void*)pDeflateInStart, Stream.next_in, Stream.avail_in);6676pState->nMemmoveBytes += Stream.avail_in;6677}6678Stream.next_in = pDeflateInStart;6679pDeflateInEnd = Stream.next_in + Stream.avail_in;6680}6681}6682size_t nSpace = pDeflateInRealEnd - pDeflateInEnd;6683size_t nBytes = MicroProfileMin(nSpace, nSize);6684MP_ASSERT(nBytes + pDeflateInEnd <= pDeflateInRealEnd);6685memcpy((void*)pDeflateInEnd, pData, nBytes);6686Stream.avail_in += (uint32_t)nBytes;6687nSize -= nBytes;6688pData += nBytes;6689int r = mz_deflate(&Stream, MZ_NO_FLUSH);6690Flush = r == MZ_BUF_ERROR || nBytes == 0 || Stream.avail_out == 0 ? 1 : 0;6691MP_ASSERT(r == MZ_BUF_ERROR || r == MZ_OK);6692if(r == MZ_BUF_ERROR)6693{6694r = mz_deflate(&Stream, MZ_SYNC_FLUSH);6695}6696}6697}6698#endif66996700#ifndef MicroProfileSetNonBlocking // fcntl doesnt work on a some unix like platforms..6701void MicroProfileSetNonBlocking(MpSocket Socket, int NonBlocking)6702{6703#ifdef _WIN326704u_long nonBlocking = NonBlocking ? 1 : 0;6705ioctlsocket(Socket, FIONBIO, &nonBlocking);6706#else6707int Options = fcntl(Socket, F_GETFL);6708if(NonBlocking)6709{6710fcntl(Socket, F_SETFL, Options | O_NONBLOCK);6711}6712else6713{6714fcntl(Socket, F_SETFL, Options & (~O_NONBLOCK));6715}6716#endif6717}6718#endif67196720void MicroProfileWebServerStart()6721{6722#ifdef _WIN326723WSADATA wsa;6724if(WSAStartup(MAKEWORD(2, 2), &wsa))6725{6726S.ListenerSocket = (MpSocket)-1;6727return;6728}6729#endif67306731S.ListenerSocket = socket(PF_INET, SOCK_STREAM, 6);6732MP_ASSERT(!MP_INVALID_SOCKET(S.ListenerSocket));6733MicroProfileSetNonBlocking(S.ListenerSocket, 1);67346735{6736int r = 0;6737int on = 1;6738#if defined(_WIN32)6739r = setsockopt(S.ListenerSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));6740#else6741r = setsockopt(S.ListenerSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on));6742#endif6743(void)r;6744}67456746int nStartPort = S.nWebServerPort;6747struct sockaddr_in Addr;6748Addr.sin_family = AF_INET;6749Addr.sin_addr.s_addr = INADDR_ANY;6750for(int i = 0; i < 20; ++i)6751{6752Addr.sin_port = htons(nStartPort + i);6753if(0 == bind(S.ListenerSocket, (sockaddr*)&Addr, sizeof(Addr)))6754{6755S.nWebServerPort = (uint32_t)(nStartPort + i);6756break;6757}6758}6759listen(S.ListenerSocket, 8);6760}67616762void MicroProfileWebServerJoin()6763{6764if(S.WebSocketThreadRunning)6765{6766MicroProfileThreadJoin(&S.WebSocketSendThread);6767}6768S.WebSocketThreadJoined = 1;6769}67706771void MicroProfileWebServerStop()6772{6773MP_ASSERT(S.WebSocketThreadJoined);6774#ifdef _WIN326775closesocket(S.ListenerSocket);6776WSACleanup();6777#else6778close(S.ListenerSocket);6779#endif6780}6781enum MicroProfileGetCommand6782{6783EMICROPROFILE_GET_COMMAND_DUMP,6784EMICROPROFILE_GET_COMMAND_DUMP_RANGE,6785EMICROPROFILE_GET_COMMAND_LIVE,6786EMICROPROFILE_GET_COMMAND_FAVICON,6787EMICROPROFILE_GET_COMMAND_SERVICE_WORKER,6788EMICROPROFILE_GET_COMMAND_UNKNOWN,6789};6790struct MicroProfileParseGetResult6791{6792uint64_t nFrames;6793uint64_t nFrameStart;6794};6795MicroProfileGetCommand MicroProfileParseGet(const char* pGet, MicroProfileParseGetResult* pResult)6796{6797if(0 == strlen(pGet))6798{6799return EMICROPROFILE_GET_COMMAND_LIVE;6800}6801if(0 == strcmp(pGet, "favicon.ico"))6802{6803return EMICROPROFILE_GET_COMMAND_FAVICON;6804}6805if(0 == strcmp(pGet, "favicon.png"))6806{6807return EMICROPROFILE_GET_COMMAND_FAVICON;6808}6809if(0 == strcmp(pGet, "service-worker.js"))6810{6811return EMICROPROFILE_GET_COMMAND_SERVICE_WORKER;6812}6813const char* pStart = pGet;6814if(*pStart == 'b' || *pStart == 'p')6815{6816S.nWSWasConnected = 1; // do not load default when url has one specified.6817return EMICROPROFILE_GET_COMMAND_LIVE;6818}6819if(*pStart == 'r') // range6820{6821// very very manual parsing6822if('/' != *++pStart)6823return EMICROPROFILE_GET_COMMAND_UNKNOWN;6824++pStart;68256826char* pEnd = nullptr;6827uint64_t nFrameStart = strtoll(pStart, &pEnd, 10);6828if(pEnd == pStart || *pEnd != '/' || *pEnd == '\0')6829{6830return EMICROPROFILE_GET_COMMAND_UNKNOWN;6831}6832pStart = pEnd + 1;68336834uint64_t nFrameEnd = strtoll(pStart, &pEnd, 10);68356836if(pEnd == pStart || nFrameEnd <= nFrameStart)6837{6838return EMICROPROFILE_GET_COMMAND_UNKNOWN;6839}6840pResult->nFrames = nFrameEnd - nFrameStart;6841pResult->nFrameStart = nFrameStart;6842return EMICROPROFILE_GET_COMMAND_DUMP_RANGE;6843}6844while(*pGet != '\0')6845{6846if(*pGet < '0' || *pGet > '9')6847return EMICROPROFILE_GET_COMMAND_UNKNOWN;6848pGet++;6849}6850int nFrames = atoi(pStart);6851pResult->nFrameStart = (uint64_t)-1;6852if(nFrames)6853{6854pResult->nFrames = nFrames;6855}6856else6857{6858pResult->nFrames = MICROPROFILE_WEBSERVER_DEFAULT_FRAMES;6859}6860return EMICROPROFILE_GET_COMMAND_DUMP;6861}68626863void MicroProfileBase64Encode(char* pOut, const uint8_t* pIn, uint32_t nLen)6864{6865static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";6866//..straight from wikipedia.6867int b;6868char* o = pOut;6869for(uint32_t i = 0; i < nLen; i += 3)6870{6871b = (pIn[i] & 0xfc) >> 2;6872*o++ = CODES[b];6873b = (pIn[i] & 0x3) << 4;6874if(i + 1 < nLen)6875{6876b |= (pIn[i + 1] & 0xF0) >> 4;6877*o++ = CODES[b];6878b = (pIn[i + 1] & 0x0F) << 2;6879if(i + 2 < nLen)6880{6881b |= (pIn[i + 2] & 0xC0) >> 6;6882*o++ = CODES[b];6883b = pIn[i + 2] & 0x3F;6884*o++ = CODES[b];6885}6886else6887{6888*o++ = CODES[b];6889*o++ = '=';6890}6891}6892else6893{6894*o++ = CODES[b];6895*o++ = '=';6896*o++ = '=';6897}6898}6899}69006901// begin: SHA-1 in C6902// ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c6903// SHA-1 in C6904// By Steve Reid <[email protected]>6905// 100% Public Domain69066907typedef struct6908{6909uint32_t state[5];6910uint32_t count[2];6911unsigned char buffer[64];6912} MicroProfile_SHA1_CTX;6913#include <string.h>6914#ifndef _WIN326915#include <netinet/in.h>6916#endif69176918static void MicroProfile_SHA1_Transform(uint32_t[5], const unsigned char[64]);69196920#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))69216922#define blk0(i) (block->l[i] = htonl(block->l[i]))6923#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))69246925#define R0(v, w, x, y, z, i) \6926z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \6927w = rol(w, 30);6928#define R1(v, w, x, y, z, i) \6929z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \6930w = rol(w, 30);6931#define R2(v, w, x, y, z, i) \6932z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \6933w = rol(w, 30);6934#define R3(v, w, x, y, z, i) \6935z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \6936w = rol(w, 30);6937#define R4(v, w, x, y, z, i) \6938z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \6939w = rol(w, 30);69406941// Hash a single 512-bit block. This is the core of the algorithm.69426943static void MicroProfile_SHA1_Transform(uint32_t state[5], const unsigned char buffer[64])6944{6945uint32_t a, b, c, d, e;6946typedef union6947{6948unsigned char c[64];6949uint32_t l[16];6950} CHAR64LONG16;6951CHAR64LONG16* block;69526953block = (CHAR64LONG16*)buffer;6954// Copy context->state[] to working vars6955a = state[0];6956b = state[1];6957c = state[2];6958d = state[3];6959e = state[4];6960// 4 rounds of 20 operations each. Loop unrolled.6961R0(a, b, c, d, e, 0);6962R0(e, a, b, c, d, 1);6963R0(d, e, a, b, c, 2);6964R0(c, d, e, a, b, 3);6965R0(b, c, d, e, a, 4);6966R0(a, b, c, d, e, 5);6967R0(e, a, b, c, d, 6);6968R0(d, e, a, b, c, 7);6969R0(c, d, e, a, b, 8);6970R0(b, c, d, e, a, 9);6971R0(a, b, c, d, e, 10);6972R0(e, a, b, c, d, 11);6973R0(d, e, a, b, c, 12);6974R0(c, d, e, a, b, 13);6975R0(b, c, d, e, a, 14);6976R0(a, b, c, d, e, 15);6977R1(e, a, b, c, d, 16);6978R1(d, e, a, b, c, 17);6979R1(c, d, e, a, b, 18);6980R1(b, c, d, e, a, 19);6981R2(a, b, c, d, e, 20);6982R2(e, a, b, c, d, 21);6983R2(d, e, a, b, c, 22);6984R2(c, d, e, a, b, 23);6985R2(b, c, d, e, a, 24);6986R2(a, b, c, d, e, 25);6987R2(e, a, b, c, d, 26);6988R2(d, e, a, b, c, 27);6989R2(c, d, e, a, b, 28);6990R2(b, c, d, e, a, 29);6991R2(a, b, c, d, e, 30);6992R2(e, a, b, c, d, 31);6993R2(d, e, a, b, c, 32);6994R2(c, d, e, a, b, 33);6995R2(b, c, d, e, a, 34);6996R2(a, b, c, d, e, 35);6997R2(e, a, b, c, d, 36);6998R2(d, e, a, b, c, 37);6999R2(c, d, e, a, b, 38);7000R2(b, c, d, e, a, 39);7001R3(a, b, c, d, e, 40);7002R3(e, a, b, c, d, 41);7003R3(d, e, a, b, c, 42);7004R3(c, d, e, a, b, 43);7005R3(b, c, d, e, a, 44);7006R3(a, b, c, d, e, 45);7007R3(e, a, b, c, d, 46);7008R3(d, e, a, b, c, 47);7009R3(c, d, e, a, b, 48);7010R3(b, c, d, e, a, 49);7011R3(a, b, c, d, e, 50);7012R3(e, a, b, c, d, 51);7013R3(d, e, a, b, c, 52);7014R3(c, d, e, a, b, 53);7015R3(b, c, d, e, a, 54);7016R3(a, b, c, d, e, 55);7017R3(e, a, b, c, d, 56);7018R3(d, e, a, b, c, 57);7019R3(c, d, e, a, b, 58);7020R3(b, c, d, e, a, 59);7021R4(a, b, c, d, e, 60);7022R4(e, a, b, c, d, 61);7023R4(d, e, a, b, c, 62);7024R4(c, d, e, a, b, 63);7025R4(b, c, d, e, a, 64);7026R4(a, b, c, d, e, 65);7027R4(e, a, b, c, d, 66);7028R4(d, e, a, b, c, 67);7029R4(c, d, e, a, b, 68);7030R4(b, c, d, e, a, 69);7031R4(a, b, c, d, e, 70);7032R4(e, a, b, c, d, 71);7033R4(d, e, a, b, c, 72);7034R4(c, d, e, a, b, 73);7035R4(b, c, d, e, a, 74);7036R4(a, b, c, d, e, 75);7037R4(e, a, b, c, d, 76);7038R4(d, e, a, b, c, 77);7039R4(c, d, e, a, b, 78);7040R4(b, c, d, e, a, 79);7041// Add the working vars back into context.state[]7042state[0] += a;7043state[1] += b;7044state[2] += c;7045state[3] += d;7046state[4] += e;7047// Wipe variables7048a = b = c = d = e = 0;7049}70507051void MicroProfile_SHA1_Init(MicroProfile_SHA1_CTX* context)7052{7053// SHA1 initialization constants7054context->state[0] = 0x67452301;7055context->state[1] = 0xEFCDAB89;7056context->state[2] = 0x98BADCFE;7057context->state[3] = 0x10325476;7058context->state[4] = 0xC3D2E1F0;7059context->count[0] = context->count[1] = 0;7060}70617062// Run your data through this.70637064void MicroProfile_SHA1_Update(MicroProfile_SHA1_CTX* context, const unsigned char* data, unsigned int len)7065{7066unsigned int i, j;70677068j = (context->count[0] >> 3) & 63;7069if((context->count[0] += len << 3) < (len << 3))7070context->count[1]++;7071context->count[1] += (len >> 29);7072i = 64 - j;7073while(len >= i)7074{7075memcpy(&context->buffer[j], data, i);7076MicroProfile_SHA1_Transform(context->state, context->buffer);7077data += i;7078len -= i;7079i = 64;7080j = 0;7081}70827083memcpy(&context->buffer[j], data, len);7084}70857086// Add padding and return the message digest.70877088void MicroProfile_SHA1_Final(unsigned char digest[20], MicroProfile_SHA1_CTX* context)7089{7090uint32_t i, j;7091unsigned char finalcount[8];70927093for(i = 0; i < 8; i++)7094{7095finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent7096}7097MicroProfile_SHA1_Update(context, (unsigned char*)"\200", 1);7098while((context->count[0] & 504) != 448)7099{7100MicroProfile_SHA1_Update(context, (unsigned char*)"\0", 1);7101}7102MicroProfile_SHA1_Update(context, finalcount, 8); // Should cause a SHA1Transform()7103for(i = 0; i < 20; i++)7104{7105digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);7106}7107// Wipe variables7108i = j = 0;7109memset(context->buffer, 0, 64);7110memset(context->state, 0, 20);7111memset(context->count, 0, 8);7112memset(&finalcount, 0, 8);7113}71147115#undef rol7116#undef blk07117#undef blk7118#undef R07119#undef R17120#undef R27121#undef R37122#undef R471237124// end: SHA-1 in C71257126void MicroProfileWebSocketSendState(MpSocket C);7127void MicroProfileWebSocketSendEnabled(MpSocket C);7128void MicroProfileWSPrintStart(MpSocket C);7129void MicroProfileWSPrintf(const char* pFmt, ...);7130void MicroProfileWSPrintEnd();7131void MicroProfileWSFlush();7132bool MicroProfileWebSocketReceive(MpSocket C);71337134enum7135{7136TYPE_NONE = 0,7137TYPE_TIMER = 1,7138TYPE_GROUP = 2,7139TYPE_CATEGORY = 3,7140TYPE_SETTING = 4,7141TYPE_COUNTER = 5,7142};71437144enum7145{7146SETTING_FORCE_ENABLE = 0,7147SETTING_CONTEXT_SWITCH_TRACE = 1,7148SETTING_PLATFORM_MARKERS = 2,7149};71507151enum7152{7153MSG_TIMER_TREE = 1,7154MSG_ENABLED = 2,7155MSG_FRAME = 3,7156MSG_LOADSETTINGS = 4,7157MSG_PRESETS = 5,7158MSG_CURRENTSETTINGS = 6,7159MSG_COUNTERS = 7,7160MSG_FUNCTION_RESULTS = 8,7161MSG_INACTIVE_FRAME = 9,7162MSG_FUNCTION_NAMES = 10,7163MSG_INSTRUMENT_ERROR = 11,7164MSG_QUERY_INDEX = 12,7165// MSG_MODULE_NAME = 12,7166};71677168enum7169{7170VIEW_GRAPH_SPLIT = 0,7171VIEW_GRAPH_PERCENTILE = 1,7172VIEW_GRAPH_THREAD_GROUP = 2,7173VIEW_BAR = 3,7174VIEW_BAR_ALL = 4,7175VIEW_BAR_SINGLE = 5,7176VIEW_COUNTERS = 6,7177VIEW_SIZE = 7,7178};71797180void MicroProfileSocketDumpState()7181{7182fd_set Read, Write, Error;7183FD_ZERO(&Read);7184FD_ZERO(&Write);7185FD_ZERO(&Error);7186MpSocket LastSocket = 1;7187for(uint32_t i = 0; i < S.nNumWebSockets; ++i)7188{7189LastSocket = MicroProfileMax(LastSocket, S.WebSockets[i] + 1);7190FD_SET(S.WebSockets[i], &Read);7191FD_SET(S.WebSockets[i], &Write);7192FD_SET(S.WebSockets[i], &Error);7193}7194timeval tv;7195tv.tv_sec = 0;7196tv.tv_usec = 0;71977198if(-1 == select(LastSocket, &Read, &Write, &Error, &tv))7199{7200MP_ASSERT(0);7201}7202for(uint32_t i = 0; i < S.nNumWebSockets; i++)7203{7204MpSocket s = S.WebSockets[i];7205uprintf("%" PRId64 " ", (uint64_t)s);72067207if(FD_ISSET(s, &Error))7208{7209uprintf("e");7210}7211else7212{7213uprintf("_");7214}7215if(FD_ISSET(s, &Read))7216{7217uprintf("r");7218}7219else7220{7221uprintf(" ");7222}7223if(FD_ISSET(s, &Write))7224{7225uprintf("w");7226}7227else7228{7229uprintf(" ");7230}7231}7232uprintf("\n");7233for(uint32_t i = 1; i < S.nNumWebSockets; i++)7234{7235MpSocket s = S.WebSockets[i];7236int error_code;7237socklen_t error_code_size = sizeof(error_code);7238int r = getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error_code, &error_code_size);7239MP_ASSERT(r >= 0);7240if(error_code != 0)7241{7242#ifdef _WIN327243char buffer[1024];7244strerror_s(buffer, sizeof(buffer) - 1, error_code);7245fprintf(stderr, "socket error: %d %s\n", (int)s, buffer);7246#else7247fprintf(stderr, "socket error: %d %s\n", (int)s, strerror(error_code));7248#endif7249MP_ASSERT(0);7250}7251}7252}72537254bool MicroProfileSocketSend2(MpSocket Connection, const void* pMessage, int nLen);7255void* MicroProfileSocketSenderThread(void*)7256{7257MicroProfileOnThreadCreate("MicroProfileSocketSenderThread");7258while(!S.nMicroProfileShutdown)7259{7260if(S.nSocketFail)7261{7262MicroProfileSleep(100);7263continue;7264}72657266uint32_t nEnd = MICROPROFILE_WEBSOCKET_BUFFER_SIZE;7267uint32_t nGet = S.WSBuf.nSendGet.load();7268uint32_t nPut = S.WSBuf.nSendPut.load();7269uint32_t nSendStart = 0;7270uint32_t nSendAmount = 0;7271if(nGet > nPut)7272{7273nSendStart = nGet;7274nSendAmount = nEnd - nGet;7275}7276else if(nGet < nPut)7277{7278nSendStart = nGet;7279nSendAmount = nPut - nGet;7280}72817282if(nSendAmount)7283{7284MICROPROFILE_SCOPE(g_MicroProfileSendLoop);7285MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(g_MicroProfileBytesPerFlip, nSendAmount);7286if(!MicroProfileSocketSend2(S.WebSockets[0], &S.WSBuf.SendBuffer[nSendStart], nSendAmount))7287{7288S.nSocketFail = 1;7289}7290else7291{7292S.WSBuf.nSendGet.store((nGet + nSendAmount) % MICROPROFILE_WEBSOCKET_BUFFER_SIZE);7293}7294}7295else7296{7297MicroProfileSleep(20);7298}7299}7300MicroProfileOnThreadExit();7301return 0;7302}73037304void MicroProfileSocketSend(MpSocket Connection, const void* pMessage, int nLen)7305{7306if(S.nSocketFail || nLen <= 0)7307{7308return;7309}7310MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSocketSend", MP_GREEN4);7311while(nLen != 0)7312{7313MP_ASSERT(nLen > 0);7314uint32_t nEnd = MICROPROFILE_WEBSOCKET_BUFFER_SIZE;7315uint32_t nGet = S.WSBuf.nSendGet.load();7316uint32_t nPut = S.WSBuf.nSendPut.load();7317uint32_t nAmount = 0;7318if(nPut < nGet)7319{7320nAmount = nGet - nPut - 1;7321}7322else7323{7324if(nGet == 0)7325{7326nAmount = nEnd - nPut - 1;7327}7328else7329{7330nAmount = nEnd - nPut;7331}7332}7333MP_ASSERT((int)nAmount >= 0);7334nAmount = MicroProfileMin(nLen, (int)nAmount);7335if(nAmount)7336{7337memcpy(&S.WSBuf.SendBuffer[nPut], pMessage, nAmount);7338pMessage = (void*)((char*)pMessage + nAmount);7339nLen -= nAmount;7340S.WSBuf.nSendPut.store((nPut + nAmount) % MICROPROFILE_WEBSOCKET_BUFFER_SIZE);7341}7342else7343{7344if(S.nSocketFail)7345{7346return;7347}7348MicroProfileSleep(20);7349}7350}7351}73527353bool MicroProfileSocketSend2(MpSocket Connection, const void* pMessage, int nLen)7354{7355if(S.nSocketFail || nLen <= 0)7356{7357return false;7358}7359// MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSocketSend2", 0);7360#ifndef _WIN327361int error_code;7362socklen_t error_code_size = sizeof(error_code);7363getsockopt(Connection, SOL_SOCKET, SO_ERROR, &error_code, &error_code_size);7364if(error_code != 0)7365{7366return false;7367}7368#endif73697370int s = 0;7371while(nLen)7372{7373s = send(Connection, (const char*)pMessage, nLen, 0);7374if(s < 0)7375{7376const int error = errno;7377if(error == EAGAIN || error == EWOULDBLOCK)7378{7379MicroProfileSleep(20);7380continue;7381}7382break;7383}73847385nLen -= s;7386pMessage = (const char*)pMessage + s;7387}7388#ifdef _WIN327389if(s == SOCKET_ERROR)7390{7391return false;7392}7393#endif7394if(s < 0)7395{7396return false;7397}7398return true;7399}74007401uint32_t MicroProfileWebSocketIdPack(uint32_t type, uint32_t element)7402{7403MP_ASSERT(type < 255);7404MP_ASSERT(element < 0xffffff);7405return type << 24 | element;7406}7407void MicroProfileWebSocketIdUnpack(uint32_t nPacked, uint32_t& type, uint32_t& element)7408{7409type = (nPacked >> 24) & 0xff;7410element = nPacked & 0xffffff;7411}74127413struct MicroProfileWebSocketHeader07414{7415union7416{7417struct7418{7419uint8_t opcode : 4;7420uint8_t RSV3 : 1;7421uint8_t RSV2 : 1;7422uint8_t RSV1 : 1;7423uint8_t FIN : 1;7424};7425uint8_t v;7426};7427};74287429struct MicroProfileWebSocketHeader17430{7431union7432{7433struct7434{7435uint8_t payload : 7;7436uint8_t MASK : 1;7437};7438uint8_t v;7439};7440};74417442bool MicroProfileWebSocketSend(MpSocket Connection, const char* pMessage, uint64_t nLen)7443{7444MicroProfileWebSocketHeader0 h0;7445MicroProfileWebSocketHeader1 h1;7446h0.v = 0;7447h1.v = 0;7448h0.opcode = 1;7449h0.FIN = 1;7450uint32_t nExtraSizeBytes = 0;7451uint8_t nExtraSize[8];7452if(nLen > 125)7453{7454if(nLen > 0xffff)7455{7456nExtraSizeBytes = 8;7457h1.payload = 127;7458}7459else7460{7461h1.payload = 126;7462nExtraSizeBytes = 2;7463}7464uint64_t nCount = nLen;7465for(uint32_t i = 0; i < nExtraSizeBytes; ++i)7466{7467nExtraSize[nExtraSizeBytes - i - 1] = nCount & 0xff;7468nCount >>= 8;7469}74707471uint32_t nSize = 0;7472for(uint32_t i = 0; i < nExtraSizeBytes; i++)7473{7474nSize <<= 8;7475nSize += nExtraSize[i];7476}7477MP_ASSERT(nSize == nLen); // verify7478}7479else7480{7481h1.payload = nLen;7482}7483MP_ASSERT(pMessage == S.WSBuf.pBuffer); // space for header is preallocated here7484MP_ASSERT(pMessage == S.WSBuf.pBufferAllocation + 20); // space for header is preallocated here7485MP_ASSERT(nExtraSizeBytes < 18);7486char* pTmp = (char*)(pMessage - nExtraSizeBytes - 2);7487memcpy(pTmp + 2, &nExtraSize[0], nExtraSizeBytes);7488pTmp[1] = *(char*)&h1;7489pTmp[0] = *(char*)&h0;7490// MicroProfileSocketSend(Connection, pTmp, nExtraSizeBytes + 2 + nLen);7491#if 17492MicroProfileSocketSend(Connection, &h0, 1);7493MicroProfileSocketSend(Connection, &h1, 1);7494if(nExtraSizeBytes)7495{7496MicroProfileSocketSend(Connection, &nExtraSize[0], nExtraSizeBytes);7497}7498MicroProfileSocketSend(Connection, pMessage, nLen);7499#endif7500return true;7501}75027503void MicroProfileWebSocketClearTimers()7504{7505while(S.WebSocketTimers > -1)7506{7507int nNext = S.TimerInfo[S.WebSocketTimers].nWSNext;7508S.TimerInfo[S.WebSocketTimers].nWSNext = -2;7509S.WebSocketTimers = nNext;7510}7511MP_ASSERT(S.WebSocketTimers == -1);7512while(S.WebSocketCounters > -1)7513{7514int nNext = S.CounterInfo[S.WebSocketCounters].nWSNext;7515S.CounterInfo[S.WebSocketCounters].nWSNext = -2;7516S.WebSocketCounters = nNext;7517}7518MP_ASSERT(S.WebSocketCounters == -1);75197520while(S.WebSocketGroups > -1)7521{7522int nNext = S.GroupInfo[S.WebSocketGroups].nWSNext;7523S.GroupInfo[S.WebSocketGroups].nWSNext = -2;7524S.WebSocketGroups = nNext;7525}7526MP_ASSERT(S.WebSocketGroups == -1);7527S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;7528}7529void MicroProfileWebSocketToggleTimer(uint32_t nTimer)7530{7531if(nTimer < S.nTotalTimers)7532{7533auto& TI = S.TimerInfo[nTimer];7534int* pPrev = &S.WebSocketTimers;7535while(*pPrev > -1 && *pPrev != (int)nTimer)7536{7537MP_ASSERT(*pPrev < (int)S.nTotalTimers && *pPrev >= 0);7538pPrev = &S.TimerInfo[*pPrev].nWSNext;7539}7540if(TI.nWSNext >= -1)7541{7542MP_ASSERT(*pPrev == (int)nTimer);7543*pPrev = TI.nWSNext;7544TI.nWSNext = -2;7545}7546else7547{7548MP_ASSERT(*pPrev == -1);7549TI.nWSNext = -1;7550*pPrev = (int)nTimer;7551}7552S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;7553}7554}75557556void MicroProfileWebSocketToggleCounter(uint32_t nCounter)7557{7558if(nCounter < S.nNumCounters)7559{7560auto& TI = S.CounterInfo[nCounter];7561int* pPrev = &S.WebSocketCounters;7562while(*pPrev > -1 && *pPrev != (int)nCounter)7563{7564MP_ASSERT(*pPrev < (int)S.nNumCounters && *pPrev >= 0);7565pPrev = &S.CounterInfo[*pPrev].nWSNext;7566}7567if(TI.nWSNext >= -1)7568{7569MP_ASSERT(*pPrev == (int)nCounter);7570*pPrev = TI.nWSNext;7571TI.nWSNext = -2;7572}7573else7574{7575MP_ASSERT(*pPrev == -1);7576TI.nWSNext = -1;7577*pPrev = (int)nCounter;7578}7579S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;7580}7581}75827583void MicroProfileWebSocketToggleGroup(uint32_t nGroup)7584{7585if(nGroup < S.nGroupCount)7586{7587auto& TI = S.GroupInfo[nGroup];7588int* pPrev = &S.WebSocketGroups;7589while(*pPrev > -1 && *pPrev != (int)nGroup)7590{7591MP_ASSERT(*pPrev < (int)S.nGroupCount && *pPrev >= 0);7592pPrev = &S.GroupInfo[*pPrev].nWSNext;7593}7594if(TI.nWSNext >= -1)7595{7596MP_ASSERT(*pPrev == (int)nGroup);7597*pPrev = TI.nWSNext;7598TI.nWSNext = -2;7599}7600else7601{7602MP_ASSERT(*pPrev == -1);7603TI.nWSNext = -1;7604*pPrev = (int)nGroup;7605}7606S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;7607}7608}76097610bool MicroProfileWebSocketTimerEnabled(uint32_t nTimer)7611{7612if(nTimer < S.nTotalTimers)7613{7614return S.TimerInfo[nTimer].nWSNext > -2;7615}7616return false;7617}76187619bool MicroProfileWebSocketCounterEnabled(uint32_t nCounter)7620{7621if(nCounter < S.nNumCounters)7622{7623return S.CounterInfo[nCounter].nWSNext > -2;7624}7625return false;7626}7627void MicroProfileWebSocketCommand(uint32_t nCommand)7628{7629uint32_t nType, nElement;7630MicroProfileWebSocketIdUnpack(nCommand, nType, nElement);7631switch(nType)7632{7633case TYPE_NONE:7634break;7635case TYPE_SETTING:7636switch(nElement)7637{7638case SETTING_FORCE_ENABLE:7639MicroProfileSetEnableAllGroups(!MicroProfileGetEnableAllGroups());7640break;7641case SETTING_CONTEXT_SWITCH_TRACE:7642if(!S.bContextSwitchRunning)7643{7644MicroProfileStartContextSwitchTrace();7645}7646else7647{7648MicroProfileStopContextSwitchTrace();7649}7650break;7651case SETTING_PLATFORM_MARKERS:7652MicroProfilePlatformMarkersSetEnabled(!MicroProfilePlatformMarkersGetEnabled());7653break;7654}7655S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;7656break;7657case TYPE_TIMER:7658MicroProfileWebSocketToggleTimer(nElement);7659break;7660case TYPE_GROUP:7661MicroProfileToggleGroup(nElement);7662break;7663case TYPE_CATEGORY:7664MicroProfileToggleCategory(nElement);7665break;7666case TYPE_COUNTER:7667MicroProfileWebSocketToggleCounter(nElement);7668break;7669default:7670uprintf("unknown type %d\n", nType);7671}7672}7673#define MICROPROFILE_PRESET_HEADER_MAGIC2 0x285868137674#define MICROPROFILE_PRESET_HEADER_VERSION2 0x0000020076757676struct MicroProfileSettingsFileHeader7677{7678uint32_t nMagic;7679uint32_t nVersion;7680uint32_t nNumHeaders;7681uint32_t nHeadersOffset;7682uint32_t nMaxJsonSize;7683uint32_t nMaxNameSize;7684};7685struct MicroProfileSettingsHeader7686{7687uint32_t nJsonOffset;7688uint32_t nJsonSize;7689uint32_t nNameOffset;7690uint32_t nNameSize;7691};76927693template <typename T>7694void MicroProfileParseSettings(const char* pFileName, T CB)7695{7696std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());76977698FILE* F = fopen(pFileName, "rb");7699if(!F)7700{7701return;7702}7703long nFileSize = 0;7704fseek(F, 0, SEEK_END);7705nFileSize = ftell(F);7706char* pFile = 0;7707char* pAlloc = 0;7708if(nFileSize > (32 << 10))7709{7710pFile = pAlloc = (char*)MP_ALLOC(nFileSize + 1, 1);7711}7712else7713{7714pFile = (char*)alloca(nFileSize + 1);7715}7716fseek(F, 0, SEEK_SET);7717if(1 != fread(pFile, nFileSize, 1, F))7718{7719uprintf("failed to read settings file\n");7720fclose(F);7721return;7722}7723fclose(F);7724pFile[nFileSize] = '\0';77257726char* pPos = pFile;7727char* pEnd = pFile + nFileSize;77287729while(pPos != pEnd)7730{7731const char* pName = 0;7732int nNameLen = 0;7733const char* pJson = 0;7734int nJsonLen = 0;7735int Failed = 0;77367737auto SkipWhite = [&](char* pPos, const char* pEnd)7738{7739while(pPos != pEnd)7740{7741if(isspace(*pPos))7742{7743pPos++;7744}7745else if('#' == *pPos)7746{7747while(pPos != pEnd && *pPos != '\n')7748{7749++pPos;7750}7751}7752else7753{7754break;7755}7756}7757return pPos;7758};77597760auto ParseName = [&](char* pPos, char* pEnd, const char** ppName, int* pLen)7761{7762pPos = SkipWhite(pPos, pEnd);7763int nLen = 0;7764*ppName = pPos;77657766while(pPos != pEnd && (isalpha(*pPos) || isdigit(*pPos) || *pPos == '_'))7767{7768nLen++;7769pPos++;7770}7771*pLen = nLen;7772if(pPos == pEnd || !isspace(*pPos))7773{7774Failed = 1;7775return pEnd;7776}7777*pPos++ = '\0';7778return pPos;7779};77807781auto ParseJson = [&](char* pPos, char* pEnd, const char** pJson, int* pLen) -> char*7782{7783pPos = SkipWhite(pPos, pEnd);7784if(*pPos != '{' || pPos == pEnd)7785{7786Failed = 1;7787return pPos;7788}7789*pJson = pPos++;7790int nLen = 1;7791int nDepth = 1;7792while(pPos != pEnd && nDepth != 0)7793{7794nLen++;7795char nChar = *pPos++;7796if(nChar == '{')7797{7798nDepth++;7799}7800else if(nChar == '}')7801{7802nDepth--;7803}7804}7805if(pPos == pEnd || !isspace(*pPos))7806{7807Failed = 1;7808return pEnd;7809}7810*pLen = nLen;7811*pPos++ = '\0';7812return pPos;7813};78147815pPos = ParseName(pPos, pEnd, &pName, &nNameLen);7816pPos = ParseJson(pPos, pEnd, &pJson, &nJsonLen);7817if(Failed)7818{7819break;7820}7821if(!CB(pName, nNameLen, pJson, nJsonLen))7822{7823break;7824}7825}7826if(pAlloc)7827MP_FREE(pAlloc);7828}78297830bool MicroProfileSavePresets(const char* pSettingsName, const char* pJsonSettings)7831{7832std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());78337834FILE* F = fopen(S.pSettingsTemp, "w");7835if(!F)7836{7837return false;7838}78397840bool bWritten = false;78417842MicroProfileParseSettings(S.pSettings,7843[&](const char* pName, uint32_t nNameSize, const char* pJson, uint32_t nJsonSize) -> bool7844{7845fwrite(pName, nNameSize, 1, F);7846fputc(' ', F);7847if(0 != MP_STRCASECMP(pSettingsName, pName))7848{7849fwrite(pJson, nJsonSize, 1, F);7850}7851else7852{7853bWritten = true;7854fwrite(pJsonSettings, strlen(pJsonSettings), 1, F);7855}7856fputc('\n', F);7857return true;7858});7859if(!bWritten)7860{7861fwrite(pSettingsName, strlen(pSettingsName), 1, F);7862fputc(' ', F);7863fwrite(pJsonSettings, strlen(pJsonSettings), 1, F);7864fputc('\n', F);7865}7866fflush(F);7867fclose(F);7868#ifdef MICROPROFILE_MOVE_FILE7869MICROPROFILE_MOVE_FILE(S.pSettingsTemp, S.pSettings);7870#elif defined(_WIN32)7871MoveFileExA(S.pSettingsTemp, S.pSettings, MOVEFILE_REPLACE_EXISTING);7872#else7873rename(S.pSettingsTemp, S.pSettings);7874#endif7875return false;7876}78777878void MicroProfileWriteJsonString(const char* pJson, uint32_t nJsonLen)7879{7880char* pCur = (char*)pJson;7881char* pEnd = pCur + nJsonLen;7882MicroProfileWSPrintf("\"", pCur);7883while(pCur != pEnd)7884{7885char* pTag = strchr(pCur, '\"');7886if(pTag)7887{7888*pTag = '\0';7889MicroProfileWSPrintf("%s\\\"", pCur);7890*pTag = '\"';7891pCur = pTag + 1;7892}7893else7894{7895MicroProfileWSPrintf("%s\"", pCur);7896pCur = pEnd;7897}7898}7899};79007901void MicroProfileWebSocketSendPresets(MpSocket Connection)7902{7903std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());7904uprintf("sending presets ... \n");7905MicroProfileWSPrintStart(Connection);7906MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{", MSG_PRESETS);7907MicroProfileWSPrintf("\"p\":{\"Default\":\"{}\"");79087909MicroProfileParseSettings(S.pSettings,7910[](const char* pName, uint32_t nNameLen, const char* pJson, uint32_t nJsonLen)7911{7912MicroProfileWSPrintf(",\"%s\":", pName);7913MicroProfileWriteJsonString(pJson, nJsonLen);79147915return true;7916});7917MicroProfileWSPrintf("},\"r\":{");7918bool bFirst = true;7919MicroProfileParseSettings(S.pSettingsReadOnly,7920[&bFirst](const char* pName, uint32_t nNameLen, const char* pJson, uint32_t nJsonLen)7921{7922MicroProfileWSPrintf("%c\"%s\":", bFirst ? ' ' : ',', pName);7923MicroProfileWriteJsonString(pJson, nJsonLen);79247925bFirst = false;7926return true;7927});7928MicroProfileWSPrintf("}}}");7929MicroProfileWSFlush();7930MicroProfileWSPrintEnd();7931}79327933#define LOAD_PRESET_DEFAULT 0x17934#define LOAD_PRESET_READONLY 0x279357936void MicroProfileLoadPresets(const char* pSettingsName, uint32_t nLoadPresetType)7937{7938std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());7939const char* pPresetFiles[] = { S.pSettings, S.pSettingsReadOnly };7940for(uint32_t i = 0; i < 2; ++i)7941{7942if(nLoadPresetType & (1u << i))7943{7944const char* pPresetFile = pPresetFiles[i];7945bool bReadOnly = (1u << i) == LOAD_PRESET_READONLY;7946bool bSuccess = false;7947MicroProfileParseSettings(pPresetFile,7948[&bSuccess, bReadOnly, pSettingsName](const char* pName, uint32_t l0, const char* pJson, uint32_t l1)7949{7950if(0 == MP_STRCASECMP(pName, pSettingsName))7951{7952uint32_t nLen = (uint32_t)strlen(pJson) + 1;7953if(nLen > S.nJsonSettingsBufferSize)7954{7955if(S.pJsonSettings)7956S.pJsonSettings = nullptr;7957S.pJsonSettings = (char*)MP_ALLOC(nLen, 1);7958S.nJsonSettingsBufferSize = nLen;7959}7960S.pJsonSettingsName = pSettingsName;7961memcpy(S.pJsonSettings, pJson, nLen);7962S.nJsonSettingsPending = 1;7963S.bJsonSettingsReadOnly = bReadOnly ? 1 : 0;7964bSuccess = true;7965return false;7966}7967return true;7968});7969if(bSuccess)7970return;7971}7972}7973}79747975bool MicroProfileWebSocketReceive(MpSocket Connection)7976{79777978// 0 1 2 37979// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 17980// +-+-+-+-+-------+-+-------------+-------------------------------+7981// |F|R|R|R| opcode|M| Payload len | Extended payload length |7982// |I|S|S|S| (4) |A| (7) | (16/64) |7983// |N|V|V|V| |S| | (if payload len==126/127) |7984// | |1|2|3| |K| | |7985// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +7986int r;7987uint64_t nSize;7988uint64_t nSizeBytes = 0;7989uint8_t Mask[4];7990static unsigned char* Bytes = 0;7991static uint64_t BytesAllocated = 0;7992MicroProfileWebSocketHeader0 h0;7993MicroProfileWebSocketHeader1 h1;7994static_assert(sizeof(h0) == 1, "");7995static_assert(sizeof(h1) == 1, "");7996r = recv(Connection, (char*)&h0, 1, 0);7997if(1 != r)7998goto fail;7999r = recv(Connection, (char*)&h1, 1, 0);8000if(1 != r)8001goto fail;80028003if(h0.v == 0x88)8004{8005goto fail;8006}80078008if(h0.RSV1 != 0 || h0.RSV2 != 0 || h0.RSV3 != 0)8009goto fail;80108011nSize = h1.payload;8012nSizeBytes = 0;8013switch(nSize)8014{8015case 126:8016nSizeBytes = 2;8017break;8018case 127:8019nSizeBytes = 8;8020break;8021default:8022break;8023}8024if(nSizeBytes)8025{8026nSize = 0;8027uint64_t MessageLength = 0;80288029uint8_t BytesMessage[8];8030r = recv(Connection, (char*)&BytesMessage[0], nSizeBytes, 0);8031if((int)nSizeBytes != r)8032goto fail;8033for(uint32_t i = 0; i < nSizeBytes; i++)8034{8035nSize <<= 8;8036nSize += BytesMessage[i];8037}80388039for(uint32_t i = 0; i < nSizeBytes; i++)8040MessageLength |= BytesMessage[i] << ((nSizeBytes - 1 - i) * 8);8041MP_ASSERT(MessageLength == nSize);8042}80438044if(h1.MASK)8045{8046recv(Connection, (char*)&Mask[0], 4, 0);8047}80488049MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(g_MicroProfileBytesPerFlip, nSize);8050if(nSize + 1 > BytesAllocated)8051{8052Bytes = (unsigned char*)MP_REALLOC(Bytes, nSize + 1);8053BytesAllocated = nSize + 1;8054}8055recv(Connection, (char*)Bytes, nSize, 0);8056for(uint32_t i = 0; i < nSize; ++i)8057Bytes[i] ^= Mask[i & 3];80588059Bytes[nSize] = '\0';8060switch(Bytes[0])8061{8062case 'a':8063{8064S.nAggregateFlip = strtoll((const char*)&Bytes[1], nullptr, 10);8065}8066break;8067case 's':8068{8069char* pJson = strchr((char*)Bytes, ',');8070if(pJson && *pJson != '\0')8071{8072*pJson = '\0';8073MicroProfileSavePresets((const char*)Bytes + 1, (const char*)pJson + 1);8074}8075break;8076}80778078case 'l':8079{8080MicroProfileLoadPresets((const char*)Bytes + 1, LOAD_PRESET_DEFAULT);8081break;8082}8083case 'm':8084{8085MicroProfileLoadPresets((const char*)Bytes + 1, LOAD_PRESET_READONLY);8086break;8087}8088case 'd':8089{8090MicroProfileWebSocketClearTimers();8091memset(&S.nActiveGroupsWanted, 0, sizeof(S.nActiveGroupsWanted));8092S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED;8093break;8094}8095case 'c':8096{8097char* pStr = (char*)Bytes + 1;8098char* pEnd = pStr + nSize - 1;8099uint32_t Message = strtol(pStr, &pEnd, 10);8100MicroProfileWebSocketCommand(Message);8101}8102break;8103case 'f':8104MicroProfileToggleFrozen();8105break;8106case 'v':8107S.nWSViewMode = (int)Bytes[1] - '0';8108break;8109case 'r':8110uprintf("got clear message\n");8111S.nAggregateClear = 1;8112break;8113case 'x':8114MicroProfileWebSocketClearTimers();8115break;8116#if MICROPROFILE_DYNAMIC_INSTRUMENT8117case 'D': // instrumentation without loading queryable symbols.8118{8119uprintf("got INSTRUMENT Message: %s\n", (const char*)&Bytes[0]);8120char* pGet = (char*)&Bytes[1];8121uint32_t nNumArguments = 0;8122#ifdef _WIN328123r = sscanf_s(pGet, "%d", &nNumArguments);8124#else8125r = sscanf(pGet, "%d", &nNumArguments);8126#endif8127if(r != 1)8128{8129uprintf("failed to parse..\n");8130break;8131}8132while(' ' == *pGet || (*pGet >= '0' && *pGet <= '9'))8133{8134pGet++;8135}8136if(nNumArguments > 200)8137nNumArguments = 200;8138uint32_t nParsedArguments = 0;8139const char* pModule = 0;8140const char* pSymbol = 0;8141const char** pModules = (const char**)(alloca(sizeof(const char*) * nNumArguments));8142const char** pSymbols = (const char**)(alloca(sizeof(const char*) * nNumArguments));8143auto Next = [&pGet]() -> const char*8144{8145if(!pGet)8146return 0;8147const char* pRet = pGet;8148pGet = (char*)strchr(pRet, '!');8149if(!pGet)8150{8151return 0;8152}8153*pGet++ = '\0';8154return (const char*)pRet;8155};8156do8157{8158pModule = Next();8159pSymbol = Next();8160if(pModule && pSymbol)8161{8162pModules[nParsedArguments] = pModule;8163pSymbols[nParsedArguments] = pSymbol;8164uprintf("found symbol %s ::: %s \n", pModule, pSymbol);8165nParsedArguments++;8166if(nParsedArguments == nNumArguments)8167{8168break;8169}8170}8171} while(pGet);81728173MicroProfileInstrumentWithoutSymbols(pModules, pSymbols, nParsedArguments);81748175break;8176}8177case 'I':8178case 'i':8179{8180uprintf("got Message: %s\n", (const char*)&Bytes[0]);8181void* p = 0;8182uint32_t nColor = 0x0;8183int nMinBytes = 0;8184int nMaxCalls = 0;8185int nCharsRead = 0;8186#ifdef _WIN328187r = sscanf_s((const char*)&Bytes[1], "%p %x %d %d%n", &p, &nColor, &nMinBytes, &nMaxCalls, &nCharsRead);8188#else8189r = sscanf((const char*)&Bytes[1], "%p %x %d %d%n", &p, &nColor, &nMinBytes, &nMaxCalls, &nCharsRead);8190#endif8191if(r == 4)8192{8193const char* pModule = (const char*)&Bytes[1];8194// int nNumChars = stbsp_snprintf(0, 0, "%p %x", p, nColor);8195pModule += nCharsRead;8196while(*pModule != ' ' && *pModule != '\0')8197++pModule;81988199if(*pModule == '\0')8200break;82018202pModule++;8203const char* pName = pModule;8204while(*pName != '!' && *pName != '\0')8205{8206pName++;8207}8208if(*pName == '!')8209{8210// name and module seperately8211*(char*)pName = '\0';8212pName++;8213}8214else8215{8216// name only8217pName = pModule;8218pModule = "";8219}82208221uprintf("scanning for ptr %p %x mod:'%s' name'%s'\n", p, nColor, pModule, pName);8222if(Bytes[0] == 'I')8223{8224MicroProfileInstrumentFunctionsCalled(p, pModule, pName, nMinBytes, nMaxCalls);8225}8226else8227{8228MicroProfileInstrumentFunction(p, pModule, pName, nColor);8229}8230}8231}8232break;8233case 'S':8234uprintf("loading symbols...\n");8235MicroProfileSymbolInitialize(true);8236break;8237case 'q':8238MicroProfileSymbolQueryFunctions(Connection, 1 + (const char*)Bytes);8239break;8240case 'L':8241uprintf("LOAD MODULE: '%s'\n", 1 + (const char*)Bytes);8242MicroProfileSymbolInitialize(true, 1 + (const char*)Bytes);8243break;8244#else8245case 'D':8246case 'I':8247case 'i':8248case 'S':8249case 'q':8250case 'L':8251break;8252#endif8253default:8254uprintf("got unknown message size %lld: '%s'\n", (long long)nSize, Bytes);8255}8256return true;82578258fail:8259return false;8260}8261void MicroProfileWebSocketSendPresets(MpSocket Connection);82628263void MicroProfileWebSocketHandshake(MpSocket Connection, char* pWebSocketKey)8264{8265// reset web socket buffer8266S.WSBuf.nSendPut.store(0);8267S.WSBuf.nSendGet.store(0);8268S.nSocketFail = 0;82698270const char* pGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";8271const char* pHandShake = "HTTP/1.1 101 Switching Protocols\r\n"8272"Upgrade: websocket\r\n"8273"Connection: Upgrade\r\n"8274"Sec-WebSocket-Accept: ";82758276char EncodeBuffer[512];8277int nLen = stbsp_snprintf(EncodeBuffer, sizeof(EncodeBuffer) - 1, "%s%s", pWebSocketKey, pGUID);8278// uprintf("encode buffer is '%s' %d, %d\n", EncodeBuffer, nLen, (int)strlen(EncodeBuffer));82798280uint8_t sha[20];8281MicroProfile_SHA1_CTX ctx;8282MicroProfile_SHA1_Init(&ctx);8283MicroProfile_SHA1_Update(&ctx, (unsigned char*)EncodeBuffer, nLen);8284MicroProfile_SHA1_Final((unsigned char*)&sha[0], &ctx);8285char HashOut[(2 + sizeof(sha) / 3) * 4];8286memset(&HashOut[0], 0, sizeof(HashOut));8287MicroProfileBase64Encode(&HashOut[0], &sha[0], sizeof(sha));82888289char Reply[11024];8290nLen = stbsp_snprintf(Reply, sizeof(Reply) - 1, "%s%s\r\n\r\n", pHandShake, HashOut);8291;8292MP_ASSERT(nLen >= 0);8293MicroProfileSocketSend(Connection, Reply, nLen);8294S.WebSockets[S.nNumWebSockets++] = Connection;82958296S.WSCategoriesSent = 0;8297S.WSGroupsSent = 0;8298S.WSTimersSent = 0;8299S.WSCountersSent = 0;8300S.nJsonSettingsPending = 0;8301#if MICROPROFILE_DYNAMIC_INSTRUMENT8302S.WSFunctionsInstrumentedSent = 0;8303S.WSSymbolModulesSent = 0;8304{8305uint64_t t0 = MP_TICK();8306MicroProfileSymbolUpdateModuleList();8307uint64_t t1 = MP_TICK();8308float fTime = float(MicroProfileTickToMsMultiplierCpu()) * (t1 - t0);8309(void)fTime;8310uprintf("update module list time %6.2fms\n", fTime);8311}8312#endif83138314MicroProfileWebSocketSendState(Connection);8315MicroProfileWebSocketSendPresets(Connection);8316if(!S.nWSWasConnected)8317{8318S.nWSWasConnected = 1;8319MicroProfileLoadPresets("Default", LOAD_PRESET_DEFAULT | LOAD_PRESET_READONLY);8320}8321else8322{8323#if MICROPROFILE_DYNAMIC_INSTRUMENT8324MicroProfileWSPrintStart(Connection);8325MicroProfileWSPrintf("{\"k\":\"%d\",\"qp\":%d}", MSG_QUERY_INDEX, S.nQueryProcessed);8326MicroProfileWSFlush();8327MicroProfileWSPrintEnd();8328#endif8329if(S.pJsonSettings)8330{8331MicroProfileWSPrintStart(Connection);8332MicroProfileWSPrintf(8333"{\"k\":\"%d\",\"ro\":%d,\"name\":\"%s\",\"v\":%s}", MSG_CURRENTSETTINGS, S.bJsonSettingsReadOnly ? 1 : 0, S.pJsonSettingsName ? S.pJsonSettingsName : "", S.pJsonSettings);8334MicroProfileWSFlush();8335MicroProfileWSPrintEnd();8336}8337}8338}83398340void MicroProfileWebSocketSendCounters()8341{8342MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileWebSocketSendCounters", MP_GREEN4);8343if(S.nWSViewMode == VIEW_COUNTERS)8344{8345MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":[", MSG_COUNTERS);8346for(uint32_t i = 0; i < S.nNumCounters; ++i)8347{8348bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0;8349if(IsDouble)8350{8351double dCounter = S.CountersDouble[i].load();8352MicroProfileWSPrintf("%c%f", i == 0 ? ' ' : ',', dCounter);8353}8354else8355{8356uint64_t nCounter = S.Counters[i].load();8357MicroProfileWSPrintf("%c%lld", i == 0 ? ' ' : ',', nCounter);8358}8359}8360MicroProfileWSPrintf("]}");8361MicroProfileWSFlush();8362}8363}83648365#if MICROPROFILE_DYNAMIC_INSTRUMENT8366void MicroProfileSymbolSendModuleState()8367{8368if(S.WSSymbolModulesSent != S.SymbolNumModules || S.nSymbolsDirty.load()) // todo: tag when modulestate is updated.8369{8370S.nSymbolsDirty.exchange(0);8371MicroProfileWSPrintf(",\"M\":[");8372bool bFirst = true;8373for(int i = 0; i < S.SymbolNumModules; ++i)8374{8375MicroProfileSymbolModule& M = S.SymbolModules[i];8376const char* pModuleName = (const char*)M.pBaseString;8377uint64_t nAddrBegin = M.Regions[0].nBegin;8378// intptr_t nProgress = M.nProgress;8379intptr_t nProgressTarget = M.nProgressTarget;8380nProgressTarget = MicroProfileMax(intptr_t(1), M.nProgressTarget);8381// nProgress = MicroProfileMin(nProgressTarget, M.nProgress);8382float fLoadPrc = M.nProgress / float(nProgressTarget);8383uint64_t nNumSymbols = M.nSymbolsLoaded;8384#define FMT "{\"n\":\"%s\",\"a\":\"%llx\",\"s\":\"%lld\", \"p\":%f, \"d\":%d}"8385MicroProfileWSPrintf(bFirst ? FMT : ("," FMT), pModuleName, nAddrBegin, nNumSymbols, fLoadPrc, M.bDownloading ? 1 : 0);8386#undef FMT8387bFirst = false;8388}8389MicroProfileWSPrintf("]");8390S.WSSymbolModulesSent = S.SymbolNumModules;8391}8392}8393#endif83948395void MicroProfileWebSocketSendFrame(MpSocket Connection)8396{8397if(S.nFrameCurrent != S.WebSocketFrameLast[0] || S.nFrozen)8398{8399MicroProfileWebSocketSendState(Connection);8400MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileWebSocketSendFrame", MP_GREEN4);8401MicroProfileWSPrintStart(Connection);8402float fTickToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());8403float fTickToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());8404MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];8405MicroProfileFrameState* pFrameNext = &S.Frames[S.nFrameNext];84068407uint64_t nFrameTicks = pFrameNext->nFrameStartCpu - pFrameCurrent->nFrameStartCpu;8408uint64_t nFrame = pFrameCurrent->nFrameId;8409double fTime = nFrameTicks * fTickToMsCpu;8410MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"t\":%f,\"f\":%lld,\"a\":%d,\"fr\":%d,\"m\":%d", MSG_FRAME, fTime, nFrame, MicroProfileGetCurrentAggregateFrames(), S.nFrozen, S.nWSViewMode);8411#if MICROPROFILE_DYNAMIC_INSTRUMENT8412MicroProfileWSPrintf(",\"s\":{\"n\":%d,\"f\":%d,\"r\":%d,\"l\":%d,\"q\":%d}",8413S.SymbolNumModules,8414S.SymbolState.nModuleLoadsFinished.load(),8415S.SymbolState.nModuleLoadsRequested.load(),8416S.SymbolState.nSymbolsLoaded.load(),8417S.pPendingQuery ? 1 : 0);8418MicroProfileSymbolSendModuleState();8419#endif84208421auto WriteTickArray = [fTickToMsCpu, fTickToMsGpu](MicroProfile::GroupTime* pFrameGroup)8422{8423MicroProfileWSPrintf("[");8424int f = 0;8425for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)8426{8427uint64_t nTicksExcl = pFrameGroup[i].nTicksExclusive;8428if(nTicksExcl)8429{8430uint64_t nTicks = pFrameGroup[i].nTicks;8431float fCount = (float)pFrameGroup[i].nCount;8432float fToMs = S.GroupInfo[i].Type == MicroProfileTokenTypeCpu ? fTickToMsCpu : fTickToMsGpu;84338434MicroProfileWSPrintf("%c[%f,%f,%f]", f ? ',' : ' ', nTicks * fToMs, nTicksExcl * fToMs, fCount);8435f = 1;8436}8437}8438MicroProfileWSPrintf("]");8439};8440auto WriteIndexArray = [](MicroProfile::GroupTime* pFrameGroup)8441{8442MicroProfileWSPrintf("[");8443int f = 0;8444for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)8445{8446uint64_t nTicksExcl = pFrameGroup[i].nTicksExclusive;8447if(nTicksExcl)8448{8449uint32_t id = MicroProfileWebSocketIdPack(TYPE_GROUP, i);8450MicroProfileWSPrintf("%c%d", f ? ',' : ' ', id);8451f = 1;8452}8453}8454MicroProfileWSPrintf("]");8455};84568457MicroProfileWSPrintf(",\"g\":");8458WriteTickArray(S.FrameGroup);8459MicroProfileWSPrintf(",\"gi\":");8460WriteIndexArray(S.FrameGroup);8461if(S.nWSViewMode == VIEW_GRAPH_THREAD_GROUP)8462{8463MicroProfileWSPrintf(",\"gt\":[");8464int f = 0;8465for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)8466{8467if(0 != (S.FrameGroupThreadValid[i / 32] & (1 << (i % 32))))8468{8469if(!f)8470MicroProfileWSPrintf("{");8471else8472MicroProfileWSPrintf(",{");8473MicroProfileThreadLog* pLog = S.Pool[i];8474MicroProfileWSPrintf("\"i\":%d,\"n\":\"%s\",\"g\":", i, pLog->ThreadName);8475WriteTickArray(&S.FrameGroupThread[i][0]);8476MicroProfileWSPrintf(",\"gi\":");8477WriteIndexArray(&S.FrameGroupThread[i][0]);8478MicroProfileWSPrintf("}");8479f = 1;8480}8481}8482MicroProfileWSPrintf("]");8483}84848485if(S.nFrameCurrent != S.WebSocketFrameLast[0])8486{8487MicroProfileWSPrintf(",\"x\":{\"t\":{");8488int nTimer = S.WebSocketTimers;8489// uprintf("T : ");8490while(nTimer >= 0)8491{8492MicroProfileTimerInfo& TI = S.TimerInfo[nTimer];8493float fTickToMs = TI.Type == MicroProfileTokenTypeGpu ? fTickToMsGpu : fTickToMsCpu;8494uint32_t id = MicroProfileWebSocketIdPack(TYPE_TIMER, nTimer);8495fTime = fTickToMs * S.Frame[nTimer].nTicks;8496float fCount = (float)S.Frame[nTimer].nCount;8497float fTimeExcl = fTickToMs * S.FrameExclusive[nTimer];8498// uprintf("%4.2f, ", fTimeExcl);8499if(!MicroProfileGroupActive(TI.nGroupIndex))8500{8501fTime = fCount = fTimeExcl = 0.f;8502}8503nTimer = TI.nWSNext;8504MicroProfileWSPrintf("\"%d\":[%f,%f,%f]%c", id, fTime, fTimeExcl, fCount, nTimer == -1 ? ' ' : ',');8505}8506MicroProfileWSPrintf("}, \"c\":{");8507int nCounter = S.WebSocketCounters;8508while(nCounter >= 0)8509{8510MicroProfileCounterInfo& CI = S.CounterInfo[nCounter];8511bool IsDouble = (CI.nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0;8512uint32_t id = MicroProfileWebSocketIdPack(TYPE_COUNTER, nCounter);8513int nCounterNext = CI.nWSNext;8514if(IsDouble)8515{8516double value = S.CountersDouble[nCounter].load();8517MicroProfileWSPrintf("\"%d\":%f%c", id, value, nCounterNext < 0 ? ' ' : ',');8518}8519else8520{8521uint64_t value = S.Counters[nCounter].load();8522MicroProfileWSPrintf("\"%d\":%lld%c", id, value, nCounterNext < 0 ? ' ' : ',');8523}8524nCounter = nCounterNext;8525}8526MicroProfileWSPrintf("}, \"g\":{");8527// uprintf("\n");8528MicroProfileWSPrintf("}}");8529}8530MicroProfileWSPrintf("}}");8531MicroProfileWSFlush();8532MicroProfileWebSocketSendCounters();8533MicroProfileWSPrintEnd();8534S.WebSocketFrameLast[0] = S.nFrameCurrent;8535}8536else8537{8538MicroProfileWSPrintStart(Connection);8539MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"fr\":%d,\"m\":%d", MSG_INACTIVE_FRAME, S.nFrozen, S.nWSViewMode);8540#if MICROPROFILE_DYNAMIC_INSTRUMENT8541MicroProfileWSPrintf(",\"s\":{\"n\":%d,\"f\":%d,\"r\":%d,\"l\":%d,\"q\":%d}",8542S.SymbolNumModules,8543S.SymbolState.nModuleLoadsFinished.load(),8544S.SymbolState.nModuleLoadsRequested.load(),8545S.SymbolState.nSymbolsLoaded.load(),8546S.pPendingQuery ? 1 : 0);8547#endif8548MicroProfileWSPrintf("}}");8549MicroProfileWSFlush();8550MicroProfileWebSocketSendCounters();8551MicroProfileWSPrintEnd();8552}8553#if MICROPROFILE_DYNAMIC_INSTRUMENT8554MicroProfileSymbolQuerySendResult(Connection);8555MicroProfileSymbolSendFunctionNames(Connection);8556MicroProfileSymbolSendErrors(Connection);8557#endif8558}85598560void MicroProfileWebSocketFrame()8561{8562if(!S.nNumWebSockets)8563{8564return;8565}8566MICROPROFILE_SCOPEI("MicroProfile", "Websocket-update", MP_GREEN4);8567fd_set Read, Write, Error;8568FD_ZERO(&Read);8569FD_ZERO(&Write);8570FD_ZERO(&Error);8571MpSocket LastSocket = 1;8572for(uint32_t i = 0; i < S.nNumWebSockets; ++i)8573{8574LastSocket = MicroProfileMax(LastSocket, S.WebSockets[i] + 1);8575FD_SET(S.WebSockets[i], &Read);8576FD_SET(S.WebSockets[i], &Write);8577FD_SET(S.WebSockets[i], &Error);8578}8579timeval tv;8580tv.tv_sec = 0;8581tv.tv_usec = 0;85828583if(-1 == select(LastSocket, &Read, &Write, &Error, &tv))8584{8585MP_ASSERT(0);8586}8587for(uint32_t i = 0; i < S.nNumWebSockets;)8588{8589MpSocket s = S.WebSockets[i];8590bool bConnected = true;8591if(FD_ISSET(s, &Error))8592{8593MP_ASSERT(0); // todo, remove & fix.8594}8595if(FD_ISSET(s, &Read))8596{8597bConnected = MicroProfileWebSocketReceive(s);8598}8599if(FD_ISSET(s, &Write))8600{8601if(S.nJsonSettingsPending)8602{8603MicroProfileWSPrintStart(s);8604MicroProfileWSPrintf(8605"{\"k\":\"%d\",\"ro\":%d,\"name\":\"%s\",\"v\":%s}", MSG_LOADSETTINGS, S.bJsonSettingsReadOnly ? 1 : 0, S.pJsonSettingsName ? S.pJsonSettingsName : "", S.pJsonSettings);8606MicroProfileWSFlush();8607MicroProfileWSPrintEnd();8608S.nJsonSettingsPending = 0;8609}8610if(S.nWebSocketDirty)8611{8612MicroProfileFlipEnabled();8613MicroProfileWebSocketSendEnabled(s);8614S.nWebSocketDirty = 0;8615}8616MicroProfileWebSocketSendFrame(s);8617}8618if(S.nSocketFail)8619{8620bConnected = false;8621}8622S.nSocketFail = 0;86238624if(!bConnected)8625{8626uprintf("removing socket %" PRId64 "\n", (uint64_t)s);86278628#ifndef _WIN328629shutdown(S.WebSockets[i], SHUT_WR);8630#else8631shutdown(S.WebSockets[i], 1);8632#endif8633char tmp[128];8634int r = 1;8635while(r > 0)8636{8637r = recv(S.WebSockets[i], tmp, sizeof(tmp), 0);8638}8639#ifdef _WIN328640closesocket(S.WebSockets[i]);8641#else8642close(S.WebSockets[i]);8643#endif86448645--S.nNumWebSockets;8646S.WebSockets[i] = S.WebSockets[S.nNumWebSockets];8647uprintf("done removing\n");8648}8649else8650{8651++i;8652}8653}8654if(S.nWasFrozen)8655{8656S.nWasFrozen--;8657}8658}86598660void MicroProfileWSPrintStart(MpSocket C)8661{8662MP_ASSERT(S.WSBuf.Socket == 0);8663MP_ASSERT(S.WSBuf.nPut == 0);8664S.WSBuf.Socket = C;8665}86668667void MicroProfileResizeWSBuf(uint32_t nMinSize = 0)8668{8669uint32_t nNewSize = MicroProfileMax(S.WSBuf.nPut + 2 * (nMinSize + 2 + 20), MicroProfileMax(S.WSBuf.nBufferSize * 3 / 2, (uint32_t)MICROPROFILE_WEBSOCKET_BUFFER_SIZE));8670S.WSBuf.pBufferAllocation = (char*)MICROPROFILE_REALLOC(S.WSBuf.pBufferAllocation, nNewSize);8671S.WSBuf.pBuffer = S.WSBuf.pBufferAllocation + 20;8672S.WSBuf.nBufferSize = nNewSize - 20;8673}86748675char* MicroProfileWSPrintfCallback(const char* buf, void* user, int len)8676{8677MP_ASSERT(S.WSBuf.nPut == buf - S.WSBuf.pBuffer);8678S.WSBuf.nPut += len;8679if(S.WSBuf.nPut + STB_SPRINTF_MIN + 2 >= S.WSBuf.nBufferSize) //8680{8681MicroProfileResizeWSBuf(S.WSBuf.nPut + STB_SPRINTF_MIN);8682}8683return S.WSBuf.pBuffer + S.WSBuf.nPut;8684}86858686void MicroProfileWSPrintf(const char* pFmt, ...)8687{8688if(!S.WSBuf.nBufferSize)8689{8690MicroProfileResizeWSBuf(STB_SPRINTF_MIN * 2);8691}8692va_list args;8693va_start(args, pFmt);8694MP_ASSERT(S.WSBuf.nPut + STB_SPRINTF_MIN < S.WSBuf.nBufferSize);8695stbsp_vsprintfcb(MicroProfileWSPrintfCallback, 0, S.WSBuf.pBuffer + S.WSBuf.nPut, pFmt, args);8696va_end(args);8697}86988699void MicroProfileWSPrintEnd()8700{8701MP_ASSERT(S.WSBuf.nPut == 0);8702S.WSBuf.Socket = 0;8703}87048705void MicroProfileWSFlush()8706{8707MP_ASSERT(S.WSBuf.Socket != 0);8708MP_ASSERT(S.WSBuf.nPut != 0);8709MicroProfileWebSocketSend(S.WSBuf.Socket, &S.WSBuf.pBuffer[0], S.WSBuf.nPut);8710S.WSBuf.nPut = 0;8711}8712void MicroProfileWebSocketSendEnabledMessage(uint32_t id, int bEnabled)8713{8714MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"e\":%d}}", MSG_ENABLED, id, bEnabled ? 1 : 0);8715MicroProfileWSFlush();8716}8717void MicroProfileWebSocketSendEnabled(MpSocket C)8718{8719MICROPROFILE_SCOPEI("MicroProfile", "Websocket-SendEnabled", MP_GREEN4);8720MicroProfileWSPrintStart(C);8721for(uint32_t i = 0; i < S.nCategoryCount; ++i)8722{8723MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_CATEGORY, i), MicroProfileCategoryEnabled(i));8724}87258726for(uint32_t i = 0; i < S.nGroupCount; ++i)8727{8728MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_GROUP, i), MicroProfileGroupEnabled(i));8729}8730for(uint32_t i = 0; i < S.nTotalTimers; ++i)8731{8732MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_TIMER, i), MicroProfileWebSocketTimerEnabled(i));8733}8734for(uint32_t i = 0; i < S.nNumCounters; ++i)8735{8736MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_COUNTER, i), MicroProfileWebSocketCounterEnabled(i));8737}8738MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_FORCE_ENABLE), MicroProfileGetEnableAllGroups());8739MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_CONTEXT_SWITCH_TRACE), S.bContextSwitchRunning);8740MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_PLATFORM_MARKERS), MicroProfilePlatformMarkersGetEnabled());87418742MicroProfileWSPrintEnd();8743}8744void MicroProfileWebSocketSendEntry(uint32_t id, uint32_t parent, const char* pName, int nEnabled, uint32_t nColor, uint32_t nType)8745{8746MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"pid\":%d,", MSG_TIMER_TREE, id, parent);8747MicroProfileWSPrintf("\"name\":\"%s\",", pName);8748MicroProfileWSPrintf("\"e\":%d,", nEnabled);8749MicroProfileWSPrintf("\"type\":%d,", nType);8750if(nColor == 0x42)8751{8752MicroProfileWSPrintf("\"color\":\"\"");8753}8754else8755{8756MicroProfileWSPrintf("\"color\":\"#%02x%02x%02x\"", MICROPROFILE_UNPACK_RED(nColor) & 0xff, MICROPROFILE_UNPACK_GREEN(nColor) & 0xff, MICROPROFILE_UNPACK_BLUE(nColor) & 0xff);8757}87588759MicroProfileWSPrintf("}}");8760MicroProfileWSFlush();8761}87628763void MicroProfileWebSocketSendCounterEntry(uint32_t id, uint32_t parent, const char* pName, int nEnabled, int64_t nLimit, int nFormat)8764{8765MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"pid\":%d,", MSG_TIMER_TREE, id, parent);8766MicroProfileWSPrintf("\"name\":\"%s\",", pName);8767MicroProfileWSPrintf("\"e\":%d,", nEnabled);8768MicroProfileWSPrintf("\"limit\":%lld,", nLimit);8769MicroProfileWSPrintf("\"format\":%d", nFormat);8770MicroProfileWSPrintf("}}");8771MicroProfileWSFlush();8772}87738774void MicroProfileWebSocketSendState(MpSocket C)8775{8776if(S.WSCategoriesSent != S.nCategoryCount || S.WSGroupsSent != S.nGroupCount || S.WSTimersSent != S.nTotalTimers || S.WSCountersSent != S.nNumCounters)8777{8778MicroProfileWSPrintStart(C);8779uint32_t root = MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_FORCE_ENABLE);8780MicroProfileWebSocketSendEntry(root, 0, "All", MicroProfileGetEnableAllGroups(), (uint32_t)-1, 0);8781for(uint32_t i = S.WSCategoriesSent; i < S.nCategoryCount; ++i)8782{87838784MicroProfileCategory& CI = S.CategoryInfo[i];8785uint32_t id = MicroProfileWebSocketIdPack(TYPE_CATEGORY, i);8786uint32_t parent = root;8787MicroProfileWebSocketSendEntry(id, parent, CI.pName, MicroProfileCategoryEnabled(i), 0xffffffff, 0);8788}87898790for(uint32_t i = S.WSGroupsSent; i < S.nGroupCount; ++i)8791{8792MicroProfileGroupInfo& GI = S.GroupInfo[i];8793uint32_t id = MicroProfileWebSocketIdPack(TYPE_GROUP, i);8794uint32_t parent = MicroProfileWebSocketIdPack(TYPE_CATEGORY, GI.nCategory);8795MicroProfileWebSocketSendEntry(id, parent, GI.pName, MicroProfileGroupEnabled(i), GI.nColor, GI.Type);8796}87978798for(uint32_t i = S.WSTimersSent; i < S.nTotalTimers; ++i)8799{8800MicroProfileTimerInfo& TI = S.TimerInfo[i];8801uint32_t id = MicroProfileWebSocketIdPack(TYPE_TIMER, i);8802uint32_t parent = MicroProfileWebSocketIdPack(TYPE_GROUP, TI.nGroupIndex);8803MicroProfileWebSocketSendEntry(id, parent, TI.pName, MicroProfileWebSocketTimerEnabled(i), TI.nColor, TI.Type);8804}88058806for(uint32_t i = S.WSCountersSent; i < S.nNumCounters; ++i)8807{8808MicroProfileCounterInfo& CI = S.CounterInfo[i];8809uint32_t id = MicroProfileWebSocketIdPack(TYPE_COUNTER, i);8810uint32_t parent = CI.nParent == -1 ? 0u : MicroProfileWebSocketIdPack(TYPE_COUNTER, CI.nParent);8811MicroProfileWebSocketSendCounterEntry(id, parent, CI.pName, MicroProfileWebSocketCounterEnabled(i), CI.nLimit, CI.eFormat);8812}8813#if MICROPROFILE_CONTEXT_SWITCH_TRACE8814MicroProfileWebSocketSendEntry(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_CONTEXT_SWITCH_TRACE), 0, "Context Switch Trace", S.bContextSwitchRunning, (uint32_t)-1, 0);8815#endif8816#if MICROPROFILE_PLATFORM_MARKERS8817MicroProfileWebSocketSendEntry(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_PLATFORM_MARKERS), 0, "Platform Markers", S.bContextSwitchRunning, (uint32_t)-1);8818#endif8819MicroProfileWSPrintEnd();88208821S.WSCategoriesSent = S.nCategoryCount;8822S.WSGroupsSent = S.nGroupCount;8823S.WSTimersSent = S.nTotalTimers;8824S.WSCountersSent = S.nNumCounters;8825}8826}88278828bool MicroProfileWebServerUpdate()8829{8830MICROPROFILE_SCOPEI("MicroProfile", "Webserver-update", MP_GREEN4);8831MpSocket Connection = accept(S.ListenerSocket, 0, 0);8832bool bServed = false;8833MicroProfileWebSocketFrame();8834if(!MP_INVALID_SOCKET(Connection))8835{8836std::lock_guard<std::recursive_mutex> Lock(MicroProfileMutex());8837char Req[8192];8838int nReceived = recv(Connection, Req, sizeof(Req) - 1, 0);8839if(nReceived > 0)8840{8841Req[nReceived] = '\0';8842uprintf("req received\n%s", Req);88438844#define MICROPROFILE_HTML_PNG_HEADER "HTTP/1.0 200 OK\r\nContent-Type: image/png\r\n\r\n"8845#define MICROPROFILE_HTML_JS_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/javascript\r\n\r\n"8846#if MICROPROFILE_MINIZ8847// Expires: Tue, 01 Jan 2199 16:00:00 GMT\r\n8848#define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Encoding: deflate\r\n\r\n"8849#else8850#define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"8851#endif88528853char* pHttp = strstr(Req, "HTTP/");88548855char* pGet = strstr(Req, "GET /");8856char* pHost = strstr(Req, "Host: ");8857char* pWebSocketKey = strstr(Req, "Sec-WebSocket-Key: ");8858auto Terminate = [](char* pString)8859{8860char* pEnd = pString;8861while(*pEnd != '\0')8862{8863if(*pEnd == '\r' || *pEnd == '\n' || *pEnd == ' ')8864{8865*pEnd = '\0';8866return;8867}8868pEnd++;8869}8870};88718872if(pWebSocketKey)8873{8874if(S.nNumWebSockets) // only allow 18875{8876return false;8877}8878pWebSocketKey += sizeof("Sec-WebSocket-Key: ") - 1;8879Terminate(pWebSocketKey);8880MicroProfileWebSocketHandshake(Connection, pWebSocketKey);8881return false;8882}88838884if(pHost)8885{8886pHost += sizeof("Host: ") - 1;8887Terminate(pHost);8888}88898890if(pHttp && pGet)8891{8892*pHttp = '\0';8893pGet += sizeof("GET /") - 1;8894Terminate(pGet);8895MicroProfileParseGetResult R;8896auto P = MicroProfileParseGet(pGet, &R);8897switch(P)8898{8899case EMICROPROFILE_GET_COMMAND_SERVICE_WORKER:8900{8901MicroProfileSetNonBlocking(Connection, 1);8902uint64_t nTickStart = MP_TICK();8903send(Connection, MICROPROFILE_HTML_JS_HEADER, sizeof(MICROPROFILE_HTML_JS_HEADER) - 1, 0);8904const char* JsCode = "self.addEventListener(\"fetch\", () => {}); \r\n\r\n";8905send(Connection, JsCode, (int)strlen(JsCode), 0);8906break;8907}8908case EMICROPROFILE_GET_COMMAND_FAVICON:8909{8910MicroProfileSetNonBlocking(Connection, 1);8911uint64_t nTickStart = MP_TICK();8912send(Connection, MICROPROFILE_HTML_PNG_HEADER, sizeof(MICROPROFILE_HTML_PNG_HEADER) - 1, 0);8913extern const uint32_t uprof_512[];8914extern const uint32_t uprof_512_len;8915const char* pFile = (const char*)&uprof_512[0];8916uint32_t nFileSize = uprof_512_len;8917send(Connection, pFile, nFileSize, 0);8918}8919break;8920case EMICROPROFILE_GET_COMMAND_LIVE:8921{8922MicroProfileSetNonBlocking(Connection, 0);8923uint64_t nTickStart = MP_TICK();8924send(Connection, MICROPROFILE_HTML_HEADER, sizeof(MICROPROFILE_HTML_HEADER) - 1, 0);8925uint64_t nDataStart = S.nWebServerDataSent;8926S.WebServerPut = 0;8927#if 0 == MICROPROFILE_MINIZ8928MicroProfileDumpHtmlLive(MicroProfileWriteSocket, &Connection);8929uint64_t nDataEnd = S.nWebServerDataSent;8930uint64_t nTickEnd = MP_TICK();8931uint64_t nDiff = (nTickEnd - nTickStart);8932float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;8933int nKb = ((nDataEnd-nDataStart)>>10) + 1;8934int nCompressedKb = nKb;8935MicroProfilePrintf(MicroProfileWriteSocket, &Connection, "\n<!-- Sent %dkb in %.2fms-->\n\n",nKb, fMs);8936MicroProfileFlushSocket(Connection);8937#else8938MicroProfileCompressedSocketState CompressState;8939MicroProfileCompressedSocketStart(&CompressState, Connection);8940MicroProfileDumpHtmlLive(MicroProfileCompressedWriteSocket, &CompressState);8941S.nWebServerDataSent += CompressState.nSize;8942uint64_t nDataEnd = S.nWebServerDataSent;8943uint64_t nTickEnd = MP_TICK();8944uint64_t nDiff = (nTickEnd - nTickStart);8945float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;8946int nKb = ((nDataEnd - nDataStart) >> 10) + 1;8947int nCompressedKb = ((CompressState.nCompressedSize) >> 10) + 1;8948MicroProfilePrintf(MicroProfileCompressedWriteSocket, &CompressState, "\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);8949MicroProfileCompressedSocketFinish(&CompressState);8950MicroProfileFlushSocket(Connection);8951#endif89528953uprintf("\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);8954(void)nCompressedKb;8955}8956break;8957case EMICROPROFILE_GET_COMMAND_DUMP_RANGE:8958case EMICROPROFILE_GET_COMMAND_DUMP:8959{8960{8961MicroProfileSetNonBlocking(Connection, 0);8962uint64_t nTickStart = MP_TICK();8963send(Connection, MICROPROFILE_HTML_HEADER, sizeof(MICROPROFILE_HTML_HEADER) - 1, 0);8964uint64_t nDataStart = S.nWebServerDataSent;8965S.WebServerPut = 0;8966#if 0 == MICROPROFILE_MINIZ8967MicroProfileDumpHtml(MicroProfileWriteSocket, &Connection, R.nFrames, pHost, R.nFrameStart);8968uint64_t nDataEnd = S.nWebServerDataSent;8969uint64_t nTickEnd = MP_TICK();8970uint64_t nDiff = (nTickEnd - nTickStart);8971float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;8972int nKb = ((nDataEnd-nDataStart)>>10) + 1;8973int nCompressedKb = nKb;8974MicroProfilePrintf(MicroProfileWriteSocket, &Connection, "\n<!-- Sent %dkb in %.2fms-->\n\n",nKb, fMs);8975MicroProfileFlushSocket(Connection);8976#else8977MicroProfileCompressedSocketState CompressState;8978MicroProfileCompressedSocketStart(&CompressState, Connection);89798980MicroProfileDumpHtml(MicroProfileCompressedWriteSocket, &CompressState, R.nFrames, pHost, R.nFrameStart);89818982S.nWebServerDataSent += CompressState.nSize;8983uint64_t nDataEnd = S.nWebServerDataSent;8984uint64_t nTickEnd = MP_TICK();8985uint64_t nDiff = (nTickEnd - nTickStart);8986float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff;8987int nKb = ((nDataEnd - nDataStart) >> 10) + 1;8988int nCompressedKb = ((CompressState.nCompressedSize) >> 10) + 1;8989MicroProfilePrintf(MicroProfileCompressedWriteSocket, &CompressState, "\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);8990MicroProfileCompressedSocketFinish(&CompressState);8991MicroProfileFlushSocket(Connection);8992#endif89938994uprintf("\n<!-- Sent %dkb(compressed %dkb) in %.2fms-->\n\n", nKb, nCompressedKb, fMs);8995(void)nCompressedKb;8996}8997}8998break;8999case EMICROPROFILE_GET_COMMAND_UNKNOWN:9000{9001uprintf("unknown get command %s\n", pGet);9002}9003break;9004}9005}9006}9007#ifdef _WIN329008closesocket(Connection);9009#else9010close(Connection);9011#endif9012}9013return bServed;9014}9015#endif90169017#if MICROPROFILE_CONTEXT_SWITCH_TRACE9018// functions that need to be implemented per platform.9019void* MicroProfileTraceThread(void* unused);9020int MicroProfileIsLocalThread(uint32_t nThreadId);90219022void MicroProfileStartContextSwitchTrace()9023{9024if(!S.bContextSwitchRunning && !S.nMicroProfileShutdown)9025{9026S.bContextSwitchRunning = true;9027S.bContextSwitchStop = false;9028MicroProfileThreadStart(&S.ContextSwitchThread, MicroProfileTraceThread);9029}9030}90319032void MicroProfileJoinContextSwitchTrace()9033{9034if(S.bContextSwitchStop)9035{9036MicroProfileThreadJoin(&S.ContextSwitchThread);9037}9038}90399040void MicroProfileStopContextSwitchTrace()9041{9042if(S.bContextSwitchRunning)9043{9044S.bContextSwitchStop = true;9045}9046}90479048#ifdef _WIN329049#define INITGUID9050#include <evntcons.h>9051#include <evntrace.h>9052#include <strsafe.h>90539054static GUID g_MicroProfileThreadClassGuid = { 0x3d6fa8d1, 0xfe05, 0x11d0, 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c };90559056struct MicroProfileSCSwitch9057{9058uint32_t NewThreadId;9059uint32_t OldThreadId;9060int8_t NewThreadPriority;9061int8_t OldThreadPriority;9062uint8_t PreviousCState;9063int8_t SpareByte;9064int8_t OldThreadWaitReason;9065int8_t OldThreadWaitMode;9066int8_t OldThreadState;9067int8_t OldThreadWaitIdealProcessor;9068uint32_t NewThreadWaitTime;9069uint32_t Reserved;9070};90719072VOID WINAPI MicroProfileContextSwitchCallback(PEVENT_TRACE pEvent)9073{9074if(pEvent->Header.Guid == g_MicroProfileThreadClassGuid)9075{9076if(pEvent->Header.Class.Type == 36)9077{9078MicroProfileSCSwitch* pCSwitch = (MicroProfileSCSwitch*)pEvent->MofData;9079if((pCSwitch->NewThreadId != 0) || (pCSwitch->OldThreadId != 0))9080{9081MicroProfileContextSwitch Switch;9082Switch.nThreadOut = pCSwitch->OldThreadId;9083Switch.nThreadIn = pCSwitch->NewThreadId;9084Switch.nCpu = pEvent->BufferContext.ProcessorNumber;9085Switch.nTicks = pEvent->Header.TimeStamp.QuadPart;9086MicroProfileContextSwitchPut(&Switch);9087}9088}9089}9090}90919092ULONG WINAPI MicroProfileBufferCallback(PEVENT_TRACE_LOGFILEA Buffer)9093{9094return (S.bContextSwitchStop || !S.bContextSwitchRunning) ? FALSE : TRUE;9095}90969097struct MicroProfileKernelTraceProperties : public EVENT_TRACE_PROPERTIES9098{9099char dummy[sizeof(KERNEL_LOGGER_NAME)];9100};91019102void MicroProfileContextSwitchShutdownTrace()9103{9104TRACEHANDLE SessionHandle = 0;9105MicroProfileKernelTraceProperties sessionProperties;91069107ZeroMemory(&sessionProperties, sizeof(sessionProperties));9108sessionProperties.Wnode.BufferSize = sizeof(sessionProperties);9109sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;9110sessionProperties.Wnode.ClientContext = 1; // QPC clock resolution9111sessionProperties.Wnode.Guid = SystemTraceControlGuid;9112sessionProperties.BufferSize = 1;9113sessionProperties.NumberOfBuffers = 128;9114sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;9115sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;9116sessionProperties.MaximumFileSize = 0;9117sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);9118sessionProperties.LogFileNameOffset = 0;91199120EVENT_TRACE_LOGFILEA log;9121ZeroMemory(&log, sizeof(log));9122log.LoggerName = (LPSTR)KERNEL_LOGGER_NAMEA;9123log.ProcessTraceMode = 0;9124TRACEHANDLE hLog = OpenTraceA(&log);9125if(hLog)9126{9127ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties, EVENT_TRACE_CONTROL_STOP);9128}9129CloseTrace(hLog);9130}91319132typedef VOID(WINAPI* EventCallback)(PEVENT_TRACE);9133typedef ULONG(WINAPI* BufferCallback)(PEVENT_TRACE_LOGFILEA);9134bool MicroProfileStartWin32Trace(EventCallback EvtCb, BufferCallback BufferCB)9135{9136MicroProfileContextSwitchShutdownTrace();9137ULONG status = ERROR_SUCCESS;9138TRACEHANDLE SessionHandle = 0;9139MicroProfileKernelTraceProperties sessionProperties;91409141ZeroMemory(&sessionProperties, sizeof(sessionProperties));9142sessionProperties.Wnode.BufferSize = sizeof(sessionProperties);9143sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;9144sessionProperties.Wnode.ClientContext = 1; // QPC clock resolution9145sessionProperties.Wnode.Guid = SystemTraceControlGuid;9146sessionProperties.BufferSize = 1;9147sessionProperties.NumberOfBuffers = 128;9148sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_PROCESS;9149sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;9150sessionProperties.MaximumFileSize = 0;9151sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);9152sessionProperties.LogFileNameOffset = 0;91539154StopTrace(NULL, KERNEL_LOGGER_NAME, &sessionProperties);9155status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties);91569157if(ERROR_SUCCESS != status)9158{9159return false;9160}91619162EVENT_TRACE_LOGFILEA log;9163ZeroMemory(&log, sizeof(log));91649165log.LoggerName = (LPSTR)KERNEL_LOGGER_NAME;9166log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP;9167log.EventCallback = EvtCb;9168log.BufferCallback = BufferCB;91699170TRACEHANDLE hLog = OpenTraceA(&log);9171ProcessTrace(&hLog, 1, 0, 0);9172CloseTrace(hLog);9173MicroProfileContextSwitchShutdownTrace();9174return true;9175}91769177#include <psapi.h>9178#include <tlhelp32.h>9179#include <winternl.h>9180#define ThreadQuerySetWin32StartAddress 99181typedef LONG NTSTATUS;9182typedef NTSTATUS(WINAPI* pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);9183#define STATUS_SUCCESS ((NTSTATUS)0x000 00000L)9184#define ThreadQuerySetWin32StartAddress 99185#undef Process32First9186#undef Process32Next9187#undef PROCESSENTRY329188#undef Module32First9189#undef Module32Next9190#undef MODULEENTRY3291919192struct MicroProfileWin32ContextSwitchShared9193{9194std::atomic<int64_t> nPut;9195std::atomic<int64_t> nGet;9196std::atomic<int64_t> nQuit;9197std::atomic<int64_t> nTickTrace;9198std::atomic<int64_t> nTickProgram;9199enum9200{9201BUFFER_SIZE = (2 << 20) / sizeof(MicroProfileContextSwitch),9202};9203MicroProfileContextSwitch Buffer[BUFFER_SIZE];9204};92059206struct MicroProfileWin32ThreadInfo9207{9208struct Process9209{9210uint32_t pid;9211uint32_t nNumModules;9212uint32_t nModuleStart;9213const char* pProcessModule;9214};9215struct Module9216{9217int64_t nBase;9218int64_t nEnd;9219const char* pName;9220};9221enum9222{9223MAX_PROCESSES = 5 * 1024,9224MAX_THREADS = 20 * 1024,9225MAX_MODULES = 20 * 1024,9226MAX_STRINGS = 16 * 1024,9227MAX_CHARS = 128 * 1024,9228};9229uint32_t nNumProcesses;9230uint32_t nNumThreads;9231uint32_t nStringOffset;9232uint32_t nNumStrings;9233uint32_t nNumModules;9234Process P[MAX_PROCESSES];9235Module M[MAX_MODULES];9236MicroProfileThreadInfo T[MAX_THREADS];9237const char* pStrings[MAX_STRINGS];9238char StringData[MAX_CHARS];9239};92409241static MicroProfileWin32ThreadInfo g_ThreadInfo;92429243const char* MicroProfileWin32ThreadInfoAddString(const char* pString)9244{9245size_t nLen = strlen(pString);9246uint32_t nHash = *(uint32_t*)pString;9247nHash ^= (nHash >> 16);9248enum9249{9250MAX_SEARCH = 256,9251};9252for(uint32_t i = 0; i < MAX_SEARCH; ++i)9253{9254uint32_t idx = (i + nHash) % MicroProfileWin32ThreadInfo::MAX_STRINGS;9255if(0 == g_ThreadInfo.pStrings[idx])9256{9257g_ThreadInfo.pStrings[idx] = &g_ThreadInfo.StringData[g_ThreadInfo.nStringOffset];9258memcpy(&g_ThreadInfo.StringData[g_ThreadInfo.nStringOffset], pString, nLen + 1);9259g_ThreadInfo.nStringOffset += (uint32_t)(nLen + 1);9260return g_ThreadInfo.pStrings[idx];9261}9262if(0 == strcmp(g_ThreadInfo.pStrings[idx], pString))9263{9264return g_ThreadInfo.pStrings[idx];9265}9266}9267return "internal hash table fail: should never happen";9268}9269void MicroProfileWin32ExtractModules(MicroProfileWin32ThreadInfo::Process& P)9270{9271HANDLE hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, P.pid);9272MODULEENTRY32 me;9273if(Module32First(hModuleSnapshot, &me))9274{9275do9276{9277if(g_ThreadInfo.nNumModules < MicroProfileWin32ThreadInfo::MAX_MODULES)9278{9279auto& M = g_ThreadInfo.M[g_ThreadInfo.nNumModules++];9280P.nNumModules++;9281intptr_t nBase = (intptr_t)me.modBaseAddr;9282intptr_t nEnd = nBase + me.modBaseSize;9283M.nBase = nBase;9284M.nEnd = nEnd;9285M.pName = MicroProfileWin32ThreadInfoAddString(&me.szModule[0]);9286}9287} while(Module32Next(hModuleSnapshot, &me));9288}9289if(hModuleSnapshot)9290CloseHandle(hModuleSnapshot);9291}9292void MicroProfileWin32InitThreadInfo2()9293{9294memset(&g_ThreadInfo, 0, sizeof(g_ThreadInfo));9295#if MICROPROFILE_DEBUG9296float fToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());9297#endif92989299HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);9300PROCESSENTRY32 pe32;9301THREADENTRY32 te32;9302te32.dwSize = sizeof(THREADENTRY32);9303pe32.dwSize = sizeof(PROCESSENTRY32);9304{9305#if MICROPROFILE_DEBUG9306int64_t nTickStart = MP_TICK();9307#endif9308if(Process32First(hSnap, &pe32))9309{9310do9311{93129313MicroProfileWin32ThreadInfo::Process P;9314P.pid = pe32.th32ProcessID;9315P.pProcessModule = MicroProfileWin32ThreadInfoAddString(pe32.szExeFile);9316g_ThreadInfo.P[g_ThreadInfo.nNumProcesses++] = P;9317} while(Process32Next(hSnap, &pe32) && g_ThreadInfo.nNumProcesses < MicroProfileWin32ThreadInfo::MAX_PROCESSES);9318}9319#if MICROPROFILE_DEBUG9320int64_t nTicksEnd = MP_TICK();9321float fMs = fToMsCpu * (nTicksEnd - nTickStart);9322uprintf("Process iteration %6.2fms processes %d\n", fMs, g_ThreadInfo.nNumProcesses);9323#endif9324}9325{9326#if MICROPROFILE_DEBUG9327int64_t nTickStart = MP_TICK();9328#endif9329for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i)9330{9331g_ThreadInfo.P[i].nModuleStart = g_ThreadInfo.nNumModules;9332g_ThreadInfo.P[i].nNumModules = 0;9333MicroProfileWin32ExtractModules(g_ThreadInfo.P[i]);9334}9335#if MICROPROFILE_DEBUG9336int64_t nTicksEnd = MP_TICK();9337float fMs = fToMsCpu * (nTicksEnd - nTickStart);9338uprintf("Module iteration %6.2fms NumModules %d\n", fMs, g_ThreadInfo.nNumModules);9339#endif9340}93419342pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationThread");9343intptr_t dwStartAddress;9344ULONG olen;9345uint32_t nThreadsTested = 0;9346uint32_t nThreadsSucceeded = 0;93479348if(Thread32First(hSnap, &te32))9349{9350#if MICROPROFILE_DEBUG9351int64_t nTickStart = MP_TICK();9352#endif9353do9354{9355nThreadsTested++;9356const char* pModule = "?";9357HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID);9358if(hThread)9359{93609361NTSTATUS ntStatus = NtQueryInformationThread(hThread, (THREADINFOCLASS)ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(dwStartAddress), &olen);9362if(0 == ntStatus)9363{9364uint32_t nProcessIndex = (uint32_t)-1;9365for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i)9366{9367if(g_ThreadInfo.P[i].pid == te32.th32OwnerProcessID)9368{9369nProcessIndex = i;9370break;9371}9372}9373if(nProcessIndex != (uint32_t)-1)9374{9375uint32_t nModuleStart = g_ThreadInfo.P[nProcessIndex].nModuleStart;9376uint32_t nNumModules = g_ThreadInfo.P[nProcessIndex].nNumModules;9377for(uint32_t i = 0; i < nNumModules; ++i)9378{9379auto& M = g_ThreadInfo.M[nModuleStart + i];9380if(M.nBase <= dwStartAddress && M.nEnd >= dwStartAddress)9381{9382pModule = M.pName;9383}9384}9385}9386}9387}9388if(hThread)9389CloseHandle(hThread);9390{9391MicroProfileThreadInfo T;9392T.pid = te32.th32OwnerProcessID;9393T.tid = te32.th32ThreadID;9394const char* pProcess = "unknown";9395for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i)9396{9397if(g_ThreadInfo.P[i].pid == T.pid)9398{9399pProcess = g_ThreadInfo.P[i].pProcessModule;9400break;9401}9402}9403T.pProcessModule = pProcess;9404T.pThreadModule = MicroProfileWin32ThreadInfoAddString(pModule);9405T.nIsLocal = GetCurrentProcessId() == T.pid ? 1 : 0;9406nThreadsSucceeded++;9407g_ThreadInfo.T[g_ThreadInfo.nNumThreads++] = T;9408}94099410} while(Thread32Next(hSnap, &te32) && g_ThreadInfo.nNumThreads < MicroProfileWin32ThreadInfo::MAX_THREADS);94119412#if MICROPROFILE_DEBUG9413int64_t nTickEnd = MP_TICK();9414float fMs = fToMsCpu * (nTickEnd - nTickStart);9415uprintf("Thread iteration %6.2fms Threads %d\n", fMs, g_ThreadInfo.nNumThreads);9416#endif9417}9418}94199420void MicroProfileWin32UpdateThreadInfo()9421{9422static int nWasRunning = 1;9423static int nOnce = 0;9424int nRunning = MicroProfileAnyGroupActive() ? 1 : 0;94259426if((0 == nRunning && 1 == nWasRunning) || nOnce == 0)9427{9428nOnce = 1;9429MicroProfileWin32InitThreadInfo2();9430}9431nWasRunning = nRunning;9432}94339434const char* MicroProfileThreadNameFromId(MicroProfileThreadIdType nThreadId)9435{9436MicroProfileWin32UpdateThreadInfo();9437static char result[1024];9438for(uint32_t i = 0; i < g_ThreadInfo.nNumThreads; ++i)9439{9440if(g_ThreadInfo.T[i].tid == nThreadId)9441{9442sprintf_s(result, "p:%s t:%s", g_ThreadInfo.T[i].pProcessModule, g_ThreadInfo.T[i].pThreadModule);9443return result;9444}9445}9446sprintf_s(result, "?");9447return result;9448}94499450#define MICROPROFILE_FILEMAPPING "microprofile-shared"9451#ifdef MICROPROFILE_WIN32_COLLECTOR9452#define MICROPROFILE_WIN32_CSWITCH_TIMEOUT 15 // seconds to wait before collector exits9453static MicroProfileWin32ContextSwitchShared* g_pShared = 0;9454VOID WINAPI MicroProfileContextSwitchCallbackCollector(PEVENT_TRACE pEvent)9455{9456static int64_t nPackets = 0;9457static int64_t nSkips = 0;9458if(pEvent->Header.Guid == g_MicroProfileThreadClassGuid)9459{9460if(pEvent->Header.Class.Type == 36)9461{9462MicroProfileSCSwitch* pCSwitch = (MicroProfileSCSwitch*)pEvent->MofData;9463if((pCSwitch->NewThreadId != 0) || (pCSwitch->OldThreadId != 0))9464{9465MicroProfileContextSwitch Switch;9466Switch.nThreadOut = pCSwitch->OldThreadId;9467Switch.nThreadIn = pCSwitch->NewThreadId;9468Switch.nCpu = pEvent->BufferContext.ProcessorNumber;9469Switch.nTicks = pEvent->Header.TimeStamp.QuadPart;9470int64_t nPut = g_pShared->nPut.load(std::memory_order_relaxed);9471int64_t nGet = g_pShared->nGet.load(std::memory_order_relaxed);9472nPackets++;9473if(nPut - nGet < MicroProfileWin32ContextSwitchShared::BUFFER_SIZE)9474{9475g_pShared->Buffer[nPut % MicroProfileWin32ContextSwitchShared::BUFFER_SIZE] = Switch;9476g_pShared->nPut.store(nPut + 1, std::memory_order_release);9477nSkips = 0;9478}9479else9480{9481nSkips++;9482}9483}9484}9485}9486if(0 == (nPackets % (4 << 10)))9487{9488int64_t nTickTrace = MP_TICK();9489g_pShared->nTickTrace.store(nTickTrace);9490int64_t nTickProgram = g_pShared->nTickProgram.load();9491float fTickToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());9492float fTime = fabs(fTickToMs * (nTickTrace - nTickProgram));9493printf("\rRead %" PRId64 " CSwitch Packets, Skips %" PRId64 " Time difference %6.3fms ", nPackets, nSkips, fTime);9494fflush(stdout);9495if(fTime > MICROPROFILE_WIN32_CSWITCH_TIMEOUT * 1000)9496{9497g_pShared->nQuit.store(1);9498}9499}9500}95019502ULONG WINAPI MicroProfileBufferCallbackCollector(PEVENT_TRACE_LOGFILEA Buffer)9503{9504return (g_pShared->nQuit.load()) ? FALSE : TRUE;9505}95069507int main(int argc, char* argv[])9508{9509if(argc != 2)9510{9511return 1;9512}9513printf("using file '%s'\n", argv[1]);9514HANDLE hMemory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, argv[1]);9515if(hMemory == NULL)9516{9517return 1;9518}9519g_pShared = (MicroProfileWin32ContextSwitchShared*)MapViewOfFile(hMemory, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MicroProfileWin32ContextSwitchShared));95209521if(g_pShared != NULL)9522{9523MicroProfileStartWin32Trace(MicroProfileContextSwitchCallbackCollector, MicroProfileBufferCallbackCollector);9524UnmapViewOfFile(g_pShared);9525}95269527CloseHandle(hMemory);9528return 0;9529}9530#endif9531#include <shellapi.h>9532void* MicroProfileTraceThread(void* unused)9533{9534MicroProfileOnThreadCreate("ContextSwitchThread");9535MicroProfileContextSwitchShutdownTrace();9536if(!MicroProfileStartWin32Trace(MicroProfileContextSwitchCallback, MicroProfileBufferCallback))9537{9538MicroProfileContextSwitchShutdownTrace();9539// not running as admin. try and start other process.9540MicroProfileWin32ContextSwitchShared* pShared = 0;9541char Filename[512];9542time_t t = time(NULL);9543_snprintf_s(Filename, sizeof(Filename), "%s_%d", MICROPROFILE_FILEMAPPING, (int)t);95449545HANDLE hMemory = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(MicroProfileWin32ContextSwitchShared), Filename);9546if(hMemory != NULL)9547{9548pShared = (MicroProfileWin32ContextSwitchShared*)MapViewOfFile(hMemory, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MicroProfileWin32ContextSwitchShared));9549if(pShared != NULL)9550{9551#ifdef _M_IX869552#define CSWITCH_EXE "microprofile-win32-cswitch_x86.exe"9553#else9554#define CSWITCH_EXE "microprofile-win32-cswitch_x64.exe"9555#endif9556pShared->nTickProgram.store(MP_TICK());9557pShared->nTickTrace.store(MP_TICK());9558HINSTANCE Instance = ShellExecuteA(NULL, "runas", CSWITCH_EXE, Filename, "", SW_SHOWMINNOACTIVE);9559int64_t nInstance = (int64_t)Instance;9560if(nInstance >= 32)9561{9562int64_t nPut, nGet;9563while(!S.bContextSwitchStop)9564{9565nPut = pShared->nPut.load(std::memory_order_acquire);9566nGet = pShared->nGet.load(std::memory_order_relaxed);9567if(nPut == nGet)9568{9569Sleep(20);9570}9571else9572{9573for(int64_t i = nGet; i != nPut; i++)9574{9575MicroProfileContextSwitchPut(&pShared->Buffer[i % MicroProfileWin32ContextSwitchShared::BUFFER_SIZE]);9576}9577pShared->nGet.store(nPut, std::memory_order_release);9578pShared->nTickProgram.store(MP_TICK());9579}9580}9581pShared->nQuit.store(1);9582}9583}9584UnmapViewOfFile(pShared);9585}9586CloseHandle(hMemory);9587}9588S.bContextSwitchRunning = false;9589MicroProfileOnThreadExit();9590return 0;9591}95929593MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId)9594{9595MicroProfileWin32UpdateThreadInfo();95969597for(uint32_t i = 0; i < g_ThreadInfo.nNumThreads; ++i)9598{9599if(g_ThreadInfo.T[i].tid == nThreadId)9600{9601return g_ThreadInfo.T[i];9602}9603}9604MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0);9605return TI;9606}9607uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray)9608{9609MicroProfileWin32InitThreadInfo2();9610*pThreadArray = &g_ThreadInfo.T[0];9611return g_ThreadInfo.nNumThreads;9612}96139614#elif defined(__APPLE__)9615#include <sys/time.h>9616void* MicroProfileTraceThread(void* unused)9617{9618FILE* pFile = fopen("mypipe", "r");9619if(!pFile)9620{9621uprintf("CONTEXT SWITCH FAILED TO OPEN FILE: make sure to run dtrace script\n");9622S.bContextSwitchRunning = false;9623return 0;9624}9625uprintf("STARTING TRACE THREAD\n");9626char* pLine = 0;9627size_t cap = 0;9628size_t len = 0;9629struct timeval tv;96309631gettimeofday(&tv, NULL);96329633uint64_t nsSinceEpoch = ((uint64_t)(tv.tv_sec) * 1000000 + (uint64_t)(tv.tv_usec)) * 1000;9634uint64_t nTickEpoch = MP_TICK();9635uint32_t nLastThread[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS] = { 0 };9636mach_timebase_info_data_t sTimebaseInfo;9637mach_timebase_info(&sTimebaseInfo);9638S.bContextSwitchRunning = true;96399640uint64_t nProcessed = 0;9641uint64_t nProcessedLast = 0;9642while((len = getline(&pLine, &cap, pFile)) > 0 && !S.bContextSwitchStop)9643{9644nProcessed += len;9645if(nProcessed - nProcessedLast > 10 << 10)9646{9647nProcessedLast = nProcessed;9648uprintf("processed %llukb %llukb\n", (nProcessed - nProcessedLast) >> 10, nProcessed >> 10);9649}96509651char* pX = strchr(pLine, 'X');9652if(pX)9653{9654int cpu = atoi(pX + 1);9655char* pX2 = strchr(pX + 1, 'X');9656char* pX3 = strchr(pX2 + 1, 'X');9657int thread = atoi(pX2 + 1);9658char* lala;9659int64_t timestamp = strtoll(pX3 + 1, &lala, 10);9660MicroProfileContextSwitch Switch;96619662// convert to ticks.9663uint64_t nDeltaNsSinceEpoch = timestamp - nsSinceEpoch;9664uint64_t nDeltaTickSinceEpoch = sTimebaseInfo.numer * nDeltaNsSinceEpoch / sTimebaseInfo.denom;9665uint64_t nTicks = nDeltaTickSinceEpoch + nTickEpoch;9666if(cpu < MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS)9667{9668Switch.nThreadOut = nLastThread[cpu];9669Switch.nThreadIn = thread;9670nLastThread[cpu] = thread;9671Switch.nCpu = cpu;9672Switch.nTicks = nTicks;9673MicroProfileContextSwitchPut(&Switch);9674}9675}9676}9677uprintf("EXITING TRACE THREAD\n");9678S.bContextSwitchRunning = false;9679return 0;9680}96819682MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId)9683{9684MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0);9685return TI;9686}9687uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray)9688{9689*pThreadArray = 0;9690return 0;9691}96929693#endif9694#else96959696MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId)9697{9698MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0);9699return TI;9700}9701uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray)9702{9703*pThreadArray = 0;9704return 0;9705}9706void MicroProfileStopContextSwitchTrace()9707{9708}9709void MicroProfileJoinContextSwitchTrace()9710{9711}9712void MicroProfileStartContextSwitchTrace()9713{9714}97159716#endif97179718#if MICROPROFILE_GPU_TIMERS9719void MicroProfileGpuShutdownPlatform()9720{9721if(S.pGPU)9722{9723MicroProfileGpuShutdown();9724MP_FREE(S.pGPU);9725S.pGPU = nullptr;9726MicroProfileGpuInsertTimeStamp_Callback = nullptr;9727MicroProfileGpuGetTimeStamp_Callback = nullptr;9728MicroProfileTicksPerSecondGpu_Callback = nullptr;9729MicroProfileGetGpuTickReference_Callback = nullptr;9730MicroProfileGpuFlip_Callback = nullptr;9731MicroProfileGpuShutdown_Callback = nullptr;9732}9733}97349735void MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType eType,9736MicroProfileGpuTimerState* pGPU,9737MicroProfileGpuInsertTimeStamp_CB InsertTimeStamp,9738MicroProfileGpuGetTimeStamp_CB GetTimeStamp,9739MicroProfileTicksPerSecondGpu_CB TicksPerSecond,9740MicroProfileGetGpuTickReference_CB GetTickReference,9741MicroProfileGpuFlip_CB Flip,9742MicroProfileGpuShutdown_CB Shutdown)9743{97449745MP_ASSERT(S.pGPU == nullptr);9746pGPU->Type = eType;9747S.pGPU = pGPU;97489749MicroProfileGpuInsertTimeStamp_Callback = InsertTimeStamp;9750MicroProfileGpuGetTimeStamp_Callback = GetTimeStamp;9751MicroProfileTicksPerSecondGpu_Callback = TicksPerSecond;9752MicroProfileGetGpuTickReference_Callback = GetTickReference;9753MicroProfileGpuFlip_Callback = Flip;9754MicroProfileGpuShutdown_Callback = Shutdown;9755}9756#endif97579758#if MICROPROFILE_GPU_TIMERS_D3D119759//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::::'##:::9760//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####::::'####:::9761// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##::::.. ##:::9762// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##:::::: ##:::9763// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::::: ##:::9764// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##:::::: ##:::9765//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######::'######:9766//:......::::..::::::::::.......::::::........::::.......:::........::::......:::......::9767uint32_t MicroProfileGpuInsertTimeStampD3D11(void* pContext_)9768{9769MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9770if(!pGPU)9771return 0;9772MicroProfileD3D11Frame& Frame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame];9773uint32_t nStart = Frame.m_nQueryStart;9774if(Frame.m_nRateQueryStarted)9775{9776uint32_t nIndex = (uint32_t)-1;9777do9778{9779nIndex = Frame.m_nQueryCount.load();9780if(nIndex + 1 >= Frame.m_nQueryCountMax)9781{9782return (uint32_t)-1;9783}9784} while(!Frame.m_nQueryCount.compare_exchange_weak(nIndex, nIndex + 1));9785nIndex += nStart;9786uint32_t nQueryIndex = nIndex % MICROPROFILE_D3D11_MAX_QUERIES;97879788ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_pQueries[nQueryIndex];9789ID3D11DeviceContext* pContext = (ID3D11DeviceContext*)pContext_;9790pContext->End(pQuery);9791return nQueryIndex;9792}9793return (uint32_t)-1;9794}97959796uint64_t MicroProfileGpuGetTimeStampD3D11(uint32_t nIndex)9797{9798if(nIndex == (uint32_t)-1)9799{9800return (uint64_t)-1;9801}9802MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9803if(!pGPU)9804return 0;98059806int64_t nResult = pGPU->m_nQueryResults[nIndex];9807MP_ASSERT(nResult != -1);9808return nResult;9809}98109811bool MicroProfileGpuGetDataD3D11(void* pQuery, void* pData, uint32_t nDataSize)9812{9813MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9814if(!pGPU)9815return false;98169817HRESULT hr;9818do9819{9820hr = ((ID3D11DeviceContext*)pGPU->m_pImmediateContext)->GetData((ID3D11Query*)pQuery, pData, nDataSize, 0);9821} while(hr == S_FALSE);9822switch(hr)9823{9824case DXGI_ERROR_DEVICE_REMOVED:9825case DXGI_ERROR_INVALID_CALL:9826case E_INVALIDARG:9827MP_BREAK();9828return false;9829}9830return true;9831}98329833uint64_t MicroProfileTicksPerSecondGpuD3D11()9834{9835MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9836if(!pGPU)9837return 1;98389839return pGPU->m_nQueryFrequency;9840}98419842uint32_t MicroProfileGpuFlipD3D11(void* pDeviceContext_)9843{9844if(!pDeviceContext_)9845{9846return (uint32_t)-1;9847}9848MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9849if(!pGPU)9850return 0;98519852ID3D11DeviceContext* pDeviceContext = (ID3D11DeviceContext*)pDeviceContext_;9853uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pDeviceContext);9854MicroProfileD3D11Frame& CurrentFrame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame];9855ID3D11DeviceContext* pImmediateContext = (ID3D11DeviceContext*)pGPU->m_pImmediateContext;9856if(CurrentFrame.m_nRateQueryStarted)9857{9858pImmediateContext->End((ID3D11Query*)CurrentFrame.m_pRateQuery);9859}9860uint32_t nNextFrame = (pGPU->m_nQueryFrame + 1) % MICROPROFILE_GPU_FRAME_DELAY;9861pGPU->m_nQueryPut = (CurrentFrame.m_nQueryStart + CurrentFrame.m_nQueryCount) % MICROPROFILE_D3D11_MAX_QUERIES;9862MicroProfileD3D11Frame& OldFrame = pGPU->m_QueryFrames[nNextFrame];9863if(OldFrame.m_nRateQueryStarted)9864{9865struct RateQueryResult9866{9867uint64_t nFrequency;9868BOOL bDisjoint;9869};9870RateQueryResult Result;9871if(MicroProfileGpuGetDataD3D11(OldFrame.m_pRateQuery, &Result, sizeof(Result)))9872{9873if(pGPU->m_nQueryFrequency != (int64_t)Result.nFrequency)9874{9875if(pGPU->m_nQueryFrequency)9876{9877OutputDebugStringA("Query freq changing");9878}9879pGPU->m_nQueryFrequency = Result.nFrequency;9880}9881uint32_t nStart = OldFrame.m_nQueryStart;9882uint32_t nCount = OldFrame.m_nQueryCount;9883for(uint32_t i = 0; i < nCount; ++i)9884{9885uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D11_MAX_QUERIES;98869887if(!MicroProfileGpuGetDataD3D11(pGPU->m_pQueries[nIndex], &pGPU->m_nQueryResults[nIndex], sizeof(uint64_t)))9888{9889pGPU->m_nQueryResults[nIndex] = -1;9890}9891}9892}9893else9894{9895uint32_t nStart = OldFrame.m_nQueryStart;9896uint32_t nCount = OldFrame.m_nQueryCount;98979898for(uint32_t i = 0; i < nCount; ++i)9899{9900uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D11_MAX_QUERIES;9901pGPU->m_nQueryResults[nIndex] = -1;9902}9903}9904pGPU->m_nQueryGet = (OldFrame.m_nQueryStart + OldFrame.m_nQueryCount) % MICROPROFILE_D3D11_MAX_QUERIES;9905}99069907pGPU->m_nQueryFrame = nNextFrame;9908MicroProfileD3D11Frame& NextFrame = pGPU->m_QueryFrames[nNextFrame];9909pImmediateContext->Begin((ID3D11Query*)NextFrame.m_pRateQuery);9910NextFrame.m_nQueryStart = pGPU->m_nQueryPut;9911NextFrame.m_nQueryCount = 0;9912if(pGPU->m_nQueryPut >= pGPU->m_nQueryGet)9913{9914NextFrame.m_nQueryCountMax = (MICROPROFILE_D3D11_MAX_QUERIES - pGPU->m_nQueryPut) + pGPU->m_nQueryGet;9915}9916else9917{9918NextFrame.m_nQueryCountMax = pGPU->m_nQueryGet - pGPU->m_nQueryPut - 1;9919}9920if(NextFrame.m_nQueryCountMax)9921NextFrame.m_nQueryCountMax -= 1;9922NextFrame.m_nRateQueryStarted = 1;9923return nFrameTimeStamp;9924}99259926void MicroProfileGpuInitD3D11(void* pDevice_, void* pImmediateContext)9927{9928ID3D11Device* pDevice = (ID3D11Device*)pDevice_;99299930MicroProfileGpuTimerStateD3D11* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateD3D11);99319932MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_D3D11,9933pGPU,9934MicroProfileGpuInsertTimeStampD3D11,9935MicroProfileGpuGetTimeStampD3D11,9936MicroProfileTicksPerSecondGpuD3D11,9937MicroProfileGetGpuTickReferenceD3D11,9938MicroProfileGpuFlipD3D11,9939MicroProfileGpuShutdownD3D11);99409941pGPU->m_pImmediateContext = pImmediateContext;99429943D3D11_QUERY_DESC Desc;9944Desc.MiscFlags = 0;9945Desc.Query = D3D11_QUERY_TIMESTAMP;9946for(uint32_t i = 0; i < MICROPROFILE_D3D11_MAX_QUERIES; ++i)9947{9948HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->m_pQueries[i]);9949MP_ASSERT(hr == S_OK);9950pGPU->m_nQueryResults[i] = -1;9951}9952HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->pSyncQuery);9953MP_ASSERT(hr == S_OK);99549955pGPU->m_nQueryPut = 0;9956pGPU->m_nQueryGet = 0;9957pGPU->m_nQueryFrame = 0;9958pGPU->m_nQueryFrequency = 0;9959Desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;9960for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i)9961{9962pGPU->m_QueryFrames[i].m_nQueryStart = 0;9963pGPU->m_QueryFrames[i].m_nQueryCount = 0;9964pGPU->m_QueryFrames[i].m_nRateQueryStarted = 0;9965hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->m_QueryFrames[i].m_pRateQuery);9966MP_ASSERT(hr == S_OK);9967}9968}99699970void MicroProfileGpuShutdownD3D11()9971{9972MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();9973if(!pGPU)9974return;99759976for(uint32_t i = 0; i < MICROPROFILE_D3D11_MAX_QUERIES; ++i)9977{9978if(pGPU->m_pQueries[i])9979{9980ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_pQueries[i];9981pQuery->Release();9982pGPU->m_pQueries[i] = 0;9983}9984}9985for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i)9986{9987if(pGPU->m_QueryFrames[i].m_pRateQuery)9988{9989ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_QueryFrames[i].m_pRateQuery;9990pQuery->Release();9991pGPU->m_QueryFrames[i].m_pRateQuery = 0;9992}9993}9994if(pGPU->pSyncQuery)9995{9996ID3D11Query* pSyncQuery = (ID3D11Query*)pGPU->pSyncQuery;9997pSyncQuery->Release();9998pGPU->pSyncQuery = 0;9999}10000}1000110002int MicroProfileGetGpuTickReferenceD3D11(int64_t* pOutCPU, int64_t* pOutGpu)10003{10004MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11();10005if(!pGPU)10006return 0;10007{10008MicroProfileD3D11Frame& Frame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame];10009if(Frame.m_nRateQueryStarted)10010{10011ID3D11Query* pSyncQuery = (ID3D11Query*)pGPU->pSyncQuery;10012ID3D11DeviceContext* pImmediateContext = (ID3D11DeviceContext*)pGPU->m_pImmediateContext;10013pImmediateContext->End(pSyncQuery);1001410015HRESULT hr;10016do10017{10018hr = pImmediateContext->GetData(pSyncQuery, pOutGpu, sizeof(*pOutGpu), 0);10019} while(hr == S_FALSE);10020*pOutCPU = MP_TICK();10021switch(hr)10022{10023case DXGI_ERROR_DEVICE_REMOVED:10024case DXGI_ERROR_INVALID_CALL:10025case E_INVALIDARG:10026MP_BREAK();10027return false;10028}10029MP_ASSERT(hr == S_OK);10030return 1;10031}10032}10033return 0;10034}10035MicroProfileGpuTimerStateD3D11* MicroProfileGetGpuTimerStateD3D11()10036{10037if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_D3D11)10038return (MicroProfileGpuTimerStateD3D11*)S.pGPU;10039return nullptr;10040}1004110042#endif1004310044#if MICROPROFILE_GPU_TIMERS_D3D1210045//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::'#######::10046//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####:::'##.... ##:10047// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##:::..::::: ##:10048// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##::::'#######::10049// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::'##::::::::10050// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##::: ##::::::::10051//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######: #########:10052//:......::::..::::::::::.......::::::........::::.......:::........::::......::.........::10053#include <d3d12.h>10054uint32_t MicroProfileGpuInsertTimeStampD3D12(void* pContext)10055{10056MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10057if(!pGPU || !pContext)10058return 0;1005910060ID3D12GraphicsCommandList* pCommandList = (ID3D12GraphicsCommandList*)pContext;1006110062bool IsCopy = D3D12_COMMAND_LIST_TYPE_COPY == pCommandList->GetType();10063uint32_t nNode = pGPU->nCurrentNode;10064uint32_t nFrame = pGPU->nFrame;1006510066ID3D12QueryHeap* pHeap = IsCopy ? pGPU->NodeState[nNode].pCopyQueueHeap : pGPU->NodeState[nNode].pHeap;1006710068uint32_t nQueryIndex = IsCopy ? ((pGPU->nFrameCountCopyQueueTimeStamps.fetch_add(1) + pGPU->nFrameStartCopyQueueTimeStamps) % MICROPROFILE_D3D12_MAX_QUERIES)10069: ((pGPU->nFrameCountTimeStamps.fetch_add(1) + pGPU->nFrameStartTimeStamps) % MICROPROFILE_D3D12_MAX_QUERIES);1007010071pCommandList->EndQuery(pHeap, D3D12_QUERY_TYPE_TIMESTAMP, nQueryIndex);10072MP_ASSERT(nQueryIndex <= 0xffff);10073uint32_t res = (IsCopy ? 0x80000000 : 0) | ((nFrame << 16) & 0x7fff0000) | (nQueryIndex);10074return res;10075}1007610077void MicroProfileGpuFetchRange(uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset)10078{10079MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10080if(!pGPU || nCount <= 0)10081return;10082void* pData = 0;10083// uprintf("fetch [%d-%d]\n", nBegin, nBegin + nCount);10084D3D12_RANGE Range = { sizeof(uint64_t) * nBegin, sizeof(uint64_t) * (nBegin + nCount) };10085pGPU->pBuffer->Map(0, &Range, &pData);10086memcpy(&pGPU->nResults[nBegin], nBegin + (uint64_t*)pData, nCount * sizeof(uint64_t));10087for(int i = 0; i < nCount; ++i)10088{10089pGPU->nQueryFrames[i + nBegin] = nFrame;10090pGPU->nResults[i + nBegin] -= nTimestampOffset;10091}10092pGPU->pBuffer->Unmap(0, 0);10093}10094void MicroProfileGpuFetchRangeCopy(uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset)10095{10096MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10097if(!pGPU || nCount <= 0)10098return;10099void* pData = 0;10100D3D12_RANGE Range = { sizeof(uint64_t) * nBegin, sizeof(uint64_t) * (nBegin + nCount) };10101pGPU->pBufferCopy->Map(0, &Range, &pData);10102memcpy(&pGPU->nResultsCopy[nBegin], nBegin + (uint64_t*)pData, nCount * sizeof(uint64_t));10103for(int i = 0; i < nCount; ++i)10104{10105pGPU->nQueryFramesCopy[i + nBegin] = nFrame;10106pGPU->nResultsCopy[i + nBegin] -= nTimestampOffset;10107}10108pGPU->pBufferCopy->Unmap(0, 0);10109}10110void MicroProfileGpuWaitFenceD3D12(uint32_t nNode, uint64_t nFence)10111{10112MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10113if(!pGPU)10114return;1011510116auto GetFence = [&]() -> uint64_t10117{10118uint64_t f0 = pGPU->NodeState[nNode].pFence->GetCompletedValue();10119uint64_t f1 = pGPU->NodeState[nNode].pFenceCopy->GetCompletedValue();10120return MicroProfileMin(f0, f1);10121};10122uint64_t nCompletedFrame = GetFence();10123// while(nCompletedFrame < nPending)10124// while(0 < nPending - nCompletedFrame)10125while(0 < (int64_t)(nFence - nCompletedFrame))10126{10127MICROPROFILE_SCOPEI("Microprofile", "gpu-wait", MP_GREEN4);10128Sleep(20); // todo: use event.10129nCompletedFrame = GetFence();10130if((uint64_t)-1 == nCompletedFrame) // likely device removed.10131return;10132}10133}1013410135void MicroProfileGpuFetchResultsD3D12(uint64_t nFrame)10136{10137MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10138if(!pGPU)10139return;10140uint64_t nPending = pGPU->nPendingFrame;1014110142// while(nPending <= nFrame)10143// while(0 <= nFrame - nPending)10144while(0 <= (int64_t)(nFrame - nPending))10145{10146uint32_t nInternal = nPending % MICROPROFILE_D3D_INTERNAL_DELAY;10147uint32_t nNode = pGPU->Frames[nInternal].nNode;10148MicroProfileGpuWaitFenceD3D12(nNode, nPending);10149int64_t nTimestampOffset = 0;10150if(nNode != 0)10151{10152// Adjust timestamp queries from GPU x to be in GPU 0's frame of reference10153HRESULT hr;10154int64_t nCPU0, nGPU0;10155hr = pGPU->NodeState[0].pCommandQueue->GetClockCalibration((uint64_t*)&nGPU0, (uint64_t*)&nCPU0);10156MP_ASSERT(hr == S_OK);10157int64_t nCPUx, nGPUx;10158hr = pGPU->NodeState[nNode].pCommandQueue->GetClockCalibration((uint64_t*)&nGPUx, (uint64_t*)&nCPUx);10159MP_ASSERT(hr == S_OK);10160int64_t nFreqCPU = MicroProfileTicksPerSecondCpu();10161int64_t nElapsedCPU = nCPUx - nCPU0;10162int64_t nElapsedGPU = pGPU->nFrequency * nElapsedCPU / nFreqCPU;10163nTimestampOffset = nGPUx - nGPU0 - nElapsedGPU;10164}1016510166{10167uint32_t nTimeStampBegin = pGPU->Frames[nInternal].nTimeStampBegin;10168uint32_t nTimeStampCount = pGPU->Frames[nInternal].nTimeStampCount;10169MicroProfileGpuFetchRange(10170nTimeStampBegin, (nTimeStampBegin + nTimeStampCount) > MICROPROFILE_D3D12_MAX_QUERIES ? MICROPROFILE_D3D12_MAX_QUERIES - nTimeStampBegin : nTimeStampCount, nPending, nTimestampOffset);10171MicroProfileGpuFetchRange(0, (nTimeStampBegin + nTimeStampCount) - MICROPROFILE_D3D12_MAX_QUERIES, nPending, nTimestampOffset);10172}10173{10174uint32_t nTimeStampBegin = pGPU->Frames[nInternal].nTimeStampBeginCopyQueue;10175uint32_t nTimeStampCount = pGPU->Frames[nInternal].nTimeStampCountCopyQueue;10176MicroProfileGpuFetchRangeCopy(10177nTimeStampBegin, (nTimeStampBegin + nTimeStampCount) > MICROPROFILE_D3D12_MAX_QUERIES ? MICROPROFILE_D3D12_MAX_QUERIES - nTimeStampBegin : nTimeStampCount, nPending, nTimestampOffset);10178MicroProfileGpuFetchRangeCopy(0, (nTimeStampBegin + nTimeStampCount) - MICROPROFILE_D3D12_MAX_QUERIES, nPending, nTimestampOffset);10179}10180nPending = ++pGPU->nPendingFrame;10181MP_ASSERT(pGPU->nFrame > nPending);10182}10183}1018410185uint64_t MicroProfileGpuGetTimeStampD3D12(uint32_t nIndex)10186{10187MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10188if(!pGPU)10189return 0;1019010191uint32_t nFrame = nIndex >> 16;10192bool IsCopy = (nFrame & 0x8000) != 0;10193nFrame &= 0x7fff;10194uint32_t nQueryIndex = nIndex & 0xffff;10195uint32_t lala = IsCopy ? pGPU->nQueryFramesCopy[nQueryIndex] : pGPU->nQueryFrames[nQueryIndex];10196// uprintf("read TS [%d <- %lld]\n", nQueryIndex, pGPU->nResults[nQueryIndex]);10197MP_ASSERT(nIndex == 0 || (0x7fff & lala) == nFrame);10198uint64_t r = IsCopy ? pGPU->nResultsCopy[nQueryIndex] : pGPU->nResults[nQueryIndex];10199if(r == 0x7fffffffffffffff)10200{10201MP_BREAK();10202}10203return r;10204}1020510206uint64_t MicroProfileTicksPerSecondGpuD3D12()10207{10208MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10209if(!pGPU)10210return 1;10211return pGPU->nFrequency;10212}1021310214uint32_t MicroProfileGpuFlipD3D12(void* pContext)10215{10216MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10217if(!pGPU)10218return 0;10219uint32_t nNode = pGPU->nCurrentNode;10220uint32_t nFrameIndex = pGPU->nFrame % MICROPROFILE_D3D_INTERNAL_DELAY;10221uint32_t nCount = 0, nStart = 0;10222uint32_t nCountCopyQueue = 0, nStartCopyQueue = 0;1022310224ID3D12CommandAllocator* pCommandAllocator = pGPU->Frames[nFrameIndex].pCommandAllocator;10225ID3D12CommandAllocator* pCommandAllocatorCopy = pGPU->Frames[nFrameIndex].pCommandAllocatorCopy;10226pCommandAllocator->Reset();10227pCommandAllocatorCopy->Reset();10228ID3D12GraphicsCommandList* pCommandList = pGPU->Frames[nFrameIndex].pCommandList[nNode];1022910230pCommandList->Reset(pCommandAllocator, nullptr);1023110232ID3D12GraphicsCommandList* pCommandListCopy = nullptr;1023310234uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pCommandList);1023510236{10237nCount = pGPU->nFrameCountTimeStamps.exchange(0);10238nStart = pGPU->nFrameStartTimeStamps;10239pGPU->nFrameStartTimeStamps = (pGPU->nFrameStartTimeStamps + nCount) % MICROPROFILE_D3D12_MAX_QUERIES;10240uint32_t nEnd = MicroProfileMin(nStart + nCount, (uint32_t)MICROPROFILE_D3D12_MAX_QUERIES);10241MP_ASSERT(nStart != nEnd);10242uint32_t nSize = nEnd - nStart;10243pCommandList->ResolveQueryData(pGPU->NodeState[nNode].pHeap, D3D12_QUERY_TYPE_TIMESTAMP, nStart, nEnd - nStart, pGPU->pBuffer, nStart * sizeof(int64_t));10244if(nStart + nCount > MICROPROFILE_D3D12_MAX_QUERIES)10245{10246pCommandList->ResolveQueryData(pGPU->NodeState[nNode].pHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, nEnd + nStart - MICROPROFILE_D3D12_MAX_QUERIES, pGPU->pBuffer, 0);10247}10248pCommandList->Close();10249}1025010251{10252pCommandListCopy = pGPU->Frames[nFrameIndex].pCommandListCopy[nNode];10253pCommandListCopy->Reset(pCommandAllocatorCopy, nullptr);1025410255nCountCopyQueue = pGPU->nFrameCountCopyQueueTimeStamps.exchange(0);10256nStartCopyQueue = pGPU->nFrameStartCopyQueueTimeStamps;10257pGPU->nFrameStartCopyQueueTimeStamps = (nStartCopyQueue + nCountCopyQueue) % MICROPROFILE_D3D12_MAX_QUERIES;10258uint32_t nEnd = MicroProfileMin(nStartCopyQueue + nCountCopyQueue, (uint32_t)MICROPROFILE_D3D12_MAX_QUERIES);10259if(nStartCopyQueue != nEnd)10260{10261uint32_t nSize = nEnd - nStartCopyQueue;10262pCommandListCopy->ResolveQueryData(10263pGPU->NodeState[nNode].pCopyQueueHeap, D3D12_QUERY_TYPE_TIMESTAMP, nStartCopyQueue, nEnd - nStartCopyQueue, pGPU->pBufferCopy, nStartCopyQueue * sizeof(int64_t));10264if(nStartCopyQueue + nCountCopyQueue > MICROPROFILE_D3D12_MAX_QUERIES)10265{10266pCommandListCopy->ResolveQueryData(pGPU->NodeState[nNode].pCopyQueueHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, nEnd + nStartCopyQueue - MICROPROFILE_D3D12_MAX_QUERIES, pGPU->pBufferCopy, 0);10267}10268}10269pCommandListCopy->Close();10270}1027110272if(pCommandList)10273{10274ID3D12CommandList* pList = pCommandList;10275pGPU->NodeState[nNode].pCommandQueue->ExecuteCommandLists(1, &pList);10276}10277if(pCommandListCopy)10278{10279ID3D12CommandList* pList = pCommandListCopy;10280pGPU->NodeState[nNode].pCommandQueueCopy->ExecuteCommandLists(1, &pList);10281}10282pGPU->NodeState[nNode].pCommandQueue->Signal(pGPU->NodeState[nNode].pFence, pGPU->nFrame);10283pGPU->NodeState[nNode].pCommandQueueCopy->Signal(pGPU->NodeState[nNode].pFenceCopy, pGPU->nFrame);10284pGPU->Frames[nFrameIndex].nTimeStampBegin = nStart;10285pGPU->Frames[nFrameIndex].nTimeStampCount = nCount;10286pGPU->Frames[nFrameIndex].nTimeStampBeginCopyQueue = nStartCopyQueue;10287pGPU->Frames[nFrameIndex].nTimeStampCountCopyQueue = nCountCopyQueue;1028810289pGPU->Frames[nFrameIndex].nNode = nNode;1029010291pGPU->nFrame++;10292// fetch from earlier frames1029310294MicroProfileGpuFetchResultsD3D12(pGPU->nFrame - MICROPROFILE_GPU_FRAME_DELAY);10295return nFrameTimeStamp;10296}1029710298void MicroProfileGpuInitD3D12(void* pDevice_, uint32_t nNodeCount, void** pCommandQueues_, void** pCommandQueuesCopy_)10299{10300MicroProfileGpuTimerStateD3D12* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateD3D12);10301memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateD3D12));1030210303MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_D3D12,10304pGPU,10305MicroProfileGpuInsertTimeStampD3D12,10306MicroProfileGpuGetTimeStampD3D12,10307MicroProfileTicksPerSecondGpuD3D12,10308MicroProfileGetGpuTickReferenceD3D12,10309MicroProfileGpuFlipD3D12,10310MicroProfileGpuShutdownD3D12);1031110312ID3D12Device* pDevice = (ID3D12Device*)pDevice_;1031310314pGPU->pDevice = pDevice;10315pGPU->nNodeCount = nNodeCount;10316MP_ASSERT(pGPU->nNodeCount <= MICROPROFILE_D3D_MAX_NODE_COUNT);1031710318for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode)10319{10320pGPU->NodeState[nNode].pCommandQueue = (ID3D12CommandQueue*)pCommandQueues_[nNode];10321pGPU->NodeState[nNode].pCommandQueueCopy = (ID3D12CommandQueue*)pCommandQueuesCopy_[nNode];10322if(nNode == 0)10323{10324pGPU->NodeState[nNode].pCommandQueue->GetTimestampFrequency((uint64_t*)&(pGPU->nFrequency));10325MP_ASSERT(pGPU->nFrequency);10326}10327else10328{10329// Don't support GPUs with different timer frequencies for now10330int64_t nFrequency;10331pGPU->NodeState[nNode].pCommandQueue->GetTimestampFrequency((uint64_t*)&nFrequency);10332MP_ASSERT(nFrequency == pGPU->nFrequency);10333}1033410335D3D12_QUERY_HEAP_DESC QHDesc;10336QHDesc.Count = MICROPROFILE_D3D12_MAX_QUERIES;10337QHDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;10338QHDesc.NodeMask = MP_NODE_MASK_ONE(nNode);10339HRESULT hr = pDevice->CreateQueryHeap(&QHDesc, IID_PPV_ARGS(&pGPU->NodeState[nNode].pHeap));10340MP_ASSERT(hr == S_OK);10341QHDesc.Type = D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP;10342hr = pDevice->CreateQueryHeap(&QHDesc, IID_PPV_ARGS(&pGPU->NodeState[nNode].pCopyQueueHeap));10343MP_ASSERT(hr == S_OK);1034410345pDevice->CreateFence(pGPU->nPendingFrame, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pGPU->NodeState[nNode].pFence));10346pDevice->CreateFence(pGPU->nPendingFrame, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pGPU->NodeState[nNode].pFenceCopy));10347}1034810349HRESULT hr;10350D3D12_HEAP_PROPERTIES HeapProperties;10351HeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;10352HeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;10353HeapProperties.CreationNodeMask = 0;10354HeapProperties.VisibleNodeMask = MP_NODE_MASK_ALL(pGPU->nNodeCount);10355HeapProperties.Type = D3D12_HEAP_TYPE_READBACK;1035610357const size_t nResourceSize = MICROPROFILE_D3D12_MAX_QUERIES * 8;1035810359D3D12_RESOURCE_DESC ResourceDesc;10360ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;10361ResourceDesc.Alignment = 0;10362ResourceDesc.Width = nResourceSize;10363ResourceDesc.Height = 1;10364ResourceDesc.DepthOrArraySize = 1;10365ResourceDesc.MipLevels = 1;10366ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;10367ResourceDesc.SampleDesc.Count = 1;10368ResourceDesc.SampleDesc.Quality = 0;10369ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;10370ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;1037110372hr = pDevice->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pGPU->pBuffer));10373MP_ASSERT(hr == S_OK);10374hr = pDevice->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pGPU->pBufferCopy));10375MP_ASSERT(hr == S_OK);1037610377pGPU->nFrame = 0;10378pGPU->nPendingFrame = 0;1037910380for(MicroProfileFrameD3D12& Frame : pGPU->Frames)10381{10382hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&Frame.pCommandAllocator));10383MP_ASSERT(hr == S_OK);10384hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&Frame.pCommandAllocatorCopy));10385MP_ASSERT(hr == S_OK);10386for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode)10387{10388hr = pDevice->CreateCommandList(MP_NODE_MASK_ONE(nNode), D3D12_COMMAND_LIST_TYPE_DIRECT, Frame.pCommandAllocator, nullptr, IID_PPV_ARGS(&Frame.pCommandList[nNode]));10389MP_ASSERT(hr == S_OK);10390hr = Frame.pCommandList[nNode]->Close();10391MP_ASSERT(hr == S_OK);10392hr = pDevice->CreateCommandList(MP_NODE_MASK_ONE(nNode), D3D12_COMMAND_LIST_TYPE_COPY, Frame.pCommandAllocatorCopy, nullptr, IID_PPV_ARGS(&Frame.pCommandListCopy[nNode]));10393MP_ASSERT(hr == S_OK);10394hr = Frame.pCommandListCopy[nNode]->Close();10395MP_ASSERT(hr == S_OK);10396}10397}10398}1039910400void MicroProfileGpuShutdownD3D12()10401{10402MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10403if(!pGPU)10404return;10405for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode)10406{10407MicroProfileGpuWaitFenceD3D12(nNode, pGPU->nFrame - 1);10408}10409for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode)10410{10411pGPU->NodeState[nNode].pHeap->Release();10412pGPU->NodeState[nNode].pCopyQueueHeap->Release();10413pGPU->NodeState[nNode].pFence->Release();10414pGPU->NodeState[nNode].pFenceCopy->Release();10415}10416pGPU->pBuffer->Release();10417pGPU->pBufferCopy->Release();10418for(MicroProfileFrameD3D12& Frame : pGPU->Frames)10419{10420Frame.pCommandAllocator->Release();10421Frame.pCommandAllocatorCopy->Release();10422for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode)10423{10424Frame.pCommandList[nNode]->Release();10425Frame.pCommandListCopy[nNode]->Release();10426}10427}10428}10429void MicroProfileSetCurrentNodeD3D12(uint32_t nNode)10430{10431MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10432pGPU->nCurrentNode = nNode;10433}1043410435int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu)10436{10437MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12();10438if(!pGPU)10439{10440*pOutCPU = 1;10441*pOutGpu = 1;10442return 1;10443}1044410445HRESULT hr = pGPU->NodeState[0].pCommandQueue->GetClockCalibration((uint64_t*)pOutGpu, (uint64_t*)pOutCPU);10446MP_ASSERT(hr == S_OK);10447return 1;10448}1044910450MicroProfileGpuTimerStateD3D12* MicroProfileGetGpuTimerStateD3D12()10451{10452if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_D3D12)10453return (MicroProfileGpuTimerStateD3D12*)S.pGPU;10454return nullptr;10455}1045610457#endif1045810459#if MICROPROFILE_GPU_TIMERS_VULKAN1046010461//:'######:::'########::'##::::'##::::'##::::'##:'##::::'##:'##:::::::'##:::'##::::'###::::'##::: ##:10462//'##... ##:: ##.... ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##::'##::::'## ##::: ###:: ##:10463// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##:'##::::'##:. ##:: ####: ##:10464// ##::'####: ########:: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: #####::::'##:::. ##: ## ## ##:10465// ##::: ##:: ##.....::: ##:::: ##::::. ##:: ##:: ##:::: ##: ##::::::: ##. ##::: #########: ##. ####:10466// ##::: ##:: ##:::::::: ##:::: ##:::::. ## ##::: ##:::: ##: ##::::::: ##:. ##:: ##.... ##: ##:. ###:10467//. ######::: ##::::::::. #######:::::::. ###::::. #######:: ########: ##::. ##: ##:::: ##: ##::. ##:10468//:......::::..::::::::::.......:::::::::...::::::.......:::........::..::::..::..:::::..::..::::..::1046910470#ifndef MICROPROFILE_VULKAN_MAX_QUERIES10471#define MICROPROFILE_VULKAN_MAX_QUERIES (32 << 10)10472#endif1047310474#define MICROPROFILE_VULKAN_MAX_NODE_COUNT 410475#define MICROPROFILE_VULKAN_INTERNAL_DELAY 81047610477#include <vulkan/vulkan.h>10478struct MicroProfileGpuFrameVulkan10479{10480uint32_t nBegin;10481uint32_t nCount;10482uint32_t nNode;10483VkCommandBuffer CommandBuffer[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10484VkFence Fences[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10485};10486struct MicroProfileGpuTimerStateVulkan : public MicroProfileGpuTimerState10487{10488VkDevice Devices[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10489VkPhysicalDevice PhysicalDevices[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10490VkQueue Queues[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10491VkQueryPool QueryPool[MICROPROFILE_VULKAN_MAX_NODE_COUNT];10492VkCommandPool CommandPool[MICROPROFILE_VULKAN_MAX_NODE_COUNT];1049310494uint32_t nNodeCount;10495uint32_t nCurrentNode;10496uint64_t nFrame;10497uint64_t nPendingFrame;10498uint32_t nFrameStart;10499std::atomic<uint32_t> nFrameCount;10500int64_t nFrequency;1050110502uint16_t nQueryFrames[MICROPROFILE_VULKAN_MAX_QUERIES];10503int64_t nResults[MICROPROFILE_VULKAN_MAX_QUERIES];1050410505MicroProfileGpuFrameVulkan Frames[MICROPROFILE_VULKAN_INTERNAL_DELAY];10506};1050710508MicroProfileGpuTimerStateVulkan* MicroProfileGetGpuTimerStateVulkan()10509{10510if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_Vulkan)10511return (MicroProfileGpuTimerStateVulkan*)S.pGPU;10512return nullptr;10513}1051410515uint32_t MicroProfileGpuInsertTimeStampVulkan(void* pContext)10516{10517MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10518if(!pGPU)10519return 0;10520VkCommandBuffer CB = (VkCommandBuffer)pContext;10521uint32_t nNode = pGPU->nCurrentNode;10522uint32_t nFrame = pGPU->nFrame;10523uint32_t nQueryIndex = (pGPU->nFrameCount.fetch_add(1) + pGPU->nFrameStart) % MICROPROFILE_VULKAN_MAX_QUERIES;10524vkCmdWriteTimestamp(CB, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, pGPU->QueryPool[nNode], nQueryIndex);10525MP_ASSERT(nQueryIndex <= 0xffff);10526// uprintf("insert timestamp %d :: %d ... ctx %p\n", nQueryIndex, nFrame, pContext);10527return ((nFrame << 16) & 0xffff0000) | (nQueryIndex);10528}1052910530void MicroProfileGpuFetchRangeVulkan(VkCommandBuffer CommandBuffer, uint32_t nNode, uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset)10531{10532if(nCount <= 0)10533return;10534MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10535if(!pGPU)10536return;1053710538vkGetQueryPoolResults(pGPU->Devices[nNode], pGPU->QueryPool[nNode], nBegin, nCount, 8 * nCount, &pGPU->nResults[nBegin], 8, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_PARTIAL_BIT);10539vkCmdResetQueryPool(CommandBuffer, pGPU->QueryPool[nNode], nBegin, nCount);10540for(int i = 0; i < nCount; ++i)10541{10542pGPU->nQueryFrames[i + nBegin] = nFrame;10543}10544}10545void MicroProfileGpuWaitFenceVulkan(uint32_t nNode, uint64_t nFrame)10546{10547MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10548if(!pGPU)10549return;1055010551int r;10552int c = 0;10553do10554{10555MICROPROFILE_SCOPEI("Microprofile", "gpu-wait", MP_GREEN4);10556r = vkWaitForFences(pGPU->Devices[nNode], 1, &pGPU->Frames[nFrame].Fences[nNode], 1, 1000 * 30);10557#if 010558if(c++ > 1000 && (c%100) == 0)10559{10560uprintf("waiting really long time for fence\n");10561OutputDebugString("waiting really long time for fence\n");10562}10563#endif10564} while(r != VK_SUCCESS);10565}1056610567void MicroProfileGpuFetchResultsVulkan(VkCommandBuffer Buffer, uint64_t nFrame)10568{10569MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10570if(!pGPU)10571return;1057210573uint64_t nPending = pGPU->nPendingFrame;10574// while(nPending <= nFrame)10575// while(0 <= nFrame - nPending)10576while(0 <= (int64_t)(nFrame - nPending))10577{10578uint32_t nInternal = nPending % MICROPROFILE_VULKAN_INTERNAL_DELAY;10579uint32_t nNode = pGPU->Frames[nInternal].nNode;10580MicroProfileGpuWaitFenceVulkan(nNode, nInternal);10581int64_t nTimestampOffset = 0;1058210583if(nNode != 0)10584{10585MP_ASSERT(0 && "NOT IMPLEMENTED");10586// note: timestamp adjustment not implemented.10587}1058810589uint32_t nBegin = pGPU->Frames[nInternal].nBegin;10590uint32_t nCount = pGPU->Frames[nInternal].nCount;10591MicroProfileGpuFetchRangeVulkan(Buffer, nNode, nBegin, (nBegin + nCount) > MICROPROFILE_VULKAN_MAX_QUERIES ? MICROPROFILE_VULKAN_MAX_QUERIES - nBegin : nCount, nPending, nTimestampOffset);10592MicroProfileGpuFetchRangeVulkan(Buffer, nNode, 0, (nBegin + nCount) - MICROPROFILE_VULKAN_MAX_QUERIES, nPending, nTimestampOffset);1059310594nPending = ++pGPU->nPendingFrame;10595MP_ASSERT(pGPU->nFrame > nPending);10596}10597}1059810599uint64_t MicroProfileGpuGetTimeStampVulkan(uint32_t nIndex)10600{10601if(nIndex == (uint32_t)-1)10602{10603return 0;10604}1060510606MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10607if(!pGPU)10608return 0;1060910610uint32_t nFrame = nIndex >> 16;10611uint32_t nQueryIndex = nIndex & 0xffff;10612uint32_t lala = pGPU->nQueryFrames[nQueryIndex];10613MP_ASSERT((0xffff & lala) == nFrame);10614// uprintf("read TS [%d <- %lld]\n", nQueryIndex, pGPU->nResults[nQueryIndex]);10615return pGPU->nResults[nQueryIndex];10616}1061710618uint64_t MicroProfileTicksPerSecondGpuVulkan()10619{10620MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10621if(!pGPU)10622return 1;10623return pGPU->nFrequency;10624}1062510626uint32_t MicroProfileGpuFlipVulkan(void* pContext)10627{10628MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10629if(!pGPU)10630return 0;1063110632uint32_t nNode = pGPU->nCurrentNode;10633uint32_t nFrameIndex = pGPU->nFrame % MICROPROFILE_VULKAN_INTERNAL_DELAY;10634uint32_t nCount = 0, nStart = 0;1063510636VkCommandBuffer CommandBuffer = pGPU->Frames[nFrameIndex].CommandBuffer[nNode];10637auto& F = pGPU->Frames[nFrameIndex];10638VkFence Fence = F.Fences[nNode];10639VkDevice Device = pGPU->Devices[nNode];10640VkQueue Queue = pGPU->Queues[nNode];1064110642vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1);10643uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pContext);10644vkResetCommandBuffer(F.CommandBuffer[nNode], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);1064510646VkCommandBufferBeginInfo CBI;10647CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;10648CBI.pNext = 0;10649CBI.pInheritanceInfo = 0;10650CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;10651vkBeginCommandBuffer(F.CommandBuffer[nNode], &CBI);10652vkResetFences(Device, 1, &Fence);1065310654nCount = pGPU->nFrameCount.exchange(0);10655nStart = pGPU->nFrameStart;10656pGPU->nFrameStart = (pGPU->nFrameStart + nCount) % MICROPROFILE_VULKAN_MAX_QUERIES;10657uint32_t nEnd = MicroProfileMin(nStart + nCount, (uint32_t)MICROPROFILE_VULKAN_MAX_QUERIES);10658MP_ASSERT(nStart != nEnd);10659uint32_t nSize = nEnd - nStart;1066010661pGPU->Frames[nFrameIndex].nBegin = nStart;10662pGPU->Frames[nFrameIndex].nCount = nCount;10663pGPU->Frames[nFrameIndex].nNode = nNode;10664pGPU->nFrame++;10665////fetch from earlier frames10666MicroProfileGpuFetchResultsVulkan(CommandBuffer, pGPU->nFrame - MICROPROFILE_GPU_FRAME_DELAY);1066710668vkEndCommandBuffer(F.CommandBuffer[nNode]);10669VkSubmitInfo SubmitInfo = {};10670SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;10671SubmitInfo.pNext = nullptr;10672SubmitInfo.waitSemaphoreCount = 0;10673SubmitInfo.pWaitSemaphores = nullptr;10674SubmitInfo.commandBufferCount = 1;10675SubmitInfo.pCommandBuffers = &CommandBuffer;10676SubmitInfo.signalSemaphoreCount = 0;10677SubmitInfo.pSignalSemaphores = nullptr;10678vkQueueSubmit(Queue, 1, &SubmitInfo, Fence);10679return nFrameTimeStamp;10680}1068110682void MicroProfileGpuInitVulkan(VkDevice* pDevices, VkPhysicalDevice* pPhysicalDevices, VkQueue* pQueues, uint32_t* QueueFamily, uint32_t nNodeCount)10683{10684MicroProfileGpuTimerStateVulkan* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateVulkan);10685memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateVulkan));10686MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_Vulkan,10687pGPU,10688MicroProfileGpuInsertTimeStampVulkan,10689MicroProfileGpuGetTimeStampVulkan,10690MicroProfileTicksPerSecondGpuVulkan,10691MicroProfileGetGpuTickReferenceVulkan,10692MicroProfileGpuFlipVulkan,10693MicroProfileGpuShutdownVulkan);1069410695pGPU->nNodeCount = nNodeCount;1069610697VkQueryPoolCreateInfo Q;10698Q.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;10699Q.pNext = 0;10700Q.flags = 0;10701Q.queryType = VK_QUERY_TYPE_TIMESTAMP;10702Q.queryCount = MICROPROFILE_VULKAN_MAX_QUERIES + 1;1070310704VkCommandPoolCreateInfo CreateInfo;10705CreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;10706CreateInfo.pNext = 0;10707CreateInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;1070810709VkResult r;10710for(uint32_t i = 0; i < nNodeCount; ++i)10711{10712pGPU->Devices[i] = pDevices[i];10713pGPU->PhysicalDevices[i] = pPhysicalDevices[i];10714pGPU->Queues[i] = pQueues[i];10715r = vkCreateQueryPool(pGPU->Devices[i], &Q, 0, &pGPU->QueryPool[i]);10716MP_ASSERT(r == VK_SUCCESS);1071710718CreateInfo.queueFamilyIndex = QueueFamily[i];10719r = vkCreateCommandPool(pGPU->Devices[i], &CreateInfo, 0, &pGPU->CommandPool[i]);10720MP_ASSERT(r == VK_SUCCESS);1072110722for(uint32_t j = 0; j < MICROPROFILE_VULKAN_INTERNAL_DELAY; ++j)10723{10724auto& F = pGPU->Frames[j];10725VkCommandBufferAllocateInfo AllocInfo;10726AllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;10727AllocInfo.pNext = 0;10728AllocInfo.commandBufferCount = 1;10729AllocInfo.commandPool = pGPU->CommandPool[i];10730AllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;10731r = vkAllocateCommandBuffers(pGPU->Devices[i], &AllocInfo, &F.CommandBuffer[i]);10732MP_ASSERT(r == VK_SUCCESS);1073310734VkFenceCreateInfo FCI;10735FCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;10736FCI.pNext = 0;10737FCI.flags = j == 0 ? 0 : VK_FENCE_CREATE_SIGNALED_BIT;10738r = vkCreateFence(pGPU->Devices[i], &FCI, 0, &F.Fences[i]);10739MP_ASSERT(r == VK_SUCCESS);10740if(j == 0)10741{10742VkCommandBufferBeginInfo CBI;10743CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;10744CBI.pNext = 0;10745CBI.pInheritanceInfo = 0;10746CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;10747vkBeginCommandBuffer(F.CommandBuffer[i], &CBI);10748vkCmdResetQueryPool(F.CommandBuffer[i], pGPU->QueryPool[i], 0, MICROPROFILE_VULKAN_MAX_QUERIES + 1);1074910750vkEndCommandBuffer(F.CommandBuffer[i]);10751VkSubmitInfo SubmitInfo = {};10752SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;10753SubmitInfo.pNext = nullptr;10754SubmitInfo.waitSemaphoreCount = 0;10755SubmitInfo.pWaitSemaphores = nullptr;10756SubmitInfo.commandBufferCount = 1;10757SubmitInfo.pCommandBuffers = &F.CommandBuffer[i];10758SubmitInfo.signalSemaphoreCount = 0;10759SubmitInfo.pSignalSemaphores = nullptr;10760vkQueueSubmit(pQueues[i], 1, &SubmitInfo, F.Fences[i]);10761vkWaitForFences(pGPU->Devices[i], 1, &F.Fences[i], 1, (uint64_t)-1);10762vkResetCommandBuffer(F.CommandBuffer[i], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);10763}10764}10765}1076610767VkPhysicalDeviceProperties Properties;10768vkGetPhysicalDeviceProperties(pPhysicalDevices[0], &Properties);10769pGPU->nFrequency = 1000000000ll / Properties.limits.timestampPeriod;10770}1077110772void MicroProfileGpuShutdownVulkan()10773{10774// this is clearly leaking ..10775}10776void MicroProfileSetCurrentNodeVulkan(uint32_t nNode)10777{1077810779MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10780if(!pGPU)10781return;10782pGPU->nCurrentNode = nNode;10783}1078410785int MicroProfileGetGpuTickReferenceVulkan(int64_t* pOutCPU, int64_t* pOutGpu)10786{10787MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan();10788if(!pGPU)10789return 0;1079010791auto& F = pGPU->Frames[pGPU->nFrame % MICROPROFILE_VULKAN_INTERNAL_DELAY];10792uint32_t nGpu = pGPU->nCurrentNode;1079310794VkCommandBufferBeginInfo CBI;10795CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;10796CBI.pNext = 0;10797CBI.pInheritanceInfo = 0;10798CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;10799VkCommandBuffer CB = F.CommandBuffer[nGpu];10800VkDevice Device = pGPU->Devices[nGpu];10801VkFence Fence = F.Fences[nGpu];1080210803vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1);10804vkResetFences(Device, 1, &Fence);10805vkResetCommandBuffer(CB, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);10806vkBeginCommandBuffer(CB, &CBI);10807vkCmdResetQueryPool(CB, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES, 1);10808vkCmdWriteTimestamp(CB, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES);10809vkEndCommandBuffer(CB);10810VkSubmitInfo SubmitInfo = {};10811SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;10812SubmitInfo.pNext = nullptr;10813SubmitInfo.waitSemaphoreCount = 0;10814SubmitInfo.pWaitSemaphores = nullptr;10815SubmitInfo.commandBufferCount = 1;10816SubmitInfo.pCommandBuffers = &CB;10817SubmitInfo.signalSemaphoreCount = 0;10818SubmitInfo.pSignalSemaphores = nullptr;10819vkQueueSubmit(pGPU->Queues[nGpu], 1, &SubmitInfo, Fence);10820vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1);10821*pOutGpu = 0;10822vkGetQueryPoolResults(Device, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES, 1, 8, pOutGpu, 8, VK_QUERY_RESULT_64_BIT);10823*pOutCPU = MP_TICK();10824return 1;10825}10826#endif1082710828#if MICROPROFILE_GPU_TIMERS_GL10829//:'######:::'########::'##::::'##:::::'######:::'##:::::::10830//'##... ##:: ##.... ##: ##:::: ##::::'##... ##:: ##:::::::10831// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::..::: ##:::::::10832// ##::'####: ########:: ##:::: ##:::: ##::'####: ##:::::::10833// ##::: ##:: ##.....::: ##:::: ##:::: ##::: ##:: ##:::::::10834// ##::: ##:: ##:::::::: ##:::: ##:::: ##::: ##:: ##:::::::10835//. ######::: ##::::::::. #######:::::. ######::: ########:10836//:......::::..::::::::::.......:::::::......::::........::1083710838void MicroProfileGpuInitGL()10839{10840MicroProfileGpuTimerStateGL* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateGL);10841memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateGL));10842MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_GL,10843pGPU,10844MicroProfileGpuInsertTimeStampGL,10845MicroProfileGpuGetTimeStampGL,10846MicroProfileTicksPerSecondGpuGL,10847MicroProfileGetGpuTickReferenceGL,10848MicroProfileGpuFlipGL,10849MicroProfileGpuShutdownGL);1085010851pGPU->GLTimerPos = 0;10852glGenQueries(MICROPROFILE_GL_MAX_QUERIES, &pGPU->GLTimers[0]);10853}1085410855uint32_t MicroProfileGpuInsertTimeStampGL(void* pContext)10856{10857MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL();10858if(!pGPU)10859return 0;1086010861uint32_t nIndex = (pGPU->GLTimerPos + 1) % MICROPROFILE_GL_MAX_QUERIES;10862glQueryCounter(pGPU->GLTimers[nIndex], GL_TIMESTAMP);10863pGPU->GLTimerPos = nIndex;10864return nIndex;10865}10866uint64_t MicroProfileGpuGetTimeStampGL(uint32_t nKey)10867{10868MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL();10869if(!pGPU)10870return 0;1087110872uint64_t result;10873glGetQueryObjectui64v(pGPU->GLTimers[nKey], GL_QUERY_RESULT, &result);10874return result;10875}1087610877uint64_t MicroProfileTicksPerSecondGpuGL()10878{10879return 1000000000ll;10880}1088110882int MicroProfileGetGpuTickReferenceGL(int64_t* pOutCpu, int64_t* pOutGpu)10883{10884MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL();10885if(!pGPU)10886return 0;1088710888int64_t nGpuTimeStamp;10889glGetInteger64v(GL_TIMESTAMP, &nGpuTimeStamp);10890if(nGpuTimeStamp)10891{10892*pOutCpu = MP_TICK();10893*pOutGpu = nGpuTimeStamp;10894#if 0 // debug test if timestamp diverges10895static int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();10896static int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();10897static int64_t nGpuStart = 0;10898static int64_t nCpuStart = 0;10899if(!nCpuStart)10900{10901nCpuStart = *pOutCpu;10902nGpuStart = *pOutGpu;10903}10904static int nCountDown = 100;10905if(0 == nCountDown--)10906{10907int64_t nCurCpu = *pOutCpu;10908int64_t nCurGpu = *pOutGpu;10909double fDistanceCpu = (nCurCpu - nCpuStart) / (double)nTicksPerSecondCpu;10910double fDistanceGpu = (nCurGpu - nGpuStart) / (double)nTicksPerSecondGpu;1091110912char buf[254];10913snprintf(buf, sizeof(buf)-1,"Distance %f %f diff %f\n", fDistanceCpu, fDistanceGpu, fDistanceCpu-fDistanceGpu);10914OutputDebugString(buf);10915nCountDown = 100;10916}10917#endif10918return 1;10919}10920return 0;10921}10922uint32_t MicroProfileGpuFlipGL(void* pContext)10923{10924return MicroProfileGpuInsertTimeStampGL(pContext);10925}1092610927void MicroProfileGpuShutdownGL()10928{10929MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL();10930if(!pGPU)10931return;1093210933glDeleteQueries(MICROPROFILE_GL_MAX_QUERIES, &pGPU->GLTimers[0]);10934}1093510936MicroProfileGpuTimerStateGL* MicroProfileGetGpuTimerStateGL()10937{10938if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_GL)10939return (MicroProfileGpuTimerStateGL*)S.pGPU;10940return nullptr;10941}10942#endif1094310944uint32_t MicroProfileStringHash(const char* pString) // note matching: code in javascript: microprofilelive.html: function StringHash(s)10945{10946uint32_t h = 0xfeedba3e;10947char c;10948while(0 != (c = *pString++))10949{10950h = c + ((h << 5) - h);10951}10952return h;10953}1095410955const char* MicroProfileStrDup(const char* pStr)10956{10957size_t len = strlen(pStr) + 1;10958char* pOut = (char*)MP_ALLOC(len, 8);10959memcpy(pOut, pStr, len);10960return pOut;10961}1096210963uint32_t MicroProfileColorFromString(const char* pString) // note matching code/constants in javascript: microprofilelive.html: function StringToColor(s)10964{10965// var h = StringHash(s);10966// var cidx = h % 360;10967// return "hsl(" + cidx + ",50%, 70%)"; //note: matching code constants in microprofile.cpp: MicroProfileColorFromString1096810969float h = MicroProfileStringHash(pString) % 360;10970float s = 0.5f;10971float l = 0.7f;10972// from https://www.rapidtables.com/convert/color/hsl-to-rgb.html10973float c = (1 - fabsf(2 * l - 1)) * s;10974float x = c * (1 - fabsf(fmodf(h / 60, 2.f) - 1));10975float m = l - c / 2.f;10976float r = 0.f, g = 0.f, b = 0.f;10977if(h < 60)10978{10979r = c;10980g = x;10981}10982else if(h < 120.f)10983{10984r = x;10985g = c;10986}10987else if(h < 180.f)10988{10989g = c;10990b = x;10991}10992else if(h < 240.f)10993{10994g = x;10995b = c;10996}10997else if(h < 300.f)10998{10999r = x;11000b = c;11001}11002else11003{11004r = c;11005b = x;11006}11007r += m;11008g += m;11009b += m;1101011011r *= 255.f;11012g *= 255.f;11013b *= 255.f;1101411015uint32_t R = MicroProfileMin(0xffu, (uint32_t)r);11016uint32_t G = MicroProfileMin(0xffu, (uint32_t)g);11017uint32_t B = MicroProfileMin(0xffu, (uint32_t)b);1101811019return (R << 16) | (G << 8) | B;11020}1102111022#if MICROPROFILE_DYNAMIC_INSTRUMENT11023// '##::::'##::'#######:::'#######::'##:::'##:::::'######::'##::::'##::::'###::::'########::'########:'########::11024// ##:::: ##:'##.... ##:'##.... ##: ##::'##:::::'##... ##: ##:::: ##:::'## ##::: ##.... ##: ##.....:: ##.... ##:11025// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::..:: ##:::: ##::'##:. ##:: ##:::: ##: ##::::::: ##:::: ##:11026// #########: ##:::: ##: ##:::: ##: #####:::::::. ######:: #########:'##:::. ##: ########:: ######::: ##:::: ##:11027// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::::..... ##: ##.... ##: #########: ##.. ##::: ##...:::: ##:::: ##:11028// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##:::::'##::: ##: ##:::: ##: ##.... ##: ##::. ##:: ##::::::: ##:::: ##:11029// ##:::: ##:. #######::. #######:: ##::. ##::::. ######:: ##:::: ##: ##:::: ##: ##:::. ##: ########: ########::11030// ..:::::..:::.......::::.......:::..::::..::::::......:::..:::::..::..:::::..::..:::::..::........::........:::1103111032#include <distorm.h>11033#include <mnemonics.h>1103411035#if MICROPROFILE_BREAK_ON_PATCH_FAIL11036#define BREAK_ON_PATCH_FAIL() MP_BREAK()11037#else11038#define BREAK_ON_PATCH_FAIL() \11039do \11040{ \11041} while(0)11042#endif1104311044void* MicroProfileX64FollowJump(void* pSrc);11045bool MicroProfileCopyInstructionBytes(char* pDest,11046void* pSrc,11047const int nLimit,11048const int nMaxSize,11049char* pTrunk,11050intptr_t nTrunkSize,11051uint32_t nUsableJumpRegs,11052int* nBytesDest,11053int* nBytesSrc,11054uint32_t* pRegsWritten,11055uint32_t* nRetSafe);11056bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError);11057template <typename Callback>11058void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules);1105911060bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size);11061bool MicroProfilePatchBeginSuspend();11062void MicroProfilePatchEndSuspend();11063bool MicroProfilePatchHasSuspendedThread(intptr_t Begin, intptr_t End);1106411065#if 111066#define STRING_MATCH_SIZE 6411067typedef uint64_t uint_string_match;11068#else11069#define STRING_MATCH_SIZE 3211070typedef uint32_t uint_string_match;11071#endif1107211073struct MicroProfileStringMatchMask11074{11075uint_string_match nMask;11076uint_string_match M[64];11077};1107811079struct MicroProfileSymbolDesc11080{11081const char* pName;11082const char* pShortName;11083intptr_t nAddress;11084intptr_t nAddressEnd;11085uint_string_match nMask;11086int nIgnoreSymbol;11087uint32_t nModule;11088};1108911090struct MicroProfileSymbolBlock11091{11092MicroProfileSymbolBlock* pNext;11093uint32_t nNumSymbols;11094uint32_t nNumChars;11095uint_string_match nMask;11096MicroProfileStringMatchMask MatchMask;11097enum11098{11099ESIZE = 4 << 10,11100};11101union11102{11103MicroProfileSymbolDesc Symbols[ESIZE / sizeof(MicroProfileSymbolDesc)];11104char Chars[ESIZE];11105};11106};1110711108typedef void (*MicroProfileOnSymbolCallback)(const char* pSymbolName, intptr_t nAddress);1110911110MP_THREAD_LOCAL uintptr_t g_MicroProfile_TLS[17] = { 16 };1111111112extern "C" MP_NOINLINE uintptr_t MicroProfile_Patch_TLS_PUSH(uintptr_t t)11113{11114uintptr_t* pTLS = &g_MicroProfile_TLS[0];1111511116uintptr_t Limit = (uint32_t)pTLS[0];11117uintptr_t Pos = (uint32_t)(pTLS[0] >> 32);11118if(Pos == Limit)11119{11120return 0;11121}11122else11123{11124pTLS[0] = (Limit) | ((Pos + 1) << 32);11125}11126pTLS[Pos + 1] = t;11127return 1;11128}11129extern "C" MP_NOINLINE uintptr_t MicroProfile_Patch_TLS_POP()11130{11131uintptr_t* pTLS = &g_MicroProfile_TLS[0];11132uintptr_t Limit = (uint32_t)pTLS[0];11133uintptr_t Pos = (uint32_t)(pTLS[0] >> 32);11134if(Pos == 0)11135{11136MP_BREAK(); // this should never happen11137return 0;11138}11139else11140{11141pTLS[0] = (Limit) | ((Pos - 1) << 32);11142}11143uintptr_t t = pTLS[Pos];11144return t;11145}1114611147char* MicroProfileInsertRegisterJump(char* pCode, intptr_t pDest, int reg)11148{11149MP_ASSERT(reg >= R_RAX && reg <= R_R15);11150int large = reg >= R_R8 ? 1 : 0;11151int offset = large ? (reg - R_R8) : (reg - R_RAX);11152unsigned char* uc = (unsigned char*)pCode;11153*uc++ = large ? 0x49 : 0x48;11154*uc++ = 0xb8 + offset;11155memcpy(uc, &pDest, 8);11156uc += 8;11157if(large)11158*uc++ = 0x41;11159*uc++ = 0xff;11160*uc++ = 0xe0 + offset;11161return (char*)uc;11162// 164: 48 b8 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rax11163// 16e: 48 b9 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rcx11164// 178: 48 ba 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rdx11165// 182: 48 bb 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rbx11166// 18c: 48 bc 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rsp11167// 196: 48 bd 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rbp11168// 1a0: 48 be 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rsi11169// 1aa: 48 bf 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rdi11170// 1b4: 49 b8 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r811171// 1be: 49 b9 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r911172// 1c8: 49 ba 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1011173// 1d2: 49 bb 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1111174// 1dc: 49 bc 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1211175// 1e6: 49 bd 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1311176// 1f0: 49 be 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1411177// 1fa: 49 bf 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r1511178// 204: ff e0 jmpq *%rax11179// 206: ff e1 jmpq *%rcx11180// 208: ff e2 jmpq *%rdx11181// 20a: ff e3 jmpq *%rbx11182// 20c: ff e4 jmpq *%rsp11183// 20e: ff e5 jmpq *%rbp11184// 210: ff e6 jmpq *%rsi11185// 212: ff e7 jmpq *%rdi11186// 214: 41 ff e0 jmpq *%r811187// 217: 41 ff e1 jmpq *%r911188// 21a: 41 ff e2 jmpq *%r1011189// 21d: 41 ff e3 jmpq *%r1111190// 220: 41 ff e4 jmpq *%r1211191// 223: 41 ff e5 jmpq *%r1311192// 226: 41 ff e6 jmpq *%r1411193// 229: 41 ff e7 jmpq *%r1511194}1119511196char* MicroProfileInsertRelativeJump(char* pCode, intptr_t pDest)11197{11198intptr_t src = intptr_t(pCode) + 5;11199intptr_t off = pDest - src;11200MP_ASSERT(off > intptr_t(0xffffffff80000000) && off <= 0x7fffffff);11201int32_t i32off = (int32_t)off;11202unsigned char* uc = (unsigned char*)pCode;11203unsigned char* c = (unsigned char*)&i32off;11204*uc++ = 0xe9;11205memcpy(uc, c, 4);11206uc += 4;11207return (char*)uc;11208}1120911210char* MicroProfileInsertRetJump(char* pCode, intptr_t pDest)11211{11212uint32_t lower = (uint32_t)pDest;11213uint32_t upper = (uint32_t)(pDest >> 32);11214unsigned char* uc = (unsigned char*)pCode;11215*uc++ = 0x68;11216memcpy(uc, &lower, 4);11217uc += 4;11218*uc++ = 0xc7;11219*uc++ = 0x44;11220*uc++ = 0x24;11221*uc++ = 0x04;11222memcpy(uc, &upper, 4);11223uc += 4;11224*uc++ = 0xc3;11225return (char*)uc;11226}1122711228uint8_t* MicroProfileInsertMov(uint8_t* p, uint8_t* pend, int r, intptr_t value)11229{11230int Large = r >= R_R8 ? 1 : 0;11231int RegIndex = Large ? (r - R_R8) : (r - R_RAX);11232*p++ = Large ? 0x49 : 0x48;11233*p++ = 0xb8 + RegIndex; // + (reg - (large?(R_R8-R_RAX):0));11234intptr_t* pAddress = (intptr_t*)p;11235pAddress[0] = value;11236p = (uint8_t*)(pAddress + 1);11237MP_ASSERT(p < pend);11238return p;11239}1124011241uint8_t* MicroProfileInsertCall(uint8_t* p, uint8_t* pend, int r)11242{11243int Large = r >= R_R8 ? 1 : 0;11244int RegIndex = Large ? (r - R_R8) : (r - R_RAX);11245if(Large)11246{11247*p++ = 0x41;11248}11249*p++ = 0xff;11250*p++ = 0xd0 + RegIndex;11251MP_ASSERT(p < pend);11252return p;11253}1125411255bool MicroProfileStringMatch(const char* pSymbol, uint32_t nStartOffset, const char** pPatterns, uint32_t* nPatternLength, uint32_t nNumPatterns)11256{11257MP_ASSERT(nStartOffset <= nNumPatterns);11258const char* p = pSymbol;11259for(uint32_t i = nStartOffset; i < nNumPatterns; ++i)11260{11261p = MP_STRCASESTR(p, pPatterns[i]);11262if(p)11263{11264p += nPatternLength[i];11265}11266else11267{11268return false;11269}11270}11271return true;11272}1127311274int MicroProfileStringMatchOffset(const char* pSymbol, const char** pPatterns, uint32_t* nPatternLength, uint32_t nNumPatterns)11275{11276int nOffset = 0;11277const char* p = pSymbol;11278for(uint32_t i = 0; i < nNumPatterns; ++i)11279{11280p = MP_STRCASESTR(p, pPatterns[i]);11281if(p)11282{11283p += nPatternLength[i];11284nOffset++;11285}11286else11287{11288break;11289}11290}11291return nOffset;11292}1129311294void* MicroProfileX64FollowJump(void* pSrc)11295{11296for(uint32_t i = 0; i < S.DynamicTokenIndex; ++i)11297if(S.FunctionsInstrumented[i] == pSrc)11298return pSrc; // if already instrumented, do not follow the jump inserted by itself.1129911300// uprintf("deref possible trampoline for %p\n", pSrc);11301_DecodeType dt = Decode64Bits;11302_DInst Instructions[1];11303unsigned int nCount = 0;1130411305_CodeInfo ci;11306ci.code = (uint8_t*)pSrc;11307ci.codeLen = 15;11308ci.codeOffset = 0;11309ci.dt = dt;11310ci.features = DF_NONE;11311int r = distorm_decompose(&ci, Instructions, 1, &nCount);11312if(!r || nCount != 1)11313{11314return pSrc; // fail, just return11315}1131611317auto& I = Instructions[0];11318if(I.opcode == I_JMP)11319{11320if(I.ops[0].type == O_PC)11321{11322if(I.ops[0].size == 0x20)11323{11324intptr_t p = (intptr_t)pSrc;11325p += I.size;11326p += I.imm.sdword;11327return (void*)p;11328}11329}11330else if(I.ops[0].type == O_SMEM)11331{11332if(I.ops[0].index == R_RIP)11333{11334intptr_t p = (intptr_t)pSrc;11335p += I.size;11336p += I.disp;11337void* pHest = *(void**)p;11338return pHest;11339}11340}11341uprintf("failed to interpret I_JMP %p %d %d\n", pSrc, I.ops[0].size, I.ops[0].type);11342return pSrc;11343MP_BREAK();11344}11345return pSrc;11346}1134711348bool MicroProfileCopyInstructionBytes(char* pDest,11349void* pSrc,11350const int nLimit,11351const int nMaxSize,11352char* pTrunk,11353intptr_t nTrunkSize,11354const uint32_t nUsableJumpRegs,11355int* pBytesDest,11356int* pBytesSrc,11357uint32_t* pRegsWritten,11358uint32_t* pRetSafe)11359{1136011361_DecodeType dt = Decode64Bits;11362_DInst Instructions[128];11363int rip[128] = { 0 };11364uint32_t nRegsWrittenInstr[128] = { 0 };11365int offsets[129] = { 0 };11366unsigned int nCount = 0;1136711368_CodeInfo ci;11369ci.code = (uint8_t*)pSrc;11370ci.codeLen = nLimit + 15;11371ci.codeOffset = 0;11372ci.dt = dt;11373ci.features = DF_NONE;11374int r = distorm_decompose(&ci, Instructions, 128, &nCount);11375if(r != DECRES_SUCCESS)11376{11377BREAK_ON_PATCH_FAIL();11378return false;11379}11380int offset = 0;11381unsigned int i = 0;11382unsigned nInstructions = 0;11383int64_t nTrunkUsage = 0;11384offsets[0] = 0;11385uint32_t nRegsWritten = 0;1138611387auto Align16 = [](intptr_t p) { return (p + 15) & (~15); };1138811389{1139011391intptr_t iTrunk = (intptr_t)pTrunk;11392intptr_t iTrunkEnd = iTrunk + nTrunkSize;11393intptr_t iTrunkAligned = (iTrunk + 15) & ~15;11394nTrunkSize = iTrunkEnd - iTrunkAligned;11395pTrunk = (char*)iTrunkAligned;11396}11397const uint8_t* pTrunkEnd = (uint8_t*)(pTrunk + nTrunkSize);1139811399auto RegToBit = [](int r) -> uint32_t11400{11401if(r >= R_RAX && r <= R_R15)11402{11403return (1u << (r - R_RAX));11404}11405else if(r >= R_EAX && r <= R_R15D)11406{11407return (1u << (r - R_EAX));11408}11409else if(r >= R_AX && r <= R_R15W)11410{11411return (1u << (r - R_AX));11412}11413else if(r >= R_AL && r <= R_R15B)11414{11415return (1u << (r - R_AL));11416}11417return 0; // might hit on registers like RIP11418MP_BREAK();11419};11420#ifdef _WIN3211421const uint32_t nUsableRegisters = RegToBit(R_RAX) | RegToBit(R_R10) | RegToBit(R_R11);11422#else11423const uint32_t nUsableRegisters = RegToBit(R_RAX) | RegToBit(R_R10) | RegToBit(R_R11);11424#endif1142511426int nBytesToMove = 0;11427for(i = 0; i < nCount; ++i)11428{11429nBytesToMove += Instructions[i].size;11430if(nBytesToMove >= nLimit)11431break;11432}11433*pBytesSrc = nBytesToMove;1143411435uint32_t nRspMask = RegToBit(R_RSP);11436*pRetSafe = 1;1143711438for(i = 0; i < nCount; ++i)11439{11440rip[i] = 0;11441auto& I = Instructions[i];11442// bool bHasRipReference = false;11443if(I.opcode == I_LEA)11444{11445}11446if(I.opcode == I_CALL)11447{11448auto& O = I.ops[0];11449if(O.type != O_PC || O.size != 0x20)11450{11451uprintf("unknown call encountered. cannot move\n");11452BREAK_ON_PATCH_FAIL();11453return false;11454}11455if((nRegsWritten & nUsableRegisters) == nUsableRegisters)11456{11457uprintf("call encountered, but register all regs was written to. TODO: push regs?\n");11458BREAK_ON_PATCH_FAIL();11459return false;11460}11461// return value might be used past return so preserve registers.11462#ifdef _WIN3211463nRegsWritten |= RegToBit(R_RAX);11464#else11465nRegsWritten |= RegToBit(R_RAX) | RegToBit(R_RDX);11466#endif11467}1146811469switch(I.ops[0].type)11470{11471case O_REG:11472{11473uint32_t reg = I.ops[0].index;11474nRegsWritten |= RegToBit(reg);11475auto& O2 = I.ops[1];11476switch(O2.type)11477{11478case O_REG:11479case O_MEM:11480case O_SMEM:11481{11482// if register is RSP 'contaminated', it prevents us from using that to do retjmps11483uint32_t nMask = RegToBit(O2.index);11484if(nRspMask & nMask)11485{11486nRspMask |= RegToBit(reg);11487}11488}11489default:11490break;11491}11492break;11493}11494case O_MEM:11495case O_SMEM:11496{11497uint32_t reg = I.ops[0].index;11498if(nRspMask & RegToBit(reg))11499{11500uprintf("found contaminated reg at +%lld\n", (long long)I.addr);11501*pRetSafe = 0;11502}11503break;11504}11505}11506nRegsWrittenInstr[i] = nRegsWritten;11507for(int j = 0; j < 4; ++j)11508{11509auto& O = I.ops[j];1151011511switch(O.type)11512{11513case O_REG:11514case O_SMEM:11515case O_MEM:11516{11517if(O.index == R_RIP)11518{11519if(j != 1)11520{11521uprintf("found non base reference of rip. fail\n");11522BREAK_ON_PATCH_FAIL();11523return false;11524}11525if(I.dispSize != 0x20 && I.dispSize != 0x10)11526{11527uprintf("found offset size != 32 && != 16 bit. not implemented\n");11528BREAK_ON_PATCH_FAIL();11529return false;11530}11531rip[i] = 1;11532nTrunkUsage += Align16(O.size / 8);11533if(nTrunkUsage > nTrunkSize)11534{11535uprintf("overuse of trunk %lld\n", (long long)nTrunkUsage);11536BREAK_ON_PATCH_FAIL();11537return false;11538}11539}11540break;11541}11542}11543}11544if(rip[i])11545{11546if(I.ops[0].type != O_REG)11547{11548uprintf("arg 0 should be O_REG, fail\n");11549BREAK_ON_PATCH_FAIL();11550return false;11551}11552if(I.ops[1].type != O_SMEM)11553{11554uprintf("arg 1 should be O_SMEM, fail was %d\n", O_SMEM);11555BREAK_ON_PATCH_FAIL();11556return false;11557}11558}11559int fc = META_GET_FC(Instructions[i].meta);11560switch(fc)11561{11562case FC_CALL:11563{11564break;11565}11566case FC_RET:11567case FC_SYS:11568case FC_UNC_BRANCH:11569case FC_CND_BRANCH:11570uprintf("found branch inst %d :: %d\n", fc, offset);11571BREAK_ON_PATCH_FAIL();11572return false;11573}11574offset += Instructions[i].size;11575offsets[i + 1] = offset;11576if(offset >= nLimit)11577{11578nInstructions = i + 1;11579break;11580}11581}11582if(nTrunkUsage > nTrunkSize)11583{11584uprintf("function using too much trunk space\n");11585BREAK_ON_PATCH_FAIL();11586return false;11587}11588if(offset < nLimit)11589{11590uprintf("function only had %d bytes of %d\n", offset, nLimit);11591BREAK_ON_PATCH_FAIL();11592return false;11593}1159411595if(0 == *pRetSafe && 0 == (nUsableJumpRegs & ~nRegsWritten))11596{11597// if ret jump is unsafe all of the usable jump regs are taken, fail.11598uprintf("cannot patch function without breaking code]\n");11599BREAK_ON_PATCH_FAIL();11600MP_BREAK();11601return false;11602}1160311604// MP_BREAK();11605*pRegsWritten = nRegsWritten;11606uint8_t* d = (uint8_t*)pDest;11607uint8_t* dend = d + nMaxSize;11608const uint8_t* s = (const uint8_t*)pSrc;1160911610nTrunkUsage = 0;1161111612for(i = 0; i < nInstructions; ++i)11613{11614auto& I = Instructions[i];11615unsigned size = Instructions[i].size;11616if(I.opcode == I_CALL)11617{11618// find reg11619uint32_t nRegsWritten = nRegsWrittenInstr[i];11620uint32_t nUsable = nUsableRegisters & ~nRegsWritten;11621MP_ASSERT(nUsable);11622int r = R_RAX;11623while(0 == (1 & nUsable))11624{11625nUsable >>= 1;11626r++;11627}1162811629intptr_t p = offsets[i + 1];11630p += (intptr_t)pSrc;11631p += I.imm.sdword;11632d = MicroProfileInsertMov(d, dend, r, p);11633d = MicroProfileInsertCall(d, dend, r);11634s += size;11635}11636else if(rip[i])11637{11638if(I.opcode == I_LEA)11639{11640if(I.ops[0].type != O_REG)11641{11642MP_BREAK();11643}11644if(I.ops[1].index != R_RIP)11645{11646MP_BREAK();11647}11648int reg = I.ops[0].index - R_RAX;11649int large = I.ops[0].index >= R_R8 ? 1 : 0;11650*d++ = large ? 0x49 : 0x48;11651*d++ = 0xb8 + (reg - (large ? (R_R8 - R_RAX) : 0));11652// calculate the offset11653int64_t offset = offsets[i + 1] + I.disp;11654intptr_t base = (intptr_t)pSrc;1165511656intptr_t sum = base + offset;11657intptr_t* pAddress = (intptr_t*)d;11658pAddress[0] = sum;11659s += size;11660d += 10;11661d = (uint8_t*)(pAddress + 1);11662}11663else11664{11665if(15 & (intptr_t)pTrunk)11666{11667MP_BREAK();11668}11669intptr_t t = (intptr_t)pTrunk;11670t = (t + 15) & ~15;11671pTrunk = (char*)t;11672auto& O = I.ops[1];11673uint32_t Op1Size = O.size / 8;1167411675memcpy(d, s, size);11676int32_t DispOriginal = (int32_t)I.disp;11677const uint8_t* pOriginal = (s + size) + DispOriginal;1167811679intptr_t DispNew = ((uint8_t*)pTrunk - (d + size));11680if(!((intptr_t)pTrunk + Op1Size <= (intptr_t)pTrunkEnd))11681{11682MP_BREAK();11683}11684memcpy(pTrunk, pOriginal, Op1Size);11685pTrunk += Align16(Op1Size);11686if(I.dispSize == 32)11687{11688int32_t off = (int32_t)DispNew;11689if(DispNew > 0x7fffffff || DispNew < 0)11690{11691MP_BREAK();11692}11693memcpy(d + size - 4, &off, 4);11694}11695else if(I.dispSize == 16)11696{11697int16_t off = (int16_t)DispNew;11698if(DispNew > 0x7fff || DispNew < 0)11699{11700MP_BREAK();11701}11702memcpy(d + size - 2, &off, 2);11703}1170411705d += size;11706s += size;11707}11708}11709else11710{11711memcpy(d, s, size);11712d += size;11713s += size;11714}11715}1171611717*pBytesDest = (int)(d - (uint8_t*)pDest);1171811719return true;11720}1172111722extern "C" void MicroProfileInterceptEnter(int a)11723{11724MicroProfileToken T = S.DynamicTokens[a];11725MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();11726MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert your instrumenting a deeply nested function11727MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[pLog->nStackScope++];11728pScopeState->Token = T;11729if(T)11730{11731pScopeState->nTick = MicroProfileEnterInternal(T);11732}11733else11734{11735pScopeState->nTick = MICROPROFILE_INVALID_TICK;11736}11737}11738extern "C" void MicroProfileInterceptLeave(int a)11739{11740MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2();11741MP_ASSERT(pLog->nStackScope > 0); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers11742MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[--pLog->nStackScope];11743MicroProfileLeaveInternal(pScopeState->Token, pScopeState->nTick);11744}1174511746bool MicroProfileInstrumentFromAddressOnly(void* pFunction)11747{11748MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunction);11749if(pDesc)11750{11751uprintf("Found function %p :: %s %s\n", (void*)pDesc->nAddress, pDesc->pName, pDesc->pShortName);11752uint32_t nColor = MicroProfileColorFromString(pDesc->pName);1175311754return MicroProfileInstrumentFunction(pFunction, MicroProfileSymbolModuleGetString(pDesc->nModule), pDesc->pName, nColor);11755}11756else11757{11758uprintf("No Function Found %p\n", pFunction);11759return false;11760}11761}1176211763template <typename CB>11764void MicroProfileInstrumentScanForFunctionCalls(CB Callback, void* pFunction, size_t nFunctionSize)11765{11766pFunction = MicroProfileX64FollowJump(pFunction);11767const intptr_t nCodeLen = nFunctionSize;11768const uint32_t nMaxInstructions = 15;11769intptr_t nOffset = 0;11770_DecodeType dt = Decode64Bits;11771_DInst Instructions[15];11772_CodeInfo ci;11773do11774{11775ci.code = nOffset + (uint8_t*)pFunction;11776ci.codeLen = nCodeLen - nOffset;11777ci.codeOffset = 0;11778ci.dt = dt;11779ci.features = DF_RETURN_FC_ONLY;11780uint32_t nCount = 0;11781uint32_t nOffsetNext = 0;1178211783int r = distorm_decompose(&ci, Instructions, nMaxInstructions, &nCount);11784// uprintf("decomposed %d\n", nCount);11785if(r != DECRES_SUCCESS && r != DECRES_MEMORYERR)11786{11787BREAK_ON_PATCH_FAIL();11788return;11789}11790if(nCount == 0)11791{11792// no instructions left11793break;11794}11795// uprintf("instructions decoded %d %p ::\n", nCount, pFunction);11796for(int i = 0; i < (int)nCount; ++i)11797{11798// rip[i] = 0;11799auto& I = Instructions[i];11800// bool bHasRipReference = false;11801if(I.addr < nOffsetNext)11802{11803MP_BREAK();11804}11805nOffsetNext = I.addr + I.size;11806if(I.opcode == I_CALL)11807{11808auto& O = I.ops[0];11809if(O.type != O_PC || O.size != 0x20)11810{11811uprintf("non immediate call encountered. cannot follow\n");11812BREAK_ON_PATCH_FAIL();11813continue;11814}11815intptr_t pDst = nOffset + (intptr_t)pFunction;11816pDst += I.addr;11817pDst += I.size;11818pDst += I.imm.sdword;1181911820void* fFun1 = MicroProfileX64FollowJump((void*)pDst);11821Callback(fFun1);11822}11823}11824nOffset += nOffsetNext;11825} while(nOffset < nCodeLen);11826}1182711828void MicroProfileInstrumentFunctionsCalled(void* pFunction, const char* pModuleName, const char* pFunctionName, int nMinBytes, int nMaxCalls)11829{11830pFunction = MicroProfileX64FollowJump(pFunction);1183111832MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunction);11833if(pDesc)11834{11835uprintf("instrumenting child functions %p %p :: %s :: %s\n", (void*)pDesc->nAddress, (void*)pDesc->nAddressEnd, pDesc->pName, pDesc->pShortName);11836int a = 0;11837(void)a;11838}11839else11840{11841uprintf("could not find symbol info\n");11842return;11843}1184411845const intptr_t nCodeLen = (intptr_t)pDesc->nAddressEnd - (intptr_t)pDesc->nAddress;1184611847MicroProfilePatchBeginSuspend();11848int NumFunctionsInstrumented = 0;11849auto Callback = [&NumFunctionsInstrumented, nMinBytes, nMaxCalls](void* pFunc)11850{11851MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunc);11852if(!pDesc)11853return;11854const char* pName = pDesc ? pDesc->pName : "??";11855intptr_t Size = pDesc->nAddressEnd - pDesc->nAddress;11856if(nMinBytes == 0 || Size >= nMinBytes)11857{11858if(0 == nMaxCalls || NumFunctionsInstrumented < nMaxCalls)11859{11860uprintf("** func Instrumented, count %d, size %d %s\n", NumFunctionsInstrumented, Size, pName);11861if(MicroProfileInstrumentFromAddressOnly(pFunc))11862{11863++NumFunctionsInstrumented;11864}11865}11866else11867{11868uprintf("** func Skipped, count %d>=%d :: %s\n", NumFunctionsInstrumented, nMaxCalls, pName);11869}11870}11871else11872{11873uprintf("** func Skipped, Size %d<%d :: %s\n", Size, nMinBytes, pName);11874}11875};11876MicroProfileInstrumentScanForFunctionCalls(Callback, pFunction, nCodeLen);1187711878MicroProfilePatchEndSuspend();11879}1188011881bool MicroProfileInstrumentFunction(void* pFunction, const char* pModuleName, const char* pFunctionName, uint32_t nColor)11882{11883MicroProfilePatchBeginSuspend();11884struct ScopeExit11885{11886~ScopeExit()11887{11888MicroProfilePatchEndSuspend();11889}11890} dummy;1189111892MicroProfilePatchError Err;11893if(S.DynamicTokenIndex == MICROPROFILE_MAX_DYNAMIC_TOKENS)11894{11895uprintf("instrument failing, out of dynamic tokens %d\n", S.DynamicTokenIndex);11896return false;11897}11898for(uint32_t i = 0; i < S.DynamicTokenIndex; ++i)11899{11900if(S.FunctionsInstrumented[i] == pFunction)11901{11902uprintf("function %p already instrumented\n", pFunction);11903return false;11904}11905}11906if(MicroProfilePatchFunction(pFunction, S.DynamicTokenIndex, MicroProfileInterceptEnter, MicroProfileInterceptLeave, &Err))11907{11908MicroProfileToken Tok = S.DynamicTokens[S.DynamicTokenIndex] = MicroProfileGetToken("PATCHED", pFunctionName, nColor, MicroProfileTokenTypeCpu, 0);11909S.FunctionsInstrumented[S.DynamicTokenIndex] = pFunction;11910S.FunctionsInstrumentedName[S.DynamicTokenIndex] = MicroProfileStringIntern(pFunctionName);11911S.FunctionsInstrumentedModuleNames[S.DynamicTokenIndex] = MicroProfileStringIntern(pModuleName);11912S.DynamicTokenIndex++;1191311914uint16_t nGroup = MicroProfileGetGroupIndex(Tok);11915if(!MicroProfileGroupActive(nGroup))11916{11917MicroProfileGroupSetEnabled(nGroup);11918}11919#if MICROPROFILE_WEBSERVER11920MicroProfileWebSocketToggleTimer(MicroProfileGetTimerIndex(Tok));11921#endif1192211923return false;11924}11925else11926{11927bool bFound = false;11928for(int i = 0; i < S.nNumPatchErrors; ++i)11929{11930if(Err.nCodeSize == S.PatchErrors[i].nCodeSize && 0 == memcmp(Err.Code, S.PatchErrors[i].Code, Err.nCodeSize))11931{11932bFound = true;11933break;11934}11935}11936if(!bFound && S.nNumPatchErrors < MICROPROFILE_MAX_PATCH_ERRORS)11937{11938memcpy(&S.PatchErrors[S.nNumPatchErrors++], &Err, sizeof(Err));11939}11940bFound = false;11941for(int i = 0; i < S.nNumPatchErrorFunctions; ++i)11942{11943if(0 == strcmp(pFunctionName, S.PatchErrorFunctionNames[i]))11944{11945bFound = true;11946}11947}11948if(!bFound && S.nNumPatchErrorFunctions < MICROPROFILE_MAX_PATCH_ERRORS)11949{11950S.PatchErrorFunctionNames[S.nNumPatchErrorFunctions++] = pFunctionName;11951}11952uprintf("interception fail!!\n");11953return false;11954}11955}1195611957void MicroProfileInstrumentPreInit();11958void MicroProfileSymbolInitializeInternal();11959void MicroProfileSymbolFreeDataInternal();11960void MicroProfileSymbolKickThread();11961void MicroProfileQueryJoinThread();1196211963bool MicroProfileSymbolInitialize(bool bStartLoad, const char* pModuleName)11964{11965if(!bStartLoad)11966return S.SymbolState.nModuleLoadsFinished.load() != 0;11967// int nRequests = 0;11968{11969MicroProfileScopeLock L(MicroProfileMutex());11970for(int i = 0; i < S.SymbolNumModules; ++i)11971{11972if(0 == pModuleName || 0 == strcmp(pModuleName, (const char*)S.SymbolModules[i].pBaseString))11973{11974if(0 == S.SymbolModules[i].nModuleLoadRequested.exchange(1))11975{11976S.SymbolState.nModuleLoadsRequested.fetch_add(1);11977}11978}11979}11980}1198111982// todo: unload modules11983MicroProfileSymbolKickThread();11984return S.SymbolState.nModuleLoadsRequested.load() == S.SymbolState.nModuleLoadsFinished.load();1198511986// if(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DEFAULT)11987// {11988// if(!bStartLoad)11989// return false;11990// {11991// MicroProfileScopeLock L(MicroProfileMutex());11992// S.SymbolState.nState.store(MICROPROFILE_SYMBOLSTATE_LOADING);11993// S.SymbolState.nSymbolsLoaded.store(0);11994// }11995// MicroProfileSymbolKickThread();11996// return false;11997// }11998// if(nRequests)11999// {12000// }12001// if(S.SymbolState.nState.load() == MICROPROFILE_SYMBOLSTATE_DONE)12002// {12003// MicroProfileQueryJoinThread();12004// }12005// if(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE && bStartLoad)12006// {12007// MicroProfileSymbolFreeDataInternal();12008// {12009// MicroProfileScopeLock L(MicroProfileMutex());12010// S.SymbolState.nState.store(MICROPROFILE_SYMBOLSTATE_LOADING);12011// S.SymbolState.nSymbolsLoaded.store(0);12012// }12013// MicroProfileSymbolKickThread();12014// return false;1201512016// }12017// else12018// {12019// return S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE;12020// }12021}1202212023void MicroProfileSymbolFreeDataInternal()12024{12025{12026uprintf("todod;....\n");12027MP_BREAK();12028// MP_ASSERT(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE);1202912030S.nNumPatchErrorFunctions = 0;12031memset(S.PatchErrorFunctionNames, 0, sizeof(S.PatchErrorFunctionNames));1203212033for(int i = 0; i < S.SymbolNumModules; ++i)12034{1203512036while(S.SymbolModules[i].pSymbolBlock)12037{12038MicroProfileSymbolBlock* pBlock = S.SymbolModules[i].pSymbolBlock;12039S.SymbolModules[i].pSymbolBlock = pBlock->pNext;12040MP_FREE(pBlock);12041MICROPROFILE_COUNTER_SUB("/MicroProfile/Symbols/Allocs", 1);12042MICROPROFILE_COUNTER_SUB("/MicroProfile/Symbols/Memory", sizeof(MicroProfileSymbolBlock));12043}12044}12045memset(&S.SymbolModules[0], 0, sizeof(S.SymbolModules));12046memset(&S.SymbolModuleNameBuffer[0], 0, sizeof(S.SymbolModuleNameBuffer));12047S.SymbolModuleNameOffset = 0;12048S.SymbolNumModules = 0;12049}12050}12051#if STRING_MATCH_SIZE == 6412052int MicroProfileCharacterMaskCharIndex(char c)12053{12054if(c >= 'A' && c <= 'Z')12055c = 'a' + (c - 'A');12056// abcdefghijklmnopqrstuvwxyz12057if(c >= 'a' && c <= 'z')12058{12059int b = c - 'a';12060return b;12061}12062if(c >= '0' && c <= '9')12063{12064int b = c - '0';12065return b + 26;12066}12067switch(c)12068{12069case ':':12070return 37;12071case ';':12072return 38;12073case '\\':12074return 39;12075case '\'':12076return 40;12077case '\"':12078return 41;12079case '/':12080return 42;12081case '{':12082return 43;12083case '}':12084return 44;12085case '(':12086return 45;12087case ')':12088return 46;12089case '[':12090return 47;12091case ']':12092return 48;12093case '<':12094return 49;12095case '>':12096return 50;12097case '.':12098return 51;12099case ',':12100return 52; // special characters12101case ' ':12102return -1; // special characters12103}12104return 63;12105}1210612107uint64_t MicroProfileCharacterMaskChar(char c)12108{12109uint64_t nMask = 1;12110int nIndex = MicroProfileCharacterMaskCharIndex(c);12111if(nIndex == -1)12112return 0;12113return nMask << nIndex;12114}1211512116#else12117uint32_t MicroProfileCharacterMaskChar(char c)12118{12119if(c >= 'A' && c <= 'Z')12120c = 'a' + (c - 'A');12121// abcdefghijklmnopqrstuvwxyz12122if(c >= 'a' && c <= 'z')12123{12124int b = c - 'a';12125b = MicroProfileMin(20, b); // squish the last together12126// static int once = 0;12127// if(0 == once)12128//{12129// for(int i = 20; i < 28; ++i)12130// {12131// uprintf("char %d is %c\n", i, (char)('a' + i));12132// }12133// once = 1;12134//}12135uint32_t v = 1;12136return v << b;12137}12138if(c >= '0' && c <= '9')12139{12140int b = c - '0';12141b += 21;12142if(b < 21 || b > 30)12143MP_BREAK();12144return 1 << b;12145}12146switch(c)12147{12148case ':':12149case ';':12150case '\\':12151case '\'':12152case '\"':12153case '/':12154case '{':12155case '}':12156case '(':12157case ')':12158case '[':12159case ']':12160return 1u << 31; // special characters12161case ' ':12162return 0;12163}12164return 0;12165}12166int MicroProfileCharacterMaskCharIndex(char c)12167{12168if(c >= 'A' && c <= 'Z')12169c = 'a' + (c - 'A');12170// abcdefghijklmnopqrstuvwxyz12171if(c >= 'a' && c <= 'z')12172{12173int b = c - 'a';12174b = MicroProfileMin(20, b); // squish the last together12175static int once = 0;12176if(0 == once)12177{12178for(int i = 20; i < 28; ++i)12179{12180uprintf("char %d is %c\n", i, (char)('a' + i));12181}12182once = 1;12183}12184return b;12185}12186if(c >= '0' && c <= '9')12187{12188int b = c - '0';12189b += 21;12190if(b < 21 || b > 30)12191MP_BREAK();12192return b;12193}12194switch(c)12195{12196case ':':12197case ';':12198case '\\':12199case '\'':12200case '\"':12201case '/':12202case '{':12203case '}':12204case '(':12205case ')':12206case '[':12207case ']':12208return 31; // special characters12209case ' ':12210return -1;12211}12212return 1;12213}12214#endif1221512216uint_string_match MicroProfileCharacterMaskString(const char* pStr)12217{12218uint_string_match nMask = 0;12219char c = 0;12220while(0 != (c = *pStr++))12221{12222nMask |= MicroProfileCharacterMaskChar(c);12223}12224return nMask;12225}1222612227void MicroProfileCharacterMaskString2(const char* pStr, MicroProfileStringMatchMask& M)12228{12229uint_string_match nMask = 0;12230char c = 0;12231int nLast = -1;12232while(0 != (c = *pStr++))12233{12234nMask |= MicroProfileCharacterMaskChar(c);12235int nIndex = MicroProfileCharacterMaskCharIndex(c);12236if(nIndex >= 0 && nLast >= 0)12237{12238MP_ASSERT(nIndex < STRING_MATCH_SIZE);12239M.M[nLast] |= 1llu << nIndex;12240}12241nLast = nIndex;12242}12243M.nMask |= nMask;12244}1224512246bool MicroProfileCharacterMatch(const MicroProfileStringMatchMask& Block, const MicroProfileStringMatchMask& String)12247{12248if(String.nMask != (Block.nMask & String.nMask))12249return false;12250for(uint32_t i = 0; i < STRING_MATCH_SIZE; ++i)12251{12252if(String.M[i] != (Block.M[i] & String.M[i]))12253return false;12254}12255return true;12256}1225712258uint32_t MicroProfileSymbolGetModule(const char* pString, intptr_t nBaseAddr)12259{1226012261for(int i = 0; i < S.SymbolNumModules; ++i)12262{12263auto& M = S.SymbolModules[i];12264for(int j = 0; j < M.nNumExecutableRegions; ++j)12265{12266if(M.Regions[j].nBegin <= nBaseAddr && nBaseAddr < M.Regions[j].nEnd)12267return i;12268}12269}12270MP_BREAK(); // should never happen.12271return 0;12272}1227312274void MicroProfileSymbolMergeExecutableRegions()12275{12276for(int i = 0; i < S.SymbolNumModules; ++i)12277{12278auto& M = S.SymbolModules[i];12279if(M.nNumExecutableRegions > 1)12280{12281std::sort(&M.Regions[0], &M.Regions[M.nNumExecutableRegions], [](const MicroProfileSymbolModuleRegion& l, const MicroProfileSymbolModuleRegion& r) { return l.nBegin < r.nBegin; });1228212283int p = 0;12284int g = 1;12285while(g < M.nNumExecutableRegions)12286{12287if(M.Regions[p].nEnd == M.Regions[g].nBegin)12288{12289M.Regions[p].nEnd = M.Regions[g].nEnd;12290g++;12291}12292else12293{12294++p;12295if(p != g)12296M.Regions[p] = M.Regions[g];12297g++;12298}12299}12300M.nNumExecutableRegions = p + 1;12301}12302}12303for(int i = 0; i < S.SymbolNumModules; ++i)12304{12305auto& M = S.SymbolModules[i];12306uprintf("region %s %s\n", M.pTrimmedString, M.pBaseString);12307for(int j = 0; j < M.nNumExecutableRegions; ++j)12308uprintf("\t[%p-%p]\n", (void*)M.Regions[j].nBegin, (void*)M.Regions[j].nEnd);12309}12310}1231112312uint32_t MicroProfileSymbolInitModule(const char* pString_, intptr_t nAddrBegin, intptr_t nAddrEnd)12313{12314const char* pString = MicroProfileStringInternSlash(pString_);12315for(int i = 0; i < S.SymbolNumModules; ++i)12316{12317auto& M = S.SymbolModules[i];12318for(int j = 0; j < M.nNumExecutableRegions; ++j)12319{12320if(M.Regions[j].nBegin <= nAddrBegin && nAddrEnd < M.Regions[j].nEnd)12321{12322MP_ASSERT(pString == M.pBaseString);12323return i;12324}12325}12326}1232712328for(int i = 0; i < S.SymbolNumModules; ++i)12329{12330auto& M = S.SymbolModules[i];12331if(M.pBaseString == pString)12332{12333MP_ASSERT((intptr_t)pString != -2);12334for(int j = 0; j < M.nNumExecutableRegions; ++j)12335if(nAddrBegin == M.Regions[j].nBegin)12336return i;1233712338if(M.nNumExecutableRegions == MICROPROFILE_MAX_MODULE_EXEC_REGIONS)12339{12340return (uint32_t)-1;12341}12342M.Regions[M.nNumExecutableRegions].nBegin = nAddrBegin;12343M.Regions[M.nNumExecutableRegions].nEnd = nAddrEnd;12344// uprintf("added module region %d %p %p %s \n", M.nNumExecutableRegions, (void*)nAddrBegin, (void*)nAddrEnd, pString);12345M.nNumExecutableRegions++;12346return i;12347}12348}1234912350MP_ASSERT((intptr_t)pString != -2);12351// trim untill last path char12352const char* pTrimmedString = pString;1235312354const char* pWork = pTrimmedString;12355bool bLastSeperator = false;12356while(*pWork != '\0')12357{12358if(bLastSeperator)12359pTrimmedString = pWork;12360bLastSeperator = *pWork == '\\' || *pWork == '/';1236112362pWork++;12363}12364int nLen = (int)strlen(pTrimmedString) + 1;12365// uprintf("STRING '%s' :: trimmedstring %s . len %d\n", pString, pTrimmedString, nLen);1236612367const char* pTrimmedIntern = MicroProfileStringIntern(pTrimmedString);12368if(S.SymbolModuleNameOffset + nLen > MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS)12369return 0;12370memcpy(S.SymbolModuleNameOffset + &S.SymbolModuleNameBuffer[0], pTrimmedString, nLen);1237112372MP_ASSERT(S.SymbolNumModules < MICROPROFILE_INSTRUMENT_MAX_MODULES);12373S.SymbolModules[S.SymbolNumModules].nModuleBase = nAddrBegin;12374S.SymbolModules[S.SymbolNumModules].nMatchOffset = 0;12375S.SymbolModules[S.SymbolNumModules].nStringOffset = S.SymbolModuleNameOffset;12376S.SymbolModules[S.SymbolNumModules].pBaseString = (const char*)pString;12377S.SymbolModules[S.SymbolNumModules].pTrimmedString = pTrimmedIntern;12378S.SymbolModules[S.SymbolNumModules].Regions[0].nBegin = nAddrBegin;12379S.SymbolModules[S.SymbolNumModules].Regions[0].nEnd = nAddrEnd;12380S.SymbolModules[S.SymbolNumModules].nNumExecutableRegions = 1;12381S.SymbolModules[S.SymbolNumModules].bDownloading = false;12382S.SymbolModules[S.SymbolNumModules].nProgress = 0;12383S.SymbolModules[S.SymbolNumModules].nProgressTarget = 0;1238412385S.SymbolModuleNameOffset += nLen;12386return S.SymbolNumModules++;12387}1238812389const char* MicroProfileSymbolModuleGetString(uint32_t nIndex)12390{12391MP_ASSERT(S.SymbolNumModules > (int)nIndex);12392return S.SymbolModules[nIndex].nStringOffset + &S.SymbolModuleNameBuffer[0];12393}1239412395bool MicroProfileSymbolIgnoreSymbol(const char* pName)12396{12397if(strstr(pName, "MicroProfile"))12398{12399#if MICROPROFILE_INSTRUMENT_MICROPROFILE == 012400return true;12401#else12402if(strstr(pName, "Log") || strstr(pName, "Scope") || strstr(pName, "Tick") || strstr(pName, "Enter") || strstr(pName, "Leave") || strstr(pName, "Thread") || strstr(pName, "Thread") ||12403strstr(pName, "Mutex")) // just for debugging: skip these so we can play around with the sample projects12404{12405return true;12406}12407#endif12408}12409#ifdef _WIN3212410if(pName[0] == '_' && pName[1] == '_')12411return true;12412if(strstr(pName, "__security_check_cookie") || strstr(pName, "_RTC_CheckStackVars") || strstr(pName, "__chkstk") || strstr(pName, "std::_Atomic") || strstr(pName, "_Init_thread_header") ||12413strstr(pName, "_Init_thread_footer"))12414{12415return true;12416}12417#endif12418return false;12419}1242012421void MicroProfileSymbolInitializeInternal()12422{12423uprintf("Starting load...\n");12424MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolInitialize", MP_CYAN);1242512426auto AllocBlock = []() -> MicroProfileSymbolBlock*12427{12428MicroProfileSymbolBlock* pBlock = MP_ALLOC_OBJECT(MicroProfileSymbolBlock);12429MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Allocs", 1);12430MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Memory", sizeof(MicroProfileSymbolBlock));12431MICROPROFILE_COUNTER_CONFIG_ONCE("/MicroProfile/Symbols/Memory", MICROPROFILE_COUNTER_FORMAT_BYTES, 0, 0);12432memset(pBlock, 0, sizeof(MicroProfileSymbolBlock));12433return pBlock;12434};1243512436auto SymbolCallback = [&](const char* pName, const char* pShortName, intptr_t nAddress, intptr_t nAddressEnd, uint32_t nModuleId)12437{12438MICROPROFILE_SCOPEI("microprofile", "SymbolCallback", MP_AUTO);12439uint32_t nModule = nModuleId;12440if(MicroProfileHashTableGetPtr(&S.SymbolModules[nModule].AddressToSymbol, (void*)nAddress))12441{12442return;12443}12444char Demangled[1024];12445if(MicroProfileDemangleName(pName, Demangled, sizeof(Demangled)))12446{12447pName = &Demangled[0];12448pShortName = &Demangled[0];12449}12450intptr_t delta = nAddressEnd - nAddress;12451S.SymbolModules[nModule].nProgress = MicroProfileMax(delta, S.SymbolModules[nModule].nProgress);12452S.nSymbolsDirty++;1245312454int nIgnoreSymbol = MicroProfileSymbolIgnoreSymbol(pName) ? 1 : 0;1245512456MicroProfileSymbolBlock* pActiveBlock = S.SymbolModules[nModule].pSymbolBlock;12457if(!pActiveBlock)12458{12459pActiveBlock = AllocBlock();12460pActiveBlock->pNext = S.SymbolModules[nModule].pSymbolBlock;12461S.SymbolModules[nModule].pSymbolBlock = pActiveBlock;12462}1246312464if(pName == pShortName)12465{12466pShortName = 0;12467}12468uint32_t nLen = (uint32_t)strlen(pName) + 1;1246912470if(nLen > MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN)12471nLen = MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN;12472uint32_t nLenShort = (uint32_t)(pShortName ? 1 + strlen(pShortName) : 0);12473if(nLenShort && nLenShort > MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN)12474nLenShort = MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN;12475uint32_t S0 = sizeof(MicroProfileSymbolDesc) * pActiveBlock->nNumSymbols;12476uint32_t S1 = pActiveBlock->nNumChars;12477uint32_t S3 = nLenShort + nLen + sizeof(MicroProfileSymbolDesc) + 64;12478if(S0 + S1 + S3 >= MicroProfileSymbolBlock::ESIZE)12479{12480MicroProfileSymbolBlock* pNewBlock = AllocBlock();12481MP_ASSERT(pActiveBlock == S.SymbolModules[nModule].pSymbolBlock);12482pNewBlock->pNext = pActiveBlock;12483S.SymbolModules[nModule].pSymbolBlock = pNewBlock;12484pActiveBlock = pNewBlock;12485}12486S0 = sizeof(MicroProfileSymbolDesc) * pActiveBlock->nNumSymbols;12487S1 = pActiveBlock->nNumChars;12488S3 = nLenShort + nLen + sizeof(MicroProfileSymbolDesc);12489MP_ASSERT(S0 + S1 + S3 < MicroProfileSymbolBlock::ESIZE);12490pActiveBlock->nNumChars += nLen;12491char* pStr = &pActiveBlock->Chars[MicroProfileSymbolBlock::ESIZE - pActiveBlock->nNumChars - 1];12492memcpy(pStr, pName, nLen);12493pStr[nLen - 1] = '\0';12494MicroProfileSymbolDesc& E = pActiveBlock->Symbols[pActiveBlock->nNumSymbols++];12495MicroProfileHashTableSetPtr(&S.SymbolModules[nModule].AddressToSymbol, (void*)nAddress, &E);1249612497E.pName = pStr;12498E.nAddress = nAddress;12499E.nAddressEnd = nAddressEnd;12500E.nIgnoreSymbol = nIgnoreSymbol;12501E.nModule = nModule;12502if(pShortName && strlen(pShortName))12503{12504pActiveBlock->nNumChars += nLenShort;12505char* pStrShort = &pActiveBlock->Chars[MicroProfileSymbolBlock::ESIZE - pActiveBlock->nNumChars - 1];12506memcpy(pStrShort, pShortName, nLenShort);12507pStrShort[nLenShort - 1] = '\0';12508E.pShortName = pStrShort;12509}12510else12511{12512E.pShortName = E.pName;12513}12514#define SYMDBG 012515#if SYMDBG12516uprintf("Got symbol %lld %lld %f .. %llx %llx %llx %s\n",12517S.SymbolModules[nModule].nProgress,12518S.SymbolModules[nModule].nProgressTarget,12519S.SymbolModules[nModule].nProgressTarget ? float(S.SymbolModules[nModule].nProgress) / float(S.SymbolModules[nModule].nProgressTarget) : 0.f,12520(int64_t)E.nAddress,12521(int64_t)S.SymbolModules[nModule].nAddrBegin,12522(int64_t)S.SymbolModules[nModule].nAddrEnd,12523E.pName);12524if(E.nAddress < (int64_t)S.SymbolModules[nModule].nAddrBegin || E.nAddress > (int64_t)S.SymbolModules[nModule].nAddrEnd)12525{12526MP_BREAK();12527}12528#endif12529E.nMask = MicroProfileCharacterMaskString(E.pShortName);12530MicroProfileCharacterMaskString2(E.pShortName, pActiveBlock->MatchMask);1253112532pActiveBlock->nMask |= E.nMask;12533MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Count", 1);12534if(nIgnoreSymbol)12535{12536MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Ignored", 1);12537}12538#if SYMDBG12539MicroProfileSleep(10);12540#endif12541#undef SYMDBG1254212543S.SymbolModules[nModule].nSymbolsLoaded.fetch_add(1);12544S.nSymbolsDirty.exchange(1);12545S.SymbolState.nSymbolsLoaded.fetch_add(1);12546MP_ASSERT((intptr_t)E.pShortName >= (intptr_t)&E); // assert pointer arithmetic is correct.12547};12548do12549{12550uint32_t nModuleLoad[MICROPROFILE_INSTRUMENT_MAX_MODULES];12551uint32_t nNumModulesRequested = 0;12552for(int i = 0; i < S.SymbolNumModules; ++i)12553{12554if(S.SymbolModules[i].nModuleLoadRequested.load() != 0 && S.SymbolModules[i].nModuleLoadFinished.load() == 0)12555{12556nModuleLoad[nNumModulesRequested] = i;12557S.SymbolModules[i].nProgress = 0;12558MicroProfileHashTableInit(&S.SymbolModules[i].AddressToSymbol, 256, 64, MicroProfileHashTableComparePtr, MicroProfileHashTableHashPtr);12559nNumModulesRequested++;12560}12561}12562if(0 == nNumModulesRequested)12563{12564break;12565}12566MicroProfileIterateSymbols(SymbolCallback, nModuleLoad, nNumModulesRequested);12567S.SymbolState.nModuleLoadsFinished.fetch_add(nNumModulesRequested);12568for(uint32_t i = 0; i < nNumModulesRequested; ++i)12569{12570if(S.SymbolModules[nModuleLoad[i]].nModuleLoadRequested.load() == S.SymbolModules[nModuleLoad[i]].nModuleLoadFinished.load())12571{12572S.SymbolModules[nModuleLoad[i]].nProgress = S.SymbolModules[nModuleLoad[i]].nProgressTarget;12573S.nSymbolsDirty.exchange(1);12574}12575}12576} while(1);12577}1257812579MicroProfileSymbolDesc* MicroProfileSymbolFindFuction(void* pAddress)12580{12581for(int i = 0; i < S.SymbolNumModules; ++i)12582{12583MicroProfileSymbolDesc* pDesc = nullptr;12584if(MicroProfileHashTableGetPtr(&S.SymbolModules[i].AddressToSymbol, pAddress, &pDesc))12585{12586if(0 == pDesc->nIgnoreSymbol)12587return pDesc;12588else12589return nullptr;12590}12591}12592return nullptr;12593}1259412595#define MICROPROFILE_MAX_FILTER 3212596#define MICROPROFILE_MAX_QUERY_RESULTS 3212597#define MICROPROFILE_MAX_FILTER_STRING 10241259812599struct MicroProfileFunctionQuery12600{12601MicroProfileFunctionQuery* pNext;12602uint32_t nState;12603const char* pFilterStrings[MICROPROFILE_MAX_FILTER];12604uint32_t nPatternLength[MICROPROFILE_MAX_FILTER];12605int nMaxFilter;1260612607uint32_t nModuleFilterMatch[MICROPROFILE_INSTRUMENT_MAX_MODULES]; // prematch the modules, so it can be skipped during search12608uint32_t nMask[MICROPROFILE_MAX_FILTER]; // masks for subpatterns skipped12609MicroProfileStringMatchMask MatchMask[MICROPROFILE_MAX_FILTER]; // masks for subpatterns skipped1261012611// results12612MicroProfileSymbolDesc* Results[MICROPROFILE_MAX_QUERY_RESULTS];12613uint32_t nNumResults;12614char FilterString[MICROPROFILE_MAX_FILTER_STRING];1261512616uint32_t QueryId;12617};1261812619MicroProfileFunctionQuery* MicroProfileAllocFunctionQuery()12620{12621MicroProfileScopeLock L(MicroProfileMutex());12622MicroProfileFunctionQuery* pQ = nullptr;12623S.nNumQueryAllocated++;12624if(S.pQueryFreeList != 0)12625{12626pQ = S.pQueryFreeList;12627S.pQueryFreeList = pQ->pNext;12628S.nNumQueryFree--;12629}12630else12631{12632pQ = MP_ALLOC_OBJECT(MicroProfileFunctionQuery);12633MICROPROFILE_COUNTER_ADD("MicroProfile/Symbols/FunctionQuery", 1);12634MICROPROFILE_COUNTER_ADD("MicroProfile/Symbols/FunctionQueryMem", sizeof(MicroProfileFunctionQuery));12635S.nNumQueryAllocated++;12636}12637memset(pQ, 0, sizeof(MicroProfileFunctionQuery));12638return pQ;12639}12640void MicroProfileFreeFunctionQuery(MicroProfileFunctionQuery* pQ)12641{12642pQ->pNext = S.pQueryFreeList;12643S.pQueryFreeList = pQ;12644}1264512646void MicroProfileProcessQuery(MicroProfileFunctionQuery* pQuery)12647{12648MicroProfileFunctionQuery& Q = *pQuery;1264912650int nBlocksTested = 0, nSymbolsTested = 0, nStringsTested = 0, nStringsTested0 = 0;12651int nBlocks = 0;12652// (void)nBlocksTested;12653// (void)nSymbolsTested;12654// (void)nStringsTested;12655// (void)nStringsTested0;12656// (void)nBlocks;1265712658int64_t t = MP_TICK();12659int64_t tt = 0;1266012661for(int i = 0; i < S.SymbolNumModules; ++i)12662{12663int nModule = i;12664uint32_t nModuleMatchOffset = Q.nModuleFilterMatch[nModule];12665MicroProfileSymbolBlock* pSymbols = S.SymbolModules[nModule].pSymbolBlock;1266612667uint32_t nMaskQ = Q.nMask[nModuleMatchOffset];12668MicroProfileStringMatchMask& MatchMaskQ = Q.MatchMask[nModuleMatchOffset];12669{12670while(pSymbols && 0 == S.pPendingQuery && Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS)12671{1267212673MICROPROFILE_SCOPEI("MicroProfile", "SymbolQueryLoop", MP_YELLOW);12674nBlocks++;12675if(MicroProfileCharacterMatch(pSymbols->MatchMask, MatchMaskQ))12676{12677nBlocksTested++;12678for(uint32_t i = 0; i < pSymbols->nNumSymbols && 0 == S.pPendingQuery && Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS; ++i)12679{12680MicroProfileSymbolDesc& E = pSymbols->Symbols[i];12681if(0 == E.nIgnoreSymbol)12682{12683nSymbolsTested++;12684if(nMaskQ == (nMaskQ & E.nMask))12685{12686nStringsTested++;12687MP_ASSERT((int)E.nModule < S.SymbolNumModules);12688if(MicroProfileStringMatch(E.pShortName, nModuleMatchOffset, &Q.pFilterStrings[0], Q.nPatternLength, Q.nMaxFilter))12689{12690if(Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS)12691{1269212693Q.Results[Q.nNumResults++] = &E;12694if(Q.nNumResults == MICROPROFILE_MAX_QUERY_RESULTS)12695tt = MP_TICK();12696}12697}12698if(Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS)12699nStringsTested0++;12700}12701}12702}12703}12704pSymbols = pSymbols->pNext;12705}12706}12707}12708int64_t tend = MP_TICK();12709float ToMS = MicroProfileTickToMsMultiplierCpu();12710float TIME = (tend - t) * ToMS;12711float TIME0 = (tt - t) * ToMS;12712uprintf(" %6.3fms [%6.3f]: %5d/%5d blocks tested. %5d symbols %5d/%5d string compares\n", TIME, TIME0, nBlocksTested, nBlocks, nSymbolsTested, nStringsTested, nStringsTested0);12713}1271412715void* MicroProfileQueryThread(void* p)12716{12717MicroProfileOnThreadCreate("MicroProfileSymbolThread");12718{12719while(1)12720{12721MicroProfileSleep(100); // todo:: use an event instead12722MicroProfileScopeLock L(MicroProfileMutex());12723if(S.pPendingQuery != nullptr)12724{12725MICROPROFILE_SCOPEI("MicroProfile", "SymbolQuery", MP_WHEAT);12726MicroProfileFunctionQuery* pQuery = S.pPendingQuery;1272712728MP_ASSERT(pQuery->QueryId > S.nQueryProcessed);12729S.pPendingQuery = 0;12730L.Unlock();1273112732// uprintf("processing query %d\n", pQuery->QueryId);12733MicroProfileProcessQuery(pQuery);1273412735L.Lock();12736S.nQueryProcessed = MicroProfileMax(pQuery->QueryId, S.nQueryProcessed);1273712738pQuery->pNext = S.pFinishedQuery;12739S.pFinishedQuery = pQuery;12740}12741if(S.SymbolState.nModuleLoadsRequested.load() != S.SymbolState.nModuleLoadsFinished.load())12742{12743L.Unlock();12744MicroProfileSymbolInitializeInternal();12745L.Lock();12746}12747}1274812749S.SymbolThreadFinished = 1;12750}12751MicroProfileOnThreadExit();12752return 0;12753}1275412755void MicroProfileQueryJoinThread()12756{12757if(S.SymbolThreadFinished)12758{12759MicroProfileThreadJoin(&S.SymbolThread);12760S.SymbolThreadFinished = 0;12761S.SymbolThreadRunning = 0;12762}12763}12764void MicroProfileSymbolKickThread()12765{12766// MicroProfileQueryJoinThread();12767if(S.SymbolThreadRunning == 0)12768{12769S.SymbolThreadRunning = 1;12770MicroProfileThreadStart(&S.SymbolThread, MicroProfileQueryThread);12771}12772}12773#if MICROPROFILE_WEBSERVER12774void MicroProfileSymbolSendFunctionNames(MpSocket Connection)12775{12776if(S.WSFunctionsInstrumentedSent < S.DynamicTokenIndex)12777{12778MicroProfileWSPrintStart(Connection);12779MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":[", MSG_FUNCTION_NAMES);12780bool bFirst = true;12781for(uint32_t i = S.WSFunctionsInstrumentedSent; i < S.DynamicTokenIndex; ++i)12782{12783const char* pString = S.FunctionsInstrumentedName[i];12784const char* pModuleString = S.FunctionsInstrumentedModuleNames[i];12785MicroProfileWSPrintf(bFirst ? "[\"%s\",\"%s\",\"%s\"]" : ",[\"%s\",\"%s\",\"%s\"]", pString, pModuleString, "unused");12786bFirst = false;12787}12788MicroProfileWSPrintf("]}");12789MicroProfileWSFlush();12790MicroProfileWSPrintEnd();1279112792S.WSFunctionsInstrumentedSent = S.DynamicTokenIndex;12793}12794}1279512796void MicroProfileSymbolSendErrors(MpSocket Connection)12797{12798if(S.nNumPatchErrors)12799{12800MicroProfileWSPrintStart(Connection);12801MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"version\":\"%d.%d\",\"data\":[", MSG_INSTRUMENT_ERROR, MICROPROFILE_MAJOR_VERSION, MICROPROFILE_MINOR_VERSION);12802bool bFirst = true;12803for(int i = 0; i < S.nNumPatchErrors; ++i)12804{12805MicroProfilePatchError& E = S.PatchErrors[i];12806(void)E;12807if(!bFirst)12808MicroProfileWSPrintf(",");12809MicroProfileWSPrintf("{\"code\":\"");12810for(int i = 0; i < E.nCodeSize; ++i)12811MicroProfileWSPrintf("%02x", E.Code[i] & 0xff);12812MicroProfileWSPrintf("\",\"message\":\"%s\",\"already\":%d}", &E.Message[0], E.AlreadyInstrumented);12813bFirst = false;12814}1281512816MicroProfileWSPrintf("],\"functions\":[");12817bFirst = true;12818for(int i = 0; i < S.nNumPatchErrorFunctions; ++i)12819{12820if(!bFirst)12821MicroProfileWSPrintf(",");1282212823MicroProfileWSPrintf("\"%s\"", S.PatchErrorFunctionNames[i]);1282412825bFirst = false;12826}1282712828MicroProfileWSPrintf("]}}");1282912830MicroProfileWSFlush();12831MicroProfileWSPrintEnd();1283212833S.nNumPatchErrors = 0;12834S.nNumPatchErrorFunctions = 0;12835}12836}1283712838void MicroProfileSymbolQuerySendResult(MpSocket Connection)12839{12840MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolQuerySendResult", MP_PINK2);12841MicroProfileFunctionQuery* pQuery = 0;12842{12843MicroProfileScopeLock L(MicroProfileMutex());1284412845uint32_t nBest = 0;1284612847while(S.pFinishedQuery != nullptr)12848{12849if(!pQuery)12850{12851pQuery = S.pFinishedQuery;12852nBest = pQuery->QueryId;12853S.pFinishedQuery = pQuery->pNext;12854}12855else12856{12857MicroProfileFunctionQuery* pQ = S.pFinishedQuery;12858S.pFinishedQuery = pQ->pNext;12859if(pQ->QueryId > nBest)12860{12861MicroProfileFreeFunctionQuery(pQuery);12862nBest = pQ->QueryId;12863pQuery = pQ;12864}12865else12866{12867MicroProfileFreeFunctionQuery(pQ);12868}12869}12870}12871}1287212873if(pQuery)12874{12875uprintf("Sending result for query %d\n", pQuery->QueryId);12876MicroProfileWSPrintStart(Connection);12877MicroProfileWSPrintf("{\"k\":\"%d\",\"q\":%d,\"v\":[", MSG_FUNCTION_RESULTS, pQuery->QueryId);12878bool bFirst = true;12879for(uint32_t i = 0; i < pQuery->nNumResults; ++i)12880{12881MicroProfileSymbolDesc& E = *pQuery->Results[i];12882if(bFirst)12883{12884MicroProfileWSPrintf("{\"a\":\"%p\",\"n\":\"%s\",\"sn\":\"%s\",\"m\":\"%s\"}", E.nAddress, E.pName, E.pShortName, MicroProfileSymbolModuleGetString(E.nModule));12885bFirst = false;12886}12887else12888{12889MicroProfileWSPrintf(",{\"a\":\"%p\",\"n\":\"%s\",\"sn\":\"%s\",\"m\":\"%s\"}", E.nAddress, E.pName, E.pShortName, MicroProfileSymbolModuleGetString(E.nModule));12890}12891}12892MicroProfileWSPrintf("]}");12893MicroProfileWSFlush();12894MicroProfileWSPrintEnd();1289512896MicroProfileScopeLock L(MicroProfileMutex());12897MicroProfileFreeFunctionQuery(pQuery);12898}12899}12900#endif1290112902void MicroProfileSymbolQueryFunctions(MpSocket Connection, const char* pFilter)12903{12904MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolQueryFunctions", MP_WHEAT);1290512906if(!MicroProfileSymbolInitialize(false))12907{12908return;12909}12910{12911int QueryId = atoi(pFilter);12912pFilter = strchr(pFilter, 'x');12913pFilter++;12914MicroProfileScopeLock L(MicroProfileMutex());12915if(0 == S.pPendingQuery || S.pPendingQuery->QueryId < (uint32_t)QueryId)12916{12917MicroProfileFunctionQuery* pQuery = S.pPendingQuery;12918if(!pQuery)12919{12920S.pPendingQuery = pQuery = MicroProfileAllocFunctionQuery();12921}12922MP_ASSERT(pQuery->pNext == 0);12923memset(pQuery, 0, sizeof(*pQuery));1292412925MicroProfileFunctionQuery& Q = *pQuery;12926Q.QueryId = QueryId;1292712928uint32_t nLen = (uint32_t)strlen(pFilter) + 1;12929if(nLen >= MICROPROFILE_MAX_FILTER_STRING)12930nLen = MICROPROFILE_MAX_FILTER_STRING - 1;1293112932memcpy(Q.FilterString, pFilter, nLen);12933Q.FilterString[nLen] = '\0';1293412935char* pBuffer = Q.FilterString;12936bool bStartString = true;12937for(uint32_t i = 0; i < nLen; ++i)12938{12939char c = pBuffer[i];12940if(c == '\0')12941{12942break;12943}12944if(isspace(c) || c == '*')12945{12946pBuffer[i] = '\0';12947bStartString = true;12948}12949else12950{12951if(bStartString)12952{12953if(Q.nMaxFilter < MICROPROFILE_MAX_FILTER)12954{12955const char* pstr = &pBuffer[i];12956Q.nMask[Q.nMaxFilter] = MicroProfileCharacterMaskString(pstr);12957MicroProfileCharacterMaskString2(pstr, Q.MatchMask[Q.nMaxFilter]);12958Q.pFilterStrings[Q.nMaxFilter++] = &pBuffer[i];12959}12960}12961bStartString = false;12962}12963}12964memset(Q.nModuleFilterMatch, 0xff, sizeof(Q.nModuleFilterMatch));12965for(int i = 0; i < S.SymbolNumModules; ++i)12966{12967Q.nModuleFilterMatch[i] = MicroProfileStringMatchOffset(MicroProfileSymbolModuleGetString(i), Q.pFilterStrings, Q.nPatternLength, Q.nMaxFilter);12968}1296912970#if 012971uprintf("query %d::",QueryId);12972for(int i = 0; i < Q.nMaxFilter; ++i)12973{12974Q.nPatternLength[i] = (uint32_t)strlen(Q.pFilterStrings[i]);12975uprintf("'%s' ", Q.pFilterStrings[i]);12976}12977uprintf("\n");12978#endif12979}12980}12981MicroProfileSymbolKickThread();12982}1298312984#if defined(_WIN32)12985// '##::::'##::'#######:::'#######::'##:::'##::::'##:::::'##:'####:'##::: ##::'#######:::'#######::12986// ##:::: ##:'##.... ##:'##.... ##: ##::'##::::: ##:'##: ##:. ##:: ###:: ##:'##.... ##:'##.... ##:12987// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##: ##: ##:: ##:: ####: ##:..::::: ##:..::::: ##:12988// #########: ##:::: ##: ##:::: ##: #####::::::: ##: ##: ##:: ##:: ## ## ##::'#######:::'#######::12989// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##: ##: ##:: ##:: ##. ####::...... ##:'##::::::::12990// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##: ##: ##:: ##:: ##:. ###:'##:::: ##: ##::::::::12991// ##:::: ##:. #######::. #######:: ##::. ##::::. ###. ###::'####: ##::. ##:. #######:: #########:12992// ..:::::..:::.......::::.......:::..::::..::::::...::...:::....::..::::..:::.......:::.........::1299312994#ifdef _WIN3212995static void* MicroProfileAllocExecutableMemory(void* pBase, size_t s);12996static void* MicroProfileAllocExecutableMemoryFar(size_t s);12997static void MicroProfileMakeMemoryExecutable(void* p, size_t s);12998static void MicroProfileMakeWriteable(void* p_, size_t size, DWORD* oldFlags);12999static void MicroProfileRestore(void* p_, size_t size, DWORD* oldFlags);1300013001extern "C" void microprofile_tramp_enter_patch();13002extern "C" void microprofile_tramp_enter();13003extern "C" void microprofile_tramp_code_begin();13004extern "C" void microprofile_tramp_code_end();13005extern "C" void microprofile_tramp_intercept0();13006extern "C" void microprofile_tramp_end();13007extern "C" void microprofile_tramp_exit();13008extern "C" void microprofile_tramp_leave();13009extern "C" void microprofile_tramp_trunk();13010extern "C" void microprofile_tramp_call_patch_pop();13011extern "C" void microprofile_tramp_call_patch_push();1301213013bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError)13014{13015char* pOriginal = (char*)f;1301613017f = MicroProfileX64FollowJump(f);13018if(MicroProfilePatchHasSuspendedThread((intptr_t)f, (intptr_t)f + 32))13019{13020uprintf("failed to patch, thread running in patch position");13021return false;13022}13023intptr_t t_enter = (intptr_t)microprofile_tramp_enter;13024intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter;13025intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter;13026intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter;13027intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter;13028intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter;13029intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter;1303013031intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter;13032intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter;13033intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset;13034intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter;13035intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter;13036int t_trunk_size = (int)((intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk);1303713038char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset);13039if(!ptramp)13040ptramp = (char*)MicroProfileAllocExecutableMemoryFar(t_end_offset);1304113042intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp);1304313044uint32_t nBytesToCopy = 14;13045if(offset < 0x80000000 && offset > -0x7fffffff)13046{13047/// offset is small enough to insert a relative jump13048nBytesToCopy = 5;13049}1305013051memcpy(ptramp, (void*)t_enter, t_end_offset);1305213053int nInstructionBytesDest = 0;13054char* pInstructionMoveDest = ptramp + t_code_begin_offset;13055char* pTrunk = ptramp + t_trunk_offset;1305613057int nInstructionBytesSrc = 0;13058uint32_t nRegsWritten = 0;13059uint32_t nRetSafe = 1;13060uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11);13061static_assert(R_RAX == 0, "R_RAX must be 0");13062if(!MicroProfileCopyInstructionBytes(13063pInstructionMoveDest, f, nBytesToCopy, (int)codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe))13064{13065if(pError)13066{13067const char* pCode = (const char*)f;13068memset(pError->Code, 0, sizeof(pError->Code));13069memcpy(pError->Code, pCode, nInstructionBytesSrc);13070int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc);13071pError->nCodeSize = nInstructionBytesSrc;13072for(int i = 0; i < nInstructionBytesSrc; ++i)13073{13074off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]);13075}13076uprintf("%s\n", pError->Message);13077}13078return false;13079}1308013081intptr_t phome = nInstructionBytesSrc + (intptr_t)f;13082uint32_t reg = nUsableJumpRegs & ~nRegsWritten;13083if(0 == reg)13084{13085if(0 == nRetSafe)13086MP_BREAK(); // should be caught earlier13087MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome);13088}13089else13090{13091int r = R_RAX;13092while((reg & 1) == 0)13093{13094reg >>= 1;13095r++;13096}13097MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r);13098}1309913100// PATCH 1 TRAMP EXIT13101intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset;13102memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8);1310313104char* pintercept = t_code_intercept0_offset + ptramp;1310513106// PATCH 1.5 Argument13107memcpy(pintercept - 4, (void*)&Argument, 4);1310813109// PATCH 2 INTERCEPT013110intptr_t addr = (intptr_t)enter; //&intercept0;13111memcpy(pintercept + 2, (void*)&addr, 8);1311213113// PATHC 2.5 argument13114memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4);1311513116intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset;13117// PATCH 3 INTERCEPT113118intptr_t addr1 = (intptr_t)leave; //&intercept1;13119memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8);1312013121intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH);13122intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP);13123memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8);13124memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8);13125MicroProfileMakeMemoryExecutable(ptramp, t_end_offset);1312613127{13128// PATCH 4 DEST FUNC1312913130DWORD OldFlags[2] = { 0 };13131MicroProfileMakeWriteable(f, nInstructionBytesSrc, OldFlags);13132char* pp = (char*)f;13133char* ppend = pp + nInstructionBytesSrc;1313413135if(nInstructionBytesSrc < 14)13136{13137pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp);13138}13139else13140{13141pp = MicroProfileInsertRegisterJump((char*)pp, (intptr_t)ptramp, R_RAX);13142}1314313144while(pp != ppend)13145{13146char c = (unsigned char)0x90;13147MP_ASSERT((unsigned char)c == (unsigned char)0x90);13148*pp++ = (unsigned char)0x90;13149}13150MicroProfileRestore(f, nInstructionBytesSrc, OldFlags);13151}13152return true;13153}1315413155static void MicroProfileMakeWriteable(void* p_, size_t s, DWORD* oldFlags)13156{13157static uint64_t nPageSize = 4 << 10;1315813159intptr_t aligned = (intptr_t)p_;13160aligned = (aligned & (~(nPageSize - 1)));13161intptr_t aligned_end = (intptr_t)p_;13162aligned_end += s;13163aligned_end = (aligned_end + nPageSize - 1) & (~(nPageSize - 1));13164uint32_t nNumPages = (uint32_t)((aligned_end - aligned) / nPageSize);13165MP_ASSERT(nNumPages >= 1 && nNumPages <= 2);13166for(uint32_t i = 0; i < nNumPages; ++i)13167{13168if(!VirtualProtect((void*)(aligned + nPageSize * i), nPageSize, PAGE_EXECUTE_READWRITE, oldFlags + i))13169{13170MP_BREAK();13171}13172}13173//*(unsigned char*)p_ = 0x90;13174}1317513176static void MicroProfileRestore(void* p_, size_t s, DWORD* oldFlags)13177{13178static uint64_t nPageSize = 4 << 10;1317913180intptr_t aligned = (intptr_t)p_;13181aligned = (aligned & (~(nPageSize - 1)));13182intptr_t aligned_end = (intptr_t)p_;13183aligned_end += s;13184aligned_end = (aligned_end + nPageSize - 1) & (~(nPageSize - 1));13185uint32_t nNumPages = (uint32_t)((aligned_end - aligned) / nPageSize);13186DWORD Dummy;13187for(uint32_t i = 0; i < nNumPages; ++i)13188{13189if(!VirtualProtect((void*)(aligned + nPageSize * i), nPageSize, oldFlags[i], &Dummy))13190{13191MP_BREAK();13192}13193}13194}1319513196void* MicroProfileAllocExecutableMemoryUp(intptr_t nBase, size_t s, uint32_t RegionIndex)13197{13198SYSTEM_INFO si;13199GetSystemInfo(&si);13200size_t Granularity = si.dwAllocationGranularity << 1;13201nBase = (nBase / Granularity) * Granularity;13202intptr_t nEnd = nBase + 0x80000000;1320313204for(uint32_t i = RegionIndex; i < S.MemoryRegions.Size; i++)13205{13206// try and allocate 2x before13207nBase = S.MemoryRegions[i].Start + S.MemoryRegions[i].Size + Granularity;13208nBase = (nBase / Granularity) * Granularity;1320913210if(nBase >= nEnd)13211break;13212void* pMemory = VirtualAlloc((void*)nBase, s, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);13213if(pMemory)13214{13215return pMemory;13216}13217}13218return nullptr;13219}1322013221static void MicroProfileUpdateMemoryRegions()13222{13223MicroProfileArrayClear(S.MemoryRegions);13224SYSTEM_INFO si;13225GetSystemInfo(&si);1322613227BYTE* Addr = (BYTE*)si.lpMinimumApplicationAddress;13228BYTE* MaxAddr = (BYTE*)si.lpMaximumApplicationAddress;13229// uprintf("updating memory regions\n");13230uint32_t idx = 0;13231(void)idx;13232while(Addr < MaxAddr)13233{13234MEMORY_BASIC_INFORMATION mbi;13235SIZE_T Result = VirtualQuery(Addr, &mbi, sizeof(mbi));13236if(Result == 0)13237break;13238MicroProfileInstrumentMemoryRegion region;13239region.Start = (intptr_t)mbi.BaseAddress;13240region.Size = (intptr_t)mbi.RegionSize;13241MicroProfileArrayPushBack(S.MemoryRegions, region);13242// uprintf("Memory Region %d: %p(%p) %p .. State=%08x Protect=%08x Type=%08x\n", idx++, mbi.BaseAddress, mbi.AllocationBase, (intptr_t)mbi.BaseAddress + mbi.RegionSize, mbi.State, mbi.Protect,13243// mbi.Type);13244Addr = (BYTE*)mbi.BaseAddress + mbi.RegionSize;13245}13246uprintf("Iterated %d regions\n", S.MemoryRegions.Size);13247}1324813249static void* MicroProfileAllocExecutableMemoryDown(intptr_t nBase, size_t s, uint32_t RegionIndex)13250{13251SYSTEM_INFO si;13252GetSystemInfo(&si);13253size_t Granularity = si.dwAllocationGranularity << 1;13254intptr_t nEnd = nBase - 0x80000000;1325513256for(int32_t i = RegionIndex; i >= 0; i--)13257{13258// try and allocate 2x before13259nBase = S.MemoryRegions[i].Start - Granularity;13260nBase = (nBase / Granularity) * Granularity;13261if(nBase < nEnd)13262break;13263void* pMemory = VirtualAlloc((void*)nBase, s, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);13264if(pMemory)13265{13266return pMemory;13267}13268}13269return nullptr;13270}1327113272static void* MicroProfileAllocExecutableMemory(void* pBase, size_t s)13273{13274uint32_t RegionIndex = 0;13275for(uint32_t i = 0; i < S.MemoryRegions.Size; ++i)13276{13277auto& R = S.MemoryRegions[i];13278if(R.Start <= (intptr_t)pBase && (intptr_t)pBase < R.Start + R.Size)13279{13280RegionIndex = i;13281break;13282}13283}1328413285s = (s + 4095) & ~(4095);13286intptr_t nBase = (intptr_t)pBase;13287void* pResult = 0;13288if(0 == pResult && nBase > 0x40000000)13289{13290pResult = MicroProfileAllocExecutableMemoryDown(nBase - 0x40000000, s, RegionIndex);13291if(0 == pResult)13292{13293pResult = MicroProfileAllocExecutableMemoryUp(nBase - 0x40000000, s, RegionIndex);13294}13295}13296if(0 == pResult && nBase < 0xffffffff40000000)13297{13298pResult = MicroProfileAllocExecutableMemoryUp(nBase + 0x40000000, s, RegionIndex);13299if(0 == pResult)13300{13301pResult = MicroProfileAllocExecutableMemoryUp(nBase + 0x40000000, s, RegionIndex);13302}13303}13304return pResult;13305}13306static void* MicroProfileAllocExecutableMemoryFar(size_t s)13307{13308static uint64_t nPageSize = 4 << 10;13309s = (s + (nPageSize - 1)) & (~(nPageSize - 1));1331013311void* pMem = VirtualAlloc(0, s, MEM_COMMIT, PAGE_READWRITE);13312MP_ASSERT(pMem);1331313314// uprintf("Allocating %zu %p\n", s, pMem);13315return pMem;13316}13317static void MicroProfileMakeMemoryExecutable(void* p, size_t s)13318{13319static uint64_t nPageSize = 4 << 10;13320s = (s + (nPageSize - 1)) & (~(nPageSize - 1));13321DWORD Unused;13322if(!VirtualProtect(p, s, PAGE_EXECUTE_READ, &Unused))13323{13324MP_BREAK();13325}13326}13327#endif1332813329int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd)13330{13331const char* pStart = pOutBegin;13332int l = (int)strlen(pStr) - 1;13333int sz = 0;13334pOutEnd--;13335if(l < 1024 && pOutBegin != pOutEnd)13336{13337const char* p = pStr;13338const char* pEnd = pStr + l + 1;13339int in = 0;13340while(p != pEnd && pOutBegin != pOutEnd)13341{13342char c = *p++;13343if(c == '(' || c == '<')13344{13345in++;13346}13347else if(c == ')' || c == '>')13348{13349in--;13350continue;13351}1335213353if(in == 0)13354{13355*pOutBegin++ = c;13356sz++;13357}13358}1335913360*pOutBegin++ = '\0';13361}13362return sz;13363}1336413365int MicroProfileFindFunctionName(const char* pStr, const char** ppStart)13366{13367int l = (int)strlen(pStr) - 1;13368if(l < 1024)13369{13370char b[1024] = { 0 };13371char* put = &b[0];1337213373const char* p = pStr;13374const char* pEnd = pStr + l + 1;13375int in = 0;13376while(p != pEnd)13377{13378char c = *p++;13379if(c == '(' || c == '<')13380{13381in++;13382}13383else if(c == ')' || c == '>')13384{13385in--;13386continue;13387}1338813389if(in == 0)13390{13391*put++ = c;13392}13393}1339413395*put++ = '\0';13396uprintf("trimmed %s\n", b);13397}1339813399// int nFirstParen = l;13400int nNumParen = 0;13401int c = 0;1340213403while(l >= 0 && pStr[l] != ')' && c++ < sizeof(" const") - 1)13404{13405l--;13406}13407if(pStr[l] == ')')13408{13409do13410{13411if(pStr[l] == ')')13412{13413nNumParen++;13414}13415else if(pStr[l] == '(')13416{13417nNumParen--;13418}13419l--;13420} while(nNumParen > 0 && l >= 0);13421}13422else13423{13424*ppStart = pStr;13425return 0;13426}13427while(l >= 0 && isspace(pStr[l]))13428{13429--l;13430}13431int nLast = l;13432while(l >= 0 && !isspace(pStr[l]))13433{13434l--;13435}13436int nFirst = l;13437if(nFirst == nLast)13438return 0;13439int nCount = nLast - nFirst + 1;13440*ppStart = pStr + nFirst;13441return nCount;13442}1344313444#include <dbghelp.h>13445#include <psapi.h>13446#include <tlhelp32.h>13447#include <winternl.h>13448struct MicroProfileQueryContext13449{1345013451const char* pFilterStrings[MICROPROFILE_MAX_FILTER];13452uint32_t nPatternLength[MICROPROFILE_MAX_FILTER];13453int nMaxFilter = 0;13454char TempBuffer[128];13455uint32_t size = 0;13456bool bFirst = false;13457};1345813459BOOL CALLBACK MicroProfileEnumModules(_In_ PCTSTR ModuleName, _In_ DWORD64 BaseOfDll, _In_opt_ PVOID UserContext)13460{1346113462MODULEINFO MI;13463GetModuleInformation(GetCurrentProcess(), (HMODULE)BaseOfDll, &MI, sizeof(MI));13464MEMORY_BASIC_INFORMATION B;13465int r = VirtualQuery((LPCVOID)BaseOfDll, (MEMORY_BASIC_INFORMATION*)&B, sizeof(B));13466char buffer[1024];13467int r1 = GetLastError();13468if(r == 0)13469{13470stbsp_snprintf(buffer, sizeof(buffer) - 1, "Error %d\n", r1);13471OutputDebugString(buffer);13472MP_BREAK();13473}13474MicroProfileSymbolInitModule(ModuleName, BaseOfDll, BaseOfDll + MI.SizeOfImage);13475return true;13476}1347713478namespace13479{13480struct QueryCallbackBase // fucking c++, this is a pain in the ass13481{13482virtual void CB(const char* pName, const char* pShortName, intptr_t addr, intptr_t addrend, uint32_t nModuleId) = 0;13483};13484template <typename T>13485struct QueryCallbackImpl : public QueryCallbackBase13486{13487T t;13488QueryCallbackImpl(T t)13489: t(t)13490{13491}13492virtual void CB(const char* pName, const char* pShortName, intptr_t addr, intptr_t addrend, uint32_t nModuleId)13493{13494t(pName, pShortName, addr, addrend, nModuleId);13495}13496};13497} // namespace1349813499static uint32_t nLastModuleIdWin32 = (uint32_t)-1;13500static intptr_t nLastModuleBaseWin32 = (intptr_t)-1;1350113502BOOL MicroProfileQueryContextEnumSymbols(_In_ PSYMBOL_INFO pSymInfo, _In_ ULONG SymbolSize, _In_opt_ PVOID UserContext)13503{13504uint32_t nModuleId = nLastModuleIdWin32;13505if(nLastModuleBaseWin32 != (intptr_t)pSymInfo->ModBase)13506{13507nLastModuleIdWin32 = nModuleId = MicroProfileSymbolGetModule((const char*)(intptr_t)-2, pSymInfo->ModBase);13508nLastModuleBaseWin32 = (intptr_t)pSymInfo->ModBase;13509}1351013511if(pSymInfo->Tag == 5 || pSymInfo->Tag == 10)13512{1351313514char FunctionName[1024];13515int ret = 0;13516int l = MicroProfileTrimFunctionName(pSymInfo->Name, &FunctionName[0], &FunctionName[1024]);13517QueryCallbackBase* pCB = (QueryCallbackBase*)UserContext;1351813519pCB->CB(pSymInfo->Name, l ? &FunctionName[0] : 0, (intptr_t)pSymInfo->Address, pSymInfo->Size + (intptr_t)pSymInfo->Address, nModuleId);13520}13521return TRUE;13522};1352313524bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size)13525{13526MICROPROFILE_SCOPEI("microprofile", "SymbolDemangle", MP_AUTO);13527if(UnDecorateSymbolName(pName, OutName, Size, UNDNAME_NAME_ONLY))13528{13529return true;13530}13531return false;13532}1353313534bool MicroProfileExtractPdbInfo(HMODULE hMod, GUID& guid, DWORD& age, char pdbName[MAX_PATH])13535{13536struct CV_INFO_PDB7013537{13538DWORD CvSignature; // "RSDS"13539GUID Signature; // GUID13540DWORD Age; // Age13541char PdbFileName[1]; // Null-terminated string13542};1354313544BYTE* base = (BYTE*)hMod;13545IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;13546if(dos->e_magic != IMAGE_DOS_SIGNATURE)13547return false;13548IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);13549if(nt->Signature != IMAGE_NT_SIGNATURE)13550return false;13551auto& dd = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];13552if(!dd.VirtualAddress || !dd.Size)13553return false;13554IMAGE_DEBUG_DIRECTORY* debugDir = (IMAGE_DEBUG_DIRECTORY*)(base + dd.VirtualAddress);13555int count = dd.Size / sizeof(IMAGE_DEBUG_DIRECTORY);13556for(int i = 0; i < count; i++)13557{13558if(debugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)13559{13560auto cv = (CV_INFO_PDB70*)(base + debugDir[i].AddressOfRawData);13561if(cv->CvSignature != 'SDSR')13562continue; // "RSDS"13563guid = cv->Signature;13564age = cv->Age;13565strcpy_s(pdbName, MAX_PATH, cv->PdbFileName);13566return true;13567}13568}13569return false;13570}1357113572bool MicroProfileDownloadPDB(HMODULE Module, HANDLE Process, char outPath[MAX_PATH])13573{13574GUID guid;13575DWORD age;13576char pdbName[MAX_PATH];13577if(!MicroProfileExtractPdbInfo(Module, guid, age, pdbName))13578{13579uprintf("Failed to download pdb\n");13580MP_BREAK();13581return false;13582}13583uprintf("pdb name %s age %d\n", pdbName, age);1358413585FILE* f = fopen(pdbName, "r");13586if(f)13587{13588fclose(f);13589strcpy_s(outPath, MAX_PATH, pdbName);13590return true;13591}13592char localPath[MAX_PATH] = {};13593BOOL ok = SymFindFileInPath(Process,13594NULL,13595pdbName,13596(PVOID)&guid, // GUID13597age, // Age135980, // FileSize (not used for PDBs)13599SSRVOPT_GUIDPTR, // we're passing GUID pointer13600outPath,13601NULL,13602NULL);13603return ok != 0;13604}1360513606#include "PDB.h"13607#include "PDB_DBIStream.h"13608#include "PDB_IPIStream.h"13609#include "PDB_InfoStream.h"13610#include "PDB_NamesStream.h"13611#include "PDB_RawFile.h"13612#include "PDB_TPIStream.h"1361313614template <typename Callback>13615void MicroProfileLoadRawPDB(Callback CB, const char* Filename, uint64_t Base, uint32_t nModuleId)13616{13617auto OnSymbol = [CB, Base, nModuleId](const char* Sym, uint32_t Offset, uint32_t Size)13618{13619char FunctionName[1024];13620int ret = 0;13621int l = MicroProfileTrimFunctionName(Sym, &FunctionName[0], &FunctionName[1024]);13622const char* fname = l ? &FunctionName[0] : nullptr;13623CB(Sym, fname, (intptr_t)Offset + Base, (intptr_t)Offset + Base + Size, nModuleId);13624};1362513626void* File = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, nullptr);1362713628if(File == INVALID_HANDLE_VALUE)13629{13630MP_BREAK();13631}1363213633void* FileMapping = CreateFileMappingA(File, nullptr, PAGE_READONLY, 0, 0, nullptr);1363413635if(FileMapping == nullptr)13636{13637CloseHandle(File);13638MP_BREAK();13639}1364013641void* BaseAddress = MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);1364213643if(BaseAddress == nullptr)13644{13645CloseHandle(FileMapping);13646CloseHandle(File);13647}1364813649BY_HANDLE_FILE_INFORMATION FileInformation;13650const bool GetInformationResult = GetFileInformationByHandle(File, &FileInformation);13651if(!GetInformationResult)13652{13653UnmapViewOfFile(BaseAddress);13654CloseHandle(FileMapping);13655CloseHandle(File);1365613657MP_BREAK();13658}1365913660const size_t FileSizeHighBytes = static_cast<size_t>(FileInformation.nFileSizeHigh) << 32;13661const size_t FileSizeLowBytes = FileInformation.nFileSizeLow;13662const size_t FileSize = FileSizeHighBytes | FileSizeLowBytes;1366313664const PDB::RawFile RawPdbFile = PDB::CreateRawFile(BaseAddress);13665if(PDB::HasValidDBIStream(RawPdbFile) != PDB::ErrorCode::Success)13666{13667MP_BREAK();13668}13669const PDB::InfoStream InfoStream(RawPdbFile);13670if(InfoStream.UsesDebugFastLink())13671{13672MP_BREAK();13673}1367413675// const PDB::Header* h = InfoStream.GetHeader();13676// uprintf("Version %u, signature %u, age %u, GUID %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n",13677// static_cast<uint32_t>(h->version), h->signature, h->age,13678// h->guid.Data1, h->guid.Data2, h->guid.Data3,13679// h->guid.Data4[0], h->guid.Data4[1], h->guid.Data4[2], h->guid.Data4[3], h->guid.Data4[4], h->guid.Data4[5], h->guid.Data4[6], h->guid.Data4[7]);1368013681const PDB::DBIStream DbiStream = PDB::CreateDBIStream(RawPdbFile);13682if(PDB::ErrorCode::Success != DbiStream.HasValidSymbolRecordStream(RawPdbFile))13683{13684MP_BREAK();13685}1368613687if(PDB::ErrorCode::Success != DbiStream.HasValidPublicSymbolStream(RawPdbFile))13688{13689MP_BREAK();13690}1369113692if(PDB::ErrorCode::Success != DbiStream.HasValidGlobalSymbolStream(RawPdbFile))13693{13694MP_BREAK();13695}1369613697if(PDB::ErrorCode::Success != DbiStream.HasValidSectionContributionStream(RawPdbFile))13698{13699MP_BREAK();13700}1370113702if(PDB::ErrorCode::Success != DbiStream.HasValidImageSectionStream(RawPdbFile))13703{13704MP_BREAK();13705}1370613707const PDB::ImageSectionStream ImageSectionStream = DbiStream.CreateImageSectionStream(RawPdbFile);13708const PDB::ModuleInfoStream ModuleInfoStream = DbiStream.CreateModuleInfoStream(RawPdbFile);13709const PDB::CoalescedMSFStream SymbolRecordStream = DbiStream.CreateSymbolRecordStream(RawPdbFile);1371013711const PDB::ArrayView<PDB::ModuleInfoStream::Module> modules = ModuleInfoStream.GetModules();1371213713for(const PDB::ModuleInfoStream::Module& module : modules)13714{13715if(!module.HasSymbolStream())13716{13717continue;13718}1371913720const PDB::ModuleSymbolStream moduleSymbolStream = module.CreateSymbolStream(RawPdbFile);13721moduleSymbolStream.ForEachSymbol(13722[&ImageSectionStream, &OnSymbol](const PDB::CodeView::DBI::Record* record)13723{13724// only grab function symbols from the module streams13725const char* name = nullptr;13726uint32_t rva = 0u;13727uint32_t size = 0u;13728if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_FRAMEPROC)13729{13730// functionSymbols[functionSymbols.size() - 1].frameProc = record;13731return;13732}13733else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_THUNK32)13734{13735if(record->data.S_THUNK32.thunk == PDB::CodeView::DBI::ThunkOrdinal::TrampolineIncremental)13736{13737// we have never seen incremental linking thunks stored inside a S_THUNK32 symbol, but better safe than sorry13738name = "ILT";13739rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_THUNK32.section, record->data.S_THUNK32.offset);13740size = 5u;13741}13742}13743else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_TRAMPOLINE)13744{13745// incremental linking thunks are stored in the linker module13746name = "ILT";13747rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_TRAMPOLINE.thunkSection, record->data.S_TRAMPOLINE.thunkOffset);13748size = 5u;13749}13750else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_LPROC32)13751{13752name = record->data.S_LPROC32.name;13753rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_LPROC32.section, record->data.S_LPROC32.offset);13754size = record->data.S_LPROC32.codeSize;13755}13756else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_GPROC32)13757{13758name = record->data.S_GPROC32.name;13759rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_GPROC32.section, record->data.S_GPROC32.offset);13760size = record->data.S_GPROC32.codeSize;13761}13762else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_LPROC32_ID)13763{13764name = record->data.S_LPROC32_ID.name;13765rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_LPROC32_ID.section, record->data.S_LPROC32_ID.offset);13766size = record->data.S_LPROC32_ID.codeSize;13767}13768else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_GPROC32_ID)13769{13770name = record->data.S_GPROC32_ID.name;13771rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_GPROC32_ID.section, record->data.S_GPROC32_ID.offset);13772size = record->data.S_GPROC32_ID.codeSize;13773}1377413775if(rva == 0u)13776{13777return;13778}13779// uprintf("func %p / %d .. %s \n", rva, size, name);13780OnSymbol(name, rva, size);13781});13782}13783const PDB::PublicSymbolStream PublicSymbolStream = DbiStream.CreatePublicSymbolStream(RawPdbFile);13784{13785const PDB::ArrayView<PDB::HashRecord> HashRecords = PublicSymbolStream.GetRecords();13786const size_t Count = HashRecords.GetLength();1378713788for(const PDB::HashRecord& HashRecord : HashRecords)13789{13790const PDB::CodeView::DBI::Record* Record = PublicSymbolStream.GetRecord(SymbolRecordStream, HashRecord);13791if(Record->header.kind != PDB::CodeView::DBI::SymbolRecordKind::S_PUB32)13792{13793continue;13794}1379513796if((PDB_AS_UNDERLYING(Record->data.S_PUB32.flags) & PDB_AS_UNDERLYING(PDB::CodeView::DBI::PublicSymbolFlags::Function)) == 0u)13797{13798continue;13799}1380013801const uint32_t rva = ImageSectionStream.ConvertSectionOffsetToRVA(Record->data.S_PUB32.section, Record->data.S_PUB32.offset);13802if(rva == 0u)13803{13804continue;13805}13806OnSymbol(Record->data.S_PUB32.name, rva, 0);13807}13808}13809UnmapViewOfFile(BaseAddress);13810CloseHandle(FileMapping);13811CloseHandle(File);13812}1381313814bool MicroProfilePatchHasSuspendedThread(intptr_t Begin, intptr_t End)13815{13816MicroProfileSuspendState& State = S.SuspendState;13817for(uint32_t i = 0; i < State.NumSuspended; ++i)13818{13819intptr_t ip = State.SuspendedIP[i];13820if(Begin <= ip && ip <= End)13821return true;13822}13823return false;13824}1382513826bool MicroProfilePatchBeginSuspend()13827{13828MicroProfileSuspendState& State = S.SuspendState;1382913830if(State.SuspendCounter++ > 0)13831return true;13832MicroProfileUpdateMemoryRegions();1383313834MicroProfileMutex().lock();13835MP_ASSERT(State.NumSuspended == 0);1383613837DWORD ProcessId = GetCurrentProcessId();13838DWORD ThreadId = GetCurrentThreadId();1383913840HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);13841if(hSnap == INVALID_HANDLE_VALUE)13842{13843return false;13844}13845THREADENTRY32 te{};13846te.dwSize = sizeof(te);13847State.NumSuspended = 0;1384813849if(Thread32First(hSnap, &te))13850{13851do13852{13853if(te.th32OwnerProcessID != ProcessId)13854continue;13855if(te.th32ThreadID == ThreadId)13856continue;13857HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID);13858if(!hThread)13859{13860continue;13861}13862DWORD PrevCount = SuspendThread(hThread);13863if(PrevCount == (DWORD)-1)13864{13865CloseHandle(hThread);13866continue;13867}1386813869CONTEXT ctx{};13870ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; // Rip + registers13871if(GetThreadContext(hThread, &ctx))13872{13873State.SuspendedIP[State.NumSuspended] = (intptr_t)ctx.Rip;13874}13875if(State.NumSuspended < MICROPROFILE_SUSPEND_MAX)13876{13877State.Suspended[State.NumSuspended++] = hThread;13878}13879} while(Thread32Next(hSnap, &te));13880}13881else13882{13883uprintf("Thread32First failed %08x\n", GetLastError());13884CloseHandle(hSnap);13885return false;13886}13887CloseHandle(hSnap);13888return State.NumSuspended > 0;13889}1389013891void MicroProfilePatchEndSuspend()13892{13893MicroProfileSuspendState& State = S.SuspendState;13894if(0 == --State.SuspendCounter)13895{1389613897for(uint32_t i = 0; i < State.NumSuspended; ++i)13898{13899ResumeThread(State.Suspended[i]);13900CloseHandle(State.Suspended[i]);13901}13902State.NumSuspended = 0;13903MicroProfileMutex().unlock();13904}13905}1390613907template <typename Callback>13908void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules)13909{13910MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3);13911QueryCallbackImpl<Callback> Context(CB);13912if(MicroProfileSymInit())13913{13914// uprintf("symbols loaded!\n");13915// API_VERSION* pv = ImagehlpApiVersion();13916// uprintf("VERSION %d.%d.%d\n", pv->MajorVersion, pv->MinorVersion, pv->Revision);1391713918nLastModuleBaseWin32 = -1;13919if(SymEnumerateModules64(GetCurrentProcess(), (PSYM_ENUMMODULES_CALLBACK64)MicroProfileEnumModules, NULL))13920{13921}13922QueryCallbackBase* pBase = &Context;13923if(nNumModules)13924{13925HANDLE hProcess = GetCurrentProcess();13926char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];13927PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;13928uint64_t t0 = MP_TICK();13929for(uint32_t i = 0; i < nNumModules; ++i)13930{13931uint32_t nModule = nModules[i];13932int64_t nBytes = 0;13933MEMORY_BASIC_INFORMATION B;1393413935for(int j = 0; j < S.SymbolModules[nModule].nNumExecutableRegions; ++j)13936{13937intptr_t b = S.SymbolModules[nModule].Regions[j].nBegin;13938intptr_t e = S.SymbolModules[nModule].Regions[j].nEnd;13939while(b < e)13940{13941int r = VirtualQuery((LPCVOID)b, &B, sizeof(B));13942if(!r)13943break;13944switch(B.Protect)13945{13946case PAGE_EXECUTE:13947case PAGE_EXECUTE_READ:13948case PAGE_EXECUTE_READWRITE:13949case PAGE_EXECUTE_WRITECOPY:13950nBytes += B.RegionSize;13951// uprintf("RANGE %p, %p .. %5.2fkb %08x, %08x\n", B.BaseAddress, (void*)(intptr_t(B.BaseAddress) + B.RegionSize), B.RegionSize / 1024.f, B.State, B.Protect);13952}13953b = intptr_t(B.BaseAddress) + B.RegionSize;13954}13955}13956S.SymbolModules[nModule].nProgressTarget = nBytes;1395713958char pdbPath[MAX_PATH];13959HMODULE Module = (HMODULE)S.SymbolModules[nModule].nModuleBase;13960S.nSymbolsDirty++;13961S.SymbolModules[nModule].bDownloading = true;13962if(MicroProfileDownloadPDB(Module, hProcess, pdbPath))13963{13964S.SymbolModules[nModule].bDownloading = false;13965S.nSymbolsDirty++;13966MicroProfileLoadRawPDB<Callback>(CB, pdbPath, S.SymbolModules[nModule].nModuleBase, nModule);13967}13968S.SymbolModules[nModule].bDownloading = false;13969S.nSymbolsDirty++;13970S.SymbolModules[nModule].nProgress = S.SymbolModules[nModule].nProgressTarget;13971S.SymbolModules[nModule].nModuleLoadFinished.exchange(1);13972}1397313974uint64_t t1 = MP_TICK();13975float fTime = float(MicroProfileTickToMsMultiplierCpu()) * (t1 - t0);13976uprintf("load symbol time %6.2fms\n", fTime);13977}13978MicroProfileSymCleanup();13979}13980}1398113982static int MicroProfileWin32SymInitCount = 0;13983static int MicroProfileWin32SymInitSuccess = 0;1398413985bool MicroProfileSymInit()13986{13987if(0 == MicroProfileWin32SymInitCount++)13988{13989auto h = GetCurrentProcess();13990SymCleanup(h);13991SymSetOptions(SYMOPT_DEFERRED_LOADS);13992if(SymInitialize(h, 0, FALSE))13993{1399413995MicroProfileWin32SymInitSuccess = 1;13996char Path[MAX_PATH];13997bool PathValid = SymGetSearchPath(h, Path, MAX_PATH) > 0;13998if(PathValid)13999{14000PathValid = strlen(Path) > 3;14001}14002if(!PathValid)14003{14004SymSetSearchPath(h, "srv*C:\\symbols*https://msdl.microsoft.com/download/symbols");14005}14006}14007else14008{14009MicroProfileWin32SymInitSuccess = 0;14010}14011}14012return MicroProfileWin32SymInitSuccess != 0;14013}14014void MicroProfileSymCleanup()14015{14016if(0 == --MicroProfileWin32SymInitCount)14017{14018MicroProfileWin32SymInitSuccess = 0;14019SymCleanup(GetCurrentProcess());14020}14021}1402214023static void* g_pFunctionFoundHack = 0;14024static const char* g_pFunctionpNameFound = 0;14025static char g_Demangled[512];1402614027BOOL MicroProfileQueryContextEnumSymbols1(_In_ PSYMBOL_INFO pSymInfo, _In_ ULONG SymbolSize, _In_opt_ PVOID UserContext)14028{14029if(pSymInfo->Tag == 5 || pSymInfo->Tag == 10)14030{14031char str[200];14032stbsp_snprintf(str, sizeof(str) - 1, "%s : %p\n", pSymInfo->Name, (void*)pSymInfo->Address);14033OutputDebugStringA(str);14034g_pFunctionpNameFound = pSymInfo->Name;14035g_pFunctionFoundHack = (void*)pSymInfo->Address;14036return FALSE;14037}14038return TRUE;14039};1404014041const char* MicroProfileDemangleSymbol(const char* pSymbol)14042{14043return pSymbol; // todo: for some reasons all symbols im seaing right now are already undecorated?14044}1404514046void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols)14047{14048char SymString[512];14049const char* pStr = 0;14050if(MicroProfileSymInit())14051{14052HANDLE h = GetCurrentProcess();14053for(uint32_t i = 0; i < nNumSymbols; ++i)14054{14055int nCount = stbsp_snprintf(SymString, sizeof(SymString) - 1, "%s!%s", pModules[i], pSymbols[i]);14056if(nCount <= sizeof(SymString) - 1)14057{14058g_pFunctionFoundHack = 0;14059if(SymEnumSymbols(h, 0, SymString, MicroProfileQueryContextEnumSymbols1, 0))14060{14061if(g_pFunctionFoundHack)14062{14063uint32_t nColor = MicroProfileColorFromString(pSymbols[i]);14064const char* pDemangled = pSymbols[i]; // MicroProfileDemangleSymbol(pSymbols[i]);14065MicroProfileInstrumentFunction(g_pFunctionFoundHack, pModules[i], pDemangled, nColor);14066}14067}14068}14069}14070MicroProfileSymCleanup();14071}14072}1407314074void MicroProfileSymbolEnumModules()14075{14076HMODULE modules[1024];14077DWORD needed;14078HANDLE h = GetCurrentProcess();1407914080if(EnumProcessModules(h, modules, sizeof(modules), &needed))14081{14082int count = needed / sizeof(HMODULE);14083for(int i = 0; i < count; i++)14084{14085char moduleName[MAX_PATH];14086if(GetModuleFileNameEx(h, modules[i], moduleName, MAX_PATH))14087{14088MODULEINFO mi = {};14089if(GetModuleInformation(h, modules[i], &mi, sizeof(mi)))14090{14091MicroProfileEnumModules(moduleName, (DWORD64)mi.lpBaseOfDll, 0);14092}14093}14094}14095}14096}1409714098void MicroProfileSymbolUpdateModuleList()14099{14100MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolUpdateModuleList", MP_PINK3);14101// QueryCallbackImpl<Callback> Context(CB);14102if(MicroProfileSymInit())14103{14104uprintf("symbols loaded!\n");14105API_VERSION* pv = ImagehlpApiVersion();14106uprintf("VERSION %d.%d.%d\n", pv->MajorVersion, pv->MinorVersion, pv->Revision);1410714108nLastModuleBaseWin32 = -1;14109MicroProfileSymbolEnumModules();14110MicroProfileSymCleanup();14111}14112}1411314114#endif1411514116#if defined(__APPLE__) && defined(__MACH__)14117// '##::::'##::'#######:::'#######::'##:::'##:::::'#######:::'######::'##::::'##:14118// ##:::: ##:'##.... ##:'##.... ##: ##::'##:::::'##.... ##:'##... ##:. ##::'##::14119// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::: ##: ##:::..:::. ##'##:::14120// #########: ##:::: ##: ##:::: ##: #####::::::: ##:::: ##:. ######::::. ###::::14121// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##:::: ##::..... ##::: ## ##:::14122// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##:::: ##:'##::: ##:: ##:. ##::14123// ##:::: ##:. #######::. #######:: ##::. ##::::. #######::. ######:: ##:::. ##:14124// ..:::::..:::.......::::.......:::..::::..::::::.......::::......:::..:::::..::1412514126#include <cxxabi.h>14127#include <distorm.h>14128#include <dlfcn.h>14129#include <mach/mach.h>14130#include <mach/mach_vm.h>14131#include <mnemonics.h>14132#include <sys/mman.h>14133#include <unistd.h>1413414135static void* MicroProfileAllocExecutableMemory(void* f, size_t s);14136static void MicroProfileMakeWriteable(void* p_);1413714138extern "C" void microprofile_tramp_enter_patch();14139extern "C" void microprofile_tramp_enter();14140extern "C" void microprofile_tramp_code_begin();14141extern "C" void microprofile_tramp_code_end();14142extern "C" void microprofile_tramp_intercept0();14143extern "C" void microprofile_tramp_end();14144extern "C" void microprofile_tramp_exit();14145extern "C" void microprofile_tramp_leave();14146extern "C" void microprofile_tramp_trunk();14147extern "C" void microprofile_tramp_call_patch_pop();14148extern "C" void microprofile_tramp_call_patch_push();1414914150bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError) __attribute__((optnone))14151{14152if(pError)14153{14154memcpy(&pError->Code[0], f, 12);14155}1415614157intptr_t t_enter = (intptr_t)microprofile_tramp_enter;14158intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter;14159intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter;14160intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter;14161intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter;14162intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter;14163intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter;1416414165intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter;14166intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter;14167intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset;14168intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter;14169intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter;14170intptr_t t_trunk_size = (intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk;1417114172char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset);1417314174intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp);1417514176uint32_t nBytesToCopy = 14;14177if(offset < 0x80000000 && offset > -0x7fffffff)14178{14179/// offset is small enough to insert a relative jump14180nBytesToCopy = 5;14181}1418214183memcpy(ptramp, (void*)t_enter, t_end_offset);1418414185int nInstructionBytesDest = 0;14186char* pInstructionMoveDest = ptramp + t_code_begin_offset;14187char* pTrunk = ptramp + t_trunk_offset;1418814189int nInstructionBytesSrc = 0;1419014191uint32_t nRegsWritten = 0;14192uint32_t nRetSafe = 0;14193uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11); // scratch && !parameter register14194if(!MicroProfileCopyInstructionBytes(14195pInstructionMoveDest, f, nBytesToCopy, codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe))14196{14197if(pError)14198{14199const char* pCode = (const char*)f;14200memset(pError->Code, 0, sizeof(pError->Code));14201memcpy(pError->Code, pCode, nInstructionBytesSrc);14202int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc);14203pError->nCodeSize = nInstructionBytesSrc;14204for(int i = 0; i < nInstructionBytesSrc; ++i)14205{14206off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]);14207}14208uprintf("%s\n", pError->Message);14209}14210return false;14211}14212intptr_t phome = nInstructionBytesSrc + (intptr_t)f;14213uint32_t reg = nUsableJumpRegs & ~nRegsWritten;14214static_assert(R_RAX == 0, "R_RAX must be 0");14215if(0 == reg)14216{14217if(nRetSafe == 0)14218{14219MP_BREAK(); // shout fail earlier14220}14221MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome);14222}14223else14224{14225int r = R_RAX;14226while((reg & 1) == 0)14227{14228reg >>= 1;14229r++;14230}14231MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r);14232}1423314234// PATCH 1 TRAMP EXIT14235intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset;14236memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8);1423714238char* pintercept = t_code_intercept0_offset + ptramp;1423914240// PATCH 1.5 Argument14241memcpy(pintercept - 4, (void*)&Argument, 4);1424214243// PATCH 2 INTERCEPT014244intptr_t addr = (intptr_t)enter; //&intercept0;14245memcpy(pintercept + 2, (void*)&addr, 8);1424614247// PATHC 2.5 argument14248memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4);1424914250intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset;14251// PATCH 3 INTERCEPT114252intptr_t addr1 = (intptr_t)leave; //&intercept1;14253memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8);1425414255intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH);14256intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP);14257memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8);14258memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8);1425914260{14261// PATCH 4 DEST FUNC1426214263MicroProfileMakeWriteable(f);14264char* pp = (char*)f;14265char* ppend = pp + nInstructionBytesSrc;14266if(nInstructionBytesSrc < 14)14267{14268uprintf("inserting 5b jump\n");14269pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp);14270}14271else14272{14273uprintf("inserting 14b jump\n");14274pp = MicroProfileInsertRegisterJump(pp, (intptr_t)ptramp, R_RAX);14275}14276while(pp != ppend)14277{14278*pp++ = 0x90;14279}14280}14281return true;14282}1428314284static void MicroProfileMakeWriteable(void* p_)14285{14286#ifdef _PATCH_TEST14287// for testing..14288static const uint32_t WritableSize = 16;14289static uint32_t WritableCount = 0;14290static intptr_t WritableStart[WritableSize] = { 0 };14291static intptr_t WritableEnd[WritableSize] = { 0 };14292for(uint32_t i = 0; i < WritableCount; ++i)14293{14294intptr_t x = (intptr_t)p_;14295if(x >= WritableStart[i] && x < WritableEnd[i])14296{14297return;14298}14299}1430014301#endif1430214303intptr_t p = (intptr_t)p_;14304// uprintf("MicroProfilemakewriteable %lx\n", p);14305mach_port_name_t task = mach_task_self();14306vm_map_offset_t vmoffset = 0;14307mach_vm_size_t vmsize = 0;14308uint32_t nd;14309kern_return_t kr;14310vm_region_submap_info_64 vbr;14311mach_msg_type_number_t vbrcount = sizeof(vbr) / 4;1431214313while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount)))14314{14315if(p >= (intptr_t)vmoffset && p <= intptr_t(vmoffset + vmsize))14316{14317if(0 == (vbr.protection & VM_PROT_WRITE))14318{14319// uprintf("region match .. enabling write\n");14320int x = mprotect((void*)vmoffset, vmsize, PROT_WRITE | PROT_READ | PROT_EXEC);14321if(x)14322{14323// uprintf("mprotect failed ... err %d:: %d %s\n", errno, x, strerror(errno));14324}14325else14326{14327uprintf("region is [%llx,%llx] .. %08llx %d", vmoffset, vmoffset + vmsize, vmsize, vbr.is_submap);14328uprintf("prot: %c%c%c %c%c%c\n",14329vbr.protection & VM_PROT_READ ? 'r' : '-',14330vbr.protection & VM_PROT_WRITE ? 'w' : '-',14331vbr.protection & VM_PROT_EXECUTE ? 'x' : '-',1433214333vbr.max_protection & VM_PROT_READ ? 'r' : '-',14334vbr.max_protection & VM_PROT_WRITE ? 'w' : '-',14335vbr.max_protection & VM_PROT_EXECUTE ? 'x' : '-');14336continue;14337}14338}14339else14340{14341#ifdef _PATCH_TEST14342if(WritableCount < WritableSize)14343{14344WritableStart[WritableCount] = vmoffset;14345WritableEnd[WritableCount] = vmoffset + vmsize;14346WritableCount++;14347}1434814349#endif14350}14351}1435214353vmoffset += vmsize;14354vbrcount = sizeof(vbr) / 4;14355}14356}1435714358int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd)14359{14360int l = strlen(pStr) - 1;14361int sz = 0;14362pOutEnd--;14363if(l < pOutEnd - pOutBegin && pOutBegin != pOutEnd)14364{14365const char* p = pStr;14366const char* pEnd = pStr + l + 1;14367int in = 0;14368while(p != pEnd && pOutBegin != pOutEnd)14369{14370char c = *p++;14371if(c == '(' || c == '<')14372{14373in++;14374}14375else if(c == ')' || c == '>')14376{14377in--;14378continue;14379}1438014381if(in == 0)14382{14383*pOutBegin++ = c;14384sz++;14385}14386}1438714388*pOutBegin++ = '\0';14389}14390return sz;14391}1439214393int MicroProfileFindFunctionName(const char* pStr, const char** ppStart)14394{14395int l = strlen(pStr) - 1;14396if(l < 1024)14397{14398char b[1024] = { 0 };14399char* put = &b[0];1440014401const char* p = pStr;14402const char* pEnd = pStr + l + 1;14403int in = 0;14404while(p != pEnd)14405{14406char c = *p++;14407if(c == '(' || c == '<')14408{14409in++;14410}14411else if(c == ')' || c == '>')14412{14413in--;14414continue;14415}1441614417if(in == 0)14418{14419*put++ = c;14420}14421}1442214423*put++ = '\0';14424uprintf("trimmed %s\n", b);14425}1442614427// int nFirstParen = l;14428int nNumParen = 0;14429int c = 0;1443014431while(l >= 0 && pStr[l] != ')' && c++ < (int)(sizeof(" const") - 1))14432{14433l--;14434}14435if(pStr[l] == ')')14436{14437do14438{14439if(pStr[l] == ')')14440{14441nNumParen++;14442}14443else if(pStr[l] == '(')14444{14445nNumParen--;14446}14447l--;14448} while(nNumParen > 0 && l >= 0);14449}14450else14451{14452*ppStart = pStr;14453return 0;14454}14455while(l >= 0 && isspace(pStr[l]))14456{14457--l;14458}14459int nLast = l;14460while(l >= 0 && !isspace(pStr[l]))14461{14462l--;14463}14464int nFirst = l;14465if(nFirst == nLast)14466return 0;14467int nCount = nLast - nFirst + 1;14468*ppStart = pStr + nFirst;14469return nCount;14470}1447114472const char* MicroProfileDemangleSymbol(const char* pSymbol)14473{14474static unsigned long size = 128;14475static char* pTempBuffer = (char*)malloc(size); // needs to be malloc because demangle function might realloc it.14476unsigned long len = size;14477int ret = 0;14478char* pBuffer = pTempBuffer;14479pBuffer = abi::__cxa_demangle(pSymbol, pTempBuffer, &len, &ret);14480if(ret == 0)14481{14482if(pBuffer != pTempBuffer)14483{14484pTempBuffer = pBuffer;14485if(len < size)14486__builtin_trap();14487size = len;14488}14489return pTempBuffer;14490}14491else14492{14493return pSymbol;14494}14495}1449614497template <typename Callback>14498void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules)14499{14500MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3);14501char FunctionName[1024];14502(void)FunctionName;14503mach_port_name_t task = mach_task_self();14504vm_map_offset_t vmoffset = 0;14505mach_vm_size_t vmsize = 0;14506uint32_t nd;14507kern_return_t kr;14508vm_region_submap_info_64 vbr;14509mach_msg_type_number_t vbrcount = sizeof(vbr) / 4;1451014511intptr_t nCurrentModule = -1;14512uint32_t nCurrentModuleId = -1;1451314514auto OnFunction = [&](void* addr, void* addrend, const char* pSymbol, const char* pModuleName, void* pModuleAddr) -> bool14515{14516const char* pStr = MicroProfileDemangleSymbol(pSymbol);14517;14518int l = MicroProfileTrimFunctionName(pStr, &FunctionName[0], &FunctionName[1024]);14519if(nCurrentModule != (intptr_t)pModuleAddr)14520{14521nCurrentModule = (intptr_t)pModuleAddr;14522nCurrentModuleId = MicroProfileSymbolGetModule(pModuleName, nCurrentModule);14523}1452414525CB(l ? &FunctionName[0] : pStr, l ? &FunctionName[0] : 0, (intptr_t)addr, (intptr_t)addrend, nCurrentModuleId);14526return true;14527};14528vm_offset_t addr_prev = 0;1452914530while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount)))14531{14532{14533addr_prev = vmoffset + vmsize;14534if(0 != (vbr.protection & VM_PROT_EXECUTE))14535{14536bool bProcessModule = true;14537int nModule = -1;14538if(nNumModules)14539{14540bProcessModule = false;14541for(uint32_t i = 0; i < nNumModules; ++i)14542{14543intptr_t nBase = S.SymbolModules[nModules[i]].Regions[0].nBegin;14544if((intptr_t)vmoffset == nBase)14545{14546bProcessModule = true;14547nModule = nModules[i];14548break;14549}14550}14551}14552if(bProcessModule)14553{14554S.SymbolModules[nModule].nProgressTarget = S.SymbolModules[nModule].Regions[0].nEnd - S.SymbolModules[nModule].Regions[0].nBegin;14555dl_info di;14556int r = 0;14557r = dladdr((void*)vmoffset, &di);14558if(r)14559{14560OnFunction(di.dli_saddr, (void*)addr_prev, di.dli_sname, di.dli_fname, di.dli_fbase);14561}14562intptr_t addr = vmoffset + vmsize - 1;14563while(1)14564{14565r = dladdr((void*)(addr), &di);14566if(r)14567{14568if(!di.dli_sname)14569{14570break;14571}14572OnFunction(di.dli_saddr, (void*)addr_prev, di.dli_sname, di.dli_fname, di.dli_fbase);14573}14574else14575{14576break;14577}14578addr_prev = (vm_offset_t)di.dli_saddr;14579addr = (intptr_t)di.dli_saddr - 1;14580if(di.dli_saddr < (void*)vmoffset)14581{14582break;14583}14584}14585for(int i = 0; i < S.SymbolNumModules; ++i)14586{14587if(S.SymbolModules[i].Regions[0].nBegin == (intptr_t)vmoffset)14588{14589S.SymbolModules[i].nModuleLoadFinished.store(1);14590}14591}14592}14593}14594}14595vmoffset += vmsize;14596vbrcount = sizeof(vbr) / 4;14597}14598}1459914600void MicroProfileSymbolUpdateModuleList()14601{14602char FunctionName[1024];14603(void)FunctionName;14604mach_port_name_t task = mach_task_self();14605vm_map_offset_t vmoffset = 0;14606mach_vm_size_t vmsize = 0;14607uint32_t nd;14608kern_return_t kr;14609vm_region_submap_info_64 vbr;14610mach_msg_type_number_t vbrcount = sizeof(vbr) / 4;1461114612while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount)))14613{14614{14615if(0 != (vbr.protection & VM_PROT_EXECUTE))14616{14617dl_info di;14618int r = 0;14619r = dladdr((void*)vmoffset, &di);14620if(r)14621{14622uprintf("[0x%p-0x%p] (0x%p) %s %s\n", (void*)vmoffset, (void*)addr_prev, di.dli_fbase, di.dli_fname, di.dli_sname);14623MicroProfileSymbolInitModule(di.dli_fname, (intptr_t)vmoffset, (intptr_t)vmoffset + vmsize);14624}14625}14626}14627vmoffset += vmsize;14628vbrcount = sizeof(vbr) / 4;14629}14630}1463114632static void* MicroProfileAllocExecutableMemory(void* f, size_t s)14633{14634static uint64_t nPageSize = 0;14635if(!nPageSize)14636{14637nPageSize = getpagesize();14638}14639s = (s + (nPageSize - 1)) & (~(nPageSize - 1));1464014641void* pMem = mmap((void*)f, s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0);1464214643// uprintf("Allocating %zu %p\n", s, pMem);14644return pMem;14645}1464614647bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size)14648{14649// demangle not implemented14650strcpy(OutName, pName);14651return true;14652}1465314654bool MicroProfilePatchBeginSuspend()14655{14656// Not implemented14657return true;14658}1465914660void MicroProfilePatchEndSuspend()14661{14662// Not implemented14663}1466414665void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols)14666{14667void* M = dlopen(0, 0);14668for(uint32_t i = 0; i < nNumSymbols; ++i)14669{14670// uprintf("trying to find symbol %s\n", pSym);14671void* s = dlsym(M, pSymbols[i]);14672uprintf("sym returned %p\n", s);14673if(s)14674{14675uint32_t nColor = MicroProfileColorFromString(pSymbols[i]);14676const char* pDemangled = MicroProfileDemangleSymbol(pSymbols[i]);14677MicroProfileInstrumentFunction(s, pModules[i], pDemangled, nColor);14678}14679}14680dlclose(M);14681}14682#endif1468314684#if defined(__unix__) && defined(__x86_64__)14685// '##::::'##::'#######:::'#######::'##:::'##::::'##:::::::'####:'##::: ##:'##::::'##:'##::::'##:14686// ##:::: ##:'##.... ##:'##.... ##: ##::'##::::: ##:::::::. ##:: ###:: ##: ##:::: ##:. ##::'##::14687// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::::::: ##:: ####: ##: ##:::: ##::. ##'##:::14688// #########: ##:::: ##: ##:::: ##: #####::::::: ##:::::::: ##:: ## ## ##: ##:::: ##:::. ###::::14689// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##:::::::: ##:: ##. ####: ##:::: ##::: ## ##:::14690// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##:::::::: ##:: ##:. ###: ##:::: ##:: ##:. ##::14691// ##:::: ##:. #######::. #######:: ##::. ##:::: ########:'####: ##::. ##:. #######:: ##:::. ##:14692// ..:::::..:::.......::::.......:::..::::..:::::........::....::..::::..:::.......:::..:::::..::1469314694#include <cxxabi.h>14695#include <distorm.h>14696#include <dlfcn.h>14697#include <mnemonics.h>14698#include <sys/mman.h>14699#include <unistd.h>1470014701static void* MicroProfileAllocExecutableMemory(void* f, size_t s);14702static void MicroProfileMakeWriteable(void* p_);1470314704extern "C" void microprofile_tramp_enter_patch() asm("_microprofile_tramp_enter_patch");14705extern "C" void microprofile_tramp_enter() asm("_microprofile_tramp_enter");14706extern "C" void microprofile_tramp_code_begin() asm("_microprofile_tramp_code_begin");14707extern "C" void microprofile_tramp_code_end() asm("_microprofile_tramp_code_end");14708extern "C" void microprofile_tramp_intercept0() asm("_microprofile_tramp_intercept0");14709extern "C" void microprofile_tramp_end() asm("_microprofile_tramp_end");14710extern "C" void microprofile_tramp_exit() asm("_microprofile_tramp_exit");14711extern "C" void microprofile_tramp_leave() asm("_microprofile_tramp_leave");14712extern "C" void microprofile_tramp_trunk() asm("_microprofile_tramp_trunk");14713extern "C" void microprofile_tramp_call_patch_pop() asm("_microprofile_tramp_call_patch_pop");14714extern "C" void microprofile_tramp_call_patch_push() asm("_microprofile_tramp_call_patch_push");1471514716bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError)14717{14718if(pError)14719{14720memcpy(&pError->Code[0], f, 12);14721}1472214723intptr_t t_enter = (intptr_t)microprofile_tramp_enter;14724intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter;14725intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter;14726intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter;14727intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter;14728intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter;14729intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter;1473014731intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter;14732intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter;14733intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset;14734intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter;14735intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter;14736intptr_t t_trunk_size = (intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk;1473714738char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset);1473914740intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp);1474114742uint32_t nBytesToCopy = 14;14743if(offset < 0x80000000 && offset > -0x7fffffff)14744{14745/// offset is small enough to insert a relative jump14746nBytesToCopy = 5;14747}1474814749memcpy(ptramp, (void*)t_enter, t_end_offset);1475014751int nInstructionBytesDest = 0;14752char* pInstructionMoveDest = ptramp + t_code_begin_offset;14753char* pTrunk = ptramp + t_trunk_offset;1475414755int nInstructionBytesSrc = 0;1475614757uint32_t nRegsWritten = 0;14758uint32_t nRetSafe = 0;14759uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11); // scratch && !parameter register14760if(!MicroProfileCopyInstructionBytes(14761pInstructionMoveDest, f, nBytesToCopy, codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe))14762{14763if(pError)14764{14765const char* pCode = (const char*)f;14766memset(pError->Code, 0, sizeof(pError->Code));14767memcpy(pError->Code, pCode, nInstructionBytesSrc);14768int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc);14769pError->nCodeSize = nInstructionBytesSrc;14770for(int i = 0; i < nInstructionBytesSrc; ++i)14771{14772off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]);14773}14774uprintf("%s\n", pError->Message);14775}14776return false;14777}14778intptr_t phome = nInstructionBytesSrc + (intptr_t)f;14779uint32_t reg = nUsableJumpRegs & ~nRegsWritten;14780static_assert(R_RAX == 0, "R_RAX must be 0");14781if(0 == reg)14782{14783if(nRetSafe == 0)14784{14785MP_BREAK(); // shout fail earlier14786}14787MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome);14788}14789else14790{14791int r = R_RAX;14792while((reg & 1) == 0)14793{14794reg >>= 1;14795r++;14796}14797MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r);14798}1479914800// PATCH 1 TRAMP EXIT14801intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset;14802memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8);1480314804char* pintercept = t_code_intercept0_offset + ptramp;1480514806// PATCH 1.5 Argument14807memcpy(pintercept - 4, (void*)&Argument, 4);1480814809// PATCH 2 INTERCEPT014810intptr_t addr = (intptr_t)enter; //&intercept0;14811memcpy(pintercept + 2, (void*)&addr, 8);1481214813// PATHC 2.5 argument14814memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4);1481514816intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset;14817// PATCH 3 INTERCEPT114818intptr_t addr1 = (intptr_t)leave; //&intercept1;14819memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8);1482014821intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH);14822intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP);14823memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8);14824memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8);1482514826{14827// PATCH 4 DEST FUNC1482814829MicroProfileMakeWriteable(f);14830char* pp = (char*)f;14831char* ppend = pp + nInstructionBytesSrc;1483214833if(nInstructionBytesSrc < 14)14834{14835uprintf("inserting 5b jump\n");14836pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp);14837}14838else14839{14840uprintf("inserting 14b jump\n");14841pp = MicroProfileInsertRegisterJump(pp, (intptr_t)ptramp, R_RAX);14842}14843while(pp != ppend)14844{14845*pp++ = 0x90;14846}14847}14848return true;14849}1485014851static void MicroProfileMakeWriteable(void* p_)14852{14853intptr_t nPageSize = (intptr_t)getpagesize();14854intptr_t p = ((intptr_t)p_) & ~(nPageSize - 1);14855intptr_t e = nPageSize + ((14 + (intptr_t)p_) & ~(nPageSize - 1));14856size_t s = e - p;14857mprotect((void*)p, s, PROT_READ | PROT_WRITE | PROT_EXEC);14858}1485914860int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd)14861{14862int l = strlen(pStr) - 1;14863int sz = 0;14864pOutEnd--;14865if(l < pOutEnd - pOutBegin && pOutBegin != pOutEnd)14866{14867const char* p = pStr;14868const char* pEnd = pStr + l + 1;14869int in = 0;14870while(p != pEnd && pOutBegin != pOutEnd)14871{14872char c = *p++;14873if(c == '(' || c == '<')14874{14875in++;14876}14877else if(c == ')' || c == '>')14878{14879in--;14880continue;14881}1488214883if(in == 0)14884{14885*pOutBegin++ = c;14886sz++;14887}14888}1488914890*pOutBegin++ = '\0';14891}14892return sz;14893}1489414895int MicroProfileFindFunctionName(const char* pStr, const char** ppStart)14896{14897int l = strlen(pStr) - 1;14898if(l < 1024)14899{14900char b[1024] = { 0 };14901char* put = &b[0];1490214903const char* p = pStr;14904const char* pEnd = pStr + l + 1;14905int in = 0;14906while(p != pEnd)14907{14908char c = *p++;14909if(c == '(' || c == '<')14910{14911in++;14912}14913else if(c == ')' || c == '>')14914{14915in--;14916continue;14917}1491814919if(in == 0)14920{14921*put++ = c;14922}14923}1492414925*put++ = '\0';14926uprintf("trimmed %s\n", b);14927}1492814929// int nFirstParen = l;14930int nNumParen = 0;14931int c = 0;1493214933while(l >= 0 && pStr[l] != ')' && c++ < (int)(sizeof(" const") - 1))14934{14935l--;14936}14937if(pStr[l] == ')')14938{14939do14940{14941if(pStr[l] == ')')14942{14943nNumParen++;14944}14945else if(pStr[l] == '(')14946{14947nNumParen--;14948}14949l--;14950} while(nNumParen > 0 && l >= 0);14951}14952else14953{14954*ppStart = pStr;14955return 0;14956}14957while(l >= 0 && isspace(pStr[l]))14958{14959--l;14960}14961int nLast = l;14962while(l >= 0 && !isspace(pStr[l]))14963{14964l--;14965}14966int nFirst = l;14967if(nFirst == nLast)14968return 0;14969int nCount = nLast - nFirst + 1;14970*ppStart = pStr + nFirst;14971return nCount;14972}1497314974const char* MicroProfileDemangleSymbol(const char* pSymbol)14975{14976static unsigned long size = 128;14977static char* pTempBuffer = (char*)malloc(size); // needs to be malloc because demangle function might realloc it.14978unsigned long len = size;14979int ret = 0;14980char* pBuffer = pTempBuffer;14981pBuffer = abi::__cxa_demangle(pSymbol, pTempBuffer, &len, &ret);14982if(ret == 0)14983{14984if(pBuffer != pTempBuffer)14985{14986pTempBuffer = pBuffer;14987if(len < size)14988__builtin_trap();14989size = len;14990}14991return pTempBuffer;14992}14993else14994{14995return pSymbol;14996}14997}1499814999template <typename Callback>15000void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules)15001{15002MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3);15003char FunctionName[1024];1500415005intptr_t nCurrentModule = -1;15006uint32_t nCurrentModuleId = -1;1500715008auto OnFunction = [&](void* addr, void* addrend, const char* pSymbol, const char* pModuleName, void* pModuleAddr) -> bool15009{15010const char* pStr = MicroProfileDemangleSymbol(pSymbol);15011;15012int l = MicroProfileTrimFunctionName(pStr, &FunctionName[0], &FunctionName[1024]);15013MP_ASSERT(nCurrentModule == (intptr_t)pModuleAddr);15014CB(l ? &FunctionName[0] : pStr, l ? &FunctionName[0] : 0, (intptr_t)addr, (intptr_t)addrend, nCurrentModuleId);15015return true;15016};1501715018for(int i = 0; i < S.SymbolNumModules; ++i)15019{15020auto& M = S.SymbolModules[i];15021if(0 != nNumModules)15022{15023bool bProcess = false;15024for(uint32_t j = 0; j < nNumModules; ++j)15025{15026if(nModules[j] == (uint32_t)i)15027{15028bProcess = true;15029break;15030}15031}15032if(!bProcess)15033continue;15034}15035nCurrentModuleId = i;15036Dl_info di;15037int r = 0;15038r = dladdr((void*)(M.Regions[0].nBegin), &di);15039if(r)15040{15041nCurrentModule = (intptr_t)di.dli_fbase;15042M.nProgressTarget = 0;15043for(int j = 0; j < M.nNumExecutableRegions; ++j)15044{15045M.nProgressTarget += M.Regions[j].nEnd - M.Regions[j].nBegin;15046}15047for(int j = 0; j < M.nNumExecutableRegions; ++j)15048{15049const intptr_t nBegin = M.Regions[j].nBegin;15050const intptr_t nEnd = M.Regions[j].nEnd;15051int r = 0;15052intptr_t nAddr = (nEnd - 8) & ~7;15053intptr_t nAddrPrev = nEnd;15054while(1)15055{15056r = dladdr((void*)(nAddr), &di);15057if(r && di.dli_sname)15058{15059OnFunction(di.dli_saddr, (void*)nAddrPrev, di.dli_sname, di.dli_fname, di.dli_fbase);15060nAddrPrev = (intptr_t)di.dli_saddr;15061nAddr = (intptr_t)di.dli_saddr - 1;15062}15063else15064{15065nAddr = (nAddr - 7) & ~7; // pretty ineffecient, but it seems linux just returns 0 when there is no symbols, making this the only option I can come up with?15066}15067if(nAddr < nBegin)15068{15069break;15070}15071}15072}15073M.nProgress = M.nProgressTarget;15074M.nModuleLoadFinished.store(1);15075}15076}15077}1507815079void MicroProfileSymbolUpdateModuleList()15080{15081// So, this was the only way I could find to do this..15082// Is this seriously how they want this to be done?15083FILE* F = fopen("/proc/self/maps", "r");15084char* line = 0;15085size_t len;15086ssize_t read;15087Dl_info di;15088while((read = getline(&line, &len, F)) != -1)15089{15090void* pBase = 0;15091void* pEnd = 0;15092char c, r, w, x, p;1509315094if(8 == sscanf(line, "%p%c%p%c%c%c%c%c", &pBase, &c, &pEnd, &c, &r, &w, &x, &p))15095{15096if('x' == x)15097{15098int r = 0;15099r = dladdr(pBase, &di);15100if(r)15101{15102if('[' != di.dli_fname[0])15103{15104MicroProfileSymbolInitModule(di.dli_fname, (intptr_t)pBase, (intptr_t)pEnd);15105}15106}15107}15108}15109}15110fclose(F);15111MicroProfileSymbolMergeExecutableRegions();15112}1511315114static void* MicroProfileAllocExecutableMemory(void* f, size_t s)15115{15116static uint64_t nPageSize = 0;15117if(!nPageSize)15118{15119nPageSize = getpagesize();15120}15121s = (s + (nPageSize - 1)) & (~(nPageSize - 1));1512215123void* pMem = mmap(f, s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0);15124return pMem;15125}1512615127bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size)15128{15129// demangle not implemented15130strcpy(OutName, pName);15131return true;15132}1513315134bool MicroProfilePatchBeginSuspend()15135{15136// Not implemented15137return true;15138}1513915140void MicroProfilePatchEndSuspend()15141{15142// Not implemented15143}1514415145// not yet tested.15146void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols)15147{15148void* M = dlopen(0, 0);15149for(uint32_t i = 0; i < nNumSymbols; ++i)15150{15151// uprintf("trying to find symbol %s\n", pSym);15152void* s = dlsym(M, pSymbols[i]);15153uprintf("sym returned %p\n", s);15154if(s)15155{15156uint32_t nColor = MicroProfileColorFromString(pSymbols[i]);15157const char* pDemangled = MicroProfileDemangleSymbol(pSymbols[i]);15158MicroProfileInstrumentFunction(s, pModules[i], pDemangled, nColor);15159}15160}15161dlclose(M);15162}1516315164#endif1516515166#endif1516715168void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, uint32_t nSearchLimit, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc)15169{15170pTable->nAllocated = nInitialSize;15171pTable->nUsed = 0;15172uint32_t nSize = nInitialSize * sizeof(MicroProfileHashTableEntry);15173pTable->pEntries = (MicroProfileHashTableEntry*)MICROPROFILE_ALLOC(nSize, 8);15174pTable->CompareFunc = CompareFunc;15175pTable->HashFunc = HashFunc;15176pTable->nSearchLimit = nSearchLimit;15177pTable->nLim = pTable->nAllocated / 5;15178if(pTable->nLim > pTable->nSearchLimit)15179pTable->nLim = pTable->nSearchLimit;15180memset(pTable->pEntries, 0, nSize);15181}15182void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable)15183{15184MICROPROFILE_FREE(pTable->pEntries);15185}1518615187uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K)15188{15189uint64_t H = pTable->HashFunc ? (*pTable->HashFunc)(K) : K;15190return H == 0 ? 1 : H;15191}1519215193void MicroProfileHashTableGrow(MicroProfileHashTable* pTable)15194{15195uint32_t nAllocated = pTable->nAllocated;15196uint32_t nNewSize = nAllocated * 2;15197uprintf("GROW %d -> %d\n", nAllocated, nNewSize);1519815199MicroProfileHashTable New;15200MicroProfileHashTableInit(&New, nNewSize, pTable->nSearchLimit, pTable->CompareFunc, pTable->HashFunc);15201for(uint32_t i = 0; i < nAllocated; ++i)15202{15203MicroProfileHashTableEntry& E = pTable->pEntries[i];15204if(E.Hash != 0)15205{15206MicroProfileHashTableSet(&New, E.Key, E.Value, E.Hash, false);15207}15208}15209MicroProfileHashTableDestroy(pTable);15210*pTable = New;15211}1521215213bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value)15214{15215uint64_t H = MicroProfileHashTableHash(pTable, Key);15216return MicroProfileHashTableSet(pTable, Key, Value, H, true);15217}1521815219MicroProfileHashTableIterator MicroProfileGetHashTableIteratorBegin(MicroProfileHashTable* HashTable)15220{15221return MicroProfileHashTableIterator(0, HashTable);15222}1522315224MicroProfileHashTableIterator MicroProfileGetHashTableIteratorEnd(MicroProfileHashTable* HashTable)15225{15226return MicroProfileHashTableIterator(HashTable->nAllocated, HashTable);15227}1522815229bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value, uint64_t H, bool bAllowGrow)15230{15231if(H == 0)15232MP_BREAK(); // not supported.15233MicroProfileHashCompareFunction Cmp = pTable->CompareFunc;15234while(1)15235{15236const uint32_t nLim = pTable->nLim;15237uint32_t B = H % pTable->nAllocated;15238MicroProfileHashTableEntry* pEntries = pTable->pEntries;1523915240for(uint32_t i = 0; i < pTable->nAllocated; ++i)15241{15242uint32_t Idx = (B + i) % pTable->nAllocated;15243if(pEntries[Idx].Hash == 0)15244{15245pEntries[Idx].Hash = H;15246pEntries[Idx].Key = Key;15247pEntries[Idx].Value = Value;15248return true;15249}15250else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key))15251{15252pEntries[Idx].Value = Value;15253return true;15254}15255else if(i > nLim)15256{15257break;15258}15259}15260if(bAllowGrow)15261{15262MicroProfileHashTableGrow(pTable);15263}15264else15265{15266MP_BREAK();15267}15268}15269MP_BREAK();15270}1527115272bool MicroProfileHashTableGet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t* pValue)15273{15274uint64_t H = MicroProfileHashTableHash(pTable, Key);15275uint32_t B = H % pTable->nAllocated;15276MicroProfileHashTableEntry* pEntries = pTable->pEntries;15277MicroProfileHashCompareFunction Cmp = pTable->CompareFunc;15278for(uint32_t i = 0; i < pTable->nAllocated; ++i)15279{15280uint32_t Idx = (B + i) % pTable->nAllocated;15281if(pEntries[Idx].Hash == 0)15282{15283return false;15284}15285else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key))15286{15287*pValue = pEntries[Idx].Value;15288return true;15289}15290}15291return false;15292}1529315294bool MicroProfileHashTableRemove(MicroProfileHashTable* pTable, uint64_t Key)15295{1529615297uint64_t H = MicroProfileHashTableHash(pTable, Key);15298uint32_t B = H % pTable->nAllocated;15299MicroProfileHashTableEntry* pEntries = pTable->pEntries;15300MicroProfileHashCompareFunction Cmp = pTable->CompareFunc;15301uint32_t nBase = (uint32_t)-1;15302uint32_t nAllocated = pTable->nAllocated;15303for(uint32_t i = 0; i < nAllocated; ++i)15304{15305uint32_t Idx = (B + i) % nAllocated;15306if(pEntries[Idx].Hash == 0)15307{15308return false;15309}15310else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key))15311{15312nBase = Idx;15313break;15314}15315}15316pEntries[nBase].Hash = 0;15317pEntries[nBase].Key = 0;15318pEntries[nBase].Value = 0;15319nBase++;15320for(uint32_t i = 0; i < nAllocated; ++i)15321{15322uint32_t Idx = (nBase + i) % nAllocated;15323if(pEntries[Idx].Hash == 0)15324{15325break;15326}15327else15328{15329MicroProfileHashTableEntry E = pEntries[Idx];15330pEntries[Idx] = {};15331MicroProfileHashTableSet(pTable, E.Key, E.Value, E.Hash, false);15332}15333}15334return true;15335}15336uint64_t MicroProfileHashTableHashString(uint64_t pString)15337{15338return MicroProfileStringHash((const char*)pString);15339}1534015341bool MicroProfileHashTableCompareString(uint64_t L, uint64_t R)15342{15343return 0 == strcmp((const char*)L, (const char*)R);15344}15345uint64_t MicroProfileHashTableHashPtr(uint64_t x)15346{15347x ^= x >> 33;15348x *= 0xff51afd7ed558ccdULL;15349x ^= x >> 33;15350x *= 0xc4ceb9fe1a85ec53ULL;15351x ^= x >> 33;15352return x;15353}15354bool MicroProfileHashTableComparePtr(uint64_t L, uint64_t R)15355{15356return L == R;15357}1535815359bool MicroProfileHashTableSetString(MicroProfileHashTable* pTable, const char* pKey, const char* pValue)15360{15361return MicroProfileHashTableSet(pTable, (uint64_t)pKey, (uintptr_t)pValue);15362}1536315364bool MicroProfileHashTableGetString(MicroProfileHashTable* pTable, const char* pKey, const char** pValue)15365{15366return MicroProfileHashTableGet(pTable, (uint64_t)pKey, (uintptr_t*)pValue);15367}1536815369bool MicroProfileHashTableRemoveString(MicroProfileHashTable* pTable, const char* pKey)15370{15371return MicroProfileHashTableRemove(pTable, (uint64_t)pKey);15372}1537315374bool MicroProfileHashTableSetPtr(MicroProfileHashTable* pTable, const void* pKey, void* pValue)15375{15376return MicroProfileHashTableSet(pTable, (uint64_t)pKey, (uintptr_t)pValue);15377}1537815379template <typename T>15380bool MicroProfileHashTableGetPtr(MicroProfileHashTable* pTable, const void* pKey, T** pValue)15381{15382uintptr_t Dummy;15383uintptr_t* Arg = pValue ? (uintptr_t*)pValue : &Dummy;15384return MicroProfileHashTableGet(pTable, (uint64_t)pKey, Arg);15385}1538615387bool MicroProfileHashTableRemovePtr(MicroProfileHashTable* pTable, const char* pKey)15388{15389return MicroProfileHashTableRemove(pTable, (uint64_t)pKey);15390}1539115392template <typename T>15393T& MicroProfileArray<T>::operator[](const uint32_t Index)15394{15395return Data[Index];15396}1539715398template <typename T>15399const T& MicroProfileArray<T>::operator[](const uint32_t Index) const15400{15401MP_ASSERT(Index < Size);15402return Data[Index];15403}15404template <typename T>15405T* MicroProfileArray<T>::begin()15406{15407return Data;15408}15409template <typename T>15410T* MicroProfileArray<T>::end()15411{15412return Data + Size;15413}1541415415template <typename T>15416void MicroProfileArrayInit(MicroProfileArray<T>& Array, uint32_t InitialCapacity)15417{15418MP_ASSERT(Array.Data == nullptr);15419MP_ASSERT(Array.Size == 0);15420MP_ASSERT(Array.Capacity == 0);15421Array.Capacity = InitialCapacity;15422Array.Data = MP_ALLOC_OBJECT_ARRAY(T, InitialCapacity);15423Array.Size = 0;15424}15425template <typename T>15426void MicroProfileArrayDestroy(MicroProfileArray<T>& Array, uint32_t InitialCapacity)15427{15428if(Array.Data)15429MP_FREE(Array.Data);15430memset(Array, 0, sizeof(*Array));15431}15432template <typename T>15433void MicroProfileArrayClear(MicroProfileArray<T>& Array)15434{15435Array.Size = 0;15436}1543715438template <typename T>15439void MicroProfileArrayPushBack(MicroProfileArray<T>& Array, const T& v)15440{15441uint32_t& Size = Array.Size;15442uint32_t& Capacity = Array.Capacity;15443if(Size >= Capacity)15444{15445uint32_t NewCapacity = (MicroProfileMax<uint32_t>(1u, Capacity) + 1) * 3 / 2;15446T* NewData = MP_ALLOC_OBJECT_ARRAY(T, NewCapacity);15447memcpy(NewData, Array.Data, Size * sizeof(T));15448if(Array.Data)15449{15450MP_FREE(Array.Data);15451}15452Array.Data = NewData;15453Capacity = NewCapacity;15454}15455Array.Data[Size++] = v;15456}1545715458void MicroProfileStringBlockFree(MicroProfileStringBlock* pBlock)15459{15460MicroProfileCounterAdd(S.CounterToken_StringBlock_Count, -1);15461MicroProfileCounterAdd(S.CounterToken_StringBlock_Memory, -(int64_t)(pBlock->nSize + sizeof(MicroProfileStringBlock)));1546215463MP_FREE(pBlock);15464}15465MicroProfileStringBlock* MicroProfileStringBlockAlloc(uint32_t nSize)15466{15467nSize = MicroProfileMax(nSize, (uint32_t)(MicroProfileStringBlock::DEFAULT_SIZE - sizeof(MicroProfileStringBlock)));15468nSize += sizeof(MicroProfileStringBlock);15469MicroProfileCounterAdd(S.CounterToken_StringBlock_Count, 1);15470MicroProfileCounterAdd(S.CounterToken_StringBlock_Memory, nSize);15471// uprintf("alloc string block %d sizeof strings is %d\n", nSize, (int)sizeof(MicroProfileStringBlock));15472MicroProfileStringBlock* pBlock = (MicroProfileStringBlock*)MP_ALLOC(nSize, 8);15473pBlock->pNext = 0;15474pBlock->nSize = nSize - sizeof(MicroProfileStringBlock);15475pBlock->nUsed = 0;15476return pBlock;15477}1547815479void MicroProfileStringsInit(MicroProfileStrings* pStrings)15480{15481MicroProfileHashTableInit(&pStrings->HashTable, 1, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString);15482pStrings->pFirst = 0;15483pStrings->pLast = 0;15484}15485void MicroProfileStringsDestroy(MicroProfileStrings* pStrings)15486{15487MicroProfileStringBlock* pBlock = pStrings->pFirst;15488while(pBlock)15489{15490MicroProfileStringBlock* pNext = pBlock->pNext;15491MicroProfileStringBlockFree(pBlock);15492pBlock = pNext;15493}15494MicroProfileCounterSet(S.CounterToken_StringBlock_Waste, 0);15495MicroProfileCounterSet(S.CounterToken_StringBlock_Strings, 0);1549615497memset(pStrings, 0, sizeof(*pStrings));15498}1549915500const char* MicroProfileStringIntern(const char* pStr)15501{15502return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), 0);15503}1550415505const char* MicroProfileStringInternLower(const char* pStr)15506{15507return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), ESTRINGINTERN_LOWERCASE);15508}15509const char* MicroProfileStringInternSlash(const char* pStr)15510{15511return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), ESTRINGINTERN_FORCEFORWARDSLASH);15512}1551315514const char* MicroProfileStringIntern(const char* pStr_, uint32_t nLen, uint32_t nFlags)15515{15516MicroProfileStrings* pStrings = &S.Strings;15517const char* pStr = pStr_;15518char* pLowerCaseStr = (char*)alloca(nLen + 1);15519if(0 != (nFlags & (ESTRINGINTERN_FORCEFORWARDSLASH | ESTRINGINTERN_LOWERCASE)))15520{15521for(uint32_t i = 0; i < nLen; ++i)15522{15523char c = pStr[i];15524if(nFlags & ESTRINGINTERN_LOWERCASE)15525{15526c = tolower(c);15527}15528if(nFlags & ESTRINGINTERN_FORCEFORWARDSLASH)15529{15530if(c == '\\')15531c = '/';15532}15533pLowerCaseStr[i] = c;15534}15535pLowerCaseStr[nLen] = '\0';15536pStr = pLowerCaseStr;15537}15538const char* pRet;15539if(MicroProfileHashTableGetString(&pStrings->HashTable, pStr, &pRet))15540{15541if(0 != strcmp(pStr, pRet))15542{15543MP_BREAK();15544}15545return pRet;15546}15547else15548{15549if(pStr[nLen] != '\0')15550MP_BREAK(); // string should be 0 terminated.15551nLen += 1;15552MicroProfileStringBlock* pBlock = pStrings->pLast;15553if(0 == pBlock || pBlock->nUsed + nLen > pBlock->nSize)15554{15555MicroProfileStringBlock* pNewBlock = MicroProfileStringBlockAlloc(nLen);15556if(pBlock)15557{15558pBlock->pNext = pNewBlock;15559pStrings->pLast = pNewBlock;15560MicroProfileCounterAdd(S.CounterToken_StringBlock_Waste, pBlock->nSize - pBlock->nUsed);15561}15562else15563{15564pStrings->pLast = pStrings->pFirst = pNewBlock;15565}15566pBlock = pNewBlock;15567}15568MicroProfileCounterAdd(S.CounterToken_StringBlock_Strings, 1);15569char* pDest = &pBlock->Memory[pBlock->nUsed];15570pBlock->nUsed += nLen;15571MP_ASSERT(pBlock->nUsed <= pBlock->nSize);15572memcpy(pDest, pStr, nLen);15573MicroProfileHashTableSetString(&pStrings->HashTable, pDest, pDest);1557415575#if 015576void DumpTableStr(MicroProfileHashTable* pTable);15577DumpTableStr(&pStrings->HashTable);15578#endif1557915580return pDest;15581}15582}1558315584void DumpTable(MicroProfileHashTable* pTable)15585{15586for(uint32_t i = 0; i < pTable->nAllocated; ++i)15587{15588if(pTable->pEntries[i].Hash != 0)15589{15590uprintf("[%05d,%05" PRIu64 "] ::::%" PRIx64 ", %p .. hash %" PRIx64 "\n",15591i,15592pTable->pEntries[i].Hash % pTable->nAllocated,15593pTable->pEntries[i].Key,15594(void*)pTable->pEntries[i].Value,15595pTable->pEntries[i].Hash);15596}15597}15598};15599void DumpTableStr(MicroProfileHashTable* pTable)15600{15601int c = 0;15602(void)c;15603for(uint32_t i = 0; i < pTable->nAllocated; ++i)15604{15605if(pTable->pEntries[i].Hash != 0)15606{15607uprintf("%03d [%05d,%05" PRIu64 "] ::::%s, %s .. hash %" PRIx64 "\n",15608c++,15609i,15610pTable->pEntries[i].Hash % pTable->nAllocated,15611(const char*)pTable->pEntries[i].Key,15612(const char*)pTable->pEntries[i].Value,15613pTable->pEntries[i].Hash);15614}15615}15616uprintf("FillPrc %f\n", 100.f * c / (float)pTable->nAllocated);15617};1561815619static const char* txt[] = { "gaudy", "chilly", "obtain", "suspend", "jelly", "peel", "nauseating", "complain", "cave", "practise", "sail", "close",15620"drawer", "mature", "impossible", "exist", "sister", "poke", "ancient", "paddle", "ask", "shallow", "outrageous", "healthy",15621"reading", "obey", "water", "elbow", "abnormal", "trap", "wholesale", "lovely", "stupid", "comparison", "swim", "brash",15622"towering", "accept", "invention", "plantation", "spooky", "tiger", "knot", "literate", "awake", "itch", "medical", "ticket",15623"tawdry", "correct", "mine", "accidental", "dinner", "produce", "protective", "red", "dreary", "toe", "drain", "zesty",15624"inform", "boundless", "ghost", "attend", "rely", "fill", "liquid", "pump", "continue", "spark", "church", "fortunate",15625"truthful", "conscious", "possible", "motion", "evanescent", "branch", "skirt", "number", "meek", "hour", "form", "work",15626"car", "post", "talk", "fear", "tightfisted", "dress", "perform", "fry", "courageous", "dysfunctional", "page", "one",15627"annoy", "abrasive", "dependent", "payment" };1562815629void MicroProfileStringInternTest()15630{15631MicroProfileStringsInit(&S.Strings);15632uint32_t nCount = sizeof(txt) / sizeof(txt[0]);15633const char* pStrings[100];15634const char* pStrings2[100];1563515636DumpTableStr(&S.Strings.HashTable);15637for(uint32_t i = 0; i < nCount; ++i)15638{15639pStrings[i] = MicroProfileStringIntern(txt[i]);15640pStrings2[i] = MicroProfileStrDup(txt[i]);15641}1564215643for(uint32_t i = 0; i < nCount; ++i)15644{15645const char* pStr = MicroProfileStringIntern(pStrings2[i]);15646if(pStr != pStrings[i])15647{15648MP_BREAK();15649}15650}15651DumpTableStr(&S.Strings.HashTable);1565215653MicroProfileStringsDestroy(&S.Strings);15654}1565515656void MicroProfileHashTableTest()15657{15658MicroProfileStringInternTest();1565915660MicroProfileHashTable T;15661MicroProfileHashTable* pTable = &T;15662MicroProfileHashTableInit(pTable, 1, 100, 0, 0);1566315664#define NUM_ITEMS 1001566515666uint64_t Keys[NUM_ITEMS];15667uint64_t Values[NUM_ITEMS];15668memset(Keys, 0xff, sizeof(Keys));15669memset(Values, 0xff, sizeof(Values));1567015671static int l = 0;15672auto RR = [&]() -> uint64_t15673{15674if(l++ % 4 < 2)15675{15676return l;15677}15678uint64_t l2 = rand();15679uint64_t u = rand();15680return l2 | (u << 32);15681};15682auto RRUnique = [&]()15683{15684bool bFound = false;15685uint64_t V = 0;15686do15687{15688V = RR();15689for(uint32_t i = 0; i != NUM_ITEMS; ++i)15690{15691if(V == Keys[i])15692{15693bFound = true;15694}15695}15696if(!bFound)15697{15698return V;15699}15700} while(bFound);15701MP_BREAK();15702return (uint64_t)0;15703};1570415705Keys[0] = 0;15706Values[0] = 42;15707for(uint32_t i = 1; i < NUM_ITEMS; ++i)15708{15709Keys[i] = RRUnique();15710Values[i] = RR();15711}1571215713for(uint32_t i = 0; i < NUM_ITEMS; ++i)15714{15715MicroProfileHashTableSet(pTable, Keys[i], Values[i]);15716}1571715718for(uint32_t i = 0; i < NUM_ITEMS; ++i)15719{15720uintptr_t V;15721if(MicroProfileHashTableGet(pTable, Keys[i], &V))15722{15723if(V != Values[i])15724{15725MP_BREAK();15726}15727}15728else15729{15730MP_BREAK();15731}15732uint64_t nonkey = RRUnique();15733if(MicroProfileHashTableGet(pTable, nonkey, &V))15734{15735MP_BREAK();15736}15737}1573815739DumpTable(pTable);15740if(!MicroProfileHashTableRemove(pTable, 0))15741{15742MP_BREAK();15743}15744uprintf("removed\n");15745DumpTable(pTable);15746uintptr_t v;15747if(MicroProfileHashTableGet(pTable, 0, &v))15748{15749MP_BREAK();15750}15751if(MicroProfileHashTableGet(pTable, 1, &v))15752{15753if(v != 2)15754MP_BREAK();15755}1575615757MicroProfileHashTableDestroy(pTable);1575815759MicroProfileHashTable Strings;15760MicroProfileHashTableInit(&Strings, 1, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString);15761uint32_t nCount = sizeof(txt) / sizeof(txt[0]);15762for(uint32_t i = 0; i < nCount; i += 2)15763{15764MicroProfileHashTableSetString(&Strings, txt[i], txt[i + 1]);15765}15766DumpTableStr(&Strings);1576715768for(uint32_t i = 0; i < nCount; i += 2)15769{15770const char* pKey = txt[i];15771const char* pValue = txt[i + 1];15772const char* pRes = 0;15773if(MicroProfileHashTableGetString(&Strings, pKey, &pRes))15774{15775if(pRes != pValue)15776{15777MP_BREAK();15778}15779}15780else15781{15782MP_BREAK();15783}15784}15785uint32_t nRem = nCount / 2;15786for(uint32_t i = 0; i < nRem; i += 2)15787{15788const char* pKey = txt[i];15789const char* pValue = txt[i + 1];1579015791if(!MicroProfileHashTableRemoveString(&Strings, pKey))15792{15793MP_BREAK();15794}15795if(MicroProfileHashTableRemoveString(&Strings, pValue))15796{15797MP_BREAK();15798}15799}15800for(uint32_t i = 0; i < nRem; i += 2)15801{15802const char* pKey = txt[i];15803if(MicroProfileHashTableRemoveString(&Strings, pKey))15804{15805MP_BREAK();15806}15807}1580815809for(uint32_t i = 0; i < nCount; i += 2)15810{15811const char* pKey = txt[i];15812const char* pValue = txt[i + 1];15813const char* V;15814if(MicroProfileHashTableGetString(&Strings, pKey, &V))15815{15816if(i < nRem)15817{15818MP_BREAK();15819}15820else15821{15822if(V != pValue)15823MP_BREAK();15824}15825}15826else15827{15828if(i >= nRem)15829MP_BREAK();15830}15831}1583215833DumpTableStr(&Strings);15834MicroProfileHashTableDestroy(&Strings);15835}1583615837uint32_t MicroProfileGetColor(uint32_t TimerIndex)15838{15839MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex];15840if(TI.nColor == MP_AUTO)15841{15842return MicroProfileColorFromString(TI.pName);15843}15844else15845{15846return TI.nColor;15847}15848}1584915850#if MICROPROFILE_IMGUI15851#include "imgui.h"15852#ifndef MICROPROFILE_IMGUI_MAX_GRAPHS15853#define MICROPROFILE_IMGUI_MAX_GRAPHS 6415854#endif1585515856#define MICROPROFILE_IMGUI_GRAPH_SIZE 2561585715858struct MicroProfileImguiTimerState15859{15860int TimerIndex = -1;15861uint64_t FrameFetched = (uint64_t)-1;15862uint32_t nColor = 0;15863float fValues[MICROPROFILE_IMGUI_GRAPH_SIZE];15864};1586515866struct MicroProfileImguiState15867{15868MicroProfileImguiTimerState Timers[MICROPROFILE_IMGUI_MAX_GRAPHS];15869uint32_t NumTimers = 0;15870uint32_t GraphPut;15871};1587215873static MicroProfileImguiState ImguiState;1587415875void MicroProfileImguiGather()15876{15877MICROPROFILE_SCOPEI("MicroProfile", "ImguiGather", MP_AUTO);15878uint32_t Put = ImguiState.GraphPut;15879for(uint32_t i = 0; i < ImguiState.NumTimers; ++i)15880{15881MicroProfileImguiTimerState* pGraphInfo = &ImguiState.Timers[i];15882uint64_t Ticks = S.Frame[pGraphInfo->TimerIndex].nTicks;15883float fToMs = S.TimerInfo[pGraphInfo->TimerIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTickToMsMultiplierGpu() : MicroProfileTickToMsMultiplierCpu();15884pGraphInfo->fValues[Put] = fToMs * Ticks;15885}15886ImguiState.GraphPut = (ImguiState.GraphPut + 1) % MICROPROFILE_IMGUI_GRAPH_SIZE;15887}1588815889uint32_t MicroProfileImGuiColor(uint32_t Color)15890{15891uint32_t A = 0xff;15892uint32_t R = 0xff & (Color >> 16);15893uint32_t G = 0xff & (Color >> 8);15894uint32_t B = 0xff & (Color);1589515896return (A << IM_COL32_A_SHIFT) | (R << IM_COL32_R_SHIFT) | (G << IM_COL32_G_SHIFT) | (B << IM_COL32_B_SHIFT);15897}1589815899void MicroProfileImguiControls()15900{15901using namespace ImGui;15902uint32_t IdCounter = 42;15903{15904PushID(IdCounter++);15905int Aggr = MicroProfileGetAggregateFrames();15906Text("Aggregate Frames %7d", MicroProfileGetCurrentAggregateFrames());15907SameLine();15908if(RadioButton("Inf", Aggr == 0))15909MicroProfileSetAggregateFrames(0);15910int AggrFrameOptions[] = {1591130,1591260,15913100,159141000,15915};15916for(int i = 0; i < sizeof(AggrFrameOptions) / sizeof(AggrFrameOptions[0]); ++i)15917{15918int v = AggrFrameOptions[i];15919char Buffer[32];15920stbsp_snprintf(Buffer, sizeof(Buffer) - 1, "%d", v);15921SameLine();15922if(RadioButton(Buffer, Aggr == v))15923MicroProfileSetAggregateFrames(v);15924}1592515926if(Aggr == 0)15927{15928if(Button("Clear Inf Aggregate"))15929S.nAggregateClear = 1;15930}1593115932PopID();15933}15934Separator();15935{15936PushID(IdCounter++);15937Text("Categories");15938if(BeginTable("CategoryTable", 3, 0))15939{15940TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);15941TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed, 70);15942TableSetupColumn("Off", ImGuiTableColumnFlags_WidthFixed, 70);15943for(uint32_t i = 0; i < S.nCategoryCount; ++i)15944{15945PushID(i);15946TableNextRow();15947TableSetColumnIndex(0);15948Text(S.CategoryInfo[i].pName);15949bool bEnabled = MicroProfileCategoryEnabled(i);15950bool bDisabled = MicroProfileCategoryDisabled(i);15951TableSetColumnIndex(1);15952if(RadioButton("On", bEnabled))15953MicroProfileEnableCategory(S.CategoryInfo[i].pName);15954TableSetColumnIndex(2);15955if(RadioButton("Off", bDisabled))15956MicroProfileDisableCategory(S.CategoryInfo[i].pName);1595715958PopID();15959}15960EndTable();15961}15962PopID();15963}15964Separator();15965{15966PushID(IdCounter++);15967Text("Groups");15968if(BeginTable("GroupTable", 3, 0))15969{15970TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);15971TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed, 70);15972TableSetupColumn("Off", ImGuiTableColumnFlags_WidthFixed, 70);1597315974for(uint32_t i = 0; i < S.nGroupCount; ++i)15975{15976TableNextRow();15977PushID(i);15978const char* pName = S.GroupInfo[i].pName;15979bool bEnabled = MicroProfileGroupEnabled(i);15980TableSetColumnIndex(0);15981Text(pName);15982TableSetColumnIndex(1);15983if(RadioButton("On", bEnabled))15984MicroProfileToggleGroup(i);15985TableSetColumnIndex(2);15986if(RadioButton("Off", !bEnabled))15987MicroProfileToggleGroup(i);15988PopID();15989}15990EndTable();15991}15992PopID();15993}15994}1599515996MicroProfileImguiTimerState* MicroProfileImguiGetTimerState(int TimerIndex)15997{15998MicroProfileImguiTimerState* ptr = nullptr;15999for(uint32_t i = 0; i < ImguiState.NumTimers; ++i)16000if(ImguiState.Timers[i].TimerIndex == TimerIndex)16001return &ImguiState.Timers[i];1600216003if(ImguiState.NumTimers < MICROPROFILE_IMGUI_MAX_GRAPHS)16004{16005MicroProfileImguiTimerState* pState = &ImguiState.Timers[ImguiState.NumTimers++];16006pState->TimerIndex = TimerIndex;16007pState->nColor = MicroProfileGetColor(TimerIndex);16008memset(&pState->fValues[0], 0, sizeof(pState->fValues));16009return pState;16010}1601116012return nullptr;16013}1601416015void MicroProfileImguiTable(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries)16016{16017using namespace ImGui;16018const uint32_t NumColumns = 6;16019ImGuiIO& io = ImGui::GetIO();1602016021float Padding = GetStyle().CellPadding.x * 2;16022float GroupWidth = CalcTextSize("Group").x;16023float NameWidth = CalcTextSize("Name").x;16024float BaseWidth = CalcTextSize("100000.00").x;16025float Height = CalcTextSize("G").y + Padding;1602616027for(uint32_t i = 0; i < NumEntries; ++i)16028{16029uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer);16030const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex];16031const MicroProfileGroupInfo& GI = S.GroupInfo[TI.nGroupIndex];16032GroupWidth = MicroProfileMax(GroupWidth, CalcTextSize(GI.pName).x);16033NameWidth = MicroProfileMax(NameWidth, CalcTextSize(TI.pName).x);16034}1603516036float TableWidth = GroupWidth + NameWidth + BaseWidth * 4 + NumColumns * Padding + (NumColumns - 1) * GetStyle().ItemSpacing.x;16037float TableHeight = Height * (NumEntries + 1);1603816039ImVec2 TablePos = ImVec2(0.f, 0.f);16040if(Window.Align == MICROPROFILE_IMGUI_ALIGN_TOP_RIGHT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT)16041TablePos.x = io.DisplaySize.x - TableWidth;1604216043if(Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_LEFT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT)16044TablePos.y = io.DisplaySize.y - TableHeight;16045TablePos.x += Window.OffsetX;16046TablePos.y += Window.OffsetY;1604716048SetCursorScreenPos(TablePos);1604916050if(BeginTable("MicroProfileImguiTable", NumColumns, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX))16051{16052TableSetupColumn("Group", ImGuiTableColumnFlags_WidthFixed, GroupWidth);16053TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, NameWidth);1605416055TableSetupColumn("Max", ImGuiTableColumnFlags_WidthFixed, BaseWidth);16056TableSetupColumn("Min", ImGuiTableColumnFlags_WidthFixed, BaseWidth);16057TableSetupColumn("Avg", ImGuiTableColumnFlags_WidthFixed, BaseWidth);16058TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, BaseWidth);1605916060TableHeadersRow();1606116062for(uint32_t i = 0; i < NumEntries; ++i)16063{16064uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer);1606516066MicroProfileTimerValues Values;16067MicroProfileCalcTimers(TimerIndex, Values);16068const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex];16069const MicroProfileGroupInfo& GI = S.GroupInfo[TI.nGroupIndex];16070TableNextRow();16071ImU32 RowBGColor = GetColorU32((i % 2) ? ImVec4(0.1f, 0.1f, 0.1f, 0.85f) : ImVec4(0.2f, 0.2f, 0.2f, 0.85f));16072TableSetBgColor(ImGuiTableBgTarget_RowBg1, RowBGColor);16073PushID(i);16074float fMax = 0.f, fMin = 0.f, fAvg = 0.f, fTime = 0.f;1607516076auto RightAlignedFloat = [](float f)16077{16078float CellWidth = GetContentRegionAvail().x;16079char Buffer[32];16080stbsp_snprintf(Buffer, sizeof(Buffer) - 1, "%.2f", f);16081ImVec2 TextSize = CalcTextSize(Buffer);16082SetCursorPosX(GetCursorPosX() + (CellWidth - TextSize.x));16083TextUnformatted(Buffer);16084};1608516086TableSetColumnIndex(0);16087Text(GI.pName);16088TableSetColumnIndex(1);16089Text(TI.pName);16090TableSetColumnIndex(2);16091RightAlignedFloat(Values.MaxMs);16092TableSetColumnIndex(3);16093RightAlignedFloat(Values.MinMs);16094TableSetColumnIndex(4);16095RightAlignedFloat(Values.AverageMs);16096TableSetColumnIndex(5);16097RightAlignedFloat(Values.TimeMs);16098PopID();16099}16100EndTable();16101}16102}1610316104void MicroProfileImguiGraphs(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries)16105{16106using namespace ImGui;16107ImGuiIO& io = ImGui::GetIO();16108uint32_t Width = Window.GraphWidth;16109uint32_t Height = (Window.GraphHeight + GetStyle().ItemSpacing.y) * NumEntries;1611016111ImVec2 Pos = ImVec2(0.f, 0.f);16112if(Window.Align == MICROPROFILE_IMGUI_ALIGN_TOP_RIGHT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT)16113Pos.x = io.DisplaySize.x - Width;1611416115if(Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_LEFT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT)16116Pos.y = io.DisplaySize.y - Height;1611716118Pos.x += Window.OffsetX;16119Pos.y += Window.OffsetY;16120for(uint32_t i = 0; i < NumEntries; ++i)16121{16122SetCursorScreenPos(Pos);16123uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer);16124float GraphMax = Entries[i].GraphMax;16125const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex];1612616127MicroProfileImguiTimerState* TimerState = MicroProfileImguiGetTimerState(TimerIndex);1612816129PushID(i << 16 | TimerIndex);16130if(TimerState->nColor == 0)16131TimerState->nColor = MicroProfileGetColor(TimerIndex);16132ImVec4 FrameBg = GetStyleColorVec4(ImGuiCol_FrameBg);16133FrameBg.x = 0.15f;16134FrameBg.y = 0.15f;16135FrameBg.z = 0.15f;16136FrameBg.w = 0.8f;1613716138PushStyleColor(ImGuiCol_PlotLines, MicroProfileImGuiColor(TimerState->nColor));16139PushStyleColor(ImGuiCol_FrameBg, FrameBg);16140uint32_t Start = (ImguiState.GraphPut) % MICROPROFILE_IMGUI_GRAPH_SIZE;16141uint32_t Last = (ImguiState.GraphPut + MICROPROFILE_IMGUI_GRAPH_SIZE - 1) % MICROPROFILE_IMGUI_GRAPH_SIZE;16142PlotLines("", &TimerState->fValues[0], MICROPROFILE_IMGUI_GRAPH_SIZE, Start, nullptr, 0.f, GraphMax, ImVec2(Window.GraphWidth, Window.GraphHeight));1614316144char TimeStr[32];16145stbsp_snprintf(TimeStr, sizeof(TimeStr) - 1, "%.3fms", TimerState->fValues[Last]);16146ImVec2 PlotMin = GetItemRectMin();16147ImVec2 PlotMax = GetItemRectMax();16148ImVec2 NameSize = CalcTextSize(TI.pName);16149ImVec2 NamePos = ImVec2(PlotMin.x + 1, PlotMax.y - NameSize.y - 1);16150ImVec2 TimeSize = CalcTextSize(TimeStr);16151ImVec2 TimePos = ImVec2(PlotMax.x - TimeSize.x - 1, PlotMax.y - TimeSize.y - 1);16152GetWindowDrawList()->AddText(NamePos, GetColorU32(ImGuiCol_Text), TI.pName);16153GetWindowDrawList()->AddText(TimePos, GetColorU32(ImGuiCol_Text), TimeStr);1615416155PopStyleColor();16156PopStyleColor();16157PopID();16158Pos.y += Window.GraphHeight + GetStyle().ItemSpacing.y;16159}16160}1616116162#endif1616316164#undef uprintf1616516166#undef S16167#ifdef _WIN3216168#pragma warning(pop)16169#undef microprofile_fopen_helper16170#endif1617116172#ifdef MICROPROFILE_PS416173#define MICROPROFILE_PS4_IMPL16174#include "microprofile_ps4.h"16175#endif16176#ifdef MICROPROFILE_XBOXONE16177#define MICROPROFILE_XBOXONE_IMPL16178#include "microprofile_xboxone.h"16179#endif1618016181#endif // #if MICROPROFILE_ENABLED1618216183#include "microprofile_html.h"16184#include "microprofile_icons.h"161851618616187