Skip to content

Commit 189082d

Browse files
Store Duration as u64 nanoseconds
This shrinks the size of storage from 16 bytes to 8, reducing memory usage from 4.65 GB to 3 GB. This preserves precision and accuracy -- we never have large enough times to fill up 2^64 nanoseconds. We may want to explore going further, by storing in a (u16, u16) (and splitting up into nanoseconds/seconds or so). But that's more complicated, and this gets us pretty major wins as is.
1 parent f10a4ca commit 189082d

File tree

2 files changed

+50
-35
lines changed

2 files changed

+50
-35
lines changed

collector/src/self_profile.rs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use serde::de::Deserializer;
12
use serde::{Deserialize, Serialize};
23
use std::convert::TryFrom;
34
use std::sync::Arc;
@@ -15,22 +16,16 @@ impl Into<InternalSelfProfile> for SelfProfile {
1516
let query_data = self.query_data;
1617
InternalSelfProfile::Perf {
1718
label: query_data.iter().map(|qd| qd.label.clone()).collect(),
18-
self_time: query_data
19-
.iter()
20-
.map(|qd| u64::try_from(qd.self_time.as_nanos()).unwrap())
21-
.collect(),
19+
self_time: query_data.iter().map(|qd| qd.self_time).collect(),
2220
number_of_cache_hits: query_data
2321
.iter()
2422
.map(|qd| qd.number_of_cache_hits)
2523
.collect(),
2624
invocation_count: query_data.iter().map(|qd| qd.invocation_count).collect(),
27-
blocked_time: query_data
28-
.iter()
29-
.map(|qd| u64::try_from(qd.blocked_time.as_nanos()).unwrap())
30-
.collect(),
25+
blocked_time: query_data.iter().map(|qd| qd.blocked_time).collect(),
3126
incremental_load_time: query_data
3227
.iter()
33-
.map(|qd| u64::try_from(qd.incremental_load_time.as_nanos()).unwrap())
28+
.map(|qd| qd.incremental_load_time)
3429
.collect(),
3530
}
3631
}
@@ -55,13 +50,11 @@ impl From<InternalSelfProfile> for SelfProfile {
5550
} => {
5651
let mut query_data = Vec::with_capacity(label.len());
5752
let label = label.into_iter();
58-
let mut self_time = self_time.into_iter().map(from_nanoseconds_to_duration);
53+
let mut self_time = self_time.into_iter();
5954
let mut number_of_cache_hits = number_of_cache_hits.into_iter();
6055
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);
56+
let mut blocked_time = blocked_time.into_iter();
57+
let mut incremental_load_time = incremental_load_time.into_iter();
6558
for label in label {
6659
query_data.push(QueryData {
6760
label,
@@ -72,6 +65,7 @@ impl From<InternalSelfProfile> for SelfProfile {
7265
incremental_load_time: incremental_load_time.next().unwrap(),
7366
});
7467
}
68+
assert_eq!(query_data.capacity(), query_data.len());
7569
query_data.shrink_to_fit();
7670
SelfProfile {
7771
query_data: Arc::new(query_data),
@@ -101,28 +95,49 @@ enum InternalSelfProfile {
10195
},
10296
}
10397

104-
// FIXME: We would prefer to store the nanoseconds as u128, which is lossless,
105-
// but serde's untagged enum representation (and the internal buffering API it
106-
// uses) do not support this yet.
107-
fn from_nanoseconds_to_duration(nanos: u64) -> Duration {
108-
const NANOS_PER_SEC: u64 = 1_000_000_000;
109-
Duration::new(
110-
u64::try_from(nanos / NANOS_PER_SEC).unwrap(),
111-
u32::try_from(nanos % NANOS_PER_SEC).unwrap(),
112-
)
113-
}
114-
11598
#[derive(Deserialize, Clone, Debug)]
11699
pub struct QueryData {
117100
pub label: QueryLabel,
118-
pub self_time: Duration,
101+
#[serde(deserialize_with = "SerdeDuration::into_nanos")]
102+
self_time: u64,
119103
pub number_of_cache_hits: u32,
120104
pub invocation_count: u32,
121-
pub blocked_time: Duration,
122-
pub incremental_load_time: Duration,
105+
blocked_time: u64,
106+
incremental_load_time: u64,
107+
}
108+
109+
#[derive(Deserialize)]
110+
#[serde(untagged)]
111+
enum SerdeDuration {
112+
Nanoseconds(u64),
113+
Duration(Duration),
114+
}
115+
116+
impl SerdeDuration {
117+
fn into_nanos<'de, D>(deserializer: D) -> Result<u64, D::Error>
118+
where
119+
D: Deserializer<'de>,
120+
{
121+
match SerdeDuration::deserialize(deserializer)? {
122+
SerdeDuration::Nanoseconds(v) => Ok(v),
123+
SerdeDuration::Duration(d) => Ok(u64::try_from(d.as_nanos()).unwrap()),
124+
}
125+
}
123126
}
124127

125128
impl QueryData {
129+
pub fn self_time(&self) -> Duration {
130+
Duration::from_nanos(self.self_time)
131+
}
132+
133+
pub fn blocked_time(&self) -> Duration {
134+
Duration::from_nanos(self.blocked_time)
135+
}
136+
137+
pub fn incremental_load_time(&self) -> Duration {
138+
Duration::from_nanos(self.incremental_load_time)
139+
}
140+
126141
pub fn number_of_cache_misses(&self) -> u32 {
127142
self.invocation_count - self.number_of_cache_hits
128143
}

site/src/server.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ fn get_self_profile_data(
649649
.as_ref()
650650
.ok_or(format!("No self profile results for this commit"))?
651651
.clone();
652-
let total_time = profile.query_data.iter().map(|qd| qd.self_time).sum();
652+
let total_time = profile.query_data.iter().map(|qd| qd.self_time()).sum();
653653
let totals = self_profile::QueryData {
654654
label: "Totals".into(),
655655
self_time: total_time,
@@ -678,11 +678,11 @@ fn get_self_profile_data(
678678
.iter()
679679
.map(|qd| qd.invocation_count)
680680
.sum(),
681-
blocked_time: profile.query_data.iter().map(|qd| qd.blocked_time).sum(),
681+
blocked_time: profile.query_data.iter().map(|qd| qd.blocked_time()).sum(),
682682
incremental_load_time: profile
683683
.query_data
684684
.iter()
685-
.map(|qd| qd.incremental_load_time)
685+
.map(|qd| qd.incremental_load_time())
686686
.sum(),
687687
};
688688
let mut profile = self_profile::SelfProfile {
@@ -691,15 +691,15 @@ fn get_self_profile_data(
691691
.iter()
692692
.map(|qd| self_profile::QueryData {
693693
label: qd.label,
694-
self_time: qd.self_time,
695-
percent_total_time: ((qd.self_time.as_nanos() as f64
694+
self_time: qd.self_time(),
695+
percent_total_time: ((qd.self_time().as_nanos() as f64
696696
/ totals.self_time.as_nanos() as f64)
697697
* 100.0) as f32,
698698
number_of_cache_misses: qd.number_of_cache_misses(),
699699
number_of_cache_hits: qd.number_of_cache_hits,
700700
invocation_count: qd.invocation_count,
701-
blocked_time: qd.blocked_time,
702-
incremental_load_time: qd.incremental_load_time,
701+
blocked_time: qd.blocked_time(),
702+
incremental_load_time: qd.incremental_load_time(),
703703
})
704704
.collect(),
705705
totals,

0 commit comments

Comments
 (0)