Re: [RFC 3/6] scripts/simpletrace-rust: Add helpers to parse trace file
> > +fn read_type(mut fobj: ) -> Result > > +{ > > +let mut tbuf = [0u8; 8]; > > +if let Err(e) = fobj.read_exact( tbuf) { > > +if e.kind() == ErrorKind::UnexpectedEof { > > +return Ok(RecordType::Empty); > > +} else { > > +return Err(Error::ReadFile(e)); > > +} > > +} > > + > > +/* > > + * Safe because the layout of the trace record requires us to parse > > + * the type first, and then there is a check on the validity of the > > + * record type. > > + */ > > +let raw_t = > > +unsafe { std::mem::transmute::<[u8; 8], RecordRawType>(tbuf) }; > > A safe alternative: > https://doc.rust-lang.org/std/primitive.u64.html#method.from_ne_bytes? Thanks! Will use it. > > +match raw_t.rtype { > > +RECORD_TYPE_MAPPING => Ok(RecordType::Mapping), > > +RECORD_TYPE_EVENT => Ok(RecordType::Event), > > +_ => Err(Error::UnknownRecType(raw_t.rtype)), > > +} > > +} > > +} [snip] > > +{ > > +fn read_header(mut fobj: ) -> Result > > +{ > > +let mut raw_hdr = [0u8; 24]; > > +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; > > + > > +/* > > + * Safe because the size of log header (struct LogHeader) > > + * is 24 bytes, which is ensured by simple trace backend. > > + */ > > +let hdr = > > +unsafe { std::mem::transmute::<[u8; 24], LogHeader>(raw_hdr) }; > > Or u64::from_ne_bytes() for each field. Will do. > > +Ok(hdr) > > +} > > +} [snip] > > +impl ReadHeader for RecordHeader > > +{ > > +fn read_header(mut fobj: ) -> Result > > +{ > > +let mut raw_hdr = [0u8; 24]; > > +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; > > + > > +/* > > + * Safe because the size of record header (struct RecordHeader) > > + * is 24 bytes, which is ensured by simple trace backend. > > + */ > > +let hdr: RecordHeader = > > +unsafe { std::mem::transmute::<[u8; 24], > > RecordHeader>(raw_hdr) }; > > Or u64::from_ne_bytes() and u32::from_ne_bytes() for all fields. Will do. Thanks, Zhao
Re: [RFC 3/6] scripts/simpletrace-rust: Add helpers to parse trace file
On Mon, May 27, 2024 at 04:14:18PM +0800, Zhao Liu wrote: > Refer to scripts/simpletrace.py, add the helpers to read the trace file > and parse the record type field, record header and log header. > > Suggested-by: Paolo Bonzini > Signed-off-by: Zhao Liu > --- > scripts/simpletrace-rust/src/main.rs | 151 +++ > 1 file changed, 151 insertions(+) > > diff --git a/scripts/simpletrace-rust/src/main.rs > b/scripts/simpletrace-rust/src/main.rs > index 2d2926b7658d..b3b8baee7c66 100644 > --- a/scripts/simpletrace-rust/src/main.rs > +++ b/scripts/simpletrace-rust/src/main.rs > @@ -14,21 +14,172 @@ > mod trace; > > use std::env; > +use std::fs::File; > +use std::io::Error as IOError; > +use std::io::ErrorKind; > +use std::io::Read; > > use clap::Arg; > use clap::Command; > use thiserror::Error; > use trace::Event; > > +const RECORD_TYPE_MAPPING: u64 = 0; > +const RECORD_TYPE_EVENT: u64 = 1; > + > #[derive(Error, Debug)] > pub enum Error > { > #[error("usage: {0} [--no-header] ")] > CliOptionUnmatch(String), > +#[error("Failed to read file: {0}")] > +ReadFile(IOError), > +#[error("Unknown record type ({0})")] > +UnknownRecType(u64), > } > > pub type Result = std::result::Result; > > +enum RecordType > +{ > +Empty, > +Mapping, > +Event, > +} > + > +#[repr(C)] > +#[derive(Clone, Copy, Default)] > +struct RecordRawType > +{ > +rtype: u64, > +} > + > +impl RecordType > +{ > +fn read_type(mut fobj: ) -> Result > +{ > +let mut tbuf = [0u8; 8]; > +if let Err(e) = fobj.read_exact( tbuf) { > +if e.kind() == ErrorKind::UnexpectedEof { > +return Ok(RecordType::Empty); > +} else { > +return Err(Error::ReadFile(e)); > +} > +} > + > +/* > + * Safe because the layout of the trace record requires us to parse > + * the type first, and then there is a check on the validity of the > + * record type. > + */ > +let raw_t = > +unsafe { std::mem::transmute::<[u8; 8], RecordRawType>(tbuf) }; A safe alternative: https://doc.rust-lang.org/std/primitive.u64.html#method.from_ne_bytes? > +match raw_t.rtype { > +RECORD_TYPE_MAPPING => Ok(RecordType::Mapping), > +RECORD_TYPE_EVENT => Ok(RecordType::Event), > +_ => Err(Error::UnknownRecType(raw_t.rtype)), > +} > +} > +} > + > +trait ReadHeader > +{ > +fn read_header(fobj: ) -> Result > +where > +Self: Sized; > +} > + > +#[repr(C)] > +#[derive(Clone, Copy)] > +struct LogHeader > +{ > +event_id: u64, > +magic: u64, > +version: u64, > +} > + > +impl ReadHeader for LogHeader > +{ > +fn read_header(mut fobj: ) -> Result > +{ > +let mut raw_hdr = [0u8; 24]; > +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; > + > +/* > + * Safe because the size of log header (struct LogHeader) > + * is 24 bytes, which is ensured by simple trace backend. > + */ > +let hdr = > +unsafe { std::mem::transmute::<[u8; 24], LogHeader>(raw_hdr) }; Or u64::from_ne_bytes() for each field. > +Ok(hdr) > +} > +} > + > +#[derive(Default)] > +struct RecordInfo > +{ > +event_id: u64, > +timestamp_ns: u64, > +record_pid: u32, > +args_payload: Vec, > +} > + > +impl RecordInfo > +{ > +fn new() -> Self > +{ > +Default::default() > +} > +} > + > +#[repr(C)] > +#[derive(Clone, Copy)] > +struct RecordHeader > +{ > +event_id: u64, > +timestamp_ns: u64, > +record_length: u32, > +record_pid: u32, > +} > + > +impl RecordHeader > +{ > +fn extract_record(, mut fobj: ) -> Result > +{ > +let mut info = RecordInfo::new(); > + > +info.event_id = self.event_id; > +info.timestamp_ns = self.timestamp_ns; > +info.record_pid = self.record_pid; > +info.args_payload = vec![ > +0u8; > +self.record_length as usize > +- std::mem::size_of::() > +]; > +fobj.read_exact( info.args_payload) > +.map_err(Error::ReadFile)?; > + > +Ok(info) > +} > +} > + > +impl ReadHeader for RecordHeader > +{ > +fn read_header(mut fobj: ) -> Result > +{ > +let mut raw_hdr = [0u8; 24]; > +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; > + > +/* > + * Safe because the size of record header (struct RecordHeader) > + * is 24 bytes, which is ensured by simple trace backend. > + */ > +let hdr: RecordHeader = > +unsafe { std::mem::transmute::<[u8; 24], RecordHeader>(raw_hdr) > }; Or u64::from_ne_bytes() and u32::from_ne_bytes() for all fields. > +Ok(hdr) > +} > +} > + > pub struct EventArgPayload {} > > trait Analyzer > -- > 2.34.1 > signature.asc Description: PGP signature
[RFC 3/6] scripts/simpletrace-rust: Add helpers to parse trace file
Refer to scripts/simpletrace.py, add the helpers to read the trace file and parse the record type field, record header and log header. Suggested-by: Paolo Bonzini Signed-off-by: Zhao Liu --- scripts/simpletrace-rust/src/main.rs | 151 +++ 1 file changed, 151 insertions(+) diff --git a/scripts/simpletrace-rust/src/main.rs b/scripts/simpletrace-rust/src/main.rs index 2d2926b7658d..b3b8baee7c66 100644 --- a/scripts/simpletrace-rust/src/main.rs +++ b/scripts/simpletrace-rust/src/main.rs @@ -14,21 +14,172 @@ mod trace; use std::env; +use std::fs::File; +use std::io::Error as IOError; +use std::io::ErrorKind; +use std::io::Read; use clap::Arg; use clap::Command; use thiserror::Error; use trace::Event; +const RECORD_TYPE_MAPPING: u64 = 0; +const RECORD_TYPE_EVENT: u64 = 1; + #[derive(Error, Debug)] pub enum Error { #[error("usage: {0} [--no-header] ")] CliOptionUnmatch(String), +#[error("Failed to read file: {0}")] +ReadFile(IOError), +#[error("Unknown record type ({0})")] +UnknownRecType(u64), } pub type Result = std::result::Result; +enum RecordType +{ +Empty, +Mapping, +Event, +} + +#[repr(C)] +#[derive(Clone, Copy, Default)] +struct RecordRawType +{ +rtype: u64, +} + +impl RecordType +{ +fn read_type(mut fobj: ) -> Result +{ +let mut tbuf = [0u8; 8]; +if let Err(e) = fobj.read_exact( tbuf) { +if e.kind() == ErrorKind::UnexpectedEof { +return Ok(RecordType::Empty); +} else { +return Err(Error::ReadFile(e)); +} +} + +/* + * Safe because the layout of the trace record requires us to parse + * the type first, and then there is a check on the validity of the + * record type. + */ +let raw_t = +unsafe { std::mem::transmute::<[u8; 8], RecordRawType>(tbuf) }; +match raw_t.rtype { +RECORD_TYPE_MAPPING => Ok(RecordType::Mapping), +RECORD_TYPE_EVENT => Ok(RecordType::Event), +_ => Err(Error::UnknownRecType(raw_t.rtype)), +} +} +} + +trait ReadHeader +{ +fn read_header(fobj: ) -> Result +where +Self: Sized; +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct LogHeader +{ +event_id: u64, +magic: u64, +version: u64, +} + +impl ReadHeader for LogHeader +{ +fn read_header(mut fobj: ) -> Result +{ +let mut raw_hdr = [0u8; 24]; +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; + +/* + * Safe because the size of log header (struct LogHeader) + * is 24 bytes, which is ensured by simple trace backend. + */ +let hdr = +unsafe { std::mem::transmute::<[u8; 24], LogHeader>(raw_hdr) }; +Ok(hdr) +} +} + +#[derive(Default)] +struct RecordInfo +{ +event_id: u64, +timestamp_ns: u64, +record_pid: u32, +args_payload: Vec, +} + +impl RecordInfo +{ +fn new() -> Self +{ +Default::default() +} +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct RecordHeader +{ +event_id: u64, +timestamp_ns: u64, +record_length: u32, +record_pid: u32, +} + +impl RecordHeader +{ +fn extract_record(, mut fobj: ) -> Result +{ +let mut info = RecordInfo::new(); + +info.event_id = self.event_id; +info.timestamp_ns = self.timestamp_ns; +info.record_pid = self.record_pid; +info.args_payload = vec![ +0u8; +self.record_length as usize +- std::mem::size_of::() +]; +fobj.read_exact( info.args_payload) +.map_err(Error::ReadFile)?; + +Ok(info) +} +} + +impl ReadHeader for RecordHeader +{ +fn read_header(mut fobj: ) -> Result +{ +let mut raw_hdr = [0u8; 24]; +fobj.read_exact( raw_hdr).map_err(Error::ReadFile)?; + +/* + * Safe because the size of record header (struct RecordHeader) + * is 24 bytes, which is ensured by simple trace backend. + */ +let hdr: RecordHeader = +unsafe { std::mem::transmute::<[u8; 24], RecordHeader>(raw_hdr) }; +Ok(hdr) +} +} + pub struct EventArgPayload {} trait Analyzer -- 2.34.1