1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2.
//! Memory-aware query limits for perfetto trace queries
//!
//! Adjusts query limits based on available system memory to prevent OOM
//! while maximizing data accessibility on systems with plenty of RAM.
use sysinfo::System;
/// Memory-aware limit calculator
pub struct MemoryAwareLimits {
available_memory_gb: f64,
}
impl MemoryAwareLimits {
/// Create a new limit calculator based on current system memory
pub fn new() -> Self {
let mut sys = System::new_all();
sys.refresh_memory();
let available_memory_bytes = sys.available_memory();
let available_memory_gb = available_memory_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
Self {
available_memory_gb,
}
}
/// Get default limit for event queries based on available memory
///
/// Memory thresholds:
/// - < 4GB: 1,000 events (conservative)
/// - 4-8GB: 10,000 events
/// - 8-16GB: 50,000 events
/// - 16-32GB: 100,000 events
/// - 32-64GB: 500,000 events
/// - >= 64GB: unlimited (query entire trace)
pub fn event_query_limit(&self) -> Option<usize> {
if self.available_memory_gb >= 64.0 {
None // Unlimited - query entire trace
} else if self.available_memory_gb >= 32.0 {
Some(500_000)
} else if self.available_memory_gb >= 16.0 {
Some(100_000)
} else if self.available_memory_gb >= 8.0 {
Some(50_000)
} else if self.available_memory_gb >= 4.0 {
Some(10_000)
} else {
Some(1_000)
}
}
/// Get default limit for timeline queries
///
/// More conservative than event queries since timelines include
/// aggregated data that can be memory-intensive
pub fn timeline_limit(&self) -> usize {
if self.available_memory_gb >= 64.0 {
10_000
} else if self.available_memory_gb >= 32.0 {
5_000
} else if self.available_memory_gb >= 16.0 {
1_000
} else if self.available_memory_gb >= 8.0 {
500
} else {
100
}
}
/// Get default limit for analysis results (top N processes, outliers, etc.)
pub fn analysis_result_limit(&self) -> usize {
if self.available_memory_gb >= 32.0 {
1_000
} else if self.available_memory_gb >= 16.0 {
500
} else if self.available_memory_gb >= 8.0 {
100
} else {
50
}
}
/// Get display limit (how many events to show in output)
///
/// Always conservative to keep JSON responses manageable
pub fn display_limit(&self) -> usize {
if self.available_memory_gb >= 16.0 {
500
} else if self.available_memory_gb >= 8.0 {
200
} else {
100
}
}
/// Get available memory in GB
pub fn available_gb(&self) -> f64 {
self.available_memory_gb
}
}
impl Default for MemoryAwareLimits {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_limits_calculation() {
let limits = MemoryAwareLimits::new();
println!("Available memory: {:.2} GB", limits.available_gb());
println!("Event query limit: {:?}", limits.event_query_limit());
println!("Timeline limit: {}", limits.timeline_limit());
println!("Analysis result limit: {}", limits.analysis_result_limit());
println!("Display limit: {}", limits.display_limit());
// Basic sanity checks
assert!(limits.timeline_limit() > 0);
assert!(limits.analysis_result_limit() > 0);
assert!(limits.display_limit() > 0);
assert!(limits.display_limit() <= limits.timeline_limit());
}
}