diff options
Diffstat (limited to 'external/optick/optick_core.h')
-rw-r--r-- | external/optick/optick_core.h | 568 |
1 files changed, 568 insertions, 0 deletions
diff --git a/external/optick/optick_core.h b/external/optick/optick_core.h new file mode 100644 index 0000000..9ddf46b --- /dev/null +++ b/external/optick/optick_core.h @@ -0,0 +1,568 @@ +#pragma once +#include "optick.config.h" + +#if USE_OPTICK + +#include <mutex> +#include <thread> + +#include "optick_common.h" + +#include "optick_memory.h" +#include "optick_message.h" +#include "optick_serialization.h" + +#include "optick_gpu.h" + +#include <atomic> + +// We expect to have 1k unique strings going through Optick at once +// The chances to hit a collision are 1 in 10 trillion (odds of a meteor landing on your house) +// We should be quite safe here :) +// https://preshing.com/20110504/hash-collision-probabilities/ +// Feel free to add a seed and wait for another strike if armageddon starts +namespace Optick +{ + struct StringHash + { + uint64 hash; + + StringHash(size_t h) : hash(h) {} + StringHash(const char* str) : hash(CalcHash(str)) {} + + bool operator==(const StringHash& other) const { return hash == other.hash; } + bool operator<(const StringHash& other) const { return hash < other.hash; } + + static uint64 CalcHash(const char* str); + }; +} + +// Overriding default hash function to return hash value directly +namespace std +{ + template<> + struct hash<Optick::StringHash> + { + size_t operator()(const Optick::StringHash& x) const + { + return (size_t)x.hash; + } + }; +} + +namespace Optick +{ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct Trace; +struct SymbolEngine; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ScopeHeader +{ + EventTime event; + uint32 boardNumber; + int32 threadNumber; + int32 fiberNumber; + + ScopeHeader(); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream& operator << ( OutputDataStream& stream, const ScopeHeader& ob); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ScopeData +{ + ScopeHeader header; + vector<EventData> categories; + vector<EventData> events; + + void AddEvent(const EventData& data) + { + events.push_back(data); + if (data.description->color != Color::Null) + { + categories.push_back(data); + } + } + + void InitRootEvent(const EventData& data) + { + header.event = data; + AddEvent(data); + } + + void Send(); + void Clear(); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(OPTICK_MSVC) +#pragma warning( push ) +#pragma warning( disable : 4996 ) +#endif //OPTICK_MSVC +template<int N> +struct OptickString +{ + char data[N]; + OptickString() {} + OptickString<N>& operator=(const char* text) { strncpy(data, text ? text : "null", N - 1); data[N - 1] = 0; return *this; } + OptickString(const char* text) { *this = text; } +}; +#if defined(OPTICK_MSVC) +#pragma warning( pop ) +#endif +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct Point +{ + float x, y, z; + Point() {} + Point(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} + Point(float pos[3]) : x(pos[0]), y(pos[1]), z(pos[2]) {} +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template<int N> +OutputDataStream& operator<<(OutputDataStream &stream, const OptickString<N>& ob) +{ + size_t length = strnlen(ob.data, N); + stream << (uint32)length; + return stream.Write(ob.data, length); +} +OutputDataStream& operator<<(OutputDataStream& stream, const Point& ob); +OutputDataStream& operator<<(OutputDataStream& stream, const ScopeData& ob); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef MemoryPool<EventData, 1024> EventBuffer; +typedef MemoryPool<const EventData*, 32> CategoryBuffer; +typedef MemoryPool<SyncData, 1024> SynchronizationBuffer; +typedef MemoryPool<FiberSyncData, 1024> FiberSyncBuffer; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef OptickString<32> ShortString; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef TagData<float> TagFloat; +typedef TagData<int32> TagS32; +typedef TagData<uint32> TagU32; +typedef TagData<uint64> TagU64; +typedef TagData<Point> TagPoint; +typedef TagData<ShortString> TagString; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef MemoryPool<TagFloat, 1024> TagFloatBuffer; +typedef MemoryPool<TagS32, 1024> TagS32Buffer; +typedef MemoryPool<TagU32, 1024> TagU32Buffer; +typedef MemoryPool<TagU64, 1024> TagU64Buffer; +typedef MemoryPool<TagPoint, 64> TagPointBuffer; +typedef MemoryPool<TagString, 1024> TagStringBuffer; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Base64 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +string base64_decode(string const& encoded_string); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Board +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef MemoryPool<EventDescription, 4096> EventDescriptionList; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class EventDescriptionBoard +{ + // List of stored Event Descriptions + EventDescriptionList boardDescriptions; + + // Shared Descriptions + typedef unordered_map<StringHash, EventDescription*> DescriptionMap; + DescriptionMap sharedDescriptions; + MemoryBuffer<64 * 1024> sharedNames; + std::mutex sharedLock; + +public: + EventDescription* CreateDescription(const char* name, const char* file = nullptr, uint32_t line = 0, uint32_t color = Color::Null, uint32_t filter = 0); + EventDescription* CreateSharedDescription(const char* name, const char* file = nullptr, uint32_t line = 0, uint32_t color = Color::Null, uint32_t filter = 0); + + static EventDescriptionBoard& Get(); + + const EventDescriptionList& GetEvents() const; + + friend OutputDataStream& operator << (OutputDataStream& stream, const EventDescriptionBoard& ob); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct EventStorage +{ + Mode::Type currentMode; + EventBuffer eventBuffer; + FiberSyncBuffer fiberSyncBuffer; + + TagFloatBuffer tagFloatBuffer; + TagS32Buffer tagS32Buffer; + TagU32Buffer tagU32Buffer; + TagU64Buffer tagU64Buffer; + TagPointBuffer tagPointBuffer; + TagStringBuffer tagStringBuffer; + + struct GPUStorage + { + static const int MAX_GPU_NODES = 2; + array<array<EventBuffer, GPU_QUEUE_COUNT>, MAX_GPU_NODES> gpuBuffer; + GPUContext context; + + void Clear(bool preserveMemory); + + EventData* Start(const EventDescription& desc); + void Stop(EventData& data); + }; + GPUStorage gpuStorage; + + uint32 pushPopEventStackIndex; + array<EventData*, 32> pushPopEventStack; + + bool isFiberStorage; + + EventStorage(); + + OPTICK_INLINE EventData& NextEvent() + { + return eventBuffer.Add(); + } + + // Free all temporary memory + void Clear(bool preserveContent) + { + currentMode = Mode::OFF; + eventBuffer.Clear(preserveContent); + fiberSyncBuffer.Clear(preserveContent); + gpuStorage.Clear(preserveContent); + ClearTags(preserveContent); + + while (pushPopEventStackIndex) + { + pushPopEventStack[--pushPopEventStackIndex] = nullptr; + } + } + + void ClearTags(bool preserveContent) + { + tagFloatBuffer.Clear(preserveContent); + tagS32Buffer.Clear(preserveContent); + tagU32Buffer.Clear(preserveContent); + tagU64Buffer.Clear(preserveContent); + tagPointBuffer.Clear(preserveContent); + tagStringBuffer.Clear(preserveContent); + } + + void Reset() + { + Clear(true); + } +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ProcessDescription +{ + string name; + ProcessID processID; + uint64 uniqueKey; + ProcessDescription(const char* processName, ProcessID pid, uint64 key); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ThreadDescription +{ + string name; + ThreadID threadID; + ProcessID processID; + int32 maxDepth; + int32 priority; + uint32 mask; + + ThreadDescription(const char* threadName, ThreadID tid, ProcessID pid, int32 maxDepth = 1, int32 priority = 0, uint32 mask = 0); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct FiberDescription +{ + uint64 id; + + FiberDescription(uint64 _id) + : id(_id) + {} +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct ThreadEntry +{ + ThreadDescription description; + EventStorage storage; + EventStorage** threadTLS; + + bool isAlive; + + ThreadEntry(const ThreadDescription& desc, EventStorage** tls) : description(desc), threadTLS(tls), isAlive(true) {} + void Activate(Mode::Type mode); + void Sort(); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct FiberEntry +{ + FiberDescription description; + EventStorage storage; + + FiberEntry(const FiberDescription& desc) : description(desc) {} +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef vector<ThreadEntry*> ThreadList; +typedef vector<FiberEntry*> FiberList; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct SysCallData : EventData +{ + uint64 id; + uint64 threadID; +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OutputDataStream &operator << (OutputDataStream &stream, const SysCallData &ob); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class SysCallCollector +{ + typedef MemoryPool<SysCallData, 1024 * 32> SysCallPool; +public: + SysCallPool syscallPool; + + SysCallData& Add(); + void Clear(); + + bool Serialize(OutputDataStream& stream); +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct CallstackDesc +{ + uint64 threadID; + uint64 timestamp; + uint64* callstack; + uint8 count; +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CallstackCollector +{ + // Packed callstack list: {ThreadID, Timestamp, Count, Callstack[Count]} + typedef MemoryPool<uint64, 1024 * 32> CallstacksPool; + CallstacksPool callstacksPool; +public: + void Add(const CallstackDesc& desc); + void Clear(); + + bool SerializeModules(OutputDataStream& stream); + bool SerializeSymbols(OutputDataStream& stream); + bool SerializeCallstacks(OutputDataStream& stream); + + bool IsEmpty() const; +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct SwitchContextDesc +{ + int64_t timestamp; + uint64 oldThreadId; + uint64 newThreadId; + uint8 cpuId; + uint8 reason; +}; +////////////////////////////////////////////////////////////////////////// +OutputDataStream &operator << (OutputDataStream &stream, const SwitchContextDesc &ob); +////////////////////////////////////////////////////////////////////////// +class SwitchContextCollector +{ + typedef MemoryPool<SwitchContextDesc, 1024 * 32> SwitchContextPool; + SwitchContextPool switchContextPool; +public: + void Add(const SwitchContextDesc& desc); + void Clear(); + bool Serialize(OutputDataStream& stream); +}; +////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct CaptureStatus +{ + enum Type + { + OK = 0, + ERR_TRACER_ALREADY_EXISTS = 1, + ERR_TRACER_ACCESS_DENIED = 2, + ERR_TRACER_FAILED = 3, + ERR_TRACER_INVALID_PASSWORD = 4, + }; +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class Core +{ + std::recursive_mutex coreLock; + std::recursive_mutex threadsLock; + + ThreadList threads; + FiberList fibers; + + int64 progressReportedLastTimestampMS; + + vector<EventTime> frames; + uint32 boardNumber; + + CallstackCollector callstackCollector; + SwitchContextCollector switchContextCollector; + + vector<std::pair<string, string>> summary; + + std::atomic<uint32_t> frameNumber; + + struct Attachment + { + string name; + vector<uint8_t> data; + File::Type type; + Attachment(File::Type t, const char* n) : name(n), type(t) {} + }; + list<Attachment> attachments; + + StateCallback stateCallback; + + vector<ProcessDescription> processDescs; + vector<ThreadDescription> threadDescs; + + array<const EventDescription*, FrameType::COUNT> frameDescriptions; + + State::Type currentState; + State::Type pendingState; + + CaptureSettings settings; + + void UpdateEvents(); + uint32_t Update(); + bool UpdateState(); + + Core(); + ~Core(); + + static Core notThreadSafeInstance; + + void DumpCapturingProgress(); + void SendHandshakeResponse(CaptureStatus::Type status); + + + void DumpEvents(EventStorage& entry, const EventTime& timeSlice, ScopeData& scope); + void DumpTags(EventStorage& entry, ScopeData& scope); + void DumpThread(ThreadEntry& entry, const EventTime& timeSlice, ScopeData& scope); + void DumpFiber(FiberEntry& entry, const EventTime& timeSlice, ScopeData& scope); + + void CleanupThreadsAndFibers(); + + void DumpBoard(uint32 mode, EventTime timeSlice, uint32 mainThreadIndex); + + void GenerateCommonSummary(); +public: + void Activate(Mode::Type mode); + volatile Mode::Type currentMode; + + // Active Frame (is used as buffer) + static OPTICK_THREAD_LOCAL EventStorage* storage; + + // Resolves symbols + SymbolEngine* symbolEngine; + + // Controls GPU activity + // Graphics graphics; + + // System scheduler trace + Trace* tracer; + + // SysCall Collector + SysCallCollector syscallCollector; + + // GPU Profiler + GPUProfiler* gpuProfiler; + + // Returns thread collection + const vector<ThreadEntry*>& GetThreads() const; + + // Request to start a new capture + void StartCapture(); + + // Request to stop an active capture + void StopCapture(); + + // Request to stop an active capture + void CancelCapture(); + + // Requests to dump current capture + void DumpCapture(); + + // Report switch context event + bool ReportSwitchContext(const SwitchContextDesc& desc); + + // Report switch context event + bool ReportStackWalk(const CallstackDesc& desc); + + // Serialize and send current profiling progress + void DumpProgress(const char* message = ""); + + // Too much time from last report + bool IsTimeToReportProgress() const; + + // Serialize and send frames + void DumpFrames(uint32 mode = Mode::DEFAULT); + + // Serialize and send frames + void DumpSummary(); + + // Registers thread and create EventStorage + ThreadEntry* RegisterThread(const ThreadDescription& description, EventStorage** slot); + + // UnRegisters thread + bool UnRegisterThread(ThreadID threadId, bool keepAlive = false); + + // Check is registered thread + bool IsRegistredThread(ThreadID id); + + // Registers finer and create EventStorage + bool RegisterFiber(const FiberDescription& description, EventStorage** slot); + + // Registers ProcessDescription + bool RegisterProcessDescription(const ProcessDescription& description); + + // Registers ThreaDescription (used for threads from other processes) + bool RegisterThreadDescription(const ThreadDescription& description); + + // Sets state change callback + bool SetStateChangedCallback(StateCallback cb); + + // Attaches a key-value pair to the next capture + bool AttachSummary(const char* key, const char* value); + + // Attaches a screenshot to the current capture + bool AttachFile(File::Type type, const char* name, const uint8_t* data, uint32_t size); + bool AttachFile(File::Type type, const char* name, std::istream& stream); + bool AttachFile(File::Type type, const char* name, const char* path); + bool AttachFile(File::Type type, const char* name, const wchar_t* path); + + // Initalizes GPU profiler + void InitGPUProfiler(GPUProfiler* profiler); + + // Initializes root password for the device + bool SetSettings(const CaptureSettings& settings); + + // Current Frame Number (since the game started) + uint32_t GetCurrentFrame() const { return frameNumber; } + + // Returns Frame Description + const EventDescription* GetFrameDescription(FrameType::Type frame) const; + + // NOT Thread Safe singleton (performance) + static Core& Get(); + + // Main Update Function + static uint32_t NextFrame() { return Get().Update(); } +}; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +#endif //USE_OPTICK
\ No newline at end of file |