diff options
| author | Joakim Tjernlund <Joakim.Tjernlund@transmode.se> | 2009-11-19 13:22:44 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2009-12-05 01:32:32 +0100 | 
| commit | cd514aeb996e2f7aefbe1f78481965d9d074aed4 (patch) | |
| tree | 7d137cf995168e0722913d670a696f81344f69ec | |
| parent | 20dde48bcadd856c86a91d5463831a10be46db83 (diff) | |
| download | olio-uboot-2014.01-cd514aeb996e2f7aefbe1f78481965d9d074aed4.tar.xz olio-uboot-2014.01-cd514aeb996e2f7aefbe1f78481965d9d074aed4.zip | |
zlib: Optimize decompression
This patch optimizes the direct copy procedure.
Uses get_unaligned() but only in one place.
The copy loop just above this one can also use this
optimization, but I havn't done so as I have not tested if it
is a win there too.
On my MPC8321 this is about 17% faster on my JFFS2 root FS
than the original. No speed test has been performed in u-boot.
Size increase on ppc: 484 bytes
Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
| -rw-r--r-- | lib_generic/zlib.c | 56 | 
1 files changed, 44 insertions, 12 deletions
| diff --git a/lib_generic/zlib.c b/lib_generic/zlib.c index 8fe3bd0dd..572196865 100644 --- a/lib_generic/zlib.c +++ b/lib_generic/zlib.c @@ -26,8 +26,10 @@  #define ZUTIL_H  #define ZLIB_INTERNAL -#include "u-boot/zlib.h"  #include <common.h> +#include <compiler.h> +#include <asm/unaligned.h> +#include "u-boot/zlib.h"  /* To avoid a build time warning */  #ifdef STDC  #include <malloc.h> @@ -400,6 +402,7 @@ void inflate_fast OF((z_streamp strm, unsigned start));   */  #define OFF 1  #define PUP(a) *++(a) +#define UP_UNALIGNED(a) get_unaligned(++(a))  /*     Decode literal, length, and distance codes and write out the resulting @@ -616,18 +619,47 @@ unsigned start;         /* inflate()'s starting value for strm->avail_out */                      }                  }                  else { +		    unsigned short *sout; +		    unsigned long loops; +                      from = out - dist;          /* copy direct from output */ -                    do {                        /* minimum length is three */ -                        PUP(out) = PUP(from); -                        PUP(out) = PUP(from); -                        PUP(out) = PUP(from); -                        len -= 3; -                    } while (len > 2); -                    if (len) { -                        PUP(out) = PUP(from); -                        if (len > 1) -                            PUP(out) = PUP(from); -                    } +                    /* minimum length is three */ +		    /* Align out addr */ +		    if (!((long)(out - 1 + OFF) & 1)) { +			PUP(out) = PUP(from); +			len--; +		    } +		    sout = (unsigned short *)(out - OFF); +		    if (dist > 2 ) { +			unsigned short *sfrom; + +			sfrom = (unsigned short *)(from - OFF); +			loops = len >> 1; +			do +			    PUP(sout) = UP_UNALIGNED(sfrom); +			while (--loops); +			out = (unsigned char *)sout + OFF; +			from = (unsigned char *)sfrom + OFF; +		    } else { /* dist == 1 or dist == 2 */ +			unsigned short pat16; + +			pat16 = *(sout-2+2*OFF); +			if (dist == 1) +#if defined(__BIG_ENDIAN) +			    pat16 = (pat16 & 0xff) | ((pat16 & 0xff ) << 8); +#elif defined(__LITTLE_ENDIAN) +			    pat16 = (pat16 & 0xff00) | ((pat16 & 0xff00 ) >> 8); +#else +#error __BIG_ENDIAN nor __LITTLE_ENDIAN is defined +#endif +			loops = len >> 1; +			do +			    PUP(sout) = pat16; +			while (--loops); +			out = (unsigned char *)sout + OFF; +		    } +		    if (len & 1) +			PUP(out) = PUP(from);                  }              }              else if ((op & 64) == 0) {          /* 2nd level distance code */ |