Skip to content

Commit 3a5279e

Browse files
committed
make corpus-blame subcommand fast
1 parent 235432f commit 3a5279e

3 files changed

Lines changed: 96 additions & 11 deletions

File tree

src/cli/cov_html.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::HashMap;
22
use crate::instrumentation::BBCoveragePass;
33
use crate::ir::debuginfo_helper::resolve_source_location;
4-
use std::collections::BTreeSet;
4+
use std::collections::{BTreeMap, BTreeSet};
55
use std::fmt::Write;
66
use std::path::PathBuf;
77
use std::sync::Arc;
@@ -149,6 +149,12 @@ pub(crate) struct ReportInfo {
149149
mod_spec: Arc<ModuleSpec>,
150150
pub(crate) files: Vec<FileInfo>,
151151
path_to_fileid: HashMap<String, FileId>,
152+
online_cache: Option<OnlineCache>,
153+
}
154+
155+
struct OnlineCache {
156+
covered_keys: crate::HashSet<Location>,
157+
offset_lookup: BTreeMap<u64, Box<[(FileId, u32)]>>,
152158
}
153159

154160
impl ReportInfo {
@@ -185,9 +191,83 @@ impl ReportInfo {
185191
mod_spec,
186192
files,
187193
path_to_fileid,
194+
online_cache: None,
188195
})
189196
}
190197

198+
pub(crate) fn process_line_coverage_online(&mut self, sess: &JitFuzzingSession) {
199+
tracy_full::zone!("process_line_coverage_online");
200+
let first = self.online_cache.is_none();
201+
let cache = self.online_cache.get_or_insert_with(|| {
202+
tracy_full::zone!("process_line_coverage_online: compute cache");
203+
let offset_lookup = self
204+
.mod_spec
205+
.functions
206+
.iter()
207+
.flat_map(|func| {
208+
func.operator_offset_rel.iter().map(|rel| {
209+
let addr = func.operators_wasm_bin_offset_base as u64 + *rel as u64;
210+
let mut locs = Vec::new();
211+
resolve_source_location(&self.mod_spec, addr, |x| {
212+
for x in x {
213+
if x.line() == 0 {
214+
continue;
215+
}
216+
if let Some(file) = x.file() {
217+
let file_id = self.path_to_fileid[&file.full_path()];
218+
locs.push((file_id, x.line() - 1))
219+
}
220+
}
221+
});
222+
223+
(addr, locs.into_boxed_slice())
224+
})
225+
})
226+
.collect();
227+
OnlineCache {
228+
covered_keys: crate::HashSet::default(),
229+
offset_lookup,
230+
}
231+
});
232+
if first {
233+
tracy_full::zone!("process_line_coverage_online: mark instrumented");
234+
for locs in cache.offset_lookup.values() {
235+
for (file_id, line) in locs {
236+
self.files[file_id.0 as usize]
237+
.line_coverage
238+
.set_instrumented(*line as usize);
239+
}
240+
}
241+
}
242+
let mut new_coverage = Vec::new();
243+
{
244+
tracy_full::zone!("process_line_coverage_online: scan coverage");
245+
for loc in sess
246+
.get_pass::<BBCoveragePass>()
247+
.coverage
248+
.iter_covered_keys()
249+
{
250+
if cache.covered_keys.insert(loc) {
251+
new_coverage.push(loc);
252+
}
253+
}
254+
}
255+
256+
{
257+
tracy_full::zone!("process_line_coverage_online: mark covered");
258+
for loc in new_coverage {
259+
let func = &self.mod_spec.functions[loc.function as usize];
260+
let base = func.operators_wasm_bin_offset_base as u64;
261+
let offset = func.operator_offset_rel[loc.index as usize] as u64;
262+
for (file_id, line) in &cache.offset_lookup[&(base + offset)] {
263+
self.files[file_id.0 as usize]
264+
.line_coverage
265+
.set_covered(*line as usize);
266+
}
267+
}
268+
}
269+
}
270+
191271
pub(crate) fn process_line_coverage(&mut self, sess: &JitFuzzingSession) {
192272
tracy_full::zone!("ReportInfo::process_line_coverage");
193273
let mod_spec = self.mod_spec.clone();

src/cli/mod.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,16 +257,17 @@ pub(crate) fn main() {
257257
if inputs.is_empty() {
258258
println!("No input specified. Exiting.")
259259
}
260+
261+
let size_limit = input_size_limit.unwrap_or(crate::TEST_CASE_SIZE_LIMIT);
262+
assert!(size_limit <= crate::TEST_CASE_SIZE_LIMIT);
263+
260264
for input in inputs {
261265
println!("Testcase: {input:?}");
262266
let testcase = std::fs::read(&input).expect("couldn't read input");
263267
let size = testcase.len();
264-
assert!(size <= crate::TEST_CASE_SIZE_LIMIT);
265-
if let Some(size_limit) = input_size_limit
266-
&& size > size_limit
267-
{
268+
if size > size_limit {
268269
println!(
269-
"Testcase: {input:?}: skipped due to size limit ({size} > {size_limit}"
270+
"Testcase: {input:?}: skipped due to size limit ({size} > {size_limit})"
270271
);
271272
continue;
272273
}
@@ -843,12 +844,13 @@ pub(crate) fn main() {
843844
};
844845
blame(&report_info, "<init>", &mut res);
845846

846-
for (path, input) in corpus_entries {
847-
print!("blaming {:?}: run \r", path);
847+
let total = corpus_entries.len();
848+
for (i, (path, input)) in corpus_entries.into_iter().enumerate() {
849+
print!("[{i}/{total}] blaming {path:?}: run \r");
848850
sess.run(&input, &mut stats).expect_ok();
849-
print!("blaming {:?}: process \r", path);
850-
report_info.process_line_coverage(&sess);
851-
print!("blaming {:?}: blame \r", path);
851+
print!("[{i}/{total}] blaming {path:?}: process \r");
852+
report_info.process_line_coverage_online(&sess);
853+
print!("[{i}/{total}] blaming {path:?}: blame \r");
852854
blame(&report_info, &path.to_string_lossy(), &mut res);
853855
}
854856

src/fuzzer/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub(crate) fn fuzz(mod_spec: Arc<ModuleSpec>, opts: orc::CliOpts) {
2929
.unwrap_or_else(|| std::thread::available_parallelism().unwrap().get());
3030

3131
let start = std::time::Instant::now();
32+
if let Some(corpus_dir) = opts.g.corpus_dir() {
33+
let _ = std::fs::create_dir(corpus_dir);
34+
}
3235

3336
let orc_handle = OrchestratorHandle::new(mod_spec.clone(), opts.clone());
3437

0 commit comments

Comments
 (0)