Skip to content

A Julia interface for the Tracy instrumentation-based profiler, designed for multithreaded simulations.

License

Notifications You must be signed in to change notification settings

nhz2/ZoneProfilers.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZoneProfilers.jl (WIP)

A Julia interface for the Tracy instrumentation-based profiler, designed for multithreaded simulations.

logo

Overview

ZoneProfilers provides utilities to mark up code for logging and timing.

ZoneProfilerTracy provides a wrapper of the Tracy C library v0.9.1 for profiling marked-up code.

ZoneProfilers uses an explicit profiler parameter to be passed through your call chain:

# ZoneProfilers approach - explicit profiler parameter
using ZoneProfilers
function simulate_physics(; profiler=NullProfiler())
    @zone profiler sleep(0.01)
end

function run_simulation(; profiler=NullProfiler())
    @zone profiler name="simulation" begin
        for step in 1:10
            simulate_physics(; profiler)  # Pass profiler down
        end
    end
end

# Production: zero runtime overhead due to specialization
run_simulation()  # Uses NullProfiler(), compiled away

# Development: full profiling
# Use TracyProfiler_jll to run the tracy GUI
import TracyProfiler_jll
using ZoneProfilerTracy: TracyProfiler
profiler = TracyProfiler(TracyProfiler_jll)

run_simulation(;profiler)  # Full instrumentation

API Reference

Profiler Management

  • wait_for_connection(profiler) - Wait for the profiler recorder to be connected
  • is_connected(profiler) - Check if the recorder is connected
  • app_info!(profiler, text) - Write the trace description
  • new_stack(profiler, name) -> new_profiler - Create a new zone stack

Messaging

  • message!(profiler, text; [color]) - Log standalone message

Zone Management

  • @zone profiler [name=, color=, active=] expression - Profile an expression
  • @zone_begin profiler [name=, color=, active=] - Start a profiling zone
  • zone_end!(profiler) - End current zone
  • zone_active(profiler) - Check if current zone is active

Zone Modification

  • zone_color!(profiler, color) - Set zone color at runtime
  • zone_text!(profiler, text) - Add a line of text to the current zone
  • @zone_show profiler vars... - Convenience macro to display variable names and values as zone text
  • @zone_repr profiler vars... - Convenience macro to display repr of variables as zone text

Frame Marking

  • frame_mark!(profiler, [name]) - Mark frame boundary
  • frame_mark_begin!(profiler, name) - Start named frame
  • frame_mark_end!(profiler, name) - End named frame

Plotting

  • plot!(profiler, name, value) - Add data point to plot

Important limitations

In addition, ZoneProfilerTracy is not compatible with julia built with the WITH_TRACY=1 make option.

Every instance of string or symbol data passed to the profiler can't be longer than 64 KB.

Symbols passed to the profiler are required to have stable pointers for the rest of the lifetime of the process. Currently, in Julia, Symbols are not garbage collected, but this might change in a future version of the language. To be future-proof, you must ensure there is a global reference to a symbol before passing it to a profiler.

The name passed to the @zone macros is limited to 511 bytes. Source file path lengths are limited to 2047 bytes.

Due to the mismatch between how multithreading works in Julia vs C++, currently, the GUI display of context switches is not accurate. The "Draw context switches" option should be disabled in the Tracy GUI.

Currently, there is no support for callstack logging. Help in supporting this would be greatly appreciated.

A connected tracy server can read arbitrary memory in the profiled process, so only use ZoneProfilerTracy in trusted environments.

Tracy is not supported on 32-bit systems.

Core Concepts

Messages

message!(profiler, "hello world")
message!(profiler, Symbol("this string is interned"))
message!(profiler, "warning"; color=:yellow)

messages

Zones

Zones represent a block of code you want to profile:

@zone profiler name="physics_update" color=:blue begin
    # physics_update
    sleep(0.1)
end

Zones can be nested to form a stack:

@zone profiler name="physics_update" color=:blue begin
    # physics_update
    sleep(0.1)
    @zone profiler name="part one" begin
        sleep(0.1)
    end
    @zone profiler name="part two" begin
        sleep(0.1)
    end
end

When using the @zone macro, name and color must be literals. Use zone_color! to set the color of a zone at runtime. Use zone_text! to append a line of text to the zone annotation. For convenience, use @zone_show to display variable names and values, or @zone_repr to display just the repr output.

The @zone_show and @zone_repr macros are particularly useful because expressions are only evaluated when the zone is active, avoiding performance overhead and side effects when profiling is disabled.

@zone profiler name="physics_update" begin
    # physics_update
    sleep(0.1)
    @zone profiler name="part one" color=0x0000FF begin
        u = rand()
        if u < 0.5
            # make the zone red and note the value of `u`
            zone_color!(profiler, 0xFF0000)
            # Guard with `zone_active(profiler) &&` to avoid constructing the string when not profiling.
            zone_active(profiler) && zone_text!(profiler, "Rare event, u = $(u)")
            # Or use @zone_show as a convenience - expression is only evaluated when zone is active
            @zone_show profiler u
            # Or use @zone_repr to show just the repr without the variable name
            @zone_repr profiler u
        end
        sleep(0.1)
    end
    @zone profiler name="part two" begin
        sleep(0.1)
    end
end

zonecolor

Multiple Zone Stacks

ZoneProfilers supports task-local zone stacks.

A profiler with a new zone stack can be made using new_stack.

Asynchronous tasks that create or modify zones or send messages should do so to a local zone stack. Zone stack names can be reused if the previous zone stack with that name is empty.

Multiple tasks should not concurrently share a zone stack.

# Each task gets its own profiling context
Threads.@threads for i in 1:10
    local task_profiler = new_stack(profiler, ()->Symbol("worker_$i"))
    @zone task_profiler name="parallel_work" begin
        if zone_active(task_profiler)
            message!(task_profiler, "Hello from worker $(i)")
        end
        # task-specific work
        sleep(rand()*0.1)
        # task local information
        zone_text!(task_profiler, "Chunk")
        zone_value!(task_profiler, UInt64(i))
    end
end

zonesparallel

Frame marks and Plots

Track key simulation metrics over time:

# Monitor performance metrics
particles = Float64[]
for step in 1:1000
    @zone profiler name="simulation_step" begin
        # Your simulation code
        # advance_simulation!(system, dt)
        push!(particles, rand())

        # Track metrics over time
        plot!(profiler, :particle_count, Float64(length(particles)))
    end
    
    frame_mark!(profiler) # mark the end of a step and the beginning of the next step.
end

frames

Frame marking and plotting are safe to do concurrently with a shared profiler.

Conditional Profiling

Enable profiling only when needed to minimize overhead:

const PROFILING_ENABLED = false

# Profile only when explicitly enabled
@zone profiler active=PROFILING_ENABLED name="expensive_computation" begin
    # expensive_computation()
end

# Or use dynamic conditions, for example, only profile on Monday
using Dates
should_profile() = Dates.dayofweek(Dates.now()) == Dates.Monday

@zone profiler active=should_profile name="expensive_computation" begin
    # expensive_computation()
end

The expression in the zone is run if the profiling is active or not. The function passed to active will not be evaluated if the profiler is a NullProfiler, for even less overhead.

See Also

About

A Julia interface for the Tracy instrumentation-based profiler, designed for multithreaded simulations.

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •  

Languages