diff --git a/contrib/Makefile b/contrib/Makefile
index bd251f6..f3d3fe6 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -47,7 +47,8 @@ SUBDIRS = \
 		tsm_system_time \
 		tsearch2	\
 		unaccent	\
-		vacuumlo
+		vacuumlo	\
+		vacuum_progress
 
 ifeq ($(with_openssl),yes)
 SUBDIRS += sslinfo
diff --git a/contrib/vacuum_progress/Makefile b/contrib/vacuum_progress/Makefile
new file mode 100644
index 0000000..5fa5fc4
--- /dev/null
+++ b/contrib/vacuum_progress/Makefile
@@ -0,0 +1,15 @@
+# contrib/passwordcheck/Makefile
+
+MODULE_big = vacuum_progress
+OBJS = vacuum_progress.o $(WIN32RES)
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/vacuum_progress
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/vacuum_progress/vacuum_progress.c b/contrib/vacuum_progress/vacuum_progress.c
new file mode 100644
index 0000000..0c862cb
--- /dev/null
+++ b/contrib/vacuum_progress/vacuum_progress.c
@@ -0,0 +1,126 @@
+/*-------------------------------------------------------------------------
+ *
+ * vacuum_progress.c
+ *
+ * IDENTIFICATION
+ *	  contrib/vacuum_progress/vacuum_progress.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "commands/vacuum.h"
+#include "portability/instr_time.h"
+#include "fmgr.h"
+#include "funcapi.h"
+#include "storage/block.h"
+#include "access/htup_details.h"
+#include "pgstat.h"
+
+PG_MODULE_MAGIC;
+
+extern void _PG_init(void);
+#define SKIP_PAGES_THRESHOLD	((BlockNumber) 32)
+
+typedef struct PgStat_Vacuum
+{
+	instr_time start_time;
+	double elapsed_time;
+	double remaining_time;
+	uint32 total_pages;
+	uint32 scanned_pages;
+	uint32 vacuumed_pages;
+} PgStat_Vacuum;
+
+PgStat_Vacuum backend_stat;
+
+/*
+ * Calculating progress at the end of every page scanned by lazy_scan_heap.
+ * This can be improved to calculate progress at specified intervals only.
+ *
+ * Vacuum Progress is measured in terms of pages scanned
+ * versus total pages to be scanned.
+ */
+
+static void
+calculate_progress(BlockNumber vacuumed_pages, BlockNumber pages_to_be_skipped,
+					BlockNumber scanned_pages)
+{
+	uint32 percent_complete;
+	instr_time elapsed_time;
+	INSTR_TIME_SET_CURRENT(elapsed_time);
+	INSTR_TIME_SUBTRACT(elapsed_time,backend_stat.start_time);
+	backend_stat.elapsed_time = INSTR_TIME_GET_DOUBLE(elapsed_time);
+
+	backend_stat.scanned_pages = scanned_pages;
+	backend_stat.vacuumed_pages = vacuumed_pages;
+
+	if(pages_to_be_skipped > SKIP_PAGES_THRESHOLD)
+	{
+		backend_stat.total_pages = backend_stat.total_pages - pages_to_be_skipped;
+	}
+
+	percent_complete = scanned_pages * 100 / backend_stat.total_pages;
+
+	backend_stat.remaining_time = backend_stat.elapsed_time *
+								(backend_stat.total_pages - scanned_pages) / scanned_pages;
+	elog(LOG,"%d pages vaccumed %d scanned_pages %d total pages\n",
+								vacuumed_pages, scanned_pages, backend_stat.total_pages);
+	elog(LOG,"%f s elapsed time %f s remaining time", backend_stat.elapsed_time,
+								backend_stat.remaining_time);
+}
+
+/*
+ * Storing VACUUM start time and total pages to be scanned
+ * in a global struct shared across backends.
+ */
+static void
+initial_vacuum_stats(BlockNumber total_pages)
+{
+	backend_stat.total_pages= total_pages;
+	INSTR_TIME_SET_CURRENT(backend_stat.start_time);
+}
+
+/*
+ * SQL callable function for creating  a view displaying VACUUM progress
+ */
+PG_FUNCTION_INFO_V1(pg_get_vacuum_progress);
+Datum
+pg_get_vacuum_progress(PG_FUNCTION_ARGS)
+{
+	TupleDesc	tupdesc;
+	Datum				value[5];
+	bool null[5];
+
+	tupdesc = CreateTemplateTupleDesc(5, false);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "VacuumedPages",
+						INT4OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ScannedPages",
+						INT4OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "TotalPages",
+						INT4OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "ElapsedTime",
+						FLOAT8OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "RemainingTime",
+						FLOAT8OID, -1, 0);
+
+	BlessTupleDesc(tupdesc);
+
+	value[0] = UInt32GetDatum(backend_stat.vacuumed_pages);
+	value[1] = UInt32GetDatum(backend_stat.scanned_pages);
+	value[2] = UInt32GetDatum(backend_stat.total_pages);
+	value[3] = Float8GetDatum(backend_stat.elapsed_time);
+	value[4] = Float8GetDatum(backend_stat.remaining_time);
+	PG_RETURN_DATUM(HeapTupleGetDatum(
+								   heap_form_tuple(tupdesc, value, null)));
+}
+
+/*
+ * Module initialization function
+ */
+void
+_PG_init(void)
+{
+	vacuum_stats = calculate_progress;
+	vacuum_stat_initial = initial_vacuum_stats;
+}
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index a01cfb4..6e6bab0 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -157,7 +157,8 @@ static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
 static int	vac_cmp_itemptr(const void *left, const void *right);
 static bool heap_page_is_all_visible(Relation rel, Buffer buf,
 						 TransactionId *visibility_cutoff_xid);
-
+vacuum_stats_type vacuum_stats = NULL;
+vacuum_stats_initial_type vacuum_stat_initial = NULL;
 
 /*
  *	lazy_vacuum_rel() -- perform LAZY VACUUM for one heap relation
@@ -470,8 +471,13 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 
 	indstats = (IndexBulkDeleteResult **)
 		palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
-
 	nblocks = RelationGetNumberOfBlocks(onerel);
+
+	if(vacuum_stat_initial)
+	{
+		(*vacuum_stat_initial)(nblocks);
+	}
+
 	vacrelstats->rel_pages = nblocks;
 	vacrelstats->scanned_pages = 0;
 	vacrelstats->nonempty_pages = 0;
@@ -520,7 +526,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		vacuum_delay_point();
 	}
 	if (next_not_all_visible_block >= SKIP_PAGES_THRESHOLD)
+	{
 		skipping_all_visible_blocks = true;
+	}
 	else
 		skipping_all_visible_blocks = false;
 
@@ -559,7 +567,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			 * following blocks.
 			 */
 			if (next_not_all_visible_block - blkno > SKIP_PAGES_THRESHOLD)
+			{
 				skipping_all_visible_blocks = true;
+			}
 			else
 				skipping_all_visible_blocks = false;
 			all_visible_according_to_vm = false;
@@ -1062,6 +1072,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		 */
 		if (vacrelstats->num_dead_tuples == prev_dead_count)
 			RecordPageWithFreeSpace(onerel, blkno, freespace);
+		if(vacuum_stats)
+		{
+			(*vacuum_stats)(vacuumed_pages, (next_not_all_visible_block - blkno), vacrelstats->scanned_pages);
+		}
 	}
 
 	pfree(frozen);
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index e3a31af..a700b94 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -192,6 +192,15 @@ extern void vacuum_delay_point(void);
 extern void lazy_vacuum_rel(Relation onerel, int options,
 				VacuumParams *params, BufferAccessStrategy bstrategy);
 
+typedef void (*vacuum_stats_type) (BlockNumber vacuumed_pages, BlockNumber pages_to_be_skipped,
+								BlockNumber scanned_pages);
+
+extern PGDLLIMPORT vacuum_stats_type vacuum_stats;
+
+typedef void (*vacuum_stats_initial_type) (BlockNumber nblocks);
+
+extern PGDLLIMPORT vacuum_stats_initial_type vacuum_stat_initial;
+
 /* in commands/analyze.c */
 extern void analyze_rel(Oid relid, RangeVar *relation, int options,
 			VacuumParams *params, List *va_cols, bool in_outer_xact,
