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

triedb/pathdb: introduce lookup structure to optimize node query #30557

Closed

Conversation

rjl493456442
Copy link
Member

@rjl493456442 rjl493456442 commented Oct 8, 2024

Implemented the #30022

Benchmark needed

@rjl493456442 rjl493456442 force-pushed the pathdb-lookup-simple branch 3 times, most recently from a341a94 to 8e7ef2c Compare October 9, 2024 12:44
@rjl493456442 rjl493456442 force-pushed the pathdb-lookup-simple branch 2 times, most recently from 64c34fc to 98e91df Compare October 14, 2024 06:52
@rjl493456442
Copy link
Member Author

[[ Master ]]

[CPU]

Showing nodes accounting for 247.19s, 42.68% of 579.16s total
Dropped 2211 nodes (cum <= 2.90s)
Showing top 10 nodes out of 314
      flat  flat%   sum%        cum   cum%
    44.53s  7.69%  7.69%     52.65s  9.09%  runtime.findObject
    41.84s  7.22% 14.91%     42.53s  7.34%  runtime.cgocall                               (ecrecover)
    31.51s  5.44% 20.35%     38.55s  6.66%  runtime.mapaccess2_faststr                    (difflayer.Node)
    28.81s  4.97% 25.33%     28.81s  4.97%  golang.org/x/crypto/sha3.keccakF1600
    25.94s  4.48% 29.81%    141.79s 24.48%  runtime.scanobject
    18.05s  3.12% 32.92%     26.66s  4.60%  runtime.mapaccess2                            (difflayer.Node)
    14.88s  2.57% 35.49%     14.88s  2.57%  internal/runtime/syscall.Syscall6
    14.50s  2.50% 38.00%     14.50s  2.50%  sync/atomic.(*Int32).Add
    13.66s  2.36% 40.35%     13.84s  2.39%  runtime.(*gcBits).bitp (inline)
    13.47s  2.33% 42.68%     49.84s  8.61%  runtime.mallocgc

[INUSE-SPACE]

