perf: use strings.Builder

instead of concatenating strings in a loop
Avoids quadratic complexity
This commit is contained in:
Philippe Antoine 2025-11-06 13:49:47 +01:00
parent 15ff378a89
commit 1625a322f4
13 changed files with 52 additions and 25 deletions

View file

@ -19,6 +19,7 @@ package abi
import ( import (
"errors" "errors"
"fmt" "fmt"
"strings"
) )
type SelectorMarshaling struct { type SelectorMarshaling struct {
@ -68,19 +69,23 @@ func parseElementaryType(unescapedSelector string) (string, string, error) {
return "", "", fmt.Errorf("failed to parse elementary type: %v", err) return "", "", fmt.Errorf("failed to parse elementary type: %v", err)
} }
// handle arrays // handle arrays
var parsedTypeSb71 strings.Builder
for len(rest) > 0 && rest[0] == '[' { for len(rest) > 0 && rest[0] == '[' {
parsedType = parsedType + string(rest[0]) parsedTypeSb71.WriteString(string(rest[0]))
rest = rest[1:] rest = rest[1:]
var parsedTypeSb74 strings.Builder
for len(rest) > 0 && isDigit(rest[0]) { for len(rest) > 0 && isDigit(rest[0]) {
parsedType = parsedType + string(rest[0]) parsedTypeSb74.WriteString(string(rest[0]))
rest = rest[1:] rest = rest[1:]
} }
parsedType += parsedTypeSb74.String()
if len(rest) == 0 || rest[0] != ']' { if len(rest) == 0 || rest[0] != ']' {
return "", "", fmt.Errorf("failed to parse array: expected ']', got %c", unescapedSelector[0]) return "", "", fmt.Errorf("failed to parse array: expected ']', got %c", unescapedSelector[0])
} }
parsedType = parsedType + string(rest[0]) parsedTypeSb71.WriteString(string(rest[0]))
rest = rest[1:] rest = rest[1:]
} }
parsedType += parsedTypeSb71.String()
return parsedType, rest, nil return parsedType, rest, nil
} }

View file

@ -171,6 +171,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
used = make(map[string]bool) used = make(map[string]bool)
) )
expression += "(" expression += "("
var expressionSb174 strings.Builder
for idx, c := range components { for idx, c := range components {
cType, err := NewType(c.Type, c.InternalType, c.Components) cType, err := NewType(c.Type, c.InternalType, c.Components)
if err != nil { if err != nil {
@ -192,11 +193,12 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
}) })
elems = append(elems, &cType) elems = append(elems, &cType)
names = append(names, c.Name) names = append(names, c.Name)
expression += cType.stringKind expressionSb174.WriteString(cType.stringKind)
if idx != len(components)-1 { if idx != len(components)-1 {
expression += "," expressionSb174.WriteString(",")
} }
} }
expression += expressionSb174.String()
expression += ")" expression += ")"
typ.TupleType = reflect.StructOf(fields) typ.TupleType = reflect.StructOf(fields)

View file

@ -121,6 +121,7 @@ func ParseDerivationPath(path string) (DerivationPath, error) {
// to its canonical representation. // to its canonical representation.
func (path DerivationPath) String() string { func (path DerivationPath) String() string {
result := "m" result := "m"
var resultSb124 strings.Builder
for _, component := range path { for _, component := range path {
var hardened bool var hardened bool
if component >= 0x80000000 { if component >= 0x80000000 {
@ -129,9 +130,10 @@ func (path DerivationPath) String() string {
} }
result = fmt.Sprintf("%s/%d", result, component) result = fmt.Sprintf("%s/%d", result, component)
if hardened { if hardened {
result += "'" resultSb124.WriteString("'")
} }
} }
result += resultSb124.String()
return result return result
} }

View file

@ -52,12 +52,14 @@ type AmbiguousAddrError struct {
func (err *AmbiguousAddrError) Error() string { func (err *AmbiguousAddrError) Error() string {
files := "" files := ""
var filesSb55 strings.Builder
for i, a := range err.Matches { for i, a := range err.Matches {
files += a.URL.Path filesSb55.WriteString(a.URL.Path)
if i < len(err.Matches)-1 { if i < len(err.Matches)-1 {
files += ", " filesSb55.WriteString(", ")
} }
} }
files += filesSb55.String()
return fmt.Sprintf("multiple keys match address (%s)", files) return fmt.Sprintf("multiple keys match address (%s)", files)
} }

View file

@ -109,22 +109,24 @@ func dumpRecordKV(kv []interface{}, indent int) string {
} }
} }
// Print the keys, invoking formatters for known keys. // Print the keys, invoking formatters for known keys.
var outSb112 strings.Builder
for i := 0; i < len(kv); i += 2 { for i := 0; i < len(kv); i += 2 {
key := kv[i].(string) key := kv[i].(string)
val := kv[i+1].(rlp.RawValue) val := kv[i+1].(rlp.RawValue)
pad := longestKey - len(key) pad := longestKey - len(key)
out += strings.Repeat(" ", indent) + strconv.Quote(key) + strings.Repeat(" ", pad+1) outSb112.WriteString(strings.Repeat(" ", indent) + strconv.Quote(key) + strings.Repeat(" ", pad+1))
formatter := attrFormatters[key] formatter := attrFormatters[key]
if formatter == nil { if formatter == nil {
formatter = formatAttrRaw formatter = formatAttrRaw
} }
fmtval, ok := formatter(val) fmtval, ok := formatter(val)
if ok { if ok {
out += fmtval + "\n" outSb112.WriteString(fmtval + "\n")
} else { } else {
out += hex.EncodeToString(val) + " (!)\n" outSb112.WriteString(hex.EncodeToString(val) + " (!)\n")
} }
} }
out += outSb112.String()
return out return out
} }

