Skip to content

Commit a991024

Browse files
committed
Construct graph response more directly
Instead of creating a graph response in a fashion suitable for the old graph endpoint, then transforming it to something suitable for the new graph endpoint, create the response for the new endpoint directly.
1 parent 35f451b commit a991024

File tree

1 file changed

+65
-97
lines changed

1 file changed

+65
-97
lines changed

site/src/request_handlers/graph.rs

Lines changed: 65 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::api::{graph, ServerResult};
77
use crate::db::{self, ArtifactId, Benchmark, Profile, Scenario};
88
use crate::interpolate::Interpolated;
99
use crate::load::SiteCtxt;
10-
use crate::selector::{Path, PathComponent, Query, Selector, SeriesResponse, Tag};
10+
use crate::selector::{Query, Selector, SeriesResponse, Tag};
1111

1212
pub async fn handle_graph(
1313
body: graph::Request,
@@ -30,51 +30,7 @@ pub async fn handle_graph(
3030
}
3131
}
3232

33-
let range = ctxt.data_range(body.start.clone()..=body.end.clone());
34-
let commits: Vec<ArtifactId> = range.iter().map(|c| c.clone().into()).collect();
35-
36-
let mut benchmarks = HashMap::new();
37-
38-
let benchmarks_impl = handle_graph_impl(body, ctxt).await?;
39-
40-
for (benchmark_, benchmark_data) in benchmarks_impl.iter() {
41-
let mut by_profile = HashMap::with_capacity(3);
42-
43-
for (profile, series) in benchmark_data.iter() {
44-
let mut by_run = HashMap::with_capacity(3);
45-
46-
for (name, points) in series.iter() {
47-
let mut series = graph::Series {
48-
points: Vec::new(),
49-
is_interpolated: Default::default(),
50-
};
51-
52-
for (idx, point) in points.iter().enumerate() {
53-
series.points.push(point.value);
54-
if point.is_interpolated {
55-
series.is_interpolated.insert(idx as u16);
56-
}
57-
}
58-
59-
by_run.insert(name.clone(), series);
60-
}
61-
62-
by_profile.insert(profile.parse::<Profile>().unwrap(), by_run);
63-
}
64-
65-
benchmarks.insert(benchmark_.clone(), by_profile);
66-
}
67-
68-
let resp = Arc::new(graph::Response {
69-
commits: commits
70-
.into_iter()
71-
.map(|c| match c {
72-
ArtifactId::Commit(c) => (c.date.0.timestamp(), c.sha),
73-
ArtifactId::Tag(_) => unreachable!(),
74-
})
75-
.collect(),
76-
benchmarks,
77-
});
33+
let resp = graph_response(body, ctxt).await?;
7834

