{
    long        write_secs,
                sync_secs,
-               total_secs;
+               total_secs,
+               longest_secs,
+               average_secs;
    int         write_usecs,
                sync_usecs,
-               total_usecs;
+               total_usecs,
+               longest_usecs,
+               average_usecs;
+   uint64      average_sync_time;
 
    CheckpointStats.ckpt_end_t = GetCurrentTimestamp();
 
                        CheckpointStats.ckpt_sync_end_t,
                        &sync_secs, &sync_usecs);
 
+   /*
+    * Timing values returned from CheckpointStats are in microseconds.
+    * Convert to the second plus microsecond form that TimestampDifference
+    * returns for homogeneous printing.
+    */
+   longest_secs = (long) (CheckpointStats.ckpt_longest_sync / 1000000);
+   longest_usecs = CheckpointStats.ckpt_longest_sync -
+       (uint64) longest_secs * 1000000;
+
+   average_sync_time = 0;
+   if (CheckpointStats.ckpt_sync_rels > 0) 
+       average_sync_time = CheckpointStats.ckpt_agg_sync_time /
+           CheckpointStats.ckpt_sync_rels;
+   average_secs = (long) (average_sync_time / 1000000);
+   average_usecs = average_sync_time - (uint64) average_secs * 1000000;
+
    if (restartpoint)
        elog(LOG, "restartpoint complete: wrote %d buffers (%.1f%%); "
-            "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s",
+            "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
+            "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
             CheckpointStats.ckpt_bufs_written,
             (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
             write_secs, write_usecs / 1000,
             sync_secs, sync_usecs / 1000,
-            total_secs, total_usecs / 1000);
+            total_secs, total_usecs / 1000,
+            CheckpointStats.ckpt_sync_rels,
+            longest_secs, longest_usecs / 1000,
+            average_secs, average_usecs / 1000);
    else
        elog(LOG, "checkpoint complete: wrote %d buffers (%.1f%%); "
             "%d transaction log file(s) added, %d removed, %d recycled; "
-            "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s",
+            "write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
+            "sync files=%d, longest=%ld.%03d s, average=%ld.%03d s",
             CheckpointStats.ckpt_bufs_written,
             (double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
             CheckpointStats.ckpt_segs_added,
             CheckpointStats.ckpt_segs_recycled,
             write_secs, write_usecs / 1000,
             sync_secs, sync_usecs / 1000,
-            total_secs, total_usecs / 1000);
+            total_secs, total_usecs / 1000,
+            CheckpointStats.ckpt_sync_rels,
+            longest_secs, longest_usecs / 1000,
+            average_secs, average_usecs / 1000);
 }
 
 /*
 
 
 #include "catalog/catalog.h"
 #include "miscadmin.h"
+#include "portability/instr_time.h"
 #include "postmaster/bgwriter.h"
 #include "storage/fd.h"
 #include "storage/bufmgr.h"
    PendingOperationEntry *entry;
    int         absorb_counter;
 
+   /* Statistics on sync times */
+   int         processed = 0;
+   instr_time  sync_start,
+               sync_end,
+               sync_diff; 
+   uint64      elapsed;
+   uint64      longest = 0;
+   uint64      total_elapsed = 0;
+
    /*
     * This is only called during checkpoints, and checkpoints should only
     * occur in processes that have created a pendingOpsTable.
                seg = _mdfd_getseg(reln, entry->tag.forknum,
                              entry->tag.segno * ((BlockNumber) RELSEG_SIZE),
                                   false, EXTENSION_RETURN_NULL);
+
+               if (log_checkpoints)
+                   INSTR_TIME_SET_CURRENT(sync_start);
+               else
+                   INSTR_TIME_SET_ZERO(sync_start);
+
                if (seg != NULL &&
                    FileSync(seg->mdfd_vfd) >= 0)
+               {
+                   if (log_checkpoints && (! INSTR_TIME_IS_ZERO(sync_start)))
+                   {
+                       INSTR_TIME_SET_CURRENT(sync_end);
+                       sync_diff = sync_end;
+                       INSTR_TIME_SUBTRACT(sync_diff, sync_start);
+                       elapsed = INSTR_TIME_GET_MICROSEC(sync_diff);
+                       if (elapsed > longest)
+                           longest = elapsed;
+                       total_elapsed += elapsed;
+                       processed++;
+                       elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f msec", 
+                           processed, FilePathName(seg->mdfd_vfd), (double) elapsed / 1000);
+                   }
+
                    break;      /* success; break out of retry loop */
+               }
 
                /*
                 * XXX is there any point in allowing more than one retry?
            elog(ERROR, "pendingOpsTable corrupted");
    }                           /* end loop over hashtable entries */
 
+   /* Return sync performance metrics for report at checkpoint end */
+   CheckpointStats.ckpt_sync_rels = processed;
+   CheckpointStats.ckpt_longest_sync = longest;
+   CheckpointStats.ckpt_agg_sync_time = total_elapsed;
+
    /* Flag successful completion of mdsync */
    mdsync_in_progress = false;
 }