OLD | NEW |
(Empty) | |
| 1 From d62eac3b93d61dc07c7b4c0d1738db14415b6309 Mon Sep 17 00:00:00 2001 |
| 2 From: Adenilson Cavalcanti <adenilson.cavalcanti@arm.com> |
| 3 Date: Mon, 30 Jan 2017 15:30:38 -0800 |
| 4 Subject: [PATCH] NEON implementation for Adler32 |
| 5 |
| 6 The checksum is calculated in the uncompressed PNG data |
| 7 and can be made much faster by using SIMD. |
| 8 |
| 9 Tests in ARMv8 yielded an improvement of about 3x |
| 10 (e.g. walltime was 350ms x 125ms for a 4096x4096 bytes |
| 11 executed 30 times). |
| 12 --- |
| 13 third_party/zlib/BUILD.gn | 5 ++ |
| 14 third_party/zlib/README.chromium | 4 +- |
| 15 third_party/zlib/adler32.c | 8 +++ |
| 16 third_party/zlib/neon_adler32.c | 120 +++++++++++++++++++++++++++++++++++++++ |
| 17 third_party/zlib/neon_adler32.h | 13 +++++ |
| 18 5 files changed, 149 insertions(+), 1 deletion(-) |
| 19 create mode 100644 third_party/zlib/neon_adler32.c |
| 20 create mode 100644 third_party/zlib/neon_adler32.h |
| 21 |
| 22 diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn |
| 23 index 5086563..09dfa5f 100644 |
| 24 --- a/third_party/zlib/BUILD.gn |
| 25 +++ b/third_party/zlib/BUILD.gn |
| 26 @@ -73,6 +73,11 @@ static_library("zlib") { |
| 27 |
| 28 if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) { |
| 29 sources += [ "x86.c" ] |
| 30 + } else if (current_cpu == "arm" || current_cpu == "arm64") { |
| 31 + sources += [ |
| 32 + "neon_adler32.c", |
| 33 + "neon_adler32.h", |
| 34 + ] |
| 35 } |
| 36 |
| 37 configs -= [ "//build/config/compiler:chromium_code" ] |
| 38 diff --git a/third_party/zlib/README.chromium b/third_party/zlib/README.chromium |
| 39 index fe6bc10..166eb33 100644 |
| 40 --- a/third_party/zlib/README.chromium |
| 41 +++ b/third_party/zlib/README.chromium |
| 42 @@ -24,5 +24,7 @@ Local Modifications: |
| 43 additions. |
| 44 - google.patch contains changes from the upstream version, mostly related to |
| 45 the build. |
| 46 - - Intel SIMD optimisations from https://github.com/jtkukunas/zlib/ have been |
| 47 + - Intel SIMD optimizations from https://github.com/jtkukunas/zlib/ have been |
| 48 integrated. These changes are reflected in simd.patch. |
| 49 + - NEON SIMD optimizations for Adler32 checksum were integrated. Changes |
| 50 + are reflected in neon_adler32.patch. |
| 51 \ No newline at end of file |
| 52 diff --git a/third_party/zlib/adler32.c b/third_party/zlib/adler32.c |
| 53 index d0be438..0b74c72 100644 |
| 54 --- a/third_party/zlib/adler32.c |
| 55 +++ b/third_party/zlib/adler32.c |
| 56 @@ -6,6 +6,9 @@ |
| 57 /* @(#) $Id$ */ |
| 58 |
| 59 #include "zutil.h" |
| 60 +#ifdef __ARM_NEON__ |
| 61 +#include "neon_adler32.h" |
| 62 +#endif |
| 63 |
| 64 local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); |
| 65 |
| 66 @@ -65,6 +68,11 @@ uLong ZEXPORT adler32_z(adler, buf, len) |
| 67 const Bytef *buf; |
| 68 z_size_t len; |
| 69 { |
| 70 +#ifdef __ARM_NEON__ |
| 71 + if (len > 31) |
| 72 + return NEON_adler32(adler, buf, len); |
| 73 +#endif |
| 74 + |
| 75 unsigned long sum2; |
| 76 unsigned n; |
| 77 |
| 78 diff --git a/third_party/zlib/neon_adler32.c b/third_party/zlib/neon_adler32.c |
| 79 new file mode 100644 |
| 80 index 0000000..a0f95fb |
| 81 --- /dev/null |
| 82 +++ b/third_party/zlib/neon_adler32.c |
| 83 @@ -0,0 +1,120 @@ |
| 84 +/* Copyright 2017 The Chromium Authors. All rights reserved. |
| 85 + * Use of this source code is governed by a BSD-style license that can be |
| 86 + * found in the LICENSE file. |
| 87 +*/ |
| 88 + |
| 89 +#include "neon_adler32.h" |
| 90 +#ifdef __ARM_NEON__ |
| 91 +#include <arm_neon.h> |
| 92 + |
| 93 +static void NEON_accum32(uint32_t *s, const unsigned char *buf, |
| 94 + unsigned int len) |
| 95 +{ |
| 96 + static const uint8_t taps[32] = { |
| 97 + 32, 31, 30, 29, 28, 27, 26, 25, |
| 98 + 24, 23, 22, 21, 20, 19, 18, 17, |
| 99 + 16, 15, 14, 13, 12, 11, 10, 9, |
| 100 + 8, 7, 6, 5, 4, 3, 2, 1 }; |
| 101 + |
| 102 + uint32x2_t adacc2, s2acc2, as; |
| 103 + uint8x16_t t0 = vld1q_u8(taps), t1 = vld1q_u8(taps + 16); |
| 104 + |
| 105 + uint32x4_t adacc = vdupq_n_u32(0), s2acc = vdupq_n_u32(0); |
| 106 + adacc = vsetq_lane_u32(s[0], adacc, 0); |
| 107 + s2acc = vsetq_lane_u32(s[1], s2acc, 0); |
| 108 + |
| 109 + while (len >= 2) { |
| 110 + uint8x16_t d0 = vld1q_u8(buf), d1 = vld1q_u8(buf + 16); |
| 111 + uint16x8_t adler, sum2; |
| 112 + s2acc = vaddq_u32(s2acc, vshlq_n_u32(adacc, 5)); |
| 113 + adler = vpaddlq_u8( d0); |
| 114 + adler = vpadalq_u8(adler, d1); |
| 115 + sum2 = vmull_u8( vget_low_u8(t0), vget_low_u8(d0)); |
| 116 + sum2 = vmlal_u8(sum2, vget_high_u8(t0), vget_high_u8(d0)); |
| 117 + sum2 = vmlal_u8(sum2, vget_low_u8(t1), vget_low_u8(d1)); |
| 118 + sum2 = vmlal_u8(sum2, vget_high_u8(t1), vget_high_u8(d1)); |
| 119 + adacc = vpadalq_u16(adacc, adler); |
| 120 + s2acc = vpadalq_u16(s2acc, sum2); |
| 121 + len -= 2; |
| 122 + buf += 32; |
| 123 + } |
| 124 + |
| 125 + while (len > 0) { |
| 126 + uint8x16_t d0 = vld1q_u8(buf); |
| 127 + uint16x8_t adler, sum2; |
| 128 + s2acc = vaddq_u32(s2acc, vshlq_n_u32(adacc, 4)); |
| 129 + adler = vpaddlq_u8(d0); |
| 130 + sum2 = vmull_u8( vget_low_u8(t1), vget_low_u8(d0)); |
| 131 + sum2 = vmlal_u8(sum2, vget_high_u8(t1), vget_high_u8(d0)); |
| 132 + adacc = vpadalq_u16(adacc, adler); |
| 133 + s2acc = vpadalq_u16(s2acc, sum2); |
| 134 + buf += 16; |
| 135 + len--; |
| 136 + } |
| 137 + |
| 138 + adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc)); |
| 139 + s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc)); |
| 140 + as = vpadd_u32(adacc2, s2acc2); |
| 141 + s[0] = vget_lane_u32(as, 0); |
| 142 + s[1] = vget_lane_u32(as, 1); |
| 143 +} |
| 144 + |
| 145 +static void NEON_handle_tail(uint32_t *pair, const unsigned char *buf, |
| 146 + unsigned int len) |
| 147 +{ |
| 148 + /* Oldie K&R code integration. */ |
| 149 + unsigned int i; |
| 150 + for (i = 0; i < len; ++i) { |
| 151 + pair[0] += buf[i]; |
| 152 + pair[1] += pair[0]; |
| 153 + } |
| 154 +} |
| 155 + |
| 156 +unsigned long NEON_adler32(unsigned long adler, const unsigned char *buf, |
| 157 + const unsigned int len) |
| 158 +{ |
| 159 + /* The largest prime smaller than 65536. */ |
| 160 + const uint32_t M_BASE = 65521; |
| 161 + /* This is the threshold where doing accumulation may overflow. */ |
| 162 + const int M_NMAX = 5552; |
| 163 + |
| 164 + unsigned long sum2; |
| 165 + uint32_t pair[2]; |
| 166 + int n = M_NMAX; |
| 167 + unsigned int done = 0; |
| 168 + /* Oldie K&R code integration. */ |
| 169 + unsigned int i; |
| 170 + |
| 171 + /* Split Adler-32 into component sums, it can be supplied by |
| 172 + * the caller sites (e.g. in a PNG file). |
| 173 + */ |
| 174 + sum2 = (adler >> 16) & 0xffff; |
| 175 + adler &= 0xffff; |
| 176 + pair[0] = adler; |
| 177 + pair[1] = sum2; |
| 178 + |
| 179 + for (i = 0; i < len; i += n) { |
| 180 + if ((i + n) > len) |
| 181 + n = len - i; |
| 182 + |
| 183 + if (n < 16) |
| 184 + break; |
| 185 + |
| 186 + NEON_accum32(pair, buf + i, n / 16); |
| 187 + pair[0] %= M_BASE; |
| 188 + pair[1] %= M_BASE; |
| 189 + |
| 190 + done += (n / 16) * 16; |
| 191 + } |
| 192 + |
| 193 + /* Handle the tail elements. */ |
| 194 + if (done < len) { |
| 195 + NEON_handle_tail(pair, (buf + done), len - done); |
| 196 + pair[0] %= M_BASE; |
| 197 + pair[1] %= M_BASE; |
| 198 + } |
| 199 + |
| 200 + /* D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. */ |
| 201 + return (pair[1] << 16) | pair[0]; |
| 202 +} |
| 203 +#endif |
| 204 diff --git a/third_party/zlib/neon_adler32.h b/third_party/zlib/neon_adler32.h |
| 205 new file mode 100644 |
| 206 index 0000000..febe9a1 |
| 207 --- /dev/null |
| 208 +++ b/third_party/zlib/neon_adler32.h |
| 209 @@ -0,0 +1,13 @@ |
| 210 +/* Copyright 2017 The Chromium Authors. All rights reserved. |
| 211 + * Use of this source code is governed by a BSD-style license that can be |
| 212 + * found in the LICENSE file. |
| 213 +*/ |
| 214 +#ifndef __NEON_ADLER32__ |
| 215 +#define __NEON_ADLER32__ |
| 216 + |
| 217 +#ifdef __ARM_NEON__ |
| 218 +unsigned long NEON_adler32(unsigned long adler, |
| 219 + const unsigned char* buf, |
| 220 + const unsigned int len); |
| 221 +#endif |
| 222 +#endif |
| 223 -- |
| 224 2.7.4 |
| 225 |
OLD | NEW |