87 lines
1.4 KiB
C++
87 lines
1.4 KiB
C++
|
|
||
|
#include "perf_trace.h"
|
||
|
#include "efitime.h"
|
||
|
#include "efifeatures.h"
|
||
|
#include "os_util.h"
|
||
|
|
||
|
#define TRACE_BUFFER_LENGTH 4096
|
||
|
|
||
|
enum class Phase : char
|
||
|
{
|
||
|
Start,
|
||
|
End,
|
||
|
InstantThread,
|
||
|
InstantGlobal,
|
||
|
|
||
|
};
|
||
|
|
||
|
struct TraceEntry
|
||
|
{
|
||
|
PE Event;
|
||
|
Phase Type;
|
||
|
uint8_t Data;
|
||
|
uint8_t ThreadId;
|
||
|
uint32_t Timestamp;
|
||
|
};
|
||
|
|
||
|
static_assert(sizeof(TraceEntry) == 8);
|
||
|
|
||
|
static TraceEntry s_traceBuffer[TRACE_BUFFER_LENGTH];
|
||
|
static size_t s_nextIdx = 0;
|
||
|
|
||
|
void perfEventImpl(PE event, Phase type, uint8_t data)
|
||
|
{
|
||
|
if constexpr (!ENABLE_PERF_TRACE)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint32_t timestamp = getTimeNowLowerNt();
|
||
|
|
||
|
size_t idx;
|
||
|
|
||
|
// Critical section: reserve index under lock
|
||
|
{
|
||
|
bool wasLocked = lockAnyContext();
|
||
|
|
||
|
idx = s_nextIdx++;
|
||
|
if (s_nextIdx >= TRACE_BUFFER_LENGTH)
|
||
|
{
|
||
|
s_nextIdx = 0;
|
||
|
}
|
||
|
|
||
|
if (!wasLocked) {
|
||
|
unlockAnyContext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We can safely write data out of the lock, our spot is reserved
|
||
|
TraceEntry& entry = s_traceBuffer[idx];
|
||
|
|
||
|
entry.Event = event;
|
||
|
entry.Type = type;
|
||
|
entry.ThreadId = 0; // TODO
|
||
|
entry.Timestamp = timestamp;
|
||
|
entry.Data = data;
|
||
|
}
|
||
|
|
||
|
void perfEventBegin(PE event, uint8_t data)
|
||
|
{
|
||
|
perfEventImpl(event, Phase::Start, data);
|
||
|
}
|
||
|
|
||
|
void perfEventEnd(PE event, uint8_t data)
|
||
|
{
|
||
|
perfEventImpl(event, Phase::End, data);
|
||
|
}
|
||
|
|
||
|
void perfEventInstantThread(PE event, uint8_t data)
|
||
|
{
|
||
|
perfEventImpl(event, Phase::InstantThread, data);
|
||
|
}
|
||
|
|
||
|
void perfEventInstantGlobal(PE event, uint8_t data)
|
||
|
{
|
||
|
perfEventImpl(event, Phase::InstantGlobal, data);
|
||
|
}
|