diff options
| author | Rui Ueyama <ruiu@google.com> | 2014-07-29 14:29:14 +1000 |
|---|---|---|
| committer | Nigel Tao <nigeltao@golang.org> | 2014-07-29 14:29:14 +1000 |
| commit | 0100afbdcc065ec20631d60cf7621d642f44b9d5 (patch) | |
| tree | dc3e55d2bab0f11506ded9ab4d86558b6e099ca8 /src/pkg | |
| parent | d3fb02b5c5850f53721d923be6770246aca7f69e (diff) | |
| download | go-0100afbdcc065ec20631d60cf7621d642f44b9d5.tar.xz | |
image/png: use branch-free abs function
benchmark old ns/op new ns/op delta
BenchmarkPaeth 5.06 6.02 +18.97%
BenchmarkDecodeGray 1010551 956911 -5.31%
BenchmarkDecodeNRGBAGradient 3877813 3754160 -3.19%
BenchmarkDecodeNRGBAOpaque 3194058 3079094 -3.60%
BenchmarkDecodePaletted 699243 700211 +0.14%
BenchmarkDecodeRGB 2835733 2692120 -5.06%
BenchmarkDecodeInterlacing 3651805 3563124 -2.43%
BenchmarkEncodeGray 4399183 4404113 +0.11%
BenchmarkEncodeNRGBOpaque 13323627 13306485 -0.13%
BenchmarkEncodeNRGBA 15840092 15751188 -0.56%
BenchmarkEncodePaletted 4396622 4404373 +0.18%
BenchmarkEncodeRGBOpaque 13320475 13279189 -0.31%
BenchmarkEncodeRGBA 36898392 36781002 -0.32%
LGTM=nigeltao
R=nigeltao
CC=golang-codereviews
https://golang.org/cl/117290043
Diffstat (limited to 'src/pkg')
| -rw-r--r-- | src/pkg/image/png/paeth.go | 41 | ||||
| -rw-r--r-- | src/pkg/image/png/paeth_test.go | 8 |
2 files changed, 25 insertions, 24 deletions
diff --git a/src/pkg/image/png/paeth.go b/src/pkg/image/png/paeth.go index 37978aa662..9ed6300c86 100644 --- a/src/pkg/image/png/paeth.go +++ b/src/pkg/image/png/paeth.go @@ -4,6 +4,21 @@ package png +// intSize is either 32 or 64. +const intSize = 32 << (^uint(0) >> 63) + +func abs(x int) int { + // m := -1 if x < 0. m := 0 otherwise. + m := x >> (intSize - 1) + + // In two's complement representation, the negative number + // of any number (except the smallest one) can be computed + // by flipping all the bits and add 1. This is faster than + // code with a branch. + // See Hacker's Delight, section 2-4. + return (x ^ m) - m +} + // paeth implements the Paeth filter function, as per the PNG specification. func paeth(a, b, c uint8) uint8 { // This is an optimized version of the sample code in the PNG spec. @@ -16,16 +31,9 @@ func paeth(a, b, c uint8) uint8 { pc := int(c) pa := int(b) - pc pb := int(a) - pc - pc = pa + pb - if pa < 0 { - pa = -pa - } - if pb < 0 { - pb = -pb - } - if pc < 0 { - pc = -pc - } + pc = abs(pa + pb) + pa = abs(pa) + pb = abs(pb) if pa <= pb && pa <= pc { return a } else if pb <= pc { @@ -44,16 +52,9 @@ func filterPaeth(cdat, pdat []byte, bytesPerPixel int) { b = int(pdat[j]) pa = b - c pb = a - c - pc = pa + pb - if pa < 0 { - pa = -pa - } - if pb < 0 { - pb = -pb - } - if pc < 0 { - pc = -pc - } + pc = abs(pa + pb) + pa = abs(pa) + pb = abs(pb) if pa <= pb && pa <= pc { // No-op. } else if pb <= pc { diff --git a/src/pkg/image/png/paeth_test.go b/src/pkg/image/png/paeth_test.go index bb084861ae..cfc1896cd7 100644 --- a/src/pkg/image/png/paeth_test.go +++ b/src/pkg/image/png/paeth_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -func abs(x int) int { +func slowAbs(x int) int { if x < 0 { return -x } @@ -21,9 +21,9 @@ func abs(x int) int { // It is a straight port of the sample code in the PNG spec, section 9.4. func slowPaeth(a, b, c uint8) uint8 { p := int(a) + int(b) - int(c) - pa := abs(p - int(a)) - pb := abs(p - int(b)) - pc := abs(p - int(c)) + pa := slowAbs(p - int(a)) + pb := slowAbs(p - int(b)) + pc := slowAbs(p - int(c)) if pa <= pb && pa <= pc { return a } else if pb <= pc { |
