1 use crate::event
::Event
;
2 use crate::file_header
::FILE_HEADER_SIZE
;
3 use crate::{ProfilerFiles, RawEvent, StringTable, TimestampKind}
;
8 use std
::time
::{Duration, SystemTime}
;
10 pub struct ProfilingData
{
12 string_table
: StringTable
,
16 pub fn new(path_stem
: &Path
) -> Result
<ProfilingData
, Box
<dyn Error
>> {
17 let paths
= ProfilerFiles
::new(path_stem
);
19 let string_data
= fs
::read(paths
.string_data_file
).expect("couldn't read string_data file");
21 fs
::read(paths
.string_index_file
).expect("couldn't read string_index file");
22 let event_data
= fs
::read(paths
.events_file
).expect("couldn't read events file");
24 let string_table
= StringTable
::new(string_data
, index_data
)?
;
32 pub fn iter(&self) -> impl Iterator
<Item
= Event
<'_
>> {
33 ProfilerEventIterator
::new(&self)
36 pub fn iter_matching_events(&self) -> impl Iterator
<Item
= MatchingEvent
<'_
>> {
37 MatchingEventsIterator
::new(ProfilerEventIterator
::new(&self))
41 struct ProfilerEventIterator
<'a
> {
42 data
: &'a ProfilingData
,
43 curr_event_idx
: usize,
46 impl<'a
> ProfilerEventIterator
<'a
> {
47 pub fn new(data
: &'a ProfilingData
) -> ProfilerEventIterator
<'a
> {
48 ProfilerEventIterator
{
55 impl<'a
> Iterator
for ProfilerEventIterator
<'a
> {
56 type Item
= Event
<'a
>;
58 fn next(&mut self) -> Option
<Event
<'a
>> {
59 let event_start_addr
= FILE_HEADER_SIZE
+ self.curr_event_idx
* mem
::size_of
::<RawEvent
>();
60 let event_end_addr
= event_start_addr
+ mem
::size_of
::<RawEvent
>();
61 if event_end_addr
> self.data
.event_data
.len() {
65 self.curr_event_idx
+= 1;
67 let raw_event_bytes
= &self.data
.event_data
[event_start_addr
..event_end_addr
];
69 let mut raw_event
= RawEvent
::default();
71 let raw_event
= std
::slice
::from_raw_parts_mut(
72 &mut raw_event
as *mut RawEvent
as *mut u8,
73 std
::mem
::size_of
::<RawEvent
>(),
75 raw_event
.copy_from_slice(raw_event_bytes
);
78 let string_table
= &self.data
.string_table
;
80 let mut timestamp
= SystemTime
::UNIX_EPOCH
;
81 timestamp
+= Duration
::from_nanos(raw_event
.timestamp
.nanos());
84 event_kind
: string_table
.get(raw_event
.event_kind
).to_string(),
85 label
: string_table
.get(raw_event
.id
).to_string(),
88 timestamp_kind
: raw_event
.timestamp
.kind(),
89 thread_id
: raw_event
.thread_id
,
94 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
95 pub enum MatchingEvent
<'a
> {
96 StartStop(Event
<'a
>, Event
<'a
>),
100 struct MatchingEventsIterator
<'a
> {
101 events
: ProfilerEventIterator
<'a
>,
102 thread_stacks
: Vec
<Vec
<Event
<'a
>>>,
105 impl<'a
> MatchingEventsIterator
<'a
> {
106 pub fn new(events
: ProfilerEventIterator
<'a
>) -> MatchingEventsIterator
<'a
> {
107 MatchingEventsIterator
{
109 thread_stacks
: vec
![],
114 impl<'a
> Iterator
for MatchingEventsIterator
<'a
> {
115 type Item
= MatchingEvent
<'a
>;
117 fn next(&mut self) -> Option
<MatchingEvent
<'a
>> {
118 while let Some(event
) = self.events
.next() {
119 match event
.timestamp_kind
{
120 TimestampKind
::Start
=> {
121 let thread_id
= event
.thread_id
as usize;
122 if thread_id
>= self.thread_stacks
.len() {
123 let growth_size
= (thread_id
+ 1) - self.thread_stacks
.len();
124 self.thread_stacks
.append(&mut vec
![vec
![]; growth_size
])
127 self.thread_stacks
[thread_id
].push(event
);
129 TimestampKind
::Instant
=> {
130 return Some(MatchingEvent
::Instant(event
));
132 TimestampKind
::End
=> {
133 let thread_id
= event
.thread_id
as usize;
134 let previous_event
= self.thread_stacks
[thread_id
]
136 .expect("no previous event");
137 if previous_event
.event_kind
!= event
.event_kind
138 || previous_event
.label
!= event
.label
141 "the event with label: \"{}\" went out of scope of the parent \
142 event with label: \"{}\"",
143 previous_event
.label
, event
.label
147 return Some(MatchingEvent
::StartStop(previous_event
, event
));