Skip to content

Commit 63c9f16

Browse files
crox JSON output directly
1 parent 0bae930 commit 63c9f16

File tree

9 files changed

+545
-57
lines changed

9 files changed

+545
-57
lines changed

Cargo.lock

Lines changed: 97 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ debug = 1
77

88
[profile.release.package.collector]
99
debug = 1
10+
11+
[patch."https://github.com/rust-lang/measureme"]
12+
analyzeme = { path = "../measureme/analyzeme" }

site/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ async-trait = "0.1"
4040
database = { path = "../database" }
4141
bytes = "0.5.6"
4242
url = "2"
43+
analyzeme = { git = "https://github.com/rust-lang/measureme" }
44+
tar = "0.4"
4345

4446
[dependencies.collector]
4547
path = "../collector"

site/src/flamegraph.svg

Loading

site/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ pub mod db;
2626
mod interpolate;
2727
pub mod load;
2828
mod selector;
29+
mod self_profile;
2930
pub mod server;
3031
pub mod util;

site/src/self_profile.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//! This module handles self-profile "rich" APIs (e.g., chrome profiler JSON)
2+
//! generation from the raw artifacts on demand.
3+
4+
use crate::load::InputData;
5+
use anyhow::Context;
6+
use bytes::buf::BufExt;
7+
use hyper::StatusCode;
8+
use std::collections::HashMap;
9+
use std::fmt;
10+
use std::io::Read;
11+
12+
type Response = http::Response<hyper::Body>;
13+
14+
pub mod crox;
15+
16+
pub fn generate(pieces: Pieces, mut params: HashMap<String, String>) -> anyhow::Result<Vec<u8>> {
17+
let removed = params.remove("type");
18+
match removed.as_deref() {
19+
Some("crox") => {
20+
let opt = serde_json::from_str(&serde_json::to_string(&params).unwrap())
21+
.context("crox opts")?;
22+
Ok(crox::generate(pieces, opt).context("crox")?)
23+
}
24+
_ => anyhow::bail!("Unknown type, specify type={crox}"),
25+
}
26+
}
27+
28+
pub struct Pieces {
29+
pub string_data: Vec<u8>,
30+
pub string_index: Vec<u8>,
31+
pub events: Vec<u8>,
32+
}
33+
34+
impl fmt::Debug for Pieces {
35+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36+
f.debug_struct("Pieces")
37+
.field("string_data", &self.string_data.len())
38+
.field("string_index", &self.string_index.len())
39+
.field("events", &self.events.len())
40+
.finish()
41+
}
42+
}
43+
44+
pub async fn get_pieces(
45+
body: crate::api::self_profile_raw::Request,
46+
data: &InputData,
47+
) -> Result<Pieces, Response> {
48+
let res = crate::server::handle_self_profile_raw(body, data, false).await;
49+
let url = match res {
50+
Ok(v) => v.url,
51+
Err(e) => {
52+
let mut resp = Response::new(e.into());
53+
*resp.status_mut() = StatusCode::BAD_REQUEST;
54+
return Err(resp);
55+
}
56+
};
57+
log::trace!("downloading {}", url);
58+
59+
let resp = match reqwest::get(&url).await {
60+
Ok(r) => r,
61+
Err(e) => {
62+
let mut resp = Response::new(format!("{:?}", e).into());
63+
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
64+
return Err(resp);
65+
}
66+
};
67+
68+
if !resp.status().is_success() {
69+
let mut resp =
70+
Response::new(format!("upstream status {:?} is not successful", resp.status()).into());
71+
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
72+
return Err(resp);
73+
}
74+
75+
let tarball = match resp.bytes().await {
76+
Ok(b) => b,
77+
Err(e) => {
78+
let mut resp =
79+
Response::new(format!("could not download from upstream: {:?}", e).into());
80+
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
81+
return Err(resp);
82+
}
83+
};
84+
let tarball = tar::Archive::new(std::io::BufReader::new(snap::read::FrameDecoder::new(
85+
tarball.reader(),
86+
)));
87+
let pieces = match Pieces::from_tarball(tarball) {
88+
Ok(v) => v,
89+
Err(e) => {
90+
let mut resp = Response::new(format!("could not extract from tarball: {:?}", e).into());
91+
*resp.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
92+
return Err(resp);
93+
}
94+
};
95+
Ok(pieces)
96+
}
97+
98+
impl Pieces {
99+
fn from_tarball<R: std::io::Read>(mut tarball: tar::Archive<R>) -> anyhow::Result<Pieces> {
100+
let mut pieces = Pieces {
101+
string_data: Vec::new(),
102+
string_index: Vec::new(),
103+
events: Vec::new(),
104+
};
105+
106+
for entry in tarball.entries().context("entries")? {
107+
let mut entry = entry.context("tarball entry")?;
108+
let path = entry.path_bytes();
109+
if *path == *b"self-profile.string_index" {
110+
entry
111+
.read_to_end(&mut pieces.string_index)
112+
.context("reading string index")?;
113+
} else if *path == *b"self-profile.string_data" {
114+
entry
115+
.read_to_end(&mut pieces.string_data)
116+
.context("reading string data")?;
117+
} else if *path == *b"self-profile.events" {
118+
entry
119+
.read_to_end(&mut pieces.events)
120+
.context("reading events")?;
121+
}
122+
}
123+
124+
Ok(pieces)
125+
}
126+
}

0 commit comments

Comments
 (0)