Skip to content

Commit 23bdede

Browse files
committed
Implement missing chunks parser features
This should implement everything except for the `complexity` parser.
1 parent 596c305 commit 23bdede

6 files changed

Lines changed: 161 additions & 182 deletions

File tree

core/benches/pyreport.rs

Lines changed: 13 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use std::collections::HashMap;
22

33
use codecov_rs::{
4-
parsers::pyreport::{chunks, chunks_serde, report_json},
5-
test_utils::test_report::{TestReport, TestReportBuilder},
4+
parsers::pyreport::{chunks_serde, report_json},
5+
test_utils::test_report::TestReportBuilder,
66
};
77
use criterion::{criterion_group, criterion_main, Criterion};
88
use test_utils::fixtures::{read_fixture, FixtureFormat::Pyreport, FixtureSize::Large};
9-
use winnow::Parser as _;
109

1110
criterion_group!(
1211
benches,
@@ -55,24 +54,25 @@ fn parse_report_json(input: &[u8]) -> report_json::ParsedReportJson {
5554
}
5655

5756
fn simple_chunks(c: &mut Criterion) {
58-
let chunks = &[
57+
let chunks: &[&[u8]] = &[
5958
// Header and one chunk with an empty line
60-
"{}\n<<<<< end_of_header >>>>>\n{}\n",
59+
b"{}\n<<<<< end_of_header >>>>>\n{}\n",
6160
// No header, one chunk with a populated line and an empty line
62-
"{}\n[1, null, [[0, 1]]]\n",
61+
b"{}\n[1, null, [[0, 1]]]\n",
6362
// No header, two chunks, the second having just one empty line
64-
"{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n",
63+
b"{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n",
6564
// Header, two chunks, the second having multiple data lines and an empty line
66-
"{}\n<<<<< end_of_header >>>>>\n{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n[1, null, [[0, 1]]]\n[1, null, [[0, 1]]]\n",
65+
b"{}\n<<<<< end_of_header >>>>>\n{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n[1, null, [[0, 1]]]\n[1, null, [[0, 1]]]\n",
6766
];
6867

6968
let files = HashMap::from([(0, 0), (1, 1), (2, 2)]);
7069
let sessions = HashMap::from([(0, 0), (1, 1), (2, 2)]);
7170

71+
let report_json = report_json::ParsedReportJson { files, sessions };
7272
c.bench_function("simple_chunks", |b| {
7373
b.iter(|| {
7474
for input in chunks {
75-
parse_chunks_file(input, files.clone(), sessions.clone())
75+
parse_chunks_file_serde(input, report_json.clone());
7676
}
7777
})
7878
});
@@ -87,7 +87,6 @@ fn complex_chunks(c: &mut Criterion) {
8787
"worker-c71ddfd4cb1753c7a540e5248c2beaa079fc3341-chunks.txt",
8888
)
8989
.unwrap();
90-
let chunks = std::str::from_utf8(&chunks).unwrap();
9190

9291
// parsing the chunks depends on having loaded the `report_json`
9392
let report = read_fixture(
@@ -96,79 +95,14 @@ fn complex_chunks(c: &mut Criterion) {
9695
"worker-c71ddfd4cb1753c7a540e5248c2beaa079fc3341-report_json.json",
9796
)
9897
.unwrap();
99-
let report_json::ParsedReportJson { files, sessions } = parse_report_json(&report);
98+
let report_json = parse_report_json(&report);
10099

101100
c.bench_function("complex_chunks", |b| {
102-
b.iter(|| parse_chunks_file(chunks, files.clone(), sessions.clone()))
101+
b.iter(|| parse_chunks_file_serde(&chunks, report_json.clone()))
103102
});
104103
}
105104

106-
fn parse_chunks_file(input: &str, files: HashMap<usize, i64>, sessions: HashMap<usize, i64>) {
105+
fn parse_chunks_file_serde(input: &[u8], report_json: report_json::ParsedReportJson) {
107106
let report_builder = TestReportBuilder::default();
108-
109-
let chunks_ctx = chunks::ParseCtx::new(report_builder, files, sessions);
110-
let mut chunks_stream = chunks::ReportOutputStream::<&str, TestReport, TestReportBuilder> {
111-
input,
112-
state: chunks_ctx,
113-
};
114-
115-
chunks::parse_chunks_file
116-
.parse_next(&mut chunks_stream)
117-
.unwrap();
118-
}
119-
120-
#[divan::bench]
121-
fn simple_chunks_serde() {
122-
let chunks: &[&[u8]] = &[
123-
// Header and one chunk with an empty line
124-
b"{}\n<<<<< end_of_header >>>>>\n{}\n",
125-
// No header, one chunk with a populated line and an empty line
126-
b"{}\n[1, null, [[0, 1]]]\n",
127-
// No header, two chunks, the second having just one empty line
128-
b"{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n",
129-
// Header, two chunks, the second having multiple data lines and an empty line
130-
b"{}\n<<<<< end_of_header >>>>>\n{}\n[1, null, [[0, 1]]]\n\n<<<<< end_of_chunk >>>>>\n{}\n[1, null, [[0, 1]]]\n[1, null, [[0, 1]]]\n",
131-
];
132-
133-
let report_json = report_json::ParsedReportJson {
134-
files: Default::default(),
135-
sessions: Default::default(),
136-
};
137-
138-
for input in chunks {
139-
parse_chunks_file_serde(input, &report_json);
140-
}
141-
}
142-
143-
// this is currently <300 ms on my machine
144-
#[divan::bench(sample_count = 10)]
145-
fn complex_chunks_serde(bencher: Bencher) {
146-
// this is a ~96M `chunks` file
147-
let chunks =
148-
load_fixture("pyreport/large/worker-c71ddfd4cb1753c7a540e5248c2beaa079fc3341-chunks.txt");
149-
150-
// parsing the chunks depends on having loaded the `report_json`
151-
let report = load_fixture(
152-
"pyreport/large/worker-c71ddfd4cb1753c7a540e5248c2beaa079fc3341-report_json.json",
153-
);
154-
let report_json = parse_report_json(&report);
155-
156-
bencher.bench(|| parse_chunks_file_serde(&chunks, &report_json));
157-
}
158-
159-
fn parse_chunks_file_serde(input: &[u8], report_json: &report_json::ParsedReportJson) {
160-
let mut report_builder = TestReportBuilder::default();
161-
chunks_serde::parse_chunks_file(input, report_json, &mut report_builder).unwrap();
162-
}
163-
164-
#[track_caller]
165-
fn load_fixture(path: &str) -> Vec<u8> {
166-
let path = format!("./fixtures/{path}");
167-
let contents = std::fs::read(path).unwrap();
168-
169-
if contents.starts_with(b"version https://git-lfs.github.com/spec/v1") {
170-
panic!("Fixture has not been pulled from Git LFS");
171-
}
172-
173-
contents
107+
chunks_serde::parse_chunks_file(input, report_json, report_builder).unwrap();
174108
}

0 commit comments

Comments
 (0)