View file

@ -265,9 +265,11 @@ func confirmAndRemoveDB(paths []string, kind string, ctx *cli.Context, removeFla
err error err error
) )
msg := fmt.Sprintf("Location(s) of '%s': \n", kind) msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
var msgSb268 strings.Builder
for _, path := range paths { for _, path := range paths {
msg += fmt.Sprintf("\t- %s\n", path) msgSb268.WriteString(fmt.Sprintf("\t- %s\n", path))
} }
msg += msgSb268.String()
fmt.Println(msg) fmt.Println(msg)
if ctx.IsSet(removeFlagName) { if ctx.IsSet(removeFlagName) {
confirm = ctx.Bool(removeFlagName) confirm = ctx.Bool(removeFlagName)

View file

@ -711,7 +711,7 @@ func (bc *BlockChain) initializeHistoryPruning(latest uint64) error {
// here, but it'd be a bit dangerous since they may not have intended this // here, but it'd be a bit dangerous since they may not have intended this
// action to happen. So just tell them how to do it. // action to happen. So just tell them how to do it.
log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cfg.ChainHistoryMode.String())) log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cfg.ChainHistoryMode.String()))
log.Error(fmt.Sprintf("Run 'geth prune-history' to prune pre-merge history.")) log.Error("Run 'geth prune-history' to prune pre-merge history.")
return errors.New("history pruning requested via configuration") return errors.New("history pruning requested via configuration")
} }
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()] predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
@ -2704,11 +2704,13 @@ func (bc *BlockChain) logForkReadiness(block *types.Block) {
// relevant information. // relevant information.
func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string {
var receiptString string var receiptString string
var receiptStringSb2707 strings.Builder
for i, receipt := range receipts { for i, receipt := range receipts {
receiptString += fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x", receiptStringSb2707.WriteString(fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x",
i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(),
receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState))
} }
receiptString += receiptStringSb2707.String()
version, vcs := version.Info() version, vcs := version.Info()
platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS)
if vcs != "" { if vcs != "" {

View file

@ -24,6 +24,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"strings"
"sync" "sync"
"time" "time"
@ -280,6 +281,7 @@ func (db *Database) Stat() (string, error) {
if len(stats.LevelSizes) > 0 { if len(stats.LevelSizes) > 0 {
message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" +
"-------+------------+---------------+---------------+---------------+---------------\n" "-------+------------+---------------+---------------+---------------+---------------\n"
var messageSb283 strings.Builder
for level, size := range stats.LevelSizes { for level, size := range stats.LevelSizes {
read := stats.LevelRead[level] read := stats.LevelRead[level]
write := stats.LevelWrite[level] write := stats.LevelWrite[level]
@ -294,10 +296,11 @@ func (db *Database) Stat() (string, error) {
totalRead += read totalRead += read
totalWrite += write totalWrite += write
totalDuration += duration totalDuration += duration
message += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", messageSb283.WriteString(fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
level, tables, float64(size)/1048576.0, duration.Seconds(), level, tables, float64(size)/1048576.0, duration.Seconds(),
float64(read)/1048576.0, float64(write)/1048576.0) float64(read)/1048576.0, float64(write)/1048576.0))
} }
message += messageSb283.String()
message += "-------+------------+---------------+---------------+---------------+---------------\n" message += "-------+------------+---------------+---------------+---------------+---------------\n"
message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(), totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(),

View file

@ -113,13 +113,15 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
} }
// Compile the rule pattern into a regular expression // Compile the rule pattern into a regular expression
matcher := ".*" matcher := ".*"
var matcherSb116 strings.Builder
for _, comp := range strings.Split(parts[0], "/") { for _, comp := range strings.Split(parts[0], "/") {
if comp == "*" { if comp == "*" {
matcher += "(/.*)?" matcherSb116.WriteString("(/.*)?")
} else if comp != "" { } else if comp != "" {
matcher += "/" + regexp.QuoteMeta(comp) matcher += "/" + regexp.QuoteMeta(comp)
} }
} }
matcher += matcherSb116.String()
if !strings.HasSuffix(parts[0], ".go") { if !strings.HasSuffix(parts[0], ".go") {
matcher += "/[^/]+\\.go" matcher += "/[^/]+\\.go"
} }

View file

@ -693,7 +693,7 @@ func (c *ChainConfig) Description() string {
if c.VerkleTime != nil { if c.VerkleTime != nil {
banner += fmt.Sprintf(" - Verkle: @%-10v blob: (%s)\n", *c.VerkleTime, c.BlobScheduleConfig.Verkle) banner += fmt.Sprintf(" - Verkle: @%-10v blob: (%s)\n", *c.VerkleTime, c.BlobScheduleConfig.Verkle)
} }
banner += fmt.Sprintf("\nAll fork specifications can be found at https://ethereum.github.io/execution-specs/src/ethereum/forks/\n") banner += "\nAll fork specifications can be found at https://ethereum.github.io/execution-specs/src/ethereum/forks/\n"
return banner return banner
} }

