-
Notifications
You must be signed in to change notification settings - Fork 62
[sled-diagnostics] use ParallelTaskSet for multiple commands #8151
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
Changes from 1 commit
edb0440
6a5a376
b5eb158
dee2f7e
ef87515
c1ff648
f89127e
10de4e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,8 @@ | |||||||||||||||||
|
|
||||||||||||||||||
| //! Diagnostics for an Oxide sled that exposes common support commands. | ||||||||||||||||||
|
|
||||||||||||||||||
| use futures::{StreamExt, stream::FuturesUnordered}; | ||||||||||||||||||
| use std::sync::Arc; | ||||||||||||||||||
|
|
||||||||||||||||||
| use slog::Logger; | ||||||||||||||||||
|
|
||||||||||||||||||
| #[macro_use] | ||||||||||||||||||
|
|
@@ -21,6 +22,7 @@ cfg_if::cfg_if! { | |||||||||||||||||
|
|
||||||||||||||||||
| pub mod logs; | ||||||||||||||||||
| pub use logs::{LogError, LogsHandle}; | ||||||||||||||||||
| use tokio::{sync::Semaphore, task::JoinSet}; | ||||||||||||||||||
|
|
||||||||||||||||||
| mod queries; | ||||||||||||||||||
| pub use crate::queries::{ | ||||||||||||||||||
|
|
@@ -29,6 +31,59 @@ pub use crate::queries::{ | |||||||||||||||||
| }; | ||||||||||||||||||
| use queries::*; | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Max number of commands to run in parallel | ||||||||||||||||||
| const MAX_PARALLELISM: usize = 50; | ||||||||||||||||||
|
||||||||||||||||||
|
|
||||||||||||||||||
| trait ParallelCommandExecution { | ||||||||||||||||||
| type Output; | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Add a command to the set of commands to be executed. | ||||||||||||||||||
| async fn add_command<F>(&mut self, command: F) | ||||||||||||||||||
| where | ||||||||||||||||||
| F: std::future::Future<Output = Self::Output> + Send + 'static; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| struct MultipleCommands<T> { | ||||||||||||||||||
| semaphore: Arc<Semaphore>, | ||||||||||||||||||
| set: JoinSet<T>, | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| impl<T: 'static> MultipleCommands<T> { | ||||||||||||||||||
| fn new() -> MultipleCommands<T> { | ||||||||||||||||||
| let semaphore = Arc::new(Semaphore::new(MAX_PARALLELISM)); | ||||||||||||||||||
|
||||||||||||||||||
| let set = JoinSet::new(); | ||||||||||||||||||
|
|
||||||||||||||||||
| Self { semaphore, set } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Wait for all commands to execute and return their output. | ||||||||||||||||||
| async fn join_all(self) -> Vec<T> { | ||||||||||||||||||
| self.set.join_all().await | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| impl<T> ParallelCommandExecution for MultipleCommands<T> | ||||||||||||||||||
| where | ||||||||||||||||||
| T: Send + 'static, | ||||||||||||||||||
| { | ||||||||||||||||||
| type Output = T; | ||||||||||||||||||
|
|
||||||||||||||||||
| async fn add_command<F>(&mut self, command: F) | ||||||||||||||||||
| where | ||||||||||||||||||
| F: std::future::Future<Output = Self::Output> + Send + 'static, | ||||||||||||||||||
| { | ||||||||||||||||||
| let permit = Arc::clone(&self.semaphore) | ||||||||||||||||||
| .acquire_owned() | ||||||||||||||||||
| .await | ||||||||||||||||||
| .expect("semaphore acquire"); | ||||||||||||||||||
| let _abort_handle = self.set.spawn(async move { | ||||||||||||||||||
|
||||||||||||||||||
| let permit = Arc::clone(&self.semaphore) | |
| .acquire_owned() | |
| .await | |
| .expect("semaphore acquire"); | |
| let _abort_handle = self.set.spawn(async move { | |
| let semaphore = self.semaphore.clone(); | |
| let _abort_handle = self.set.spawn(async move { | |
| let permit = semaphore.acquire().await.expect("semaphore acquire"); |
This way, all the tasks are spawned immediately, and the task adding commands to the set can do so synchronously (changing add_command to a normal fn) and then just wait for them to all come back. Right now, the task that adds commands has to get woken up a bunch of times to add the next one to the set; I wonder whether changing this to spawn everything synchronously would make a meaningful difference in performance...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change I see the following...
stable rust + 1gb RSS:
took 24.416534527s
beta rust + 1gb RSS:
took 3.829577938s
Over chat I told you that with beta rust and the joinset we saw took 3.674288649s so it's negligible but overall I think a better design to go with your suggestion. I am going to push a commit to this branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah well, it was worth a shot, i guess! thanks for giving it a spin!
Uh oh!
There was an error while loading. Please reload this page.