Skip to content

Perf - use ArrayVec instead of Vec for internal AudioParam buffer #363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 3, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
use std::any::Any;
use std::slice::{Iter, IterMut};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::{Arc, OnceLock};

use arrayvec::ArrayVec;

use crate::context::AudioContextRegistration;
use crate::node::{
Expand All @@ -11,8 +13,6 @@ use crate::node::{
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
use crate::{AtomicF32, RENDER_QUANTUM_SIZE};

use std::sync::OnceLock;

/// For SetTargetAtTime event, that theoretically cannot end, if the diff between
/// the current value and the target is below this threshold, the value is set
/// to target value and the event is considered ended.
Expand Down Expand Up @@ -620,7 +620,7 @@ pub(crate) struct AudioParamProcessor {
shared_parts: Arc<AudioParamShared>,
event_timeline: AudioParamEventTimeline,
last_event: Option<AudioParamEvent>,
buffer: Vec<f32>,
buffer: ArrayVec<f32, RENDER_QUANTUM_SIZE>,
}

impl AudioProcessor for AudioParamProcessor {
Expand Down Expand Up @@ -670,11 +670,11 @@ impl AudioProcessor for AudioParamProcessor {
}

impl AudioParamProcessor {
// warning: tick in called directly in the unit tests so everything important
// for the tests should be done here
// Warning: compute_intrinsic_values in called directly in the unit tests so
// everything important for the tests should be done here
// The returned value is only used in tests
fn compute_intrinsic_values(&mut self, block_time: f64, dt: f64, count: usize) -> &[f32] {
self.compute_buffer(block_time, dt, count);

self.buffer.as_slice()
}

Expand Down Expand Up @@ -1088,7 +1088,14 @@ impl AudioParamProcessor {
match some_event {
None => {
if is_a_rate {
self.buffer.resize(count, self.intrinsic_value);
// @note - we use `count` rather then `buffer.remaining_capacity`
// to correctly unit tests where `count` is lower than RENDER_QUANTUM_SIZE
//
// @todo(perf) - consider using try_extend_from_slice
// which internally uses ptr::copy_nonoverlapping
for _ in self.buffer.len()..count {
self.buffer.push(self.intrinsic_value);
}
}
break;
}
Expand Down Expand Up @@ -1614,7 +1621,7 @@ pub(crate) fn audio_param_pair(
shared_parts,
event_timeline: AudioParamEventTimeline::new(),
last_event: None,
buffer: Vec::with_capacity(RENDER_QUANTUM_SIZE),
buffer: ArrayVec::new(),
};

(param, processor)
Expand Down