- commit
- 74a712598c4003cd48a56912340aa0cb8d293aa7
- parent
- fc0deece2ba5bd5511bd86e79c9072c0f8cf9943
- author
- Dami <dami.etoile@gmail.com>
| A | internal/ | 100 | ++++++++++++++++++++++++++++++ |
| M | internal/ | 8 | ++- |
@@ -0,0 +1,100 @@
1+//go:build stress2+3+package ui4+5+import (6+ "fmt"7+ "testing"8+9+ "github.com/FelineStateMachine/012/internal/macro"10+ "github.com/FelineStateMachine/012/internal/sheet"11+)12+13+// replayActions is a recording of n actions as a user makes them: entries14+// of numbers, text and formulas, moves between them, a selection and a15+// command now and then.16+func replayActions(n int, relative bool) []macro.Action {17+ out := make([]macro.Action, 0, n)18+ for i := 0; len(out) < n; i++ {19+ row := i/4 + 120+ switch i % 8 {21+ case 0:22+ out = append(out, macro.Call("enter", fmt.Sprint(i)))23+ case 1:24+ out = append(out, macro.Call("enter", "item "+fmt.Sprint(i)))25+ case 2:26+ a := macro.Call("enter", fmt.Sprintf("=A%d*2", row))27+ if relative {28+ a = a.With("origin", fmt.Sprintf("C%d", row))29+ }30+ out = append(out, a)31+ case 3:32+ out = append(out, macro.Call("extend", 2, 0))33+ case 4:34+ out = append(out, macro.Call("run", "format.bold"))35+ case 5, 6:36+ if relative {37+ out = append(out, macro.Call("move", 1, 0))38+ } else {39+ out = append(out, macro.Call("select", fmt.Sprintf("%s%d", sheet.ColName(i%8-4), row)))40+ }41+ case 7:42+ if relative {43+ out = append(out, macro.Call("move", -2, 1))44+ } else {45+ out = append(out, macro.Call("select", fmt.Sprintf("A%d", row+1)))46+ }47+ }48+ }49+ return out50+}51+52+// BenchmarkMacroReplay replays a 1000-action recorded macro through the53+// real path: the script on its own goroutine, each call served on the54+// model through Bubble Tea messages, all of it one undo step.55+func BenchmarkMacroReplay(b *testing.B) {56+ for _, relative := range []bool{false, true} {57+ name := "absolute"58+ if relative {59+ name = "relative"60+ }61+ src := macro.Source(recordingHeader(relative), replayActions(1000, relative))62+ b.Run(name+"/actions=1000", func(b *testing.B) {63+ b.ReportAllocs()64+ for b.Loop() {65+ b.StopTimer()66+ m := newModel()67+ m.book().SaveMacro("", sheet.Macro{Name: "Bench", Source: src}, "add")68+ m.trustHere()69+ mc, _ := m.book().Macro("Bench")70+ b.StartTimer()71+ run(m, m.runMacro(mc))72+ if m.warn != "" {73+ b.Fatal(m.warn)74+ }75+ }76+ b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(b.N)/1000, "ns/action")77+ })78+ }79+}80+81+// BenchmarkMacroScript is a script's own loop: 10,000 cells set and read82+// back, to show what a call to the spreadsheet costs next to Starlark83+// computing on its own.84+func BenchmarkMacroScript(b *testing.B) {85+ src := "for i in range(1, 5001):\n set(\"A\" + str(i), i)\n x = get(\"A\" + str(i))\n"86+ b.ReportAllocs()87+ for b.Loop() {88+ b.StopTimer()89+ m := newModel()90+ m.book().SaveMacro("", sheet.Macro{Name: "Loop", Source: src}, "add")91+ m.trustHere()92+ mc, _ := m.book().Macro("Loop")93+ b.StartTimer()94+ run(m, m.runMacro(mc))95+ if m.warn != "" {96+ b.Fatal(m.warn)97+ }98+ }99+ b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(b.N)/10000, "ns/call")100+}@@ -86,9 +86,13 @@ func wholeRef(r sheet.Rect) string {
8686 return r.String()8787 }8888 89-// readRange is r to read, trimmed to the used range when it's larger90-// than that.89+// readRange is r to read: a large range (whole columns, say) is trimmed90+// to the used range. Small ones aren't, as finding the used range takes91+// a pass over the sheet.9192 func readRange(s *sheet.Sheet, r sheet.Rect) (sheet.Rect, error) {93+ if (r.To.Col-r.From.Col+1)*(r.To.Row-r.From.Row+1) <= 1<<12 {94+ return r, nil95+ }9296 if used, ok := s.UsedRange(); ok && (r.To.Col > used.To.Col || r.To.Row > used.To.Row) {9397 r.To = sheet.Addr{Col: max(min(r.To.Col, used.To.Col), r.From.Col), Row: max(min(r.To.Row, used.To.Row), r.From.Row)}9498 }