Skip to content

Conversation

AlexanderYastrebov
Copy link
Contributor

After profiling geth startup times for #16874
it turned out that most of the time was spent resizing accounts slice
for ordered insertion.

This change uses map to track all accounts instead of slice to improve performance.

geth startup time using keystore with one million accounts reduced from
23 minutes to 2.5 minutes.

Benchmarks show relatively-small overhead increase for small keystores and large
decrease for huge:

goos: linux
goarch: amd64
pkg: github.com/ethereum/go-ethereum/accounts/keystore
                                  │      HEAD~1       │                  HEAD                   │
                                  │      sec/op       │    sec/op      vs base                  │
Add/preload=10-8                         1.030µ ±  5%    1.447µ ±  7%    +40.51% (p=0.000 n=10)
Add/preload=100-8                        1.109µ ±  4%    1.463µ ±  3%    +31.88% (p=0.000 n=10)
Add/preload=1000-8                       1.860µ ±  3%    1.477µ ±  5%    -20.57% (p=0.000 n=10)
Add/preload=1000000-8                 5177.640µ ±  2%    1.654µ ± 11%    -99.97% (p=0.000 n=10)
Find/preload=10/by_address-8             23.70n ±  1%    23.88n ±  3%          ~ (p=0.271 n=10)
Find/preload=10/by_path-8                50.43n ±  2%    39.88n ±  5%    -20.94% (p=0.000 n=10)
Find/preload=10/ambiguous-8              323.6n ±  1%   1049.0n ±  3%   +224.17% (p=0.000 n=10)
Find/preload=100/by_address-8            23.69n ±  1%    23.63n ±  6%          ~ (p=0.739 n=10)
Find/preload=100/by_path-8              362.70n ±  1%    37.84n ±  3%    -89.57% (p=0.000 n=10)
Find/preload=100/ambiguous-8             2.683µ ±  2%   19.235µ ±  2%   +617.05% (p=0.000 n=10)
Find/preload=1000/by_address-8           26.45n ±  1%    27.73n ±  2%     +4.82% (p=0.000 n=10)
Find/preload=1000/by_path-8            3211.00n ±  3%    38.22n ±  8%    -98.81% (p=0.000 n=10)
Find/preload=1000/ambiguous-8            26.14µ ±  2%   263.59µ ±  1%   +908.41% (p=0.000 n=10)
Find/preload=1000000/by_address-8        26.47n ±  4%    26.41n ±  1%          ~ (p=0.566 n=10)
Find/preload=1000000/by_path-8      3683325.50n ±  4%    44.09n ± 45%   -100.00% (p=0.000 n=10)
Find/preload=1000000/ambiguous-8         39.68m ± 14%   819.48m ±  7%  +1965.01% (p=0.000 n=10)
geomean                                  2.346µ          791.4n          -66.27%

                                  │     HEAD~1     │                   HEAD                    │
                                  │      B/op      │      B/op       vs base                   │
Add/preload=10-8                      643.0 ± 0%        662.0 ±  0%    +2.95% (p=0.000 n=10)
Add/preload=100-8                     643.0 ± 0%        662.0 ±  0%    +2.95% (p=0.000 n=10)
Add/preload=1000-8                    584.0 ± 5%        662.0 ±  0%   +13.36% (p=0.000 n=10)
Add/preload=1000000-8                 88.00 ± 0%       662.00 ± 17%  +652.27% (p=0.000 n=10)
Find/preload=10/by_address-8          0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=10/by_path-8             0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=10/ambiguous-8           624.0 ± 0%       1200.0 ±  0%   +92.31% (p=0.000 n=10)
Find/preload=100/by_address-8         0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=100/by_path-8            0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=100/ambiguous-8        6.047Ki ± 0%     12.047Ki ±  0%   +99.22% (p=0.000 n=10)
Find/preload=1000/by_address-8        0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/by_path-8           0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/ambiguous-8       56.05Ki ± 0%     112.05Ki ±  0%   +99.92% (p=0.000 n=10)
Find/preload=1000000/by_address-8     0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/by_path-8        0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/ambiguous-8    53.41Mi ± 0%     106.81Mi ±  0%  +100.00% (p=0.000 n=10)
geomean                                          ²                    +36.09%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                  │    HEAD~1    │                 HEAD                  │
                                  │  allocs/op   │ allocs/op   vs base                   │
Add/preload=10-8                    3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=100-8                   3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=1000-8                  3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=1000000-8               2.000 ± 0%     4.000 ± 0%  +100.00% (p=0.000 n=10)
Find/preload=10/by_address-8        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=10/by_path-8           0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=10/ambiguous-8         2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=100/by_address-8       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=100/by_path-8          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=100/ambiguous-8        2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=1000/by_address-8      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/by_path-8         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/ambiguous-8       2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=1000000/by_address-8   0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/by_path-8      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/ambiguous-8    2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
geomean                                        ²                +21.97%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

Updates #16874

After profiling geth startup times for ethereum#16874
it turned out that most of the time was spent resizing accounts slice
for ordered insertion.

