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를 아래와 같이 공유합니다.

Trackback 0 Comment 6
  1. 수원온달 2013.04.16 00:36 address edit & del reply

    Snappy 의 존재에 대하여 알려 주셔서 대단히 감사합니다.
    속도도 어마어마 하고
    성능이 안좋은 테블릿 pc에서 엔코딩 했어야 해서 걱정 했는데
    엄청 좋네요. 이거 보고 침대에서 벌떡 일어나 코딩 하고 결과 보고
    잠이 안오네요 내일이 두군두군해요 ㅎ

    다시한번 감사합니다

    • Favicon of https://greenfishblog.tistory.com BlogIcon 초록생선 2013.04.16 08:44 신고 address edit & del

      Snappy가 바로 그런 용도로 만들어 졌습니다. 물론, 속도도 빠르지만, 압축률에 있어서도 몇% over되는건 크게 중요한건 아니죠(용도에 따라). 참고로, Snappy와 반대인 것(높은 압축률, 낮은 속도)이 zopfli이고 이또한 google에서 관리합니다. 이는 보통 web의 static data등등... 에서 쓰이면 용의하니 알아두시면 좋습니다.

  2. Favicon of http://www.iruis.net BlogIcon iruis 2013.08.16 13:22 address edit & del reply

    snappy도 최소한 헤더 정도는 있겠죠? hello, world!의 글자 수 보다 늘어난 것은 아마 글자의 반복여부 보다는 너무 짧은 길이의 내용을 압축 했기 때문으로 보입니다.

    • Favicon of https://greenfishblog.tistory.com BlogIcon 초록생선 2013.08.16 13:28 신고 address edit & del

      꽤나 유동적일 수 있지만, 그냥 인터넷 뉴스 같은 text들을 압축해도 용량이 커지기고 합니다. 물론, 비례적으로 증가하는 것이 아니라, 상수값, 즉 압축 헤더 정도일 것이구요... 대략 실험했을때, 같은 text이더라도, zlib 보다는 그 비용(+알파)이 큰 것으로 보였습니다... 그리고, snappy는 반복 구간이 많을 수 록 유리했던거 같습니다.

  3. forensic 2015.04.27 14:44 address edit & del reply

    소스코드 감사합니다. 허나 궁금한 점이 있습니다. char형의 hello world를 RawCompress 하는 과정은 알겠는데 RawCompressed Binary는 어떻게 RawUnCompress 하나요? 잘 안되네요....

    • Favicon of https://greenfishblog.tistory.com BlogIcon 초록생선 2015.04.27 16:10 신고 address edit & del

      char를 쓴건, 1byte 단위의 정보(byte)를 받겠다는 뜻이지,
      글자 1개를 뜻하는건 아닐겁니다...

      즉,
      구조체 data같은 binary들도,
      (char*)같이 pointer로 형변환해서 전달하면,
      아무런 문제 없을겁니다.
      즉, RawCompress((char*)&stBinary, sizeof(stBinary), ...)
      해도 되는데,

      RawUnCompress 하나요? 잘 안되네요....
      ==>
      아마도 잘 될겁니다...