A high-performance library for tracking internal variables in concurrent Rust applications.
- High Performance: Minimal overhead in performance-critical code paths
- Thread-Safe: Safe for multi-threaded and parallel applications
- Configurable Sampling: Record values at specified intervals, or on every index change
- Flexible Indexing: Index recordings by time, step, run, or custom dimensions
- Recording thread-local and/or deeply-nested variables in performance-sensitive simulation code
- Tracking state in multi-threaded applications without disrupting execution flow
use rapid_recorder::prelude::*;
#[repr(u32)]
pub enum MyReadings {
Temperature,
Pressure,
}
impl_rapid_recorder_named_usize!(MyReadings);
fn main() {
// Initialize recorder
let recorder: RapidRecorder<_, MyReadings> = RapidRecorder::new(1_000_000, 10);
// Create a recording group
let mut group = recorder.add_group(
RapidRecorderGroup::new()
.sample_rate(DefaultSamplingFrequency::EveryOne)
.index_type(DefaultIndexDimmension::Step),
);
// Record values in a loop
for step in 0..1000 {
group.start_record(step);
// Deep in your code, record values
let temperature = calculate_temperature();
group.add(MyReadings::Temperature, temperature);
let pressure = calculate_pressure();
group.add(MyReadings::Pressure, pressure);
}
// After processing, analyze the data
let history = recorder.sorted_history();
// Process history...
}
Run cargo run --example performance_test
- Single Index Management: Manage record indexes in a single thread, while adding readings from multiple threads
for i in 0..1000 { // single threaded loop
group.start_record(i); // Call start_record in main thread
// It's safe to add readings from parallel threads, nested as deep as you want
(0..10).into_par_iter().for_each(|_| {
// Deep in parallel code
group.add(MyReadings::Temperature, 42.0);
});
}
- Different Sampling Rates: Use multiple groups for different sampling needs
let mut high_frequency_group = recorder.add_group(
RapidRecorderGroup::new()
.sample_rate(DefaultSamplingFrequency::EveryOne)
.index_type(DefaultIndexDimmension::Step),
);
let mut low_frequency_group = recorder.add_group(
RapidRecorderGroup::new()
.sample_rate(DefaultSamplingFrequency::EveryHundred)
.index_type(DefaultIndexDimmension::Step),
);
- Multiple Index Dimensions: Track different types of indexes
let mut step_group = recorder.add_group(
RapidRecorderGroup::new()
.index_type(DefaultIndexDimmension::Step),
);
let mut time_group = recorder.add_group(
RapidRecorderGroup::new()
.index_type(DefaultIndexDimmension::Time),
);
- Multiple Values for Same Reading: Adding the same reading name multiple times per record from different threads
// Not recommended - only one value will be recorded and we can't even guarantee it was the last value
(0..10).into_par_iter().for_each(|_| {
group.add(MyReadings::Temperature, get_random_value());
});
- Distributing Primary Record Indexes: Creating new groups in parallel threads
// Not recommended - poor performance
(0..100).into_par_iter().for_each(|i| {
let mut group = recorder.add_group(...);
group.start_record(i);
// Record things...
});