View file

@ -22,6 +22,7 @@ import (
"go/format" "go/format"
"go/types" "go/types"
"sort" "sort"
"strings"
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
@ -624,12 +625,14 @@ func (op structOp) writeOptionalFields(b *bytes.Buffer, ctx *genContext, v strin
for i, field := range op.optionalFields { for i, field := range op.optionalFields {
selector := v + "." + field.name selector := v + "." + field.name
cond := "" cond := ""
var condSb627 strings.Builder
for j := i; j < len(op.optionalFields); j++ { for j := i; j < len(op.optionalFields); j++ {
if j > i { if j > i {
cond += " || " condSb627.WriteString(" || ")
} }
cond += zeroV[j] condSb627.WriteString(zeroV[j])
} }
cond += condSb627.String()
fmt.Fprintf(b, "if %s {\n", cond) fmt.Fprintf(b, "if %s {\n", cond)
fmt.Fprint(b, field.elem.genWrite(ctx, selector)) fmt.Fprint(b, field.elem.genWrite(ctx, selector))
fmt.Fprintf(b, "}\n") fmt.Fprintf(b, "}\n")

View file

@ -101,13 +101,15 @@ func (n valueNode) String() string { return n.fstring("") }
func (n *fullNode) fstring(ind string) string { func (n *fullNode) fstring(ind string) string {
resp := fmt.Sprintf("[\n%s ", ind) resp := fmt.Sprintf("[\n%s ", ind)
var respSb104 strings.Builder
for i, node := range &n.Children { for i, node := range &n.Children {
if node == nil { if node == nil {
resp += fmt.Sprintf("%s: <nil> ", indices[i]) respSb104.WriteString(fmt.Sprintf("%s: <nil> ", indices[i]))
} else { } else {
resp += fmt.Sprintf("%s: %v", indices[i], node.fstring(ind+" ")) respSb104.WriteString(fmt.Sprintf("%s: %v", indices[i], node.fstring(ind+" ")))
} }
} }
resp += respSb104.String()
return resp + fmt.Sprintf("\n%s] ", ind) return resp + fmt.Sprintf("\n%s] ", ind)
} }

View file

@ -606,9 +606,9 @@ func (db *Database) journalPath() string {
} }
var fname string var fname string
if db.isVerkle { if db.isVerkle {
fname = fmt.Sprintf("verkle.journal") fname = "verkle.journal"
} else { } else {
fname = fmt.Sprintf("merkle.journal") fname = "merkle.journal"
} }
return filepath.Join(db.config.JournalDirectory, fname) return filepath.Join(db.config.JournalDirectory, fname)
} }