Skip to content
Closed

wip #17396

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/scripts/exec_bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
1. sync a minimal node...once synced kill the process

2. in `cmd/scripts/exec_bench/sample.yml` (or create a copy so you're not bothered by git), update the source_dir (from 1.)
2.1 you can also remove the entry for erigon_cmd2 (and only erigon_cmd1 will be executed)

3. create directory and set permissions:

Expand Down
56 changes: 33 additions & 23 deletions cmd/scripts/exec_bench/exec_bench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -223,28 +223,32 @@ parse_config() {
exit 1
fi

if [[ "$ERIGON_CMD2" == "null" ]] || [[ -z "$ERIGON_CMD2" ]]; then
log_error "erigon_cmd2 is not specified in config"
exit 1
fi

# Extract datadirs from commands
DATADIR1=$(extract_datadir "$ERIGON_CMD1" "erigon_cmd1")
DATADIR2=$(extract_datadir "$ERIGON_CMD2" "erigon_cmd2")

# Ensure datadirs are different
if [[ "$DATADIR1" == "$DATADIR2" ]]; then
log_error "Both commands use the same datadir: $DATADIR1"
log_error "Commands must use different datadirs for benchmarking"
exit 1
# erigon_cmd2 is optional
if [[ "$ERIGON_CMD2" != "null" ]] && [[ -n "$ERIGON_CMD2" ]]; then
DATADIR2=$(extract_datadir "$ERIGON_CMD2" "erigon_cmd2")

# Ensure datadirs are different
if [[ "$DATADIR1" == "$DATADIR2" ]]; then
log_error "Both commands use the same datadir: $DATADIR1"
log_error "Commands must use different datadirs for benchmarking"
exit 1
fi

log_info "Configuration loaded:"
log_info " source_datadir: $SOURCE_DATADIR"
log_info " erigon_cmd1: $ERIGON_CMD1"
log_info " extracted datadir1: $DATADIR1"
log_info " erigon_cmd2: $ERIGON_CMD2"
log_info " extracted datadir2: $DATADIR2"
else
log_info "Configuration loaded:"
log_info " source_datadir: $SOURCE_DATADIR"
log_info " erigon_cmd1: $ERIGON_CMD1"
log_info " extracted datadir1: $DATADIR1"
log_info " erigon_cmd2: <not specified>"
fi

log_info "Configuration loaded:"
log_info " source_datadir: $SOURCE_DATADIR"
log_info " erigon_cmd1: $ERIGON_CMD1"
log_info " extracted datadir1: $DATADIR1"
log_info " erigon_cmd2: $ERIGON_CMD2"
log_info " extracted datadir2: $DATADIR2"
}

# Function to mirror datadir
Expand Down Expand Up @@ -343,17 +347,23 @@ main() {
execute_benchmark "$ERIGON_CMD1" "$DATADIR1" 1

log_info ""
log_info "--- Run 2 ---"
mirror_datadir "$SOURCE_DATADIR" "$DATADIR2"
execute_benchmark "$ERIGON_CMD2" "$DATADIR2" 2
if [[ "$ERIGON_CMD2" != "null" ]] && [[ -n "$ERIGON_CMD2" ]]; then
log_info "--- Run 2 ---"
mirror_datadir "$SOURCE_DATADIR" "$DATADIR2"
execute_benchmark "$ERIGON_CMD2" "$DATADIR2" 2
fi



# Summary
log_info "========================================="
log_info "Benchmark execution completed successfully"
log_info "========================================="
log_info "Results:"
log_info " Run 1: $DATADIR1 - Check benchmark_run1_*.log"
log_info " Run 2: $DATADIR2 - Check benchmark_run2_*.log"
if [[ "$ERIGON_CMD2" != "null" ]] && [[ -n "$ERIGON_CMD2" ]]; then
log_info " Run 2: $DATADIR2 - Check benchmark_run2_*.log"
fi
}

main "$@"
4 changes: 3 additions & 1 deletion cmd/scripts/exec_bench/sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ source_datadir: /erigon-data/par_eth
chain: mainnet
## --block is added by script to the stage_exec commands
erigon_cmd1: ERIGON_NO_PRUNE=true ERIGON_NO_MERGE=true ERIGON_DISCARD_COMMITMENT=true ./build/bin/integration stage_exec --datadir /erigon-data/par_eth_serial/ --chain mainnet --batchSize=10g --no-commit --metrics --metrics.addr=0.0.0.0 --metrics.port 6061
erigon_cmd2: ERIGON_EXEC3_PARALLEL=true ERIGON_NO_PRUNE=true ERIGON_NO_MERGE=true ERIGON_DISCARD_COMMITMENT=true ./build/bin/integration stage_exec --datadir /erigon-data/par_eth_par/ --chain mainnet --batchSize=10g --no-commit --metrics --metrics.addr=0.0.0.0 --metrics.port 6062

## if erigon_cmd2 is empty or null, only one run will be done (erigon_cmd1)
#erigon_cmd2: ERIGON_EXEC3_PARALLEL=true ERIGON_NO_PRUNE=true ERIGON_NO_MERGE=true ERIGON_DISCARD_COMMITMENT=true ./build/bin/integration stage_exec --datadir /erigon-data/par_eth_par/ --chain mainnet --batchSize=10g --no-commit --metrics --metrics.addr=0.0.0.0 --metrics.port 6062
44 changes: 9 additions & 35 deletions db/state/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ type u128 struct{ hi, lo uint64 } //nolint
type u192 struct{ hi, lo, ext uint64 } //nolint

type DomainGetFromFileCache struct {
sync.RWMutex
*freelru.LRU[uint64, domainGetFromFileCacheItem]
*freelru.ShardedLRU[uint64, domainGetFromFileCacheItem]
enabled, trace bool
limit uint32
}
Expand All @@ -32,75 +31,50 @@ type domainGetFromFileCacheItem struct {
}

var (
domainGetFromFileCacheLimit = uint32(dbg.EnvInt("D_LRU", 10_000))
domainGetFromFileCacheLimit = uint32(dbg.EnvInt("D_LRU", 1_000_000))
domainGetFromFileCacheTrace = dbg.EnvBool("D_LRU_TRACE", false)
domainGetFromFileCacheEnabled = dbg.EnvBool("D_LRU_ENABLED", true)
)

func NewDomainGetFromFileCache(limit uint32) *DomainGetFromFileCache {
c, err := freelru.New[uint64, domainGetFromFileCacheItem](limit, u64noHash)
c, err := freelru.NewSharded[uint64, domainGetFromFileCacheItem](limit, u64noHash)
if err != nil {
panic(err)
}
return &DomainGetFromFileCache{LRU: c, enabled: domainGetFromFileCacheEnabled, trace: domainGetFromFileCacheTrace, limit: limit}
return &DomainGetFromFileCache{ShardedLRU: c, enabled: domainGetFromFileCacheEnabled, trace: domainGetFromFileCacheTrace, limit: limit}
}

func (c *DomainGetFromFileCache) Add(key uint64, value domainGetFromFileCacheItem) (evicted bool) {
c.Lock()
defer c.Unlock()
return c.LRU.Add(key, value)
return c.ShardedLRU.Add(key, value)
}

func (c *DomainGetFromFileCache) Get(key uint64) (value domainGetFromFileCacheItem, ok bool) {
c.Lock() // get upates cache vars
defer c.Unlock()
return c.LRU.Get(key)
return c.ShardedLRU.Get(key)
}

func (c *DomainGetFromFileCache) SetTrace(v bool) { c.trace = v }
func (c *DomainGetFromFileCache) LogStats(dt kv.Domain) {
if c == nil {
return
}
c.RLock()
defer c.RUnlock()
if !c.enabled || !c.trace {
return
}
m := c.Metrics()
log.Warn("[dbg] DomainGetFromFileCache", "a", dt.String(), "ratio", fmt.Sprintf("%.2f", float64(m.Hits)/float64(m.Hits+m.Misses)), "hit", m.Hits, "Collisions", m.Collisions, "Evictions", m.Evictions, "Inserts", m.Inserts, "limit", c.limit)
}

func newDomainVisible(name kv.Domain, files []visibleFile) *domainVisible {
func newDomainVisible(name kv.Domain, files []visibleFile, resetCache bool) *domainVisible {
d := &domainVisible{
name: name,
files: files,
}
limit := domainGetFromFileCacheLimit
if name == kv.CodeDomain {
limit = limit / 10 // CodeDomain has compressed values - means cache will store values (instead of pointers to mmap)
if resetCache {
d.cache = newDomainCache(name)
}
if limit == 0 {
domainGetFromFileCacheEnabled = false
}
d.caches = &sync.Pool{New: func() any { return NewDomainGetFromFileCache(limit) }}
return d
}

func (v *domainVisible) newGetFromFileCache() *DomainGetFromFileCache {
if !domainGetFromFileCacheEnabled {
return nil
}
return v.caches.Get().(*DomainGetFromFileCache)
}
func (v *domainVisible) returnGetFromFileCache(c *DomainGetFromFileCache) {
if c == nil {
return
}
c.LogStats(v.name)
v.caches.Put(c)
}

var (
iiGetFromFileCacheLimit = uint32(dbg.EnvInt("II_LRU", 4096))
iiGetFromFileCacheTrace = dbg.EnvBool("II_LRU_TRACE", false)
Expand Down
53 changes: 33 additions & 20 deletions db/state/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"path/filepath"
"sort"
"strings"
"sync"
"time"

btree2 "github.com/tidwall/btree"
Expand Down Expand Up @@ -92,10 +91,22 @@ type Domain struct {
checker *DependencyIntegrityChecker
}

func newDomainCache(name kv.Domain) *DomainGetFromFileCache {
limit := domainGetFromFileCacheLimit
if name == kv.CodeDomain {
limit = limit / 100 // CodeDomain has compressed values - means cache will store values (instead of pointers to mmap)
}
if limit == 0 {
domainGetFromFileCacheEnabled = false
return nil
}
return NewDomainGetFromFileCache(limit)
}

type domainVisible struct {
files []visibleFile
name kv.Domain
caches *sync.Pool
files []visibleFile
name kv.Domain
cache *DomainGetFromFileCache
}

func NewDomain(cfg statecfg.DomainCfg, stepSize uint64, dirs datadir.Dirs, logger log.Logger) (*Domain, error) {
Expand All @@ -109,7 +120,7 @@ func NewDomain(cfg statecfg.DomainCfg, stepSize uint64, dirs datadir.Dirs, logge
d := &Domain{
DomainCfg: cfg,
dirtyFiles: btree2.NewBTreeGOptions(filesItemLess, btree2.Options{Degree: 128, NoLocks: false}),
_visible: newDomainVisible(cfg.Name, []visibleFile{}),
_visible: newDomainVisible(cfg.Name, []visibleFile{}, false),
}

var err error
Expand Down Expand Up @@ -341,7 +352,7 @@ func (d *Domain) reCalcVisibleFiles(toTxNum uint64) {
return d.checker.CheckDependentPresent(ue, All, startTxNum, endTxNum)
}
}
d._visible = newDomainVisible(d.Name, calcVisibleFiles(d.dirtyFiles, d.Accessors, checker, false, toTxNum))
d._visible = newDomainVisible(d.Name, calcVisibleFiles(d.dirtyFiles, d.Accessors, checker, false, toTxNum), true)
d.History.reCalcVisibleFiles(toTxNum)
}

Expand Down Expand Up @@ -611,14 +622,19 @@ func (d *Domain) BeginFilesRo() *DomainRoTx {
}
}

if d._visible.cache == nil {
d._visible.cache = newDomainCache(d.Name)
}

return &DomainRoTx{
name: d.Name,
stepSize: d.stepSize,
d: d,
ht: d.History.BeginFilesRo(),
visible: d._visible,
files: d._visible.files,
salt: d.salt.Load(),
name: d.Name,
stepSize: d.stepSize,
d: d,
ht: d.History.BeginFilesRo(),
visible: d._visible,
files: d._visible.files,
salt: d.salt.Load(),
getFromFileCache: d._visible.cache,
}
}

Expand Down Expand Up @@ -1391,11 +1407,8 @@ func (dt *DomainRoTx) getLatestFromFiles(k []byte, maxTxNum uint64) (v []byte, f

getFromFileCache := dt.getFromFileCache

if useCache && getFromFileCache == nil {
if dt.getFromFileCache == nil {
dt.getFromFileCache = dt.visible.newGetFromFileCache()
}
getFromFileCache = dt.getFromFileCache
if !useCache {
getFromFileCache = nil
}
if getFromFileCache != nil && maxTxNum == math.MaxUint64 {
if cv, ok := getFromFileCache.Get(hi); ok {
Expand Down Expand Up @@ -1517,6 +1530,8 @@ func (dt *DomainRoTx) Close() {
dt.closeValsCursor()
files := dt.files
dt.files = nil
dt.getFromFileCache.LogStats(dt.name)
dt.getFromFileCache = nil
for i := range files {
src := files[i].src
if src == nil || src.frozen {
Expand All @@ -1532,8 +1547,6 @@ func (dt *DomainRoTx) Close() {
}
}
dt.ht.Close()

dt.visible.returnGetFromFileCache(dt.getFromFileCache)
}

// reusableReader - for short read-and-forget operations. Must Reset this reader before use
Expand Down
Loading