Skip to content

Commit 3c8a92e

Browse files
authored
Merge pull request #506 from mstange/push-zmvswrxqnsry
Reduce JSON size, emit version 53
2 parents b69b482 + 8ff9eaf commit 3c8a92e

File tree

10 files changed

+131
-164
lines changed

10 files changed

+131
-164
lines changed

fxprof-processed-profile/src/counters.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use serde::ser::{Serialize, SerializeMap, Serializer};
22

3+
use crate::serialization_helpers::SliceWithPermutation;
4+
use crate::timestamp::{
5+
SerializableTimestampSliceAsDeltas, SerializableTimestampSliceAsDeltasWithPermutation,
6+
};
37
use crate::{GraphColor, ProcessHandle, Timestamp};
48

59
/// A counter. Can be created with [`Profile::add_counter`](crate::Profile::add_counter).
@@ -89,6 +93,9 @@ struct CounterSamples {
8993
time: Vec<Timestamp>,
9094
number: Vec<u32>,
9195
count: Vec<f64>,
96+
97+
is_sorted_by_time: bool,
98+
last_sample_timestamp: Timestamp,
9299
}
93100

94101
impl CounterSamples {
@@ -97,6 +104,9 @@ impl CounterSamples {
97104
time: Vec::new(),
98105
number: Vec::new(),
99106
count: Vec::new(),
107+
108+
is_sorted_by_time: true,
109+
last_sample_timestamp: Timestamp::from_nanos_since_reference(0),
100110
}
101111
}
102112

@@ -109,6 +119,11 @@ impl CounterSamples {
109119
self.time.push(timestamp);
110120
self.count.push(value_delta);
111121
self.number.push(number_of_operations_delta);
122+
123+
if timestamp < self.last_sample_timestamp {
124+
self.is_sorted_by_time = false;
125+
}
126+
self.last_sample_timestamp = timestamp;
112127
}
113128
}
114129

@@ -117,9 +132,25 @@ impl Serialize for CounterSamples {
117132
let len = self.time.len();
118133
let mut map = serializer.serialize_map(None)?;
119134
map.serialize_entry("length", &len)?;
120-
map.serialize_entry("count", &self.count)?;
121-
map.serialize_entry("number", &self.number)?;
122-
map.serialize_entry("time", &self.time)?;
135+
136+
if self.is_sorted_by_time {
137+
map.serialize_entry("count", &self.count)?;
138+
map.serialize_entry("number", &self.number)?;
139+
map.serialize_entry(
140+
"timeDeltas",
141+
&SerializableTimestampSliceAsDeltas(&self.time),
142+
)?;
143+
} else {
144+
let mut indexes: Vec<usize> = (0..self.time.len()).collect();
145+
indexes.sort_unstable_by_key(|index| self.time[*index]);
146+
map.serialize_entry("count", &SliceWithPermutation(&self.count, &indexes))?;
147+
map.serialize_entry("number", &SliceWithPermutation(&self.number, &indexes))?;
148+
map.serialize_entry(
149+
"timeDeltas",
150+
&SerializableTimestampSliceAsDeltasWithPermutation(&self.time, &indexes),
151+
)?;
152+
}
153+
123154
map.end()
124155
}
125156
}

fxprof-processed-profile/src/frame_table.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,6 @@ impl FrameTable {
100100
})
101101
}
102102

