Driver, Input: Performance & Benchmarks (#27)
* Driver Benchmarks Benchmarks driver use cases for single packet send, multiple packet send, float vs opus, and the cost of head-of-queue track removal. Mix costs for large packet counts are also included. This is a prelude to the optimisations discussed in #21. * Typo in benchmark * Place Opus packet directly into packet buffer Cleans up some other logic surrounding this, too. Gets a 16.9% perf improvement on opus packet passthrough (sub 5us here). * Better track removal In theory this should be faster, but it aint. Keeping in case reducing struct sizes down the line magically makes this faster. * Reduce size of Input, TrackHandle Metadata is now boxed away. Similarly, TrackHandles are neatly Arc'd to reduce their size to pointer length (and mitigate the impact of copies if we add in more fields).
This commit is contained in:
@@ -17,10 +17,15 @@ use uuid::Uuid;
|
||||
///
|
||||
/// [`Track`]: Track
|
||||
pub struct TrackHandle {
|
||||
inner: Arc<InnerHandle>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct InnerHandle {
|
||||
command_channel: UnboundedSender<TrackCommand>,
|
||||
seekable: bool,
|
||||
uuid: Uuid,
|
||||
metadata: Arc<Metadata>,
|
||||
metadata: Box<Metadata>,
|
||||
}
|
||||
|
||||
impl TrackHandle {
|
||||
@@ -32,14 +37,16 @@ impl TrackHandle {
|
||||
command_channel: UnboundedSender<TrackCommand>,
|
||||
seekable: bool,
|
||||
uuid: Uuid,
|
||||
metadata: Metadata,
|
||||
metadata: Box<Metadata>,
|
||||
) -> Self {
|
||||
Self {
|
||||
let inner = Arc::new(InnerHandle {
|
||||
command_channel,
|
||||
seekable,
|
||||
uuid,
|
||||
metadata: Arc::new(metadata),
|
||||
}
|
||||
metadata,
|
||||
});
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Unpauses an audio track.
|
||||
@@ -75,7 +82,7 @@ impl TrackHandle {
|
||||
/// [`seek_time`]: TrackHandle::seek_time
|
||||
/// [`Input`]: crate::input::Input
|
||||
pub fn is_seekable(&self) -> bool {
|
||||
self.seekable
|
||||
self.inner.seekable
|
||||
}
|
||||
|
||||
/// Seeks along the track to the specified position.
|
||||
@@ -86,7 +93,7 @@ impl TrackHandle {
|
||||
/// [`Input`]: crate::input::Input
|
||||
/// [`TrackError::SeekUnsupported`]: TrackError::SeekUnsupported
|
||||
pub fn seek_time(&self, position: Duration) -> TrackResult<()> {
|
||||
if self.seekable {
|
||||
if self.is_seekable() {
|
||||
self.send(TrackCommand::Seek(position))
|
||||
} else {
|
||||
Err(TrackError::SeekUnsupported)
|
||||
@@ -139,7 +146,7 @@ impl TrackHandle {
|
||||
/// [`Input`]: crate::input::Input
|
||||
/// [`TrackError::SeekUnsupported`]: TrackError::SeekUnsupported
|
||||
pub fn enable_loop(&self) -> TrackResult<()> {
|
||||
if self.seekable {
|
||||
if self.is_seekable() {
|
||||
self.send(TrackCommand::Loop(LoopState::Infinite))
|
||||
} else {
|
||||
Err(TrackError::SeekUnsupported)
|
||||
@@ -154,7 +161,7 @@ impl TrackHandle {
|
||||
/// [`Input`]: crate::input::Input
|
||||
/// [`TrackError::SeekUnsupported`]: TrackError::SeekUnsupported
|
||||
pub fn disable_loop(&self) -> TrackResult<()> {
|
||||
if self.seekable {
|
||||
if self.is_seekable() {
|
||||
self.send(TrackCommand::Loop(LoopState::Finite(0)))
|
||||
} else {
|
||||
Err(TrackError::SeekUnsupported)
|
||||
@@ -169,7 +176,7 @@ impl TrackHandle {
|
||||
/// [`Input`]: crate::input::Input
|
||||
/// [`TrackError::SeekUnsupported`]: TrackError::SeekUnsupported
|
||||
pub fn loop_for(&self, count: usize) -> TrackResult<()> {
|
||||
if self.seekable {
|
||||
if self.is_seekable() {
|
||||
self.send(TrackCommand::Loop(LoopState::Finite(count)))
|
||||
} else {
|
||||
Err(TrackError::SeekUnsupported)
|
||||
@@ -178,7 +185,7 @@ impl TrackHandle {
|
||||
|
||||
/// Returns this handle's (and track's) unique identifier.
|
||||
pub fn uuid(&self) -> Uuid {
|
||||
self.uuid
|
||||
self.inner.uuid
|
||||
}
|
||||
|
||||
/// Returns the metadata stored in the handle.
|
||||
@@ -188,8 +195,8 @@ impl TrackHandle {
|
||||
/// read-only from then on.
|
||||
///
|
||||
/// [`Input`]: crate::input::Input
|
||||
pub fn metadata(&self) -> Arc<Metadata> {
|
||||
self.metadata.clone()
|
||||
pub fn metadata(&self) -> &Metadata {
|
||||
&self.inner.metadata
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -199,7 +206,8 @@ impl TrackHandle {
|
||||
pub fn send(&self, cmd: TrackCommand) -> TrackResult<()> {
|
||||
// As the send channels are unbounded, we can be reasonably certain
|
||||
// that send failure == cancellation.
|
||||
self.command_channel
|
||||
self.inner
|
||||
.command_channel
|
||||
.send(cmd)
|
||||
.map_err(|_e| TrackError::Finished)
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ use tracing::{info, warn};
|
||||
/// ```
|
||||
///
|
||||
/// [`TrackEvent`]: crate::events::TrackEvent
|
||||
/// [`Driver::queue`]: crate::driver::Driver::queue
|
||||
/// [`Driver::queue`]: crate::driver::Driver
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TrackQueue {
|
||||
// NOTE: the choice of a parking lot mutex is quite deliberate
|
||||
|
||||
Reference in New Issue
Block a user