From 5636a9990bed537510e34bc3a796c46a7586a23c Mon Sep 17 00:00:00 2001 From: Ryan Gonzalez Date: Wed, 13 Sep 2023 10:41:00 -0500 Subject: [PATCH] Improve performance of simple reflist merges When merging reflists with ignoreConflicting set to true and overrideMatching set to false, the individual ref components are never examined, but the refs are still split anyway. Avoiding the split when we never use the components brings a massive speedup: on my system, the included benchmark goes from ~1500 us/it to ~180 us/it. Signed-off-by: Ryan Gonzalez --- deb/reflist.go | 53 +++++++++++++++++++++------------------ deb/reflist_bench_test.go | 30 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 deb/reflist_bench_test.go diff --git a/deb/reflist.go b/deb/reflist.go index 187475dd..8a795da5 100644 --- a/deb/reflist.go +++ b/deb/reflist.go @@ -310,38 +310,41 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching, ignoreConfli overridenName = nil overriddenArch = nil } else { - partsL := bytes.Split(rl, []byte(" ")) - archL, nameL, versionL := partsL[0][1:], partsL[1], partsL[2] + if !ignoreConflicting || overrideMatching { + partsL := bytes.Split(rl, []byte(" ")) + archL, nameL, versionL := partsL[0][1:], partsL[1], partsL[2] - partsR := bytes.Split(rr, []byte(" ")) - archR, nameR, versionR := partsR[0][1:], partsR[1], partsR[2] + partsR := bytes.Split(rr, []byte(" ")) + archR, nameR, versionR := partsR[0][1:], partsR[1], partsR[2] - if !ignoreConflicting && bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) && bytes.Equal(versionL, versionR) { - // conflicting duplicates with same arch, name, version, but different file hash - result.Refs = append(result.Refs, r.Refs[ir]) - il++ - ir++ - overridenName = nil - overriddenArch = nil - continue - } - - if overrideMatching { - if bytes.Equal(archL, overriddenArch) && bytes.Equal(nameL, overridenName) { - // this package has already been overridden on the right - il++ - continue - } - - if bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) { - // override with package from the right + if !ignoreConflicting && bytes.Equal(archL, archR) && + bytes.Equal(nameL, nameR) && bytes.Equal(versionL, versionR) { + // conflicting duplicates with same arch, name, version, but different file hash result.Refs = append(result.Refs, r.Refs[ir]) il++ ir++ - overriddenArch = archL - overridenName = nameL + overridenName = nil + overriddenArch = nil continue } + + if overrideMatching { + if bytes.Equal(archL, overriddenArch) && bytes.Equal(nameL, overridenName) { + // this package has already been overridden on the right + il++ + continue + } + + if bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) { + // override with package from the right + result.Refs = append(result.Refs, r.Refs[ir]) + il++ + ir++ + overriddenArch = archL + overridenName = nameL + continue + } + } } // otherwise append smallest of two diff --git a/deb/reflist_bench_test.go b/deb/reflist_bench_test.go new file mode 100644 index 00000000..367f3d09 --- /dev/null +++ b/deb/reflist_bench_test.go @@ -0,0 +1,30 @@ +package deb + +import ( + "fmt" + "sort" + "testing" +) + +func BenchmarkReflistSimpleMerge(b *testing.B) { + const count = 4096 + + l := NewPackageRefList() + r := NewPackageRefList() + + for i := 0; i < count; i++ { + if i%2 == 0 { + l.Refs = append(l.Refs, []byte(fmt.Sprintf("Pamd64 pkg%d %d", i, i))) + } else { + r.Refs = append(r.Refs, []byte(fmt.Sprintf("Pamd64 pkg%d %d", i, i))) + } + } + + sort.Sort(l) + sort.Sort(r) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + l.Merge(r, false, true) + } +}