Skip to content

Commit 8193f4d

Browse files
committed
Auto merge of #216 - smklein:v9, r=michaelwoerister
v9 format: Increase StringId and Addr size to u64, fixing ICEs during self-profiling This PR introduces a new "v9" format for profdata files, which uses u64s for addressing into files instead of u32s. This avoids ICEs which were possible with large traces, mentioned in the attached issues. Fixes: #214, rust-lang/rust#99282 --- This is my first contribution to this repo, so I've made sure that tests are passing, but I'm interested in ensuring the following work: - [x] I originally encountered this issue from #214 -- I'd love to get advice on "how to rebuild the self-profiling feature using this code" to ensure this change works end-to-end too. EDIT: I did this, it works! No longer seeing ICEs on large profile traces. - [x] I see that there are compatibility tests with v7 and v8 formats (e.g. `can_read_v8_profdata_files`) -- I'd be interested in creating one for v9 too, but I'm not actually that familiar with "how to generate a new `.mm_profdata` file" without the whole toolchain built to help me. I'm interested in fixing this before merging, but would appreciate pointers! EDIT: This is done -- I added a v9 format test after tracing a minimal rust binary created via `cargo new`.
2 parents 6e3ab7d + 4c716fc commit 8193f4d

File tree

24 files changed

+270
-71
lines changed

24 files changed

+270
-71
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [11.0.0] - 2023-12-14
4+
5+
### Changed
6+
- `measureme`: Update StringId and Addr sizes from u32 to u64 ([GH-216])
7+
- `analyzeme`: v9 file format, which uses larger events ([GH-216])
8+
39
## [10.1.2] - 2023-12-14
410

511
### Changed
@@ -232,3 +238,4 @@
232238
[GH-208]: https://github.com/rust-lang/measureme/pull/208
233239
[GH-209]: https://github.com/rust-lang/measureme/pull/209
234240
[GH-211]: https://github.com/rust-lang/measureme/pull/211
241+
[GH-216]: https://github.com/rust-lang/measureme/pull/216

analyzeme/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "analyzeme"
3-
version = "10.1.2"
3+
version = "11.0.0"
44
authors = ["Wesley Wiser <[email protected]>", "Michael Woerister <michaelwoerister@posteo>"]
55
edition = "2018"
66
license = "MIT OR Apache-2.0"
@@ -14,7 +14,13 @@ serde = { version = "1.0", features = ["derive"] }
1414

1515
# Depending on older versions of this crate allows us to keep supporting older
1616
# file formats.
17+
18+
# File format: v7
1719
analyzeme_9_2_0 = { package = "analyzeme", git = "https://github.com/rust-lang/measureme", tag = "9.2.0" }
1820

21+
# File format: v8
22+
decodeme_10_1_2 = { package = "decodeme", git = "https://github.com/rust-lang/measureme", tag = "10.1.2" }
23+
measureme_10_1_2 = { package = "measureme", git = "https://github.com/rust-lang/measureme", tag = "10.1.2" }
24+
1925
[dev-dependencies]
2026
flate2 = "1.0"

analyzeme/src/file_formats/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ use std::fmt::Debug;
33

44
pub mod v7;
55
pub mod v8;
6+
pub mod v9;
67

7-
pub use v8 as current;
8+
pub use v9 as current;
89

910
/// The [EventDecoder] knows how to decode events for a specific file format.
1011
pub trait EventDecoder: Debug + Send + Sync {
1112
fn num_events(&self) -> usize;
12-
fn metadata(&self) -> &Metadata;
13+
fn metadata(&self) -> Metadata;
1314
fn decode_full_event<'a>(&'a self, event_index: usize) -> Event<'a>;
1415
fn decode_lightweight_event<'a>(&'a self, event_index: usize) -> LightweightEvent;
1516
}

analyzeme/src/file_formats/v7.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ impl super::EventDecoder for EventDecoder {
4141
self.legacy_profiling_data.num_events()
4242
}
4343

