~eliasnaur/gio-patches

gio: io/router: improve areaOp methods performance v1 PROPOSED

~pierrec
~pierrec: 1
 io/router: improve areaOp methods performance

 2 files changed, 36 insertions(+), 19 deletions(-)
#437556 apple.yml success
#437557 freebsd.yml success
#437558 linux.yml failed
#437559 openbsd.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/20497/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH gio] io/router: improve areaOp methods performance Export this patch

~pierrec
From: pierre <pierre.curto@gmail.com>

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 <pierre.curto@gmail.com>
---
 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 ab9348b..ef56841 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 e457f8e..7f87606 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))
	}
}
-- 
2.30.1
> From: pierre <pierre.curto@gmail.com>
> 
> 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 <pierre.curto@gmail.com>
> ---
> 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 ab9348b..ef56841 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
you could probably squeeze a few performance bits off by replacing with:
rx := 0.5 * size.X
ry := 0.5 * size.Y

-s
builds.sr.ht
gio/patches: FAILED in 21m53s

[io/router: improve areaOp methods performance][0] from [~pierrec][1]

[0]: https://lists.sr.ht/~eliasnaur/gio-patches/patches/20497
[1]: mailto:pierre.curto@gmail.com

✗ #437558 FAILED  gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/437558
✓ #437556 SUCCESS gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/437556
✓ #437559 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/437559
✓ #437557 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/437557
Merged. Thanks for investigating!

Elias