Session Summary

RxInfer provides a built-in session logging system that helps track and analyze various aspects of RxInfer usages. This feature is particularly useful for debugging, performance monitoring, and understanding the behavior of your inference models.

Note

Sessions are not shared and are intended for your personal use. However, you can opt-in to share your session data with the RxInfer team. See RxInfer Usage Telemetry for more details.

Overview

Session logging in RxInfer automatically captures and maintains statistics for:

  • Model source code and metadata
  • Input data characteristics
  • Execution timing and success rates
  • Error information (if any)
  • Environment information (Julia version, OS, etc.)
  • Context keys used across invocations

Basic Usage

By default, RxInfer creates and maintains a global session that logs all inference invocations:

using RxInfer

# Define a simple model
@model function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

# Run inference with default session logging
result = infer(
    model = simple_model(),
    data = (y = 1.0,)
)

# Access the current session
session = RxInfer.default_session()

# Get statistics for inference invocations
stats = RxInfer.get_session_stats(session, :inference)
println("Number of invokes: $(stats.total_invokes)")
println("Success rate: $(round(stats.success_rate * 100, digits=1))%")
Number of invokes: 58
Success rate: 98.3%
Note

The number of logged invocations may be different from the number of invocations in the example above since the session is created and logged at the start of the documentation build.

Session Capacity

By default, RxInfer maintains a fixed-size history of the invocations. When this limit is exceeded, the oldest invocations are automatically dropped. This prevents memory growth while maintaining recent history.

RxInfer.DEFAULT_SESSION_STATS_CAPACITYConstant
DEFAULT_SESSION_STATS_CAPACITY

The default capacity for the circular buffer storing session invocations. This value determines how many past invocations are stored for each label's statistics. Can be modified at compile time using preferences:

using RxInfer
set_session_stats_capacity!(100)

The change requires a Julia session restart to take effect. Default value is 1000. Must be a positive integer.

source
RxInfer.set_session_stats_capacity!Function
set_session_stats_capacity!(capacity::Int)

Set the default capacity for session statistics at compile time. The change requires a Julia session restart to take effect.

source

This is particularly useful when:

  • Running benchmarks that might generate many invocations
  • Working with long-running applications
  • Managing memory usage in resource-constrained environments
Note

Changing the session stats capacity requires a Julia session restart to take effect. The change is persistent across Julia sessions until explicitly changed again.

Custom sessions

You can also pass custom sessions to the infer function:

using RxInfer

@model function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

# Create a custom session
session = RxInfer.create_session()

# Run inference with custom session
result = infer(
    model = simple_model(),
    data = (y = 1.0,),
    session = session
)

println("Session ID: $(session.id)")
println("Created at: $(session.created_at)")
Session ID: 2089360f-a1e6-4d7c-a0ca-0a6adc1b6a53
Created at: 2025-02-24T09:40:04.739

or pass nothing to disable session logging:

result = infer(
    model = simple_model(),
    data = (y = 1.0,),
    session = nothing # skips session logging for this invocation
)
Inference results:
  Posteriors       | available for (x)

See Configuration for more details on how to manage sessions.

Session Reset

You can reset the session to its initial state with RxInfer.reset_session! function:

RxInfer.reset_session!Function
reset_session!(session, [ labels ])

Removes gathered statistics from the session. Optionally accepts a vector of labels to delete. If no labels specified deletes everything.

source

Session Statistics

RxInfer maintains detailed statistics for each label in a session. Currently, only the :inference label is actively used, which collects information about inference invocations.

What's being collected