44-
fn metadata(&self) -> &Metadata {
45-
&self.metadata
44+
fn metadata(&self) -> Metadata {
45+
self.metadata.clone()
4646
}
4747

4848
fn decode_full_event(&self, event_index: usize) -> Event<'_> {

analyzeme/src/file_formats/v8.rs

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,84 @@
11
//! This module implements file loading for the v8 file format used until
2-
//! crate version 10.0.0
2+
//! crate version 10.0.0.
3+
//!
4+
//! The difference from v8 to v9 copes with the expansion of StringId and Addr
5+
//! types from u32 to u64. Most of the EventDecoder interface is actually
6+
//! unchanged, but the construction of "EventDecoder::new", which parses
7+
//! the stream of events, varies based on these sizes.
8+
//!
9+
//! This file provides conversions to current interfaces, relying on an
10+
//! old version of this crate to parse the u32-based v8 version.
311
4-
use crate::{Event, LightweightEvent};
5-
pub use decodeme::EventDecoder;
12+
use crate::{Event, EventPayload, LightweightEvent, Timestamp};
613
use decodeme::Metadata;
14+
use decodeme_10_1_2::event_payload::EventPayload as OldEventPayload;
15+
use decodeme_10_1_2::event_payload::Timestamp as OldTimestamp;
16+
use decodeme_10_1_2::lightweight_event::LightweightEvent as OldLightweightEvent;
17+
pub use decodeme_10_1_2::EventDecoder;
18+
use decodeme_10_1_2::Metadata as OldMetadata;
719

8-
pub const FILE_FORMAT: u32 = decodeme::CURRENT_FILE_FORMAT_VERSION;
20+
pub const FILE_FORMAT: u32 = measureme_10_1_2::file_header::CURRENT_FILE_FORMAT_VERSION;
21+
22+
// NOTE: These are functionally a hand-rolled "impl From<Old> -> New", but
23+
// given orphan rules, it seems undesirable to spread version-specific
24+
// converters around the codebase.
25+
//
26+
// In lieu of an idiomatic type conversion, we at least centralize compatibility
27+
// with the old "v8" version to this file.
28+
29+
fn v8_metadata_as_current(old: &OldMetadata) -> Metadata {
30+
Metadata {
31+
start_time: old.start_time,
32+
process_id: old.process_id,
33+
cmd: old.cmd.clone(),
34+
}
35+
}
36+
37+
fn v8_timestamp_as_current(old: OldTimestamp) -> Timestamp {
38+
match old {
39+
OldTimestamp::Interval { start, end } => Timestamp::Interval { start, end },
40+
OldTimestamp::Instant(t) => Timestamp::Instant(t),
41+
}
42+
}
43+
44+
fn v8_event_payload_as_current(old: OldEventPayload) -> EventPayload {
45+
match old {
46+
OldEventPayload::Timestamp(t) => EventPayload::Timestamp(v8_timestamp_as_current(t)),
47+
OldEventPayload::Integer(t) => EventPayload::Integer(t),
48+
}
49+
}
50+
51+
fn v8_lightweightevent_as_current(old: OldLightweightEvent) -> LightweightEvent {
52+
LightweightEvent {
53+
event_index: old.event_index,
54+
thread_id: old.thread_id,
55+
payload: v8_event_payload_as_current(old.payload),
56+
}
57+
}
958

1059
impl super::EventDecoder for EventDecoder {
1160
fn num_events(&self) -> usize {
1261
self.num_events()
1362
}
1463

15-
fn metadata(&self) -> &Metadata {
16-
self.metadata()
64+
fn metadata(&self) -> Metadata {
65+
let old = self.metadata();
66+
v8_metadata_as_current(&old)
1767
}
1868

1969
fn decode_full_event(&self, event_index: usize) -> Event<'_> {
20-
self.decode_full_event(event_index)
70+
let old = self.decode_full_event(event_index);
71+
72+
Event {
73+
event_kind: old.event_kind,
74+
label: old.label,
75+
additional_data: old.additional_data,
76+
payload: v8_event_payload_as_current(old.payload),
77+
thread_id: old.thread_id,
78+
}
2179
}
2280

2381
fn decode_lightweight_event(&self, event_index: usize) -> LightweightEvent {
24-
self.decode_lightweight_event(event_index)
82+
v8_lightweightevent_as_current(self.decode_lightweight_event(event_index))
2583
}
2684
}

analyzeme/src/file_formats/v9.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! This module implements file loading for the v9 file format
2+
3+
use crate::{Event, LightweightEvent};
4+
pub use decodeme::EventDecoder;
5+
use decodeme::Metadata;
6+
7+
pub const FILE_FORMAT: u32 = decodeme::CURRENT_FILE_FORMAT_VERSION;
8+
9+
impl super::EventDecoder for EventDecoder {
10+
fn num_events(&self) -> usize {
11+
self.num_events()
12+
}
13+
14+
fn metadata(&self) -> Metadata {
15+
self.metadata()
16+
}
17+
18+
fn decode_full_event(&self, event_index: usize) -> Event<'_> {
19+
self.decode_full_event(event_index)
20+
}
21+
22+
fn decode_lightweight_event(&self, event_index: usize) -> LightweightEvent {
23+
self.decode_lightweight_event(event_index)
24+
}
25+
}

