mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
trie: add combined depth summary
This commit is contained in:
parent
a596a0aba3
commit
07015878c7
2 changed files with 123 additions and 4 deletions
|
|
@ -328,9 +328,11 @@ func Summarize(dumpPath string, config *InspectConfig) error {
|
|||
}
|
||||
summary.StorageCount++
|
||||
summary.DepthHistogram[snapshot.MaxDepth]++
|
||||
summary.StorageTotals.Short += snapshot.Summary.Short
|
||||
summary.StorageTotals.Full += snapshot.Summary.Full
|
||||
summary.StorageTotals.Value += snapshot.Summary.Value
|
||||
for i := 0; i < trieStatLevels; i++ {
|
||||
summary.StorageLevels[i].Short += record.Levels[i].Short
|
||||
summary.StorageLevels[i].Full += record.Levels[i].Full
|
||||
summary.StorageLevels[i].Value += record.Levels[i].Value
|
||||
}
|
||||
|
||||
depthTop.TryInsert(snapshot)
|
||||
totalTop.TryInsert(snapshot)
|
||||
|
|
@ -339,6 +341,11 @@ func Summarize(dumpPath string, config *InspectConfig) error {
|
|||
if summary.Account == nil {
|
||||
return fmt.Errorf("dump file %s does not contain the account trie sentinel record", dumpPath)
|
||||
}
|
||||
for i := 0; i < trieStatLevels; i++ {
|
||||
summary.StorageTotals.Short += summary.StorageLevels[i].Short
|
||||
summary.StorageTotals.Full += summary.StorageLevels[i].Full
|
||||
summary.StorageTotals.Value += summary.StorageLevels[i].Value
|
||||
}
|
||||
summary.TopByDepth = depthTop.Sorted()
|
||||
summary.TopByTotalNodes = totalTop.Sorted()
|
||||
summary.TopByValueNodes = valueTop.Sorted()
|
||||
|
|
@ -522,6 +529,7 @@ type inspectSummary struct {
|
|||
Account *storageStats
|
||||
StorageCount uint64
|
||||
StorageTotals jsonLevel
|
||||
StorageLevels [trieStatLevels]jsonLevel
|
||||
DepthHistogram [trieStatLevels]uint64
|
||||
TopByDepth []*storageStats
|
||||
TopByTotalNodes []*storageStats
|
||||
|
|
@ -529,6 +537,7 @@ type inspectSummary struct {
|
|||
}
|
||||
|
||||
func (s *inspectSummary) display() {
|
||||
s.displayCombinedDepthTable()
|
||||
s.Account.toLevelStats().display("Accounts trie")
|
||||
fmt.Println("Storage trie aggregate summary")
|
||||
fmt.Printf("Total storage tries: %d\n", s.StorageCount)
|
||||
|
|
@ -553,6 +562,30 @@ func (s *inspectSummary) display() {
|
|||
s.displayTop("Top storage tries by value (slot) count", s.TopByValueNodes)
|
||||
}
|
||||
|
||||
func (s *inspectSummary) displayCombinedDepthTable() {
|
||||
accountTotal := s.Account.Summary.Short + s.Account.Summary.Full + s.Account.Summary.Value
|
||||
storageTotal := s.StorageTotals.Short + s.StorageTotals.Full + s.StorageTotals.Value
|
||||
|
||||
fmt.Println("Trie Depth Distribution")
|
||||
fmt.Printf("Account Trie: %d nodes\n", accountTotal)
|
||||
fmt.Printf("Storage Tries: %d nodes across %d tries\n", storageTotal, s.StorageCount)
|
||||
|
||||
b := new(strings.Builder)
|
||||
table := tablewriter.NewWriter(b)
|
||||
table.SetHeader([]string{"Depth", "Account Nodes", "Storage Nodes"})
|
||||
for i := 0; i < trieStatLevels; i++ {
|
||||
accountNodes := s.Account.Levels[i].Short + s.Account.Levels[i].Full + s.Account.Levels[i].Value
|
||||
storageNodes := s.StorageLevels[i].Short + s.StorageLevels[i].Full + s.StorageLevels[i].Value
|
||||
if accountNodes == 0 && storageNodes == 0 {
|
||||
continue
|
||||
}
|
||||
table.AppendBulk([][]string{{fmt.Sprint(i), fmt.Sprint(accountNodes), fmt.Sprint(storageNodes)}})
|
||||
}
|
||||
table.Render()
|
||||
fmt.Print(b.String())
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func (s *inspectSummary) displayTop(title string, list []*storageStats) {
|
||||
fmt.Println(title)
|
||||
if len(list) == 0 {
|
||||
|
|
@ -575,6 +608,7 @@ func (s *inspectSummary) MarshalJSON() ([]byte, error) {
|
|||
type jsonStorageSummary struct {
|
||||
TotalStorageTries uint64 `json:"TotalStorageTries"`
|
||||
Totals jsonLevel `json:"Totals"`
|
||||
Levels []jsonLevel `json:"Levels"`
|
||||
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
|
||||
}
|
||||
type jsonInspectSummary struct {
|
||||
|
|
@ -593,6 +627,7 @@ func (s *inspectSummary) MarshalJSON() ([]byte, error) {
|
|||
StorageSummary: jsonStorageSummary{
|
||||
TotalStorageTries: s.StorageCount,
|
||||
Totals: s.StorageTotals,
|
||||
Levels: trimLevels(s.StorageLevels),
|
||||
DepthHistogram: s.DepthHistogram,
|
||||
},
|
||||
TopByDepth: s.TopByDepth,
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
|
|
@ -56,12 +59,93 @@ func TestInspect(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("inspect failed: %v", err)
|
||||
}
|
||||
reanalysisPath := filepath.Join(tempDir, "trie-summary-reanalysis.json")
|
||||
if err := Summarize(dumpPath, &InspectConfig{
|
||||
TopN: 1,
|
||||
Path: filepath.Join(tempDir, "trie-summary-reanalysis.json"),
|
||||
Path: reanalysisPath,
|
||||
}); err != nil {
|
||||
t.Fatalf("summarize failed: %v", err)
|
||||
}
|
||||
|
||||
inspectSummaryPath := filepath.Join(tempDir, "trie-summary.json")
|
||||
inspectOut := loadInspectJSON(t, inspectSummaryPath)
|
||||
reanalysisOut := loadInspectJSON(t, reanalysisPath)
|
||||
|
||||
if len(inspectOut.StorageSummary.Levels) == 0 {
|
||||
t.Fatal("expected StorageSummary.Levels to be populated")
|
||||
}
|
||||
if !reflect.DeepEqual(inspectOut.AccountTrie, reanalysisOut.AccountTrie) {
|
||||
t.Fatal("account trie summary mismatch between inspect and summarize")
|
||||
}
|
||||
if !reflect.DeepEqual(inspectOut.StorageSummary, reanalysisOut.StorageSummary) {
|
||||
t.Fatal("storage summary mismatch between inspect and summarize")
|
||||
}
|
||||
|
||||
assertStorageTotalsMatchLevels(t, inspectOut)
|
||||
assertStorageTotalsMatchLevels(t, reanalysisOut)
|
||||
assertAccountTotalsMatchLevels(t, inspectOut.AccountTrie)
|
||||
assertAccountTotalsMatchLevels(t, reanalysisOut.AccountTrie)
|
||||
|
||||
var histogramTotal uint64
|
||||
for _, count := range inspectOut.StorageSummary.DepthHistogram {
|
||||
histogramTotal += count
|
||||
}
|
||||
if histogramTotal != inspectOut.StorageSummary.TotalStorageTries {
|
||||
t.Fatalf("depth histogram total %d does not match total storage tries %d", histogramTotal, inspectOut.StorageSummary.TotalStorageTries)
|
||||
}
|
||||
}
|
||||
|
||||
type inspectJSONOutput struct {
|
||||
// Reuse storageStats for AccountTrie JSON to avoid introducing a parallel
|
||||
// account summary test type. AccountTrie JSON includes Levels+Summary,
|
||||
// which map directly; other storageStats fields remain zero-values.
|
||||
AccountTrie storageStats `json:"AccountTrie"`
|
||||
|
||||
StorageSummary struct {
|
||||
TotalStorageTries uint64 `json:"TotalStorageTries"`
|
||||
Totals jsonLevel `json:"Totals"`
|
||||
Levels []jsonLevel `json:"Levels"`
|
||||
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
|
||||
} `json:"StorageSummary"`
|
||||
}
|
||||
|
||||
func loadInspectJSON(t *testing.T, path string) inspectJSONOutput {
|
||||
t.Helper()
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read %s: %v", path, err)
|
||||
}
|
||||
var out inspectJSONOutput
|
||||
if err := json.Unmarshal(raw, &out); err != nil {
|
||||
t.Fatalf("failed to decode %s: %v", path, err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func assertStorageTotalsMatchLevels(t *testing.T, out inspectJSONOutput) {
|
||||
t.Helper()
|
||||
var fromLevels jsonLevel
|
||||
for _, level := range out.StorageSummary.Levels {
|
||||
fromLevels.Short += level.Short
|
||||
fromLevels.Full += level.Full
|
||||
fromLevels.Value += level.Value
|
||||
}
|
||||
if fromLevels.Short != out.StorageSummary.Totals.Short || fromLevels.Full != out.StorageSummary.Totals.Full || fromLevels.Value != out.StorageSummary.Totals.Value {
|
||||
t.Fatalf("storage totals mismatch: levels=%+v totals=%+v", fromLevels, out.StorageSummary.Totals)
|
||||
}
|
||||
}
|
||||
|
||||
func assertAccountTotalsMatchLevels(t *testing.T, account storageStats) {
|
||||
t.Helper()
|
||||
var fromLevels jsonLevel
|
||||
for _, level := range account.Levels {
|
||||
fromLevels.Short += level.Short
|
||||
fromLevels.Full += level.Full
|
||||
fromLevels.Value += level.Value
|
||||
}
|
||||
if fromLevels.Short != account.Summary.Short || fromLevels.Full != account.Summary.Full || fromLevels.Value != account.Summary.Value {
|
||||
t.Fatalf("account totals mismatch: levels=%+v totals=%+v", fromLevels, account.Summary)
|
||||
}
|
||||
}
|
||||
|
||||
func makeAccountsWithStorage(db *testDb, size int, storage bool) (addresses [][20]byte, accounts [][]byte) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue