Profiler

Records profiling events into user-specified buffer.

Used together with Zone to record data and with EventRange/ZoneRange/etc. for analysis.

Profiler writes profiling data into a byte buffer passed to Profiler constructor by the user. Once there is not enough space to write any more profiling events, the profiler quietly ignores any events (this can be checked by outOfSpace()). Profiler never allocates heap memory by itself.

Recorded data can be accessed at any time through profileData() and analyzed with help of EventRange, ZoneRange and other tharsis.prof utilities. reset() can be used to clear recorded data and start recording from scratch.

Note:

Profiler is not designed to be used from multiple threads. If you need to profile multiple threads, create a separate Profiler for each thread and either analyze the results through separate EventRange/ZoneRange instances, or merge them through accumulatedZoneRange.

Note:

Accessing profile data from an out-of-space profiler or in the middle of a zone will result in an EventRange that's missing some zone end events. Incomplete raw profiling results or EventRanges should never be concatenated. ZoneRange will automatically end the unfinished zones.

Memory consumption:

Depending on the worload and number of zones, Profiler can eat through assigned memory rather quickly. With 10000 zones at 120 FPS the overhead is going to be around 14 MiB per second.

Constructors

this
this(ubyte[] profileBuffer)

Construct a Profiler writing profiling data to specified buffer.

Members

Functions

checkpointEvent
void checkpointEvent()

Emit a checkpoint event.

diagnostics
Diagnostics diagnostics()

Get diagnostics about the profiler, such as which events are the most common.

outOfSpace
bool outOfSpace()

Is the profiler out of space?

profileData
const(ubyte)[] profileData()

Get the raw data recorded by the profiler.

reset
void reset()

Reset the profiler.

variableEvent
void variableEvent(V value)

Emit a variable event.

zoneEndEvent
void zoneEndEvent(uint nestLevel)

Emit a zone end event, when code exits a zone.

zoneNestLevel
uint zoneNestLevel()

Get the nest level of the current zone, if any.

zoneStartEvent
uint zoneStartEvent(string info)

Emit a zone start event, when code enters a zone.

Manifest constants

maxEventBytes
enum maxEventBytes;

Maximum size of any single event in bytes. Used to quickly check if we're out of space.

Structs

Diagnostics
struct Diagnostics

Diagnostics used to profile the profiler.

Examples

ubyte[] storage = new ubyte[Profiler.maxEventBytes + 2048];
auto profiler = new Profiler(storage);

// Simulate 16 'frames'
foreach(frame; 0 .. 16)
{
    Zone topLevel = Zone(profiler, "frame");
    // Record a variable event (useful for tracking FPS, entity count, network
    // traffic, etc.). Only uint, int and float supported at the moment.
    profiler.variableEvent!"frame" = cast(uint)frame;

    // Simulate frame overhead. Replace this with your frame code.
    {
        Zone nested1 = Zone(profiler, "frameStart");
        foreach(i; 0 .. 1000) { continue; }
    }
    {
        Zone nested2 = Zone(profiler, "frameCore");
        foreach(i; 0 .. 10000) { continue; }
    }
}

// see tharsis.profiler.ranges for how to process recorded data
// This example uses C malloc/free and std.typecons.scoped to show how to use Profiler
// without GC allocations.

const storageLength = Profiler.maxEventBytes + 2048;

import core.stdc.stdlib;
// A simple typed-slice malloc wrapper function would avoid the ugly cast/slicing.
ubyte[] storage  = (cast(ubyte*)malloc(storageLength))[0 .. storageLength];
scope(exit) { free(storage.ptr); }

import std.typecons;
auto profiler = scoped!Profiler(storage);

// std.typecons.scoped! stores the Profiler on the stack.
// Simulate 16 'frames'
foreach(frame; 0 .. 16)
{
    Zone topLevel = Zone(profiler, "frame");

    // Simulate frame overhead. Replace this with your frame code.
    {
        Zone nested1 = Zone(profiler, "frameStart");
        foreach(i; 0 .. 1000) { continue; }
    }
    {
        Zone nested2 = Zone(profiler, "frameCore");
        foreach(i; 0 .. 10000) { continue; }
    }
}

// see tharsis.profiler.ranges for how to process recorded data

Meta