Skip to content

all: reuse the global hash buffer #31839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Conversation

nthumann
Copy link

As #31769 defined a global hash pool, so we can reuse it, and also remove the unnecessary KeccakState buffering

@MariusVanDerWijden
Copy link
Member

I pretty deliberately not changed these cases as I think using the buffer here would be a tiny bit slower than reusing the buffer that we already have. I would be fine with merging it, if you could show that the two approaches are roughly the same time wise

@nthumann
Copy link
Author

I pretty deliberately not changed these cases as I think using the buffer here would be a tiny bit slower than reusing the buffer that we already have. I would be fine with merging it, if you could show that the two approaches are roughly the same time wise

I added a benchmark test for rawdb.SafeDeleteRange, here is the result with benchstat:

$ go test -benchmem --benchtime=1m -run=^$ -bench ^BenchmarkSafeDeleteRange github.com/ethereum/go-ethereum/core/rawdb > old.txt
# change the code to reuse the hash pool
$ go test -benchmem --benchtime=1m -run=^$ -bench ^BenchmarkSafeDeleteRange github.com/ethereum/go-ethereum/core/rawdb > new.txt

The diff as below:

$ benchstat old.txt new.txt
goos: darwin
goarch: arm64
pkg: github.com/ethereum/go-ethereum/core/rawdb
cpu: Apple M4 Max
                   │   old.txt    │             new.txt             │
                   │    sec/op    │    sec/op     vs base           │
SafeDeleteRange-16   26.22m ± ∞ ¹   23.07m ± ∞ ¹  ~ (p=1.000 n=1) ²
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05

                   │    old.txt    │             new.txt              │
                   │     B/op      │     B/op       vs base           │
SafeDeleteRange-16   12.04Mi ± ∞ ¹   11.23Mi ± ∞ ¹  ~ (p=1.000 n=1) ²
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05

                   │   old.txt    │             new.txt             │
                   │  allocs/op   │  allocs/op    vs base           │
SafeDeleteRange-16   119.9k ± ∞ ¹   119.9k ± ∞ ¹  ~ (p=1.000 n=1) ²
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05
  1. The new approach is about 12% faster than the old one, and the memory usage is also reduced by about 6.7%.
  2. The allocs/op is not changed, because the SafeDeleteRange function is not changed, only the hashPool is reused in the SafeDeleteRange function.

So I think the pool reuse performance should be a litter better than the old one?
Please let me know if I've missed sth or anything the benchmark test is not correct.

@rjl493456442 rjl493456442 changed the title chore: reuse the global hash buffer all: reuse the global hash buffer May 26, 2025
@nthumann nthumann requested a review from rjl493456442 May 26, 2025 16:50
@nthumann nthumann requested a review from rjl493456442 May 27, 2025 16:22
@rjl493456442
Copy link
Member

rjl493456442 commented May 28, 2025

@MariusVanDerWijden looks like there is no big difference between two approaches.

// goos: darwin
// goarch: arm64
// pkg: github.com/ethereum/go-ethereum/crypto
// cpu: Apple M1 Pro
// BenchmarkKeccak256Hash
// BenchmarkKeccak256Hash-8   	  931095	      1270 ns/op	      32 B/op	       1 allocs/op
func BenchmarkKeccak256Hash(b *testing.B) {
	var input [512]byte
	rand.Read(input[:])

	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		Keccak256Hash(input[:])
	}
}

// goos: darwin
// goarch: arm64
// pkg: github.com/ethereum/go-ethereum/crypto
// cpu: Apple M1 Pro
// BenchmarkHashData
// BenchmarkHashData-8   	  793386	      1278 ns/op	      32 B/op	       1 allocs/op
func BenchmarkHashData(b *testing.B) {
	var (
		input  [512]byte
		buffer = NewKeccakState()
	)
	rand.Read(input[:])

	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		HashData(buffer, input[:])
	}
}

Copy link
Member

@MariusVanDerWijden MariusVanDerWijden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants