Re: ResourceOwner refactoring - Mailing list pgsql-hackers

From Heikki Linnakangas
Subject Re: ResourceOwner refactoring
Date
Msg-id ad52c002-821c-e0e3-b406-9a0ab72a07bf@iki.fi
Whole thread Raw
In response to Re: ResourceOwner refactoring  (Michael Paquier <michael@paquier.xyz>)
Responses Re: ResourceOwner refactoring  (Robert Haas <robertmhaas@gmail.com>)
List pgsql-hackers
On 21/01/2021 06:14, Michael Paquier wrote:
> On Thu, Jan 21, 2021 at 12:11:37AM +0200, Heikki Linnakangas wrote:
>> Summary: In the the worst scenario, the patched version is still 24% slower
>> than unpatched. But many other scenarios are now faster with the patch.
> 
> Is there a reason explaining the sudden drop for numsnaps within the
> [10,60] range?  The gap looks deeper with a low numkeep.

It's the switch from array to hash table. With the patch, the array 
holds 8 entries. Without the patch, it's 64 entries. So you see a drop 
around those points. I added more data points in that range to get a 
better picture:

LIFO tests:
  numkeep | numsnaps | unpatched | patched | ratio
---------+----------+-----------+---------+-------
        0 |        1 |      32.8 |    32.9 |  1.00
        0 |        2 |      31.6 |    32.8 |  1.04
        0 |        4 |      32.7 |    32.0 |  0.98
        0 |        6 |      34.1 |    33.9 |  0.99
        0 |        8 |      35.1 |    32.4 |  0.92
        0 |       10 |      34.0 |    37.1 |  1.09
        0 |       15 |      33.1 |    35.9 |  1.08
        0 |       20 |      33.0 |    38.8 |  1.18
        0 |       25 |      32.9 |    42.3 |  1.29
        0 |       30 |      32.9 |    40.5 |  1.23
        0 |       35 |      33.1 |    39.9 |  1.21
        0 |       40 |      33.0 |    39.0 |  1.18
        0 |       45 |      35.3 |    41.1 |  1.16
        0 |       50 |      33.0 |    40.8 |  1.24
        0 |       55 |      32.8 |    40.6 |  1.24
        0 |       58 |      33.0 |    41.5 |  1.26
        0 |       60 |      33.1 |    41.6 |  1.26
        0 |       62 |      32.8 |    41.7 |  1.27
        0 |       64 |      46.8 |    40.9 |  0.87
        0 |       66 |      47.0 |    42.5 |  0.90
        0 |       68 |      47.1 |    41.8 |  0.89
        0 |       70 |      47.8 |    41.7 |  0.87
(22 rows)

FIFO tests:
  numkeep | numsnaps | unpatched | patched | ratio
---------+----------+-----------+---------+-------
        0 |        1 |      32.3 |    32.1 |  0.99
        0 |        2 |      33.4 |    31.6 |  0.95
        0 |        4 |      34.0 |    31.4 |  0.92
        0 |        6 |      35.4 |    33.2 |  0.94
        0 |        8 |      34.8 |    31.9 |  0.92
        0 |       10 |      35.4 |    40.2 |  1.14
        0 |       15 |      35.4 |    40.3 |  1.14
        0 |       20 |      35.6 |    43.8 |  1.23
        0 |       25 |      35.4 |    42.4 |  1.20
        0 |       30 |      36.0 |    43.3 |  1.20
        0 |       35 |      36.4 |    45.1 |  1.24
        0 |       40 |      36.9 |    46.6 |  1.26
        0 |       45 |      37.7 |    45.3 |  1.20
        0 |       50 |      37.2 |    43.9 |  1.18
        0 |       55 |      38.4 |    46.8 |  1.22
        0 |       58 |      37.6 |    45.0 |  1.20
        0 |       60 |      37.7 |    46.6 |  1.24
        0 |       62 |      38.4 |    46.5 |  1.21
        0 |       64 |      48.7 |    47.6 |  0.98
        0 |       66 |      48.2 |    45.8 |  0.95
        0 |       68 |      48.5 |    47.5 |  0.98
        0 |       70 |      48.4 |    47.3 |  0.98
(22 rows)

Let's recap the behavior:

Without patch
-------------

For each different kind of resource, there's an array that holds up to 
64 entries. In ResourceOwnerForget(), the array is scanned linearly. If 
the array fills up, we replace the array with a hash table. After 
switching, all operations use the hash table.

With patch
----------

There is one array that holds up to 8 entries. It is shared by all 
resources. In ResourceOwnerForget(), the array is always scanned.

If the array fills up, all the entries are moved to a hash table, 
freeing up space in the array, and the new entry is added to the array. 
So the array is used together with the hash table, like an LRU cache of 
the most recently remembered entries.


Why this change? I was afraid that now that all different resources 
share the same data structure, remembering e.g. a lot of locks at the 
beginning of a transaction would cause the switch to the hash table, 
making all subsequent remember/forget operations, like for buffer pins, 
slower. That kind of interference seems bad. By continuing to use the 
array for the recently-remembered entries, we avoid that problem. The 
[numkeep, numsnaps] = [65, 70] test is in that regime, and the patched 
version was significantly faster.

Because the array is now always scanned, I felt that it needs to be 
small, to avoid wasting much time scanning for entries that have already 
been moved to the hash table. That's why I made it just 8 entries.

Perhaps 8 entries is too small, after all? Linearly scanning an array is 
very fast. To test that, I bumped up RESOWNER_ARRAY_SIZE to 64, and ran 
the test again:

  numkeep | numsnaps | lifo_time_ns | fifo_time_ns
---------+----------+--------------+--------------
        0 |        1 |         35.4 |         31.5
        0 |        2 |         32.3 |         32.3
        0 |        4 |         32.8 |         31.0
        0 |        6 |         34.5 |         33.7
        0 |        8 |         33.9 |         32.7
        0 |       10 |         33.7 |         33.0
        0 |       15 |         34.8 |         33.1
        0 |       20 |         35.0 |         32.6
        0 |       25 |         36.9 |         33.0
        0 |       30 |         38.7 |         33.2
        0 |       35 |         39.9 |         34.5
        0 |       40 |         40.8 |         35.5
        0 |       45 |         42.6 |         36.4
        0 |       50 |         44.9 |         37.8
        0 |       55 |         45.4 |         38.5
        0 |       58 |         47.7 |         39.6
        0 |       60 |         45.9 |         40.2
        0 |       62 |         47.6 |         40.9
        0 |       64 |         51.4 |         41.2
        0 |       66 |         38.2 |         39.8
        0 |       68 |         39.7 |         40.3
        0 |       70 |         38.1 |         40.9
(22 rows)

Here you can see that as numsnaps increases, the test becomes slower, 
but then it becomes faster again at 64-66, when it switches to the hash 
table. So 64 seems too much. 32 seems to be the sweet spot here, that's 
where scanning the hash and scanning the array are about the same speed.

- Heikki



pgsql-hackers by date:

Previous
From: Bharath Rupireddy
Date:
Subject: Re: Is Recovery actually paused?
Next
From: Amit Kapila
Date:
Subject: Re: Single transaction in the tablesync worker?