Browse Source

Merge pull request #21 from emfree/improve_copy_efficiency

Improve copy efficiency in block decompression
Pierre Curto 8 years ago
parent
commit
2fcda4cb70
2 changed files with 42 additions and 4 deletions
  1. 13 4
      block.go
  2. 29 0
      lz4_test.go

+ 13 - 4
block.go

@@ -101,11 +101,20 @@ func UncompressBlock(src, dst []byte, di int) (int, error) {
 		}
 
 		// copy the match (NB. match is at least 4 bytes long)
-		// NB. past di, copy() would write old bytes instead of
-		// the ones we just copied, so split the work into the largest chunk.
-		for ; mLen >= offset; mLen -= offset {
-			di += copy(dst[di:], dst[di-offset:di])
+		if mLen >= offset {
+			bytesToCopy := offset * (mLen / offset)
+			// Efficiently copy the match dst[di-offset:di] into the slice
+			// dst[di:di+bytesToCopy]
+			expanded := dst[di-offset : di+bytesToCopy]
+			n := offset
+			for n <= bytesToCopy+offset {
+				copy(expanded[n:], expanded[:n])
+				n *= 2
+			}
+			di += bytesToCopy
+			mLen -= bytesToCopy
 		}
+
 		di += copy(dst[di:], dst[di-offset:di-offset+mLen])
 	}
 }

+ 29 - 0
lz4_test.go

@@ -295,6 +295,21 @@ func BenchmarkUncompressBlock(b *testing.B) {
 	}
 }
 
+func BenchmarkUncompressConstantBlock(b *testing.B) {
+	d := make([]byte, 4096)
+	z := make([]byte, 4096)
+	source := make([]byte, 4096)
+	n, err := lz4.CompressBlock(source, z, 0)
+	if err != nil {
+		b.Errorf("CompressBlock: %s", err)
+		b.FailNow()
+	}
+	z = z[:n]
+	for i := 0; i < b.N; i++ {
+		lz4.UncompressBlock(z, d, 0)
+	}
+}
+
 func BenchmarkCompressBlock(b *testing.B) {
 	d := append([]byte{}, lorem...)
 	z := make([]byte, len(lorem))
@@ -310,6 +325,20 @@ func BenchmarkCompressBlock(b *testing.B) {
 	}
 }
 
+func BenchmarkCompressConstantBlock(b *testing.B) {
+	d := make([]byte, 4096)
+	z := make([]byte, 4096)
+	n, err := lz4.CompressBlock(d, z, 0)
+	if err != nil {
+		b.Errorf("CompressBlock: %s", err)
+		b.FailNow()
+	}
+	z = z[:n]
+	for i := 0; i < b.N; i++ {
+		lz4.CompressBlock(d, z, 0)
+	}
+}
+
 func BenchmarkCompressBlockHC(b *testing.B) {
 	d := append([]byte{}, lorem...)
 	z := make([]byte, len(lorem))