This change uses map to track all accounts instead of slice to improve performance.

geth startup time using keystore with one million accounts reduced from
23 minutes to 2.5 minutes.

Benchmarks show relatively-small overhead increase for small keystores and large
decrease for huge:
```
goos: linux
goarch: amd64
pkg: github.com/ethereum/go-ethereum/accounts/keystore
                                  │      HEAD~1       │                  HEAD                   │
                                  │      sec/op       │    sec/op      vs base                  │
Add/preload=10-8                         1.030µ ±  5%    1.447µ ±  7%    +40.51% (p=0.000 n=10)
Add/preload=100-8                        1.109µ ±  4%    1.463µ ±  3%    +31.88% (p=0.000 n=10)
Add/preload=1000-8                       1.860µ ±  3%    1.477µ ±  5%    -20.57% (p=0.000 n=10)
Add/preload=1000000-8                 5177.640µ ±  2%    1.654µ ± 11%    -99.97% (p=0.000 n=10)
Find/preload=10/by_address-8             23.70n ±  1%    23.88n ±  3%          ~ (p=0.271 n=10)
Find/preload=10/by_path-8                50.43n ±  2%    39.88n ±  5%    -20.94% (p=0.000 n=10)
Find/preload=10/ambiguous-8              323.6n ±  1%   1049.0n ±  3%   +224.17% (p=0.000 n=10)
Find/preload=100/by_address-8            23.69n ±  1%    23.63n ±  6%          ~ (p=0.739 n=10)
Find/preload=100/by_path-8              362.70n ±  1%    37.84n ±  3%    -89.57% (p=0.000 n=10)
Find/preload=100/ambiguous-8             2.683µ ±  2%   19.235µ ±  2%   +617.05% (p=0.000 n=10)
Find/preload=1000/by_address-8           26.45n ±  1%    27.73n ±  2%     +4.82% (p=0.000 n=10)
Find/preload=1000/by_path-8            3211.00n ±  3%    38.22n ±  8%    -98.81% (p=0.000 n=10)
Find/preload=1000/ambiguous-8            26.14µ ±  2%   263.59µ ±  1%   +908.41% (p=0.000 n=10)
Find/preload=1000000/by_address-8        26.47n ±  4%    26.41n ±  1%          ~ (p=0.566 n=10)
Find/preload=1000000/by_path-8      3683325.50n ±  4%    44.09n ± 45%   -100.00% (p=0.000 n=10)
Find/preload=1000000/ambiguous-8         39.68m ± 14%   819.48m ±  7%  +1965.01% (p=0.000 n=10)
geomean                                  2.346µ          791.4n          -66.27%

                                  │     HEAD~1     │                   HEAD                    │
                                  │      B/op      │      B/op       vs base                   │
Add/preload=10-8                      643.0 ± 0%        662.0 ±  0%    +2.95% (p=0.000 n=10)
Add/preload=100-8                     643.0 ± 0%        662.0 ±  0%    +2.95% (p=0.000 n=10)
Add/preload=1000-8                    584.0 ± 5%        662.0 ±  0%   +13.36% (p=0.000 n=10)
Add/preload=1000000-8                 88.00 ± 0%       662.00 ± 17%  +652.27% (p=0.000 n=10)
Find/preload=10/by_address-8          0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=10/by_path-8             0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=10/ambiguous-8           624.0 ± 0%       1200.0 ±  0%   +92.31% (p=0.000 n=10)
Find/preload=100/by_address-8         0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=100/by_path-8            0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=100/ambiguous-8        6.047Ki ± 0%     12.047Ki ±  0%   +99.22% (p=0.000 n=10)
Find/preload=1000/by_address-8        0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/by_path-8           0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/ambiguous-8       56.05Ki ± 0%     112.05Ki ±  0%   +99.92% (p=0.000 n=10)
Find/preload=1000000/by_address-8     0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/by_path-8        0.000 ± 0%        0.000 ±  0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/ambiguous-8    53.41Mi ± 0%     106.81Mi ±  0%  +100.00% (p=0.000 n=10)
geomean                                          ²                    +36.09%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                  │    HEAD~1    │                 HEAD                  │
                                  │  allocs/op   │ allocs/op   vs base                   │
Add/preload=10-8                    3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=100-8                   3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=1000-8                  3.000 ± 0%     4.000 ± 0%   +33.33% (p=0.000 n=10)
Add/preload=1000000-8               2.000 ± 0%     4.000 ± 0%  +100.00% (p=0.000 n=10)
Find/preload=10/by_address-8        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=10/by_path-8           0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=10/ambiguous-8         2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=100/by_address-8       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=100/by_path-8          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=100/ambiguous-8        2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=1000/by_address-8      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/by_path-8         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000/ambiguous-8       2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
Find/preload=1000000/by_address-8   0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/by_path-8      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Find/preload=1000000/ambiguous-8    2.000 ± 0%     3.000 ± 0%   +50.00% (p=0.000 n=10)
geomean                                        ²                +21.97%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

Updates ethereum#16874
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