@ -103,6 +103,7 @@ static void show_instrumentation_count(const char *qlabel, int which,
PlanState * planstate , ExplainState * es ) ;
PlanState * planstate , ExplainState * es ) ;
static void show_foreignscan_info ( ForeignScanState * fsstate , ExplainState * es ) ;
static void show_foreignscan_info ( ForeignScanState * fsstate , ExplainState * es ) ;
static const char * explain_get_index_name ( Oid indexId ) ;
static const char * explain_get_index_name ( Oid indexId ) ;
static void show_buffer_usage ( ExplainState * es , const BufferUsage * usage ) ;
static void ExplainIndexScanDetails ( Oid indexid , ScanDirection indexorderdir ,
static void ExplainIndexScanDetails ( Oid indexid , ScanDirection indexorderdir ,
ExplainState * es ) ;
ExplainState * es ) ;
static void ExplainScanTarget ( Scan * plan , ExplainState * es ) ;
static void ExplainScanTarget ( Scan * plan , ExplainState * es ) ;
@ -1437,108 +1438,73 @@ ExplainNode(PlanState *planstate, List *ancestors,
/* Show buffer usage */
/* Show buffer usage */
if ( es - > buffers & & planstate - > instrument )
if ( es - > buffers & & planstate - > instrument )
{
show_buffer_usage ( es , & planstate - > instrument - > bufusage ) ;
const BufferUsage * usage = & planstate - > instrument - > bufusage ;
if ( es - > format = = EXPLAIN_FORMAT_TEXT )
/* Show worker detail */
if ( es - > analyze & & es - > verbose & & planstate - > worker_instrument )
{
{
bool has_shared = ( usage - > shared_blks_hit > 0 | |
WorkerInstrumentation * w = planstate - > worker_instrument ;
usage - > shared_blks_read > 0 | |
bool opened_group = false ;
usage - > shared_blks_dirtied > 0 | |
int n ;
usage - > shared_blks_written > 0 ) ;
bool has_local = ( usage - > local_blks_hit > 0 | |
usage - > local_blks_read > 0 | |
usage - > local_blks_dirtied > 0 | |
usage - > local_blks_written > 0 ) ;
bool has_temp = ( usage - > temp_blks_read > 0 | |
usage - > temp_blks_written > 0 ) ;
bool has_timing = ( ! INSTR_TIME_IS_ZERO ( usage - > blk_read_time ) | |
! INSTR_TIME_IS_ZERO ( usage - > blk_write_time ) ) ;
/* Show only positive counter values. */
for ( n = 0 ; n < w - > num_workers ; + + n )
if ( has_shared | | has_local | | has_temp )
{
{
appendStringInfoSpaces ( es - > str , es - > indent * 2 ) ;
Instrumentation * instrument = & w - > instrument [ n ] ;
appendStringInfoString ( es - > str , " Buffers: " ) ;
double nloops = instrument - > nloops ;
double startup_sec ;
double total_sec ;
double rows ;
if ( has_shared )
if ( nloops < = 0 )
continue ;
startup_sec = 1000.0 * instrument - > startup / nloops ;
total_sec = 1000.0 * instrument - > total / nloops ;
rows = instrument - > ntuples / nloops ;
if ( es - > format = = EXPLAIN_FORMAT_TEXT )
{
{
appendStringInfoString ( es - > str , " shared " ) ;
appendStringInfoSpaces ( es - > str , es - > indent * 2 ) ;
if ( usage - > shared_blks_hit > 0 )
appendStringInfo ( es - > str , " Worker %d: " , n ) ;
appendStringInfo ( es - > str , " hit=%ld " ,
if ( es - > timing )
usage - > shared_blks_hit ) ;
appendStringInfo ( es - > str ,
if ( usage - > shared_blks_read > 0 )
" actual time=%.3f..%.3f rows=%.0f loops=%.0f \n " ,
appendStringInfo ( es - > str , " read=%ld " ,
startup_sec , total_sec , rows , nloops ) ;
usage - > shared_blks_read ) ;
else
if ( usage - > shared_blks_dirtied > 0 )
appendStringInfo ( es - > str ,
appendStringInfo ( es - > str , " dirtied=%ld " ,
" actual rows=%.0f loops=%.0f \n " ,
usage - > shared_blks_dirtied ) ;
rows , nloops ) ;
if ( usage - > shared_blks_written > 0 )
es - > indent + + ;
appendStringInfo ( es - > str , " written=%ld " ,
if ( es - > buffers )
usage - > shared_blks_written ) ;
show_buffer_usage ( es , & instrument - > bufusage ) ;
if ( has_local | | has_temp )
es - > indent - - ;
appendStringInfoChar ( es - > str , ' , ' ) ;
}
}
if ( has_local )
else
{
{
appendStringInfoString ( es - > str , " local " ) ;
if ( ! opened_group )
if ( usage - > local_blks_hit > 0 )
appendStringInfo ( es - > str , " hit=%ld " ,
usage - > local_blks_hit ) ;
if ( usage - > local_blks_read > 0 )
appendStringInfo ( es - > str , " read=%ld " ,
usage - > local_blks_read ) ;
if ( usage - > local_blks_dirtied > 0 )
appendStringInfo ( es - > str , " dirtied=%ld " ,
usage - > local_blks_dirtied ) ;
if ( usage - > local_blks_written > 0 )
appendStringInfo ( es - > str , " written=%ld " ,
usage - > local_blks_written ) ;
if ( has_temp )
appendStringInfoChar ( es - > str , ' , ' ) ;
}
if ( has_temp )
{
{
appendStringInfoString ( es - > str , " temp " ) ;
ExplainOpenGroup ( " Workers " , " Workers " , false , es ) ;
if ( usage - > temp_blks_read > 0 )
opened_group = true ;
appendStringInfo ( es - > str , " read=%ld " ,
usage - > temp_blks_read ) ;
if ( usage - > temp_blks_written > 0 )
appendStringInfo ( es - > str , " written=%ld " ,
usage - > temp_blks_written ) ;
}
appendStringInfoChar ( es - > str , ' \n ' ) ;
}
}
ExplainOpenGroup ( " Worker " , NULL , true , es ) ;
ExplainPropertyInteger ( " Worker Number " , n , es ) ;
/* As above, show only positive counter values. */
if ( es - > timing )
if ( has_timing )
{
{
appendStringInfoSpaces ( es - > str , es - > indent * 2 ) ;
ExplainPropertyFloat ( " Actual Startup Time " , startup_sec , 3 , es ) ;
appendStringInfoString ( es - > str , " I/O Timings: " ) ;
ExplainPropertyFloat ( " Actual Total Time " , total_sec , 3 , es ) ;
if ( ! INSTR_TIME_IS_ZERO ( usage - > blk_read_time ) )
appendStringInfo ( es - > str , " read=%0.3f " ,
INSTR_TIME_GET_MILLISEC ( usage - > blk_read_time ) ) ;
if ( ! INSTR_TIME_IS_ZERO ( usage - > blk_write_time ) )
appendStringInfo ( es - > str , " write=%0.3f " ,
INSTR_TIME_GET_MILLISEC ( usage - > blk_write_time ) ) ;
appendStringInfoChar ( es - > str , ' \n ' ) ;
}
}
ExplainPropertyFloat ( " Actual Rows " , rows , 0 , es ) ;
ExplainPropertyFloat ( " Actual Loops " , nloops , 0 , es ) ;
if ( es - > buffers )
show_buffer_usage ( es , & instrument - > bufusage ) ;
ExplainCloseGroup ( " Worker " , NULL , true , es ) ;
}
}
else
{
ExplainPropertyLong ( " Shared Hit Blocks " , usage - > shared_blks_hit , es ) ;
ExplainPropertyLong ( " Shared Read Blocks " , usage - > shared_blks_read , es ) ;
ExplainPropertyLong ( " Shared Dirtied Blocks " , usage - > shared_blks_dirtied , es ) ;
ExplainPropertyLong ( " Shared Written Blocks " , usage - > shared_blks_written , es ) ;
ExplainPropertyLong ( " Local Hit Blocks " , usage - > local_blks_hit , es ) ;
ExplainPropertyLong ( " Local Read Blocks " , usage - > local_blks_read , es ) ;
ExplainPropertyLong ( " Local Dirtied Blocks " , usage - > local_blks_dirtied , es ) ;
ExplainPropertyLong ( " Local Written Blocks " , usage - > local_blks_written , es ) ;
ExplainPropertyLong ( " Temp Read Blocks " , usage - > temp_blks_read , es ) ;
ExplainPropertyLong ( " Temp Written Blocks " , usage - > temp_blks_written , es ) ;
ExplainPropertyFloat ( " I/O Read Time " , INSTR_TIME_GET_MILLISEC ( usage - > blk_read_time ) , 3 , es ) ;
ExplainPropertyFloat ( " I/O Write Time " , INSTR_TIME_GET_MILLISEC ( usage - > blk_write_time ) , 3 , es ) ;
}
}
if ( opened_group )
ExplainCloseGroup ( " Workers " , " Workers " , false , es ) ;
}
}
/* Get ready to display the child plans */
/* Get ready to display the child plans */
@ -2276,6 +2242,113 @@ explain_get_index_name(Oid indexId)
return result ;
return result ;
}
}
/*
* Show buffer usage details .
*/
static void
show_buffer_usage ( ExplainState * es , const BufferUsage * usage )
{
if ( es - > format = = EXPLAIN_FORMAT_TEXT )
{
bool has_shared = ( usage - > shared_blks_hit > 0 | |
usage - > shared_blks_read > 0 | |
usage - > shared_blks_dirtied > 0 | |
usage - > shared_blks_written > 0 ) ;
bool has_local = ( usage - > local_blks_hit > 0 | |
usage - > local_blks_read > 0 | |
usage - > local_blks_dirtied > 0 | |
usage - > local_blks_written > 0 ) ;
bool has_temp = ( usage - > temp_blks_read > 0 | |
usage - > temp_blks_written > 0 ) ;
bool has_timing = ( ! INSTR_TIME_IS_ZERO ( usage - > blk_read_time ) | |
! INSTR_TIME_IS_ZERO ( usage - > blk_write_time ) ) ;
/* Show only positive counter values. */
if ( has_shared | | has_local | | has_temp )
{
appendStringInfoSpaces ( es - > str , es - > indent * 2 ) ;
appendStringInfoString ( es - > str , " Buffers: " ) ;
if ( has_shared )
{
appendStringInfoString ( es - > str , " shared " ) ;
if ( usage - > shared_blks_hit > 0 )
appendStringInfo ( es - > str , " hit=%ld " ,
usage - > shared_blks_hit ) ;
if ( usage - > shared_blks_read > 0 )
appendStringInfo ( es - > str , " read=%ld " ,
usage - > shared_blks_read ) ;
if ( usage - > shared_blks_dirtied > 0 )
appendStringInfo ( es - > str , " dirtied=%ld " ,
usage - > shared_blks_dirtied ) ;
if ( usage - > shared_blks_written > 0 )
appendStringInfo ( es - > str , " written=%ld " ,
usage - > shared_blks_written ) ;
if ( has_local | | has_temp )
appendStringInfoChar ( es - > str , ' , ' ) ;
}
if ( has_local )
{
appendStringInfoString ( es - > str , " local " ) ;
if ( usage - > local_blks_hit > 0 )
appendStringInfo ( es - > str , " hit=%ld " ,
usage - > local_blks_hit ) ;
if ( usage - > local_blks_read > 0 )
appendStringInfo ( es - > str , " read=%ld " ,
usage - > local_blks_read ) ;
if ( usage - > local_blks_dirtied > 0 )
appendStringInfo ( es - > str , " dirtied=%ld " ,
usage - > local_blks_dirtied ) ;
if ( usage - > local_blks_written > 0 )
appendStringInfo ( es - > str , " written=%ld " ,
usage - > local_blks_written ) ;
if ( has_temp )
appendStringInfoChar ( es - > str , ' , ' ) ;
}
if ( has_temp )
{
appendStringInfoString ( es - > str , " temp " ) ;
if ( usage - > temp_blks_read > 0 )
appendStringInfo ( es - > str , " read=%ld " ,
usage - > temp_blks_read ) ;
if ( usage - > temp_blks_written > 0 )
appendStringInfo ( es - > str , " written=%ld " ,
usage - > temp_blks_written ) ;
}
appendStringInfoChar ( es - > str , ' \n ' ) ;
}
/* As above, show only positive counter values. */
if ( has_timing )
{
appendStringInfoSpaces ( es - > str , es - > indent * 2 ) ;
appendStringInfoString ( es - > str , " I/O Timings: " ) ;
if ( ! INSTR_TIME_IS_ZERO ( usage - > blk_read_time ) )
appendStringInfo ( es - > str , " read=%0.3f " ,
INSTR_TIME_GET_MILLISEC ( usage - > blk_read_time ) ) ;
if ( ! INSTR_TIME_IS_ZERO ( usage - > blk_write_time ) )
appendStringInfo ( es - > str , " write=%0.3f " ,
INSTR_TIME_GET_MILLISEC ( usage - > blk_write_time ) ) ;
appendStringInfoChar ( es - > str , ' \n ' ) ;
}
}
else
{
ExplainPropertyLong ( " Shared Hit Blocks " , usage - > shared_blks_hit , es ) ;
ExplainPropertyLong ( " Shared Read Blocks " , usage - > shared_blks_read , es ) ;
ExplainPropertyLong ( " Shared Dirtied Blocks " , usage - > shared_blks_dirtied , es ) ;
ExplainPropertyLong ( " Shared Written Blocks " , usage - > shared_blks_written , es ) ;
ExplainPropertyLong ( " Local Hit Blocks " , usage - > local_blks_hit , es ) ;
ExplainPropertyLong ( " Local Read Blocks " , usage - > local_blks_read , es ) ;
ExplainPropertyLong ( " Local Dirtied Blocks " , usage - > local_blks_dirtied , es ) ;
ExplainPropertyLong ( " Local Written Blocks " , usage - > local_blks_written , es ) ;
ExplainPropertyLong ( " Temp Read Blocks " , usage - > temp_blks_read , es ) ;
ExplainPropertyLong ( " Temp Written Blocks " , usage - > temp_blks_written , es ) ;
ExplainPropertyFloat ( " I/O Read Time " , INSTR_TIME_GET_MILLISEC ( usage - > blk_read_time ) , 3 , es ) ;
ExplainPropertyFloat ( " I/O Write Time " , INSTR_TIME_GET_MILLISEC ( usage - > blk_write_time ) , 3 , es ) ;
}
}
/*
/*
* Add some additional details about an IndexScan or IndexOnlyScan
* Add some additional details about an IndexScan or IndexOnlyScan
*/
*/