From 8dbf55f23034a2468cd17516dcc61d2915ec7675 Mon Sep 17 00:00:00 2001 From: Joe Vilches Date: Mon, 5 Feb 2024 11:48:07 -0800 Subject: [PATCH] Add ability to time captured benchmarks (#1569) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1569 Added a `benchmark` function that takes a path representing a directory to read captures from. This is supplied by the caller due to annoyance with filesystem access in C++. This calls into timing code with and prints it out to the console. Reviewed By: NickGerleman Differential Revision: D53104632 fbshipit-source-id: fe8bcb0a87198701865fb04193894591d2eff821 --- benchmark/Benchmark.cpp | 63 ++++++++++++++++++++++++++++++++++++++++- benchmark/Benchmark.h | 7 +++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/benchmark/Benchmark.cpp b/benchmark/Benchmark.cpp index 2ffb3c39..054952a8 100644 --- a/benchmark/Benchmark.cpp +++ b/benchmark/Benchmark.cpp @@ -14,6 +14,11 @@ namespace facebook::yoga { using namespace nlohmann; +using namespace std::chrono; + +constexpr uint32_t kNumRepititions = 1000; +using SteadyClockDurations = + std::array; std::string invalidArgumentMessage(std::string arg, std::string enumName) { return arg + " does not represent any " + enumName + " values"; @@ -317,15 +322,71 @@ YGNodeRef buildTreeFromJson(json& j, YGNodeRef parent, size_t index) { return node; } -void generateBenchmark(const std::filesystem::path& capturePath) { +BenchmarkResult generateBenchmark(const std::filesystem::path& capturePath) { std::ifstream captureFile(capturePath); json capture = json::parse(captureFile); + auto treeCreationBegin = steady_clock::now(); YGNodeRef root = buildTreeFromJson(capture, nullptr, 0 /*index*/); + auto treeCreationEnd = steady_clock::now(); + auto layoutBegin = steady_clock::now(); YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + auto layoutEnd = steady_clock::now(); YGNodeFreeRecursive(root); + + return BenchmarkResult{ + treeCreationEnd - treeCreationBegin, layoutEnd - layoutBegin}; +} + +static void printBenchmarkResult( + std::string name, + SteadyClockDurations& durations) { + std::array timesInMs; + double mean = 0; + for (uint32_t i = 0; i < kNumRepititions; i++) { + auto ms = duration(durations[i]).count(); + timesInMs[i] = ms; + mean += ms; + } + mean /= kNumRepititions; + + std::sort(timesInMs.begin(), timesInMs.end()); + double median = timesInMs[kNumRepititions / 2]; + + double variance = 0; + for (uint32_t i = 0; i < kNumRepititions; i++) { + variance += std::pow(timesInMs[i] - mean, 2); + } + variance /= kNumRepititions; + double stddev = std::sqrt(variance); + + printf("%s: median: %lf ms, stddev: %lf ms\n", name.c_str(), median, stddev); +} + +void benchmark(std::filesystem::path& capturesDir) { + for (auto& capture : std::filesystem::directory_iterator(capturesDir)) { + if (capture.is_directory() || capture.path().extension() != ".json") { + continue; + } + + SteadyClockDurations treeCreationDurations; + SteadyClockDurations layoutDurations; + SteadyClockDurations totalDurations; + + for (uint32_t i = 0; i < kNumRepititions; i++) { + BenchmarkResult result = generateBenchmark(capture.path()); + treeCreationDurations[i] = result.treeCreationDuration; + layoutDurations[i] = result.layoutDuration; + totalDurations[i] = result.treeCreationDuration + result.layoutDuration; + } + + std::string captureName = capture.path().stem(); + printBenchmarkResult(captureName + " tree creation", treeCreationDurations); + printBenchmarkResult(captureName + " layout", layoutDurations); + printBenchmarkResult(captureName + " total", totalDurations); + } } } // namespace facebook::yoga diff --git a/benchmark/Benchmark.h b/benchmark/Benchmark.h index 29cf5e0f..8212ecca 100644 --- a/benchmark/Benchmark.h +++ b/benchmark/Benchmark.h @@ -7,11 +7,14 @@ #pragma once -#include +#include #include namespace facebook::yoga { -void generateBenchmark(const std::filesystem::path& capturePath); +struct BenchmarkResult { + std::chrono::steady_clock::duration treeCreationDuration; + std::chrono::steady_clock::duration layoutDuration; +}; } // namespace facebook::yoga