@@ -418,37 +418,155 @@ async def statement(phase, sql):
418418
419419
420420def build_initialization_section (benchmark_runs , options ):
421+ """Separate measured loading counters from DDL and maintenance timings."""
422+ labels = {
423+ 'schema' : 'Create schema' ,
424+ 'unlogged' : 'Set tables UNLOGGED' ,
425+ 'prepare' : 'Prepare generator' ,
426+ 'data' : 'Load data' ,
427+ 'after_data' : 'Post-load processing' ,
428+ 'logged' : 'Set tables LOGGED' ,
429+ 'indexes' : 'Build indexes' ,
430+ 'constraints' : 'Apply constraints' ,
431+ 'finalize' : 'Finalize dataset' ,
432+ 'vacuum' : 'Vacuum and freeze' ,
433+ 'analyze' : 'Analyze relations' ,
434+ 'restore_settings_and_sync' : 'Restore durability settings' ,
435+ }
421436 reports = {}
422437 for run in benchmark_runs :
423438 evidence = run .get ('initialization' )
424439 if evidence is None :
425440 continue
426441 index = run ['iteration' ]['index' ]
427- rows = []
442+ groups = {}
443+ loads = []
444+ operations = []
428445 for phase in evidence ['phases' ]:
429- tasks = phase .get ('tasks' , [])
430- rows .append (
431- [
432- phase ['name' ],
433- round (phase ['elapsed_seconds' ], 3 ),
434- sum (task ['rows' ] for task in tasks ),
435- sum (task ['batches' ] for task in tasks ),
436- ]
437- )
446+ kind = phase ['name' ].split (':' , 1 )[0 ]
447+ group = groups .setdefault (kind , {'seconds' : 0.0 , 'phases' : [], 'tasks' : []})
448+ group ['seconds' ] += phase ['elapsed_seconds' ]
449+ group ['phases' ].append (phase )
450+ group ['tasks' ].extend (phase .get ('tasks' , []))
451+ if kind == 'data' :
452+ for task in phase .get ('tasks' , []):
453+ loads .append (
454+ [
455+ task ['name' ],
456+ round (task ['worker_seconds' ], 3 ),
457+ f'Rows inserted: { task ["rows" ]:,} ; batches: { task ["batches" ]:,} ' ,
458+ ]
459+ )
460+ elif kind in ('indexes' , 'constraints' ):
461+ # Aggregate timings already appear in the summary. Listing them
462+ # again beside individual tasks invites double-counting.
463+ action = 'Build index' if kind == 'indexes' else 'Apply constraint'
464+ for task in phase .get ('tasks' , []):
465+ operations .append (
466+ [
467+ action ,
468+ round (task ['worker_seconds' ], 3 ),
469+ f'{ task ["name" ]} ; completed executions: { task ["batches" ]:,} . '
470+ 'Time includes execution and commit.' ,
471+ ]
472+ )
473+ else :
474+ relation = phase ['name' ].partition (':' )[2 ]
475+ description = {
476+ 'schema' : 'Create profile schemas and supporting objects: '
477+ + ', ' .join (evidence .get ('schemas' , [])),
478+ 'unlogged' : f'Set { relation } to UNLOGGED before bulk loading.' ,
479+ 'logged' : (
480+ f'Set { relation } to LOGGED before bulk loading.'
481+ if options ['table_mode' ] == 'logged'
482+ else f'Restore WAL logging for { relation } after loading.'
483+ ),
484+ 'vacuum' : f'VACUUM (FREEZE, ANALYZE) { relation } : freeze rows and '
485+ 'refresh visibility and planner statistics.' ,
486+ 'prepare' : 'Execute profile setup SQL for data generation.' ,
487+ 'after_data' : 'Execute profile post-load SQL, including declared '
488+ 'data corrections; affected rows are not recorded.' ,
489+ 'finalize' : 'Execute profile finalization SQL, such as materialized '
490+ 'view refresh and workload bounds setup.' ,
491+ 'analyze' : 'ANALYZE profile relations, including partitioned parents.' ,
492+ 'restore_settings_and_sync' : 'Restore pre-load durability settings; '
493+ 'checkpoint and sync only if fsync changed.' ,
494+ }.get (kind , f'Execute custom initialization step { phase ["name" ]} .' )
495+ operations .append (
496+ [
497+ labels .get (kind , kind ),
498+ round (phase ['elapsed_seconds' ], 3 ),
499+ description ,
500+ ]
501+ )
502+
503+ summary = []
504+ for kind , group in groups .items ():
505+ tasks = group ['tasks' ]
506+ if kind == 'data' :
507+ inserted = sum (task ['rows' ] for task in tasks )
508+ batches = sum (task ['batches' ] for task in tasks )
509+ work = f'{ inserted :,} rows inserted; { len (tasks ):,} load tasks; { batches :,} batches'
510+ elif kind in ('indexes' , 'constraints' ):
511+ work = f'Tasks: { len (tasks ):,} ; executions: { sum (t ["batches" ] for t in tasks ):,} '
512+ elif kind in ('unlogged' , 'logged' , 'vacuum' ):
513+ work = f'{ len (group ["phases" ]):,} relations'
514+ else :
515+ work = {
516+ 'schema' : 'Create tables and supporting objects' ,
517+ 'prepare' : 'Install generator helpers' ,
518+ 'after_data' : 'Apply profile post-processing; row counts not collected' ,
519+ 'finalize' : 'Run profile finalization SQL' ,
520+ 'analyze' : 'Refresh planner statistics' ,
521+ 'restore_settings_and_sync' : 'Restore settings; sync storage if fsync changed' ,
522+ }.get (kind , 'Execute profile SQL; row counts not collected' )
523+ summary .append ([labels .get (kind , kind ), round (group ['seconds' ], 3 ), work ])
438524 barrier = evidence ['replication_barrier' ]
439- rows .append (['replica_replay_barrier' , round (barrier ['elapsed_seconds' ], 3 ), None , None ])
525+ summary .append (
526+ [
527+ 'Wait for replica replay' ,
528+ round (barrier ['elapsed_seconds' ], 3 ),
529+ f'{ barrier ["replicas" ]} replicas caught up to { barrier ["target_lsn" ]} ' ,
530+ ]
531+ )
440532 reports [f'iteration_{ index } ' ] = {
441- 'header' : f'Iteration { index } : initialization phases' ,
442- 'description' : f'Workers: { options ["workers" ]} ; batch rows: { options ["batch_rows" ]} ; '
443- f'tables during load: { options ["table_mode" ]} ; fsync during load: { options ["fsync" ]} ; '
444- f'loader synchronous_commit: { options ["synchronous_commit" ]} . '
445- f'Final fsync: { evidence ["fsync_after" ]} ; replicas caught up: { barrier ["replicas" ]} ; '
446- f'replay target: { barrier ["target_lsn" ]} . '
447- 'Rows and batches describe data jobs; elapsed times are wall-clock seconds.' ,
533+ 'header' : f'Iteration { index } : initialization summary' ,
534+ 'description' : f'Up to { options ["workers" ]} load workers; '
535+ f'batch limit: { options ["batch_rows" ]:,} rows. '
536+ f'Tables during load: { options ["table_mode" ]} ; fsync policy: { options ["fsync" ]} ; '
537+ f'synchronous_commit policy: { options ["synchronous_commit" ]} ; '
538+ f'fsync after initialization: { evidence ["fsync_after" ]} . '
539+ 'Times are measured elapsed seconds per stage; per-relation operations are grouped. '
540+ 'Parallel worker times are not added to stage elapsed time.' ,
448541 'item_type' : 'table' ,
449542 'state' : 'expanded' ,
450543 'collection_status' : 'ok' ,
451- 'theader' : ['phase' , 'elapsed_seconds' , 'rows' , 'jobs' ],
452- 'data' : rows ,
544+ 'theader' : ['Stage' , 'Elapsed (s)' , 'Work performed' ],
545+ 'data' : summary ,
546+ }
547+ reports [f'iteration_{ index } _loading' ] = {
548+ 'header' : f'Iteration { index } : data loading by task' ,
549+ 'description' : 'Inserted rows come from PostgreSQL INSERT/COPY completion counts. '
550+ 'They are not final table sizes: post-load processing may update or delete rows. '
551+ 'Batches count successful loader executions, including single-statement tasks. '
552+ 'Worker time is cumulative execution time including commit, not wall-clock time. '
553+ 'Task names identify loader jobs, not necessarily physical tables; inserting into '
554+ 'a partitioned parent routes rows to its partitions without separate loader jobs.' ,
555+ 'item_type' : 'table' ,
556+ 'state' : 'collapsed' ,
557+ 'collection_status' : 'ok' ,
558+ 'theader' : ['Load task' , 'Worker time (s)' , 'Details' ],
559+ 'data' : loads ,
560+ }
561+ reports [f'iteration_{ index } _operations' ] = {
562+ 'header' : f'Iteration { index } : SQL and maintenance details' ,
563+ 'description' : 'Individual operations, without the stage totals already shown above. '
564+ 'Each row describes the work actually timed. Index tasks can run in parallel, '
565+ 'so adding these times does not give total initialization elapsed time.' ,
566+ 'item_type' : 'table' ,
567+ 'state' : 'collapsed' ,
568+ 'collection_status' : 'ok' ,
569+ 'theader' : ['Operation' , 'Time (s)' , 'Description' ],
570+ 'data' : operations ,
453571 }
454572 return {'header' : 'Database initialization' , 'state' : 'expanded' , 'reports' : reports }
0 commit comments