Skip to main content

Overview

Tracer is Atlas Engine’s lightweight TCP-based diagnostics system that provides real-time telemetry, logging, and profiling data. It enables you to monitor render performance, track resource usage, and debug issues without impacting production builds.

Architecture

Tracer uses a client-server model:
  • Engine Client: Sends telemetry packets over TCP (default port 5123)
  • Tracer Server: External tool that receives and visualizes diagnostic data
  • NetworkPipe: TCP connection managing message streaming

Getting Started

Starting Tracer

#include <atlas/tracer/log.h>

// Start tracer connection on default port (5123)
TracerServices::getInstance().startTracing(TRACER_PORT);

// Check connection status
if (TracerServices::getInstance().isOk()) {
    atlas_log("Tracer connected successfully");
}

Basic Logging

// Log an informational message
atlas_log("Application started");

// Log a warning
atlas_warning("Texture quality reduced for performance");

// Log an error
atlas_error("Failed to load model: file not found");
Log messages automatically include:
  • Timestamp
  • Source file and line number (log.h:80, log.h:82, log.h:85)
  • Severity level
  • Message content

Performance Profiling

Timing Scopes

Use DebugTimer to measure execution time:
{
    DebugTimer timer("ShadowPass");
    renderShadows();
} // Timer stops and reports duration automatically

{
    DebugTimer timer("PhysicsUpdate");
    physics.update(deltaTime);
}

Manual Timing

DebugTimer timer("CustomOperation");
performExpensiveOperation();
uint64_t microseconds = timer.stop();
atlas_log("Operation took " + std::to_string(microseconds) + "us");

Timing Events

Send structured timing data to the tracer:
TimingEventPacket event;
event.name = "TerrainGeneration";
event.subsystem = TimingEventSubsystem::Rendering;
event.durationMs = 16.7f;
event.frameNumber = currentFrame;
event.send();

Available Subsystems

  • Rendering - Graphics and shader execution
  • Physics - Physics simulation and collision
  • AI - Pathfinding and behavior trees
  • Scripting - Script execution and VM operations
  • Animation - Skeletal animation and blending
  • Audio - Sound mixing and streaming
  • Networking - Network I/O and synchronization
  • Io - File system operations
  • Scene - Scene graph updates
  • Other - Uncategorized operations

Graphics Debugging

Draw Call Tracking

DrawCallInfo drawCall;
drawCall.callerObject = "TerrainRenderer";
drawCall.type = DrawCallType::Indexed;
drawCall.frameNumber = currentFrame;
drawCall.send();

Frame Statistics

FrameDrawInfo frameInfo;
frameInfo.frameNumber = currentFrame;
frameInfo.drawCallCount = totalDrawCalls;
frameInfo.frameTimeMs = 16.6f;
frameInfo.fps = 60.0f;
frameInfo.send();

Frame Timing

FrameTimingPacket timing;
timing.frameNumber = currentFrame;
timing.cpuFrameTimeMs = 12.3f;
timing.gpuFrameTimeMs = 14.2f;
timing.mainThreadTimeMs = 10.5f;
timing.workerThreadTimeMs = 1.8f;
timing.memoryMb = 512.0f;
timing.cpuUsagePercent = 45.0f;
timing.gpuUsagePercent = 78.0f;
timing.send();

Resource Monitoring

Resource Events

ResourceEventInfo event;
event.callerObject = "TextureManager";
event.resourceType = DebugResourceType::Texture;
event.operation = DebugResourceOperation::Loaded;
event.frameNumber = currentFrame;
event.sizeMb = 4.5f;
event.send();

Resource Types

  • Texture - 2D/3D textures and cube maps
  • Buffer - Vertex, index, and uniform buffers
  • Shader - Compiled shader programs
  • Mesh - Geometry and vertex data

Resource Operations

  • Created - Resource allocated
  • Loaded - Resource data uploaded
  • Unloaded - Resource freed

Frame Resource Summary

FrameResourcesInfo resourceInfo;
resourceInfo.frameNumber = currentFrame;
resourceInfo.resourcesCreated = 5;
resourceInfo.resourcesLoaded = 12;
resourceInfo.resourcesUnloaded = 3;
resourceInfo.totalMemoryMb = 245.6f;
resourceInfo.send();

Resource Tracking

Use the singleton tracker for aggregate statistics:
auto& tracker = ResourceTracker::getInstance();
atlas_log("Total resources loaded: " + 
    std::to_string(tracker.loadedResources));
atlas_log("Total memory: " + 
    std::to_string(tracker.totalMemoryMb) + " MB");

Memory Profiling

Allocation Tracking

AllocationPacket alloc;
alloc.description = "Shadow map depth buffer";
alloc.owner = "ShadowRenderer";
alloc.domain = DebugMemoryDomain::GPU;
alloc.kind = DebugResourceKind::RenderTarget;
alloc.sizeMb = 16.0f;
alloc.frameNumber = currentFrame;
alloc.send();

