2013. 3. 20. 14:31

압축 알고리즘 비교 (zlib / lz4 / snappy), snappy의 visual studio(vc++) 컴파일 하기

보통 압축 알고리즘으로 zlib를 쓰게 됩니다. 허나, 반복적이거나 큰 용량 혹은 네트웍크 등에서 빠른 응답이 필요한 경우, 때에 따라서는 "매우 빠른 속도"의 압축 알고리즘 선택에 대해 고민하게 됩니다. 그래서 최근 google의 snappy나 lz4와 같은 알고리즘이 많이 언급됩니다. 해당 알고리즘의 속도는 "매우 빠른" 것으로 보입니다. 실제로도 그러하구요.

본 블로그 포스트에서는 속도 보다는(왜냐하면 lz4나 snappy는 타 알고리즘에 비해 매우 빠른것으로 확인되었으므로), 압축률에 대해 비교해 보도록 하겠습니다. 여기에서 "압축률"은 원본 크기 대비 압축된 크기로, 100%는 copy를 의미하며 낮을 수록 "압축 효과가 좋다"라고 가정하겠습니다.

테스트 환경 : XP SP3 (VMWare)
테스트 데이터 : XP가 설치된 drive의 모든 사용된 sector data (4096 바이트 단위)
고리즘 종류 결과 크기 압축률 (순위)
zlib (compress level 9) 1,677,090,622 byte 48.59% (1)
zlib (compress level 1) 1,712,936,591 byte 49.63% (2)
snappy 1,983,481,882 byte 57.47% (4)
lz4 1,962,871,809 byte 56.87% (3)
copy 3,450,912,768 byte 100% (5)
(zlib : 1.2.7 사용, snappy : 1.1.0 사용, lz4 : r90 사용)

테스트는 XP가 설치된 disk의 사용된 sector를 기반으로 했는데, 이는 binary와 text, 그리고 비어있는 공간(0으로 채워진)등, 테스트하기에 매우 조화로운 상태(?)임을 가정했기 때문입니다.
압축률은 copy >>> snappy >= lz4 > zlib 1 >= zlib 9와 같다는 결과입니다. 예상한 대로 입니다.
물론, snappy와 lz4가 근사하게 나타나는데, 그 속도의 차이는 측정하지는 않았습니다. 속도도 두개 모두 비슷하리라 예상되며, snappy가 그래도 google에서 관리하다 보니, 향후에 좀더 발전하지 않을까 추측도 해봅니다.

여하튼, 중요한 결론중 하나로, zlib의 압축 효과와 snappy 혹은 lz4의 압축 효과와 "그렇게 큰 차이"는 나지 않는다는 점입니다. 3.4GB 데이터중 270MB 정도의 차이가 나니깐 말입니다. 비율로 따져보면, 대략 8% 정도의 차이입니다. 그런데 반해 그 속도의 차이는 "어마어마" 합니다. 속도의 차이는 직접 구굴링해 보시기 바랍니다.

이제, 압축률을 조금 양보할 수 있다면, snappy나 lz4와 같은 고속 알고리즘을 사용하는 것도 좋다는 결론을 조심스럽게 내려 봅니다.

참고) snappy 알고리즘 Visual Studio에서 컴파일 하기

snappy 알고리즘은 기본적으로 linux 기반으로 관리되다 보니, Visual Studio에서 빌드하는 방법이 생각보단 많이 알려져 있지 않아 공유합니다.

1) 다음의 snappy source를 Solution에 추가합니다.
- snappy.cc / snappy-c.cc / snappy-sinksource.cc / snappy-stubs-internal.cc

2) Additional Include Directories에 snappy 경로를 추가합니다.
- ./; ./snappy-1.1.0

3) 빌드 합니다. 그럼 다음과 같은 오류가 발생합니다.
- fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory

4) 오류 원인이 된 snappy-stubs-public.h로 이동합니다.

5) 아래와 같이 #include <stdint.h>를 주석처리합니다.
// #include <stdint.h>

6) 해당 파일의 #if 1을 #if 0으로 변경합니다.
#if 0
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#else
typedef signed char int8;
typedef unsigned char uint8;
...

7) 그러면 컴파일이 성공됩니다.

8) Preprocessor Definition에 __i386__을 추가하십시요. 혹은 source code내의 __i386__을 WIN32로 변경하십시요.

9) 만약, X64 빌드인 경우, Preprocessor Definitions에 __x86_64__를 추가하십시요. 혹은 source code내의 __x86_64__를 WIN64로 replace하시기 바랍니다.

다음과 같이 winmain 함수가 가능합니다.

#include "stdafx.h"
#include "snappy.h"

int _tmain(int argc, _TCHAR* argv[])
{
 char *src  = "hello, world!";
 char dest[32] = {0,};
 size_t length  = 32;

 snappy::RawCompress(src, strlen(src), dest, &length);
 printf("[hello, world!] was snappied as sizeof = %d\r\n", length);

 return 0;
}

그럼 다음과 같은 결과가 나옵니다.
[hello, world!] was snappied as sizeof = 15
계속하려면 아무 키나 누르십시오 . . .
특이한건, 원본보다 그 크기가 늘어나 버렸습니다! 몇몇 문장으로 테스트해 봤는데, ascii text에 대해서는 압축 효과가 크게 좋아 보이진 않았으나, abcdabcdabcd...와 같은 반복적인 text는 효과가 있었습니다.

위 project를 아래와 같이 공유합니다.