Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bump 7z #517

Merged
merged 1 commit into from
Oct 4, 2024
Merged

bump 7z #517

merged 1 commit into from
Oct 4, 2024

Conversation

pazos
Copy link
Member

@pazos pazos commented Oct 2, 2024

from 19.00 to 24.06

It seems faster uncompressing on arm64 but I didn't benchmark.


This change is Reviewable

@benoit-pierre
Copy link
Contributor

benoit-pierre commented Oct 2, 2024

If you want faster, I have a patch for ZSTD support in my meson branch. For 19.00, but I think latest has builtin support.

@Frenzie Frenzie merged commit 26f9f10 into koreader:master Oct 4, 2024
3 checks passed
@pazos
Copy link
Member Author

pazos commented Oct 4, 2024

If you want faster, I have a patch for ZSTD support in my meson branch. For 19.00, but I think latest has builtin support.

I was happy with fast as before. I'm even happier now with "faster". I wouldn't mind "even faster" but I care much more about the compression ratio. So, if we can squeeze the same data in ZSTD as in XZ I'm all in for the change :)

@Frenzie
Copy link
Member

Frenzie commented Oct 4, 2024

Keep in mind memory usage could also be an issue. Those Android 4.x ereaders aren't very well endowed, and zstd is known to use rather a lot more while decompressing.

@benoit-pierre
Copy link
Contributor

Well, we have reduced our APKs size, compared to past versions:

Version ARM ARM64 x86
2024.04 31.1 MB 32.5 MB 33 MB
2024.07 30.6 MB 32 MB 32.4 MB
nightly (229-gcba79bca1) 28.2 MB 29.3 MB 31.1 MB

So we have a little headroom.

@pazos
Copy link
Member Author

pazos commented Oct 4, 2024

On modern devices the difference on speed while uncompressing should be below 1s, because that's what should take to extract our current 7z payload.

Well, we have reduced our APKs size, compared to past versions:

You did. Nice work. These few MB sum up on the monthtly bandwidth, I guess.

Anyhow, feel free to do it. I'm curious enough to give it a benchmark on a few emulators and a couple of VMs ;)

@benoit-pierre
Copy link
Contributor

I ran some tests, with that patch:

diff --git i/jni/lzma/7z/C/7zDec.c w/jni/lzma/7z/C/7zDec.c
index c9b4064e..e16bdcd2 100755
--- i/jni/lzma/7z/C/7zDec.c
+++ w/jni/lzma/7z/C/7zDec.c
@@ -3,29 +3,46 @@
 
 #include "Precomp.h"
 
+#include <android/log.h>
 #include <string.h>
+#include <stdio.h>
 
 /* #define Z7_PPMD_SUPPORT */
+/* #define Z7_ZSTD_SUPPORT */
+#define Z7_NO_METHOD_BCJ2
+#define Z7_NO_METHODS_FILTERS
+/* #define Z7_NO_METHOD_LZMA */
+/* #define Z7_NO_METHOD_LZMA2 */
 
 #include "7z.h"
 #include "7zCrc.h"
 
+#include "Alloc.h"
+#ifndef Z7_NO_METHOD_BCJ2
 #include "Bcj2.h"
+#endif
 #include "Bra.h"
 #include "CpuArch.h"
 #include "Delta.h"
+#ifndef Z7_NO_METHOD_LZMA
 #include "LzmaDec.h"
+#endif
+#ifndef Z7_NO_METHOD_LZMA2
 #include "Lzma2Dec.h"
+#endif
 #ifdef Z7_PPMD_SUPPORT
 #include "Ppmd7.h"
 #endif
+#ifdef Z7_ZSTD_SUPPORT
+#include "ZstdDec.h"
+#endif
 
 #define k_Copy 0
-#ifndef Z7_NO_METHOD_LZMA2
 #define k_LZMA2 0x21
-#endif
 #define k_LZMA  0x30101
 #define k_BCJ2  0x303011B
+#define k_PPMD  0x30401
+#define k_ZSTD  0x4f71101
 
 #if !defined(Z7_NO_METHODS_FILTERS)
 #define Z7_USE_BRANCH_FILTER
@@ -61,8 +78,6 @@
 
 #ifdef Z7_PPMD_SUPPORT
 
-#define k_PPMD 0x30401
-
 typedef struct
 {
   IByteIn vt;
@@ -160,6 +175,75 @@ static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, I
 
 #endif
 
+#ifdef Z7_ZSTD_SUPPORT
+
+static SRes SzDecodeZstd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+  void           *inBuf = NULL;
+  CZstdDecHandle  dec = NULL;
+  SRes            res;
+
+  inBuf = ISzAlloc_Alloc(allocMain, inSize);
+  if (inBuf == NULL) {
+    res = SZ_ERROR_MEM;
+    goto end;
+  }
+
+  {
+    SizeT size = inSize;
+
+    res = ILookInStream_Read(inStream, inBuf, &size);
+    if (res != SZ_OK || size != inSize) {
+      res = SZ_ERROR_READ;
+      goto end;
+    }
+  }
+
+  dec = ZstdDec_Create(&g_AlignedAlloc, &g_BigAlloc);
+  if (!dec) {
+    res = SZ_ERROR_MEM;
+    goto end;
+  }
+
+  ZstdDec_Init(dec);
+
+  {
+    CZstdDecState   state;
+
+    ZstdDecState_Clear(&state);
+
+    state.inBuf = inBuf;
+    state.inPos = 0;
+    state.inLim = inSize;
+    state.outSize_Defined = True;
+    state.outSize = outSize;
+    state.outBuf_fromCaller = outBuffer;
+    state.outBufSize_fromCaller = outSize;
+
+    do {
+      res = ZstdDec_Decode(dec, &state);
+      if (res != SZ_OK)
+      {
+        CZstdDecResInfo status;
+        ZstdDec_GetResInfo(dec, &state, res, &status);
+        res = status.decode_SRes;
+        break;
+      }
+    } while (state.outProcessed < outSize);
+  }
+
+end:
+  if (dec)
+    ZstdDec_Destroy(dec);
+  if (inBuf != NULL)
+    ISzAlloc_Free(allocMain, inBuf);
+  return res;
+}
+
+#endif
+
+#ifndef Z7_NO_METHOD_LZMA
 
 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
     Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
@@ -218,6 +302,7 @@ static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, I
   return res;
 }
 
+#endif
 
 #ifndef Z7_NO_METHOD_LZMA2
 
@@ -304,12 +389,17 @@ static BoolInt IS_MAIN_METHOD(UInt32 m)
   switch (m)
   {
     case k_Copy:
+  #ifndef Z7_NO_METHOD_LZMA
     case k_LZMA:
+  #endif
   #ifndef Z7_NO_METHOD_LZMA2
     case k_LZMA2:
   #endif
   #ifdef Z7_PPMD_SUPPORT
     case k_PPMD:
+  #endif
+  #ifdef Z7_ZSTD_SUPPORT
+    case k_ZSTD:
   #endif
       return True;
   }