Memory Domains

  • GPU - Graphics memory (VRAM)
  • CPU - System memory (RAM)

Resource Kinds

  • VertexBuffer - Vertex attribute data
  • IndexBuffer - Index data for indexed draws
  • UniformBuffer - Shader uniform data
  • StorageBuffer - Shader storage buffers (SSBO)
  • Texture2d - 2D texture data
  • Texture3d - 3D volume textures
  • TextureCube - Cube map faces
  • RenderTarget - Color attachments
  • DepthStencil - Depth/stencil buffers
  • Sampler - Texture samplers
  • PipelineCache - Cached pipeline state
  • AccelerationStructure - Ray tracing structures
  • Other - Uncategorized allocations

Frame Memory Summary

FrameMemoryPacket memoryStats;
memoryStats.frameNumber = currentFrame;
memoryStats.totalAllocatedMb = 512.0f;
memoryStats.totalGPUMb = 384.0f;
memoryStats.totalCPUMb = 128.0f;
memoryStats.allocationCount = 45;
memoryStats.deallocationCount = 12;
memoryStats.send();

Object-Level Debugging

Object Telemetry

DebugObjectPacket objInfo;
objInfo.objectId = model.getId();
objInfo.objectType = DebugObjectType::StaticMesh;
objInfo.triangleCount = 15420;
objInfo.materialCount = 3;
objInfo.vertexBufferSizeMb = 2.1f;
objInfo.indexBufferSizeMb = 0.8f;
objInfo.textureCount = 5;
objInfo.drawCallsForObject = 3;
objInfo.frameCount = currentFrame;
objInfo.send();

Object Types

  • StaticMesh - Static geometry
  • SkeletalMesh - Animated skinned mesh
  • ParticleSystem - Particle emitters
  • LightProbe - Light probe volumes
  • Terrain - Terrain patches
  • Other - Custom object types

Network Communication

NetworkPipe API

#include <atlas/network/pipe.h>

// Create and configure pipe
NetworkPipe pipe;
pipe.setPort(5123);

// Register message handler
pipe.onReceive([](const std::string& msg) {
    std::cout << "Received: " << msg << std::endl;
});

// Start connection
pipe.start();

// Send messages
pipe.send("Hello from Atlas\n");

// Get message history
auto messages = pipe.getMessages();

// Clean shutdown
pipe.stop();

Message Format

Tracer uses newline-delimited JSON packets:
{
  "type": "timing_event",
  "name": "ShadowPass",
  "subsystem": "rendering",
  "duration_ms": 3.4,
  "frame": 1234
}

Console Filtering

Control which log levels appear in console output:
Logger::getInstance().setConsoleFilter(
    true,  // Show info logs
    true,  // Show warnings
    false  // Hide errors from console (still sent to tracer)
);

Real-World Example

Complete profiling setup for a game loop:
#include <atlas/tracer/log.h>
#include <atlas/tracer/data.h>

void initTracer() {
    TracerServices::getInstance().startTracing(TRACER_PORT);
    if (TracerServices::getInstance().isOk()) {
        atlas_log("Tracer connected on port 5123");
    }
}

void gameLoop() {
    unsigned int frame = 0;
    
    while (running) {
        DebugTimer frameTimer("FullFrame");
        
        {
            DebugTimer timer("Input");
            processInput();
        }
        
        {
            DebugTimer timer("Physics");
            physics.update(deltaTime);
        }
        
        {
            DebugTimer timer("Rendering");
            renderer.render();
            
            // Track draw calls
            FrameDrawInfo drawInfo;
            drawInfo.frameNumber = frame;
            drawInfo.drawCallCount = renderer.getDrawCallCount();
            drawInfo.frameTimeMs = deltaTime * 1000.0f;
            drawInfo.fps = 1.0f / deltaTime;
            drawInfo.send();
        }
        
        frame++;
    }
}

Integration with Workspace

The Workspace system uses Tracer for asset loading feedback:
// From workspace.cpp:17-19
atlas_log("Creating resource: " + name);

// From workspace.cpp:52
atlas_warning("Resource not found: " + name);

// From workspace.cpp:88
atlas_error("Resource not found in group: " + name);

Best Practices

Profile Early

Start profiling during development to catch performance issues early

Use Scoped Timers

Prefer DebugTimer RAII over manual timing for automatic cleanup

Track Resources

Monitor resource creation/deletion to detect memory leaks

Filter Noise

Use console filtering to focus on relevant diagnostics
Tracer is an alpha API and may change in future versions. The protocol and packet formats are subject to evolution.
The NetworkPipe class manages connection retry and automatic reconnection. If the tracer server disconnects, the pipe will attempt to reconnect in the background (pipe.h:68-69).

Build docs developers (and LLMs) love