From 57c945dd3b5c0dfe148ed7c8cb5dfb35ca72fd40 Mon Sep 17 00:00:00 2001 From: b-ma Date: Fri, 22 Sep 2023 19:34:08 +0200 Subject: [PATCH 1/4] perf: use ArrayVec instead of Vec for param buffer --- src/param.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/param.rs b/src/param.rs index f83a919f..1466ca6c 100644 --- a/src/param.rs +++ b/src/param.rs @@ -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::{ @@ -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. @@ -620,7 +620,7 @@ pub(crate) struct AudioParamProcessor { shared_parts: Arc, event_timeline: AudioParamEventTimeline, last_event: Option, - buffer: Vec, + buffer: ArrayVec, } impl AudioProcessor for AudioParamProcessor { @@ -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 used in tests 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() } @@ -1088,7 +1088,11 @@ impl AudioParamProcessor { match some_event { None => { if is_a_rate { - self.buffer.resize(count, self.intrinsic_value); + let buffer = [self.intrinsic_value; RENDER_QUANTUM_SIZE]; + // we don't use `buffer.remaining_capacity` to correctly handle + // the tests where `count` is lower than RENDER_QUANTUM_SIZE + let remaining = count - self.buffer.len(); + let _ = self.buffer.try_extend_from_slice(&buffer[..remaining]); } break; } @@ -1614,7 +1618,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) From 37ae1fec38e32976865c6660082c52c8186af16e Mon Sep 17 00:00:00 2001 From: b-ma Date: Fri, 22 Sep 2023 19:51:25 +0200 Subject: [PATCH 2/4] typo --- src/param.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/param.rs b/src/param.rs index 1466ca6c..ecfbabfe 100644 --- a/src/param.rs +++ b/src/param.rs @@ -672,7 +672,7 @@ impl AudioProcessor for AudioParamProcessor { impl AudioParamProcessor { // 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 used in tests is only used in tests + // 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() From b07f4b94cb8802b41f0028b0dac87b933ccca551 Mon Sep 17 00:00:00 2001 From: b-ma Date: Tue, 3 Oct 2023 10:21:56 +0200 Subject: [PATCH 3/4] refactor: simplify filling buffer when no event left --- src/param.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/param.rs b/src/param.rs index ecfbabfe..5ee0dd8d 100644 --- a/src/param.rs +++ b/src/param.rs @@ -1088,11 +1088,11 @@ impl AudioParamProcessor { match some_event { None => { if is_a_rate { - let buffer = [self.intrinsic_value; RENDER_QUANTUM_SIZE]; - // we don't use `buffer.remaining_capacity` to correctly handle - // the tests where `count` is lower than RENDER_QUANTUM_SIZE - let remaining = count - self.buffer.len(); - let _ = self.buffer.try_extend_from_slice(&buffer[..remaining]); + // @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; } From 4a5e4dc70dfae4d81fd77665bb9ca4d04beb4ede Mon Sep 17 00:00:00 2001 From: b-ma Date: Tue, 3 Oct 2023 10:39:00 +0200 Subject: [PATCH 4/4] doc: comment on using `count` --- src/param.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/param.rs b/src/param.rs index 5ee0dd8d..50f1ffba 100644 --- a/src/param.rs +++ b/src/param.rs @@ -1088,6 +1088,9 @@ impl AudioParamProcessor { match some_event { None => { if is_a_rate { + // @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 {