Skip to content

Commit c9fb0d4

Browse files
committed
Avoid intermediate Vec allocations in coverage mapping creation
1 parent bba6c6c commit c9fb0d4

File tree

5 files changed

+33
-42
lines changed

5 files changed

+33
-42
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,12 @@ impl<'tcx> FunctionCoverage<'tcx> {
180180
self.source_hash
181181
}
182182

183-
/// Generate an array of CounterExpressions, and an iterator over all `Counter`s and their
184-
/// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
185-
/// `CounterMappingRegion`s.
183+
/// Generate an array of CounterExpressions, and an array of all `Counter`s and their
184+
/// associated `Regions` sorted by `Region`, from which the LLVM-specific
185+
/// `CoverageMapGenerator` will create `CounterMappingRegion`s.
186186
pub fn get_expressions_and_counter_regions(
187187
&self,
188-
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
188+
) -> (Vec<CounterExpression>, Vec<(Counter, &CodeRegion)>) {
189189
assert!(
190190
self.source_hash != 0 || !self.is_used,
191191
"No counters provided the source_hash for used function: {:?}",
@@ -198,21 +198,31 @@ impl<'tcx> FunctionCoverage<'tcx> {
198198
// the two vectors should correspond 1:1.
199199
assert_eq!(self.expressions.len(), counter_expressions.len());
200200

201-
let counter_regions = self.counter_regions();
202-
let expression_regions = self.expression_regions();
203-
let unreachable_regions = self.unreachable_regions();
204-
205-
let counter_regions =
206-
counter_regions.chain(expression_regions.into_iter().chain(unreachable_regions));
207-
(counter_expressions, counter_regions)
208-
}
209-
210-
fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
211-
self.counters.iter_enumerated().filter_map(|(index, entry)| {
201+
let counter_regions = self.counters.iter_enumerated().filter_map(|(index, entry)| {
212202
// Option::map() will return None to filter out missing counters. This may happen
213203
// if, for example, a MIR-instrumented counter is removed during an optimization.
214204
entry.as_ref().map(|region| (Counter::counter_value_reference(index), region))
215-
})
205+
});
206+
207+
// Find all of the expression IDs that weren't optimized out AND have
208+
// an attached code region, and return the corresponding mapping as a
209+
// counter/region pair.
210+
let expression_regions =
211+
self.expressions.iter_enumerated().filter_map(|(id, expression)| {
212+
let code_region = expression.as_ref()?.region.as_ref()?;
213+
Some((Counter::expression(id), code_region))
214+
});
215+
let unreachable_regions =
216+
self.unreachable_regions.iter().map(|region| (Counter::ZERO, region));
217+
218+
let mut all_regions: Vec<_> = expression_regions.collect();
219+
all_regions.extend(counter_regions);
220+
all_regions.extend(unreachable_regions);
221+
222+
// make sure all the regions are sorted
223+
all_regions.sort_unstable_by_key(|(_counter, region)| *region);
224+
225+
(counter_expressions, all_regions)
216226
}
217227

218228
/// Convert this function's coverage expression data into a form that can be
@@ -244,21 +254,4 @@ impl<'tcx> FunctionCoverage<'tcx> {
244254
})
245255
.collect::<Vec<_>>()
246256
}
247-
248-
fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> {
249-
// Find all of the expression IDs that weren't optimized out AND have
250-
// an attached code region, and return the corresponding mapping as a
251-
// counter/region pair.
252-
self.expressions
253-
.iter_enumerated()
254-
.filter_map(|(id, expression)| {
255-
let code_region = expression.as_ref()?.region.as_ref()?;
256-
Some((Counter::expression(id), code_region))
257-
})
258-
.collect::<Vec<_>>()
259-
}
260-
261-
fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
262-
self.unreachable_regions.iter().map(|region| (Counter::ZERO, region))
263-
}
264257
}

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,13 @@ impl CoverageMapGenerator {
142142
/// Using the `expressions` and `counter_regions` collected for the current function, generate
143143
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
144144
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
145-
/// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
146-
fn write_coverage_mapping<'a>(
145+
/// the given `coverage_mapping_buffer` byte buffer, compliant with the LLVM Coverage Mapping format.
146+
fn write_coverage_mapping(
147147
&mut self,
148148
expressions: Vec<CounterExpression>,
149-
counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
149+
counter_regions: Vec<(Counter, &CodeRegion)>,
150150
coverage_mapping_buffer: &RustString,
151151
) {
152-
let mut counter_regions = counter_regions.collect::<Vec<_>>();
153152
if counter_regions.is_empty() {
154153
return;
155154
}
@@ -164,7 +163,6 @@ impl CoverageMapGenerator {
164163
// `file_id` (indexing files referenced by the current function), and construct the
165164
// function-specific `virtual_file_mapping` from `file_id` to its index in the module's
166165
// `filenames` array.
167-
counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
168166
for (counter, region) in counter_regions {
169167
let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
170168
let same_file = current_file_name.is_some_and(|p| p == file_name);

compiler/rustc_mir_transform/src/coverage/debug.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@
4444
//! points, which can be enabled via environment variable:
4545
//!
4646
//! ```shell
47-
//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug
47+
//! RUSTC_LOG=rustc_mir_transform::coverage=debug
4848
//! ```
4949
//!
5050
//! Other module paths with coverage-related debug logs may also be of interest, particularly for
5151
//! debugging the coverage map data, injected as global variables in the LLVM IR (during rustc's
5252
//! code generation pass). For example:
5353
//!
5454
//! ```shell
55-
//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
55+
//! RUSTC_LOG=rustc_mir_transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
5656
//! ```
5757
//!
5858
//! Coverage Debug Options

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
216216
}
217217

218218
////////////////////////////////////////////////////
219-
// Remove the counter or edge counter from of each `CoverageSpan`s associated
219+
// Remove the counter or edge counter from each `CoverageSpan`s associated
220220
// `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
221221
//
222222
// `Coverage` statements injected from `CoverageSpan`s will include the code regions

compiler/rustc_mir_transform/src/coverage/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! pass.
33
//!
44
//! ```shell
5-
//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage'
5+
//! ./x.py test --keep-stage 1 compiler/rustc_mir_transform --test-args '--show-output coverage'
66
//! ```
77
//!
88
//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage`

0 commit comments

Comments
 (0)