Skip to content

Commit 6bf2017

Browse files
committed
Auto merge of #717 - Mark-Simulacrum:shrink-html-report, r=Mark-Simulacrum
Avoid extra allocations while generating HTML reports Tested locally on a sample report that the results look visually the same.
2 parents 76cd44d + ffb0b6a commit 6bf2017

21 files changed

+531
-375
lines changed

src/assets.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -161,5 +161,7 @@ pub fn render_template<C: Serialize>(name: &str, context: &C) -> Fallible<String
161161
tera = &TERA_CACHE;
162162
}
163163

164-
Ok(tera.render(name, context).to_failure()?)
164+
Ok(tera
165+
.render(name, context)
166+
.map_err(|e| failure::format_err!("{:?}", e))?)
165167
}

src/report/display.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl ResultName for TestResult {
7878
}
7979
}
8080

81-
#[derive(Serialize)]
81+
#[derive(PartialEq, Eq, Hash, Serialize)]
8282
pub enum Color {
8383
Single(&'static str),
8484
Striped(&'static str, &'static str),

src/report/html.rs

+96-60
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashMap;
2+
13
use crate::assets;
24
use crate::experiments::Experiment;
35
use crate::prelude::*;
@@ -6,7 +8,9 @@ use crate::report::{
68
ResultColor, ResultName, TestResults,
79
};
810
use crate::results::EncodingType;
9-
use indexmap::IndexMap;
11+
use indexmap::{IndexMap, IndexSet};
12+
13+
use super::CrateVersionStatus;
1014

1115
#[derive(Serialize)]
1216
struct NavbarItem {
@@ -23,15 +27,15 @@ enum CurrentPage {
2327
}
2428

2529
#[derive(Serialize)]
26-
enum ReportCratesHTML {
27-
Plain(Vec<CrateResultHTML>),
30+
enum ReportCratesHTML<'a> {
31+
Plain(Vec<CrateResultHTML<'a>>),
2832
Tree {
2933
count: u32,
30-
tree: IndexMap<String, Vec<CrateResultHTML>>,
34+
tree: IndexMap<String, Vec<CrateResultHTML<'a>>>,
3135
},
3236
RootResults {
3337
count: u32,
34-
results: IndexMap<String, Vec<CrateResultHTML>>,
38+
results: IndexMap<String, Vec<CrateResultHTML<'a>>>,
3539
},
3640
}
3741

@@ -61,13 +65,13 @@ impl CurrentPage {
6165
struct ResultsContext<'a> {
6266
ex: &'a Experiment,
6367
nav: Vec<NavbarItem>,
64-
categories: Vec<(Comparison, ReportCratesHTML)>,
68+
// (comparison, category color, ...)
69+
categories: Vec<(Comparison, usize, ReportCratesHTML<'a>)>,
6570
info: IndexMap<Comparison, u32>,
6671
full: bool,
6772
crates_count: usize,
68-
comparison_colors: IndexMap<Comparison, Color>,
69-
result_colors: Vec<Color>,
70-
result_names: Vec<String>,
73+
colors: IndexSet<Color>,
74+
result_names: IndexSet<String>,
7175
}
7276

7377
#[derive(Serialize)]
@@ -80,20 +84,52 @@ struct DownloadsContext<'a> {
8084
}
8185

8286
#[derive(Serialize)]
83-
struct CrateResultHTML {
84-
name: String,
85-
url: String,
87+
struct CrateResultHTML<'a> {
88+
name: &'a str,
89+
url: &'a str,
8690
res: Comparison,
8791
#[serde(skip_serializing_if = "Option::is_none")]
88-
status: Option<String>,
89-
runs: [Option<BuildTestResultHTML>; 2],
92+
status: Option<CrateVersionStatus>,
93+
color_idx: usize,
94+
runs: [Option<BuildTestResultHTML<'a>>; 2],
9095
}
9196

9297
// Map TestResult to usize to avoid the presence of special characters in html
9398
#[derive(Serialize)]
94-
struct BuildTestResultHTML {
95-
res: usize,
96-
log: String,
99+
struct BuildTestResultHTML<'a> {
100+
color_idx: usize,
101+
name_idx: usize,
102+
log: &'a str,
103+
}
104+
105+
fn to_html_crate_result<'a>(
106+
colors: &mut IndexSet<Color>,
107+
result_names: &mut IndexSet<String>,
108+
category_color: usize,
109+
result: &'a CrateResult,
110+
) -> CrateResultHTML<'a> {
111+
let mut runs = [None, None];
112+
113+
for (pos, run) in result.runs.iter().enumerate() {
114+
if let Some(run) = run {
115+
let (color_idx, _) = colors.insert_full(run.res.color());
116+
let (name_idx, _) = result_names.insert_full(run.res.short_name());
117+
runs[pos] = Some(BuildTestResultHTML {
118+
color_idx,
119+
name_idx,
120+
log: run.log.as_str(),
121+
});
122+
}
123+
}
124+
125+
CrateResultHTML {
126+
name: result.name.as_str(),
127+
url: result.url.as_str(),
128+
status: result.status,
129+
res: result.res,
130+
color_idx: category_color,
131+
runs,
132+
}
97133
}
98134

99135
fn write_report<W: ReportWriter>(
@@ -105,54 +141,37 @@ fn write_report<W: ReportWriter>(
105141
dest: &W,
106142
output_templates: bool,
107143
) -> Fallible<()> {
108-
let mut comparison_colors = IndexMap::new();
109-
let mut test_results_to_int = IndexMap::new();
110-
let mut result_colors = Vec::new();
111-
let mut result_names = Vec::new();
144+
let mut colors = IndexSet::new();
145+
let mut result_names = IndexSet::new();
112146

113-
let mut to_html_crate_result = |result: CrateResult| {
114-
let mut runs = [None, None];
115-
116-
for (pos, run) in result.runs.iter().enumerate() {
117-
if let Some(ref run) = run {
118-
let idx = test_results_to_int
119-
.entry(run.res.clone())
120-
.or_insert_with(|| {
121-
result_colors.push(run.res.color());
122-
result_names.push(run.res.short_name());
123-
result_names.len() - 1
124-
});
125-
runs[pos] = Some(BuildTestResultHTML {
126-
res: *idx,
127-
log: run.log.clone(),
128-
});
129-
}
130-
}
131-
132-
CrateResultHTML {
133-
name: result.name.clone(),
134-
url: result.url.clone(),
135-
status: result.status.map(|status| status.to_string()),
136-
res: result.res,
137-
runs,
138-
}
139-
};
147+
let color_for_category = res
148+
.categories
149+
.keys()
150+
.map(|category| (category.color(), colors.insert_full(category.color()).0))
151+
.collect::<HashMap<_, _>>();
140152

141153
let categories = res
142154
.categories
143155
.iter()
144156
.filter(|(category, _)| full || category.show_in_summary())
145-
.map(|(&category, crates)| (category, crates.to_owned()))
157+
.map(|(&category, crates)| (category, crates))
146158
.flat_map(|(category, crates)| {
147-
comparison_colors.insert(category, category.color());
148-
159+
let category_color_idx = *color_for_category.get(&category.color()).unwrap();
149160
match crates {
150161
ReportCrates::Plain(crates) => vec![(
151162
category,
163+
category_color_idx,
152164
ReportCratesHTML::Plain(
153165
crates
154-
.into_iter()
155-
.map(|result| to_html_crate_result(result))
166+
.iter()
167+
.map(|result| {
168+
to_html_crate_result(
169+
&mut colors,
170+
&mut result_names,
171+
category_color_idx,
172+
result,
173+
)
174+
})
156175
.collect::<Vec<_>>(),
157176
),
158177
)]
@@ -163,8 +182,15 @@ fn write_report<W: ReportWriter>(
163182
.map(|(root, deps)| {
164183
(
165184
root.to_string(),
166-
deps.into_iter()
167-
.map(|result| to_html_crate_result(result))
185+
deps.iter()
186+
.map(|result| {
187+
to_html_crate_result(
188+
&mut colors,
189+
&mut result_names,
190+
category_color_idx,
191+
result,
192+
)
193+
})
168194
.collect::<Vec<_>>(),
169195
)
170196
})
@@ -175,8 +201,15 @@ fn write_report<W: ReportWriter>(
175201
(
176202
res.long_name(),
177203
krates
178-
.into_iter()
179-
.map(|result| to_html_crate_result(result))
204+
.iter()
205+
.map(|result| {
206+
to_html_crate_result(
207+
&mut colors,
208+
&mut result_names,
209+
category_color_idx,
210+
result,
211+
)
212+
})
180213
.collect::<Vec<_>>(),
181214
)
182215
})
@@ -185,13 +218,15 @@ fn write_report<W: ReportWriter>(
185218
vec![
186219
(
187220
category,
221+
category_color_idx,
188222
ReportCratesHTML::Tree {
189223
count: tree.keys().len() as u32,
190224
tree,
191225
},
192226
),
193227
(
194228
category,
229+
category_color_idx,
195230
ReportCratesHTML::RootResults {
196231
count: results.keys().len() as u32,
197232
results,
@@ -216,13 +251,14 @@ fn write_report<W: ReportWriter>(
216251
info: res.info.clone(),
217252
full,
218253
crates_count,
219-
comparison_colors,
220-
result_colors,
254+
colors,
221255
result_names,
222256
};
223257

224258
info!("generating {}", to);
225-
let html = minifier::html::minify(&assets::render_template("report/results.html", &context)?);
259+
let rendered = assets::render_template("report/results.html", &context)
260+
.context("rendering template report/results.html")?;
261+
let html = minifier::html::minify(&rendered);
226262
dest.write_string(to, html.into(), &mime::TEXT_HTML)?;
227263

228264
if output_templates {

templates/macros.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
{% for run in crate.runs %}
3737
<span class="run">
3838
{% if run %}
39-
<b class="r{{ run.res }}"></b>
40-
<a href="{{ run.log|safe }}/log.txt">{{ result_names[run.res] }}</a>
39+
<b class="c{{ run.color_idx }}"></b>
40+
<a href="{{ run.log|safe }}/log.txt">{{ result_names[run.name_idx] }}</a>
4141
{% else %}
42-
<b class="c{{ crate.res }}"></b>
42+
<b class="c{{ crate.color_idx }}"></b>
4343
{{ crate.res }}
4444
{% endif %}
4545
</span>

templates/report/results.html

+9-18
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,8 @@
55

66
{% block extra_head %}
77
<style>
8-
{% for color in result_colors %}
9-
.r{{ loop.index0 }} {
10-
{% if color.Single %}
11-
background: {{ color.Single }};
12-
{% elif color.Striped %}
13-
background: repeating-linear-gradient(-45deg, {{ color.Striped[0] }}, {{ color.Striped[0] }} 15px, {{ color.Striped[1] }} 15px, {{ color.Striped[1] }} 30px);
14-
{% endif %}
15-
}
16-
{% endfor %}
17-
18-
{% for name, color in comparison_colors %}
19-
.c{{ name }} {
8+
{% for color in colors %}
9+
.c{{ loop.index0 }} {
2010
{% if color.Single %}
2111
background: {{ color.Single }};
2212
{% elif color.Striped %}
@@ -31,10 +21,11 @@
3121
{% if categories %}
3222
{% for iter in categories %}
3323
{% set name = iter.0 %}
34-
{% set crates = iter.1 %}
24+
{% set category_color_idx = iter.1 %}
25+
{% set crates = iter.2 %}
3526
<div class="category">
3627
{% if crates.Plain %}
37-
<div class="header c{{ name }} toggle" data-toggle="#crt-{{ name }}">
28+
<div class="header c{{ category_color_idx }} toggle" data-toggle="#crt-{{ name }}">
3829
{{ name }} ({{ crates.Plain|length }})
3930
</div>
4031
<div class="crates hidden" id="crt-{{ name }}">
@@ -44,14 +35,14 @@
4435
{% endfor %}
4536
</div>
4637
{% elif crates.Tree and crates.Tree.count > 0 %}
47-
<div class="header c{{ name }} toggle" data-toggle="#crt-{{ name }}-tr">
38+
<div class="header c{{ category_color_idx }} toggle" data-toggle="#crt-{{ name }}-tr">
4839
{{ name }}: dependencies ({{ crates.Tree.count }} root crates, {{info[name]}} {{ name }} crates in total)
4940
</div>
5041
<div class="crates hidden" id="crt-{{ name }}-tr">
5142
{% for root, subcrates in crates.Tree.tree %}
5243
<div class="category">
5344
<div class="flex toggle" data-toggle="#{{ name }}-tr{{ loop.index }}">
54-
<div class="header c{{ name}} subheader">{{ name}}</div>
45+
<div class="header c{{ category_color_idx }} subheader">{{ name}}</div>
5546
<div class="header header-background">
5647
{{ root }} ({{ subcrates|length }})
5748
</div>
@@ -66,14 +57,14 @@
6657
{% endfor %}
6758
</div>
6859
{% elif crates.RootResults %}
69-
<div class="header c{{ name }} toggle" data-toggle="#crt-{{ name }}-rt">
60+
<div class="header c{{ category_color_idx }} toggle" data-toggle="#crt-{{ name }}-rt">
7061
{{ name }}: root results ({{ crates.RootResults.count }} different results, {{info[name]}} {{ name }} crates in total)
7162
</div>
7263
<div class="crates hidden" id="crt-{{ name }}-rt">
7364
{% for result, subcrates in crates.RootResults.results %}
7465
<div class="category">
7566
<div class="flex toggle" data-toggle="#{{ name }}-rt{{ loop.index }}">
76-
<div class="header c{{ name}} subheader">{{ name}}</div>
67+
<div class="header c{{ category_color_idx }} subheader">{{ name}}</div>
7768
<div class="header header-background">
7869
{{ result }} ({{ subcrates|length }})
7970
</div>

0 commit comments

Comments
 (0)