Commit c1120e9b authored by Benoît Lizé's avatar Benoît Lizé Committed by Commit Bot

tools/android: Benchmark brotli compression on JS.

Adds support for brotli compression to the compression_benchmark test
tool. Results below are taken from a sample of JS files found on the web (see
the linked bug).

Overall, at comparable compression ratios, brotli is slower than zlib for
decompression but faster at compression, on Android and Linux. Tested on
Pixel (Android) and Xeon "broadwell" (linux).

For instance, for a 32kiB chunk size:
- Linux
Zlib
Size = 32768
Compression
  Compression ratio = 2.97379
  Throughput = 35.7633MB/s
  Latency (size = 32768) = 916.246us
Decompression
  Throughput = 329.092MB/s
  Latency (size = 32768) = 99.5711us

Brotli
Size = 32768
Compression
  Compression ratio = 2.81762
  Throughput = 52.4092MB/s
  Latency (size = 32768) = 625.234us
Decompression
  Throughput = 159.92MB/s
  Latency (size = 32768) = 204.903us

- Android
Zlib
Size = 32768
Compression
  Compression ratio = 2.97379
  Throughput = 18.7666MB/s
  Latency (size = 32768) = 1746.08us
Decompression
  Throughput = 204.837MB/s
  Latency (size = 32768) = 159.971us

Brotli
Size = 32768
Compression
  Compression ratio = 2.81762
  Throughput = 30.1437MB/s
  Latency (size = 32768) = 1087.06us
Decompression
  Throughput = 85.4071MB/s
  Latency (size = 32768) = 383.668us

Bug: 907489
Change-Id: Ia6b0877fa6964098bd99e8d2dea3ff09e316d910
Reviewed-on: https://chromium-review.googlesource.com/c/1356549
Commit-Queue: Kenichi Ishibashi <bashi@chromium.org>
Reviewed-by: default avatarKenichi Ishibashi <bashi@chromium.org>
Reviewed-by: default avatarEgor Pasko <pasko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612903}
parent c8b19fef
......@@ -20,6 +20,8 @@ executable("compression_benchmark") {
deps = [
"//base",
"//base/test:test_support",
"//third_party/brotli:dec",
"//third_party/brotli:enc",
"//third_party/snappy",
"//third_party/zlib/google:compression_utils",
]
......
include_rules = [
"+third_party/brotli",
"+third_party/snappy",
"+third_party/zlib",
]
......@@ -12,11 +12,15 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "third_party/brotli/include/brotli/decode.h"
#include "third_party/brotli/include/brotli/encode.h"
#include "third_party/snappy/src/snappy.h"
#include "third_party/zlib/google/compression_utils.h"
namespace {
enum class CompressionType { kSnappy, kZlib, kBrotli };
void LogThroughputAndLatency(size_t chunk_size,
size_t chunk_count,
base::TimeTicks tick,
......@@ -34,7 +38,7 @@ void LogThroughputAndLatency(size_t chunk_size,
void CompressChunks(const std::string& contents,
size_t chunk_size,
bool snappy,
CompressionType compression_type,
std::vector<std::string>* compressed_chunks) {
CHECK(compressed_chunks);
size_t chunk_count = contents.size() / chunk_size;
......@@ -42,10 +46,26 @@ void CompressChunks(const std::string& contents,
for (size_t i = 0; i < chunk_count; ++i) {
std::string compressed;
base::StringPiece input(contents.c_str() + i * chunk_size, chunk_size);
if (snappy)
CHECK(snappy::Compress(input.data(), input.size(), &compressed));
else
CHECK(compression::GzipCompress(input, &compressed));
switch (compression_type) {
case CompressionType::kSnappy:
CHECK(snappy::Compress(input.data(), input.size(), &compressed));
break;
case CompressionType::kZlib:
CHECK(compression::GzipCompress(input, &compressed));
break;
case CompressionType::kBrotli: {
std::vector<uint8_t> compressed_data(
BrotliEncoderMaxCompressedSize(input.size()));
size_t encoded_size = compressed_data.size();
CHECK(BrotliEncoderCompress(
3, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, input.size(),
reinterpret_cast<const uint8_t*>(input.data()), &encoded_size,
reinterpret_cast<uint8_t*>(&compressed_data[0])));
compressed.assign(reinterpret_cast<const char*>(&compressed_data[0]),
encoded_size);
} break;
}
compressed_chunks->push_back(compressed);
}
......@@ -53,17 +73,28 @@ void CompressChunks(const std::string& contents,
void BenchmarkDecompression(const std::string& contents,
size_t chunk_size,
bool snappy) {
CompressionType compression_type) {
std::vector<std::string> compressed_chunks;
CompressChunks(contents, chunk_size, snappy, &compressed_chunks);
CompressChunks(contents, chunk_size, compression_type, &compressed_chunks);
auto tick = base::TimeTicks::Now();
for (const auto& chunk : compressed_chunks) {
std::string uncompressed;
if (snappy) {
snappy::Uncompress(chunk.c_str(), chunk.size(), &uncompressed);
} else {
CHECK(compression::GzipUncompress(chunk, &uncompressed));
switch (compression_type) {
case CompressionType::kSnappy:
snappy::Uncompress(chunk.c_str(), chunk.size(), &uncompressed);
break;
case CompressionType::kZlib:
CHECK(compression::GzipUncompress(chunk, &uncompressed));
break;
case CompressionType::kBrotli: {
size_t decoded_size = chunk_size;
std::vector<uint8_t> decoded_data(chunk_size);
CHECK(BrotliDecoderDecompress(
chunk.size(), reinterpret_cast<const uint8_t*>(&chunk[0]),
&decoded_size, &decoded_data[0]));
CHECK_EQ(chunk_size, decoded_size);
} break;
}
}
auto tock = base::TimeTicks::Now();
......@@ -73,10 +104,10 @@ void BenchmarkDecompression(const std::string& contents,
void BenchmarkCompression(const std::string& contents,
size_t chunk_size,
bool snappy) {
CompressionType compression_type) {
auto tick = base::TimeTicks::Now();
std::vector<std::string> compressed_chunks;
CompressChunks(contents, chunk_size, snappy, &compressed_chunks);
CompressChunks(contents, chunk_size, compression_type, &compressed_chunks);
auto tock = base::TimeTicks::Now();
size_t compressed_size = 0;
......@@ -112,14 +143,27 @@ int main(int argc, char** argv) {
for (size_t i = 0; i < repeats; ++i)
repeated_contents.append(contents);
for (bool use_snappy : {false, true}) {
LOG(INFO) << "\n\n\n\n" << (use_snappy ? "Snappy" : "Gzip");
for (CompressionType compression_type :
{CompressionType::kSnappy, CompressionType::kZlib,
CompressionType::kBrotli}) {
switch (compression_type) {
LOG(INFO) << "\n\n\n\n";
case CompressionType::kSnappy:
LOG(INFO) << "Snappy";
break;
case CompressionType::kZlib:
LOG(INFO) << "Zlib";
break;
case CompressionType::kBrotli:
LOG(INFO) << "Brotli";
break;
}
for (size_t size = kPageSize; size < contents.size(); size *= 2) {
LOG(INFO) << "Size = " << size;
LOG(INFO) << "Compression";
BenchmarkCompression(repeated_contents, size, use_snappy);
BenchmarkCompression(repeated_contents, size, compression_type);
LOG(INFO) << "Decompression";
BenchmarkDecompression(repeated_contents, size, use_snappy);
BenchmarkDecompression(repeated_contents, size, compression_type);
}
}
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment