mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
Move NumSpeculativeProcs from module variable to function parameter (#931)
This will prevent data races when more than one parallel execution are running at the same time.
This commit is contained in:
parent
7e0e4c8905
commit
eedeaed1fb
3 changed files with 41 additions and 43 deletions
|
|
@ -37,12 +37,6 @@ type ExecVersionView struct {
|
||||||
sender common.Address
|
sender common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
var NumSpeculativeProcs int = 8
|
|
||||||
|
|
||||||
func SetProcs(specProcs int) {
|
|
||||||
NumSpeculativeProcs = specProcs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ev *ExecVersionView) Execute() (er ExecResult) {
|
func (ev *ExecVersionView) Execute() (er ExecResult) {
|
||||||
er.ver = ev.ver
|
er.ver = ev.ver
|
||||||
if er.err = ev.et.Execute(ev.mvh, ev.ver.Incarnation); er.err != nil {
|
if er.err = ev.et.Execute(ev.mvh, ev.ver.Incarnation); er.err != nil {
|
||||||
|
|
@ -180,6 +174,9 @@ type ParallelExecutor struct {
|
||||||
// Stores the execution statistics for the last incarnation of each task
|
// Stores the execution statistics for the last incarnation of each task
|
||||||
stats map[int]ExecutionStat
|
stats map[int]ExecutionStat
|
||||||
|
|
||||||
|
// Number of workers that execute transactions speculatively
|
||||||
|
numSpeculativeProcs int
|
||||||
|
|
||||||
statsMutex sync.Mutex
|
statsMutex sync.Mutex
|
||||||
|
|
||||||
// Channel for tasks that should be prioritized
|
// Channel for tasks that should be prioritized
|
||||||
|
|
@ -255,7 +252,7 @@ type ExecutionStat struct {
|
||||||
Worker int
|
Worker int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewParallelExecutor(tasks []ExecTask, profile bool, metadata bool) *ParallelExecutor {
|
func NewParallelExecutor(tasks []ExecTask, profile bool, metadata bool, numProcs int) *ParallelExecutor {
|
||||||
numTasks := len(tasks)
|
numTasks := len(tasks)
|
||||||
|
|
||||||
var resultQueue SafeQueue
|
var resultQueue SafeQueue
|
||||||
|
|
@ -271,27 +268,28 @@ func NewParallelExecutor(tasks []ExecTask, profile bool, metadata bool) *Paralle
|
||||||
}
|
}
|
||||||
|
|
||||||
pe := &ParallelExecutor{
|
pe := &ParallelExecutor{
|
||||||
tasks: tasks,
|
tasks: tasks,
|
||||||
stats: make(map[int]ExecutionStat, numTasks),
|
numSpeculativeProcs: numProcs,
|
||||||
chTasks: make(chan ExecVersionView, numTasks),
|
stats: make(map[int]ExecutionStat, numTasks),
|
||||||
chSpeculativeTasks: make(chan struct{}, numTasks),
|
chTasks: make(chan ExecVersionView, numTasks),
|
||||||
chSettle: make(chan int, numTasks),
|
chSpeculativeTasks: make(chan struct{}, numTasks),
|
||||||
chResults: make(chan struct{}, numTasks),
|
chSettle: make(chan int, numTasks),
|
||||||
specTaskQueue: specTaskQueue,
|
chResults: make(chan struct{}, numTasks),
|
||||||
resultQueue: resultQueue,
|
specTaskQueue: specTaskQueue,
|
||||||
lastSettled: -1,
|
resultQueue: resultQueue,
|
||||||
skipCheck: make(map[int]bool),
|
lastSettled: -1,
|
||||||
execTasks: makeStatusManager(numTasks),
|
skipCheck: make(map[int]bool),
|
||||||
validateTasks: makeStatusManager(0),
|
execTasks: makeStatusManager(numTasks),
|
||||||
diagExecSuccess: make([]int, numTasks),
|
validateTasks: makeStatusManager(0),
|
||||||
diagExecAbort: make([]int, numTasks),
|
diagExecSuccess: make([]int, numTasks),
|
||||||
mvh: MakeMVHashMap(),
|
diagExecAbort: make([]int, numTasks),
|
||||||
lastTxIO: MakeTxnInputOutput(numTasks),
|
mvh: MakeMVHashMap(),
|
||||||
txIncarnations: make([]int, numTasks),
|
lastTxIO: MakeTxnInputOutput(numTasks),
|
||||||
estimateDeps: make(map[int][]int),
|
txIncarnations: make([]int, numTasks),
|
||||||
preValidated: make(map[int]bool),
|
estimateDeps: make(map[int][]int),
|
||||||
begin: time.Now(),
|
preValidated: make(map[int]bool),
|
||||||
profile: profile,
|
begin: time.Now(),
|
||||||
|
profile: profile,
|
||||||
}
|
}
|
||||||
|
|
||||||
return pe
|
return pe
|
||||||
|
|
@ -329,10 +327,10 @@ func (pe *ParallelExecutor) Prepare() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pe.workerWg.Add(NumSpeculativeProcs + numGoProcs)
|
pe.workerWg.Add(pe.numSpeculativeProcs + numGoProcs)
|
||||||
|
|
||||||
// Launch workers that execute transactions
|
// Launch workers that execute transactions
|
||||||
for i := 0; i < NumSpeculativeProcs+numGoProcs; i++ {
|
for i := 0; i < pe.numSpeculativeProcs+numGoProcs; i++ {
|
||||||
go func(procNum int) {
|
go func(procNum int) {
|
||||||
defer pe.workerWg.Done()
|
defer pe.workerWg.Done()
|
||||||
|
|
||||||
|
|
@ -366,7 +364,7 @@ func (pe *ParallelExecutor) Prepare() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if procNum < NumSpeculativeProcs {
|
if procNum < pe.numSpeculativeProcs {
|
||||||
for range pe.chSpeculativeTasks {
|
for range pe.chSpeculativeTasks {
|
||||||
doWork(pe.specTaskQueue.Pop().(ExecVersionView))
|
doWork(pe.specTaskQueue.Pop().(ExecVersionView))
|
||||||
}
|
}
|
||||||
|
|
@ -597,12 +595,12 @@ func (pe *ParallelExecutor) Step(res *ExecResult) (result ParallelExecutionResul
|
||||||
|
|
||||||
type PropertyCheck func(*ParallelExecutor) error
|
type PropertyCheck func(*ParallelExecutor) error
|
||||||
|
|
||||||
func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyCheck, metadata bool, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
|
func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyCheck, metadata bool, numProcs int, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
|
||||||
if len(tasks) == 0 {
|
if len(tasks) == 0 {
|
||||||
return ParallelExecutionResult{MakeTxnInputOutput(len(tasks)), nil, nil, nil}, nil
|
return ParallelExecutionResult{MakeTxnInputOutput(len(tasks)), nil, nil, nil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pe := NewParallelExecutor(tasks, profile, metadata)
|
pe := NewParallelExecutor(tasks, profile, metadata, numProcs)
|
||||||
err = pe.Prepare()
|
err = pe.Prepare()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -636,6 +634,6 @@ func executeParallelWithCheck(tasks []ExecTask, profile bool, check PropertyChec
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteParallel(tasks []ExecTask, profile bool, metadata bool, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
|
func ExecuteParallel(tasks []ExecTask, profile bool, metadata bool, numProcs int, interruptCtx context.Context) (result ParallelExecutionResult, err error) {
|
||||||
return executeParallelWithCheck(tasks, profile, nil, metadata, interruptCtx)
|
return executeParallelWithCheck(tasks, profile, nil, metadata, numProcs, interruptCtx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import (
|
||||||
|
|
||||||
type OpType int
|
type OpType int
|
||||||
|
|
||||||
|
var numProcs = 8
|
||||||
|
|
||||||
const readType = 0
|
const readType = 0
|
||||||
const writeType = 1
|
const writeType = 1
|
||||||
const otherType = 2
|
const otherType = 2
|
||||||
|
|
@ -425,7 +427,7 @@ func runParallel(t *testing.T, tasks []ExecTask, validation PropertyCheck, metad
|
||||||
profile := false
|
profile := false
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
result, err := executeParallelWithCheck(tasks, false, validation, metadata, nil)
|
result, err := executeParallelWithCheck(tasks, false, validation, metadata, numProcs, nil)
|
||||||
|
|
||||||
if result.Deps != nil && profile {
|
if result.Deps != nil && profile {
|
||||||
result.Deps.Report(*result.Stats, func(str string) { fmt.Println(str) })
|
result.Deps.Report(*result.Stats, func(str string) { fmt.Println(str) })
|
||||||
|
|
@ -458,7 +460,7 @@ func runParallel(t *testing.T, tasks []ExecTask, validation PropertyCheck, metad
|
||||||
func runParallelGetMetadata(t *testing.T, tasks []ExecTask, validation PropertyCheck) map[int]map[int]bool {
|
func runParallelGetMetadata(t *testing.T, tasks []ExecTask, validation PropertyCheck) map[int]map[int]bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
res, err := executeParallelWithCheck(tasks, true, validation, false, nil)
|
res, err := executeParallelWithCheck(tasks, true, validation, false, numProcs, nil)
|
||||||
|
|
||||||
assert.NoError(t, err, "error occur during parallel execution")
|
assert.NoError(t, err, "error occur during parallel execution")
|
||||||
|
|
||||||
|
|
@ -943,7 +945,7 @@ func TestBreakFromCircularDependency(t *testing.T) {
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
// This should not hang
|
// This should not hang
|
||||||
_, err := ExecuteParallel(tasks, false, true, ctx)
|
_, err := ExecuteParallel(tasks, false, true, numProcs, ctx)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected cancel error")
|
t.Error("Expected cancel error")
|
||||||
|
|
@ -976,7 +978,7 @@ func TestBreakFromPartialCircularDependency(t *testing.T) {
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
// This should not hang
|
// This should not hang
|
||||||
_, err := ExecuteParallel(tasks, false, true, ctx)
|
_, err := ExecuteParallel(tasks, false, true, numProcs, ctx)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected cancel error")
|
t.Error("Expected cancel error")
|
||||||
|
|
|
||||||
|
|
@ -263,8 +263,6 @@ var parallelizabilityTimer = metrics.NewRegisteredTimer("block/parallelizability
|
||||||
// transactions failed to execute due to insufficient gas it will return an error.
|
// transactions failed to execute due to insufficient gas it will return an error.
|
||||||
// nolint:gocognit
|
// nolint:gocognit
|
||||||
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
||||||
blockstm.SetProcs(cfg.ParallelSpeculativeProcesses)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
receipts types.Receipts
|
receipts types.Receipts
|
||||||
header = block.Header()
|
header = block.Header()
|
||||||
|
|
@ -364,7 +362,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
||||||
backupStateDB := statedb.Copy()
|
backupStateDB := statedb.Copy()
|
||||||
|
|
||||||
profile := false
|
profile := false
|
||||||
result, err := blockstm.ExecuteParallel(tasks, profile, metadata, interruptCtx)
|
result, err := blockstm.ExecuteParallel(tasks, profile, metadata, cfg.ParallelSpeculativeProcesses, interruptCtx)
|
||||||
|
|
||||||
if err == nil && profile && result.Deps != nil {
|
if err == nil && profile && result.Deps != nil {
|
||||||
_, weight := result.Deps.LongestPath(*result.Stats)
|
_, weight := result.Deps.LongestPath(*result.Stats)
|
||||||
|
|
@ -398,7 +396,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
||||||
t.totalUsedGas = usedGas
|
t.totalUsedGas = usedGas
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = blockstm.ExecuteParallel(tasks, false, metadata, interruptCtx)
|
_, err = blockstm.ExecuteParallel(tasks, false, metadata, cfg.ParallelSpeculativeProcesses, interruptCtx)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue