Deserialize from the `.ixes` binary format.
(bytes: &[u8])
| 1428 | num_shards: num_shards as u32, |
| 1429 | shards, |
| 1430 | total_cross_ingress: total_cross, |
| 1431 | tree: None, |
| 1432 | } |
| 1433 | } |
| 1434 | |
| 1435 | /// Attach the bisection tree (from [`Hypergraph::partition_with_tree`]) for |
| 1436 | /// tree-aligned aggregation. |
| 1437 | #[must_use] |
| 1438 | pub fn with_tree(mut self, tree: AggNode) -> Self { |
| 1439 | self.tree = Some(tree); |
| 1440 | self |
| 1441 | } |
| 1442 | |
| 1443 | /// A human-readable what-if summary line. |
| 1444 | pub fn summary(&self) -> String { |
| 1445 | let hbs: Vec<u64> = self.shards.iter().map(|s| s.heartbeats).collect(); |
| 1446 | let nonempty: Vec<u64> = self |
| 1447 | .shards |
| 1448 | .iter() |
| 1449 | .filter(|s| !s.blocks.is_empty()) |
| 1450 | .map(|s| s.heartbeats) |
| 1451 | .collect(); |
| 1452 | let max = hbs.iter().copied().max().unwrap_or(0); |
| 1453 | let min = nonempty.iter().copied().min().unwrap_or(0); |
| 1454 | let total: u128 = hbs.iter().map(|&h| u128::from(h)).sum(); |
| 1455 | let mean = if self.shards.is_empty() { |
| 1456 | 0 |
| 1457 | } else { |
| 1458 | (total / self.shards.len() as u128) as u64 |
| 1459 | }; |
| 1460 | let empty = self.shards.iter().filter(|s| s.blocks.is_empty()).count(); |
| 1461 | let max_cross = |
| 1462 | self.shards.iter().map(|s| s.cross_ingress).max().unwrap_or(0); |
| 1463 | let peaks: Vec<u64> = self |
| 1464 | .shards |
| 1465 | .iter() |
| 1466 | .map(|s| s.measured_peak_bytes) |
| 1467 | .filter(|&p| p != 0) |
| 1468 | .collect(); |
| 1469 | #[allow(clippy::cast_precision_loss)] |
| 1470 | let measured = if peaks.is_empty() { |
| 1471 | String::new() |
| 1472 | } else { |