1 # Prediction parameters, not machine bounds or correctness certificates. The 2 # worker count is not a profile value: callers pass the runtime's pool size. 3 import Base 4 5 type Configuration is Data: 6 Configuration{mac_ns: F32,copy_byte_ns: F32,operation_ns: F32,grain_ns: F32,wake_round_ns: F32} 7 8 # One element's cost. Bytes price loading, storing and the loop that moves 9 # them, as the copies that measured copy_byte_ns do; operations are the other 10 # scalar work, counted from source. 11 def element_ns(+bytes: F32,+operations: F32,config: Configuration) -> F32: 12 Configuration{mac_ns,byte_ns,operation_ns,grain,wake} = config 13 (bytes * byte_ns + operations * operation_ns : F32) 14 15 # The official runtime grows fork tasks and queues fork-free tasks for its 16 # work round (monk_step, row_grow, cube_run). No fixed number of leaves can 17 # be subtracted as already completed by growth. Price complete waves of at 18 # most workers leaves, using the largest path (including clones) per wave. 19 # This is a conservative scheduling estimate, not a bound on the runtime's 20 # static ring distribution. Callers charge the two wake rounds separately. 21 def region_ns(+workers: U32,+leaves: U32,+span: F32) -> F32: 22 +pool = U32.max(workers,1) 23 +waves = (leaves / pool + Bool.pick(U32,U32.is_zero((leaves % pool : U32)),0,1) : U32) 24 (span * U32.to_f32(waves) : F32)