Skip to content

Commit

Permalink
decompressor: add LZ4 decompressor module
Browse files Browse the repository at this point in the history
Add support for LZ4 decompression in the Linux Kernel. LZ4 Decompression
APIs for kernel are based on LZ4 implementation by Yann Collet.

Benchmark Results(PATCH v3)
Compiler: Linaro ARM gcc 4.6.2

1. ARMv7, 1.5GHz based board
   Kernel: linux 3.4
   Uncompressed Kernel Size: 14MB
        Compressed Size  Decompression Speed
   LZO  6.7MB            20.1MB/s, 25.2MB/s(UA)
   LZ4  7.3MB            29.1MB/s, 45.6MB/s(UA)

2. ARMv7, 1.7GHz based board
   Kernel: linux 3.7
   Uncompressed Kernel Size: 14MB
        Compressed Size  Decompression Speed
   LZO  6.0MB            34.1MB/s, 52.2MB/s(UA)
   LZ4  6.5MB            86.7MB/s
- UA: Unaligned memory Access support
- Latest patch set for LZO applied

This patch set is for adding support for LZ4-compressed Kernel.  LZ4 is a
very fast lossless compression algorithm and it also features an extremely
fast decoder [1].

But we have five of decompressors already and one question which does
arise, however, is that of where do we stop adding new ones?  This issue
had been discussed and came to the conclusion [2].

Russell King said that we should have:

 - one decompressor which is the fastest
 - one decompressor for the highest compression ratio
 - one popular decompressor (eg conventional gzip)

If we have a replacement one for one of these, then it should do exactly
that: replace it.

The benchmark shows that an 8% increase in image size vs a 66% increase
in decompression speed compared to LZO(which has been known as the
fastest decompressor in the Kernel).  Therefore the "fast but may not be
small" compression title has clearly been taken by LZ4 [3].

[1] http://code.google.com/p/lz4/
[2] http://thread.gmane.org/gmane.linux.kbuild.devel/9157
[3] http://thread.gmane.org/gmane.linux.kbuild.devel/9347

LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html
LZ4 source repository: http://code.google.com/p/lz4/

Change-Id: Ib7d1226ac0facea4c66f3ff50661242294ba6746
Signed-off-by: Kyungsik Lee <[email protected]>
Signed-off-by: Yann Collet <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Russell King <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Florian Fainelli <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Kyungsik Lee authored and kondors1995 committed Jul 18, 2016
1 parent 450b22e commit e51b25d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
16 changes: 16 additions & 0 deletions include/linux/lz4.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
<<<<<<< HEAD
#define LZ4_MEM_COMPRESS (4096 * sizeof(unsigned char *))
#define LZ4HC_MEM_COMPRESS (65538 * sizeof(unsigned char *))
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

/*
* lz4_compressbound()
Expand All @@ -23,6 +26,7 @@ static inline size_t lz4_compressbound(size_t isize)
}

/*
<<<<<<< HEAD
* lz4_compress()
* src : source address of the original data
* src_len : size of the original data
Expand All @@ -40,6 +44,8 @@ int lz4_compress(const unsigned char *src, size_t src_len,
unsigned char *dst, size_t *dst_len, void *wrkmem);

/*
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
* lz4_decompress()
* src : source address of the compressed data
* src_len : is the input size, whcih is returned after decompress done
Expand All @@ -50,8 +56,13 @@ int lz4_compress(const unsigned char *src, size_t src_len,
* note : Destination buffer must be already allocated.
* slightly faster than lz4_decompress_unknownoutputsize()
*/
<<<<<<< HEAD
int lz4_decompress(const unsigned char *src, size_t *src_len,
unsigned char *dest, size_t actual_dest_len);
=======
int lz4_decompress(const char *src, size_t *src_len, char *dest,
size_t actual_dest_len);
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

/*
* lz4_decompress_unknownoutputsize()
Expand All @@ -65,6 +76,11 @@ int lz4_decompress(const unsigned char *src, size_t *src_len,
* Error if return (< 0)
* note : Destination buffer must be already allocated.
*/
<<<<<<< HEAD
int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len,
unsigned char *dest, size_t *dest_len);
=======
int lz4_decompress_unknownoutputsize(const char *src, size_t src_len,
char *dest, size_t *dest_len);
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
#endif
42 changes: 42 additions & 0 deletions lib/lz4/lz4_decompress.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/*
* LZ4 Decompressor for Linux kernel
*
<<<<<<< HEAD
* Copyright (C) 2013, LG Electronics, Kyungsik Lee <[email protected]>
=======
* Copyright (C) 2013 LG Electronics Co., Ltd. (http://www.lge.com/)
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
*
* Based on LZ4 implementation by Yann Collet.
*
Expand Down Expand Up @@ -72,8 +76,11 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
len = *ip++;
for (; len == 255; length += 255)
len = *ip++;
<<<<<<< HEAD
if (unlikely(length > (size_t)(length + len)))
goto _output_error;
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
length += len;
}

Expand Down Expand Up @@ -108,8 +115,11 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
if (length == ML_MASK) {
for (; *ip == 255; length += 255)
ip++;
<<<<<<< HEAD
if (unlikely(length > (size_t)(length + *ip)))
goto _output_error;
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
length += *ip++;
}

Expand Down Expand Up @@ -159,7 +169,11 @@ static int lz4_uncompress(const char *source, char *dest, int osize)

/* write overflow error detected */
_output_error:
<<<<<<< HEAD
return -1;
=======
return (int) (-(((char *)ip) - source));
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
}

static int lz4_uncompress_unknownoutputsize(const char *source, char *dest,
Expand Down Expand Up @@ -192,8 +206,11 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest,
int s = 255;
while ((ip < iend) && (s == 255)) {
s = *ip++;
<<<<<<< HEAD
if (unlikely(length > (size_t)(length + s)))
goto _output_error;
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
length += s;
}
}
Expand Down Expand Up @@ -234,8 +251,11 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest,
if (length == ML_MASK) {
while (ip < iend) {
int s = *ip++;
<<<<<<< HEAD
if (unlikely(length > (size_t)(length + s)))
goto _output_error;
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
length += s;
if (s == 255)
continue;
Expand Down Expand Up @@ -288,11 +308,19 @@ static int lz4_uncompress_unknownoutputsize(const char *source, char *dest,

/* write overflow error detected */
_output_error:
<<<<<<< HEAD
return -1;
}

int lz4_decompress(const unsigned char *src, size_t *src_len,
unsigned char *dest, size_t actual_dest_len)
=======
return (int) (-(((char *) ip) - source));
}

int lz4_decompress(const char *src, size_t *src_len, char *dest,
size_t actual_dest_len)
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
{
int ret = -1;
int input_len = 0;
Expand All @@ -307,11 +335,19 @@ int lz4_decompress(const unsigned char *src, size_t *src_len,
return ret;
}
#ifndef STATIC
<<<<<<< HEAD
EXPORT_SYMBOL(lz4_decompress);
#endif

int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len,
unsigned char *dest, size_t *dest_len)
=======
EXPORT_SYMBOL_GPL(lz4_decompress);
#endif

int lz4_decompress_unknownoutputsize(const char *src, size_t src_len,
char *dest, size_t *dest_len)
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
{
int ret = -1;
int out_len = 0;
Expand All @@ -327,8 +363,14 @@ int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len,
return ret;
}
#ifndef STATIC
<<<<<<< HEAD
EXPORT_SYMBOL(lz4_decompress_unknownoutputsize);

MODULE_LICENSE("Dual BSD/GPL");
=======
EXPORT_SYMBOL_GPL(lz4_decompress_unknownoutputsize);

MODULE_LICENSE("GPL");
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
MODULE_DESCRIPTION("LZ4 Decompressor");
#endif
39 changes: 39 additions & 0 deletions lib/lz4/lz4defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
/*
* Detects 64 bits mode
*/
<<<<<<< HEAD
#if defined(CONFIG_64BIT)
=======
#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \
|| defined(__ppc64__) || defined(__LP64__))
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
#define LZ4_ARCH64 1
#else
#define LZ4_ARCH64 0
Expand All @@ -20,6 +25,7 @@
/*
* Architecture-specific macros
*/
<<<<<<< HEAD
#define ARM_EFFICIENT_UNALIGNED_ACCESS
#define BYTE u8
typedef struct _U16_S { u16 v; } U16_S;
Expand All @@ -28,11 +34,21 @@ typedef struct _U64_S { u64 v; } U64_S;
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)

