diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 3924a51..f4267ed 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -75,6 +75,12 @@ double		bgwriter_lru_multiplier = 2.0;
  */
 int			target_prefetch_pages = 0;
 
+/*
+ * Counters to measure bgwriter effectiveness.
+ */
+uint64		bgwriter_clean_dirty_before_evict = 0;
+uint64		bgwriter_clean_evict_before_dirty = 0;
+
 /* local state for StartBufferIO and related functions */
 static volatile BufferDesc *InProgressBuf = NULL;
 static bool IsForInput;
@@ -804,7 +810,9 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
 	 * 1 so that the buffer can survive one clock-sweep pass.)
 	 */
 	buf->tag = newTag;
-	buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT);
+	if ((buf->flags & BM_BGWRITER_CLEANED) != 0)
+		++bgwriter_clean_evict_before_dirty;
+	buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT | BM_BGWRITER_CLEANED);
 	if (relpersistence == RELPERSISTENCE_PERMANENT)
 		buf->flags |= BM_TAG_VALID | BM_PERMANENT;
 	else
@@ -976,6 +984,11 @@ MarkBufferDirty(Buffer buffer)
 
 	if (!(bufHdr->flags & BM_DIRTY))
 		dirtied = true;
+	if ((bufHdr->flags & BM_BGWRITER_CLEANED) != 0)
+	{
+		++bgwriter_clean_dirty_before_evict;
+		bufHdr->flags &= ~BM_BGWRITER_CLEANED;
+	}
 
 	bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
 
@@ -1650,6 +1663,13 @@ SyncOneBuffer(int buf_id, bool skip_recently_used)
 	}
 
 	/*
+	 * If skip_recently_used = true, then this is the bgwriter doing cleaning.
+	 * If it's false, this is a checkpoint, so we don't set the flag.
+	 */
+	if (skip_recently_used)
+		bufHdr->flags |= BM_BGWRITER_CLEANED;
+
+	/*
 	 * Pin it, share-lock it, write it.  (FlushBuffer will do nothing if the
 	 * buffer is clean by the time we've locked it.)
 	 */
@@ -1729,6 +1749,11 @@ AtProcExit_Buffers(int code, Datum arg)
 
 	/* localbuf.c needs a chance too */
 	AtProcExit_LocalBuffers();
+
+	elog(LOG,
+		 "bgwriter_clean: " UINT64_FORMAT " evict-before-dirty, "
+         UINT64_FORMAT " dirty-before-evict",
+		 bgwriter_clean_evict_before_dirty, bgwriter_clean_dirty_before_evict);
 }
 
 /*
@@ -2360,7 +2385,14 @@ SetBufferCommitInfoNeedsSave(Buffer buffer)
 		LockBufHdr(bufHdr);
 		Assert(bufHdr->refcount > 0);
 		if (!(bufHdr->flags & BM_DIRTY))
+		{
 			dirtied = true;
+			if ((bufHdr->flags & BM_BGWRITER_CLEANED) != 0)
+			{
+				++bgwriter_clean_dirty_before_evict;
+				bufHdr->flags &= ~BM_BGWRITER_CLEANED;
+			}
+		}
 		bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
 		UnlockBufHdr(bufHdr);
 
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index e43719e..dc70530 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -39,6 +39,7 @@
 #define BM_CHECKPOINT_NEEDED	(1 << 7)		/* must write for checkpoint */
 #define BM_PERMANENT			(1 << 8)		/* permanent relation (not
 												 * unlogged) */
+#define BM_BGWRITER_CLEANED		(1 << 9)		/* bg writer has cleaned it */
 
 typedef bits16 BufFlags;
 
