| 261 | } |
| 262 | |
| 263 | pub fn build_benchmark_table(results: &[FetchLocalRunBenchmarkResult]) -> String { |
| 264 | // Group results by executor |
| 265 | let mut grouped: HashMap<&ExecutorName, Vec<&FetchLocalRunBenchmarkResult>> = HashMap::new(); |
| 266 | for result in results { |
| 267 | grouped |
| 268 | .entry(&result.benchmark.executor) |
| 269 | .or_default() |
| 270 | .push(result); |
| 271 | } |
| 272 | |
| 273 | // Build tables in a consistent order: Simulation (Valgrind), Walltime, Memory |
| 274 | let executor_order = [ |
| 275 | ExecutorName::Valgrind, |
| 276 | ExecutorName::WallTime, |
| 277 | ExecutorName::Memory, |
| 278 | ]; |
| 279 | |
| 280 | let mut output = String::new(); |
| 281 | for executor in &executor_order { |
| 282 | if let Some(executor_results) = grouped.get(executor) { |
| 283 | if !output.is_empty() { |
| 284 | output.push('\n'); |
| 285 | } |
| 286 | let table = match executor { |
| 287 | ExecutorName::Valgrind => build_simulation_table(executor_results), |
| 288 | ExecutorName::WallTime => build_walltime_table(executor_results), |
| 289 | ExecutorName::Memory => build_memory_table(executor_results), |
| 290 | }; |
| 291 | output.push_str(&table); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | output |
| 296 | } |
| 297 | |
| 298 | pub fn build_detailed_summary(result: &FetchLocalRunBenchmarkResult) -> String { |
| 299 | let name = &result.benchmark.name; |