analyzeme/src/profiling_data.rs

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use measureme::file_header::{
77
use measureme::{
88
EventId, PageTag, RawEvent, SerializationSink, SerializationSinkBuilder, StringTableBuilder,
99
};
10+
use std::cell::OnceCell;
1011
use std::fs;
1112
use std::path::Path;
1213
use std::sync::Arc;
@@ -15,6 +16,7 @@ use std::{error::Error, path::PathBuf};
1516
#[derive(Debug)]
1617
pub struct ProfilingData {
1718
event_decoder: Box<dyn EventDecoder>,
19+
metadata: OnceCell<Metadata>,
1820
}
1921

2022
impl ProfilingData {
@@ -50,9 +52,6 @@ impl ProfilingData {
5052
data: Vec<u8>,
5153
diagnostic_file_path: Option<&Path>,
5254
) -> Result<ProfilingData, Box<dyn Error + Send + Sync>> {
53-
// let event_decoder = EventDecoder::new(data, diagnostic_file_path)?;
54-
// Ok(ProfilingData { event_decoder })
55-
5655
let file_format_version = read_file_header(
5756
&data,
5857
FILE_MAGIC_TOP_LEVEL,
@@ -66,6 +65,10 @@ impl ProfilingData {
6665
data,
6766
diagnostic_file_path,
6867
)?),
68+
file_formats::v9::FILE_FORMAT => Box::new(file_formats::v9::EventDecoder::new(
69+
data,
70+
diagnostic_file_path,
71+
)?),
6972
unsupported_version => {
7073
let msg = if unsupported_version > file_formats::current::FILE_FORMAT {
7174
format!(
@@ -83,11 +86,15 @@ impl ProfilingData {
8386
}
8487
};
8588

86-
Ok(ProfilingData { event_decoder })
89+
Ok(ProfilingData {
90+
event_decoder,
91+
metadata: OnceCell::new(),
92+
})
8793
}
8894

8995
pub fn metadata(&self) -> &Metadata {
90-
self.event_decoder.metadata()
96+
// Cache the metadata during the first access
97+
self.metadata.get_or_init(|| self.event_decoder.metadata())
9198
}
9299

93100
pub fn iter<'a>(&'a self) -> ProfilerEventIterator<'a> {
@@ -301,6 +308,7 @@ impl ProfilingDataBuilder {
301308
)
302309
.unwrap(),
303310
),
311+
metadata: OnceCell::new(),
304312
}
305313
}
306314

@@ -641,6 +649,86 @@ mod tests {
641649
);
642650
}
643651