#define A16(x) (((U16_S *)(x))->v)
=======
#define BYTE u8
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \
|| defined(CONFIG_ARM) && __LINUX_ARM_ARCH__ >= 6 \
&& defined(ARM_EFFICIENT_UNALIGNED_ACCESS)
typedef struct _U32_S { u32 v; } U32_S;
typedef struct _U64_S { u64 v; } U64_S;

>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
#define A32(x) (((U32_S *)(x))->v)
#define A64(x) (((U64_S *)(x))->v)

#define PUT4(s, d) (A32(d) = A32(s))
#define PUT8(s, d) (A64(d) = A64(s))
<<<<<<< HEAD

#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
(d = s - A16(p))
Expand All @@ -48,10 +64,15 @@ typedef struct _U64_S { u64 v; } U64_S;
#define A32(x) get_unaligned((u32 *)&(((U16_S *)(x))->v))
#define A16(x) get_unaligned((u16 *)&(((U16_S *)(x))->v))

=======
#else /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */

>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
#define PUT4(s, d) \
put_unaligned(get_unaligned((const u32 *) s), (u32 *) d)
#define PUT8(s, d) \
put_unaligned(get_unaligned((const u64 *) s), (u64 *) d)
<<<<<<< HEAD

#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
(d = s - get_unaligned_le16(p))
Expand All @@ -61,13 +82,16 @@ typedef struct _U64_S { u64 v; } U64_S;
put_unaligned_le16(v, (u16 *)(p)); \
p += 2; \
} while (0)
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module
#endif

#define COPYLENGTH 8
#define ML_BITS 4
#define ML_MASK ((1U << ML_BITS) - 1)
#define RUN_BITS (8 - ML_BITS)
#define RUN_MASK ((1U << RUN_BITS) - 1)
<<<<<<< HEAD
#define MEMORY_USAGE 14
#define MINMATCH 4
#define SKIPSTRENGTH 6
Expand All @@ -91,6 +115,8 @@ typedef struct _U64_S { u64 v; } U64_S;
((MINMATCH * 8) - HASHLOG64K))
#define HASH_VALUE(p) (((A32(p)) * 2654435761U) >> \
((MINMATCH * 8) - HASH_LOG))
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

#if LZ4_ARCH64/* 64-bit */
#define STEPSIZE 8
Expand All @@ -110,13 +136,16 @@ typedef struct _U64_S { u64 v; } U64_S;
LZ4_WILDCOPY(s, d, e); \
} \
} while (0)
<<<<<<< HEAD
#define HTYPE u32

#ifdef __BIG_ENDIAN
#define LZ4_NBCOMMONBYTES(val) (__builtin_clzll(val) >> 3)
#else
#define LZ4_NBCOMMONBYTES(val) (__builtin_ctzll(val) >> 3)
#endif
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

#else /* 32-bit */
#define STEPSIZE 4
Expand All @@ -135,6 +164,7 @@ typedef struct _U64_S { u64 v; } U64_S;
} while (0)

#define LZ4_SECURECOPY LZ4_WILDCOPY
<<<<<<< HEAD
#define HTYPE const u8*

#ifdef __BIG_ENDIAN
Expand All @@ -144,15 +174,24 @@ typedef struct _U64_S { u64 v; } U64_S;
#endif

#endif
=======
#endif

#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
(d = s - get_unaligned_le16(p))
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

#define LZ4_WILDCOPY(s, d, e) \
do { \
LZ4_COPYPACKET(s, d); \
} while (d < e)
<<<<<<< HEAD

#define LZ4_BLINDCOPY(s, d, l) \
do { \
u8 *e = (d) + l; \
LZ4_WILDCOPY(s, d, e); \
d = e; \
} while (0)
=======
>>>>>>> e34e7be... decompressor: add LZ4 decompressor module

0 comments on commit e51b25d

Please sign in to comment.