Skip to content

Commit 3603395

Browse files
Prefer serializing self-profile data into a SoA
This both allows for much better compression (2 GB to 760 MB, with each timing file going from 3.4 MB to 1.4 MB of compressed JSON), as well as far faster deserialization (54 to 25 seconds). However, the new format is still fully backwards compatible with the old (and we use this feature to deserialize data from measureme in the collector).
1 parent 3bf4d88 commit 3603395

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

collector/src/self_profile.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,115 @@
11
use serde::{Deserialize, Serialize};
2+
use std::convert::TryFrom;
23
use std::time::Duration;
34

45
#[derive(Serialize, Deserialize, Debug, Clone)]
6+
#[serde(into = "InternalSelfProfile")]
7+
#[serde(from = "InternalSelfProfile")]
58
pub struct SelfProfile {
69
pub query_data: Vec<QueryData>,
710
}
811

12+
impl Into<InternalSelfProfile> for SelfProfile {
13+
fn into(self) -> InternalSelfProfile {
14+
let query_data = self.query_data;
15+
InternalSelfProfile::Perf {
16+
label: query_data.iter().map(|qd| qd.label.clone()).collect(),
17+
self_time: query_data
18+
.iter()
19+
.map(|qd| u64::try_from(qd.self_time.as_nanos()).unwrap())
20+
.collect(),
21+
number_of_cache_misses: query_data
22+
.iter()
23+
.map(|qd| qd.number_of_cache_misses)
24+
.collect(),
25+
number_of_cache_hits: query_data
26+
.iter()
27+
.map(|qd| qd.number_of_cache_hits)
28+
.collect(),
29+
invocation_count: query_data.iter().map(|qd| qd.invocation_count).collect(),
30+
blocked_time: query_data
31+
.iter()
32+
.map(|qd| u64::try_from(qd.blocked_time.as_nanos()).unwrap())
33+
.collect(),
34+
incremental_load_time: query_data
35+
.iter()
36+
.map(|qd| u64::try_from(qd.incremental_load_time.as_nanos()).unwrap())
37+
.collect(),
38+
}
39+
}
40+
}
41+
42+
impl From<InternalSelfProfile> for SelfProfile {
43+
fn from(profile: InternalSelfProfile) -> SelfProfile {
44+
match profile {
45+
InternalSelfProfile::Rustc { query_data } => SelfProfile { query_data },
46+
InternalSelfProfile::Perf {
47+
label,
48+
self_time,
49+
number_of_cache_misses,
50+
number_of_cache_hits,
51+
invocation_count,
52+
blocked_time,
53+
incremental_load_time,
54+
} => {
55+
let mut query_data = Vec::with_capacity(label.len());
56+
let label = label.into_iter();
57+
let mut self_time = self_time.into_iter().map(from_nanoseconds_to_duration);
58+
let mut number_of_cache_misses = number_of_cache_misses.into_iter();
59+
let mut number_of_cache_hits = number_of_cache_hits.into_iter();
60+
let mut invocation_count = invocation_count.into_iter();
61+
let mut blocked_time = blocked_time.into_iter().map(from_nanoseconds_to_duration);
62+
let mut incremental_load_time = incremental_load_time
63+
.into_iter()
64+
.map(from_nanoseconds_to_duration);
65+
for label in label {
66+
query_data.push(QueryData {
67+
label,
68+
self_time: self_time.next().unwrap(),
69+
number_of_cache_misses: number_of_cache_misses.next().unwrap(),
70+
number_of_cache_hits: number_of_cache_hits.next().unwrap(),
71+
invocation_count: invocation_count.next().unwrap(),
72+
blocked_time: blocked_time.next().unwrap(),
73+
incremental_load_time: incremental_load_time.next().unwrap(),
74+
});
75+
}
76+
SelfProfile { query_data }
77+
}
78+
}
79+
}
80+
}
81+
82+
#[derive(Serialize, Deserialize)]
83+
#[serde(untagged)]
84+
enum InternalSelfProfile {
85+
Rustc {
86+
query_data: Vec<QueryData>,
87+
},
88+
Perf {
89+
label: Vec<QueryLabel>,
90+
// nanos
91+
self_time: Vec<u64>,
92+
number_of_cache_misses: Vec<u32>,
93+
number_of_cache_hits: Vec<u32>,
94+
invocation_count: Vec<u32>,
95+
// nanos
96+
blocked_time: Vec<u64>,
97+
// nanos
98+
incremental_load_time: Vec<u64>,
99+
},
100+
}
101+
102+
// FIXME: We would prefer to store the nanoseconds as u128, which is lossless,
103+
// but serde's untagged enum representation (and the internal buffering API it
104+
// uses) do not support this yet.
105+
fn from_nanoseconds_to_duration(nanos: u64) -> Duration {
106+
const NANOS_PER_SEC: u64 = 1_000_000_000;
107+
Duration::new(
108+
u64::try_from(nanos / NANOS_PER_SEC).unwrap(),
109+
u32::try_from(nanos % NANOS_PER_SEC).unwrap(),
110+
)
111+
}
112+
9113
#[derive(Serialize, Deserialize, Clone, Debug)]
10114
pub struct QueryData {
11115
pub label: QueryLabel,

0 commit comments

Comments
 (0)