dial9 0.5.0-rc0

Low-overhead async runtime telemetry: event recording, Tokio integration, CPU/memory profiling, and a trace viewer CLI
#![cfg(feature = "memory-profiling")]
#![cfg(feature = "analysis")]
#![cfg(target_os = "linux")]
//! Test that the allocator hook captures sampled allocations into the trace.

mod common;

use common::{CAPTURE_BUFFER_SIZE, capture_processor, decode_all};
use dial9::analysis::analysis_events::Dial9Event;
use dial9::memory::{Dial9Allocator, MemoryProfiler, MemoryProfilingConfig};
use dial9::{MemoryBuffer, RecorderPipelineExt, RecorderTokioExt, recorder};
use std::time::Duration;

#[global_allocator]
static ALLOC: Dial9Allocator = Dial9Allocator::system();

#[test]
fn hook_captures_sampled_allocations() {
    let (capture, batches) = capture_processor();

    let recorder = recorder(MemoryBuffer::new(CAPTURE_BUFFER_SIZE).unwrap())
        .with_custom_pipeline(|p| p.pipe(capture))
        .build();
    let (recorder, rt) = recorder
        .attach_tokio_runtime(|t| {
            t.enable_all();
            t.worker_threads(1);
        })
        .expect("attach tokio");

    let handle = recorder.handle().clone();
    let _mem_guard = MemoryProfiler::from_config(
        MemoryProfilingConfig::builder()
            .sample_rate_bytes(1024)
            .rng_seed(42)
            .build(),
    )
    .install(handle)
    .expect("install should succeed");

    rt.block_on(async {
        for _ in 0..100 {
            let v: Vec<u8> = Vec::with_capacity(1024);
            std::hint::black_box(v);
        }
        // Give the flush thread time to drain.
        tokio::time::sleep(Duration::from_millis(200)).await;
    });

    drop(rt);
    recorder.graceful_shutdown(Duration::from_secs(1));

    let b = batches.lock().unwrap();
    let events: Vec<Dial9Event> = decode_all(&b);
    let allocs: Vec<_> = events
        .iter()
        .filter(|e| matches!(e, Dial9Event::AllocEvent(_)))
        .collect();

    assert!(
        !allocs.is_empty(),
        "expected at least one AllocEvent from sampled allocations, got 0"
    );

    // Verify the event has reasonable fields.
    if let Dial9Event::AllocEvent(e) = &allocs[0] {
        assert!(e.size > 0, "size should be non-zero");
        assert!(
            !e.callchain.is_empty(),
            "callchain should have at least one frame"
        );
    }
}