Skip to content

Commit

Permalink
Add support for reading file format version 7.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwoerister committed Sep 13, 2021
1 parent 68d0161 commit 14db1f7
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 13 deletions.
4 changes: 4 additions & 0 deletions analyzeme/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ measureme = { path = "../measureme" }
rustc-hash = "1.0.1"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"

# Depending on older versions of this crate allows us to keep supporting older
# file formats.
analyzeme_9_2_0 = { package = "analyzeme", git = "https://github.com/michaelwoerister/measureme", branch = "v9.2.0" }
15 changes: 15 additions & 0 deletions analyzeme/src/file_formats/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use decodeme::{event::Event, lightweight_event::LightweightEvent, Metadata};
use std::fmt::Debug;

pub mod v7;
pub mod v8;

pub use v8 as current;

/// The [EventDecoder] knows how to decode events for a specific file format.
pub trait EventDecoder: Debug + Send + Sync {
fn num_events(&self) -> usize;
fn metadata(&self) -> &Metadata;
fn decode_full_event<'a>(&'a self, event_index: usize) -> Event<'a>;
fn decode_lightweight_event<'a>(&'a self, event_index: usize) -> LightweightEvent;
}
81 changes: 81 additions & 0 deletions analyzeme/src/file_formats/v7.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! This module implements file loading for the v7 file format used until
//! crate version 9.2.0

use std::{error::Error, path::Path};

use analyzeme_9_2_0::ProfilingData;
use decodeme::{
event::Event,
event_payload::{EventPayload, Timestamp},
lightweight_event::LightweightEvent,
Metadata,
};

pub const FILE_FORMAT: u32 = analyzeme_9_2_0::CURRENT_FILE_FORMAT_VERSION;

#[derive(Debug)]
pub struct EventDecoder {
legacy_profiling_data: ProfilingData,
metadata: Metadata,
}

impl EventDecoder {
pub fn new(
entire_file_data: Vec<u8>,
_diagnostic_file_path: Option<&Path>,
) -> Result<EventDecoder, Box<dyn Error + Send + Sync>> {
let legacy_profiling_data = ProfilingData::from_paged_buffer(entire_file_data)?;

let metadata = Metadata {
start_time: legacy_profiling_data.metadata.start_time,
cmd: legacy_profiling_data.metadata.cmd.clone(),
process_id: legacy_profiling_data.metadata.process_id,
};

Ok(EventDecoder {
legacy_profiling_data,
metadata,
})
}
}

impl super::EventDecoder for EventDecoder {
fn num_events(&self) -> usize {
self.legacy_profiling_data.num_events()
}

fn metadata(&self) -> &Metadata {
&self.metadata
}

fn decode_full_event<'a>(&'a self, event_index: usize) -> Event<'a> {
let legacy_event = self.legacy_profiling_data.decode_full_event(event_index);
let timestamp = convert_timestamp(legacy_event.timestamp);

Event {
event_kind: legacy_event.event_kind,
label: legacy_event.label,
additional_data: legacy_event.additional_data,
thread_id: legacy_event.thread_id,
payload: EventPayload::Timestamp(timestamp),
}
}

fn decode_lightweight_event<'a>(&'a self, event_index: usize) -> LightweightEvent {
let legacy_event = self
.legacy_profiling_data
.decode_lightweight_event(event_index);
LightweightEvent {
event_index,
thread_id: legacy_event.thread_id,
payload: EventPayload::Timestamp(convert_timestamp(legacy_event.timestamp)),
}
}
}

fn convert_timestamp(legacy_timestamp: analyzeme_9_2_0::Timestamp) -> Timestamp {
match legacy_timestamp {
analyzeme_9_2_0::Timestamp::Interval { start, end } => Timestamp::Interval { start, end },
analyzeme_9_2_0::Timestamp::Instant(t) => Timestamp::Instant(t),
}
}
26 changes: 26 additions & 0 deletions analyzeme/src/file_formats/v8.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! This module implements file loading for the v8 file format used until
//! crate version 10.0.0

use crate::{Event, LightweightEvent};
pub use decodeme::EventDecoder;
use decodeme::Metadata;

pub const FILE_FORMAT: u32 = measureme::file_header::CURRENT_FILE_FORMAT_VERSION;

impl super::EventDecoder for EventDecoder {
fn num_events(&self) -> usize {
self.num_events()
}

fn metadata(&self) -> &Metadata {
self.metadata()
}

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

fn decode_lightweight_event<'a>(&'a self, event_index: usize) -> LightweightEvent {
self.decode_lightweight_event(event_index)
}
}
1 change: 1 addition & 0 deletions analyzeme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//! To retrieve an `Iterator` of all of the events in the file,
//! call the [`ProfilingData::iter()`] method.

