-
Notifications
You must be signed in to change notification settings - Fork 181
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
perf: optimize MemoryStorage.Compact method by improving memory allocation #267
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 1911860538 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Hi @1911860538. Thanks for your PR. I'm waiting for a etcd-io member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
…ation Signed-off-by: huangzw <[email protected]>
… Compact method Signed-off-by: huangzw <[email protected]>
685b9b3
to
04f8874
Compare
/ok-to-test |
My code update appears to be leading to unexpected issues because the original logic only copied the Term and Index of the i-th element, whereas after my modification, it now copies all fields of the i-th element. ents := make([]pb.Entry, uint64(len(ms.ents)) - i)
// Only copy Index and Term of the compact index entry (first entry).
// These fields are sufficient for log matching in the Raft algorithm,
// while Type and Data are not needed since the entry's command has
// already been applied to the state machine.
ents[0].Index = ms.ents[i].Index
ents[0].Term = ms.ents[i].Term
copy(ents[1:], ms.ents[i+1:]) |
The Benchmark results of my local code indicate that this code modification results in a slight performance boost, whereas the previous code changes showed no performance improvement. package entry_compact
import (
"bytes"
"testing"
)
type Entry struct {
Term uint64
Index uint64
Type int32
Data []byte
}
const (
compactIndex = 100
entriesLen = 1000
)
func getEntries(length int) []Entry {
src := make([]Entry, length)
for i := range length {
src[i] = Entry{
Term: uint64(i),
Index: uint64(i),
Type: int32(i),
Data: []byte{'0'},
}
}
return src
}
func copy1(src []Entry, index int) []Entry {
dst := make([]Entry, 1, len(src)-index)
dst[0].Term = src[0].Term
dst[0].Index = src[0].Index
dst = append(dst, src[index+1:]...)
return dst
}
func copy2(src []Entry, index int) []Entry {
dst := make([]Entry, len(src)-index)
dst[0].Term = src[0].Term
dst[0].Index = src[0].Index
copy(dst[1:], src[index+1:])
return dst
}
func copy3(src []Entry, index int) []Entry {
dst := make([]Entry, len(src)-index)
copy(dst, src[index:])
return dst
}
func BenchmarkCopy1(b *testing.B) {
src := getEntries(entriesLen)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy1(src, compactIndex)
}
}
func BenchmarkCopy2(b *testing.B) {
src := getEntries(entriesLen)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy2(src, compactIndex)
}
}
func BenchmarkCopy3(b *testing.B) {
src := getEntries(entriesLen)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy3(src, compactIndex)
}
}
func TestSame(t *testing.T) {
src := getEntries(entriesLen)
c1 := copy1(src, compactIndex)
c2 := copy2(src, compactIndex)
if len(c1) != len(c2) {
t.Fatal("copied slices are not the same length")
}
for i := range c1 {
c1i := c1[i]
c2i := c2[i]
if c1i.Term != c2i.Term || c1i.Index != c2i.Index || c1i.Type != c2i.Type || bytes.Compare(c1i.Data, c2i.Data) != 0 {
t.Fatal("copied items are not same")
}
}
} Test output
Benchmark output
|
Avoiding the use of
append
, and directly copying remaining entries to a new slice for better performance.