Skip to content

Commit c58589c

Browse files
Merge pull request #978 from tgnottingham/update-flamegraph-crox-support
Update flamegraph and crox support
2 parents 088c9a2 + 4f5f99e commit c58589c

File tree

4 files changed

+41
-83
lines changed

4 files changed

+41
-83
lines changed

site/src/request_handlers/self_profile.rs

+32-24
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,33 @@ pub async fn handle_self_profile_processed_download(
2525
body.benchmark,
2626
body.run_name
2727
);
28+
2829
let start = Instant::now();
29-
let pieces = match get_pieces(body, ctxt).await {
30+
31+
let (url, is_tarball) = match handle_self_profile_raw(body, ctxt).await {
32+
Ok(v) => (v.url, v.is_tarball),
33+
Err(e) => {
34+
let mut resp = Response::new(e.into());
35+
*resp.status_mut() = StatusCode::BAD_REQUEST;
36+
return resp;
37+
}
38+
};
39+
40+
if is_tarball {
41+
let mut resp =
42+
Response::new("Processing legacy format self-profile data is not supported".into());
43+
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
44+
return resp;
45+
}
46+
47+
let data = match get_self_profile_raw_data(&url).await {
3048
Ok(v) => v,
3149
Err(e) => return e,
3250
};
33-
log::trace!("got pieces {:?} in {:?}", pieces, start.elapsed());
3451

35-
let output = match crate::self_profile::generate(&title, pieces, params) {
52+
log::trace!("got data in {:?}", start.elapsed());
53+
54+
let output = match crate::self_profile::generate(&title, data, params) {
3655
Ok(c) => c,
3756
Err(e) => {
3857
log::error!("Failed to generate json {:?}", e);
@@ -166,22 +185,10 @@ fn get_self_profile_data(
166185
Ok(profile)
167186
}
168187

169-
async fn get_pieces(
170-
body: crate::api::self_profile_raw::Request,
171-
ctxt: &SiteCtxt,
172-
) -> Result<crate::self_profile::Pieces, Response> {
173-
let res = handle_self_profile_raw(body, ctxt).await;
174-
let url = match res {
175-
Ok(v) => v.url,
176-
Err(e) => {
177-
let mut resp = Response::new(e.into());
178-
*resp.status_mut() = StatusCode::BAD_REQUEST;
179-
return Err(resp);
180-
}
181-
};
188+
async fn get_self_profile_raw_data(url: &str) -> Result<Vec<u8>, Response> {
182189
log::trace!("downloading {}", url);
183190

184-
let resp = match reqwest::get(&url).await {
191+
let resp = match reqwest::get(url).await {
185192
Ok(r) => r,
186193
Err(e) => {
187194
let mut resp = Response::new(format!("{:?}", e).into());
@@ -197,7 +204,7 @@ async fn get_pieces(
197204
return Err(resp);
198205
}
199206

200-
let tarball = match resp.bytes().await {
207+
let compressed = match resp.bytes().await {
201208
Ok(b) => b,
202209
Err(e) => {
203210
let mut resp =
@@ -206,18 +213,19 @@ async fn get_pieces(
206213
return Err(resp);
207214
}
208215
};
209-
let tarball = tar::Archive::new(std::io::BufReader::new(snap::read::FrameDecoder::new(
210-
tarball.reader(),
211-
)));
212-
let pieces = match crate::self_profile::Pieces::from_tarball(tarball) {
216+
217+
let mut data = Vec::new();
218+
219+
match snap::read::FrameDecoder::new(compressed.reader()).read_to_end(&mut data) {
213220
Ok(v) => v,
214221
Err(e) => {
215-
let mut resp = Response::new(format!("could not extract from tarball: {:?}", e).into());
222+
let mut resp = Response::new(format!("could not decode: {:?}", e).into());
216223
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
217224
return Err(resp);
218225
}
219226
};
220-
Ok(pieces)
227+
228+
Ok(data)
221229
}
222230

223231
pub async fn handle_self_profile_raw_download(

site/src/self_profile.rs

+3-51
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
44
use anyhow::Context;
55
use std::collections::HashMap;
6-
use std::fmt;
7-
use std::io::Read;
86

97
pub mod crox;
108
pub mod flamegraph;
@@ -17,7 +15,7 @@ pub struct Output {
1715

1816
pub fn generate(
1917
title: &str,
20-
pieces: Pieces,
18+
self_profile_data: Vec<u8>,
2119
mut params: HashMap<String, String>,
2220
) -> anyhow::Result<Output> {
2321
let removed = params.remove("type");
@@ -27,7 +25,7 @@ pub fn generate(
2725
.context("crox opts")?;
2826
Ok(Output {
2927
filename: "chrome_profiler.json",
30-
data: crox::generate(pieces, opt).context("crox")?,
28+
data: crox::generate(self_profile_data, opt).context("crox")?,
3129
is_download: true,
3230
})
3331
}
@@ -36,56 +34,10 @@ pub fn generate(
3634
.context("flame opts")?;
3735
Ok(Output {
3836
filename: "flamegraph.svg",
39-
data: flamegraph::generate(title, pieces, opt).context("flame")?,
37+
data: flamegraph::generate(title, self_profile_data, opt).context("flame")?,
4038
is_download: false,
4139
})
4240
}
4341
_ => anyhow::bail!("Unknown type, specify type={crox,flamegraph}"),
4442
}
4543
}
46-
47-
pub struct Pieces {
48-
pub string_data: Vec<u8>,
49-
pub string_index: Vec<u8>,
50-
pub events: Vec<u8>,
51-
}
52-
53-
impl fmt::Debug for Pieces {
54-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55-
f.debug_struct("Pieces")
56-
.field("string_data", &self.string_data.len())
57-
.field("string_index", &self.string_index.len())
58-
.field("events", &self.events.len())
59-
.finish()
60-
}
61-
}
62-
63-
impl Pieces {
64-
pub fn from_tarball<R: std::io::Read>(mut tarball: tar::Archive<R>) -> anyhow::Result<Pieces> {
65-
let mut pieces = Pieces {
66-
string_data: Vec::new(),
67-
string_index: Vec::new(),
68-
events: Vec::new(),
69-
};
70-
71-
for entry in tarball.entries().context("entries")? {
72-
let mut entry = entry.context("tarball entry")?;
73-
let path = entry.path_bytes();
74-
if *path == *b"self-profile.string_index" {
75-
entry
76-
.read_to_end(&mut pieces.string_index)
77-
.context("reading string index")?;
78-
} else if *path == *b"self-profile.string_data" {
79-
entry
80-
.read_to_end(&mut pieces.string_data)
81-
.context("reading string data")?;
82-
} else if *path == *b"self-profile.events" {
83-
entry
84-
.read_to_end(&mut pieces.events)
85-
.context("reading events")?;
86-
}
87-
}
88-
89-
Ok(pieces)
90-
}
91-
}

site/src/self_profile/crox.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,13 @@ fn get_args(full_event: &analyzeme::Event) -> Option<HashMap<String, String>> {
125125
}
126126

127127
/// Returns JSON blob fit, `chrome_profiler.json`.
128-
pub fn generate(pieces: super::Pieces, opt: Opt) -> anyhow::Result<Vec<u8>> {
128+
pub fn generate(self_profile_data: Vec<u8>, opt: Opt) -> anyhow::Result<Vec<u8>> {
129129
let mut serializer = serde_json::Serializer::new(Vec::new());
130130

131131
let mut seq = serializer.serialize_seq(None)?;
132132

133-
let data =
134-
ProfilingData::from_buffers(pieces.string_data, pieces.string_index, pieces.events, None)
135-
.map_err(|e| anyhow::format_err!("{:?}", e))?;
133+
let data = ProfilingData::from_paged_buffer(self_profile_data)
134+
.map_err(|e| anyhow::format_err!("{:?}", e))?;
136135

137136
let thread_to_collapsed_thread =
138137
generate_thread_to_collapsed_thread_mapping(opt.collapse_threads, &data);

site/src/self_profile/flamegraph.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use inferno::flamegraph::{from_lines, Options as FlamegraphOptions};
55
#[derive(serde::Deserialize, Debug)]
66
pub struct Opt {}
77

8-
pub fn generate(title: &str, pieces: super::Pieces, _: Opt) -> anyhow::Result<Vec<u8>> {
9-
let profiling_data =
10-
ProfilingData::from_buffers(pieces.string_data, pieces.string_index, pieces.events, None)
11-
.map_err(|e| anyhow::format_err!("{:?}", e))?;
8+
pub fn generate(title: &str, self_profile_data: Vec<u8>, _: Opt) -> anyhow::Result<Vec<u8>> {
9+
let profiling_data = ProfilingData::from_paged_buffer(self_profile_data)
10+
.map_err(|e| anyhow::format_err!("{:?}", e))?;
1211

1312
let recorded_stacks = collapse_stacks(&profiling_data)
1413
.iter()

0 commit comments

Comments
 (0)