From 868ba6279a20e4d1412c2d576c67400167de6694 Mon Sep 17 00:00:00 2001 From: LaG1924 <12997935+LaG1924@users.noreply.github.com> Date: Tue, 30 Apr 2019 16:12:35 +0500 Subject: Integrated Optick profiler --- external/optick/optick_core.cpp | 1657 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1657 insertions(+) create mode 100644 external/optick/optick_core.cpp (limited to 'external/optick/optick_core.cpp') diff --git a/external/optick/optick_core.cpp b/external/optick/optick_core.cpp new file mode 100644 index 0000000..1d533d0 --- /dev/null +++ b/external/optick/optick_core.cpp @@ -0,0 +1,1657 @@ +#include "optick.config.h" + +#if USE_OPTICK + +#include "optick_core.h" +#include "optick_server.h" + +#include +#include + +////////////////////////////////////////////////////////////////////////// +// Start of the Platform-specific stuff +////////////////////////////////////////////////////////////////////////// +#if defined(OPTICK_MSVC) +#include "optick_core.win.h" +#endif +#if defined(OPTICK_LINUX) +#include "optick_core.linux.h" +#endif +#if defined(OPTICK_OSX) +#include "optick_core.macos.h" +#endif +#if defined(OPTICK_PS4) +#include "optick_core.ps4.h" +#endif +////////////////////////////////////////////////////////////////////////// +// End of the Platform-specific stuff +////////////////////////////////////////////////////////////////////////// + +extern "C" Optick::EventData* NextEvent() +{ + if (Optick::EventStorage* storage = Optick::Core::storage) + { + return &storage->NextEvent(); + } + + return nullptr; +} + +namespace Optick +{ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void* (*Memory::allocate)(size_t) = operator new; +void (*Memory::deallocate)(void* p) = operator delete; +std::atomic Memory::memAllocated; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +uint64_t MurmurHash64A(const void * key, int len, uint64_t seed) +{ + const uint64_t m = 0xc6a4a7935bd1e995; + const int r = 47; + + uint64_t h = seed ^ (len * m); + + const uint64_t * data = (const uint64_t *)key; + const uint64_t * end = data + (len / 8); + + while (data != end) + { + uint64_t k = *data++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + const unsigned char * data2 = (const unsigned char*)data; + + switch (len & 7) + { + case 7: h ^= uint64_t(data2[6]) << 48; + case 6: h ^= uint64_t(data2[5]) << 40; + case 5: h ^= uint64_t(data2[4]) << 32; + case 4: h ^= uint64_t(data2[3]) << 24; + case 3: h ^= uint64_t(data2[2]) << 16; + case 2: h ^= uint64_t(data2[1]) << 8; + case 1: h ^= uint64_t(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +uint64_t StringHash::CalcHash(const char* str) +{ + return MurmurHash64A(str, (int)strlen(str), 0); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Base 64 +// https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} +string base64_decode(string const& encoded_string) { + static string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int in_len = (int)encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + string ret; + + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = (unsigned char)base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = (unsigned char)base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Get current time in milliseconds +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int64 GetTimeMilliSeconds() +{ + return Platform::GetTime() * 1000 / Platform::GetFrequency(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int64 TicksToMs(int64 ticks) +{ + return ticks * 1000 / Platform::GetFrequency(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int64 TicksToUs(int64 ticks) +{ + return ticks * 1000000 / Platform::GetFrequency(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +OutputDataStream& operator<<(OutputDataStream& stream, const TagData& ob) +{ + return stream << ob.timestamp << ob.description->index << ob.data; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& os, const Symbol * const symbol) +{ + OPTICK_VERIFY(symbol, "Can't serialize NULL symbol!", return os); + return os << symbol->address << symbol->function << symbol->file << symbol->line; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& os, const Module& module) +{ + return os << module.path << (uint64)module.address << (uint64)module.size; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// VS TODO: Replace with random access iterator for MemoryPool +template +void SortMemoryPool(MemoryPool& memoryPool) +{ + size_t count = memoryPool.Size(); + if (count == 0) + return; + + vector memoryArray; + memoryArray.resize(count); + memoryPool.ToArray(&memoryArray[0]); + + std::sort(memoryArray.begin(), memoryArray.end()); + + memoryPool.Clear(true); + + for (const T& item : memoryArray) + memoryPool.Add(item); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription* EventDescription::Create(const char* eventName, const char* fileName, const unsigned long fileLine, const unsigned long eventColor /*= Color::Null*/, const unsigned long filter /*= 0*/) +{ + return EventDescriptionBoard::Get().CreateDescription(eventName, fileName, fileLine, eventColor, filter); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription* EventDescription::CreateShared(const char* eventName, const char* fileName, const unsigned long fileLine, const unsigned long eventColor /*= Color::Null*/, const unsigned long filter /*= 0*/) +{ + return EventDescriptionBoard::Get().CreateSharedDescription(eventName, fileName, fileLine, eventColor, filter); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription::EventDescription() : name(""), file(""), line(0), color(0) +{ +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription& EventDescription::operator=(const EventDescription&) +{ + OPTICK_FAILED("It is pointless to copy EventDescription. Please, check you logic!"); return *this; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventData* Event::Start(const EventDescription& description) +{ + EventData* result = nullptr; + + if (EventStorage* storage = Core::storage) + { + result = &storage->NextEvent(); + result->description = &description; + result->Start(); + } + return result; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Stop(EventData& data) +{ + if (EventStorage* storage = Core::storage) + { + data.Stop(); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OPTICK_INLINE PushEvent(EventStorage* pStorage, const EventDescription* description, int64_t timestampStart) +{ + if (EventStorage* storage = pStorage) + { + EventData& result = storage->NextEvent(); + result.description = description; + result.start = timestampStart; + result.finish = EventTime::INVALID_TIMESTAMP; + storage->pushPopEventStack[storage->pushPopEventStackIndex++] = &result; + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OPTICK_INLINE PopEvent(EventStorage* pStorage, int64_t timestampFinish) +{ + if (EventStorage* storage = pStorage) + if (storage->pushPopEventStackIndex > 0) + storage->pushPopEventStack[--storage->pushPopEventStackIndex]->finish = timestampFinish; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Push(const char* name) +{ + if (EventStorage* storage = Core::storage) + { + EventDescription* desc = EventDescription::CreateShared(name); + Push(*desc); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Push(const EventDescription& description) +{ + PushEvent(Core::storage, &description, GetHighPrecisionTime()); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Pop() +{ + PopEvent(Core::storage, GetHighPrecisionTime()); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Add(EventStorage* storage, const EventDescription* description, int64_t timestampStart, int64_t timestampFinish) +{ + EventData& data = storage->eventBuffer.Add(); + data.description = description; + data.start = timestampStart; + data.finish = timestampFinish; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Push(EventStorage* storage, const EventDescription* description, int64_t timestampStart) +{ + PushEvent(storage, description, timestampStart); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Event::Pop(EventStorage* storage, int64_t timestampFinish) +{ + PopEvent(storage, timestampFinish); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventData* GPUEvent::Start(const EventDescription& description) +{ + EventData* result = nullptr; + + if (EventStorage* storage = Core::storage) + result = storage->gpuStorage.Start(description); + + return result; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void GPUEvent::Stop(EventData& data) +{ + if (EventStorage* storage = Core::storage) + storage->gpuStorage.Stop(data); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void FiberSyncData::AttachToThread(EventStorage* storage, uint64_t threadId) +{ + if (storage) + { + FiberSyncData& data = storage->fiberSyncBuffer.Add(); + data.Start(); + data.finish = EventTime::INVALID_TIMESTAMP; + data.threadId = threadId; + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void FiberSyncData::DetachFromThread(EventStorage* storage) +{ + if (storage) + { + if (FiberSyncData* syncData = storage->fiberSyncBuffer.Back()) + { + syncData->Stop(); + } + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, float val) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagFloatBuffer.Add(TagFloat(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, int32_t val) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagS32Buffer.Add(TagS32(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, uint32_t val) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagU32Buffer.Add(TagU32(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, uint64_t val) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagU64Buffer.Add(TagU64(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, float val[3]) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagPointBuffer.Add(TagPoint(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Tag::Attach(const EventDescription& description, const char* val) +{ + if (EventStorage* storage = Core::storage) + if (storage->currentMode & Mode::TAGS) + storage->tagStringBuffer.Add(TagString(description, val)); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream & operator<<(OutputDataStream &stream, const EventDescription &ob) +{ + byte flags = 0; + return stream << ob.name << ob.file << ob.line << ob.filter << ob.color << (float)0.0f << flags; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const EventTime& ob) +{ + return stream << ob.start << ob.finish; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const EventData& ob) +{ + return stream << (EventTime)(ob) << (ob.description ? ob.description->index : (uint32)-1); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const SyncData& ob) +{ + return stream << (EventTime)(ob) << ob.core << ob.reason << ob.newThreadId; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const FiberSyncData& ob) +{ + return stream << (EventTime)(ob) << ob.threadId; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static std::mutex& GetBoardLock() +{ + // Initialize as static local variable to prevent problems with static initialization order + static std::mutex lock; + return lock; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescriptionBoard& EventDescriptionBoard::Get() +{ + static EventDescriptionBoard instance; + return instance; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const EventDescriptionList& EventDescriptionBoard::GetEvents() const +{ + return boardDescriptions; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription* EventDescriptionBoard::CreateDescription(const char* name, const char* file /*= nullptr*/, uint32_t line /*= 0*/, uint32_t color /*= Color::Null*/, uint32_t filter /*= 0*/) +{ + std::lock_guard lock(GetBoardLock()); + + size_t index = boardDescriptions.Size(); + + EventDescription& desc = boardDescriptions.Add(); + desc.index = (uint32)index; + desc.name = name; + desc.file = file; + desc.line = line; + desc.color = color; + desc.filter = filter; + + return &desc; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventDescription* EventDescriptionBoard::CreateSharedDescription(const char* name, const char* file /*= nullptr*/, uint32_t line /*= 0*/, uint32_t color /*= Color::Null*/, uint32_t filter /*= 0*/) +{ + StringHash nameHash(name); + + std::lock_guard lock(sharedLock); + + std::pair cached = sharedDescriptions.insert({ nameHash, nullptr }); + + if (cached.second) + { + const char* nameCopy = sharedNames.Add(name, strlen(name) + 1, false); + cached.first->second = CreateDescription(nameCopy, file, line, color, filter); + } + + return cached.first->second; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator << (OutputDataStream& stream, const EventDescriptionBoard& ob) +{ + std::lock_guard lock(GetBoardLock()); + stream << ob.GetEvents(); + return stream; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ProcessDescription::ProcessDescription(const char* processName, ProcessID pid, uint64 key) : name(processName), processID(pid), uniqueKey(key) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ThreadDescription::ThreadDescription(const char* threadName, ThreadID tid, ProcessID pid, int32 _maxDepth /*= 1*/, int32 _priority /*= 0*/, uint32 _mask /*= 0*/) + : name(threadName), threadID(tid), processID(pid), maxDepth(_maxDepth), priority(_priority), mask(_mask) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int64_t GetHighPrecisionTime() +{ + return Platform::GetTime(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int64_t GetHighPrecisionFrequency() +{ + return Platform::GetFrequency(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream & operator<<(OutputDataStream &stream, const SysCallData &ob) +{ + return stream << (const EventData&)ob << ob.threadID << ob.id; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SysCallData& SysCallCollector::Add() +{ + return syscallPool.Add(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SysCallCollector::Clear() +{ + syscallPool.Clear(false); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool SysCallCollector::Serialize(OutputDataStream& stream) +{ + stream << syscallPool; + + if (!syscallPool.IsEmpty()) + { + syscallPool.Clear(false); + return true; + } + + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void CallstackCollector::Add(const CallstackDesc& desc) +{ + if (uint64* storage = callstacksPool.TryAdd(desc.count + 3)) + { + storage[0] = desc.threadID; + storage[1] = desc.timestamp; + storage[2] = desc.count; + + for (uint64 i = 0; i < desc.count; ++i) + { + storage[3 + i] = desc.callstack[desc.count - i - 1]; + } + } + else + { + uint64& item0 = callstacksPool.Add(); + uint64& item1 = callstacksPool.Add(); + uint64& item2 = callstacksPool.Add(); + + item0 = desc.threadID; + item1 = desc.timestamp; + item2 = desc.count; + + for (uint64 i = 0; i < desc.count; ++i) + { + callstacksPool.Add() = desc.callstack[desc.count - i - 1]; + } + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void CallstackCollector::Clear() +{ + callstacksPool.Clear(false); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool CallstackCollector::SerializeModules(OutputDataStream& stream) +{ + if (SymbolEngine* symEngine = Core::Get().symbolEngine) + { + stream << symEngine->GetModules(); + return true; + } + else + { + stream << (int)0; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool CallstackCollector::SerializeSymbols(OutputDataStream& stream) +{ + typedef unordered_set SymbolSet; + SymbolSet symbolSet; + + for (CallstacksPool::const_iterator it = callstacksPool.begin(); it != callstacksPool.end();) + { + CallstacksPool::const_iterator startIt = it; + OPTICK_UNUSED(startIt); + + uint64 threadID = *it; + OPTICK_UNUSED(threadID); + ++it; //Skip ThreadID + uint64 timestamp = *it; + OPTICK_UNUSED + (timestamp); + ++it; //Skip Timestamp + uint64 count = *it; + count = (count & 0xFF); + ++it; //Skip Count + + bool isBadAddrFound = false; + + for (uint64 i = 0; i < count; ++i) + { + uint64 address = *it; + ++it; + + if (address == 0) + { + isBadAddrFound = true; + } + + if (!isBadAddrFound) + { + symbolSet.insert(address); + } + } + } + + SymbolEngine* symEngine = Core::Get().symbolEngine; + + vector symbols; + symbols.reserve(symbolSet.size()); + + size_t callstackIndex = 0; + + Core::Get().DumpProgress("Resolving addresses... "); + + if (symEngine) + { + for (auto it = symbolSet.begin(); it != symbolSet.end(); ++it) + { + callstackIndex++; + + uint64 address = *it; + if (const Symbol* symbol = symEngine->GetSymbol(address)) + { + symbols.push_back(symbol); + } + } + } + + stream << symbols; + return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool CallstackCollector::SerializeCallstacks(OutputDataStream& stream) +{ + stream << callstacksPool; + + if (!callstacksPool.IsEmpty()) + { + callstacksPool.Clear(false); + return true; + } + + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool CallstackCollector::IsEmpty() const +{ + return callstacksPool.IsEmpty(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream & operator<<(OutputDataStream &stream, const SwitchContextDesc &ob) +{ + return stream << ob.timestamp << ob.oldThreadId << ob.newThreadId << ob.cpuId << ob.reason; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SwitchContextCollector::Add(const SwitchContextDesc& desc) +{ + switchContextPool.Add() = desc; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SwitchContextCollector::Clear() +{ + switchContextPool.Clear(false); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool SwitchContextCollector::Serialize(OutputDataStream& stream) +{ + stream << switchContextPool; + + if (!switchContextPool.IsEmpty()) + { + switchContextPool.Clear(false); + return true; + } + + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(OPTICK_MSVC) +#define CPUID(INFO, ID) __cpuid(INFO, ID) +#include +#elif defined(OPTICK_GCC) +#include +#define CPUID(INFO, ID) __cpuid(ID, INFO[0], INFO[1], INFO[2], INFO[3]) +#else +#error Platform is not supported! +#endif +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +string GetCPUName() +{ + int cpuInfo[4] = { -1 }; + char cpuBrandString[0x40] = { 0 }; + CPUID(cpuInfo, 0x80000000); + unsigned nExIds = cpuInfo[0]; + for (unsigned i = 0x80000000; i <= nExIds; ++i) + { + CPUID(cpuInfo, i); + if (i == 0x80000002) + memcpy(cpuBrandString, cpuInfo, sizeof(cpuInfo)); + else if (i == 0x80000003) + memcpy(cpuBrandString + 16, cpuInfo, sizeof(cpuInfo)); + else if (i == 0x80000004) + memcpy(cpuBrandString + 32, cpuInfo, sizeof(cpuInfo)); + } + return string(cpuBrandString); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Core& Core::Get() +{ + static Core instance; + return instance; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::StartCapture() +{ + pendingState = State::START_CAPTURE; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::StopCapture() +{ + pendingState = State::STOP_CAPTURE; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::CancelCapture() +{ + pendingState = State::CANCEL_CAPTURE; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpCapture() +{ + pendingState = State::DUMP_CAPTURE; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpProgress(const char* message) +{ + progressReportedLastTimestampMS = GetTimeMilliSeconds(); + + OutputDataStream stream; + stream << message; + + Server::Get().Send(DataResponse::ReportProgress, stream); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpEvents(EventStorage& entry, const EventTime& timeSlice, ScopeData& scope) +{ + if (!entry.eventBuffer.IsEmpty()) + { + const EventData* rootEvent = nullptr; + + entry.eventBuffer.ForEach([&](const EventData& data) + { + if (data.finish >= data.start && data.start >= timeSlice.start && timeSlice.finish >= data.finish) + { + if (!rootEvent) + { + rootEvent = &data; + scope.InitRootEvent(*rootEvent); + } + else if (rootEvent->finish < data.finish) + { + scope.Send(); + + rootEvent = &data; + scope.InitRootEvent(*rootEvent); + } + else + { + scope.AddEvent(data); + } + } + }); + + scope.Send(); + + entry.eventBuffer.Clear(false); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpTags(EventStorage& entry, ScopeData& scope) +{ + if (!entry.tagFloatBuffer.IsEmpty() || + !entry.tagS32Buffer.IsEmpty() || + !entry.tagU32Buffer.IsEmpty() || + !entry.tagU64Buffer.IsEmpty() || + !entry.tagPointBuffer.IsEmpty() || + !entry.tagStringBuffer.IsEmpty()) + { + OutputDataStream tagStream; + tagStream << scope.header.boardNumber << scope.header.threadNumber; + tagStream + << (uint32)0 + << entry.tagFloatBuffer + << entry.tagU32Buffer + << entry.tagS32Buffer + << entry.tagU64Buffer + << entry.tagPointBuffer + << (uint32)0 + << (uint32)0 + << entry.tagStringBuffer; + Server::Get().Send(DataResponse::TagsPack, tagStream); + + entry.ClearTags(false); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpThread(ThreadEntry& entry, const EventTime& timeSlice, ScopeData& scope) +{ + // We need to sort events for all the custom thread storages + if (entry.description.threadID == INVALID_THREAD_ID) + entry.Sort(); + + // Events + DumpEvents(entry.storage, timeSlice, scope); + DumpTags(entry.storage, scope); + OPTICK_ASSERT(entry.storage.fiberSyncBuffer.IsEmpty(), "Fiber switch events in native threads?"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpFiber(FiberEntry& entry, const EventTime& timeSlice, ScopeData& scope) +{ + // Events + DumpEvents(entry.storage, timeSlice, scope); + + if (!entry.storage.fiberSyncBuffer.IsEmpty()) + { + OutputDataStream fiberSynchronizationStream; + fiberSynchronizationStream << scope.header.boardNumber; + fiberSynchronizationStream << scope.header.fiberNumber; + fiberSynchronizationStream << entry.storage.fiberSyncBuffer; + Server::Get().Send(DataResponse::FiberSynchronizationData, fiberSynchronizationStream); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventTime CalculateRange(const ThreadEntry& entry, const EventDescription* rootDescription) +{ + EventTime timeSlice = { INT64_MAX, INT64_MIN }; + entry.storage.eventBuffer.ForEach([&](const EventData& data) + { + if (data.description == rootDescription) + { + timeSlice.start = std::min(timeSlice.start, data.start); + timeSlice.finish = std::max(timeSlice.finish, data.finish); + } + }); + return timeSlice; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpFrames(uint32 mode) +{ + std::lock_guard lock(threadsLock); + + if (frames.empty() || threads.empty()) + return; + + ++boardNumber; + + DumpProgress("Generating summary..."); + + GenerateCommonSummary(); + DumpSummary(); + + DumpProgress("Collecting Frame Events..."); + + + ThreadID mainThreadID = Platform::GetThreadID(); + uint32 mainThreadIndex = 0; + for (size_t i = 0; i < threads.size(); ++i) + if (threads[i]->description.threadID == mainThreadID) + mainThreadIndex = (uint32)i; + + EventTime timeSlice = CalculateRange(*threads[mainThreadIndex], GetFrameDescription(FrameType::CPU)); + if (timeSlice.start >= timeSlice.finish) + { + timeSlice.start = frames.front().start; + timeSlice.finish = frames.back().finish; + } + + DumpBoard(mode, timeSlice, mainThreadIndex); + + ScopeData threadScope; + threadScope.header.boardNumber = boardNumber; + threadScope.header.fiberNumber = -1; + + if (gpuProfiler) + gpuProfiler->Dump(mode); + + for (size_t i = 0; i < threads.size(); ++i) + { + threadScope.header.threadNumber = (uint32)i; + DumpThread(*threads[i], timeSlice, threadScope); + } + + ScopeData fiberScope; + fiberScope.header.boardNumber = (uint32)boardNumber; + fiberScope.header.threadNumber = -1; + for (size_t i = 0; i < fibers.size(); ++i) + { + fiberScope.header.fiberNumber = (uint32)i; + DumpFiber(*fibers[i], timeSlice, fiberScope); + } + + frames.clear(); + CleanupThreadsAndFibers(); + + { + DumpProgress("Serializing SwitchContexts"); + OutputDataStream switchContextsStream; + switchContextsStream << boardNumber; + switchContextCollector.Serialize(switchContextsStream); + Server::Get().Send(DataResponse::SynchronizationData, switchContextsStream); + } + + { + DumpProgress("Serializing SysCalls"); + OutputDataStream callstacksStream; + callstacksStream << boardNumber; + syscallCollector.Serialize(callstacksStream); + Server::Get().Send(DataResponse::SyscallPack, callstacksStream); + } + + if (!callstackCollector.IsEmpty()) + { + DumpProgress("Resolving callstacks"); + OutputDataStream symbolsStream; + symbolsStream << boardNumber; + callstackCollector.SerializeModules(symbolsStream); + callstackCollector.SerializeSymbols(symbolsStream); + Server::Get().Send(DataResponse::CallstackDescriptionBoard, symbolsStream); + + DumpProgress("Serializing callstacks"); + OutputDataStream callstacksStream; + callstacksStream << boardNumber; + callstackCollector.SerializeCallstacks(callstacksStream); + Server::Get().Send(DataResponse::CallstackPack, callstacksStream); + } + + Server::Get().Send(DataResponse::NullFrame, OutputDataStream::Empty); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpSummary() +{ + OutputDataStream stream; + + // Board Number + stream << boardNumber; + + // Frames + double frequency = (double)Platform::GetFrequency(); + stream << (uint32_t)frames.size(); + for (const EventTime& frame : frames) + { + double frameTimeMs = 1000.0 * (frame.finish - frame.start) / frequency; + stream << (float)frameTimeMs; + } + + // Summary + stream << (uint32_t)summary.size(); + for (size_t i = 0; i < summary.size(); ++i) + stream << summary[i].first << summary[i].second; + summary.clear(); + + // Attachments + stream << (uint32_t)attachments.size(); + for (const Attachment& att : attachments) + stream << (uint32_t)att.type << att.name << att.data; + attachments.clear(); + + // Send + Server::Get().Send(DataResponse::SummaryPack, stream); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::CleanupThreadsAndFibers() +{ + std::lock_guard lock(threadsLock); + + for (ThreadList::iterator it = threads.begin(); it != threads.end();) + { + if (!(*it)->isAlive) + { + Memory::Delete(*it); + it = threads.erase(it); + } + else + { + ++it; + } + } +} + +void Core::DumpBoard(uint32 mode, EventTime timeSlice, uint32 mainThreadIndex) +{ + OutputDataStream boardStream; + + boardStream << boardNumber; + boardStream << Platform::GetFrequency(); + boardStream << (uint64)0; // Origin + boardStream << (uint32)0; // Precision + boardStream << timeSlice; + boardStream << threads; + boardStream << fibers; + boardStream << mainThreadIndex; + boardStream << EventDescriptionBoard::Get(); + boardStream << (uint32)0; // Tags + boardStream << (uint32)0; // Run + boardStream << (uint32)0; // Filters + boardStream << (uint32)0; // ThreadDescs + boardStream << mode; // Mode + boardStream << processDescs; + boardStream << threadDescs; + boardStream << (uint32)Platform::GetProcessID(); + boardStream << (uint32)std::thread::hardware_concurrency(); + Server::Get().Send(DataResponse::FrameDescriptionBoard, boardStream); + + // Cleanup + processDescs.clear(); + threadDescs.clear(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::GenerateCommonSummary() +{ + AttachSummary("Platform", Platform::GetName()); + AttachSummary("CPU", GetCPUName().c_str()); + if (gpuProfiler) + AttachSummary("GPU", gpuProfiler->GetName().c_str()); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Core::Core() + : progressReportedLastTimestampMS(0) + , boardNumber(0) + , frameNumber(0) + , stateCallback(nullptr) + , currentState(State::DUMP_CAPTURE) + , pendingState(State::DUMP_CAPTURE) + , currentMode(Mode::OFF) + , symbolEngine(nullptr) + , tracer(nullptr) + , gpuProfiler(nullptr) +{ +#if OPTICK_ENABLE_TRACING + tracer = Platform::GetTrace(); + symbolEngine = Platform::GetSymbolEngine(); +#endif + + frameDescriptions[FrameType::CPU] = EventDescription::Create("CPU Frame", __FILE__, __LINE__); + frameDescriptions[FrameType::GPU] = EventDescription::Create("GPU Frame", __FILE__, __LINE__); + frameDescriptions[FrameType::Render] = EventDescription::Create("Render Frame", __FILE__, __LINE__); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::UpdateState() +{ + if (currentState != pendingState) + { + State::Type nextState = pendingState; + if (pendingState == State::DUMP_CAPTURE && currentState == State::START_CAPTURE) + nextState = State::STOP_CAPTURE; + + if ((stateCallback != nullptr) && !stateCallback(nextState)) + return false; + + switch (nextState) + { + case State::START_CAPTURE: + Activate((Mode::Type)settings.mode); + break; + + case State::STOP_CAPTURE: + case State::CANCEL_CAPTURE: + Activate(Mode::OFF); + break; + + case State::DUMP_CAPTURE: + DumpFrames(); + break; + } + currentState = nextState; + return true; + } + return false; +} + + +uint32_t Core::Update() +{ + std::lock_guard lock(coreLock); + + if (currentMode != Mode::OFF) + { + if (!frames.empty()) + frames.back().Stop(); + + if (settings.frameLimit > 0 && frames.size() >= settings.frameLimit) + DumpCapture(); + + if (settings.timeLimitUs > 0) + { + if (TicksToUs(frames.back().finish - frames.front().start) >= settings.timeLimitUs) + DumpCapture(); + } + + if (settings.spikeLimitUs > 0) + { + if (TicksToUs(frames.back().finish - frames.back().start) >= settings.spikeLimitUs) + DumpCapture(); + } + + if (IsTimeToReportProgress()) + DumpCapturingProgress(); + } + + UpdateEvents(); + + while (UpdateState()) {} + + if (currentMode != Mode::OFF) + { + frames.push_back(EventTime()); + frames.back().Start(); + } + + return ++frameNumber; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::UpdateEvents() +{ + Server::Get().Update(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::ReportSwitchContext(const SwitchContextDesc& desc) +{ + switchContextCollector.Add(desc); + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::ReportStackWalk(const CallstackDesc& desc) +{ + callstackCollector.Add(desc); + return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::Activate(Mode::Type mode) +{ + if (mode != currentMode) + { + Mode::Type prevMode = currentMode; + currentMode = mode; + + { + std::lock_guard lock(threadsLock); + for(auto it = threads.begin(); it != threads.end(); ++it) + { + ThreadEntry* entry = *it; + entry->Activate(mode); + } + } + + + if (mode != Mode::OFF) + { + CaptureStatus::Type status = CaptureStatus::ERR_TRACER_FAILED; + + if (tracer && (mode & Mode::TRACER)) + { + std::lock_guard lock(threadsLock); + tracer->SetPassword(settings.password.c_str()); + status = tracer->Start(mode, settings.samplingFrequency, threads); + // Let's retry with more narrow setup + if (status != CaptureStatus::OK && (mode & Mode::AUTOSAMPLING)) + status = tracer->Start((Mode::Type)(mode & ~Mode::AUTOSAMPLING), settings.samplingFrequency, threads); + } + + if (gpuProfiler && (mode & Mode::GPU)) + gpuProfiler->Start(mode); + + SendHandshakeResponse(status); + } + else + { + if (tracer) + tracer->Stop(); + + if (gpuProfiler) + gpuProfiler->Stop(prevMode); + } + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::DumpCapturingProgress() +{ + stringstream stream; + + if (currentMode != Mode::OFF) + { + size_t memUsedKb = Memory::GetAllocatedSize() >> 10; + float memUsedMb = memUsedKb / 1024.0f; + // VS TODO: Format to 3 digits + stream << "Capturing Frame " << (uint32)frames.size() << "..." << std::endl << "Memory Used: " << memUsedMb << " Mb"; + } + + DumpProgress(stream.str().c_str()); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::IsTimeToReportProgress() const +{ + return GetTimeMilliSeconds() > progressReportedLastTimestampMS + 200; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::SendHandshakeResponse(CaptureStatus::Type status) +{ + OutputDataStream stream; + stream << (uint32)status; + stream << Platform::GetName(); + stream << Server::Get().GetHostName(); + Server::Get().Send(DataResponse::Handshake, stream); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::IsRegistredThread(ThreadID id) +{ + std::lock_guard lock(threadsLock); + + for (ThreadList::iterator it = threads.begin(); it != threads.end(); ++it) + { + ThreadEntry* entry = *it; + if (entry->description.threadID == id) + { + return true; + } + } + return false; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ThreadEntry* Core::RegisterThread(const ThreadDescription& description, EventStorage** slot) +{ + std::lock_guard lock(threadsLock); + + ThreadEntry* entry = Memory::New(description, slot); + threads.push_back(entry); + + if ((currentMode != Mode::OFF) && slot != nullptr) + *slot = &entry->storage; + + return entry; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::UnRegisterThread(ThreadID threadID, bool keepAlive) +{ + std::lock_guard lock(threadsLock); + + for (ThreadList::iterator it = threads.begin(); it != threads.end(); ++it) + { + ThreadEntry* entry = *it; + if (entry->description.threadID == threadID && entry->isAlive) + { + if ((currentMode == Mode::OFF) && !keepAlive) + { + Memory::Delete(entry); + threads.erase(it); + return true; + } + else + { + entry->isAlive = false; + return true; + } + } + } + + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::RegisterFiber(const FiberDescription& description, EventStorage** slot) +{ + std::lock_guard lock(coreLock); + FiberEntry* entry = Memory::New(description); + fibers.push_back(entry); + entry->storage.isFiberStorage = true; + *slot = &entry->storage; + return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::RegisterProcessDescription(const ProcessDescription& description) +{ + processDescs.push_back(description); + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::RegisterThreadDescription(const ThreadDescription& description) +{ + threadDescs.push_back(description); + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::SetStateChangedCallback(StateCallback cb) +{ + stateCallback = cb; + return stateCallback != nullptr; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::AttachSummary(const char* key, const char* value) +{ + summary.push_back(make_pair(string(key), string(value))); + return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::AttachFile(File::Type type, const char* name, const uint8_t* data, uint32_t size) +{ + if (size > 0) + { + attachments.push_back(Attachment(type, name)); + Attachment& attachment = attachments.back(); + attachment.data.resize(size); + memcpy(&attachment.data[0], data, size); + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::AttachFile(File::Type type, const char* name, std::istream& stream) +{ + std::streampos beg = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streampos end = stream.tellg(); + stream.seekg(beg, std::ios::beg); + + size_t size =(size_t)(end - beg); + void* buffer = Memory::Alloc(size); + + stream.read((char*)buffer, size); + bool result = AttachFile(type, name, (uint8*)buffer, (uint32_t)size); + + Memory::Free(buffer); + return result; + +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::AttachFile(File::Type type, const char* name, const char* path) +{ + std::ifstream stream(path, std::ios::binary); + return AttachFile(type, name, stream); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::AttachFile(File::Type type, const char* name, const wchar_t* path) +{ +#if defined(OPTICK_MSVC) + std::ifstream stream(path, std::ios::binary); + return AttachFile(type, name, stream); +#else + char p[256] = { 0 }; + wcstombs(p, path, sizeof(p)); + std::ifstream stream(p, std::ios::binary); + return AttachFile(type, name, stream); +#endif +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Core::InitGPUProfiler(GPUProfiler* profiler) +{ + OPTICK_ASSERT(gpuProfiler == nullptr, "Can't reinitialize GPU profiler! Not supported yet!"); + Memory::Delete(gpuProfiler); + gpuProfiler = profiler; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Core::SetSettings(const CaptureSettings& captureSettings) +{ + settings = captureSettings; + + //if (tracer) + //{ + // string decoded = base64_decode(encodedPassword); + // tracer->SetPassword(decoded.c_str()); + // return true; + //} + return false; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const EventDescription* Core::GetFrameDescription(FrameType::Type frame) const +{ + return frameDescriptions[frame]; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Core::~Core() +{ + std::lock_guard lock(threadsLock); + + for (ThreadList::iterator it = threads.begin(); it != threads.end(); ++it) + { + Memory::Delete(*it); + } + threads.clear(); + + for (FiberList::iterator it = fibers.begin(); it != fibers.end(); ++it) + { + Memory::Delete(*it); + } + fibers.clear(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const vector& Core::GetThreads() const +{ + return threads; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_THREAD_LOCAL EventStorage* Core::storage = nullptr; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ScopeHeader::ScopeHeader() : boardNumber(0), threadNumber(0) +{ + +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const ScopeHeader& header) +{ + return stream << header.boardNumber << header.threadNumber << header.fiberNumber << header.event; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const ScopeData& ob) +{ + return stream << ob.header << ob.categories << ob.events; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const ThreadDescription& description) +{ + return stream << description.threadID << description.processID << description.name << description.maxDepth << description.priority << description.mask; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const ThreadEntry* entry) +{ + return stream << entry->description; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const FiberDescription& description) +{ + return stream << description.id; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const FiberEntry* entry) +{ + return stream << entry->description; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const ProcessDescription& description) +{ + return stream << description.processID << description.name << description.uniqueKey; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool SetStateChangedCallback(StateCallback cb) +{ + return Core::Get().SetStateChangedCallback(cb); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool AttachSummary(const char* key, const char* value) +{ + return Core::Get().AttachSummary(key, value); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool AttachFile(File::Type type, const char* name, const uint8_t* data, uint32_t size) +{ + return Core::Get().AttachFile(type, name, data, size); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool AttachFile(File::Type type, const char* name, const char* path) +{ + return Core::Get().AttachFile(type, name, path); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool AttachFile(File::Type type, const char* name, const wchar_t* path) +{ + return Core::Get().AttachFile(type, name, path); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator<<(OutputDataStream& stream, const Point& ob) +{ + return stream << ob.x << ob.y << ob.z; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API uint32_t NextFrame() +{ + return Core::NextFrame(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool IsActive(Mode::Type mode /*= Mode::INSTRUMENTATION_EVENTS*/) +{ + return (Core::Get().currentMode & mode) != 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API EventStorage** GetEventStorageSlotForCurrentThread() +{ + return &Core::Get().storage; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool IsFiberStorage(EventStorage* fiberStorage) +{ + return fiberStorage->isFiberStorage; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool RegisterThread(const char* name) +{ + return Core::Get().RegisterThread(ThreadDescription(name, Platform::GetThreadID(), Platform::GetProcessID()), &Core::storage) != nullptr; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool RegisterThread(const wchar_t* name) +{ + const int THREAD_NAME_LENGTH = 128; + char mbName[THREAD_NAME_LENGTH]; + wcstombs_s(mbName, name, THREAD_NAME_LENGTH); + + return Core::Get().RegisterThread(ThreadDescription(mbName, Platform::GetThreadID(), Platform::GetProcessID()), &Core::storage) != nullptr; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool UnRegisterThread(bool keepAlive) +{ + return Core::Get().UnRegisterThread(Platform::GetThreadID(), keepAlive); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API bool RegisterFiber(uint64 fiberId, EventStorage** slot) +{ + return Core::Get().RegisterFiber(FiberDescription(fiberId), slot); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API EventStorage* RegisterStorage(const char* name, uint64_t threadID, ThreadMask::Type type) +{ + ThreadEntry* entry = Core::Get().RegisterThread(ThreadDescription(name, threadID, Platform::GetProcessID(), 1, 0, type), nullptr); + return entry ? &entry->storage : nullptr; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API void GpuFlip(void* swapChain) +{ + if (GPUProfiler* gpuProfiler = Core::Get().gpuProfiler) + gpuProfiler->Flip(swapChain); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API GPUContext SetGpuContext(GPUContext context) +{ + if (EventStorage* storage = Core::storage) + { + GPUContext prevContext = storage->gpuStorage.context; + storage->gpuStorage.context = context; + return prevContext; + } + return GPUContext(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPTICK_API const EventDescription* GetFrameDescription(FrameType::Type frame) +{ + return Core::Get().GetFrameDescription(frame); + +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventStorage::EventStorage(): currentMode(Mode::OFF), pushPopEventStackIndex(0), isFiberStorage(false) +{ + +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ThreadEntry::Activate(Mode::Type mode) +{ + if (!isAlive) + return; + + if (mode != Mode::OFF) + storage.Clear(true); + + if (threadTLS != nullptr) + { + storage.currentMode = mode; + *threadTLS = mode != Mode::OFF ? &storage : nullptr; + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ThreadEntry::Sort() +{ + SortMemoryPool(storage.eventBuffer); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IsSleepOnlyScope(const ScopeData& scope) +{ + //if (!scope.categories.empty()) + // return false; + + const vector& events = scope.events; + for(auto it = events.begin(); it != events.end(); ++it) + { + const EventData& data = *it; + + if (data.description->color != Color::White) + { + return false; + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ScopeData::Send() +{ + if (!events.empty() || !categories.empty()) + { + if (!IsSleepOnlyScope(*this)) + { + OutputDataStream frameStream; + frameStream << *this; + Server::Get().Send(DataResponse::EventFrame, frameStream); + } + } + + Clear(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void ScopeData::Clear() +{ + events.clear(); + categories.clear(); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void EventStorage::GPUStorage::Clear(bool preserveMemory) +{ + for (size_t i = 0; i < gpuBuffer.size(); ++i) + for (int j = 0; j < GPU_QUEUE_COUNT; ++j) + gpuBuffer[i][j].Clear(preserveMemory); +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +EventData* EventStorage::GPUStorage::Start(const EventDescription &desc) +{ + if (GPUProfiler* gpuProfiler = Core::Get().gpuProfiler) + { + EventData& result = gpuBuffer[context.node][context.queue].Add(); + result.description = &desc; + result.start = EventTime::INVALID_TIMESTAMP; + result.finish = EventTime::INVALID_TIMESTAMP; + gpuProfiler->QueryTimestamp(context.cmdBuffer, &result.start); + return &result; + } + return nullptr; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void EventStorage::GPUStorage::Stop(EventData& data) +{ + if (GPUProfiler* gpuProfiler = Core::Get().gpuProfiler) + { + gpuProfiler->QueryTimestamp(context.cmdBuffer, &data.finish); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +#endif //USE_OPTICK \ No newline at end of file -- cgit v1.2.3