Thanks for the new version.
At Tue, 15 Mar 2022 08:07:39 +0300, Yura Sokolov <[email protected]>
wrote in
> В Пн, 14/03/2022 в 14:57 +0300, Yura Sokolov пишет:
> > В Пн, 14/03/2022 в 17:12 +0900, Kyotaro Horiguchi пишет:
> > > At Mon, 14 Mar 2022 09:15:11 +0300, Yura Sokolov
> > > <[email protected]> wrote in
> > > > В Пн, 14/03/2022 в 14:31 +0900, Kyotaro Horiguchi пишет:
> > > I tried pgbench runs with scale 100 (with 10 threads, 10 clients) on
> > > 128kB shared buffers and I saw that get_hash_entry never takes the
> > > !element_alloc() path and always allocate a fresh entry, then
> > > saturates at 30 new elements allocated at the medium of a 100 seconds
> > > run.
> > >
> > > Then, I tried the same with the patch, and I am surprized to see that
> > > the rise of the number of newly allocated elements didn't stop and
> > > went up to 511 elements after the 100 seconds run. So I found that my
> > > concern was valid. The change in dynahash actually
> > > continuously/repeatedly causes lack of free list entries. I'm not
> > > sure how much the impact given on performance if we change
> > > get_hash_entry to prefer other freelists, though.
> >
> > Well, it is quite strange SharedBufHash is not allocated as
> > HASH_FIXED_SIZE. Could you check what happens with this flag set?
> > I'll try as well.
> >
> > Other way to reduce observed case is to remember freelist_idx for
> > reused entry. I didn't believe it matters much since entries migrated
> > netherless, but probably due to some hot buffers there are tention to
> > crowd particular freelist.
>
> Well, I did both. Everything looks ok.
Hmm. v8 returns stashed element with original patition index when the
element is *not* reused. But what I saw in the previous test runs is
the REUSE->ENTER(reuse)(->REMOVE) case. So the new version looks like
behaving the same way (or somehow even worse) with the previous
version. get_hash_entry continuously suffer lack of freelist
entry. (FWIW, attached are the test-output diff for both master and
patched)
master finally allocated 31 fresh elements for a 100s run.
> ALLOCED: 31 ;; freshly allocated
v8 finally borrowed 33620 times from another freelist and 0 freshly
allocated (ah, this version changes that..)
Finally v8 results in:
> RETURNED: 50806 ;; returned stashed elements
> BORROWED: 33620 ;; borrowed from another freelist
> REUSED: 1812664 ;; stashed
> ASSIGNED: 1762377 ;; reused
>(ALLOCED: 0) ;; freshly allocated
It contains a huge degradation by frequent elog's so they cannot be
naively relied on, but it should show what is happening sufficiently.
> I lost access to Xeon 8354H, so returned to old Xeon X5675.
...
> Strange thing: both master and patched version has higher
> peak tps at X5676 at medium connections (17 or 27 clients)
> than in first october version [1]. But lower tps at higher
> connections number (>= 191 clients).
> I'll try to bisect on master this unfortunate change.
The reversing of the preference order between freshly-allocation and
borrow-from-another-freelist might affect.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/storage/buffer/buf_table.c
b/src/backend/storage/buffer/buf_table.c
index dc439940fa..ac651b98e6 100644
--- a/src/backend/storage/buffer/buf_table.c
+++ b/src/backend/storage/buffer/buf_table.c
@@ -31,7 +31,7 @@ typedef struct
int id; /* Associated
buffer ID */
} BufferLookupEnt;
-static HTAB *SharedBufHash;
+HTAB *SharedBufHash;
/*
diff --git a/src/backend/utils/hash/dynahash.c
b/src/backend/utils/hash/dynahash.c
index 3babde8d70..294516ef01 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -195,6 +195,11 @@ struct HASHHDR
long ssize; /* segment size --- must be
power of 2 */
int sshift; /* segment shift =
log2(ssize) */
int nelem_alloc; /* number of entries to
allocate at once */
+ int alloc;
+ int reuse;
+ int borrow;
+ int assign;
+ int ret;
#ifdef HASH_STATISTICS
@@ -963,6 +968,7 @@ hash_search(HTAB *hashp,
foundPtr);
}
+extern HTAB *SharedBufHash;
void *
hash_search_with_hash_value(HTAB *hashp,
const void *keyPtr,
@@ -1354,6 +1360,8 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
hctl->freeList[freelist_idx].nentries++;
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
+ if (hashp == SharedBufHash)
+ elog(LOG, "BORROWED: %d",
++hctl->borrow);
return newElement;
}
@@ -1363,6 +1371,8 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
/* no elements available to borrow either, so out of
memory */
return NULL;
}
+ else if (hashp == SharedBufHash)
+ elog(LOG, "ALLOCED: %d", ++hctl->alloc);
}
/* remove entry from freelist, bump nentries */
diff --git a/src/backend/storage/buffer/buf_table.c
b/src/backend/storage/buffer/buf_table.c
index 55bb491ad0..029bb89f26 100644
--- a/src/backend/storage/buffer/buf_table.c
+++ b/src/backend/storage/buffer/buf_table.c
@@ -31,7 +31,7 @@ typedef struct
int id; /* Associated
buffer ID */
} BufferLookupEnt;
-static HTAB *SharedBufHash;
+HTAB *SharedBufHash;
/*
diff --git a/src/backend/utils/hash/dynahash.c
b/src/backend/utils/hash/dynahash.c
index 50c0e47643..00159714d1 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -199,6 +199,11 @@ struct HASHHDR
int nelem_alloc; /* number of entries to
allocate at once */
nalloced_t nalloced; /* number of entries allocated
*/
+ int alloc;
+ int reuse;
+ int borrow;
+ int assign;
+ int ret;
#ifdef HASH_STATISTICS
/*
@@ -1006,6 +1011,7 @@ hash_search(HTAB *hashp,
foundPtr);
}
+extern HTAB *SharedBufHash;
void *
hash_search_with_hash_value(HTAB *hashp,
const void *keyPtr,
@@ -1143,6 +1149,8 @@ hash_search_with_hash_value(HTAB *hashp,
DynaHashReuse.hashp = hashp;
DynaHashReuse.freelist_idx = freelist_idx;
+ if (hashp == SharedBufHash)
+ elog(LOG, "REUSED: %d", ++hctl->reuse);
/* Caller should call HASH_ASSIGN as the very
next step. */
return (void *) ELEMENTKEY(currBucket);
}
@@ -1160,6 +1168,9 @@ hash_search_with_hash_value(HTAB *hashp,
if (likely(DynaHashReuse.element == NULL))
return (void *) ELEMENTKEY(currBucket);
+ if (hashp == SharedBufHash)
+ elog(LOG, "RETURNED: %d", ++hctl->ret);
+
freelist_idx = DynaHashReuse.freelist_idx;
/* if partitioned, must lock to touch nfree and
freeList */
if (IS_PARTITIONED(hctl))
@@ -1191,6 +1202,13 @@ hash_search_with_hash_value(HTAB *hashp,
}
else
{
+ if (hashp == SharedBufHash)
+ {
+ hctl->assign++;
+ elog(LOG, "ASSIGNED: %d (%d)",
+ hctl->assign, hctl->reuse -
hctl->assign);
+ }
+
currBucket = DynaHashReuse.element;
DynaHashReuse.element = NULL;
DynaHashReuse.hashp = NULL;
@@ -1448,6 +1466,8 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
hctl->freeList[borrow_from_idx].nfree--;
SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));
+ if (hashp == SharedBufHash)
+ elog(LOG, "BORROWED: %d",
++hctl->borrow);
return newElement;
}
@@ -1457,6 +1477,10 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
/* no elements available to borrow either, so out of
memory */
return NULL;
}
+ else if (hashp == SharedBufHash)
+ elog(LOG, "ALLOCED: %d", ++hctl->alloc);
+
+
}
/* remove entry from freelist, decrease nfree */