*** a/src/backend/storage/page/bufpage.c
--- b/src/backend/storage/page/bufpage.c
***************
*** 928,1011 **** PageSetChecksumInplace(Page page, BlockNumber blkno)
  
  /*
   * Calculate checksum for a PostgreSQL Page. This includes the page number (to
   * detect the case when a page is somehow moved to a different location), the
   * page header (excluding the checksum itself), and the page data.
   *
!  * The checksum algorithm is a modified Fletcher 64-bit (which is
!  * order-sensitive). The modification is because, at the end, we have two
!  * 64-bit sums, but we only have room for a 16-bit checksum. So, instead of
!  * using a modulus of 2^32 - 1, we use 2^8 - 1; making it also resemble a
!  * Fletcher 16-bit. We don't use Fletcher 16-bit directly, because processing
!  * single bytes at a time is slower.
   */
  static uint16
  PageCalcChecksum16(Page page, BlockNumber blkno)
  {
! 	PageHeaderData		 header_copy;
! 	uint32				*ptr32Header = (uint32 *) &header_copy;
! 	uint32				*ptr32Page	 = (uint32 *) page;
! 	int64				 sum1		 = 0;
! 	int64				 sum2		 = 0;
  	uint16				 checksum	 = 0;
  	uint8				*p8Checksum	 = (uint8 *) &checksum;
! 	int					 i;
  
  	/* only calculate the checksum for properly-initialized pages */
  	Assert(!PageIsNew(page));
  
  	/*
  	 * Initialize the checksum calculation with the page number. This helps
  	 * catch corruption from whole pages being transposed with other whole
  	 * pages.
  	 */
! 	sum1 = sum2 = (uint64) blkno;
  
  	/*
! 	 * Make a copy of the page header and set the checksum to zero in the
! 	 * copy. That allows us to calculate the checksum 32 bits at a time while
! 	 * ignoring only the checksum field during calculation.
  	 */
! 	memcpy(&header_copy, page, SizeOfPageHeaderData);
! 	header_copy.pd_checksum = 0;
! 
! 	/* compute the checksum of the header */
! 	for (i = 0; i < SizeOfPageHeaderData / sizeof(uint32); i++)
! 	{
! 		sum1 += ptr32Header[i];
! 		sum2 += sum1;
! 	}
  
  	/* now checksum the rest of the page */
! 	for (i = SizeOfPageHeaderData; i < BLCKSZ / sizeof(uint32); i++)
! 	{
! 		sum1 += ptr32Page[i];
! 		sum2 += sum1;
  
! 		/*
! 		 * Testing for overflow makes the algorithm slower, but we know that
! 		 * overflow won't happen, so only use an Assert. The overflow won't
! 		 * happen because sum2 (the larger sum) can grow to a maximum of:
! 		 *
! 		 *   2^32 * (N^2 - N)/2
! 		 *
! 		 * where N is the number of iterations of this loop. The largest block
! 		 * size is 32KB, which is 8192 iterations, which yields a number less
! 		 * than 2^61, which is still within the range of a signed int64.
! 		 */
! 		Assert(BLCKSZ <= 32768 && sum1 >=0 && sum2 >= 0);
! 	}
  
  	/*
  	 * Store the sums as bytes in the checksum. Mod 255 is used instead of 256
  	 * because 256 would miss errors in the high 24 bits of a 32-bit word read
  	 * from the page. We add one to shift the range from 0..255 to 1..256, to
  	 * make zero invalid for checksum bytes (which seems wise).
  	 */
! 	p8Checksum[0] = (sum1 % 255) + 1;
! 	p8Checksum[1] = (sum2 % 255) + 1;
  
  #ifdef DEBUG_CHECKSUM
  	elog(LOG, "checksum %u", checksum);
  #endif
  
  	return checksum;
--- 928,997 ----
  
  /*
   * Calculate checksum for a PostgreSQL Page. This includes the page number (to
   * detect the case when a page is somehow moved to a different location), the
   * page header (excluding the checksum itself), and the page data.
   *
!  * The checksum algorithm is to accumulate 64 parallel 16bit checksum values
!  * using the evolution function value = old_value * prime + data. The parallel
!  * accumulation is done to cut data dependencies and enable vectorization of
!  * the inner loop. Without vector instructions this code is likely to be
!  * load/store bound.
   */
+ #define N_SUMS 64
+ #define HASH_PRIME 31
+ #define PageChecksumOffset (offsetof(PageHeaderData, pd_checksum))
+ 
  static uint16
  PageCalcChecksum16(Page page, BlockNumber blkno)
  {
! 	uint16				(*pageArray)[N_SUMS] = (uint16 (*)[N_SUMS]) page;
! 	uint16				 sums[N_SUMS];
! 	uint32				 combined_sum;
  	uint16				 checksum	 = 0;
  	uint8				*p8Checksum	 = (uint8 *) &checksum;
! 	int					 i, j;
  
  	/* only calculate the checksum for properly-initialized pages */
  	Assert(!PageIsNew(page));
  
  	/*
  	 * Initialize the checksum calculation with the page number. This helps
  	 * catch corruption from whole pages being transposed with other whole
  	 * pages.
  	 */
! 	combined_sum = blkno;
! 
! 	/* First iteration needs to consider the checksum position as zero */
! 	for (i = 0; i < N_SUMS; i++)
! 		sums[i] = (i == PageChecksumOffset / sizeof(uint16)) ? 0 : pageArray[0][i];
  
  	/*
! 	 * As buffer size is a power of two we can safely do it a smaller power
! 	 * of two steps a time.
  	 */
! 	Assert(BLCKSZ / sizeof(uint16) % N_SUMS == 0);
  
  	/* now checksum the rest of the page */
! 	for (i = 1; i < BLCKSZ / sizeof(uint16) / N_SUMS; i++)
! 		for (j = 0; j < N_SUMS; j++)
! 			/* Written as two separate lines to unconfuse gcc */
! 			sums[j] = sums[j]*HASH_PRIME + pageArray[i][j];
  
! 	/* combine the separate sums into a single value */
! 	for (i = 0; i < N_SUMS; i++)
! 		combined_sum = combined_sum*HASH_PRIME + sums[i];
  
  	/*
  	 * Store the sums as bytes in the checksum. Mod 255 is used instead of 256
  	 * because 256 would miss errors in the high 24 bits of a 32-bit word read
  	 * from the page. We add one to shift the range from 0..255 to 1..256, to
  	 * make zero invalid for checksum bytes (which seems wise).
  	 */
! 	p8Checksum[0] = (combined_sum % 255) + 1;
! 	p8Checksum[1] = (combined_sum*HASH_PRIME % 255) + 1;
  
  #ifdef DEBUG_CHECKSUM
  	elog(LOG, "checksum %u", checksum);
  #endif
  
  	return checksum;