mod file_formats;
mod profiling_data;
mod stack_collapse;
pub mod testing_common;
Expand Down
58 changes: 45 additions & 13 deletions analyzeme/src/profiling_data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{Event, LightweightEvent};
use decodeme::{EventDecoder, Metadata};
// use crate::StringTable;
use measureme::file_header::{write_file_header, FILE_EXTENSION, FILE_MAGIC_EVENT_STREAM};
use crate::file_formats::EventDecoder;
use crate::{file_formats, Event, LightweightEvent};
use decodeme::{read_file_header, Metadata};
use measureme::file_header::{
write_file_header, FILE_EXTENSION, FILE_MAGIC_EVENT_STREAM, FILE_MAGIC_TOP_LEVEL,
};
use measureme::{
EventId, PageTag, RawEvent, SerializationSink, SerializationSinkBuilder, StringTableBuilder,
};
Expand All @@ -12,7 +14,7 @@ use std::{error::Error, path::PathBuf};

#[derive(Debug)]
pub struct ProfilingData {
event_decoder: EventDecoder,
event_decoder: Box<dyn EventDecoder>,
}

impl ProfilingData {
Expand Down Expand Up @@ -48,7 +50,35 @@ impl ProfilingData {
data: Vec<u8>,
diagnostic_file_path: Option<&Path>,
) -> Result<ProfilingData, Box<dyn Error + Send + Sync>> {
let event_decoder = EventDecoder::new(data, diagnostic_file_path)?;
// let event_decoder = EventDecoder::new(data, diagnostic_file_path)?;
// Ok(ProfilingData { event_decoder })

let file_format_version = read_file_header(
&data,
FILE_MAGIC_TOP_LEVEL,
diagnostic_file_path,
"top-level",
)?;

let event_decoder: Box<dyn file_formats::EventDecoder> = match file_format_version {
file_formats::v7::FILE_FORMAT => Box::new(file_formats::v7::EventDecoder::new(
data,
diagnostic_file_path,
)?),
file_formats::v8::FILE_FORMAT => Box::new(file_formats::v8::EventDecoder::new(
data,
diagnostic_file_path,
)?),
unsupported_version => {
let msg = format!(
"File version {} is not support by this version of measureme.",
unsupported_version
);

return Err(From::from(msg));
}
};

Ok(ProfilingData { event_decoder })
}

Expand Down Expand Up @@ -258,13 +288,15 @@ impl ProfilingDataBuilder {
.into_bytes();

ProfilingData {
event_decoder: EventDecoder::from_separate_buffers(
string_data,
index_data,
event_data,
None,
)
.unwrap(),
event_decoder: Box::new(
file_formats::current::EventDecoder::from_separate_buffers(
string_data,
index_data,
event_data,
None,
)
.unwrap(),
),
}
}

Expand Down
44 changes: 44 additions & 0 deletions decodeme/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,50 @@ pub struct Metadata {
pub cmd: String,
}

#[must_use]
pub fn read_file_header(
bytes: &[u8],
expected_magic: &[u8; 4],
diagnostic_file_path: Option<&Path>,
stream_tag: &str,
) -> Result<u32, Box<dyn Error + Send + Sync>> {
// The implementation here relies on FILE_HEADER_SIZE to have the value 8.
// Let's make sure this assumption cannot be violated without being noticed.
assert_eq!(FILE_HEADER_SIZE, 8);

let diagnostic_file_path = diagnostic_file_path.unwrap_or(Path::new("<in-memory>"));

if bytes.len() < FILE_HEADER_SIZE {
let msg = format!(
"Error reading {} stream in file `{}`: Expected file to contain at least `{:?}` bytes but found `{:?}` bytes",
stream_tag,
diagnostic_file_path.display(),
FILE_HEADER_SIZE,
bytes.len()
);

return Err(From::from(msg));
}

let actual_magic = &bytes[0..4];

if actual_magic != expected_magic {
let msg = format!(
"Error reading {} stream in file `{}`: Expected file magic `{:?}` but found `{:?}`",
stream_tag,
diagnostic_file_path.display(),
expected_magic,
actual_magic
);

return Err(From::from(msg));
}

let file_format_version = u32::from_le_bytes(bytes[4..8].try_into().unwrap());

Ok(file_format_version)
}

const RAW_EVENT_SIZE: usize = std::mem::size_of::<RawEvent>();

#[derive(Debug)]
Expand Down

0 comments on commit 14db1f7

Please sign in to comment.