Merge "Add unit test for cow compressor performance" into main am: f278b54731

Original change: https://android-review.googlesource.com/c/platform/system/core/+/2722633

Change-Id: I0d25885f62daf3f5e750be2ceeecb29a34083645
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Daniel Zheng 2023-08-23 20:34:10 +00:00 committed by Automerger Merge Worker
commit b1cbaa77de
3 changed files with 210 additions and 1 deletions

View file

@ -17,7 +17,6 @@
#pragma once
#include <memory>
#include <string_view>
#include "libsnapshot/cow_format.h"
namespace android {

View file

@ -0,0 +1,22 @@
cc_binary {
name: "cow_benchmark",
host_supported: true,
defaults: [
"fs_mgr_defaults",
"libsnapshot_cow_defaults",
],
srcs: ["cow_benchmark.cpp"],
static_libs: [
"libsnapshot_cow",
],
shared_libs: [
"libbase",
"liblog",
],
cflags: ["-Werror"],
}

View file

@ -0,0 +1,188 @@
#include <memory>
#include <array>
#include <iostream>
#include <random>
#include <libsnapshot/cow_compress.h>
#include <libsnapshot/cow_format.h>
static const uint32_t BLOCK_SZ = 4096;
static const uint32_t SEED_NUMBER = 10;
namespace android {
namespace snapshot {
static std::string CompressionToString(CowCompression& compression) {
std::string output;
switch (compression.algorithm) {
case kCowCompressBrotli:
output.append("brotli");
break;
case kCowCompressGz:
output.append("gz");
break;
case kCowCompressLz4:
output.append("lz4");
break;
case kCowCompressZstd:
output.append("zstd");
break;
case kCowCompressNone:
return "No Compression";
}
output.append(" " + std::to_string(compression.compression_level));
return output;
}
void OneShotCompressionTest() {
std::cout << "\n-------One Shot Compressor Perf Analysis-------\n";
std::vector<CowCompression> compression_list = {
{kCowCompressLz4, 0}, {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3},
{kCowCompressBrotli, 11}, {kCowCompressZstd, 3}, {kCowCompressZstd, 6},
{kCowCompressZstd, 9}, {kCowCompressZstd, 22}, {kCowCompressGz, 1},
{kCowCompressGz, 3}, {kCowCompressGz, 6}, {kCowCompressGz, 9}};
std::vector<std::unique_ptr<ICompressor>> compressors;
for (auto i : compression_list) {
compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ));
}
// Allocate a buffer of size 8 blocks.
std::array<char, 32768> buffer;
// Generate a random 4k buffer of characters
std::default_random_engine gen(SEED_NUMBER);
std::uniform_int_distribution<int> distribution(0, 10);
for (int i = 0; i < buffer.size(); i++) {
buffer[i] = static_cast<char>(distribution(gen));
}
std::vector<std::pair<double, std::string>> latencies;
std::vector<std::pair<double, std::string>> ratios;
for (size_t i = 0; i < compressors.size(); i++) {
const auto start = std::chrono::steady_clock::now();
std::basic_string<uint8_t> compressed_data =
compressors[i]->Compress(buffer.data(), buffer.size());
const auto end = std::chrono::steady_clock::now();
const auto latency =
std::chrono::duration_cast<std::chrono::nanoseconds>(end - start) / 1000.0;
const double compression_ratio =
static_cast<uint16_t>(compressed_data.size()) * 1.00 / buffer.size();
std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> "
<< latency.count() << "ms "
<< " compression ratio ->" << compression_ratio << " \n";
latencies.emplace_back(
std::make_pair(latency.count(), CompressionToString(compression_list[i])));
ratios.emplace_back(
std::make_pair(compression_ratio, CompressionToString(compression_list[i])));
}
int best_speed = 0;
int best_ratio = 0;
for (size_t i = 1; i < latencies.size(); i++) {
if (latencies[i].first < latencies[best_speed].first) {
best_speed = i;
}
if (ratios[i].first < ratios[best_ratio].first) {
best_ratio = i;
}
}
std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms "
<< latencies[best_speed].second << "\n";
std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second
<< "\n";
}
void IncrementalCompressionTest() {
std::cout << "\n-------Incremental Compressor Perf Analysis-------\n";
std::vector<CowCompression> compression_list = {
{kCowCompressLz4, 0}, {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3},
{kCowCompressBrotli, 11}, {kCowCompressZstd, 3}, {kCowCompressZstd, 6},
{kCowCompressZstd, 9}, {kCowCompressZstd, 22}, {kCowCompressGz, 1},
{kCowCompressGz, 3}, {kCowCompressGz, 6}, {kCowCompressGz, 9}};
std::vector<std::unique_ptr<ICompressor>> compressors;
for (auto i : compression_list) {
compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ));
}
// Allocate a buffer of size 8 blocks.
std::array<char, 32768> buffer;
// Generate a random 4k buffer of characters
std::default_random_engine gen(SEED_NUMBER);
std::uniform_int_distribution<int> distribution(0, 10);
for (int i = 0; i < buffer.size(); i++) {
buffer[i] = static_cast<char>(distribution(gen));
}
std::vector<std::pair<double, std::string>> latencies;
std::vector<std::pair<double, std::string>> ratios;
for (size_t i = 0; i < compressors.size(); i++) {
std::vector<std::basic_string<uint8_t>> compressed_data_vec;
int num_blocks = buffer.size() / BLOCK_SZ;
const uint8_t* iter = reinterpret_cast<const uint8_t*>(buffer.data());
const auto start = std::chrono::steady_clock::now();
while (num_blocks > 0) {
std::basic_string<uint8_t> compressed_data = compressors[i]->Compress(iter, BLOCK_SZ);
compressed_data_vec.emplace_back(compressed_data);
num_blocks--;
iter += BLOCK_SZ;
}
const auto end = std::chrono::steady_clock::now();
const auto latency =
std::chrono::duration_cast<std::chrono::nanoseconds>(end - start) / 1000.0;
size_t size = 0;
for (auto& i : compressed_data_vec) {
size += i.size();
}
const double compression_ratio = size * 1.00 / buffer.size();
std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> "
<< latency.count() << "ms "
<< " compression ratio ->" << compression_ratio << " \n";
latencies.emplace_back(
std::make_pair(latency.count(), CompressionToString(compression_list[i])));
ratios.emplace_back(
std::make_pair(compression_ratio, CompressionToString(compression_list[i])));
}
int best_speed = 0;
int best_ratio = 0;
for (size_t i = 1; i < latencies.size(); i++) {
if (latencies[i].first < latencies[best_speed].first) {
best_speed = i;
}
if (ratios[i].first < ratios[best_ratio].first) {
best_ratio = i;
}
}
std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms "
<< latencies[best_speed].second << "\n";
std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second
<< "\n";
}
} // namespace snapshot
} // namespace android
int main() {
android::snapshot::OneShotCompressionTest();
android::snapshot::IncrementalCompressionTest();
return 0;
}