103-
pub fn get_category(&self, frame_index: usize) -> CategoryPairHandle {
104-
let category = self.categories[frame_index];
105-
let subcategory = match self.subcategories[frame_index] {
106-
Subcategory::Normal(subcategory) => Some(subcategory),
107-
Subcategory::Other(_) => None,
108-
};
109-
CategoryPairHandle(category, subcategory)
110-
}
111-
112103
pub fn as_serializable<'a>(&'a self, categories: &'a [Category]) -> impl Serialize + 'a {
113104
SerializableFrameTable {
114105
table: self,

fxprof-processed-profile/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,4 @@ pub use profile::{FrameHandle, Profile, SamplingInterval, StackHandle, StringHan
7878
pub use reference_timestamp::ReferenceTimestamp;
7979
pub use sample_table::WeightType;
8080
pub use thread::ProcessHandle;
81-
pub use timestamp::*;
81+
pub use timestamp::Timestamp;

fxprof-processed-profile/src/profile.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,7 @@ impl Profile {
528528
"FrameHandle from different thread passed to Profile::intern_stack"
529529
);
530530
let thread = &mut self.threads[thread.0];
531-
let category_pair = thread.get_frame_category(frame_index);
532-
let stack_index = thread.stack_index_for_stack(prefix, frame_index, category_pair);
531+
let stack_index = thread.stack_index_for_stack(prefix, frame_index);
533532
StackHandle(thread_handle, stack_index)
534533
}
535534

@@ -926,7 +925,6 @@ impl Profile {
926925
let process = &mut self.processes[thread.process().0];
927926
let mut prefix = None;
928927
for frame_info in frames {
929-
let category_pair = frame_info.category_pair;
930928
let frame_index = Self::intern_frame_internal(
931929
thread,
932930
process,
@@ -935,7 +933,7 @@ impl Profile {
935933
&mut self.kernel_libs,
936934
&self.string_table,
937935
);
938-
prefix = Some(thread.stack_index_for_stack(prefix, frame_index, category_pair));
936+
prefix = Some(thread.stack_index_for_stack(prefix, frame_index));
939937
}
940938
prefix
941939
}
@@ -1049,7 +1047,7 @@ impl Serialize for SerializableProfileMeta<'_> {
10491047
}),
10501048
)?;
10511049
map.serialize_entry("interval", &(self.0.interval.as_secs_f64() * 1000.0))?;
1052-
map.serialize_entry("preprocessedProfileVersion", &49)?;
1050+
map.serialize_entry("preprocessedProfileVersion", &53)?;
10531051
map.serialize_entry("processType", &0)?;
10541052
map.serialize_entry("product", &self.0.product)?;
10551053
if let Some(os_name) = &self.0.os_name {
@@ -1066,7 +1064,7 @@ impl Serialize for SerializableProfileMeta<'_> {
10661064
map.serialize_entry("startTime", &self.0.reference_timestamp)?;
10671065
map.serialize_entry("symbolicated", &self.0.symbolicated)?;
10681066
map.serialize_entry("pausedRanges", &[] as &[()])?;
1069-
map.serialize_entry("version", &24)?;
1067+
map.serialize_entry("version", &24)?; // this version is ignored, only "preprocessedProfileVersion" is used
10701068
map.serialize_entry("usesOnlyOneStackType", &(!self.0.contains_js_function()))?;
10711069
map.serialize_entry("doesNotUseFrameImplementation", &true)?;
10721070
map.serialize_entry("sourceCodeIsNotOnSearchfox", &true)?;

fxprof-processed-profile/src/sample_table.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use std::fmt::{Display, Formatter};
33
use serde::ser::{Serialize, SerializeMap, Serializer};
44

55
use crate::cpu_delta::CpuDelta;
6-
use crate::serialization_helpers::SerializableSingleValueColumn;
7-
use crate::Timestamp;
6+
use crate::serialization_helpers::{SerializableSingleValueColumn, SliceWithPermutation};
7+
use crate::timestamp::{
8+
SerializableTimestampSliceAsDeltas, SerializableTimestampSliceAsDeltasWithPermutation,
9+
Timestamp,
10+
};
811

912
/// The sample table contains stacks with timestamps and some extra information.
1013
///
@@ -20,7 +23,7 @@ pub struct SampleTable {
2023
sample_stack_indexes: Vec<Option<usize>>,
2124
/// CPU usage delta since the previous sample for this thread, for each sample.
2225
sample_cpu_deltas: Vec<CpuDelta>,
23-
sorted_by_time: bool,
26+
is_sorted_by_time: bool,
2427
last_sample_timestamp: Timestamp,
2528
}
2629

@@ -76,7 +79,7 @@ impl SampleTable {
7679
sample_timestamps: Vec::new(),
7780
sample_stack_indexes: Vec::new(),
7881
sample_cpu_deltas: Vec::new(),
79-
sorted_by_time: true,
82+
is_sorted_by_time: true,
8083
last_sample_timestamp: Timestamp::from_nanos_since_reference(0),
8184
}
8285
}
@@ -93,7 +96,7 @@ impl SampleTable {
9396
self.sample_stack_indexes.push(stack_index);
9497
self.sample_cpu_deltas.push(cpu_delta);
9598
if timestamp < self.last_sample_timestamp {
96-
self.sorted_by_time = false;
99+
self.is_sorted_by_time = false;
97100
}
98101
self.last_sample_timestamp = timestamp;
99102
}
@@ -115,9 +118,12 @@ impl Serialize for SampleTable {
115118
map.serialize_entry("length", &len)?;
116119
map.serialize_entry("weightType", &self.sample_weight_type.to_string())?;
117120

118-
if self.sorted_by_time {
121+
if self.is_sorted_by_time {
119122
map.serialize_entry("stack", &self.sample_stack_indexes)?;
120-
map.serialize_entry("time", &self.sample_timestamps)?;
123+
map.serialize_entry(
124+
"timeDeltas",
125+
&SerializableTimestampSliceAsDeltas(&self.sample_timestamps),
126+
)?;
121127
map.serialize_entry("weight", &self.sample_weights)?;
122128
map.serialize_entry("threadCPUDelta", &self.sample_cpu_deltas)?;
123129
} else {
@@ -128,8 +134,11 @@ impl Serialize for SampleTable {
128134
&SliceWithPermutation(&self.sample_stack_indexes, &indexes),
129135
)?;
130136
map.serialize_entry(
131-
"time",
132-
&SliceWithPermutation(&self.sample_timestamps, &indexes),
137+
"timeDeltas",
138+
&SerializableTimestampSliceAsDeltasWithPermutation(
139+
&self.sample_timestamps,
140+
&indexes,
141+
),
133142
)?;
134143
map.serialize_entry(
135144
"weight",
@@ -144,17 +153,6 @@ impl Serialize for SampleTable {
144153
}
145154
}
146155

147-
struct SliceWithPermutation<'a, T: Serialize>(&'a [T], &'a [usize]);
148-
149-
impl<T: Serialize> Serialize for SliceWithPermutation<'_, T> {
150-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151-
where
152-
S: Serializer,
153-
{
154-
serializer.collect_seq(self.1.iter().map(|i| &self.0[*i]))
155-
}
156-
}
157-
158156
/// JS documentation of the native allocations table:
159157
///
160158
/// ```ignore

fxprof-processed-profile/src/serialization_helpers.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,14 @@ impl Serialize for SerializableOptionalTimestampColumn<'_> {
2828
seq.end()
2929
}
3030
}
31+
32+
pub struct SliceWithPermutation<'a, T: Serialize>(pub &'a [T], pub &'a [usize]);
33+
34+
impl<T: Serialize> Serialize for SliceWithPermutation<'_, T> {
35+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36+
where
37+
S: Serializer,
38+
{
39+
serializer.collect_seq(self.1.iter().map(|i| &self.0[*i]))
40+
}
41+
}
Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
use serde::ser::{Serialize, SerializeMap, Serializer};
22

3-
use crate::category::{
4-
Category, CategoryHandle, CategoryPairHandle, SerializableSubcategoryColumn, Subcategory,
5-
};
63
use crate::fast_hash_map::FastHashMap;
74

85
/// The stack table stores the tree of stack nodes of a thread. The shape of the tree is encoded in
@@ -47,10 +44,6 @@ pub struct StackTable {
4744
stack_prefixes: Vec<Option<usize>>,
4845
stack_frames: Vec<usize>,
4946

50-
/// Imported profiles may not have categories. In this case fill the array with 0s.
51-
stack_categories: Vec<CategoryHandle>,
52-
stack_subcategories: Vec<Subcategory>,
53-
5447
// (parent stack, frame_index) -> stack index
5548
index: FastHashMap<(Option<usize>, usize), usize>,
5649
}
@@ -60,60 +53,27 @@ impl StackTable {
6053
Default::default()
6154
}
6255

63-
pub fn index_for_stack(
64-
&mut self,
65-
prefix: Option<usize>,
66-
frame: usize,
67-
category_pair: CategoryPairHandle,
68-
) -> usize {
56+
pub fn index_for_stack(&mut self, prefix: Option<usize>, frame: usize) -> usize {
6957
match self.index.get(&(prefix, frame)) {
7058
Some(stack) => *stack,
7159
None => {
72-
let CategoryPairHandle(category, subcategory_index) = category_pair;
73-
let subcategory = match subcategory_index {
74-
Some(index) => Subcategory::Normal(index),
75-
None => Subcategory::Other(category),
76-
};
77-
7860
let stack = self.stack_prefixes.len();
7961
self.stack_prefixes.push(prefix);
8062
self.stack_frames.push(frame);
81-
self.stack_categories.push(category);
82-
self.stack_subcategories.push(subcategory);
8363
self.index.insert((prefix, frame), stack);
8464
stack
8565
}
8666
}
8767
}
88-
89-
pub fn serialize_with_categories<'a>(
90-
&'a self,
91-
categories: &'a [Category],
92-
) -> impl Serialize + 'a {
93-
SerializableStackTable {
94-
table: self,
95-
categories,
96-
}
97-
}
98-
}
99-
100-
struct SerializableStackTable<'a> {
101-
table: &'a StackTable,
102-
categories: &'a [Category],
10368
}
10469

105-
impl Serialize for SerializableStackTable<'_> {
70+
impl Serialize for StackTable {
10671
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
107-
let len = self.table.stack_prefixes.len();
72+
let len = self.stack_prefixes.len();
10873
let mut map = serializer.serialize_map(Some(3))?;
10974
map.serialize_entry("length", &len)?;
110-
map.serialize_entry("prefix", &self.table.stack_prefixes)?;
111-
map.serialize_entry("frame", &self.table.stack_frames)?;
112-
map.serialize_entry("category", &self.table.stack_categories)?;
113-
map.serialize_entry(
114-
"subcategory",
115-
&SerializableSubcategoryColumn(&self.table.stack_subcategories, self.categories),
116-
)?;
75+
map.serialize_entry("prefix", &self.stack_prefixes)?;
76+
map.serialize_entry("frame", &self.stack_frames)?;
11777
map.end()
11878
}
11979
}

fxprof-processed-profile/src/thread.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
33

44
use serde::ser::{SerializeMap, Serializer};
55

6-
use crate::category::{Category, CategoryPairHandle};
6+
use crate::category::Category;
77
use crate::cpu_delta::CpuDelta;
88
use crate::frame_table::{FrameTable, InternalFrame};
99
use crate::func_table::FuncTable;
@@ -116,18 +116,8 @@ impl Thread {
116116
)
117117
}
118118

119-
pub fn get_frame_category(&self, frame: usize) -> CategoryPairHandle {
120-
self.frame_table.get_category(frame)
121-
}
122-
123-
pub fn stack_index_for_stack(
124-
&mut self,
125-
prefix: Option<usize>,
126-
frame: usize,
127-
category_pair: CategoryPairHandle,
128-
) -> usize {
129-
self.stack_table
130-
.index_for_stack(prefix, frame, category_pair)
119+
pub fn stack_index_for_stack(&mut self, prefix: Option<usize>, frame: usize) -> usize {
120+
self.stack_table.index_for_stack(prefix, frame)
131121
}
132122

133123
pub fn add_sample(
@@ -265,10 +255,7 @@ impl Thread {
265255
if let Some(allocations) = &self.native_allocations {
266256
map.serialize_entry("nativeAllocations", &allocations)?;
267257
}
268-
map.serialize_entry(
269-
"stackTable",
270-
&self.stack_table.serialize_with_categories(categories),
271-
)?;
258+
map.serialize_entry("stackTable", &self.stack_table)?;
272259
map.serialize_entry("stringArray", &self.string_table)?;
273260
map.serialize_entry("tid", &self.tid)?;
274261
map.serialize_entry("unregisterTime", &thread_unregister_time)?;

0 commit comments

Comments
 (0)