652+
// To generate this revision, a v9 revision of the rust toolchain was
653+
// created, and "rustup toolchain link" was used to name it "bespoke".
654+
// Then, the following commands were executed:
655+
//
656+
// # Make a small test binary and profile it.
657+
// cargo new --bin testbinary
658+
// cargo +bespoke rustc --bin testbinary -- -Zself-profile
659+
//
660+
// # Gzip the output profdata.
661+
// gzip testbinary-...mm_profdata
662+
// mv testbinary-...mm_profdata.gz v9.mm_profdata.gz
663+
#[test]
664+
fn can_read_v9_profdata_files() {
665+
let (data, file_format_version) =
666+
read_data_and_version("tests/profdata/v9.mm_profdata.gz");
667+
assert_eq!(file_format_version, file_formats::v9::FILE_FORMAT);
668+
let profiling_data = ProfilingData::from_paged_buffer(data, None)
669+
.expect("Creating the profiling data failed");
670+
let grouped_events = group_events(&profiling_data);
671+
let event_kinds = grouped_events
672+
.keys()
673+
.map(|k| k.as_str())
674+
.collect::<HashSet<_>>();
675+
let expect_event_kinds = vec![
676+
"GenericActivity",
677+
"IncrementalResultHashing",
678+
"Query",
679+
"ArtifactSize",
680+
]
681+
.into_iter()
682+
.collect::<HashSet<_>>();
683+
assert_eq!(event_kinds, expect_event_kinds);
684+
685+
let generic_activity_len = 5125;
686+
let incremental_hashing_len = 1844;
687+
let query_len = 1877;
688+
let artifact_size_len = 24;
689+
assert_eq!(
690+
grouped_events["GenericActivity"].len(),
691+
generic_activity_len
692+
);
693+
assert_eq!(
694+
grouped_events["IncrementalResultHashing"].len(),
695+
incremental_hashing_len
696+
);
697+
assert_eq!(grouped_events["Query"].len(), query_len);
698+
assert_eq!(grouped_events["ArtifactSize"].len(), artifact_size_len);
699+
700+
assert_eq!(
701+
grouped_events["GenericActivity"][generic_activity_len / 2].label,
702+
"metadata_decode_entry_item_attrs"
703+
);
704+
assert_eq!(
705+
grouped_events["GenericActivity"][generic_activity_len / 2].duration(),
706+
Some(Duration::from_nanos(376))
707+
);
708+
709+
assert_eq!(
710+
grouped_events["IncrementalResultHashing"][incremental_hashing_len - 1].label,
711+
"crate_hash"
712+
);
713+
assert_eq!(
714+
grouped_events["IncrementalResultHashing"][incremental_hashing_len - 1].duration(),
715+
Some(Duration::from_nanos(461))
716+
);
717+
718+
assert_eq!(grouped_events["Query"][0].label, "registered_tools");
719+
assert_eq!(
720+
grouped_events["Query"][0].duration(),
721+
Some(Duration::from_nanos(45077))
722+
);
723+
724+
assert_eq!(
725+
grouped_events["ArtifactSize"][0].label,
726+
"codegen_unit_size_estimate"
727+
);
728+
assert_eq!(grouped_events["ArtifactSize"][0].duration(), None);
729+
assert_eq!(grouped_events["ArtifactSize"][0].integer(), Some(3));
730+
}
731+
644732
fn read_data_and_version(file_path: &str) -> (Vec<u8>, u32) {
645733
let data = std::fs::read(file_path).expect("Test data not found");
646734
let mut gz = flate2::read::GzDecoder::new(&data[..]);
80.5 KB
Binary file not shown.

crox/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "crox"
3-
version = "10.1.2"
3+
version = "11.0.0"
44
authors = ["Wesley Wiser <[email protected]>"]
55
edition = "2018"
66

decodeme/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "decodeme"
3-
version = "10.1.2"
3+
version = "11.0.0"
44
edition = "2018"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

decodeme/src/lib.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ where
3838
.expect("a time that can be represented as SystemTime"))
3939
}
4040

41-
#[derive(Debug, Deserialize)]
41+
#[derive(Clone, Debug, Deserialize)]
4242
pub struct Metadata {
4343
#[serde(deserialize_with = "system_time_from_nanos")]
4444
pub start_time: SystemTime,
@@ -113,9 +113,15 @@ impl EventDecoder {
113113

114114
let mut split_data = measureme::split_streams(&entire_file_data[FILE_HEADER_SIZE..]);
115115

116-
let string_data = split_data.remove(&PageTag::StringData).expect("Invalid file: No string data found");
117-
let index_data = split_data.remove(&PageTag::StringIndex).expect("Invalid file: No string index data found");
118-
let event_data = split_data.remove(&PageTag::Events).expect("Invalid file: No event data found");
116+
let string_data = split_data
117+
.remove(&PageTag::StringData)
118+
.expect("Invalid file: No string data found");
119+
let index_data = split_data
120+
.remove(&PageTag::StringIndex)
121+
.expect("Invalid file: No string index data found");
122+
let event_data = split_data
123+
.remove(&PageTag::Events)
124+
.expect("Invalid file: No event data found");
119125

120126
Self::from_separate_buffers(string_data, index_data, event_data, diagnostic_file_path)
121127
}
@@ -151,8 +157,8 @@ impl EventDecoder {
151157
event_byte_count / RAW_EVENT_SIZE
152158
}
153159

154-
pub fn metadata(&self) -> &Metadata {
155-
&self.metadata
160+
pub fn metadata(&self) -> Metadata {
161+
self.metadata.clone()
156162
}
157163

158164
pub fn decode_full_event<'a>(&'a self, event_index: usize) -> Event<'a> {

0 commit comments

Comments
 (0)