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

View file

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

View file

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

View file

@ -52,12 +52,14 @@ type AmbiguousAddrError struct {
func (err *AmbiguousAddrError) Error() string {
files := ""
var filesSb55 strings.Builder
for i, a := range err.Matches {
files += a.URL.Path
filesSb55.WriteString(a.URL.Path)
if i < len(err.Matches)-1 {
files += ", "
filesSb55.WriteString(", ")
}
}
files += filesSb55.String()
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.
var outSb112 strings.Builder
for i := 0; i < len(kv); i += 2 {
key := kv[i].(string)
val := kv[i+1].(rlp.RawValue)
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]
if formatter == nil {
formatter = formatAttrRaw
}
fmtval, ok := formatter(val)
if ok {
out += fmtval + "\n"
outSb112.WriteString(fmtval + "\n")
} else {
out += hex.EncodeToString(val) + " (!)\n"
outSb112.WriteString(hex.EncodeToString(val) + " (!)\n")
}
}
out += outSb112.String()
return out
}

View file

@ -265,9 +265,11 @@ func confirmAndRemoveDB(paths []string, kind string, ctx *cli.Context, removeFla
err error
)
msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
var msgSb268 strings.Builder
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)
if ctx.IsSet(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
// 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("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")
}
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
@ -2704,11 +2704,13 @@ func (bc *BlockChain) logForkReadiness(block *types.Block) {
// relevant information.
func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string {
var receiptString string
var receiptStringSb2707 strings.Builder
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(),
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()
platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS)
if vcs != "" {

View file

@ -24,6 +24,7 @@ import (
"bytes"
"errors"
"fmt"
"strings"
"sync"
"time"
@ -280,6 +281,7 @@ func (db *Database) Stat() (string, error) {
if len(stats.LevelSizes) > 0 {
message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" +
"-------+------------+---------------+---------------+---------------+---------------\n"
var messageSb283 strings.Builder
for level, size := range stats.LevelSizes {
read := stats.LevelRead[level]
write := stats.LevelWrite[level]
@ -294,10 +296,11 @@ func (db *Database) Stat() (string, error) {
totalRead += read
totalWrite += write
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(),
float64(read)/1048576.0, float64(write)/1048576.0)
float64(read)/1048576.0, float64(write)/1048576.0))
}
message += messageSb283.String()
message += "-------+------------+---------------+---------------+---------------+---------------\n"
message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
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
matcher := ".*"
var matcherSb116 strings.Builder
for _, comp := range strings.Split(parts[0], "/") {
if comp == "*" {
matcher += "(/.*)?"
matcherSb116.WriteString("(/.*)?")
} else if comp != "" {
matcher += "/" + regexp.QuoteMeta(comp)
}
}
matcher += matcherSb116.String()
if !strings.HasSuffix(parts[0], ".go") {
matcher += "/[^/]+\\.go"
}

View file

@ -693,7 +693,7 @@ func (c *ChainConfig) Description() string {
if c.VerkleTime != nil {
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
}

View file

@ -22,6 +22,7 @@ import (
"go/format"
"go/types"
"sort"
"strings"
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
"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 {
selector := v + "." + field.name
cond := ""
var condSb627 strings.Builder
for j := i; j < len(op.optionalFields); j++ {
if j > i {
cond += " || "
condSb627.WriteString(" || ")
}
cond += zeroV[j]
condSb627.WriteString(zeroV[j])
}
cond += condSb627.String()
fmt.Fprintf(b, "if %s {\n", cond)
fmt.Fprint(b, field.elem.genWrite(ctx, selector))
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 {
resp := fmt.Sprintf("[\n%s ", ind)
var respSb104 strings.Builder
for i, node := range &n.Children {
if node == nil {
resp += fmt.Sprintf("%s: <nil> ", indices[i])
respSb104.WriteString(fmt.Sprintf("%s: <nil> ", indices[i]))
} 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)
}

View file

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