File: geth
Type: inuse_space
Time: Dec 2, 2024 at 11:41am (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 2010.11MB, 77.94% of 2579.05MB total
Dropped 393 nodes (cum <= 12.90MB)
Showing top 10 nodes out of 159
      flat  flat%   sum%        cum   cum%
  419.69MB 16.27% 16.27%   419.69MB 16.27%  github.com/ethereum/go-ethereum/rlp.(*encBuffer).makeBytes
  282.84MB 10.97% 27.24%   282.84MB 10.97%  github.com/cockroachdb/pebble.newBatchWithSize
  249.51MB  9.67% 36.91%   478.52MB 18.55%  github.com/ethereum/go-ethereum/rlp.decodeBigInt
  229.01MB  8.88% 45.79%   229.01MB  8.88%  math/big.nat.make (inline)
  196.93MB  7.64% 53.43%   196.93MB  7.64%  github.com/ethereum/go-ethereum/rlp.(*Stream).Bytes
  158.44MB  6.14% 59.57%   211.42MB  8.20%  github.com/VictoriaMetrics/fastcache.(*bucket).Set
  143.01MB  5.55% 65.12%   854.47MB 33.13%  github.com/ethereum/go-ethereum/core/types.(*Transaction).DecodeRLP
  130.01MB  5.04% 70.16%   130.01MB  5.04%  reflect.New
  113.40MB  4.40% 74.56%   113.40MB  4.40%  github.com/ethereum/go-ethereum/p2p/rlpx.growslice
   87.27MB  3.38% 77.94%    87.27MB  3.38%  github.com/ethereum/go-ethereum/p2p/rlpx.(*readBuffer).grow

[ALLOC_SPACE]

(pprof) alloc_space
(pprof) top10
Showing nodes accounting for 64.71TB, 58.18% of 111.23TB total
Dropped 2568 nodes (cum <= 0.56TB)
Showing top 10 nodes out of 227
      flat  flat%   sum%        cum   cum%
   25.90TB 23.28% 23.28%    25.90TB 23.28%  github.com/ethereum/go-ethereum/trie.(*fullNode).copy (inline)
    7.41TB  6.66% 29.95%    21.07TB 18.95%  github.com/ethereum/go-ethereum/trie.(*committer).commitChildren
    6.77TB  6.09% 36.04%    16.23TB 14.59%  github.com/ethereum/go-ethereum/trie.decodeNode
    6.74TB  6.06% 42.10%     6.74TB  6.06%  github.com/ethereum/go-ethereum/rlp.(*encBuffer).makeBytes (inline)
    4.59TB  4.13% 46.22%     8.90TB  8.01%  github.com/ethereum/go-ethereum/trie.decodeFull
    4.31TB  3.88% 50.10%     4.31TB  3.88%  github.com/ethereum/go-ethereum/trie.decodeRef
    2.98TB  2.68% 52.79%     2.98TB  2.68%  github.com/ethereum/go-ethereum/trie.(*tracer).onRead
    2.52TB  2.27% 55.05%     2.52TB  2.27%  golang.org/x/crypto/sha3.NewLegacyKeccak256
    1.77TB  1.59% 56.65%     1.77TB  1.59%  github.com/ethereum/go-ethereum/trie/trienode.(*NodeSet).AddNode (inline)
    1.70TB  1.53% 58.18%     1.70TB  1.53%  github.com/holiman/bloomfilter/v2.newBits

[[ PR ]]

[CPU]

Showing nodes accounting for 208.28s, 42.26% of 492.80s total
Dropped 2301 nodes (cum <= 2.46s)
Showing top 10 nodes out of 337
      flat  flat%   sum%        cum   cum%
    44.87s  9.11%  9.11%     45.31s  9.19%  runtime.cgocall                              (ecrecover)                  
    41.51s  8.42% 17.53%     46.76s  9.49%  runtime.findObject
    29.38s  5.96% 23.49%     29.38s  5.96%  golang.org/x/crypto/sha3.keccakF1600
    18.48s  3.75% 27.24%    119.70s 24.29%  runtime.scanobject
    15.85s  3.22% 30.46%     15.85s  3.22%  internal/runtime/syscall.Syscall6
    14.35s  2.91% 33.37%     48.83s  9.91%  runtime.mallocgc
    13.94s  2.83% 36.20%     14.04s  2.85%  runtime.(*gcBits).bitp (inline)
    10.27s  2.08% 38.28%     10.43s  2.12%  runtime.(*mspan).heapBitsSmallForAddr
    10.20s  2.07% 40.35%     10.20s  2.07%  runtime.memmove
     9.43s  1.91% 42.26%     11.84s  2.40%  github.com/ethereum/go-ethereum/core/vm.codeBitmapInternal


[INUSE-SPACE]

File: geth
Type: inuse_space
Time: Dec 2, 2024 at 11:36am (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 1899.01MB, 75.03% of 2531.14MB total
Dropped 449 nodes (cum <= 12.66MB)
Showing top 10 nodes out of 161
      flat  flat%   sum%        cum   cum%
  282.77MB 11.17% 11.17%   282.77MB 11.17%  github.com/cockroachdb/pebble.newBatchWithSize
  270.53MB 10.69% 21.86%   270.53MB 10.69%  github.com/ethereum/go-ethereum/triedb/pathdb.init.func2
  241.66MB  9.55% 31.41%   241.66MB  9.55%  github.com/ethereum/go-ethereum/rlp.(*Stream).Bytes
  239.15MB  9.45% 40.86%   239.15MB  9.45%  github.com/ethereum/go-ethereum/rlp.(*encBuffer).makeBytes
  212.01MB  8.38% 49.23%   393.52MB 15.55%  github.com/ethereum/go-ethereum/rlp.decodeBigInt
  181.51MB  7.17% 56.40%   181.51MB  7.17%  math/big.nat.make (inline)
  140.17MB  5.54% 61.94%   201.99MB  7.98%  github.com/VictoriaMetrics/fastcache.(*bucket).Set
  114.01MB  4.50% 66.44%   775.19MB 30.63%  github.com/ethereum/go-ethereum/core/types.(*Transaction).DecodeRLP
  108.70MB  4.29% 70.74%   108.70MB  4.29%  github.com/ethereum/go-ethereum/p2p/rlpx.growslice
  108.51MB  4.29% 75.03%   108.51MB  4.29%  reflect.New

[ALLOC_SPACE]

(pprof) top10
Showing nodes accounting for 51.63TB, 57.18% of 90.30TB total
Dropped 2591 nodes (cum <= 0.45TB)
Showing top 10 nodes out of 223
      flat  flat%   sum%        cum   cum%
   20.53TB 22.74% 22.74%    20.53TB 22.74%  github.com/ethereum/go-ethereum/trie.(*fullNode).copy (inline)
    6.17TB  6.83% 29.57%    17.49TB 19.37%  github.com/ethereum/go-ethereum/trie.(*committer).commitChildren
    5.58TB  6.18% 35.75%     5.58TB  6.18%  github.com/ethereum/go-ethereum/rlp.(*encBuffer).makeBytes (inline)
    5.37TB  5.94% 41.70%    12.86TB 14.24%  github.com/ethereum/go-ethereum/trie.decodeNode
    3.64TB  4.03% 45.73%     7.05TB  7.81%  github.com/ethereum/go-ethereum/trie.decodeFull
    3.42TB  3.78% 49.51%     3.42TB  3.78%  github.com/ethereum/go-ethereum/trie.decodeRef
    2.36TB  2.61% 52.12%     2.36TB  2.61%  github.com/ethereum/go-ethereum/trie.(*tracer).onRead
    1.85TB  2.05% 54.17%     1.85TB  2.05%  golang.org/x/crypto/sha3.NewLegacyKeccak256
    1.46TB  1.62% 55.79%     1.46TB  1.62%  github.com/ethereum/go-ethereum/trie/trienode.(*NodeSet).AddNode (inline)
    1.26TB  1.39% 57.18%     1.26TB  1.39%  github.com/ethereum/go-ethereum/core/vm.codeBitmap

@rjl493456442 rjl493456442 force-pushed the pathdb-lookup-simple branch 2 times, most recently from 1771c3d to d6e8ed4 Compare December 3, 2024 03:09
@rjl493456442
Copy link
Member Author

rjl493456442 commented Dec 4, 2024

After running the benchmark for a few days, these are the conclusion I get:

Bench07 is the pull request; Bench08 is the master;

(a) the performance of node retrieval is improved significantly

The chart illustrates the time required for account trie updates. Clearly, bench07 is significantly faster than master.
More importantly, the prefetcher resolves trie nodes in advance at the transaction boundary, with most nodes being processed in the background. As a result, the actual performance difference is even greater than what the chart shows.

截屏2024-12-04 21 00 18

What's more, the difference can also be observed from the CPU profiling. As we can see about 8.56% cpu time is spent on map access which is caused by pathdb layer iteration. These two parts have been eliminated in PR.

[ Master ]
Showing nodes accounting for 247.19s, 42.68% of 579.16s total
Dropped 2211 nodes (cum <= 2.90s)
Showing top 10 nodes out of 314
      flat  flat%   sum%        cum   cum%
    44.53s  7.69%  7.69%     52.65s  9.09%  runtime.findObject
    41.84s  7.22% 14.91%     42.53s  7.34%  runtime.cgocall                               (ecrecover)
    31.51s  5.44% 20.35%     38.55s  6.66%  runtime.mapaccess2_faststr                    (difflayer.Node)
    28.81s  4.97% 25.33%     28.81s  4.97%  golang.org/x/crypto/sha3.keccakF1600
    25.94s  4.48% 29.81%    141.79s 24.48%  runtime.scanobject
    18.05s  3.12% 32.92%     26.66s  4.60%  runtime.mapaccess2                            (difflayer.Node)
    14.88s  2.57% 35.49%     14.88s  2.57%  internal/runtime/syscall.Syscall6
    14.50s  2.50% 38.00%     14.50s  2.50%  sync/atomic.(*Int32).Add
    13.66s  2.36% 40.35%     13.84s  2.39%  runtime.(*gcBits).bitp (inline)
    13.47s  2.33% 42.68%     49.84s  8.61%  runtime.mallocgc

[ PR ]
Showing nodes accounting for 208.28s, 42.26% of 492.80s total
Dropped 2301 nodes (cum <= 2.46s)
Showing top 10 nodes out of 337
      flat  flat%   sum%        cum   cum%
    44.87s  9.11%  9.11%     45.31s  9.19%  runtime.cgocall                              (ecrecover)                  
    41.51s  8.42% 17.53%     46.76s  9.49%  runtime.findObject
    29.38s  5.96% 23.49%     29.38s  5.96%  golang.org/x/crypto/sha3.keccakF1600
    18.48s  3.75% 27.24%    119.70s 24.29%  runtime.scanobject
    15.85s  3.22% 30.46%     15.85s  3.22%  internal/runtime/syscall.Syscall6
    14.35s  2.91% 33.37%     48.83s  9.91%  runtime.mallocgc
    13.94s  2.83% 36.20%     14.04s  2.85%  runtime.(*gcBits).bitp (inline)
    10.27s  2.08% 38.28%     10.43s  2.12%  runtime.(*mspan).heapBitsSmallForAddr
    10.20s  2.07% 40.35%     10.20s  2.07%  runtime.memmove
     9.43s  1.91% 42.26%     11.84s  2.40%  github.com/ethereum/go-ethereum/core/vm.codeBitmapInternal

(b) triedb commit is slower by having the additional lookup structure

This pull request introduces the lookup structure, which requires updates whenever a new block is processed. The performance difference observed here reflects the associated overhead.

Theoretically, this overhead can be optimized by parallelizing the lookup update procedure, which can save around 1-2ms per block. Unfortunately, the other parts of system (e.g. EVM execution) will be affected with unknown reason. Therefore the optimization is not included in this PR.

截屏2024-12-04 21 04 00

(c) otherwise, no major performance difference is observed

The PR is slightly faster than master. The main reason is for the ancient chain segments (before byzantium fork), prefetcher is basically useless and most of the nodes have to be resolved by the trie itself.

截屏2024-12-04 21 08 04 截屏2024-12-04 21 08 55

All in all, this pull request is still valuable while it doesn't bring too much performance benefits. We should try to optimize the lookup maintain overhead. Besides, this approach will be very valuable for state serving (accounts and storage slots) in path database. So, let's keep it open and evaluate the performance difference on state serving then.

@jingjunLi
Copy link

jingjunLi commented Dec 18, 2024

Hi @rjl493456442, Great work so far! I have a question regarding the recent benchmarks:

The current benchmarks demonstrate significant improvements in node retrieval. However, it appears that the TrieDB commit process is slower.
Would it be possible to apply this optimization to the snapshot diff layer queries? The rationale is as follows:

  1. The snapshot commit process does not consume much time overall.
  2. It can be executed in parallel with the TrieDB commit. Parallelizing these tasks ensures the overall execution time will not increase.

This approach provides optimization for snapshot queries without negatively impacting performance.

@rjl493456442
Copy link
Member Author

Close it in favor of #30971

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.

4 participants