Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5422ba1c authored by Daniel Zheng's avatar Daniel Zheng Committed by Automerger Merge Worker
Browse files

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

Merge "Add unit test for cow compressor performance" into main am: f278b547 am: b1cbaa77 am: fef270e8 am: 5196fed4 am: 16c886ed

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



Change-Id: I073562060394c20f36be21390abe2c89edbf89ff
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 6cf3383f 16c886ed
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
#pragma once

#include <memory>
#include <string_view>
#include "libsnapshot/cow_format.h"

namespace android {
+22 −0
Original line number Diff line number Diff line

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"],
}
+188 −0
Original line number Diff line number Diff line

#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;
}
 No newline at end of file