62 lines
2.7 KiB
Go
62 lines
2.7 KiB
Go
package pgstore
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// perf_test.go: the measurements a projection change has to be judged by.
|
|
//
|
|
// Benchmarks rather than tests: `go test` does not run them, so the battery stays fast, and the
|
|
// numbers are reproducible on demand — `go test ./internal/pgstore/ -bench LibraryPage -run xxx`.
|
|
// The note counter was added to the library row from reasoning alone and cost 96% of the page's
|
|
// time on a COLD corpus-sized account; this is what says so before and after. The condition is part
|
|
// of the number — on a vacuumed corpus the same change reads as about 80%, and see below for both.
|
|
//
|
|
// ⚠ THE SAME CHANGE HAS TWO HONEST NUMBERS, and the difference is the state of the corpus — which is
|
|
// why every figure about it has to carry its conditions or it reads as a contradiction:
|
|
//
|
|
// - COLD corpus, never vacuumed (act 4's own measurement): 636 ms a page against 24 ms. That is
|
|
// the number above, and nothing here reproduces it.
|
|
// - VACUUMED corpus, 40 books x 500 chapters, 1000 notes each: 16.8 ms against 3.4 ms, the join
|
|
// alone 9 ms — about 80%. Those are the NORMATIVE figures and their carrier is migration
|
|
// 00022_chapter_note_count.sql, which states them with its conditions. It is also the world THIS
|
|
// benchmark measures: `corpus` ends with `vacuum analyze`.
|
|
//
|
|
// Both are true, they measure different worlds, and the reason to keep both is that a deployment is
|
|
// not vacuumed on the day a user's library grows.
|
|
|
|
// corpus seeds one account with a library the size of a real one: books whose chapters carry
|
|
// resolutions, a fifth of them flagged.
|
|
func corpus(t testing.TB, s *Store, books, chapters, units int) string {
|
|
t.Helper()
|
|
ctx := t.Context()
|
|
now := fundedAccount(t, s, t.Context(), "u1", "1000")
|
|
for b := range books {
|
|
id := fmt.Sprintf("bk%03d", b)
|
|
seedBook(t, s, ctx, id, "u1", chapters)
|
|
exec(t, s, ctx, `
|
|
insert into chapters (id, book_id, number, units_total, units_edit_done)
|
|
select $1 || '_' || n, $1, n, $2, $2 from generate_series(1, $3) as n`, id, units, chapters)
|
|
exec(t, s, ctx, `
|
|
insert into unit_resolutions (book_id, chapter, unit, wave, shipped, flagged, at, revision)
|
|
select $1, n, u, 'edit', true, (u % 5 = 0), $2, 1
|
|
from generate_series(1, $3) as n, generate_series(0, $4) as u`,
|
|
id, now, chapters, units-1)
|
|
}
|
|
exec(t, s, ctx, `vacuum analyze`)
|
|
return "u1"
|
|
}
|
|
|
|
func BenchmarkLibraryPage(b *testing.B) {
|
|
s, ctx := testDB(b)
|
|
user := corpus(b, s, 40, 500, 10)
|
|
start := time.Now()
|
|
for b.Loop() {
|
|
if _, err := s.ListBooks(ctx, user, 100, ""); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
b.ReportMetric(float64(time.Since(start).Milliseconds())/float64(b.N), "ms/page")
|
|
}
|