Skip to content

Commit 059fc58

Browse files
committed
[move][coverage] Improve performance of coverage map generation
1 parent c201871 commit 059fc58

File tree

4 files changed

+62
-15
lines changed

4 files changed

+62
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

external-crates/move/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

external-crates/move/crates/move-coverage/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ indexmap.workspace = true
3131
lcov.workspace = true
3232
move-trace-format.workspace = true
3333
move-compiler.workspace = true
34+
rayon.workspace = true
3435

3536
[features]
3637
default = []

external-crates/move/crates/move-coverage/src/coverage_map.rs

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use move_core_types::{
1111
identifier::{IdentStr, Identifier},
1212
};
1313
use move_trace_format::format::{MoveTraceReader, TraceEvent};
14+
use rayon::prelude::*;
1415
use serde::{Deserialize, Serialize};
1516
use std::{
1617
collections::BTreeMap,
@@ -62,7 +63,7 @@ pub struct TraceMap {
6263
/// Trait for types that consume Move VM trace events. Implementors only need to provide
6364
/// `record_instruction`; directory iteration, file reading, and trace event walking are
6465
/// provided as default methods.
65-
pub trait TraceConsumer: Default {
66+
pub trait TraceConsumer: Default + Send {
6667
fn record_instruction(
6768
&mut self,
6869
test_name: &str,
@@ -72,6 +73,8 @@ pub trait TraceConsumer: Default {
7273
pc: u64,
7374
);
7475

76+
fn merge(self, other: Self) -> Self;
77+
7578
fn ingest_trace<R: Read>(
7679
mut self,
7780
test_name: &str,
@@ -102,21 +105,30 @@ pub trait TraceConsumer: Default {
102105
self
103106
}
104107

105-
fn ingest_trace_dir<P: AsRef<Path> + Debug>(mut self, dirname: P) -> Self {
106-
for entry in std::fs::read_dir(&dirname).unwrap() {
107-
let entry = entry.unwrap();
108-
let path = entry.path();
109-
if path.is_file() {
110-
let file = File::open(&path)
108+
fn ingest_trace_dir<P: AsRef<Path> + Debug>(self, dirname: P) -> Self {
109+
let entries: Vec<_> = std::fs::read_dir(&dirname)
110+
.unwrap()
111+
.filter_map(|e| {
112+
let path = e.unwrap().path();
113+
path.is_file().then_some(path)
114+
})
115+
.collect();
116+
117+
entries
118+
.par_iter()
119+
.map(|path| {
120+
let file = File::open(path)
111121
.unwrap_or_else(|e| panic!("Unable to open trace file '{:?}': {}", path, e));
112-
let move_trace_reader =
113-
MoveTraceReader::new(file).expect("Unable to read trace file");
114-
let test_name = path.file_name().unwrap().to_str().unwrap();
115-
let test_name = test_name.replace("__", "::");
116-
self = self.ingest_trace(&test_name, move_trace_reader);
117-
}
118-
}
119-
self
122+
let reader = MoveTraceReader::new(file).expect("Unable to read trace file");
123+
let test_name = path
124+
.file_name()
125+
.unwrap()
126+
.to_str()
127+
.unwrap()
128+
.replace("__", "::");
129+
Self::default().ingest_trace(&test_name, reader)
130+
})
131+
.reduce(Self::default, Self::merge)
120132
}
121133

122134
fn from_trace_dir<P: AsRef<Path> + Debug>(dirname: P) -> Self {
@@ -135,6 +147,28 @@ impl TraceConsumer for CoverageMap {
135147
) {
136148
self.insert(test_name, module_addr, module_name, func_name, pc);
137149
}
150+
151+
fn merge(mut self, other: Self) -> Self {
152+
for (exec_id, other_exec_map) in other.exec_maps {
153+
let entry = self
154+
.exec_maps
155+
.entry(exec_id)
156+
.or_insert_with(|| ExecCoverageMap::new(String::new()));
157+
for ((addr, name), other_module_map) in other_exec_map.module_maps {
158+
let module_entry = entry
159+
.module_maps
160+
.entry((addr, name.clone()))
161+
.or_insert_with(|| ModuleCoverageMap::new(addr, name));
162+
for (func_name, func_map) in other_module_map.function_maps {
163+
let func_entry = module_entry.function_maps.entry(func_name).or_default();
164+
for (pc, count) in func_map {
165+
*func_entry.entry(pc).or_insert(0) += count;
166+
}
167+
}
168+
}
169+
}
170+
self
171+
}
138172
}
139173

140174
impl TraceConsumer for TraceMap {
@@ -148,6 +182,16 @@ impl TraceConsumer for TraceMap {
148182
) {
149183
self.insert(test_name, module_addr, module_name, func_name, pc);
150184
}
185+
186+
fn merge(mut self, other: Self) -> Self {
187+
for (exec_id, other_entries) in other.exec_maps {
188+
self.exec_maps
189+
.entry(exec_id)
190+
.or_default()
191+
.extend(other_entries);
192+
}
193+
self
194+
}
151195
}
152196

153197
impl CoverageMap {

0 commit comments

Comments
 (0)