For the :inference label, each invocation records:

  • Basic Information:
    • Unique identifier (UUID)
    • Status (:success or :error)
    • Execution start and end timestamps
  • Model Information:
    • Model source code (via GraphPPL.getsource)
    • Model name (via GraphPPL.getmodel)
    • Model constraints (if specified)
    • Model meta information (if specified)
    • Model autoupdates specification (if specified)
    • Model initialization specification (if specified)
  • Data Information:
    • Input data characteristics (names, types, sizes) - no actual data is collected`
    • Datastream type (for streaming inference)
    • Return variables structure
    • Predict variables structure (for batch inference)
    • History variables structure (for streaming inference)
    • History buffer size (if specified)
  • Inference Parameters:
    • Number of iterations
    • Free energy computation flag
    • Node contraction settings
    • Progress display settings
    • Exception catching settings
  • Additional Settings:
    • Callbacks configuration
    • Addons configuration
    • Options configuration
Note

No actual data is collected for the :inference label. Only metadata such as size and type is recorded.

An example of a last infer call in the session

The documentation build for RxInfer executes real code and maintains its own session. Let's look at an example of a last infer call in the session:

using RxInfer

session = RxInfer.default_session()
Session(id=f672a5ee-f186-4e4a-910d-8d6e7ad7062c, labels=[inference])
stats = RxInfer.get_session_stats(session, :inference)
SessionStats(id=09874b51-2201-4b6a-91a9-98e4a116a282, label=:inference, total=58, success_rate=98.3%, invokes=58/1000)
last_invoke = stats.invokes[end]
SessionInvoke(id=fd109c32-7b4e-4ecd-91bc-21284d8729c7, status=success, duration=211.0ms, context_keys=[free_energy, allow_node_contraction, returnvars, showprogress, addons, options, data, model_name, predictvars, historyvars, callbacks, model, catch_exception, iterations])
last_invoke.context
Dict{Symbol, Any} with 14 entries:
  :free_energy            => false
  :allow_node_contraction => false
  :returnvars             => "Nothing"
  :showprogress           => false
  :addons                 => "Nothing"
  :options                => "Nothing"
  :data                   => InferenceLoggedDataEntry[data: y (type=Float64, si…
  :model_name             => "simple_model"
  :predictvars            => "Nothing"
  :historyvars            => "Nothing"
  :callbacks              => "Nothing"
  :model                  => "function simple_model(y)\n    x ~ Normal(mean = 0…
  :catch_exception        => false
  :iterations             => nothing

Aggregated statistics

These individual invocations are then aggregated into real-time statistics:

  • Total number of invocations and success/failure counts
  • Success rate (fraction of successful invokes)
  • Execution timing statistics (min, max, total duration)
  • Set of all context keys used across invocations
  • Fixed-size history of recent invocations (controlled by DEFAULT_SESSION_STATS_CAPACITY)
RxInfer.SessionStatsType
SessionStats

Statistics for a specific label in a session.

Fields

  • id::UUID: Unique identifier for these statistics
  • label::Symbol: The label these statistics are for
  • total_invokes::Int: Total number of invokes with this label
  • success_count::Int: Number of successful invokes
  • failed_count::Int: Number of failed invokes
  • success_rate::Float64: Fraction of successful invokes (between 0 and 1)
  • min_duration_ms::Float64: Minimum execution duration in milliseconds
  • max_duration_ms::Float64: Maximum execution duration in milliseconds
  • total_duration_ms::Float64: Total execution duration for mean calculation
  • context_keys::Set{Symbol}: Set of all context keys used across invokes
  • invokes::CircularBuffer{SessionInvoke}: A series of invokes attached to the statistics
source

You can access these statistics using get_session_stats:

using RxInfer

session = RxInfer.default_session()
stats = RxInfer.get_session_stats(session, :inference)

println("Total invokes: $(stats.total_invokes)")
println("Success rate: $(round(stats.success_rate * 100, digits=1))%")
println("Failed invokes: $(stats.failed_count)")
println("Mean duration (ms): $(stats.total_invokes > 0 ? round(stats.total_duration_ms / stats.total_invokes, digits=2) : 0.0)")
Total invokes: 58
Success rate: 98.3%
Failed invokes: 1
Mean duration (ms): 1718.09

Session Structure

A session consists of the following components:

Session Fields

  • id::UUID: Unique identifier for the session
  • created_at::DateTime: Session creation timestamp
  • environment::Dict{Symbol, Any}: System and environment information
  • stats::Dict{Symbol, SessionStats}: Statistics per label
  • semaphore::Base.Semaphore: Thread-safe semaphore for concurrent updates

Environment Information

The session automatically captures system information including:

  • Julia version
  • RxInfer version
  • Operating system
  • Machine architecture
  • CPU threads
  • System word size

Statistics Information

Each label's statistics (SessionStats) captures:

  • id::UUID: Unique identifier for these statistics
  • label::Symbol: The label these statistics are for
  • total_invokes::Int: Total number of invokes
  • success_count::Int: Number of successful invokes
  • failed_count::Int: Number of failed invokes
  • success_rate::Float64: Fraction of successful invokes
  • min_duration_ms::Float64: Minimum execution duration
  • max_duration_ms::Float64: Maximum execution duration
  • total_duration_ms::Float64: Total execution duration
  • context_keys::Set{Symbol}: Set of all context keys used
  • invokes::CircularBuffer{SessionInvoke}: Recent invocations history
RxInfer.SessionInvokeType
SessionInvoke

Represents a single invocation of an inference operation.

Fields

  • id::UUID: Unique identifier for this invocation
  • status::Symbol: Status of the invocation (e.g. :success, :failure)
  • execution_start::DateTime: When the invocation started
  • execution_end::DateTime: When the invocation completed
  • context::Dict{Symbol, Any}: Additional contextual information
source

Accessing Session Data

You can inspect session data to analyze inference behavior:

using RxInfer

@model function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

session = RxInfer.create_session()
result = infer(model = simple_model(), data = (y = 1.0,), session = session)

# Get inference statistics
stats = RxInfer.get_session_stats(session, :inference)

# Get the latest invoke
latest_invoke = stats.invokes[end]

# Check invocation status
println("Status: $(latest_invoke.status)")

# Calculate execution duration
duration = latest_invoke.execution_end - latest_invoke.execution_start
println("Duration: $duration")

# Access model source
println("Model name: $(latest_invoke.context[:model_name])")
println("Model source: $(latest_invoke.context[:model])")

# Examine data properties
for entry in latest_invoke.context[:data]
    println("\nData variable: $(entry.name)")
    println("Type: $(entry.type)")
    println("Size: $(entry.size)")
end
Status: success
Duration: 213 milliseconds
Model name: simple_model
Model source: function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

Data variable: y
Type: Float64
Size: ()

Configuration

Default Session

The default session is created automatically when RxInfer is first imported. It is used for logging all inference invocations by default.

RxInfer.default_sessionFunction
default_session()::Union{Nothing, Session}

Get the current default session. If no session exists, returns nothing.

Returns

  • Union{Nothing, Session}: The current default session or nothing if logging is disabled
source

Enabling/Disabling Logging

Session logging can be enabled or disabled globally

RxInfer.disable_session_logging!Function

Disables session logging for RxInfer globally at compile time and saves it in package preferences. Has effect after Julia restart.

Restart Julia and verify it by isnothing(RxInfer.default_session()).

Note that session logging still can be enabled manually for the current session if set_default_session! is called manually with appropriate Session object.

source
RxInfer.enable_session_logging!Function

Enables session logging for RxInfer globally at compile time and saves it in package preferences. Has effect after Julia restart.

Restart Julia and verify it by !isnothing(RxInfer.default_session()).

source

Managing Sessions

RxInfer.create_sessionFunction
create_session()

Create a new session with a unique identifier, environment info and current timestamp. The session maintains separate statistics for each label, with each label's statistics having its own circular buffer of invokes.

source
RxInfer.set_default_session!Function
set_default_session!(session::Union{Nothing, Session})

Set the default session to a new session or disable logging by passing nothing.

Arguments

  • session::Union{Nothing, Session}: The new session to set as default, or nothing to disable logging
source

Best Practices

Error Handling: Session logging automatically captures errors, making it easier to debug issues:

using RxInfer

@model function problematic_model(y)
    x ~ Normal(mean = 0.0, var = sqrt(-1.0)) # Invalid variance
    y ~ Normal(mean = x, var = 1.0)
end

try
    result = infer(model = problematic_model(), data = (y = 1.0,))
catch e
    # Check the latest invoke for error details
    stats = RxInfer.get_session_stats(RxInfer.default_session(), :inference)
    latest_invoke = stats.invokes[end]
    println("Status: $(latest_invoke.status)")
    println("Error: $(latest_invoke.context[:error])")
end
Status: error
Error: DomainError(-1.0, "sqrt was called with a negative real argument but will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")

Performance Monitoring: Use session statistics to monitor inference performance:

using RxInfer, Statistics

@model function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

session = RxInfer.create_session()

# Run multiple inferences
for i in 1:5
    infer(model = simple_model(), data = (y = randn(),), session = session)
end

stats = RxInfer.get_session_stats(session, :inference)
println("Mean duration (ms): $(round(stats.total_duration_ms / stats.total_invokes, digits=2))")
println("Success rate: $(round(stats.success_rate * 100, digits=1))%")
Mean duration (ms): 42.8
Success rate: 100.0%
Note

The first invocation is typically slower due to Julia's JIT compilation.

Data Validation: Session logging helps track data characteristics:

using RxInfer

@model function simple_model(y)
    x ~ Normal(mean = 0.0, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)
end

session = RxInfer.create_session()
result = infer(model = simple_model(), data = (y = 1.0,), session = session)

stats = RxInfer.get_session_stats(session, :inference)
latest_invoke = stats.invokes[end]

# Check data properties
for entry in latest_invoke.context[:data]
    println("Variable: $(entry.name)")
    println("Type: $(entry.type)")
end
Variable: y
Type: Float64

Session Summary

You can view a tabular summary of these statistics at any time to understand how your inference tasks are performing:

Note

Session statistics below are collected during the documentation build.

The main function for viewing session statistics is summarize_session:

RxInfer.summarize_sessionFunction
summarize_session([io::IO], session::Session, label::Symbol = :inference; n_last = 5)

Print a concise summary of session statistics for invokes with the specified label. The default label is :inference which gathers statistics of the infer function calls.

source
RxInfer.summarize_session(; n_last = 25)

Session Summary (label: inference)
Total invokes: 59
Session invokes limit: 1000
Success rate: 96.6%
Failed invokes: 2
Average execution time 1688.97ms (min: 0.0ms, max: 20277.0ms)
Context keys: free_energy, allow_node_contraction, returnvars, showprogress, initialization, addons, options, error, data, model_name, predictvars, historyvars, callbacks, datastream_type, meta, model, catch_exception, constraints, iterations, keephistory, autoupdates

Inference specific:
  Unique models: 20

Last 25 invokes, use `n_last` keyword argument to see more or less.
*  Note that benchmarking with `BenchmarkTools` or similar will pollute the session with test invokes.
   It is advised to explicitly pass `session = nothing` when benchmarking code involving the `infer` function.

Legend:
  ✓ - Present/Success   ✗ - Absent/Failure   ⚠ - Error
╭─────────────┬────────┬───────────┬───────────────────────┬──────┬──────┬──────┬──────┬───────╮
│          ID │ Status │  Duration │                 Model │ Cstr │ Meta │ Init │ Data │ Error │
├─────────────┼────────┼───────────┼───────────────────────┼──────┼──────┼──────┼──────┼───────┤
│ 7c48ca80... │      ✗ │     0.0ms │     problematic_model │    ✗ │    ✗ │    ✗ │    y │     ⚠ │
│ fd109c32... │      ✓ │   211.0ms │          simple_model │    ✗ │    ✗ │    ✗ │    y │       │
│ fb2b1d16... │      ✓ │  1895.0ms │                 Model │    ✗ │    ✗ │    ✗ │ data │       │
│ 77e081b7... │      ✓ │  1530.0ms │                 Model │    ✗ │    ✗ │    ✗ │ data │       │
│ 78aae473... │      ✓ │   210.0ms │            test_model │    ✗ │    ✗ │    ✗ │    y │       │
│ 6d8a25d9... │      ✓ │   376.0ms │            test_model │    ✗ │    ✗ │    ✗ │    y │       │
│ 7e8df752... │      ✓ │   689.0ms │             coin_toss │    ✗ │    ✗ │    ✗ │    y │       │
│ d18956b2... │      ✓ │   577.0ms │        gaussian_model │    ✗ │    ✓ │    ✗ │    y │       │
│ 9f11ee71... │      ✓ │  1007.0ms │        gaussian_model │    ✗ │    ✗ │    ✗ │    y │       │
│ 2a69ce3c... │      ✓ │ 20277.0ms │               mymodel │    ✓ │    ✗ │    ✓ │    y │       │
│ 3bd01f91... │      ✓ │  4264.0ms │          simple_model │    ✓ │    ✗ │    ✗ │    y │       │
│ 9dd3921d... │      ✓ │   234.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │    y │       │
│ ce1c8f53... │      ✓ │   346.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │  N/A │       │
│ ed23d2c2... │      ✓ │    89.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │  N/A │       │
│ fe919c46... │      ✓ │  1384.0ms │            iid_normal │    ✓ │    ✗ │    ✓ │  N/A │       │
│ c1502c32... │      ✓ │  1079.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │  N/A │       │
│ 65762f59... │      ✓ │   375.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │  N/A │       │
│ d2ead724... │      ✓ │   466.0ms │ beta_bernoulli_online │    ✗ │    ✗ │    ✓ │  N/A │       │
│ 859d9dad... │      ✓ │   615.0ms │        iid_estimation │    ✓ │    ✗ │    ✓ │    y │       │
│ a6adb3db... │      ✓ │    30.0ms │        iid_estimation │    ✓ │    ✗ │    ✓ │    y │       │
│ 9e00b6f0... │      ✓ │  1369.0ms │        iid_estimation │    ✓ │    ✗ │    ✓ │    y │       │
│ ca4203b4... │      ✓ │   166.0ms │        iid_estimation │    ✓ │    ✗ │    ✓ │    y │       │
│ 55bbefa8... │      ✓ │   888.0ms │        iid_estimation │    ✓ │    ✗ │    ✓ │    y │       │
│ 194cf11d... │      ✗ │     0.0ms │        iid_estimation │    ✗ │    ✗ │    ✗ │    y │     ⚠ │
│ 67aaaed3... │      ✓ │   103.0ms │        beta_bernoulli │    ✗ │    ✗ │    ✗ │    y │       │
╰─────────────┴────────┴───────────┴───────────────────────┴──────┴──────┴──────┴──────┴───────╯

Tip: Share this session with `RxInfer.share_session_data()` to help improve RxInfer
     and get better support when reporting issues.

The summary includes:

  • Total number of inference invocations and success rate
  • Execution time statistics (mean, min, max)
  • List of context keys present
  • Number of unique models used
  • Table of most recent invocations showing:
    • Status (success/failed)
    • Duration in milliseconds
    • Model name
    • Data variables used

Programmatic Access

If you need to access the statistics programmatically, use get_session_stats:

RxInfer.get_session_statsFunction
get_session_stats(session::Session, label::Symbol = :inference)

Get statistics for invokes with the specified label. If the label doesn't exist in the session, returns a new empty SessionStats instance.

Arguments

  • session::Union{Nothing, Session}: The session to get statistics from, or nothing
  • label::Symbol: The label to get statistics for, defaults to :inference
source
session = RxInfer.default_session()
stats = RxInfer.get_session_stats(session, :inference)
SessionStats(id=09874b51-2201-4b6a-91a9-98e4a116a282, label=:inference, total=59, success_rate=96.6%, invokes=59/1000)

Benchmarking Considerations

When benchmarking code that involves the infer function, it's important to be aware of session logging behavior:

Why Disable Session Logging During Benchmarking?

  1. Multiple Executions: Benchmarking tools like BenchmarkTools.jl execute the code multiple times to gather accurate performance metrics. Each execution is logged as a separate invoke in the session, which can quickly fill up the session buffer.

  2. Session Pollution: These benchmark runs can pollute your session history with test invocations, making it harder to track and analyze your actual inference calls.

  3. Performance Impact: While minimal, session logging does add some overhead to each infer call, which could affect benchmark results.

Best Practices

To get accurate benchmarking results and maintain a clean session history:

# DON'T: This will fill your session with benchmark invocations
@benchmark infer(model = my_model, data = my_data)

# DO: Explicitly disable session logging during benchmarking
@benchmark infer(model = my_model, data = my_data, session = nothing)

You can also temporarily disable session logging globally:

# Disable session logging
previous_session = RxInfer.default_session()
RxInfer.set_default_session!(nothing)
# Run your benchmarks
# ...
# Re-enable session logging reusing the previous session
RxInfer.set_default_session!(previous_session)

or disable it explicitly:

RxInfer.disable_session_logging!() # works after Julia restart

Developers Reference

RxInfer.SessionType
Session

A structure that maintains a log of RxInfer usage. Each session has a unique identifier and saves when it was created together with its environment. The session maintains a dictionary of labeled statistics, each tracking a series of invocations (SessionInvoke) and computing real-time statistics.

Fields

  • id::UUID: A unique identifier for the session
  • created_at::DateTime: Timestamp when the session was created
  • environment::Dict{Symbol, Any}: Information about the Julia & RxInfer versions and system when the session was created
  • semaphore::Base.Semaphore: Thread-safe semaphore for updating stats
  • stats::Dict{Symbol, SessionStats}: Statistics per label

The session logging is transparent and only collects non-sensitive information about calls. Users can inspect the session at any time using get_current_session() and reset it using reset_session!().

source
RxInfer.with_sessionFunction
with_session(f::F, session, label::Symbol = :unknown) where {F}

Execute function f within a session context with the specified label. If session is provided, logs execution details including timing and errors, and updates the session statistics for the given label. If session is nothing, executes f without logging.

source
RxInfer.append_invoke_contextFunction
append_invoke_context(f, invoke)

Append context information to a session invoke. If invoke is a SessionInvoke, executes function f with the invoke's context. If invoke is nothing, does nothing.

source
RxInfer.update_session!Function
update_session!(session::Session, label::Symbol, invoke::SessionInvoke)

Thread-safely update session statistics for a given label with a new invoke. Uses a semaphore to ensure thread safety when multiple threads try to update statistics simultaneously.

Arguments

  • session::Session: The session to update
  • label::Symbol: Label for the invoke
  • invoke::SessionInvoke: The invoke to add to statistics
source
RxInfer.update_stats!Function
update_stats!(stats::SessionStats, invoke::SessionInvoke)

Update session statistics with a new invoke.

source