7935
if is_default_query {
8036
ctxt.landing_page.store(Arc::new(Some(resp.clone())));
@@ -83,22 +39,16 @@ pub async fn handle_graph(
8339
Ok(resp)
8440
}
8541

86-
struct GraphPoint {
87-
value: f32,
88-
is_interpolated: bool,
89-
}
90-
91-
async fn handle_graph_impl(
42+
async fn graph_response(
9243
body: graph::Request,
9344
ctxt: &SiteCtxt,
94-
) -> ServerResult<HashMap<String, HashMap<String, Vec<(String, Vec<GraphPoint>)>>>> {
45+
) -> ServerResult<Arc<graph::Response>> {
9546
let range = ctxt.data_range(body.start.clone()..=body.end.clone());
96-
let commits: Arc<Vec<_>> = Arc::new(range.iter().map(|c| c.clone().into()).collect());
97-
98-
let metric: database::Metric = body.stat.parse().unwrap();
47+
let commits: Arc<Vec<_>> = Arc::new(range.into_iter().map(|c| c.clone().into()).collect());
9948
let metric_selector = Selector::One(body.stat.clone());
49+
let mut benchmarks = HashMap::new();
10050

101-
let series = ctxt
51+
let series_iterator = ctxt
10252
.statistic_series(
10353
Query::new()
10454
.set::<String>(Tag::Benchmark, Selector::All)
@@ -107,17 +57,26 @@ async fn handle_graph_impl(
10757
.set::<String>(Tag::Metric, metric_selector.clone()),
10858
commits.clone(),
10959
)
110-
.await?;
111-
112-
let mut series = series
60+
.await?
11361
.into_iter()
114-
.map(|sr| {
115-
sr.interpolate()
116-
.map(|series| to_graph_points(body.kind, series).collect::<Vec<_>>())
117-
})
118-
.collect::<Vec<_>>();
62+
.map(SeriesResponse::interpolate);
63+
64+
for series_response in series_iterator {
65+
let benchmark = series_response.path.get::<Benchmark>()?.to_string();
66+
let profile = *series_response.path.get::<Profile>()?;
67+
let scenario = series_response.path.get::<Scenario>()?.to_string();
68+
let graph_series = graph_series(body.kind, series_response.series);
69+
70+
benchmarks
71+
.entry(benchmark)
72+
.or_insert_with(HashMap::new)
73+
.entry(profile)
74+
.or_insert_with(HashMap::new)
75+
.insert(scenario, graph_series);
76+
}
11977

12078
let mut baselines = HashMap::new();
79+
let mut summary_benchmark = HashMap::new();
12180

12281
let summary_query_cases = iproduct!(
12382
ctxt.summary_scenarios(),
@@ -162,53 +121,62 @@ async fn handle_graph_impl(
162121
)
163122
.map(|((c, d), i)| ((c, Some(d.expect("interpolated") / baseline)), i));
164123

165-
let graph_data = to_graph_points(body.kind, avg_vs_baseline).collect::<Vec<_>>();
124+
let graph_series = graph_series(body.kind, avg_vs_baseline);
166125

167-
series.push(SeriesResponse {
168-
path: Path::new()
169-
.set(PathComponent::Benchmark("Summary".into()))
170-
.set(PathComponent::Profile(profile))
171-
.set(PathComponent::Scenario(scenario))
172-
.set(PathComponent::Metric(metric)),
173-
series: graph_data,
174-
})
175-
}
176-
177-
let mut by_test_case = HashMap::new();
178-
for sr in series {
179-
let benchmark = sr.path.get::<Benchmark>()?.to_string();
180-
by_test_case
181-
.entry(benchmark)
126+
summary_benchmark
127+
.entry(profile)
182128
.or_insert_with(HashMap::new)
183-
.entry(sr.path.get::<Profile>()?.to_string())
184-
.or_insert_with(Vec::new)
185-
.push((sr.path.get::<Scenario>()?.to_string(), sr.series));
129+
.insert(scenario.to_string(), graph_series);
186130
}
187131

188-
Ok(by_test_case)
132+
benchmarks.insert("Summary".to_string(), summary_benchmark);
133+
134+
Ok(Arc::new(graph::Response {
135+
commits: Arc::try_unwrap(commits)
136+
.unwrap()
137+
.into_iter()
138+
.map(|c| match c {
139+
ArtifactId::Commit(c) => (c.date.0.timestamp(), c.sha),
140+
ArtifactId::Tag(_) => unreachable!(),
141+
})
142+
.collect(),
143+
benchmarks,
144+
}))
189145
}
190146

191-
fn to_graph_points<'a>(
147+
fn graph_series(
192148
kind: GraphKind,
193-
points: impl Iterator<Item = ((ArtifactId, Option<f64>), Interpolated)> + 'a,
194-
) -> impl Iterator<Item = GraphPoint> + 'a {
149+
points: impl Iterator<Item = ((ArtifactId, Option<f64>), Interpolated)>,
150+
) -> graph::Series {
151+
let mut graph_series = graph::Series {
152+
points: Vec::new(),
153+
is_interpolated: Default::default(),
154+
};
155+
195156
let mut first = None;
196157
let mut prev = None;
197-
points.map(move |((_aid, point), interpolated)| {
158+
159+
for (idx, ((_aid, point), interpolated)) in points.enumerate() {
198160
let point = point.expect("interpolated");
199161
first = Some(first.unwrap_or(point));
200162
let first = first.unwrap();
201163
let percent_first = (point - first) / first * 100.0;
202164
let previous_point = prev.unwrap_or(point);
203165
let percent_prev = (point - previous_point) / previous_point * 100.0;
204166
prev = Some(point);
205-
GraphPoint {
206-
value: match kind {
207-
GraphKind::Raw => point as f32,
208-
GraphKind::PercentRelative => percent_prev as f32,
209-
GraphKind::PercentFromFirst => percent_first as f32,
210-
},
211-
is_interpolated: interpolated.is_interpolated(),
167+
168+
let value = match kind {
169+
GraphKind::Raw => point as f32,
170+
GraphKind::PercentRelative => percent_prev as f32,
171+
GraphKind::PercentFromFirst => percent_first as f32,
172+
};
173+
174+
graph_series.points.push(value);
175+
176+
if interpolated.is_interpolated() {
177+
graph_series.is_interpolated.insert(idx as u16);
212178
}
213-
})
179+
}
180+
181+
graph_series
214182
}

0 commit comments

Comments
 (0)