Like [`shard_esp`] but sized to a per-shard Zisk **cycle** budget (`max_cycles`) rather than a fixed shard count: grows `N` until the heaviest splittable shard fits the budget (see [`partition_for_cycle_cap`]). Use [`cycle_cap_for_ram`] to derive `max_cycles` from a host-RAM target.
( esp_path: &str, max_cycles: u64, balance: f64, parallelism: usize, out_path: Option<&str>, )
| 1577 | // partition can drive max-shard heartbeats below it. When the heaviest shard |
| 1578 | // is pinned at this floor, adding more shards only worsens imbalance — a |
| 1579 | // signal to stop raising the shard count or to split the block. |
| 1580 | let max_block_hb = |
| 1581 | profile.blocks().iter().map(|b| b.heartbeats).max().unwrap_or(0); |
| 1582 | let max_shard_hb = |
| 1583 | manifest.shards.iter().map(|s| s.heartbeats).max().unwrap_or(0); |
| 1584 | let floored = |
| 1585 | num_shards > 1 && max_shard_hb <= max_block_hb.saturating_mul(11) / 10; |
| 1586 | let note = if floored { |
| 1587 | " [balance floored by largest atomic block — more shards won't help]" |
| 1588 | } else { |
| 1589 | "" |
| 1590 | }; |
| 1591 | Ok(format!( |
| 1592 | "blocks={} delta_edges={} nets={}\n{}\n{}\nlargest_block_hb={}{}", |
| 1593 | profile.num_blocks(), |
| 1594 | profile.num_edges(), |
| 1595 | h.num_nets(), |
| 1596 | manifest.summary(), |
| 1597 | prove_report(&profile, &shard_of, &manifest, parallelism), |
| 1598 | max_block_hb, |
| 1599 | note, |
| 1600 | )) |
| 1601 | } |
| 1602 | |
| 1603 | /// Like [`shard_esp`] but sized to a per-shard Zisk **cycle** budget |
| 1604 | /// (`max_cycles`) rather than a fixed shard count: grows `N` until the heaviest |
| 1605 | /// splittable shard fits the budget (see [`partition_for_cycle_cap`]). Use |
| 1606 | /// [`cycle_cap_for_ram`] to derive `max_cycles` from a host-RAM target. |
| 1607 | pub fn shard_esp_cap( |
| 1608 | esp_path: &str, |
| 1609 | max_cycles: u64, |
| 1610 | balance: f64, |
| 1611 | parallelism: usize, |
| 1612 | out_path: Option<&str>, |
| 1613 | ) -> Result<String, String> { |
| 1614 | let bytes = |
| 1615 | std::fs::read(esp_path).map_err(|e| format!("read {esp_path}: {e}"))?; |
| 1616 | let profile = BlockProfile::from_bytes(&bytes) |
| 1617 | .map_err(|e| format!("parse {esp_path}: {e}"))?; |
| 1618 | let plan = partition_for_cycle_cap(&profile, max_cycles, balance); |
| 1619 | let mut manifest = |
| 1620 | ShardManifest::build(&profile, &plan.shard_of, plan.num_shards) |
| 1621 | .with_tree(plan.tree); |
| 1622 | for shard in &mut manifest.shards { |
| 1623 | shard.assumption_root = |
| 1624 | ixon::merkle::merkle_root_canonical(&shard.foreign_blocks); |
no test coverage detected