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.
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%
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_CAPACITY
— ConstantDEFAULT_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.
RxInfer.set_session_stats_capacity!
— Functionset_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.
This is particularly useful when:
- Running benchmarks that might generate many invocations
- Working with long-running applications
- Managing memory usage in resource-constrained environments
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!
— Functionreset_session!(session, [ labels ])
Removes gathered statistics from the session. Optionally accepts a vector of labels to delete. If no labels specified deletes everything.
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)
- Model source code (via
- 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
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.SessionStats
— TypeSessionStats
Statistics for a specific label in a session.
Fields
id::UUID
: Unique identifier for these statisticslabel::Symbol
: The label these statistics are fortotal_invokes::Int
: Total number of invokes with this labelsuccess_count::Int
: Number of successful invokesfailed_count::Int
: Number of failed invokessuccess_rate::Float64
: Fraction of successful invokes (between 0 and 1)min_duration_ms::Float64
: Minimum execution duration in millisecondsmax_duration_ms::Float64
: Maximum execution duration in millisecondstotal_duration_ms::Float64
: Total execution duration for mean calculationcontext_keys::Set{Symbol}
: Set of all context keys used across invokesinvokes::CircularBuffer{SessionInvoke}
: A series of invokes attached to the statistics
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 sessioncreated_at::DateTime
: Session creation timestampenvironment::Dict{Symbol, Any}
: System and environment informationstats::Dict{Symbol, SessionStats}
: Statistics per labelsemaphore::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 statisticslabel::Symbol
: The label these statistics are fortotal_invokes::Int
: Total number of invokessuccess_count::Int
: Number of successful invokesfailed_count::Int
: Number of failed invokessuccess_rate::Float64
: Fraction of successful invokesmin_duration_ms::Float64
: Minimum execution durationmax_duration_ms::Float64
: Maximum execution durationtotal_duration_ms::Float64
: Total execution durationcontext_keys::Set{Symbol}
: Set of all context keys usedinvokes::CircularBuffer{SessionInvoke}
: Recent invocations history
RxInfer.SessionInvoke
— TypeSessionInvoke
Represents a single invocation of an inference operation.
Fields
id::UUID
: Unique identifier for this invocationstatus::Symbol
: Status of the invocation (e.g. :success, :failure)execution_start::DateTime
: When the invocation startedexecution_end::DateTime
: When the invocation completedcontext::Dict{Symbol, Any}
: Additional contextual information
RxInfer.create_invoke
— Functioncreate_invoke()
Create a new session invoke with status set to :unknown
.
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_session
— Functiondefault_session()::Union{Nothing, Session}
Get the current default session. If no session exists, returns nothing
.
Returns
Union{Nothing, Session}
: The current default session ornothing
if logging is disabled
Enabling/Disabling Logging
Session logging can be enabled or disabled globally
RxInfer.disable_session_logging!
— FunctionDisables 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.
RxInfer.enable_session_logging!
— FunctionEnables 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())
.
Managing Sessions
RxInfer.create_session
— Functioncreate_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.
RxInfer.set_default_session!
— Functionset_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, ornothing
to disable logging
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%
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:
Session statistics below are collected during the documentation build.
The main function for viewing session statistics is summarize_session
:
RxInfer.summarize_session
— Functionsummarize_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.
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_stats
— Functionget_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 nothinglabel::Symbol
: The label to get statistics for, defaults to :inference
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?
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.Session Pollution: These benchmark runs can pollute your session history with test invocations, making it harder to track and analyze your actual inference calls.
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.Session
— TypeSession
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 sessioncreated_at::DateTime
: Timestamp when the session was createdenvironment::Dict{Symbol, Any}
: Information about the Julia & RxInfer versions and system when the session was createdsemaphore::Base.Semaphore
: Thread-safe semaphore for updating statsstats::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!()
.
RxInfer.with_session
— Functionwith_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.
RxInfer.append_invoke_context
— Functionappend_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.
RxInfer.update_session!
— Functionupdate_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 updatelabel::Symbol
: Label for the invokeinvoke::SessionInvoke
: The invoke to add to statistics
RxInfer.update_stats!
— Functionupdate_stats!(stats::SessionStats, invoke::SessionInvoke)
Update session statistics with a new invoke.