implemented search accelerator
authorYann Collet <cyan@fb.com>
Thu, 3 May 2018 23:31:41 +0000 (16:31 -0700)
committerYann Collet <cyan@fb.com>
Thu, 3 May 2018 23:31:41 +0000 (16:31 -0700)
greatly improves speed compared to non-accelerated,
especially for slower files.

On my laptop, -b12 :
```
calgary.tar :  4.3 MB/s =>  9.0 MB/s
enwik7      : 10.2 MB/s => 13.3 MB/s
silesia.tar :  4.0 MB/s =>  8.7 MB/s
```

Note : this is the simplified version,
without handling dictionaries, external buffer, nor pattern analyzer.
Current `dev` branch on these samples gives :
```
calgary.tar :  4.2 MB/s
enwik7      :  9.7 MB/s
silesia.tar :  3.5 MB/s
```

interestingly, it's slower,
presumably due to handling of dictionaries.

lib/lz4hc.c

index 132673e..6c50db5 100644 (file)
@@ -1099,6 +1099,7 @@ LZ4HC_FindLongestMatch (LZ4HC_CCtx_internal* hc4,
     int nbAttempts = maxNbAttempts;
     U32 const pattern = LZ4_read32(ip);
     U32 matchIndex;
+    int fromMStart = 0;
 
     DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
     /* First Match */
@@ -1132,8 +1133,8 @@ LZ4HC_FindLongestMatch (LZ4HC_CCtx_internal* hc4,
     }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
 
     assert(longest > MINMATCH);
-    while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) {
-        const BYTE* const matchPtr = base + matchIndex;
+    while ((matchIndex-fromMStart>=lowestMatchIndex) && (nbAttempts)) {
+        const BYTE* const matchPtr = base + matchIndex - fromMStart;
         assert(matchIndex < ipIndex);
         assert(matchIndex >= dictLimit);
         assert(matchPtr >= lowPrefixPtr);
@@ -1146,6 +1147,21 @@ LZ4HC_FindLongestMatch (LZ4HC_CCtx_internal* hc4,
                 if (mlt > longest) {
                     longest = mlt;
                     *matchpos = matchPtr;
+                    matchIndex -= fromMStart;   /* beginning of match */
+                    if (1 && matchIndex + longest <= ipIndex) {
+                        U32 distanceToNextMatch = 1;
+                        int pos;
+                        for (pos = 0; pos <= longest - MINMATCH; pos++) {
+                            U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + pos);
+                            if (candidateDist > distanceToNextMatch) {
+                                distanceToNextMatch = candidateDist;
+                                fromMStart = pos;
+                            }
+                        }
+                        if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */
+                        matchIndex -= distanceToNextMatch - fromMStart;
+                        continue;
+                    }
         }   }   }
 
         {   U32 const nextOffset = DELTANEXTU16(chainTable, matchIndex);