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(64 * 1024, 16 * 1024);
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(64 * 1024, 16 * 1024);
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 unsafe {
123 nodes[i]
124 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
125 }
126 }
127 }
128 if i % 10 == 0 && i + 9 < size {
130 let n = nodes[i];
131 unsafe {
132 nodes[i + 9]
133 .with_write_barrier(&mut context, |node| node.neighbors.push(n));
134 }
135 }
136 }
137 }
138 let graph_duration = graph_start.elapsed();
139
140 println!(" Built complex object graph in: {:?}", graph_duration);
141
142 let gc_start = Instant::now();
144 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
145 let gc_duration = gc_start.elapsed();
146
147 println!(" GC回收 {} 字节耗时: {:?}", freed, gc_duration);
148 println!(
149 " Object graph complexity: average {} neighbors per node",
150 if size > 0 { (size * 5) / size } else { 0 }
151 );
152 }
153}
154
155fn benchmark_memory_efficiency() {
157 println!("\nTesting memory usage efficiency...");
158
159 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
160 context.set_memory_limit(1024 * 1024); let partition = context.create_partition(64 * 1024, 16 * 1024);
162
163 let small_objects_count = 1000;
165 let mut small_objects = Vec::new();
166
167 for _i in 0..small_objects_count {
168 let obj = unsafe { context.alloc_raw(partition, SmallData {}) }.unwrap();
169 small_objects.push(obj);
170 }
171
172 if let Some(partition_info) = context.partition(partition) {
173 let used = partition_info.memory_used();
174 let limit = context.memory_limit();
175 let efficiency = if limit > 0 {
176 (used as f64 / limit as f64) * 100.0
177 } else {
178 0.0
179 };
180
181 println!(" After allocating {} small objects:", small_objects_count);
182 println!(
183 " Memory usage: {}/{} bytes ({:.1}%)",
184 used, limit, efficiency
185 );
186 println!(
187 " Average overhead per object: {} bytes",
188 if small_objects_count > 0 {
189 used / small_objects_count
190 } else {
191 0
192 }
193 );
194 }
195
196 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
198 println!(" Collected all objects, freed {} bytes", freed);
199
200 if let Some(partition_info) = context.partition(partition) {
202 let used_after = partition_info.memory_used();
203 println!(" Memory usage after collection: {} bytes", used_after);
204 println!(
205 " Memory collection rate: {:.1}%",
206 if freed > 0 {
207 (freed as f64 / (freed + used_after) as f64) * 100.0
208 } else {
209 0.0
210 }
211 );
212 }
213}
214
215fn benchmark_auto_gc_threshold() {
217 println!("\nTesting automatic GC threshold performance...");
218
219 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
220 context.set_memory_limit(2048); let partition = context.create_partition(64 * 1024, 16 * 1024);
222
223 context.set_gc_threshold(1500);
225
226 let mut allocated_bytes = 0;
228 let mut object_count = 0;
229
230 println!(" Allocating objects until automatic GC is triggered...");
231
232 for _i in 0..100 {
233 let node = SimpleNode {
236 _data: vec![0u8; 100],
237 };
238 match unsafe { context.alloc_raw(partition, node) } {
239 Ok(_gc_ref) => {
240 allocated_bytes += 100 + std::mem::size_of::<GcRef<SimpleNode>>(); object_count += 1;
242
243 if let Some(partition_info) = context.partition(partition)
245 && partition_info.memory_used() >= 1500
246 {
247 println!(
248 " Reached automatic GC threshold, allocated {} objects",
249 object_count
250 );
251 println!(" Estimated allocated memory: {} bytes", allocated_bytes);
252 println!(
253 " Actual memory usage: {} bytes",
254 partition_info.memory_used()
255 );
256 break;
257 }
258 }
259 Err(_) => {
260 println!(" Allocation failed, automatic GC may have been triggered");
261 break;
262 }
263 }
264 }
265
266 let freed = context.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
268 println!(" Manual GC freed {} bytes", freed);
269}
270
271#[derive(Debug)]
275struct SimpleNode {
276 _data: Vec<u8>,
277}
278
279impl GcTrace for SimpleNode {
280 fn trace(&self, _: &mut GcTraceCtx) {}
281}
282
283#[derive(Debug)]
285struct GraphNode {
286 neighbors: Vec<GcRef<GraphNode>>,
287}
288
289impl GcTrace for GraphNode {
290 fn trace(&self, tr: &mut GcTraceCtx) {
291 for neighbor in &self.neighbors {
292 tr.add(*neighbor);
293 }
294 }
295}
296
297#[derive(Debug)]
299struct SmallData {
300 }
302
303impl GcTrace for SmallData {
304 fn trace(&self, _: &mut GcTraceCtx) {}
305}
306
307gc_type_register! {
308 SimpleNode;
309 GraphNode;
310 SmallData;
311}