summaryrefslogtreecommitdiffstats
path: root/external/optick/optick_core.h
diff options
context:
space:
mode:
Diffstat (limited to 'external/optick/optick_core.h')
-rw-r--r--external/optick/optick_core.h568
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