From cfb16083a25af18998b41ae94139139e7029411c Mon Sep 17 00:00:00 2001 From: pierre Date: Wed, 24 Feb 2021 12:29:22 +0100 Subject: [PATCH] io/router: improve areaOp methods performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta AreaOp_Decode-8 10.5ns ± 2% 6.2ns ± 3% -41.50% (p=0.000 n=10+10) AreaOp_Hit-8 4.44ns ± 4% 3.57ns ± 2% -19.59% (p=0.000 n=10+10) Signed-off-by: pierre --- io/router/pointer.go | 36 +++++++++++++++++------------------- io/router/pointer_test.go | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/io/router/pointer.go b/io/router/pointer.go index dd66037c..8680ebde 100644 --- a/io/router/pointer.go +++ b/io/router/pointer.go @@ -4,7 +4,6 @@ package router import ( "encoding/binary" - "image" "gioui.org/f32" "gioui.org/internal/opconst" @@ -64,7 +63,7 @@ type pointerHandler struct { type areaOp struct { kind areaKind - rect image.Rectangle + rect f32.Rectangle } type areaNode struct { @@ -409,19 +408,22 @@ func searchTag(tags []event.Tag, tag event.Tag) (int, bool) { return 0, false } +func opDecodeFloat32(d []byte) float32 { + return float32(binary.LittleEndian.Uint32(d)) +} + func (op *areaOp) Decode(d []byte) { if opconst.OpType(d[0]) != opconst.TypeArea { panic("invalid op") } - bo := binary.LittleEndian - rect := image.Rectangle{ - Min: image.Point{ - X: int(int32(bo.Uint32(d[2:]))), - Y: int(int32(bo.Uint32(d[6:]))), + rect := f32.Rectangle{ + Min: f32.Point{ + X: opDecodeFloat32(d[2:]), + Y: opDecodeFloat32(d[6:]), }, - Max: image.Point{ - X: int(int32(bo.Uint32(d[10:]))), - Y: int(int32(bo.Uint32(d[14:]))), + Max: f32.Point{ + X: opDecodeFloat32(d[10:]), + Y: opDecodeFloat32(d[14:]), }, } *op = areaOp{ @@ -431,19 +433,15 @@ func (op *areaOp) Decode(d []byte) { } func (op *areaOp) Hit(pos f32.Point) bool { - min := f32.Point{ - X: float32(op.rect.Min.X), - Y: float32(op.rect.Min.Y), - } - pos = pos.Sub(min) + pos = pos.Sub(op.rect.Min) size := op.rect.Size() switch op.kind { case areaRect: - return 0 <= pos.X && pos.X < float32(size.X) && - 0 <= pos.Y && pos.Y < float32(size.Y) + return 0 <= pos.X && pos.X < size.X && + 0 <= pos.Y && pos.Y < size.Y case areaEllipse: - rx := float32(size.X) / 2 - ry := float32(size.Y) / 2 + rx := size.X / 2 + ry := size.Y / 2 xh := pos.X - rx yk := pos.Y - ry // The ellipse function works in all cases because diff --git a/io/router/pointer_test.go b/io/router/pointer_test.go index e457f8e7..7f876068 100644 --- a/io/router/pointer_test.go +++ b/io/router/pointer_test.go @@ -651,3 +651,22 @@ func BenchmarkRouterAdd(b *testing.B) { }) } } + +var benchAreaOp areaOp + +func BenchmarkAreaOp_Decode(b *testing.B) { + ops := new(op.Ops) + pointer.Rect(image.Rectangle{Max: image.Pt(100, 100)}).Add(ops) + for i := 0; i < b.N; i++ { + benchAreaOp.Decode(ops.Data()) + } +} + +func BenchmarkAreaOp_Hit(b *testing.B) { + ops := new(op.Ops) + pointer.Rect(image.Rectangle{Max: image.Pt(100, 100)}).Add(ops) + benchAreaOp.Decode(ops.Data()) + for i := 0; i < b.N; i++ { + benchAreaOp.Hit(f32.Pt(50, 50)) + } +}