From 807a6b10221ea0a01dfedab0ce26473f20266761 Mon Sep 17 00:00:00 2001 From: greatroar <61184462+greatroar@users.noreply.github.com> Date: Fri, 29 Oct 2021 20:20:46 +0200 Subject: [PATCH] lib/model: Optimize jobQueue performance and memory use (#8023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By truncating time.Time to an int64 nanosecond count, we lose the ability to precisely order timestamps before 1678 or after 2262, but we gain (linux/amd64, Go 1.17.1): name old time/op new time/op delta JobQueuePushPopDone10k-8 2.85ms ± 5% 2.29ms ± 2% -19.80% (p=0.000 n=20+18) JobQueueBump-8 34.0µs ± 1% 29.8µs ± 1% -12.35% (p=0.000 n=19+19) name old alloc/op new alloc/op delta JobQueuePushPopDone10k-8 2.56MB ± 0% 1.76MB ± 0% -31.31% (p=0.000 n=18+13) name old allocs/op new allocs/op delta JobQueuePushPopDone10k-8 23.0 ± 0% 23.0 ± 0% ~ (all equal) Results for BenchmarkJobQueueBump are with the fixed version, which no longer depends on b.N for the amount of work performed. rand.Rand.Intn is cheap at ~10ns per iteration. --- lib/model/queue.go | 7 ++++--- lib/model/queue_test.go | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/model/queue.go b/lib/model/queue.go index 28070a9a4..16ac83c94 100644 --- a/lib/model/queue.go +++ b/lib/model/queue.go @@ -23,7 +23,7 @@ type jobQueue struct { type jobQueueEntry struct { name string size int64 - modified time.Time + modified int64 } func newJobQueue() *jobQueue { @@ -34,7 +34,8 @@ func newJobQueue() *jobQueue { func (q *jobQueue) Push(file string, size int64, modified time.Time) { q.mut.Lock() - q.queued = append(q.queued, jobQueueEntry{file, size, modified}) + // The range of UnixNano covers a range of reasonable timestamps. + q.queued = append(q.queued, jobQueueEntry{file, size, modified.UnixNano()}) q.mut.Unlock() } @@ -191,5 +192,5 @@ func (q smallestFirst) Swap(a, b int) { q[a], q[b] = q[b], q[a] } type oldestFirst []jobQueueEntry func (q oldestFirst) Len() int { return len(q) } -func (q oldestFirst) Less(a, b int) bool { return q[a].modified.Before(q[b].modified) } +func (q oldestFirst) Less(a, b int) bool { return q[a].modified < q[b].modified } func (q oldestFirst) Swap(a, b int) { q[a], q[b] = q[b], q[a] } diff --git a/lib/model/queue_test.go b/lib/model/queue_test.go index 677c056dd..9f49a683b 100644 --- a/lib/model/queue_test.go +++ b/lib/model/queue_test.go @@ -8,6 +8,7 @@ package model import ( "fmt" + "math/rand" "testing" "time" @@ -251,16 +252,19 @@ func TestSortByAge(t *testing.T) { } func BenchmarkJobQueueBump(b *testing.B) { - files := genFiles(b.N) + files := genFiles(10000) q := newJobQueue() for _, f := range files { q.Push(f.Name, 0, time.Time{}) } + rng := rand.New(rand.NewSource(int64(b.N))) + b.ResetTimer() for i := 0; i < b.N; i++ { - q.BringToFront(files[i].Name) + r := rng.Intn(len(files)) + q.BringToFront(files[r].Name) } }