Skip to content
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

Direct user where to find samply output #1473

Merged
merged 4 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
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
9 changes: 8 additions & 1 deletion shotover-proxy/benches/windsock/profilers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ impl ProfilerRunner {
};
self.samply = if self.run_samply {
if let Some(shotover) = &shotover {
Some(Samply::run(self.results_path.clone(), shotover.child().id().unwrap()).await)
Some(
Samply::run(
self.bench_name.clone(),
self.results_path.clone(),
shotover.child().id().unwrap(),
)
.await,
)
} else {
panic!("samply not supported when benching without shotover")
}
Expand Down
66 changes: 43 additions & 23 deletions shotover-proxy/benches/windsock/profilers/samply.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use std::path::PathBuf;
use tokio::task::JoinHandle;
use windsock::ReportArchive;

pub struct Samply(JoinHandle<()>);
pub struct Samply {
bench_name: String,
handle: JoinHandle<()>,
output_file: String,
}

impl Samply {
pub async fn run(results_path: PathBuf, pid: u32) -> Samply {
pub async fn run(bench_name: String, results_path: PathBuf, pid: u32) -> Samply {
run_command(
"cargo",
&[
Expand All @@ -13,11 +18,16 @@ impl Samply {
"--git",
"https://github.com/mstange/samply",
"--rev",
"4c8d5eb164e44c4eda1b29de116f5ea546d64c65",
"59a03a716cadab7835e3a961d0107ec797e458ec",
],
)
.await;
let output_file = results_path.join("samply.json");
let output_file = results_path
.join("samply.json")
.as_os_str()
.to_str()
.unwrap()
.to_owned();
let home = std::env::var("HOME").unwrap();

// Run `sudo ls` so that we can get sudo to stop asking for password for a while.
Expand All @@ -26,28 +36,38 @@ impl Samply {
// But that would require a bunch of work so its out of scope for now.
run_command("sudo", &["ls"]).await;

Samply(tokio::spawn(async move {
run_command(
"sudo",
&[
// specify the full path as CI has trouble finding it for some reason.
&format!("{home}/.cargo/bin/samply"),
"record",
"-p",
&pid.to_string(),
"--save-only",
"--profile-name",
results_path.file_name().unwrap().to_str().unwrap(),
"--output",
output_file.as_os_str().to_str().unwrap(),
],
)
.await;
}))
Samply {
bench_name,
output_file: output_file.clone(),
handle: tokio::spawn(async move {
run_command(
"sudo",
&[
// specify the full path as CI has trouble finding it for some reason.
&format!("{home}/.cargo/bin/samply"),
"record",
"-p",
&pid.to_string(),
"--save-only",
"--profile-name",
results_path.file_name().unwrap().to_str().unwrap(),
"--output",
&output_file,
],
)
.await;
}),
}
}

pub fn wait(self) {
futures::executor::block_on(self.0).unwrap();
futures::executor::block_on(self.handle).unwrap();
let mut report = ReportArchive::load(&self.bench_name).unwrap();
report.info_messages.push(format!(
"To open profiler results run: samply load {}",
self.output_file
));
report.save();
}
}

Expand Down
35 changes: 30 additions & 5 deletions windsock/src/report.rs
rukai marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,46 @@ use tokio::sync::mpsc::UnboundedReceiver;

#[derive(Debug, Serialize, Deserialize)]
pub enum Report {
/// Indicates the warmup is over and the benchmark has begun.
/// Any Completed/Errored Events received before this are considered warmups and discarded.
Start,

/// Indicates a response came back from the service.
/// The Duration should be the time between the request being sent and the response being received
QueryCompletedIn(Duration),

/// Indicates an an error response came back from the service.
QueryErrored {
/// The time between the request being sent and the response being received
completed_in: Duration,
/// The error message received from the service or the local error that occured while trying to communicate with the service.
message: String,
},

/// Indicates a pubsub produce ack came back from the service.
/// The Duration should be the time between the request being sent and the response being received
ProduceCompletedIn(Duration),

/// Indicates a pubsub produce error response came back from the service.
ProduceErrored {
completed_in: Duration,
message: String,
},
/// Indicates a pubsub consume response comes back from the service.
ConsumeCompleted,
ConsumeErrored {
message: String,
},

/// Indicates pubsub consume error response came back from the service.
ConsumeErrored { message: String },

/// Indicates a second has passed for the benchmarker
SecondPassed(Duration),
/// contains the time that the test ran for

/// Contains the time that the test ran for
FinishedIn(Duration),

/// Adds a note that will be visible to the user when viewing the benchmark results.
AddInfoMessage(String),

/// Ignore all other reports and use the ManualReport as the only source of benchmark metrics.
/// Do not use this under normal circumstances.
/// Instead this should only be used if you have an independent benchmarker that you want to call from windsock and include in windsocks results.
Expand Down Expand Up @@ -112,7 +133,8 @@ pub struct ReportArchive {
pub(crate) operations_report: Option<OperationsReport>,
pub(crate) pubsub_report: Option<PubSubReport>,
pub metrics: Vec<Metric>,
pub(crate) error_messages: Vec<String>,
pub error_messages: Vec<String>,
pub info_messages: Vec<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Default)]
Expand Down Expand Up @@ -341,12 +363,14 @@ pub(crate) async fn report_builder(
let mut total_operation_time = Duration::from_secs(0);
let mut total_produce_time = Duration::from_secs(0);
let mut error_messages = vec![];
let mut info_messages = vec![];

while let Some(report) = rx.recv().await {
match report {
Report::Start => {
started = Some(OffsetDateTime::now_utc());
}
Report::AddInfoMessage(message) => info_messages.push(message),
Report::QueryCompletedIn(duration) => {
let report = operations_report.get_or_insert_with(OperationsReport::default);
if started.is_some() {
Expand Down Expand Up @@ -490,6 +514,7 @@ pub(crate) async fn report_builder(
tags,
pubsub_report,
error_messages,
info_messages,
operations_report,
metrics: vec![],
};
Expand Down
44 changes: 39 additions & 5 deletions windsock/src/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,7 @@ fn base(reports: &[ReportColumn], table_type: &str) {
);
println!("{}", style(error).red().bold());
for (i, message) in report.current.error_messages.iter().enumerate() {
let line = format!(" {i}. {message}");
println!("{}", line);
println!(" {i}. {message}");
}
}

Expand All @@ -748,8 +747,7 @@ fn base(reports: &[ReportColumn], table_type: &str) {
);
println!("{}", style(error).red().bold());
for (i, message) in report.current.error_messages.iter().enumerate() {
let line = format!(" {i}. {message}");
println!("{}", line);
println!(" {i}. {message}");
}
}
}
Expand All @@ -766,9 +764,17 @@ fn base(reports: &[ReportColumn], table_type: &str) {
!x.current.running_in_release
|| x.baseline
.as_ref()
.map(|x| !x.error_messages.is_empty())
.map(|x| !x.running_in_release)
.unwrap_or(false)
});
let info_found = reports.iter().any(|x| {
!x.current.info_messages.is_empty()
|| x.baseline
.as_ref()
.map(|x| !x.info_messages.is_empty())
.unwrap_or(false)
});

if errors_found && not_running_in_release_found {
// ensure these two sections are kept apart
println!();
Expand All @@ -793,6 +799,34 @@ fn base(reports: &[ReportColumn], table_type: &str) {
}
}
}

#[allow(clippy::nonminimal_bool)]
if info_found
&& (not_running_in_release_found || (errors_found && !not_running_in_release_found))
{
// ensure these two sections are kept apart
println!();
}

for report in reports {
if !report.current.info_messages.is_empty() {
let error = format!("notes for {}", report.current.tags.get_name());
println!("{}", style(error).blue().bold());
for (i, message) in report.current.info_messages.iter().enumerate() {
println!(" {i}. {message}");
}
}

if let Some(baseline) = &report.baseline {
if !baseline.info_messages.is_empty() {
let error = format!("notes for baseline {}", report.current.tags.get_name());
println!("{}", style(error).blue().bold());
for (i, message) in report.current.info_messages.iter().enumerate() {
println!(" {i}. {message}");
}
}
}
}
}

fn duration_ms(duration: Duration) -> String {
Expand Down
Loading