Skip to content

Commit

Permalink
Support purely single threaded execution (#370)
Browse files Browse the repository at this point in the history
When only a single CPU is available:
* Avoid creating threads in StateDB.IntermediateRoot
* Force single threaded hashing
  • Loading branch information
ajsutton authored and sebastianst committed Sep 17, 2024
1 parent 39e73da commit d781223
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 7 deletions.
11 changes: 5 additions & 6 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/holiman/uint256"
"golang.org/x/sync/errgroup"
)

// TriesInMemory represents the number of layers that are kept in RAM.
Expand Down Expand Up @@ -851,9 +850,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// method will internally call a blocking trie fetch from the prefetcher,
// so there's no need to explicitly wait for the prefetchers to finish.
var (
start = time.Now()
workers errgroup.Group
start = time.Now()
)
workers := newWorkerGroup()
if s.db.TrieDB().IsVerkle() {
// Whilst MPT storage tries are independent, Verkle has one single trie
// for all the accounts and all the storage slots merged together. The
Expand Down Expand Up @@ -1225,10 +1224,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
// off some milliseconds from the commit operation. Also accumulate the code
// writes to run in parallel with the computations.
var (
start = time.Now()
root common.Hash
workers errgroup.Group
start = time.Now()
root common.Hash
)
workers := newWorkerGroup()
// Schedule the account trie first since that will be the biggest, so give
// it the most time to crunch.
//
Expand Down
38 changes: 38 additions & 0 deletions core/state/workers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package state

import (
"errors"
"runtime"

"golang.org/x/sync/errgroup"
)

type workerGroup interface {
Go(func() error)
SetLimit(int)
Wait() error
}

func newWorkerGroup() workerGroup {
if runtime.NumCPU() <= 1 {
return &inlineWorkerGroup{}
} else {
var grp errgroup.Group
return &grp
}
}

type inlineWorkerGroup struct {
err error
}

func (i *inlineWorkerGroup) Go(action func() error) {
i.err = errors.Join(i.err, action())
}

func (i *inlineWorkerGroup) SetLimit(_ int) {
}

func (i *inlineWorkerGroup) Wait() error {
return i.err
}
7 changes: 7 additions & 0 deletions fork.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ def:
See upstream Geth PR 28940, and op-geth PR 368 for details.
globs:
- "triedb/pathdb/journal.go"
- title: "Single threaded execution"
description: |
The cannon fault proofs virtual machine does not support the creation of threads. To ensure compatibility,
thread creation is avoided when only a single CPU is available.
globs:
- "core/state/workers.go"
- "trie/hasher.go"
- title: "User API enhancements"
description: "Encode the Deposit Tx properties, the L1 costs, and daisy-chain RPC-calls for pre-Bedrock historical data"
sub:
Expand Down
3 changes: 2 additions & 1 deletion trie/hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package trie

import (
"runtime"
"sync"

"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -45,7 +46,7 @@ var hasherPool = sync.Pool{

func newHasher(parallel bool) *hasher {
h := hasherPool.Get().(*hasher)
h.parallel = parallel
h.parallel = parallel && runtime.NumCPU() > 1
return h
}

Expand Down

0 comments on commit d781223

Please sign in to comment.