Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use 0 for empty value #34

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Use 0 for empty value #34

wants to merge 5 commits into from

Conversation

colega
Copy link

@colega colega commented Jul 3, 2024

In the current implementation we have to initialize all metadata values to the specific empty value when we're creating a new map or growing it.

This changes empty to be the zero byte, and tombstone to be byte 1, by adding 2 to all hashes.

We do have to run one extra sum +2 to ensure that h2 hashes don't have the lower bit set, but we compensate that by doing one less operation when matching empty in the group, (two less assembly instructions in the amd64 simd code!), so there's no penalty there.

I benchmarked on ARM (Apple Silicon), and for some reason some other benchmark results have also improved (we're doing some less work, but not that much less. Maybe some operations are optimized? but why int benchmarks are unaffected then?), I'll run more benchmarks to confirm, but it would be great if someone on amd64 could double check.

goos: darwin
goarch: arm64
pkg: github.com/dolthub/swiss
                                   │    main-20    │             empty-zero-20             │
                                   │    sec/op     │    sec/op      vs base                │
MatchMetadata-12                     0.4646n ±  0%   0.4652n ±  0%        ~ (p=0.291 n=20)
StringMaps/n=16/runtime_map-12        6.098n ±  1%    6.172n ±  2%        ~ (p=0.092 n=20)
StringMaps/n=16/swiss.Map-12          13.95n ±  4%    12.67n ±  3%   -9.21% (p=0.000 n=20)
StringMaps/n=128/runtime_map-12       6.345n ±  2%    6.365n ±  1%        ~ (p=0.597 n=20)
StringMaps/n=128/swiss.Map-12         14.87n ±  3%    13.99n ±  2%   -5.95% (p=0.000 n=20)
StringMaps/n=1024/runtime_map-12      6.830n ±  1%    6.818n ±  1%        ~ (p=0.995 n=20)
StringMaps/n=1024/swiss.Map-12        11.22n ±  8%    11.93n ±  6%   +6.33% (p=0.027 n=20)
StringMaps/n=8192/runtime_map-12      13.02n ±  8%    13.22n ±  7%        ~ (p=0.941 n=20)
StringMaps/n=8192/swiss.Map-12        14.30n ± 15%    12.25n ±  7%  -14.40% (p=0.010 n=20)
StringMaps/n=131072/runtime_map-12    20.45n ±  5%    20.44n ±  0%        ~ (p=0.663 n=20)
StringMaps/n=131072/swiss.Map-12      15.77n ±  2%    15.49n ±  2%        ~ (p=0.351 n=20)
Int64Maps/n=16/runtime_map-12         4.471n ±  1%    4.530n ±  2%        ~ (p=0.159 n=20)
Int64Maps/n=16/swiss.Map-12           4.651n ± 22%    4.756n ± 26%   +2.28% (p=0.003 n=20)
Int64Maps/n=128/runtime_map-12        4.614n ±  1%    4.621n ±  2%        ~ (p=0.673 n=20)
Int64Maps/n=128/swiss.Map-12          5.423n ±  2%    5.481n ±  3%        ~ (p=0.277 n=20)
Int64Maps/n=1024/runtime_map-12       4.733n ±  1%    4.737n ±  1%        ~ (p=0.995 n=20)
Int64Maps/n=1024/swiss.Map-12         5.663n ±  1%    5.845n ±  1%   +3.21% (p=0.001 n=20)
Int64Maps/n=8192/runtime_map-12       6.762n ± 10%    7.054n ±  6%        ~ (p=0.331 n=20)
Int64Maps/n=8192/swiss.Map-12         6.556n ±  1%    6.691n ±  1%   +2.07% (p=0.000 n=20)
Int64Maps/n=131072/runtime_map-12     17.12n ±  0%    16.74n ±  0%   -2.22% (p=0.000 n=20)
Int64Maps/n=131072/swiss.Map-12      10.155n ±  1%    9.874n ±  2%   -2.77% (p=0.000 n=20)
NewMap/n=16-12                        96.66n ±  0%    90.18n ±  0%   -6.70% (p=0.000 n=20)
NewMap/n=128-12                       315.1n ±  0%    270.5n ±  0%  -14.14% (p=0.000 n=20)
NewMap/n=1024-12                      1.616µ ±  0%    1.128µ ±  1%  -30.23% (p=0.000 n=20)
NewMap/n=8192-12                     11.731µ ±  1%    5.293µ ±  0%  -54.88% (p=0.000 n=20)
NewMap/n=131072-12                   159.87µ ±  1%    48.96µ ±  1%  -69.37% (p=0.000 n=20)
Map_Put_Growing/n=16-12               214.2n ±  0%    203.5n ±  0%   -5.00% (p=0.000 n=20)
Map_Put_Growing/n=128-12              1.399µ ±  0%    1.319µ ±  0%   -5.72% (p=0.000 n=20)
Map_Put_Growing/n=1024-12             11.08µ ±  0%    10.45µ ±  0%   -5.65% (p=0.000 n=20)
Map_Put_Growing/n=8192-12             90.19µ ±  0%    84.92µ ±  0%   -5.85% (p=0.000 n=20)
Map_Put_Growing/n=131072-12           1.646m ±  2%    1.559m ±  2%   -5.26% (p=0.000 n=20)
geomean                               63.68n          57.82n         -9.20%

@colega colega mentioned this pull request Jul 3, 2024
@colega
Copy link
Author

colega commented Jul 3, 2024

This includes changes from #33

Avo documentation requires version to be pinned in order to be used in
production, however there was no reference to avo in the modules here,
so it's not possible to reproduce the build.

This extracts avo source to a submodule, in order to prevent it from
being downloaded as a transitive dependency when dolthub/swiss is
required, and adds a go:generate directive to simplify the build
process.

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
This doesn't change the logic, but by defining h2 as uint8, and using
uint8 elsewhere, we can work properly with higher bits (and define empty
in it's binary form, instead of having to use the negative value and a
comment). This will also allow us future changes without having to play
with overflows.

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
@colega colega force-pushed the empty-as-0 branch 3 times, most recently from 904b847 to 72dab86 Compare July 4, 2024 08:31
@colega colega marked this pull request as ready for review July 4, 2024 08:39
@colega
Copy link
Author

colega commented Jul 4, 2024

I ran the benchmarks in a Github codespace, the results make sense, although the deviation is quite high (expected from a virtual machine somewhere on the cloud).

goos: linux
goarch: amd64
pkg: github.com/dolthub/swiss
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ /home/codespace/main.bench │   /home/codespace/empty-zero.bench   │
                                  │           sec/op           │    sec/op     vs base                │
MatchMetadata-2                                   2.881n ±  6%   2.807n ±  4%        ~ (p=0.063 n=10)
StringMaps/n=16/runtime_map-2                     10.48n ±  9%   10.24n ±  6%        ~ (p=0.670 n=10)
StringMaps/n=16/swiss.Map-2                       16.88n ±  7%   17.45n ±  5%        ~ (p=0.342 n=10)
StringMaps/n=128/runtime_map-2                    10.92n ±  6%   10.80n ±  8%        ~ (p=0.954 n=10)
StringMaps/n=128/swiss.Map-2                      18.09n ±  5%   17.83n ±  3%        ~ (p=0.579 n=10)
StringMaps/n=1024/runtime_map-2                   11.43n ± 16%   11.21n ±  9%        ~ (p=0.579 n=10)
StringMaps/n=1024/swiss.Map-2                     18.68n ±  5%   19.25n ±  8%        ~ (p=0.197 n=10)
StringMaps/n=8192/runtime_map-2                   25.03n ±  3%   24.78n ±  5%        ~ (p=0.644 n=10)
StringMaps/n=8192/swiss.Map-2                     22.12n ±  6%   22.66n ±  5%        ~ (p=0.436 n=10)
StringMaps/n=131072/runtime_map-2                 33.67n ±  3%   34.12n ±  4%        ~ (p=1.000 n=10)
StringMaps/n=131072/swiss.Map-2                   36.48n ±  7%   37.34n ±  5%        ~ (p=0.912 n=10)
Int64Maps/n=16/runtime_map-2                      7.904n ±  6%   7.636n ±  6%        ~ (p=0.353 n=10)
Int64Maps/n=16/swiss.Map-2                        14.46n ±  4%   14.43n ±  5%        ~ (p=0.971 n=10)
Int64Maps/n=128/runtime_map-2                     8.245n ±  6%   8.073n ±  5%        ~ (p=0.280 n=10)
Int64Maps/n=128/swiss.Map-2                       15.18n ±  5%   15.32n ±  2%        ~ (p=0.631 n=10)
Int64Maps/n=1024/runtime_map-2                    8.336n ±  7%   8.523n ±  9%        ~ (p=0.256 n=10)
Int64Maps/n=1024/swiss.Map-2                      15.49n ±  8%   16.02n ±  4%        ~ (p=0.382 n=10)
Int64Maps/n=8192/runtime_map-2                    20.08n ±  5%   18.47n ±  9%   -7.99% (p=0.029 n=10)
Int64Maps/n=8192/swiss.Map-2                      16.99n ±  4%   16.86n ±  7%        ~ (p=0.362 n=10)
Int64Maps/n=131072/runtime_map-2                  28.42n ±  2%   27.52n ±  3%   -3.17% (p=0.019 n=10)
Int64Maps/n=131072/swiss.Map-2                    30.38n ±  2%   30.07n ±  2%        ~ (p=0.172 n=10)
NewMap/n=16-2                                     248.2n ± 15%   219.2n ±  6%  -11.68% (p=0.000 n=10)
NewMap/n=128-2                                    779.5n ±  7%   684.0n ±  9%  -12.25% (p=0.001 n=10)
NewMap/n=1024-2                                   3.614µ ± 12%   2.743µ ±  7%  -24.10% (p=0.000 n=10)
NewMap/n=8192-2                                   50.49µ ± 49%   37.31µ ±  7%        ~ (p=0.089 n=10)
NewMap/n=131072-2                                 328.9µ ±  8%   240.6µ ± 10%  -26.83% (p=0.000 n=10)
Map_Put_Growing/n=16-2                            571.1n ±  6%   527.5n ± 12%   -7.64% (p=0.043 n=10)
Map_Put_Growing/n=128-2                           3.405µ ± 14%   3.389µ ± 12%        ~ (p=0.481 n=10)
Map_Put_Growing/n=1024-2                          26.59µ ±  7%   26.23µ ±  7%        ~ (p=0.247 n=10)
Map_Put_Growing/n=8192-2                          235.5µ ±  4%   236.1µ ±  4%        ~ (p=0.796 n=10)
Map_Put_Growing/n=131072-2                        4.814m ± 10%   4.484m ±  5%        ~ (p=0.579 n=10)
geomean                                           142.1n         135.8n         -4.47%

It would still be nice if someone could run these on their machine.

Current value has to be written for all metadata values when we're
instantiating a new map or growing.

This changes empty to be the zero byte, and tombstone to be byte 1, by
adding 2 (h2Offset) to all hashes.

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
@colega
Copy link
Author

colega commented Jul 4, 2024

This is ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant