Skip to content

Node profiling panics on the first processed block after every activation #141

Description

@Lucas18503

Enabling node profiling panics on the first processed block after any FirewheelContext::activate, even with an empty graph. This appears to be a residual of #134, but at the first NewSchedule instead of at construction.

Reproduction

firewheel = { version = "0.12.1", features = ["node_profiling"] } and
audioadapter-buffers = { version = "4.0", default-features = false, features = ["std"] }:

use std::num::NonZeroU32;
use std::time::Duration;

use audioadapter_buffers::direct::InterleavedSlice;
use firewheel::backend::BackendProcessInfo;
use firewheel::node::StreamStatus;
use firewheel::{ActivateInfo, FirewheelConfig, FirewheelContext, FirewheelFlags};

const BLOCK_FRAMES: usize = 128;

fn main() {
    let mut cx = FirewheelContext::new(FirewheelConfig {
        flags: FirewheelFlags {
            profile_nodes: true,
            ..Default::default()
        },
        ..Default::default()
    });

    // No nodes need be added.
    let mut processor = cx
        .activate(ActivateInfo {
            sample_rate: NonZeroU32::new(48_000).unwrap(),
            max_block_frames: NonZeroU32::new(BLOCK_FRAMES as u32).unwrap(),
            num_stream_in_channels: 0,
            num_stream_out_channels: 2,
            input_to_output_latency_seconds: 0.0,
        })
        .unwrap();

    let input_storage: [f32; 0] = [];
    let mut output_storage = vec![0.0f32; BLOCK_FRAMES * 2];
    let input = InterleavedSlice::new(&input_storage, 0, 0).unwrap();
    let mut output = InterleavedSlice::new_mut(&mut output_storage, 2, BLOCK_FRAMES).unwrap();

    processor.process(
        &input,
        &mut output,
        BackendProcessInfo {
            frames: BLOCK_FRAMES,
            process_timestamp: None,
            duration_since_stream_start: Duration::ZERO,
            input_stream_status: StreamStatus::empty(),
            output_stream_status: StreamStatus::empty(),
            dropped_frames: 0,
            process_to_playback_delay: None,
        },
    );
}
thread 'main' panicked at
firewheel-graph-0.12.1/src/processor/profiling.rs:226:41:
index out of bounds: the len is 0 but the index is 0

Ordering

  1. FirewheelProcessorInner::process calls ProfilerTx::new_process_loop (processor/process.rs:57) before polling context messages.
  2. new_process_loop resizes node_cpu_sums to the profiler's current nodes length.
  3. poll_messages (processor/process.rs:92) then consumes the NewSchedule that FirewheelContext::activate sends unconditionally (context.rs:534), on first activation as well as reactivation.
  4. ProfilerTx::new_schedule clears and refills nodes, but only clears node_cpu_sums, leaving it empty.
  5. The same block goes on to visit the schedule's nodes, and the first node_completed indexes the now-empty node_cpu_sums.

Suggested fix

Resize node_cpu_sums to nodes.len() at the end of new_schedule while
is_profiling_nodes is set:

if self.is_profiling_nodes {
    self.heap_data
        .node_cpu_sums
        .resize(self.heap_data.nodes.len(), 0.0);
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions