@@ -235,10 +235,13 @@ pub struct BlockOptions {
235235 pub drop_streamed_ops : bool ,
236236 /// With windows: `0` lays each streamed chunk out on the layout thread as
237237 /// it arrives; `n > 0` lays them out on `n` threads, packed in arrival
238- /// order all the same, while the layout thread lays out the rest of the
239- /// run as soon as it is built. Production: 0. Three read −0.54 / −0.22 s of
240- /// base (FAST 421 / 422), but their extra host memory grows with the block
241- /// (BIG 390: +2.2 / +4.2 / +8.7 GiB at 1.0 / 1.3 / 1.8×).
238+ /// order all the same (the same groups and proof bytes), while the layout
239+ /// thread lays out the rest of the run as soon as it is built. Production:
240+ /// 3. Once phase A uploads ahead, the inline layout closes the middle groups
241+ /// after the card is free; three workers close them in time (FAST 835:
242+ /// phase A −0.93 s, whole block −1.00 s, peak −0.68 GiB at 1×). Unbounded
243+ /// they held more host memory as the block grew (BIG 390); `layout_ahead`
244+ /// bounds them (BIG 392: flat).
242245 pub layout_workers : usize ,
243246 /// With `layout_workers > 0`: `Some(k)` lets at most `k + 1` streamed
244247 /// chunks be laid out (or in the making) and not yet packed, where the
@@ -247,7 +250,12 @@ pub struct BlockOptions {
247250 pub layout_ahead : Option < usize > ,
248251 /// With `layout_workers > 0`: pack the rest of the run as it is laid out,
249252 /// in AIR order, so a group closes once its own tables are ready instead
250- /// of after all of them; the packing order is the same.
253+ /// of after all of them; the packing order is the same. Production: on,
254+ /// with [`Self::rest_layout_bytes`]'s waves — laid out all at once, the
255+ /// first table in AIR order was ready only with the last, and packing as
256+ /// laid out read +0.21 s (FAST 422); in waves the AIR order's prefix is
257+ /// laid out first, and since three layout workers (04984808d) phase A
258+ /// waits on the groups the rest closes.
251259 pub pack_rest_as_laid_out : bool ,
252260 /// How phase A holds each group's columns once committed
253261 /// ([`multilinear_block::Narrowing`]): production packs them narrow on the
@@ -302,9 +310,9 @@ impl BlockOptions {
302310 stream_keccak_rnd : false ,
303311 stream_memw_lt : false ,
304312 drop_streamed_ops : true ,
305- layout_workers : 0 ,
313+ layout_workers : 3 ,
306314 layout_ahead : Some ( 2 ) ,
307- pack_rest_as_laid_out : false ,
315+ pack_rest_as_laid_out : true ,
308316 narrow : multilinear_block:: Narrowing :: CARD ,
309317 upload_ahead : true ,
310318 memlog : memlog:: from_env ( ) ,
@@ -518,6 +526,9 @@ pub struct LayoutStamps {
518526 /// The rest's tables laid out narrow from the finish's packed columns
519527 /// ([`BlockOptions::pack_finished`]): how many, and their packed bytes.
520528 pub packed_rest : ( usize , usize ) ,
529+ /// Each table of the rest in AIR order: its name, when its layout ended
530+ /// (seconds since the prove started) and its group.
531+ pub rest_tables : Vec < ( String , f64 , usize ) > ,
521532}
522533
523534impl BlockStamps {
@@ -536,7 +547,7 @@ impl BlockStamps {
536547 ) ;
537548 for ( g, s) in self . groups . iter ( ) . enumerate ( ) {
538549 out. push_str ( & format ! (
539- "BLOCK GROUP {g}: tables {} · polys {} · cells {:.1} M || A wait {:.3} upload {:.3} paid {:.3} commit {:.3} retire {:.3} done@{:.2} || B upload {:.3} argue {:.3} encode {:.3} open {:.3}\n " ,
550+ "BLOCK GROUP {g}: tables {} · polys {} · cells {:.1} M || A wait {:.3} upload {:.3} paid {:.3} commit {:.3} retire {:.3} from@{:.2} done@{:.2} || B upload {:.3} argue {:.3} encode {:.3} open {:.3}\n " ,
540551 s. tables,
541552 s. polys,
542553 s. cells as f64 / 1e6 ,
@@ -545,6 +556,7 @@ impl BlockStamps {
545556 s. upload_paid,
546557 s. commit,
547558 s. retire,
559+ s. committed_at - s. commit - s. retire,
548560 s. committed_at,
549561 s. upload_b,
550562 s. argue,
@@ -607,6 +619,15 @@ impl BlockStamps {
607619 l. packed_rest. 0 ,
608620 l. packed_rest. 1 as f64 / ( 1u64 << 30 ) as f64 ,
609621 ) ) ;
622+ let tables: Vec < String > = l
623+ . rest_tables
624+ . iter ( )
625+ . map ( |( name, at, group) | format ! ( "{name}@{at:.2}·g{group}" ) )
626+ . collect ( ) ;
627+ out. push_str ( & format ! (
628+ "BLOCK REST TABLES (laid out at · group): {}\n " ,
629+ tables. join( " " )
630+ ) ) ;
610631 }
611632 out. push_str ( & format ! (
612633 "BLOCK RECOMMIT: 0 (a revived commitment builds no tree) · first-round paths from kept tops: {} calls · {} leaves re-hashed on the host · phase B on one thread + one upload helper\n " ,
@@ -2283,6 +2304,9 @@ struct RestLaid<'a> {
22832304 busy : f64 ,
22842305 /// [`LayoutStamps::packed_rest`].
22852306 packed_rest : ( usize , usize ) ,
2307+ /// Each table's AIR index and when its layout ended (seconds since the
2308+ /// prove started), in AIR order.
2309+ laid_at : Vec < ( usize , f64 ) > ,
22862310}
22872311
22882312/// `prepared_now`: derive the prepared columns here, before the tables are
@@ -2351,8 +2375,9 @@ fn lay_out_rest<'a>(
23512375 . enumerate ( )
23522376 . filter ( |( _, ( ( _, trace, _) , _) ) | trace. main_table . width != 0 )
23532377 . collect ( ) ;
2354- // Each table's seconds, for the readout, and the tables laid out narrow .
2378+ // Each table's seconds and when its layout ended, for the readout .
23552379 let timed = std:: sync:: Mutex :: new ( Vec :: with_capacity ( built. len ( ) ) ) ;
2380+ let laid_at = std:: sync:: Mutex :: new ( Vec :: with_capacity ( built. len ( ) ) ) ;
23562381 let narrow_tables = std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ;
23572382 let narrow_bytes = std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ;
23582383 let lay_out = |( i, ( ( _, trace, _) , air) ) : ( usize , ( ( _ , & mut TraceTable < F , E > , _ ) , _ ) ) | {
@@ -2371,6 +2396,9 @@ fn lay_out_rest<'a>(
23712396 table_of ( air, trace, shape, true )
23722397 }
23732398 . map ( |table| ( i, shape, table) ) ;
2399+ if let Ok ( mut laid_at) = laid_at. lock ( ) {
2400+ laid_at. push ( ( i, start. elapsed ( ) . as_secs_f64 ( ) ) ) ;
2401+ }
23742402 if let ( Some ( ledger) , Ok ( ( _, _, table) ) ) = ( ledger, & laid) {
23752403 use std:: sync:: atomic:: Ordering :: Relaxed ;
23762404 ledger. rest . fetch_sub ( rows, Relaxed ) ;
@@ -2472,6 +2500,11 @@ fn lay_out_rest<'a>(
24722500 slowest,
24732501 busy : t. elapsed ( ) . as_secs_f64 ( ) ,
24742502 packed_rest : ( narrow_tables. into_inner ( ) , narrow_bytes. into_inner ( ) ) ,
2503+ laid_at : {
2504+ let mut laid_at = laid_at. into_inner ( ) . unwrap_or_default ( ) ;
2505+ laid_at. sort_unstable_by_key ( |& ( i, _) | i) ;
2506+ laid_at
2507+ } ,
24752508 } )
24762509}
24772510
@@ -2801,6 +2834,7 @@ fn prove_streamed(
28012834 slowest,
28022835 busy: rest_busy,
28032836 packed_rest,
2837+ laid_at,
28042838 } = rest;
28052839 let names: std:: collections:: HashMap <String , usize > = refs
28062840 . iter( )
@@ -2877,6 +2911,16 @@ fn prove_streamed(
28772911 } )
28782912 . collect:: <Result <Vec <_>, Error >>( ) ?;
28792913 let busy = chunks + rest_busy + t. elapsed( ) . as_secs_f64( ) ;
2914+ let group_of = |table: usize | {
2915+ groups
2916+ . iter( )
2917+ . position( |g| g. contains( & ( table as u32 ) ) )
2918+ . unwrap_or( usize :: MAX )
2919+ } ;
2920+ let rest_tables = laid_at
2921+ . iter( )
2922+ . map( |& ( i, at) | ( refs[ i] . name( ) . to_string( ) , at, group_of( i) ) )
2923+ . collect( ) ;
28802924 Ok ( Laid {
28812925 table_counts,
28822926 runtime_page_ranges,
@@ -2895,6 +2939,7 @@ fn prove_streamed(
28952939 slowest,
28962940 ahead_most,
28972941 packed_rest,
2942+ rest_tables,
28982943 } ,
28992944 } )
29002945 } ) ;
0 commit comments