Description
What version of Go are you using (go version
)?
$ go version go version devel go1.17-e4615ad74d Wed May 26 13:25:43 2021 +0000 darwin/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="off" GOARCH="amd64" GOBIN="" GOCACHE="/Users/olivierwulveryck/Library/Caches/go-build" GOENV="/Users/olivierwulveryck/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/olivierwulveryck/GOPROJECTS/pkg/mod" GONOPROXY="github.com/dktunited" GONOSUMDB="github.com/dktunited" GOOS="darwin" GOPATH="/Users/olivierwulveryck/GOPROJECTS" GOPRIVATE="github.com/dktunited" GOPROXY="https://proxy.golang.org,direct" GOROOT="/Users/olivierwulveryck/dev/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/Users/olivierwulveryck/dev/go/pkg/tool/darwin_amd64" GOVCS="" GOVERSION="devel go1.17-e4615ad74d Wed May 26 13:25:43 2021 +0000" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/j3/t2_lsqzd5mgbv7tqvxg9ty5r0000gn/T/go-build4289980978=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
I am building a tool that is manipulating a lot of images. The process is a bit slow.
I made some performance analysis, and it appears that the drawRGBA
method is really time-consuming.
Specially the call to mask.At(mx,my).RGBA()
is causing performance penalty.
I think that most of the use cases of DrawMask
function are using an *image.Alpha
structure as a mask. Therefore doing a special treatment if the mask is *image.Alpha
could be valuable for most of the usage.
I made a simple test and bench for the drawRGBA
method (it should be done for other methods as well).
func Benchmark_drawRGBA(b *testing.B) {
r := image.Rect(0, 0, 500, 500)
dst := image.NewRGBA(r)
mask := image.NewAlpha(r)
src := image.NewRGBA(r)
for i := 0; i < b.N; i++ {
drawRGBA(dst, r, src, image.Point{}, mask, image.Point{}, Over)
}
}
Then I made a patch as an experiment:
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 8f96aa2d18..205e8cfb43 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -530,7 +530,13 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
ma := uint32(m)
if mask != nil {
- _, _, _, ma = mask.At(mx, my).RGBA()
+ if mask, ok := mask.(*image.Alpha); ok {
+ off := mask.PixOffset(mx, my)
+ ma = uint32(mask.Pix[off])
+ ma |= ma << 8
+ } else {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
}
sr, sg, sb, sa := src.At(sx, sy).RGBA()
d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
The performance enhancement is not negligible:
benchmark old ns/op new ns/op delta
Benchmark_drawRGBA-12 13178981 8599585 -34.75%
benchmark old allocs new allocs delta
Benchmark_drawRGBA-12 500000 250000 -50.00%
benchmark old bytes new bytes delta
Benchmark_drawRGBA-12 2025807 1016234 -49.84%
This is a test for opening the discussion, and I guess that other controls should be added as it makes some tests of the draw package fail. Specifically, the test.mask
causes panic, and I cannot figure out what test.mask
is nor where it is defined.
What did you expect to see?
N/A
What did you see instead?
N/A