pub fn get_ticks() -> TicksExpand description
Capture the current time. (b2GetTicks)
Examples found in repository?
examples/benchmark/main.rs (line 251)
82fn main() {
83 let benchmarks: [Benchmark; 10] = [
84 Benchmark {
85 name: "compounds",
86 create_fcn: scenes::create_compounds,
87 step_fcn: None,
88 total_step_count: 500,
89 },
90 Benchmark {
91 name: "joint_grid",
92 create_fcn: scenes::create_joint_grid,
93 step_fcn: None,
94 total_step_count: 500,
95 },
96 Benchmark {
97 name: "junkyard",
98 create_fcn: scenes::create_junkyard,
99 step_fcn: Some(scenes::step_junkyard),
100 total_step_count: 800,
101 },
102 Benchmark {
103 name: "large_pyramid",
104 create_fcn: scenes::create_large_pyramid,
105 step_fcn: None,
106 total_step_count: 500,
107 },
108 Benchmark {
109 name: "many_pyramids",
110 create_fcn: scenes::create_many_pyramids,
111 step_fcn: None,
112 total_step_count: 200,
113 },
114 Benchmark {
115 name: "rain",
116 create_fcn: scenes::create_rain,
117 step_fcn: Some(scenes::step_rain),
118 total_step_count: 1000,
119 },
120 Benchmark {
121 name: "smash",
122 create_fcn: scenes::create_smash,
123 step_fcn: None,
124 total_step_count: 300,
125 },
126 Benchmark {
127 name: "spinner",
128 create_fcn: scenes::create_spinner,
129 step_fcn: Some(scenes::step_spinner),
130 total_step_count: 500,
131 },
132 Benchmark {
133 name: "tumbler",
134 create_fcn: scenes::create_tumbler,
135 step_fcn: None,
136 total_step_count: 750,
137 },
138 Benchmark {
139 name: "washer",
140 create_fcn: scenes::create_washer,
141 step_fcn: None,
142 total_step_count: 500,
143 },
144 ];
145
146 let benchmark_count = benchmarks.len() as i32;
147
148 let mut max_steps = benchmarks[0].total_step_count;
149 for b in benchmarks.iter().skip(1) {
150 max_steps = max_steps.max(b.total_step_count);
151 }
152
153 // Profiles persist across all benchmarks, exactly like the C array that is
154 // allocated once before the benchmark loop and never reset.
155 let mut profiles: Vec<Profile> = vec![max_profile(); max_steps as usize];
156 let mut step_results: Vec<f32> = vec![0.0; max_steps as usize];
157
158 let mut run_count = 4;
159 let mut single_benchmark = -1;
160 let mut enable_continuous = true;
161 let mut record_step_times = false;
162
163 for arg in std::env::args().skip(1) {
164 if let Some(value) = arg.strip_prefix("-t=") {
165 // Serial port: the worker count is fixed at 1.
166 let _ = value.parse::<i32>().unwrap_or(0);
167 println!("Note: '-t' ignored; the Rust port runs a single-threaded solver");
168 } else if let Some(value) = arg.strip_prefix("-b=") {
169 single_benchmark = value.parse::<i32>().unwrap_or(0);
170 single_benchmark = clamp_int(single_benchmark, 0, benchmark_count - 1);
171 } else if let Some(value) = arg.strip_prefix("-w=") {
172 // Serial port: a single worker count is the only option.
173 let _ = value.parse::<i32>().unwrap_or(0);
174 println!("Note: '-w' ignored; the Rust port runs a single-threaded solver");
175 } else if let Some(value) = arg.strip_prefix("-r=") {
176 run_count = clamp_int(value.parse::<i32>().unwrap_or(0), 1, 1000);
177 } else if arg.starts_with("-nc") {
178 enable_continuous = false;
179 println!("Continuous disabled");
180 } else if arg.starts_with("-s") {
181 record_step_times = true;
182 } else if arg == "-h" {
183 println!(
184 "Usage\n\
185 -t=<integer>: the maximum number of threads to use (ignored, serial port)\n\
186 -b=<integer>: run a single benchmark\n\
187 -w=<integer>: run a single worker count (ignored, serial port)\n\
188 -r=<integer>: number of repeats (default is 4)\n\
189 -nc: disable continuous collision\n\
190 -s: record step times"
191 );
192 std::process::exit(0);
193 }
194 }
195
196 println!("Starting Box2D benchmarks");
197 println!("======================================");
198
199 // mirrors C's indexed loop
200 #[allow(clippy::needless_range_loop)]
201 for benchmark_index in 0..benchmark_count as usize {
202 if single_benchmark != -1 && benchmark_index as i32 != single_benchmark {
203 continue;
204 }
205
206 let benchmark = &benchmarks[benchmark_index];
207
208 // NDEBUG uses the full step count; debug builds cap at 10 like the C.
209 let step_count = if cfg!(debug_assertions) {
210 10
211 } else {
212 benchmark.total_step_count
213 };
214
215 let mut counters = box2d_rust::types::Counters::default();
216 let mut counters_acquired = false;
217
218 println!("benchmark: {}, steps = {}", benchmark.name, step_count);
219
220 // Single thread only in the serial port.
221 let mut min_time = 0.0f32;
222
223 println!("thread count: 1");
224
225 for run_index in 0..run_count {
226 let world_def = {
227 let mut wd = default_world_def();
228 wd.enable_continuous = enable_continuous;
229 wd.worker_count = 1;
230 wd
231 };
232 let mut world = World::new(&world_def);
233
234 (benchmark.create_fcn)(&mut world);
235
236 let time_step = 1.0 / 60.0;
237 let sub_step_count = 4;
238
239 // Initial step can be expensive and skew benchmark.
240 if let Some(step_fcn) = benchmark.step_fcn {
241 step_results[0] = step_fcn(&mut world, 0);
242 }
243
244 debug_assert!(step_count <= max_steps);
245
246 world_step(&mut world, time_step, sub_step_count);
247
248 let profile = world_get_profile(&world);
249 min_profile(&mut profiles[0], &profile);
250
251 let ticks = get_ticks();
252
253 for step_index in 1..step_count {
254 if let Some(step_fcn) = benchmark.step_fcn {
255 step_results[step_index as usize] = step_fcn(&mut world, step_index);
256 }
257
258 world_step(&mut world, time_step, sub_step_count);
259 let profile = world_get_profile(&world);
260 min_profile(&mut profiles[step_index as usize], &profile);
261 }
262
263 let ms = get_milliseconds(ticks);
264 println!("run {} : {} (ms)", run_index, ms);
265
266 if run_index == 0 {
267 min_time = ms;
268 } else {
269 min_time = min_float(min_time, ms);
270 }
271
272 if !counters_acquired {
273 counters = world_get_counters(&world);
274 counters_acquired = true;
275 }
276
277 // b2DestroyWorld: dropping the world frees it.
278 drop(world);
279 }
280
281 if record_step_times {
282 let file_name = format!("{}_t1.dat", benchmark.name);
283 if let Ok(mut file) = File::create(&file_name) {
284 // mirrors C's indexed loop
285 #[allow(clippy::needless_range_loop)]
286 for step_index in 0..step_count as usize {
287 let p = profiles[step_index];
288 let _ = writeln!(
289 file,
290 "{} {} {} {} {} {} {}",
291 p.step,
292 p.pairs,
293 p.collide,
294 p.constraints,
295 p.transforms,
296 p.refit,
297 p.sleep_islands
298 );
299 }
300 }
301 }
302
303 println!(
304 "body {} / shape {} / contact {} / joint {} / stack {}",
305 counters.body_count,
306 counters.shape_count,
307 counters.contact_count,
308 counters.joint_count,
309 counters.stack_used
310 );
311 print!("color counts:");
312 for c in counters.color_counts.iter() {
313 print!(" {}", c);
314 }
315 println!("\n");
316
317 let file_name = format!("{}.csv", benchmark.name);
318 if let Ok(mut file) = File::create(&file_name) {
319 let _ = writeln!(file, "threads,ms");
320 let _ = writeln!(file, "1,{}", min_time);
321 }
322 }
323
324 println!("======================================");
325 println!("All Box2D benchmarks complete!");
326}