performance_benchmark/
performance_benchmark.rs1use gc_lite::{GcHeap, GcRef, GcTrace, GcTraceCtx, gc_type_register};
13use std::time::{Duration, Instant};
14
15fn main() {
16 println!("=== Performance benchmark of partitioned garbage collection system ===");
17
18 println!("\n=== Object size performance test ===");
20 benchmark_object_sizes();
21
22 println!("\n=== Complex object graph performance test ===");
24 benchmark_complex_graphs();
25
26 println!("\n=== Memory usage efficiency test ===");
28 benchmark_memory_efficiency();
29
30 println!("\n=== Automatic GC threshold performance test ===");
32 benchmark_auto_gc_threshold();
33
34 println!("\nAll performance tests completed!");
35}
36
37fn benchmark_object_sizes() {
39 let sizes = [10, 100, 500, 1000, 5000];
40
41 for &size in &sizes {
42 println!("\nTest object count: {}", size);
43
44 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
45 let partition = context.create_partition();
46
47 let alloc_start = Instant::now();
49 let mut objects = Vec::new();
50 for _i in 0..size {
51 let node = unsafe {
52 context.alloc_raw(
53 partition,
54 SimpleNode {
55 _data: vec![0u8; 100],
56 },
57 )
58 } .unwrap();
60 objects.push(node);
61 }
62 let alloc_duration = alloc_start.elapsed();
63
64 println!(" Allocated {} objects in: {:?}", size, alloc_duration);
65 println!(
66 " Average allocation time per object: {:?}",
67 alloc_duration / size as u32
68 );
69
70 let gc_start = Instant::now();
72 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
73 let gc_duration = gc_start.elapsed();
74
75 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
76 println!(
77 " Average collection time per byte: {:?}",
78 if freed > 0 {
79 gc_duration / freed as u32
80 } else {
81 Duration::from_nanos(0)
82 }
83 );
84 }
85}
86
87fn benchmark_complex_graphs() {
89 let sizes = [100, 500, 1000];
90
91 for &size in &sizes {
92 println!("\nTest complex object graph size: {} nodes", size);
93
94 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
95 let partition = context.create_partition();
96
97 let graph_start = Instant::now();
99 let mut nodes = Vec::new();
100
101 for _i in 0..size {
103 let node = unsafe {
104 context.alloc_raw(
105 partition,
106 GraphNode {
107 neighbors: Vec::new(),
108 },
109 )
110 }
111 .unwrap();
112 nodes.push(node);
113 }
114
115 for i in 0..size {
117 {
118 for j in 1..=5 {
120 if i + j < size {
121 let n = nodes[i + j];
122 nodes[i].with_mut(&mut context, |node| node.neighbors.push(n));
123 }
124 }
125 if i % 10 == 0 && i + 9 < size {
127 let n = nodes[i];
128 nodes[i + 9].with_mut(&mut context, |node| node.neighbors.push(n));
129 }
130 }
131 }
132 let graph_duration = graph_start.elapsed();
133
134 println!(" Built complex object graph in: {:?}", graph_duration);
135
136 let gc_start = Instant::now();
138 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
139 let gc_duration = gc_start.elapsed();
140
141 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
142 println!(
143 " Object graph complexity: average {} neighbors per node",
144 if size > 0 { (size * 5) / size } else { 0 }
145 );
146 }
147}
148
149fn benchmark_memory_efficiency() {
151 println!("\nTesting memory usage efficiency...");
152
153 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
154 context.set_memory_limit(1024 * 1024); let partition = context.create_partition();
156
157 let small_objects_count = 1000;
159 let mut small_objects = Vec::new();
160
161 for _i in 0..small_objects_count {
162 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
163 small_objects.push(obj);
164 }
165
166 if let Some(partition_info) = context.partition(partition) {
167 let used = partition_info.memory_used();
168 let limit = context.memory_limit();
169 let efficiency = if limit > 0 {
170 (used as f64 / limit as f64) * 100.0
171 } else {
172 0.0
173 };
174
175 println!(" After allocating {} small objects:", small_objects_count);
176 println!(
177 " Memory usage: {}/{} bytes ({:.1}%)",
178 used, limit, efficiency
179 );
180 println!(
181 " Average overhead per object: {} bytes",
182 if small_objects_count > 0 {
183 used / small_objects_count
184 } else {
185 0
186 }
187 );
188 }
189
190 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
192 println!(" Collected all objects, freed {} bytes", freed);
193
194 if let Some(partition_info) = context.partition(partition) {
196 let used_after = partition_info.memory_used();
197 println!(" Memory usage after collection: {} bytes", used_after);
198 println!(
199 " Memory collection rate: {:.1}%",
200 if freed > 0 {
201 (freed as f64 / (freed + used_after) as f64) * 100.0
202 } else {
203 0.0
204 }
205 );
206 }
207}
208
209fn benchmark_auto_gc_threshold() {
211 println!("\nTesting automatic GC threshold performance...");
212
213 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
214 context.set_memory_limit(2048); let partition = context.create_partition();
216
217 context.set_gc_threshold(1500);
219
220 let mut allocated_bytes = 0;
222 let mut object_count = 0;
223
224 println!(" Allocating objects until automatic GC is triggered...");
225
226 for _i in 0..100 {
227 let node = SimpleNode {
230 _data: vec![0u8; 100],
231 };
232 match unsafe { context.alloc_raw(partition, node) } {
233 Ok(_gc_ref) => {
234 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); object_count += 1;
236
237 if let Some(partition_info) = context.partition(partition)
239 && partition_info.memory_used() >= 1500
240 {
241 println!(
242 " Reached automatic GC threshold, allocated {} objects",
243 object_count
244 );
245 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
246 println!(
247 " Actual memory usage: {} bytes",
248 partition_info.memory_used()
249 );
250 break;
251 }
252 }
253 Err(_) => {
254 println!(" Allocation failed, automatic GC may have been triggered");
255 break;
256 }
257 }
258 }
259
260 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
262 println!(" Manual GC freed {} bytes", freed);
263}
264
265#[derive(Debug)]
269struct SimpleNode {
270 _data: Vec<u8>,
271}
272
273impl GcTrace for SimpleNode {
274 fn trace(&self, _: &mut GcTraceCtx) {}
275}
276
277#[derive(Debug)]
279struct GraphNode {
280 neighbors: Vec<GcRef<GraphNode>>,
281}
282
283impl GcTrace for GraphNode {
284 fn trace(&self, tr: &mut GcTraceCtx) {
285 for neighbor in &self.neighbors {
286 tr.add(*neighbor);
287 }
288 }
289}
290
291#[derive(Debug)]
293struct SmallData {
294 }
296
297impl GcTrace for SmallData {
298 fn trace(&self, _: &mut GcTraceCtx) {}
299}
300
301gc_type_register! {
302 SimpleNode;
303 GraphNode;
304 SmallData;
305}