@@ -465,16 +555,50 @@ static SRes SzFolder_Decode2(const CSzFolder *folder,
       inSize = packPositions[(size_t)si + 1] - offset;
       RINOK(LookInStream_SeekTo(inStream, startPos + offset))
 
+      {
+        const char *method;
+        switch (coder->MethodID) {
+        case k_Copy:
+          method = "copy";
+          break;
+        case k_BCJ2:
+          method = "BCJ2";
+          break;
+        case k_LZMA:
+          method = "LZMA";
+          break;
+        case k_LZMA2:
+          method = "LZMA2";
+          break;
+        case k_PPMD:
+          method = "PPMD";
+          break;
+        case k_ZSTD:
+          method = "ZSTD";
+          break;
+        default:
+          {
+            static char _method_buf[9];
+            snprintf(_method_buf, sizeof (_method_buf), "%x", coder->MethodID);
+            method = _method_buf;
+          }
+          break;
+        }
+        __android_log_print(ANDROID_LOG_INFO, "7z", "method=%s, size=%llu/%u", method, inSize, outSizeCur);
+      }
+
       if (coder->MethodID == k_Copy)
       {
         if (inSize != outSizeCur) /* check it */
           return SZ_ERROR_DATA;
         RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
       }
+    #ifndef Z7_NO_METHOD_LZMA
       else if (coder->MethodID == k_LZMA)
       {
         RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
       }
+    #endif
     #ifndef Z7_NO_METHOD_LZMA2
       else if (coder->MethodID == k_LZMA2)
       {
@@ -486,10 +610,17 @@ static SRes SzFolder_Decode2(const CSzFolder *folder,
       {
         RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
       }
+    #endif
+    #ifdef Z7_ZSTD_SUPPORT
+      else if (coder->MethodID == k_ZSTD)
+      {
+        RINOK(SzDecodeZstd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+      }
     #endif
       else
         return SZ_ERROR_UNSUPPORTED;
     }
+    #ifndef Z7_NO_METHOD_BCJ2
     else if (coder->MethodID == k_BCJ2)
     {
       const UInt64 offset = packPositions[1];
@@ -537,6 +668,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder,
         }
       }
     }
+#endif
 #if defined(Z7_USE_BRANCH_FILTER)
     else if (ci == 1)
     {
diff --git i/jni/lzma/Android.mk w/jni/lzma/Android.mk
index 130f3f7..5309c37 100644
--- i/jni/lzma/Android.mk
+++ w/jni/lzma/Android.mk
@@ -3,12 +3,28 @@ include $(CLEAR_VARS)
 
 LOCAL_MODULE := 7z
 
-lzma_SOURCES := \
-	7zAlloc.c 7zArcIn.c 7zBuf.c 7zBuf2.c \
-	7zCrc.c 7zCrcOpt.c 7zDec.c 7zFile.c \
-	7zStream.c Bcj2.c Bra.c Bra86.c BraIA64.c \
-	CpuArch.c Delta.c Lzma2Dec.c LzmaDec.c \
-	Ppmd7.c Ppmd7Dec.c
+sevenzip_SOURCES := \
+	7zAlloc.c 7zArcIn.c 7zBuf.c 7zCrc.c \
+	7zCrcOpt.c 7zDec.c 7zFile.c 7zStream.c \
+	CpuArch.c Delta.c \
+
+# For BCJ2 support.
+# sevenzip_SOURCES += Bcj2.c
+
+# For LZMA support.
+sevenzip_SOURCES += LzmaDec.c
+
+# For LZMA2 support (need LZMA).
+sevenzip_SOURCES += Lzma2Dec.c
+
+# For PPMD support.
+# sevenzip_SOURCES += Ppmd7.c Ppmd7Dec.c
+
+# For ZSTD support.
+# sevenzip_SOURCES += Alloc.c Xxh64.c ZstdDec.c
+
+# For method filters support.
+# sevenzip_SOURCES += Bra.c Bra86.c BraIA64.c
 
 un7zip_SOURCES := \
 	7zAssetFile.cpp \
@@ -20,7 +36,7 @@ LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/un7zip
 
 LOCAL_SRC_FILES := \
-	$(addprefix 7z/C/, $(lzma_SOURCES)) \
+	$(addprefix 7z/C/, $(sevenzip_SOURCES)) \
 	$(addprefix un7zip/, $(un7zip_SOURCES)) \
 	un7z.cpp

Running on my Nexus 7 (2013):

Compression Time to compress Archive size Update installed in…
-m0=lzma2 10.6s 19 MB 5.9s
-m0=lzma2 -mx=9 15.1s 18 MB 5.7s
-m0=lzma2 -mx=9 -ma=0 6.8s 21 MB 6.0s
-m0=flzma2 3.7s 19 MB 5.8s
-m0=flzma2 -mx=9 6.4s 18 MB 5.7s
-m0=zstd -mhc=off 0.4s 26 MB 2.7s
-m0=zstd -mx=16 -mhc=off 3.9s 22 MB 2.6s
-m0=zstd -mx=18 -mhc=off 8.3s 21 MB 2.6s
-m0=zstd -mx=20 -mhc=off 21.9s 20 MB 2.6s
-m0=zstd -mx=22 -mhc=off 29.8s 20 MB 2.6s

Note: -m0=flzma2 -mx=9 (7z >= 17.02) reduce archive size by ~120K compared to -m0=lzma2 -mx=9.

Best choice, IMHO, stick with lzma2, but update our Docker images 7z version so we can use flzma2. Additionally, fork https://github.com/kornelski/7z.git and apply the patch above, so we can shave ~11KB from lib7z.so code size (on ARM).

@Frenzie
Copy link
Member

Frenzie commented Oct 15, 2024

It's a pity the flzma2 savings are mainly in compression speed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants