From 9e32854c2f108418877268368c4ee257b8e8ee23 Mon Sep 17 00:00:00 2001 From: Yaraslau Tamashevich Date: Tue, 19 Mar 2024 21:05:27 +0200 Subject: [PATCH] Add some benchmarks with unicode characters --- .github/workflows/build.yml | 20 ++++---- libtermbench/termbench.cpp | 95 ++++++++++++++++++++++++++++++++----- libtermbench/termbench.h | 6 +++ scripts/Xvfb-bench-run.sh | 8 ++-- scripts/plot_results.jl | 61 +++++++++++++++++------- tb/main.cpp | 62 +++++++++++++++++------- 6 files changed, 189 insertions(+), 63 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b09d66..03a5caf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,7 +39,7 @@ jobs: sudo apt-get install clang-format-17 - name: "Clang-format libtermbench" run: find ./libtermbench -name "*.cpp" -o -name "*.h" | xargs clang-format-17 --Werror --dry-run - - name: "Clang-format tb1" + - name: "Clang-format tb" run: find ./tb -name "*.cpp" -o -name "*.h" | xargs clang-format-17 --Werror --dry-run - name: "Check includes" run: ./scripts/check-includes.sh @@ -93,18 +93,14 @@ jobs: run: cargo install alacritty - name: "Install kitty and xterm" run: sudo apt install -y kitty xterm xvfb - - name: "run benchmarks" + - name: "Install wezterm" + run: | + curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg + echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list + sudo apt update + sudo apt install wezterm + - name: "Run benchmarks" run: ./scripts/Xvfb-bench-run.sh "./build/$CMAKE_PRESET/tb/tb" - - name: "ls" - run: ls -la - - name: "cat contour_results" - run: cat contour_results - - name: "cat kitty_results" - run: cat kitty_results - - name: "cat xterm_results" - run: cat xterm_results - - name: "cat alacritty_results" - run: cat alacritty_results - name: "Set up Julia" uses: julia-actions/setup-julia@v1 - name: "Create Plots" diff --git a/libtermbench/termbench.cpp b/libtermbench/termbench.cpp index fcaa7ed..7adc434 100644 --- a/libtermbench/termbench.cpp +++ b/libtermbench/termbench.cpp @@ -421,35 +421,104 @@ std::unique_ptr binary() return std::make_unique(); } -std::unique_ptr ascii_line(size_t N) +std::unique_ptr ascii_line(size_t line_length) { - auto name = std::to_string(N) + " chars per line"; - auto text = std::string(N, 'a') + std::string { "\n" }; + auto name = std::to_string(line_length) + " chars per line"; + auto text = std::string(line_length, 'a') + std::string { "\n" }; return std::make_unique(name, text); } -std::unique_ptr sgr_line(size_t N) +std::unique_ptr sgr_line(size_t line_length) { - auto name = std::to_string(N) + " chars with sgr per line"; + auto name = std::to_string(line_length) + " chars with sgr per line"; std::string text {}; - text += std::string { "\033[38;2;20;200;200m" }; - text += std::string(N, 'a'); + text += "\033[38;2;20;200;200m"; + text += std::string(line_length, 'a'); + text += "\n"; + text += "\033[38;2;255;255;255m"; + return std::make_unique(name, text); +} + +std::unique_ptr sgrbg_line(size_t line_length) +{ + auto name = std::to_string(line_length) + " chars with sgr and bg per line"; + std::string text {}; + text += "\033[38;2;20;200;200m\033[48;2;100;100;100m"; + text += std::string(line_length, 'a'); + text += "\033[38;2;255;255;255m\033[48;2;0;0;0m"; + text += "\n"; + return std::make_unique(name, text); +} + +std::unique_ptr unicode_simple(size_t line_length) +{ + auto name = std::to_string(line_length) + " unicode simple"; + std::string text {}; + for (size_t i = 0; i < line_length; ++i) + text += "\u0061"; + text += "\n"; + return std::make_unique(name, text); +} + +std::unique_ptr unicode_two_codepoints(size_t line_length) +{ + auto name = std::to_string(line_length) + " unicode diacritic"; + std::string text {}; + for (size_t i = 0; i < line_length; ++i) + text += "\u0061\u0308"; + text += "\n"; + return std::make_unique(name, text); +} + +std::unique_ptr unicode_three_codepoints(size_t line_length) +{ + auto name = std::to_string(line_length) + " unicode double diacritic"; + std::string text {}; + for (size_t i = 0; i < static_cast(line_length / 2); ++i) + text += "\u0061\u035D\u0062"; + text += "\n"; + return std::make_unique(name, text); +} + +std::unique_ptr unicode_fire_as_text(size_t line_length) +{ + auto name = std::to_string(line_length) + " unicode fire as text"; + std::string text {}; + for (size_t i = 0; i < static_cast(line_length / 2); ++i) + text += std::string { "\U0001F525\U0000FE0E" }; text += std::string { "\n" }; - text += std::string { "\033[38;2;255;255;255m" }; return std::make_unique(name, text); } -std::unique_ptr sgrbg_line(size_t N) +std::unique_ptr unicode_fire(size_t line_length) { - auto name = std::to_string(N) + " chars with sgr and bg per line"; + auto name = std::to_string(line_length) + " unicode fire"; std::string text {}; - text += std::string { "\033[38;2;20;200;200m\033[48;2;100;100;100m" }; - text += std::string(N, 'a'); - text += std::string { "\033[38;2;255;255;255m\033[48;2;0;0;0m" }; + for (size_t i = 0; i < static_cast(line_length / 2); ++i) + text += std::string { "\U0001F525" }; text += std::string { "\n" }; return std::make_unique(name, text); } +std::unique_ptr unicode_flag(size_t line_length) +{ + auto name = std::to_string(line_length) + " unicode flag"; + std::string text {}; + std::string flag {}; + flag += "\U0001F3F4"; + flag += "\U000E0067"; + flag += "\U000E0062"; + flag += "\U000E0065"; + flag += "\U000E006E"; + flag += "\U000E0067"; + flag += "\U000E007F"; + + for (size_t i = 0; i < static_cast(line_length / 2); ++i) + text += flag; + text += "\n"; + return std::make_unique(name, text); +} + std::unique_ptr crafted(std::string name, std::string description, std::string text) { return std::make_unique(std::move(name), std::move(description), std::move(text)); diff --git a/libtermbench/termbench.h b/libtermbench/termbench.h index 9d06510..ba7506e 100644 --- a/libtermbench/termbench.h +++ b/libtermbench/termbench.h @@ -127,5 +127,11 @@ std::unique_ptr binary(); std::unique_ptr ascii_line(size_t); std::unique_ptr sgr_line(size_t); std::unique_ptr sgrbg_line(size_t); +std::unique_ptr unicode_simple(size_t); +std::unique_ptr unicode_two_codepoints(size_t); +std::unique_ptr unicode_three_codepoints(size_t); +std::unique_ptr unicode_flag(size_t); +std::unique_ptr unicode_fire_as_text(size_t); // U+FEOE +std::unique_ptr unicode_fire(size_t); std::unique_ptr crafted(std::string name, std::string description, std::string text); } // namespace termbench::tests diff --git a/scripts/Xvfb-bench-run.sh b/scripts/Xvfb-bench-run.sh index e1a6657..2d03c4a 100755 --- a/scripts/Xvfb-bench-run.sh +++ b/scripts/Xvfb-bench-run.sh @@ -8,6 +8,7 @@ CONTOUR_BIN="${CONTOUR_BIN:-contour}" KITTY_BIN="${KITTY_BIN:-kitty}" XTERM_BIN="${XTERM_BIN:-xterm}" ALACRITTY_BIN="${ALACRITTY_BIN:-alacritty}" +WEZTERM_BIN="${WEZTERM_BIN:-wezterm}" FB_DISPLAY="${FB_DISPLAY:-:99}" OUTPUT_DIR="${PWD}" @@ -31,6 +32,7 @@ require_bin "${CONTOUR_BIN}" require_bin "${KITTY_BIN}" require_bin "${XTERM_BIN}" require_bin "${ALACRITTY_BIN}" +require_bin "${WEZTERM_BIN}" export TB_BIN=$(realpath $TB_BIN) export DISPLAY=${FB_DISPLAY} @@ -47,12 +49,9 @@ function program_exit() { function bench_terminal() { printf "\033[1m==> Running terminal: $1\033[m\n" local terminal_name=$(basename $1) - time "${@}" -e "${TB_BIN}" --fixed-size --stdout-fastpath --column-by-column --output "${OUTPUT_DIR}/${terminal_name}_results" + time "${@}" -e "${TB_BIN}" --fixed-size --column-by-column --size 2 --output "${OUTPUT_DIR}/${terminal_name}_results" local exit_code=$? printf "\033[1m==> Terminal exit code: $exit_code\033[m\n" - if [[ $exit_code -ne 0 ]]; then - program_exit $exit_code - fi } set -x @@ -67,5 +66,6 @@ bench_terminal "${CONTOUR_BIN}" display ${DISPLAY} bench_terminal "${KITTY_BIN}" bench_terminal "${XTERM_BIN}" -display ${DISPLAY} bench_terminal "${ALACRITTY_BIN}" +bench_terminal "${WEZTERM_BIN}" program_exit 0 diff --git a/scripts/plot_results.jl b/scripts/plot_results.jl index bb89dba..134ce42 100644 --- a/scripts/plot_results.jl +++ b/scripts/plot_results.jl @@ -12,11 +12,23 @@ end function get_data(data, data_type) if data_type == :ascii - name = "chars per line" + name = "chars per line:" elseif data_type == :sgr - name = "chars with sgr per line" + name = "chars with sgr per line:" elseif data_type == :sgr_bg - name = "chars with sgr and bg per line" + name = "chars with sgr and bg per line:" + elseif data_type == :unicode + name = "unicode simple:" + elseif data_type == :diacritic + name = "unicode diacritic:" + elseif data_type == :diacritic_double + name = "unicode double diacritic:" + elseif data_type == :fire + name = "unicode fire:" + elseif data_type == :fire_text + name = "unicode fire as text:" + elseif data_type == :flag + name = "unicode flag:" end lines = [] @@ -38,7 +50,8 @@ end -function generate_for_terminal(file_name) +function generate_for_terminal(file_name, prefix="results_") + try terminal_name = split(file_name,"_")[1] fig = Figure() @@ -47,21 +60,25 @@ function generate_for_terminal(file_name) data = split(open(io->read(io, String), file_name), '\n') terminal_name = split(file_name,"_")[1] + markers = [:circle :rect :cross :star4 :start5 :star6 :diamond] + get_data_l = (type) -> get_data(data,type) - ascii_speed = get_data_l(:ascii) - sgr_speed = get_data_l(:sgr) - sgr_bg_speed = get_data_l(:sgr_bg) + speed = [ get_data_l(t) for t in types] marker_size = 8 - scatter!(ax,ascii_speed, label= terminal_name * "_ascii", marker = :circle, markersize = marker_size) - scatter!(ax,sgr_speed, label=terminal_name*"_sgr", marker = :rect, markersize = marker_size) - scatter!(ax,sgr_bg_speed, label=terminal_name*"_sgr_and_bg", marker = :cross, markersize = marker_size) + for (ind,dat) in enumerate(speed) + scatter!(ax,dat, label= terminal_name * "_" * string(types[ind]), marker = markers[ind], markersize = marker_size) + end axislegend(position = :rt) - save("results_"*terminal_name*".png", fig) + save(prefix*terminal_name*".png", fig) + catch e + println(e) + end end function generate_comparison(type) + try fig = Figure() ax = Axis(fig[1,1], title = "Comparison for "*string(type), xlabel = "Length of line", ylabel = "throughput, MB/s") @@ -69,17 +86,27 @@ function generate_comparison(type) insert_from_data(ax,"alacritty_results",:rect, type) insert_from_data(ax,"xterm_results",:cross, type) insert_from_data(ax,"kitty_results",:utriangle, type) + insert_from_data(ax,"wezterm_results",:diamond, type) axislegend(position = :lt) return fig + catch e + println(e) + end end - +types = [:ascii :sgr :sgr_bg ] generate_for_terminal("contour_results") generate_for_terminal("alacritty_results") generate_for_terminal("xterm_results") generate_for_terminal("kitty_results") - - -save("comparison_ascii.png", generate_comparison(:ascii)) -save("comparison_sgr.png", generate_comparison(:sgr)) -save("comparison_sgr_bg.png", generate_comparison(:sgr_bg)) +generate_for_terminal("wezterm_results") +types = [:unicode :fire :flag :diacritic :diacritic_double :fire_text] +generate_for_terminal_l = (n) -> generate_for_terminal(n, "results_unicode_") +generate_for_terminal_l("contour_results") +generate_for_terminal_l("alacritty_results") +generate_for_terminal_l("xterm_results") +generate_for_terminal_l("kitty_results") +generate_for_terminal_l("wezterm_results") + +types = [:ascii :sgr :sgr_bg :unicode :fire :fire_text :flag :diacritic :diacritic_double] +[ save("comparison_"*string(type)*".png", generate_comparison(type)) for type in types ] diff --git a/tb/main.cpp b/tb/main.cpp index a5b8d43..c8b1184 100644 --- a/tb/main.cpp +++ b/tb/main.cpp @@ -109,6 +109,16 @@ void chunkedWriteToStdout(char const* _data, size_t _size) #endif } +struct TestsToRun +{ + bool manyLines { true }; + bool longLines { true }; + bool sgrLines { true }; + bool sgrFgBgLines { true }; + bool binary { true }; + bool columnByColumn { false }; +}; + struct BenchSettings { TerminalSize requestedTerminalSize {}; @@ -116,9 +126,9 @@ struct BenchSettings bool nullSink = false; bool stdoutFastPath = false; std::vector craftedTests {}; - bool columnByColumn = false; std::string fileout {}; std::optional earlyExitCode = std::nullopt; + TestsToRun tests {}; }; BenchSettings parseArguments(int argc, char const* argv[], TerminalSize const& initialTerminalSize) @@ -133,7 +143,7 @@ BenchSettings parseArguments(int argc, char const* argv[], TerminalSize const& i } else if (argv[i] == "--fixed-size"sv) { - settings.requestedTerminalSize.columns = 200; + settings.requestedTerminalSize.columns = 100; settings.requestedTerminalSize.lines = 30; } else if (argv[i] == "--stdout-fastpath"sv) @@ -148,7 +158,12 @@ BenchSettings parseArguments(int argc, char const* argv[], TerminalSize const& i else if (argv[i] == "--column-by-column"sv) { cout << std::format("Enabling column-by-column tests.\n"); - settings.columnByColumn = true; + settings.tests.columnByColumn = true; + settings.tests.manyLines = false; + settings.tests.longLines = false; + settings.tests.sgrLines = false; + settings.tests.sgrFgBgLines = false; + settings.tests.binary = false; } else if (argv[i] == "--size"sv && i + 1 < argc) { @@ -201,12 +216,17 @@ std::string loadFileContents(std::filesystem::path const& path) bool addTestsToBenchmark(termbench::Benchmark& tb, BenchSettings const& settings) { - tb.add(termbench::tests::many_lines()); - tb.add(termbench::tests::long_lines()); - tb.add(termbench::tests::sgr_fg_lines()); - tb.add(termbench::tests::sgr_fgbg_lines()); - tb.add(termbench::tests::binary()); - // TODO: The above tests should also be configurable via command line (-mlfgb). + + if (settings.tests.manyLines) + tb.add(termbench::tests::many_lines()); + if (settings.tests.longLines) + tb.add(termbench::tests::long_lines()); + if (settings.tests.sgrLines) + tb.add(termbench::tests::sgr_fg_lines()); + if (settings.tests.sgrFgBgLines) + tb.add(termbench::tests::sgr_fgbg_lines()); + if (settings.tests.binary) + tb.add(termbench::tests::binary()); for (auto const& test: settings.craftedTests) { @@ -219,17 +239,25 @@ bool addTestsToBenchmark(termbench::Benchmark& tb, BenchSettings const& settings tb.add(termbench::tests::crafted(test.filename().string(), "", std::move(content))); } - if (settings.columnByColumn) + if (settings.tests.columnByColumn) { auto const maxColumns { settings.requestedTerminalSize.columns * 2u }; - for (size_t i = 0; i < maxColumns; ++i) - tb.add(termbench::tests::ascii_line(i)); - for (size_t i = 0; i < maxColumns; ++i) - tb.add(termbench::tests::sgr_line(i)); - for (size_t i = 0; i < maxColumns; ++i) - tb.add(termbench::tests::sgrbg_line(i)); - } + auto add_test = [&](auto&& test) { + for (size_t i = 0; i < maxColumns; ++i) + tb.add(std::invoke(test, i)); + }; + + add_test(termbench::tests::ascii_line); + add_test(termbench::tests::unicode_simple); + add_test(termbench::tests::unicode_two_codepoints); + add_test(termbench::tests::unicode_three_codepoints); + add_test(termbench::tests::unicode_fire_as_text); + add_test(termbench::tests::unicode_fire); + add_test(termbench::tests::unicode_flag); + add_test(termbench::tests::sgr_line); + add_test(termbench::tests::sgrbg_line); + } return true; }