Skip to content

Instantly share code, notes, and snippets.

@WheretIB
Created October 2, 2019 06:56
Show Gist options
  • Save WheretIB/550717d32cab60d9cb78d256f0fb9a58 to your computer and use it in GitHub Desktop.
Save WheretIB/550717d32cab60d9cb78d256f0fb9a58 to your computer and use it in GitHub Desktop.
#pragma once
#include <assert.h>
#include "Output.h"
namespace NULLCTime
{
void clockMicroInit();
unsigned clockMicro();
}
namespace NULLC
{
template<typename T>
struct TraceArray
{
TraceArray(unsigned size)
{
count = 0;
max = size;
data = new T[size];
}
~TraceArray()
{
delete[] data;
}
unsigned count;
unsigned max;
T *data;
};
struct TraceScopeToken
{
TraceScopeToken()
{
category = "";
name = "";
}
TraceScopeToken(const char *category, const char *name) : category(category), name(name)
{
}
const char *category;
const char *name;
};
struct TraceEvent
{
unsigned isEnter : 1;
unsigned isLabel : 1;
unsigned token : 30;
unsigned ts;
};
void TraceDump();
struct TraceContext
{
TraceContext(): scopeTokens(4096), labels(262144), events(262144), outputBuf(32768), tempBuf(1024)
{
output.stream = output.openStream("trace.json");
output.outputBuf = outputBuf.data;
output.outputBufSize = outputBuf.max;
output.tempBuf = tempBuf.data;
output.tempBufSize = tempBuf.max;
output.Print('[');
needComma = false;
openEvent = false;
depth = 0;
outputDepth = 0;
}
~TraceContext()
{
TraceDump();
output.Print(']');
output.Flush();
output.closeStream(output.stream);
output.stream = NULL;
}
OutputContext output;
bool needComma;
bool openEvent;
unsigned depth;
unsigned outputDepth;
TraceArray<TraceScopeToken> scopeTokens;
TraceArray<char> labels;
TraceArray<TraceEvent> events;
TraceArray<char> outputBuf;
TraceArray<char> tempBuf;
};
extern TraceContext *traceContext;
inline TraceContext* TraceGetContext()
{
static TraceContext context;
NULLCTime::clockMicroInit();
return &context;
}
inline unsigned TraceGetToken(const char *category, const char *name)
{
TraceContext &context = *traceContext;
assert(context.scopeTokens.count < context.scopeTokens.max);
if(context.scopeTokens.count < context.scopeTokens.max)
context.scopeTokens.data[context.scopeTokens.count] = TraceScopeToken(category, name);
return context.scopeTokens.count++;
}
inline unsigned TraceGetDepth()
{
TraceContext &context = *traceContext;
return context.depth;
}
inline void TraceEnter(unsigned token)
{
TraceContext &context = *traceContext;
if(context.events.count == context.events.max)
TraceDump();
TraceEvent &traceEvent = context.events.data[context.events.count++];
traceEvent.isEnter = true;
traceEvent.isLabel = false;
traceEvent.token = token;
traceEvent.ts = NULLCTime::clockMicro();
context.depth++;
}
inline void TraceLeave()
{
TraceContext &context = *traceContext;
if(context.events.count == context.events.max)
TraceDump();
TraceEvent &traceEvent = context.events.data[context.events.count++];
traceEvent.isEnter = false;
traceEvent.isLabel = false;
traceEvent.token = 0;
traceEvent.ts = NULLCTime::clockMicro();
assert(context.depth != 0);
context.depth--;
}
inline void TraceLeaveTo(unsigned depth)
{
TraceContext &context = *traceContext;
while(context.depth > depth)
TraceLeave();
}
inline void TraceLabel(const char *str)
{
TraceContext &context = *traceContext;
unsigned count = unsigned(strlen(str)) + 1;
if(context.labels.count + count >= context.labels.max || context.events.count == context.events.max)
TraceDump();
assert(count < context.labels.max);
unsigned token = context.labels.count;
memcpy(&context.labels.data[context.labels.count], str, count);
context.labels.count += count;
TraceEvent &traceEvent = context.events.data[context.events.count++];
traceEvent.isEnter = false;
traceEvent.isLabel = true;
traceEvent.token = token;
traceEvent.ts = 0;
}
struct TraceScope
{
TraceScope(unsigned token)
{
TraceEnter(token);
}
~TraceScope()
{
TraceLeave();
}
};
inline void TraceDump()
{
TraceContext &context = *traceContext;
unsigned currentLabel = 0;
for(unsigned i = 0; i < context.events.count; i++)
{
TraceEvent &traceEvent = context.events.data[i];
if(traceEvent.isEnter)
{
TraceScopeToken &token = context.scopeTokens.data[traceEvent.token];
if(context.openEvent)
{
if(currentLabel != 0)
{
context.output.Printf("}");
currentLabel = 0;
}
context.output.Printf("},\n");
}
else if(context.needComma)
{
context.output.Printf(",\n");
context.needComma = false;
}
context.openEvent = false;
context.outputDepth++;
if(context.outputDepth > 32)
continue;
context.output.Printf("{\"ph\":\"B\",\"ts\":%d,\"pid\":1,\"tid\":1,\"name\":\"%s\",\"cat\":\"%s\"", traceEvent.ts, token.name, token.category);
context.openEvent = true;
}
else if(traceEvent.isLabel)
{
if(context.outputDepth > 32)
continue;
if(currentLabel == 0)
context.output.Printf(",\"args\":{");
else
context.output.Printf(",");
context.output.Printf("\"label %d\":\"%s\"", currentLabel, &context.labels.data[traceEvent.token]);
currentLabel++;
}
else
{
if(context.openEvent)
{
if(currentLabel != 0)
{
context.output.Printf("}");
currentLabel = 0;
}
context.output.Printf("},\n");
}
else if(context.needComma)
{
context.output.Printf(",\n");
context.needComma = false;
}
context.openEvent = false;
if(context.outputDepth > 32)
{
context.outputDepth--;
continue;
}
context.output.Printf("{\"ph\":\"E\",\"ts\":%d,\"pid\":1,\"tid\":1}", traceEvent.ts);
context.needComma = true;
context.outputDepth--;
}
}
if(context.openEvent)
{
if(currentLabel != 0)
{
context.output.Printf("}");
currentLabel = 0;
}
context.output.Printf("}");
context.needComma = true;
}
context.openEvent = false;
context.events.count = 0;
context.labels.count = 0;
}
}
#define TRACE_SCOPE(category, name) static unsigned token = NULLC::TraceGetToken(category, name); NULLC::TraceScope traceScope(token)
#define TRACE_LABEL(str) NULLC::TraceLabel(str)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment