Re: Use simplehash.h instead of dynahash in SMgr

From: Yura Sokolov <y(dot)sokolov(at)postgrespro(dot)ru>
To: David Rowley <dgrowleyml(at)gmail(dot)com>
Cc: PostgreSQL Developers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Use simplehash.h instead of dynahash in SMgr
Date: 2021-04-29 00:30:47
Message-ID: 4159ecd97e53318e6302d4091c27e97f@postgrespro.ru
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

David Rowley писал 2021-04-29 02:51:
> On Thu, 29 Apr 2021 at 00:28, Yura Sokolov <y(dot)sokolov(at)postgrespro(dot)ru>
> wrote:
>> The best result is with just:
>>
>> return (uint32)rnode->node.relNode;
>>
>> ie, relNode could be taken without mixing at all.
>> relNode is unique inside single database, and almost unique among
>> whole
>> cluster
>> since it is Oid.
>
> I admit to having tried that too just to almost eliminate the cost of
> hashing. I just didn't consider it something we'd actually do.
>
> The system catalogues are quite likely to all have the same
> relfilenode in all databases, so for workloads that have a large
> number of databases, looking up WAL records that touch the catalogues
> is going to be pretty terrible.

Single workload that could touch system catalogues in different
databases is recovery (and autovacuum?). Client backends couldn't
be connected to more than one database.

But netherless, you're right. I oversimplified it intentionally.
I wrote originally:

hashcode = (uint32)rnode->node.dbNode * 0xc2b2ae35;
hashcode ^= (uint32)rnode->node.relNode;
return hashcode;

But before sending mail I'd cut dbNode part.
Still, main point: relNode could be put unmixed into final value.
This way less collisions happen.

>
> The simplified hash function I wrote with just the relNode and dbNode
> would be the least I'd be willing to entertain. However, I just
> wouldn't be surprised if there was a good reason for that being bad
> too.
>
>
>> So, I've repeated benchmark with different number of partitons (I
>> tried
>> to catch higher fillfactor) and less amount of inserted data (since I
>> don't
>> want to stress my SSD).
>>
>> partitions/ | dynahash | dynahash + | simplehash | simplehash + |
>> fillfactor | | simple func | | simple func |
>> ------------+----------+-------------+--------------+
>> 3500/0.43 | 3.73s | 3.54s | 3.58s | 3.34s |
>> 3200/0.78 | 3.64s | 3.46s | 3.47s | 3.25s |
>> 1500/0.74 | 3.18s | 2.97s | 3.03s | 2.79s |
>>
>> Fillfactor is effective fillfactor in simplehash with than number of
>> partitions.
>> I wasn't able to measure with fillfactor close to 0.9 since looks like
>> simplehash tends to grow much earlier due to SH_GROW_MAX_MOVE.
>
> Thanks for testing that.
>
> I also ran some tests last night to test the 0.75 vs 0.9 fillfactor to
> see if it made a difference. The test was similar to last time, but I
> trimmed the number of rows inserted from 100 million down to 25
> million. Last time I tested with 1000 partitions, this time with each
> of: 100 200 300 400 500 600 700 800 900 1000 partitions. There didn't
> seem to be any point of testing lower than that as the minimum hash
> table size is 512.
>
> The averages over 10 runs were:
>
> nparts ff75 ff90
> 100 21.898 22.226
> 200 23.105 25.493
> 300 25.274 24.251
> 400 25.139 25.611
> 500 25.738 25.454
> 600 26.656 26.82
> 700 27.577 27.102
> 800 27.608 27.546
> 900 27.284 28.186
> 1000 29 28.153
>
> Or to summarise a bit, we could just look at the sum of all the
> results per fillfactor:
>
> sum ff75 2592.79
> sum ff90 2608.42 100.6%
>
> fillfactor 75 did come out slightly faster, but only just. It seems
> close enough that it might be better just to keep the 90 to save a
> little memory and improve caching elsewhere. Also, from below, you
> can see that for 300, 500, 600, 700, 1000 tables tests, the hash
> tables ended up the same size, yet there's a bit of variability in the
> timing result. So the 0.6% gain might just be noise.
>
> I don't think it's worth making the fillfactor 75.

To be clear: I didn't change SH_FILLFACTOR. It were equal to 0.9 .
I just were not able to catch table with fill factor more than 0.78.
Looks like you've got it with 900 partitions :-)

>
> Another line of thought for making it go faster would be to do
> something like get rid of the hash status field from SMgrEntry. That
> could be either coded into a single bit we'd borrow from the hash
> value, or it could be coded into the least significant bit of the data
> field. A pointer to palloc'd memory should always be MAXALIGNed,
> which means at least the lower two bits are always zero. We'd just
> need to make sure and do something like "data & ~((uintptr_t) 3)" to
> trim off the hash status bits before dereferencing the pointer. That
> would make the SMgrEntry 12 bytes on a 64-bit machine. However, it
> would also mean that some entries would span 2 cache lines, which
> might affect performance a bit.

Then data pointer will be itself unaligned to 8 bytes. While x86 is
mostly indifferent to this, doubtfully this memory economy will pay
off.

regards,
Yura Sokolov.

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Richard Yen 2021-04-29 00:54:22 Patch to allow pg_filedump to support reading of pg_filenode.map
Previous Message Tom Lane 2021-04-29 00:24:43 Re: WIP: WAL prefetch (another approach)