From 39c917469a7d14769215a6a04e5eccce2a104e3e Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 15 Apr 2022 14:55:32 +0200 Subject: [PATCH 01/59] Added internal JSON alias type --- grapher/include/grapher/core.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grapher/include/grapher/core.hpp b/grapher/include/grapher/core.hpp index 4350ced..5daed72 100644 --- a/grapher/include/grapher/core.hpp +++ b/grapher/include/grapher/core.hpp @@ -11,6 +11,8 @@ namespace grapher { +using json_t = nlohmann::json; + /// Set of results for a benchmark case iteration of a given size. struct benchmark_iteration_t { /// Size of the benchmark instance From 97defd4e3a5c2b3d4b9818bec05b1830c97bbd12 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 15 Apr 2022 15:12:46 +0200 Subject: [PATCH 02/59] Updated code to use grapher::json_t alias type instead oh nlohmann::json --- grapher/grapher-plot.cpp | 2 +- grapher/include/grapher/plotters/compare.hpp | 4 +- grapher/include/grapher/plotters/debug.hpp | 4 +- .../grapher/plotters/grouped_histogram.hpp | 4 +- .../include/grapher/plotters/plotter_i.hpp | 12 ++--- grapher/include/grapher/plotters/stack.hpp | 4 +- grapher/include/grapher/predicates.hpp | 6 ++- grapher/include/grapher/utils/config.hpp | 14 +++--- grapher/include/grapher/utils/json.hpp | 16 +++---- grapher/include/grapher/utils/plot.hpp | 6 ++- grapher/lib/grapher/plotters/compare.cpp | 10 ++-- grapher/lib/grapher/plotters/debug.cpp | 6 +-- .../grapher/plotters/grouped_histogram.cpp | 4 +- grapher/lib/grapher/plotters/stack.cpp | 12 ++--- grapher/lib/grapher/predicates.cpp | 48 +++++++++---------- grapher/lib/grapher/utils/config.cpp | 22 ++++----- grapher/lib/grapher/utils/json.cpp | 16 +++---- grapher/lib/grapher/utils/plot.cpp | 6 +-- grapher/tests/grapher/utils/json.cpp | 38 +++++++-------- 19 files changed, 119 insertions(+), 115 deletions(-) diff --git a/grapher/grapher-plot.cpp b/grapher/grapher-plot.cpp index 411122f..3ebabd4 100644 --- a/grapher/grapher-plot.cpp +++ b/grapher/grapher-plot.cpp @@ -28,7 +28,7 @@ int main(int argc, char const *argv[]) { llvm::cl::ParseCommandLineOptions(argc, argv); // Get configed - nlohmann::json config; + grapher::json_t config; { std::ifstream config_file(cli::config_opt.getValue()); if (!config_file) { diff --git a/grapher/include/grapher/plotters/compare.hpp b/grapher/include/grapher/plotters/compare.hpp index 125f690..9813abf 100644 --- a/grapher/include/grapher/plotters/compare.hpp +++ b/grapher/include/grapher/plotters/compare.hpp @@ -8,11 +8,11 @@ namespace grapher::plotters { struct plotter_compare_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const override; + grapher::json_t const &config) const override; std::string_view get_help() const override; - nlohmann::json get_default_config() const override; + grapher::json_t get_default_config() const override; }; } // namespace grapher::plotters diff --git a/grapher/include/grapher/plotters/debug.hpp b/grapher/include/grapher/plotters/debug.hpp index f8c02d1..20c6532 100644 --- a/grapher/include/grapher/plotters/debug.hpp +++ b/grapher/include/grapher/plotters/debug.hpp @@ -8,11 +8,11 @@ namespace grapher::plotters { /// Debug plotter, outputs statistics on benchmark categories struct plotter_debug_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const override; + grapher::json_t const &config) const override; std::string_view get_help() const override; - nlohmann::json get_default_config() const override; + grapher::json_t get_default_config() const override; }; } // namespace grapher::plotters diff --git a/grapher/include/grapher/plotters/grouped_histogram.hpp b/grapher/include/grapher/plotters/grouped_histogram.hpp index b7451d0..a458443 100644 --- a/grapher/include/grapher/plotters/grouped_histogram.hpp +++ b/grapher/include/grapher/plotters/grouped_histogram.hpp @@ -8,11 +8,11 @@ namespace grapher::plotters { /// Display bars struct plotter_grouped_histogram_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const override; + grapher::json_t const &config) const override; std::string_view get_help() const override; - nlohmann::json get_default_config() const override; + grapher::json_t get_default_config() const override; }; } // namespace grapher::plotters diff --git a/grapher/include/grapher/plotters/plotter_i.hpp b/grapher/include/grapher/plotters/plotter_i.hpp index 8a018a2..14fab28 100644 --- a/grapher/include/grapher/plotters/plotter_i.hpp +++ b/grapher/include/grapher/plotters/plotter_i.hpp @@ -17,7 +17,7 @@ namespace grapher { /// plotter_i::get_default_config methods. /// /// They're used to generate plots from a grapher::category_t object and a -/// nlohmann::json object for configuration. +/// grapher::json_t object for configuration. /// /// The plotter interface can also be used to implement other exportation modes /// such as CSV, plain text, debug, or even HTML export if you want. @@ -25,23 +25,23 @@ namespace grapher { /// \ingroup plotters /// Interface for plotters. Plotters should be able to: -/// - Plot a ctbench::category_t with a nlohmann::json configuration object, +/// - Plot a ctbench::category_t with a grapher::json_t configuration object, /// - Output help as a std::string_view, -/// - Output a default config as a nlohmann::json object. +/// - Output a default config as a grapher::json_t object. struct plotter_i { virtual ~plotter_i() = default; /// Plots a given ctbench::category_t at the given destination. - /// It receives a nlohmann::json object as a config. + /// It receives a grapher::json_t object as a config. virtual void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const = 0; + grapher::json_t const &config) const = 0; /// Returns a help message for end-users. virtual std::string_view get_help() const = 0; /// Returns a default config for end-users. - virtual nlohmann::json get_default_config() const = 0; + virtual grapher::json_t get_default_config() const = 0; }; /// Polymorphic representation of a plotter. diff --git a/grapher/include/grapher/plotters/stack.hpp b/grapher/include/grapher/plotters/stack.hpp index ebc246b..a58f565 100644 --- a/grapher/include/grapher/plotters/stack.hpp +++ b/grapher/include/grapher/plotters/stack.hpp @@ -10,11 +10,11 @@ namespace grapher::plotters { /// visualized as stacked curves. struct plotter_stack_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const override; + grapher::json_t const &config) const override; std::string_view get_help() const override; - nlohmann::json get_default_config() const override; + grapher::json_t get_default_config() const override; }; } // namespace grapher::plotters diff --git a/grapher/include/grapher/predicates.hpp b/grapher/include/grapher/predicates.hpp index 9b56ec5..6c0f01b 100644 --- a/grapher/include/grapher/predicates.hpp +++ b/grapher/include/grapher/predicates.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -11,10 +13,10 @@ namespace grapher { /// \ingroup predicates /// Dynamic representation of a predicate. -using predicate_t = std::function; +using predicate_t = std::function; /// \ingroup predicates /// Builds predicate and stores it in an std::function object. -predicate_t get_predicate(nlohmann::json const &constraint); +predicate_t get_predicate(grapher::json_t const &constraint); } // namespace grapher diff --git a/grapher/include/grapher/utils/config.hpp b/grapher/include/grapher/utils/config.hpp index 42d5fe4..d0d0d5c 100644 --- a/grapher/include/grapher/utils/config.hpp +++ b/grapher/include/grapher/utils/config.hpp @@ -15,25 +15,25 @@ namespace grapher { /// Named set of constraint. struct group_descriptor_t { std::string name; - std::vector predicates; + std::vector predicates; }; group_descriptor_t get_default_group_descriptor(); std::vector get_predicates(group_descriptor_t const &descriptor); -std::vector +std::vector extract_group(group_descriptor_t const &descriptor, - std::vector const &events); + std::vector const &events); -group_descriptor_t json_to_group_descriptor(nlohmann::json const &j); +group_descriptor_t json_to_group_descriptor(grapher::json_t const &j); -nlohmann::json group_descriptor_json(group_descriptor_t const &descriptor); +grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor); -std::vector +std::vector write_descriptors(std::vector const &descriptors); std::vector -read_descriptors(std::vector const &list); +read_descriptors(std::vector const &list); } // namespace grapher diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 3f432cb..42cb8e3 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -18,22 +18,22 @@ namespace grapher { /// value_jptr in the events matching the descriptor's predicates. std::vector get_values(benchmark_iteration_t const &iteration, std::vector const &predicates, - nlohmann::json::json_pointer value_jptr); + grapher::json_t::json_pointer value_jptr); /// Merges the contents of b into a, with items of a being overwritten if items /// present in b share the same key. -nlohmann::json merge_into(nlohmann::json a, nlohmann::json const &b); +grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b); /// Wrapper for strict JSON type error management. /// Exits program if value at given field location is empty or isn't of the /// right type. template -inline ValueType json_value(nlohmann::json const &object, +inline ValueType json_value(grapher::json_t const &object, LocType const &field_location, const std::experimental::source_location loc = std::experimental::source_location::current()) { - // nlohmann::json - if constexpr (std::is_same::value) { + // grapher::json_t + if constexpr (std::is_same::value) { if (!object.contains(field_location)) { llvm::errs() << loc.function_name() << " - Empty field " << field_location << ":\n" @@ -57,13 +57,13 @@ inline ValueType json_value(nlohmann::json const &object, } } - // std::vector - if constexpr (std::is_same, ValueType>::value) { + // std::vector + if constexpr (std::is_same, ValueType>::value) { if (!object.contains(field_location) || !object[field_location].is_array()) { llvm::errs() << loc.function_name() << " - Invalid field " << field_location - << ", expected std::vector:\n" + << ", expected std::vector:\n" << object.dump(2) << '\n'; std::exit(1); } else { diff --git a/grapher/include/grapher/utils/plot.hpp b/grapher/include/grapher/utils/plot.hpp index 2ef87a1..909b028 100644 --- a/grapher/include/grapher/utils/plot.hpp +++ b/grapher/include/grapher/utils/plot.hpp @@ -4,12 +4,14 @@ #include +#include "grapher/core.hpp" + namespace grapher { /// Apply config to plot. -sciplot::Plot &apply_config(sciplot::Plot &plot, nlohmann::json config); +sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config); /// Returns the default configuration for apply_config. -nlohmann::json base_default_config(); +grapher::json_t base_default_config(); } // namespace grapher diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 0bb11bf..8a0a4b4 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -23,8 +23,8 @@ std::string_view plotter_compare_t::get_help() const { "benchmark cases in the set."; } -nlohmann::json plotter_compare_t::get_default_config() const { - nlohmann::json res = grapher::base_default_config(); +grapher::json_t plotter_compare_t::get_default_config() const { + grapher::json_t res = grapher::base_default_config(); res["plotter"] = "compare"; @@ -42,10 +42,10 @@ nlohmann::json plotter_compare_t::get_default_config() const { void plotter_compare_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const { + grapher::json_t const &config) const { // Config - nlohmann::json::json_pointer value_json_pointer( + grapher::json_t::json_pointer value_json_pointer( json_value(config, "value_json_pointer")); bool draw_average = config.value("draw_average", true); @@ -54,7 +54,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, std::string plot_file_extension = config.value("plot_file_extension", ".svg"); std::vector group_descriptors = read_descriptors( - json_value>(config, "group_descriptors")); + json_value>(config, "group_descriptors")); // Drawing diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index 83d8273..f875911 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -10,15 +10,15 @@ std::string_view plotter_debug_t::get_help() const { "debug category building or traversal issues."; } -nlohmann::json plotter_debug_t::get_default_config() const { - nlohmann::json res; +grapher::json_t plotter_debug_t::get_default_config() const { + grapher::json_t res; res["plotter"] = "debug"; return res; } void plotter_debug_t::plot(const benchmark_set_t &bset, const std::filesystem::path &dest, - const nlohmann::json & /* config */) const { + const grapher::json_t & /* config */) const { llvm::outs() << "Output path: " << dest << '\n'; llvm::outs() << "Category size: " << bset.size() << '\n'; diff --git a/grapher/lib/grapher/plotters/grouped_histogram.cpp b/grapher/lib/grapher/plotters/grouped_histogram.cpp index 9db7c1c..8be36a2 100644 --- a/grapher/lib/grapher/plotters/grouped_histogram.cpp +++ b/grapher/lib/grapher/plotters/grouped_histogram.cpp @@ -12,7 +12,7 @@ std::string_view plotter_grouped_histogram_t::get_help() const { return "TODO"; } -nlohmann::json plotter_grouped_histogram_t::get_default_config() const { +grapher::json_t plotter_grouped_histogram_t::get_default_config() const { // TODO return grapher::base_default_config(); } @@ -20,7 +20,7 @@ nlohmann::json plotter_grouped_histogram_t::get_default_config() const { void plotter_grouped_histogram_t::plot( const benchmark_set_t & /* bset */, const std::filesystem::path & /* dest */, - const nlohmann::json & /* config */) const { + const grapher::json_t & /* config */) const { // TODO } diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 9169a25..603cc93 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -23,8 +23,8 @@ std::string_view plotter_stack_t::get_help() const { "field."; } -nlohmann::json plotter_stack_t::get_default_config() const { - nlohmann::json res = grapher::base_default_config(); +grapher::json_t plotter_stack_t::get_default_config() const { + grapher::json_t res = grapher::base_default_config(); res["plotter"] = "stack"; @@ -42,19 +42,19 @@ nlohmann::json plotter_stack_t::get_default_config() const { void plotter_stack_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, - nlohmann::json const &config) const { + grapher::json_t const &config) const { // Config - nlohmann::json::json_pointer feature_value_jptr( + grapher::json_t::json_pointer feature_value_jptr( config.value("value_json_pointer", "/dur")); - nlohmann::json::json_pointer feature_name_jptr( + grapher::json_t::json_pointer feature_name_jptr( config.value("name_json_pointer", "/name")); std::string plot_file_extension = config.value("plot_file_extension", ".svg"); std::vector descriptors = read_descriptors( - json_value>(config, "group_descriptors")); + json_value>(config, "group_descriptors")); // Drawing diff --git a/grapher/lib/grapher/predicates.cpp b/grapher/lib/grapher/predicates.cpp index ea31369..930d02a 100644 --- a/grapher/lib/grapher/predicates.cpp +++ b/grapher/lib/grapher/predicates.cpp @@ -23,12 +23,12 @@ namespace grapher::predicates { /// "regex": "Total*" /// } /// ``` -inline auto regex(nlohmann::json const &constraint) { +inline auto regex(grapher::json_t const &constraint) { // Validating pointer parameter - return [pointer = nlohmann::json::json_pointer{json_value( + return [pointer = grapher::json_t::json_pointer{json_value( constraint, "pointer")}, regex = std::regex(json_value(constraint, "regex"))]( - nlohmann::json const &value) -> bool { + grapher::json_t const &value) -> bool { if (!value.contains(pointer) || !value[pointer].is_string()) { return false; } @@ -77,17 +77,17 @@ inline auto regex(nlohmann::json const &constraint) { /// } /// } /// ``` -inline auto match(nlohmann::json const &constraint) { +inline auto match(grapher::json_t const &constraint) { return [matcher_flat = - json_value(constraint, "matcher").flatten(), + json_value(constraint, "matcher").flatten(), regex_match_opt = constraint.value("regex", false)]( - nlohmann::json const &value) -> bool { + grapher::json_t const &value) -> bool { auto items_iteration_proxy = matcher_flat.items(); return std::all_of( items_iteration_proxy.begin(), items_iteration_proxy.end(), [&](auto const &matcher_item_kv) -> bool { // Pointer to the value we should observe - nlohmann::json::json_pointer const ptr(matcher_item_kv.key()); + grapher::json_t::json_pointer const ptr(matcher_item_kv.key()); // Checking for existence of matching value if (!value.contains(ptr)) { @@ -117,16 +117,16 @@ inline auto match(nlohmann::json const &constraint) { /// "string": "Total Source" /// } /// ``` -inline auto streq(nlohmann::json const &constraint) { - return [pointer = nlohmann::json::json_pointer{json_value( +inline auto streq(grapher::json_t const &constraint) { + return [pointer = grapher::json_t::json_pointer{json_value( constraint, "pointer")}, str = json_value(constraint, "string")]( - nlohmann::json const &value) -> bool { + grapher::json_t const &value) -> bool { if (!value.contains(pointer) || !value[pointer].is_string()) { return false; } - return value[pointer].get_ref() == str; + return value[pointer].get_ref() == str; }; } @@ -152,11 +152,11 @@ inline auto streq(nlohmann::json const &constraint) { /// } /// } /// ``` -inline auto op_or(nlohmann::json const &constraint) { +inline auto op_or(grapher::json_t const &constraint) { return - [first = get_predicate(json_value(constraint, "first")), - second = get_predicate(json_value( - constraint, "second"))](nlohmann::json const &value) -> bool { + [first = get_predicate(json_value(constraint, "first")), + second = get_predicate(json_value( + constraint, "second"))](grapher::json_t const &value) -> bool { return first(value) || second(value); }; } @@ -182,11 +182,11 @@ inline auto op_or(nlohmann::json const &constraint) { /// } /// } /// ``` -inline auto op_and(nlohmann::json const &constraint) { +inline auto op_and(grapher::json_t const &constraint) { return - [first = get_predicate(json_value(constraint, "first")), - second = get_predicate(json_value( - constraint, "second"))](nlohmann::json const &value) -> bool { + [first = get_predicate(json_value(constraint, "first")), + second = get_predicate(json_value( + constraint, "second"))](grapher::json_t const &value) -> bool { return first(value) && second(value); }; } @@ -200,8 +200,8 @@ inline auto op_and(nlohmann::json const &constraint) { /// "type": "val_true", /// } /// ``` -inline auto val_true(nlohmann::json const & /* unused */) { - return [](nlohmann::json const &) -> bool { return true; }; +inline auto val_true(grapher::json_t const & /* unused */) { + return [](grapher::json_t const &) -> bool { return true; }; } /// \ingroup predicates @@ -213,8 +213,8 @@ inline auto val_true(nlohmann::json const & /* unused */) { /// "type": "val_false", /// } /// ``` -inline auto val_false(nlohmann::json const & /* unused */) { - return [](nlohmann::json const &) -> bool { return false; }; +inline auto val_false(grapher::json_t const & /* unused */) { + return [](grapher::json_t const &) -> bool { return false; }; } } // namespace grapher::predicates @@ -223,7 +223,7 @@ namespace grapher { /// \ingroup predicates /// Builds predicate and stores it in an std::function object. -predicate_t get_predicate(nlohmann::json const &constraint) { +predicate_t get_predicate(grapher::json_t const &constraint) { std::string constraint_type = json_value(constraint, "type"); #define REGISTER_PREDICATE(name) \ diff --git a/grapher/lib/grapher/utils/config.cpp b/grapher/lib/grapher/utils/config.cpp index c5af597..15177c0 100644 --- a/grapher/lib/grapher/utils/config.cpp +++ b/grapher/lib/grapher/utils/config.cpp @@ -17,7 +17,7 @@ namespace grapher { group_descriptor_t get_default_group_descriptor() { return {.name = "All", - .predicates = nlohmann::json::array({nlohmann::json{ + .predicates = grapher::json_t::array({grapher::json_t{ {"type", "regex"}, {"pointer", "/name"}, {"regex", "*"}, @@ -33,15 +33,15 @@ std::vector get_predicates(group_descriptor_t const &descriptor) { return predicates; } -std::vector +std::vector extract_group(group_descriptor_t const &descriptor, - std::vector const &events) { + std::vector const &events) { std::vector predicates = get_predicates(descriptor); - std::vector res; + std::vector res; std::ranges::copy_if( - events, std::back_inserter(res), [&](nlohmann::json const &event) { + events, std::back_inserter(res), [&](grapher::json_t const &event) { return std::ranges::all_of( predicates, [&](predicate_t const &p) { return p(event); }); }); @@ -49,21 +49,21 @@ extract_group(group_descriptor_t const &descriptor, return res; } -group_descriptor_t json_to_group_descriptor(nlohmann::json const &j) { +group_descriptor_t json_to_group_descriptor(grapher::json_t const &j) { return {.name = json_value(j, "name"), .predicates = - json_value>(j, "predicates")}; + json_value>(j, "predicates")}; } -nlohmann::json group_descriptor_json(group_descriptor_t const &descriptor) { +grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor) { return { {"name", descriptor.name}, {"predicates", descriptor.predicates}, }; } -std::vector +std::vector write_descriptors(std::vector const &descriptors) { - std::vector res; + std::vector res; res.reserve(descriptors.size()); for (group_descriptor_t const &d : descriptors) { @@ -73,7 +73,7 @@ write_descriptors(std::vector const &descriptors) { } std::vector -read_descriptors(std::vector const &list) { +read_descriptors(std::vector const &list) { std::vector res; res.reserve(list.size()); std::transform(list.begin(), list.end(), std::back_inserter(res), diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index b774a31..a2e644e 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -12,12 +12,12 @@ namespace grapher { std::vector get_values(benchmark_iteration_t const &iteration, std::vector const &predicates, - nlohmann::json::json_pointer value_jptr) { + grapher::json_t::json_pointer value_jptr) { std::vector res(iteration.samples.size()); auto get_val = [&](std::filesystem::path const &repetition_path) -> double { // Extract events - nlohmann::json j; + grapher::json_t j; { std::ifstream repetition_ifstream(repetition_path); repetition_ifstream >> j; @@ -28,12 +28,12 @@ std::vector get_values(benchmark_iteration_t const &iteration, return 0.; } - nlohmann::json::array_t const &events = - j["traceEvents"].get_ref(); + grapher::json_t::array_t const &events = + j["traceEvents"].get_ref(); // Accumulate double val = 0.; - for (nlohmann::json const &event : events) { + for (grapher::json_t const &event : events) { if (std::all_of(predicates.begin(), predicates.end(), [&](predicate_t const &p) -> bool { return p(event); })) { val += json_value(event, value_jptr); @@ -48,10 +48,10 @@ std::vector get_values(benchmark_iteration_t const &iteration, return res; } -nlohmann::json merge_into(nlohmann::json a, nlohmann::json const &b) { - for (nlohmann::json const b_flat = b.flatten(); +grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b) { + for (grapher::json_t const b_flat = b.flatten(); auto const &[k_ptr, v] : b_flat.items()) { - a[nlohmann::json::json_pointer(k_ptr)] = v; + a[grapher::json_t::json_pointer(k_ptr)] = v; } return a; } diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index 756cd12..eca1363 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -8,7 +8,7 @@ namespace grapher { /// Default config file for plots -nlohmann::json const default_config = { +grapher::json_t const default_config = { {"width", 1500}, {"height", 500}, {"legend_title", "Timings"}, @@ -16,7 +16,7 @@ nlohmann::json const default_config = { {"ylabel", "Time (µs)"}, }; -sciplot::Plot &apply_config(sciplot::Plot &plot, nlohmann::json config) { +sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { // Dimensions if (config.contains("width") && config.contains("height")) { plot.size(config["width"], config["height"]); @@ -38,6 +38,6 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, nlohmann::json config) { return plot; } -nlohmann::json base_default_config() { return default_config; } +grapher::json_t base_default_config() { return default_config; } } // namespace grapher diff --git a/grapher/tests/grapher/utils/json.cpp b/grapher/tests/grapher/utils/json.cpp index e852aa5..dc4b43a 100644 --- a/grapher/tests/grapher/utils/json.cpp +++ b/grapher/tests/grapher/utils/json.cpp @@ -6,17 +6,17 @@ /* TTS_CASE("find_matching - Basic") { - nlohmann::json json_a = {{"a", 42}}; - nlohmann::json json_b = {{"b", 42}}; - nlohmann::json json_c = {{"c", "42"}}; + grapher::json_t json_a = {{"a", 42}}; + grapher::json_t json_b = {{"b", 42}}; + grapher::json_t json_c = {{"c", "42"}}; - nlohmann::json json_ac = {{"a", 42}, {"c", "42"}}; - nlohmann::json json_bc = {{"b", 42}, {"c", "42"}}; + grapher::json_t json_ac = {{"a", 42}, {"c", "42"}}; + grapher::json_t json_bc = {{"b", 42}, {"c", "42"}}; - nlohmann::json json_d = {{"d", 42}}; - nlohmann::json json_ab = {{"a", 42}, {"b", 42}}; + grapher::json_t json_d = {{"d", 42}}; + grapher::json_t json_ab = {{"a", 42}, {"b", 42}}; - nlohmann::json json_ac_bc; + grapher::json_t json_ac_bc; json_ac_bc.push_back(json_ac); json_ac_bc.push_back(json_bc); @@ -55,18 +55,18 @@ TTS_CASE("find_matching - Basic") { }; TTS_CASE("find_matching - Imbricated JSON") { - nlohmann::json json_a = {{"a", 42}}; - nlohmann::json json_b = {{"b", 42}}; - nlohmann::json json_c = {{"c", "42"}}; + grapher::json_t json_a = {{"a", 42}}; + grapher::json_t json_b = {{"b", 42}}; + grapher::json_t json_c = {{"c", "42"}}; - nlohmann::json json_jsonc = {{"json_c", json_c}}; + grapher::json_t json_jsonc = {{"json_c", json_c}}; - nlohmann::json json_ab_jsonc = {{"a", 42}, {"b", 42}, {"json_c", json_c}}; - nlohmann::json json_a_jsonc = {{"a", 42}, {"json_c", json_c}}; - nlohmann::json json_b_jsonc = {{"b", 42}, {"json_c", json_c}}; + grapher::json_t json_ab_jsonc = {{"a", 42}, {"b", 42}, {"json_c", json_c}}; + grapher::json_t json_a_jsonc = {{"a", 42}, {"json_c", json_c}}; + grapher::json_t json_b_jsonc = {{"b", 42}, {"json_c", json_c}}; { - nlohmann::json list; + grapher::json_t list; list.push_back(json_a); list.push_back(json_b); @@ -85,7 +85,7 @@ TTS_CASE("find_matching - Imbricated JSON") { } { - nlohmann::json list; + grapher::json_t list; list.push_back(json_a); list.push_back(json_a_jsonc); @@ -103,7 +103,7 @@ TTS_CASE("find_matching - Imbricated JSON") { } { - nlohmann::json list; + grapher::json_t list; list.push_back(json_a); list.push_back(json_b); @@ -120,7 +120,7 @@ TTS_CASE("find_matching - Imbricated JSON") { }; TTS_CASE("merge_into - Basic") { - nlohmann::json a, b; + grapher::json_t a, b; a["a"] = 0; a["b"] = 0; From c7f763dd6f805f37f2c1d83fee86b85f3c697ba6 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 15 Apr 2022 17:01:11 +0200 Subject: [PATCH 03/59] Using boost::container::flat_map instead of std::map for JSON objects yielding a ~10% performance improvement --- grapher/include/grapher/core.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/grapher/include/grapher/core.hpp b/grapher/include/grapher/core.hpp index 5daed72..d710990 100644 --- a/grapher/include/grapher/core.hpp +++ b/grapher/include/grapher/core.hpp @@ -5,13 +5,21 @@ #include #include -#include #include +#include + namespace grapher { -using json_t = nlohmann::json; +/// Alias type for JSON objects. +using json_t = nlohmann::basic_json; + +// `time cmake --build --preset bench` results using different containers +// (poacher/brainfuck project, pre-built benchmark targets): +// - boost::container::flat_map -> 78.05 secs +// - std::map -> 87.08 secs +// - boost::container::map -> 80.16 secs /// Set of results for a benchmark case iteration of a given size. struct benchmark_iteration_t { From d5d0614cedf91b367aade8dc8b67760950a942ca Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 19 Apr 2022 09:35:27 +0200 Subject: [PATCH 04/59] Added reference to CPPP 2021 presentation --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index e02f8a1..fe7f92c 100644 --- a/readme.md +++ b/readme.md @@ -173,5 +173,8 @@ per benchmark case. In this case, you would then get 3 graphs ## Additional +- [ctbench: compile time benchmarking for Clang]( + https://www.youtube.com/watch?v=1RZY6skM0Rc) at [CPPP 2021]( + https://cppp.fr/schedule2021/) - [Pyperf - Tune the system for benchmarks]( https://pyperf.readthedocs.io/en/latest/system.html) From 039942bb402a7fc4aec2ca1c86740e68dfa0b90d Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 19 Apr 2022 09:39:06 +0200 Subject: [PATCH 05/59] Patch version bump --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2111e2c..e98fd4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -project(ctbench VERSION 0.0.1) +project(ctbench VERSION 0.0.2) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) From dc7e5485344788a521f040cc290e06a3f94514c0 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 19 Apr 2022 10:51:10 +0200 Subject: [PATCH 06/59] Fix readme link to example configs --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index fe7f92c..0390b39 100644 --- a/readme.md +++ b/readme.md @@ -97,7 +97,8 @@ ctbench_add_benchmark(function_selection.requires # Benchmark case name Once you have several benchmark cases, you can start writing a graph config. -Example configs can be found [here](./grapher/configs/), or by running +Example configs can be found [here]( +https://github.com/JPenuchot/ctbench/tree/main/grapher/configs), or by running `ctbench-grapher-utils --plotter= --command=get-default-config`. ```json From 055ed66b1053fae6a8a2646b69867e3433833f6b Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 27 Apr 2022 17:07:26 +0200 Subject: [PATCH 07/59] Added error management code --- grapher/include/grapher/utils/error.hpp | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 grapher/include/grapher/utils/error.hpp diff --git a/grapher/include/grapher/utils/error.hpp b/grapher/include/grapher/utils/error.hpp new file mode 100644 index 0000000..03ca453 --- /dev/null +++ b/grapher/include/grapher/utils/error.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +namespace grapher { + +enum error_level_t : std::uint8_t { error_v, warning_v, info_v }; + +inline std::string to_string(error_level_t error_level) { + switch (error_level) { + case error_v: + return "ERROR"; + case warning_v: + return "WARNING"; + case info_v: + return "INFO"; + } +} + +/// Prints a warning +inline void warn(std::string_view explain, + error_level_t error_level = warning_v, + std::experimental::source_location loc = + std::experimental::source_location::current()) { + llvm::errs() << fmt::format("{} {}, {}:{}:{} - {}\n", to_string(error_level), + loc.file_name(), loc.function_name(), loc.line(), + loc.column(), explain); +} + +/// Error management: if the condition is false, it will print a warning or +/// error message and termineate the program if error_level is error_v. +inline void check(bool condition, std::string_view explain, + error_level_t error_level = error_v, int err_code = -1, + std::experimental::source_location loc = + std::experimental::source_location::current()) { + if (!condition) { + warn(explain, error_level, loc); + if (error_level) { + std::exit(err_code); + } + } +} + +} // namespace grapher From ebb0e2adac1c7c6175d4185d67849efa81e2f920 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 27 Apr 2022 17:07:41 +0200 Subject: [PATCH 08/59] Linking against fmt --- grapher/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grapher/CMakeLists.txt b/grapher/CMakeLists.txt index 5f97847..5e91888 100644 --- a/grapher/CMakeLists.txt +++ b/grapher/CMakeLists.txt @@ -1,17 +1,19 @@ find_package(nlohmann_json 3.9.1 REQUIRED) find_package(sciplot REQUIRED) find_package(LLVM REQUIRED CONFIG) +find_package(fmt) # Declaring the grapher library file(GLOB_RECURSE GRAPHER_SOURCES lib/*.cpp) add_library(grapher STATIC ${GRAPHER_SOURCES}) + target_link_libraries(grapher PUBLIC ctbench-compile-opts) target_include_directories(grapher PUBLIC include) llvm_map_components_to_libnames(llvm_libs core support) target_link_libraries(grapher PUBLIC nlohmann_json::nlohmann_json - sciplot::sciplot stdc++fs tbb ${llvm_libs}) + sciplot::sciplot stdc++fs tbb fmt::fmt ${llvm_libs}) target_compile_options(grapher PUBLIC -DJSON_NOEXCEPTION) From 720f6bf0736193d45e255103994134447f025bb9 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 27 Apr 2022 17:09:34 +0200 Subject: [PATCH 09/59] Error management cleanup thanks to new check() and warn() functions --- grapher/include/grapher/utils/json.hpp | 111 ++++++++++------------- grapher/lib/grapher/plotters/compare.cpp | 24 ++--- grapher/lib/grapher/plotters/stack.cpp | 15 ++- grapher/lib/grapher/predicates.cpp | 19 ++-- grapher/lib/grapher/utils/cli.cpp | 23 ++--- 5 files changed, 91 insertions(+), 101 deletions(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 42cb8e3..9d51501 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -7,10 +7,11 @@ #include -#include +#include #include "grapher/core.hpp" #include "grapher/utils/config.hpp" +#include "grapher/utils/error.hpp" namespace grapher { @@ -32,82 +33,68 @@ inline ValueType json_value(grapher::json_t const &object, LocType const &field_location, const std::experimental::source_location loc = std::experimental::source_location::current()) { - // grapher::json_t - if constexpr (std::is_same::value) { - if (!object.contains(field_location)) { - llvm::errs() << loc.function_name() << " - Empty field " << field_location - << ":\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } - } + std::string const field_location_str = field_location; + + check(object.contains(field_location), + fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), + error_v, -1, loc); // std::string if constexpr (std::is_same::value) { - if (!object.contains(field_location) || - !object[field_location].is_string()) { - llvm::errs() << loc.function_name() << " - Invalid field " - << field_location << ", expected string:\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } + check(object[field_location].is_string(), + fmt::format("Invalid field {}, expected string:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; } // std::vector - if constexpr (std::is_same, ValueType>::value) { - if (!object.contains(field_location) || - !object[field_location].is_array()) { - llvm::errs() << loc.function_name() << " - Invalid field " - << field_location - << ", expected std::vector:\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } + else if constexpr (std::is_same, + ValueType>::value) { + check(object[field_location].is_array(), + fmt::format( + "Invalid field {}, expected std::vector:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; } // bool - if constexpr (std::is_same::value) { - if (!object.contains(field_location) || - !object[field_location].is_boolean()) { - llvm::errs() << loc.function_name() << " - Invalid field " - << field_location << ", expected bool:\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } + else if constexpr (std::is_same::value) { + check(object.contains(field_location) && + object[field_location].is_boolean(), + fmt::format("Invalid field {}, expected bool:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; } // int - if constexpr (std::is_same::value) { - if (!object.contains(field_location) || - !object[field_location].is_number()) { - llvm::errs() << loc.function_name() << " - Invalid field " - << field_location << ", expected number:\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } + else if constexpr (std::is_same::value) { + check(object[field_location].is_number(), + fmt::format("Invalid field {}, expected number:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; } // double - if constexpr (std::is_same::value) { - if (!object.contains(field_location) || - !object[field_location].is_number()) { - llvm::errs() << loc.function_name() << " - Invalid field " - << field_location << ", expected number:\n" - << object.dump(2) << '\n'; - std::exit(1); - } else { - return object[field_location]; - } + else if constexpr (std::is_same::value) { + check(object[field_location].is_number(), + fmt::format("Invalid field {}, expected number:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; + } + + // Anything else + else { + return object[field_location]; } } diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 8a0a4b4..337077d 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include @@ -13,6 +15,7 @@ #include "grapher/plotters/compare.hpp" #include "grapher/predicates.hpp" #include "grapher/utils/config.hpp" +#include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" #include "grapher/utils/plot.hpp" @@ -74,22 +77,19 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, std::vector y_average; for (benchmark_iteration_t const &iteration : bench.iterations) { - if (iteration.samples.empty()) { - llvm::errs() << "[WARNING] No data in benchmark " << bench.name - << " for iteration size " << iteration.size << "\n"; - continue; - } + check(!iteration.samples.empty(), + fmt::format("No data in benchmark {} for iteration size {}.", + bench.name, iteration.size), + error_level_t::warning_v); std::vector const values = get_values(iteration, predicates, value_json_pointer); - if (values.empty()) { - llvm::errs() << "[WARNING] No event in benchmark " << bench.name - << " at size " << iteration.size - << " matched by group descriptor " << descriptor.name - << ".\n"; - continue; - } + check(!values.empty(), + fmt::format("No event in benchmark {} at size {} matched by " + "group descriptor {}.\n", + bench.name, iteration.size, descriptor.name), + error_level_t::warning_v); // Drawing points if (draw_points) { diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 603cc93..372544a 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -1,17 +1,18 @@ #include #include +#include #include -#include +#include -#include #include #include "grapher/core.hpp" #include "grapher/plotters/stack.hpp" #include "grapher/predicates.hpp" #include "grapher/utils/config.hpp" +#include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" #include "grapher/utils/plot.hpp" @@ -92,12 +93,10 @@ void plotter_stack_t::plot(benchmark_set_t const &bset, std::vector const values = get_values(iteration, predicates, feature_value_jptr); - if (values.empty()) { - llvm::errs() << "[ERROR] No event matching descriptor " - << descriptor.name << " in benchmark " << bench.name - << " with iteration size " << iteration.size << ".\n"; - std::exit(1); - } + check(values.empty(), + fmt::format("No event matching descriptor {} in benchmark {} " + "with iteration size {}.\n", + descriptor.name, bench.name, iteration.size)); // TODO: Get better stats (standard deviation, etc...) double const y_val = diff --git a/grapher/lib/grapher/predicates.cpp b/grapher/lib/grapher/predicates.cpp index 930d02a..dbc028e 100644 --- a/grapher/lib/grapher/predicates.cpp +++ b/grapher/lib/grapher/predicates.cpp @@ -1,8 +1,4 @@ -#include "grapher/predicates.hpp" -#include "grapher/utils/json.hpp" - -#include -#include +#include #include #include @@ -10,6 +6,13 @@ #include +#include + +#include "grapher/core.hpp" +#include "grapher/predicates.hpp" +#include "grapher/utils/error.hpp" +#include "grapher/utils/json.hpp" + namespace grapher::predicates { /// \ingroup predicates @@ -241,9 +244,9 @@ predicate_t get_predicate(grapher::json_t const &constraint) { #undef REGISTER_PREDICATE - llvm::errs() << "[ERROR] Predicate error, invalid type:\n" - << constraint.dump(2) << '\n'; - std::exit(1); + check(false, + fmt::format("Predicate error, invalid type:\n{}", constraint.dump(2))); + return {}; } } // namespace grapher diff --git a/grapher/lib/grapher/utils/cli.cpp b/grapher/lib/grapher/utils/cli.cpp index 7bcdedb..33735a6 100644 --- a/grapher/lib/grapher/utils/cli.cpp +++ b/grapher/lib/grapher/utils/cli.cpp @@ -4,7 +4,10 @@ #include +#include + #include "grapher/utils/cli.hpp" +#include "grapher/utils/error.hpp" namespace grapher { @@ -18,8 +21,8 @@ build_category(llvm::cl::list const &benchmark_path_list) { fs::path bench_path(bench_path_str.data()); if (!fs::is_directory(bench_path)) { - llvm::errs() << "[WARNING] Not a directory: " << bench_path - << " (current path: " << fs::current_path() << ").\n"; + warn(fmt::format("Not a directory: {} (current path: {}).", + bench_path.string(), fs::current_path().string())); continue; } @@ -36,10 +39,9 @@ build_category(llvm::cl::list const &benchmark_path_list) { { std::istringstream iss(entry_dir.path().filename().stem()); if (!(iss >> iteration.size)) { - llvm::errs() << "[WARNING] Entry directory name is not a size: " - << entry_dir.path() - << " (current path: " << fs::current_path() << ").\n"; - + warn(fmt::format( + "Entry directory name is not a size: {} (current path: {}).", + entry_dir.path().string(), fs::current_path().string())); continue; } } @@ -50,11 +52,10 @@ build_category(llvm::cl::list const &benchmark_path_list) { // Basic property check if (!std::filesystem::is_regular_file(sample_path_entry)) { - llvm::errs() - << "[WARNING] Invalid repetition file (not a regular file): " - << sample_path_entry.path() - << " (current path: " << fs::current_path() << ").\n"; - + warn(fmt::format("Invalid repetition file (not a regular file): {} " + "(current path: {}).", + sample_path_entry.path().string(), + fs::current_path().string())); continue; } From e4bf5fabfbeed0bba04209add632bce23d83007c Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 27 Apr 2022 17:17:50 +0200 Subject: [PATCH 10/59] Slight refactoring --- grapher/lib/grapher/plotters/debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index f875911..245f005 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -19,8 +19,8 @@ grapher::json_t plotter_debug_t::get_default_config() const { void plotter_debug_t::plot(const benchmark_set_t &bset, const std::filesystem::path &dest, const grapher::json_t & /* config */) const { - llvm::outs() << "Output path: " << dest << '\n'; - llvm::outs() << "Category size: " << bset.size() << '\n'; + llvm::outs() << "Output path: " << dest << '\n' + << "Category size: " << bset.size() << '\n'; for (benchmark_case_t const &bench : bset) { llvm::outs() << "\tBenchmark case name: " << bench.name << '\n' From 30eb0233371c3af081e270b396b1af1784b155d4 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 5 May 2022 16:52:26 +0200 Subject: [PATCH 11/59] Improved json_value: reference support, better type handling (uses grapher::json_t::... for compile-time type comparisons) --- grapher/include/grapher/utils/json.hpp | 40 ++++++++++++-------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 9d51501..ce54902 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -25,22 +25,22 @@ std::vector get_values(benchmark_iteration_t const &iteration, /// present in b share the same key. grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b); -/// Wrapper for strict JSON type error management. -/// Exits program if value at given field location is empty or isn't of the -/// right type. -template -inline ValueType json_value(grapher::json_t const &object, - LocType const &field_location, - const std::experimental::source_location loc = - std::experimental::source_location::current()) { +/// Wraps value access with type checking and error reporting. +template +inline ReturnType +json_value(grapher::json_t const &object, LocType const &field_location, + const std::experimental::source_location loc = + std::experimental::source_location::current()) { + + using ValueType = std::decay_t; + std::string const field_location_str = field_location; check(object.contains(field_location), fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - // std::string - if constexpr (std::is_same::value) { + if constexpr (std::is_same::value) { check(object[field_location].is_string(), fmt::format("Invalid field {}, expected string:\n{}", field_location_str, object.dump(2)), @@ -49,20 +49,17 @@ inline ValueType json_value(grapher::json_t const &object, return object[field_location]; } - // std::vector - else if constexpr (std::is_same, - ValueType>::value) { + else if constexpr (std::is_same::value) { check(object[field_location].is_array(), - fmt::format( - "Invalid field {}, expected std::vector:\n{}", - field_location_str, object.dump(2)), + fmt::format("Invalid field {}, expected array:\n{}", + field_location_str, object.dump(2)), error_v, -1, loc); return object[field_location]; } - // bool - else if constexpr (std::is_same::value) { + else if constexpr (std::is_same::value) { check(object.contains(field_location) && object[field_location].is_boolean(), fmt::format("Invalid field {}, expected bool:\n{}", @@ -72,8 +69,8 @@ inline ValueType json_value(grapher::json_t const &object, return object[field_location]; } - // int - else if constexpr (std::is_same::value) { + else if constexpr (std::is_same::value) { check(object[field_location].is_number(), fmt::format("Invalid field {}, expected number:\n{}", field_location_str, object.dump(2)), @@ -83,7 +80,8 @@ inline ValueType json_value(grapher::json_t const &object, } // double - else if constexpr (std::is_same::value) { + else if constexpr (std::is_same::value) { check(object[field_location].is_number(), fmt::format("Invalid field {}, expected number:\n{}", field_location_str, object.dump(2)), From c7994170a449ca105c5f48dc06608bfeb7041f8d Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 5 May 2022 16:53:20 +0200 Subject: [PATCH 12/59] Removed unnecessary copies --- grapher/lib/grapher/plotters/compare.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 337077d..7a49abe 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -49,7 +49,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, // Config grapher::json_t::json_pointer value_json_pointer( - json_value(config, "value_json_pointer")); + json_value(config, "value_json_pointer")); bool draw_average = config.value("draw_average", true); bool draw_points = config.value("draw_points", true); @@ -57,7 +57,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, std::string plot_file_extension = config.value("plot_file_extension", ".svg"); std::vector group_descriptors = read_descriptors( - json_value>(config, "group_descriptors")); + json_value(config, "group_descriptors")); // Drawing From 6c6997bbdfaa3945593f8a38960ef475ea930928 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:21:20 +0200 Subject: [PATCH 13/59] Added new core types for maps and multimaps, based on boost containers --- grapher/include/grapher/core.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/grapher/include/grapher/core.hpp b/grapher/include/grapher/core.hpp index d710990..64a14f9 100644 --- a/grapher/include/grapher/core.hpp +++ b/grapher/include/grapher/core.hpp @@ -12,6 +12,17 @@ namespace grapher { +// Basic container types + +template > +using map_t = boost::container::flat_map; + +template > +using multimap_t = + boost::container::flat_multimap; + /// Alias type for JSON objects. using json_t = nlohmann::basic_json; From 007a3b02e238825527597703f103e9d1718af258 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:23:18 +0200 Subject: [PATCH 14/59] JSON value access improvements: refactoring, added support for more types, type checking conditions are more consistent. --- grapher/include/grapher/utils/json.hpp | 87 +++++++++++++++----------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index ce54902..2f3e68d 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -25,14 +25,29 @@ std::vector get_values(benchmark_iteration_t const &iteration, /// present in b share the same key. grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b); -/// Wraps value access with type checking and error reporting. -template -inline ReturnType -json_value(grapher::json_t const &object, LocType const &field_location, - const std::experimental::source_location loc = - std::experimental::source_location::current()) { +/// Wraps json_t object access with error management. +template +grapher::json_t::const_reference +json_at(grapher::json_t const &object, LocType const &field_location, + const std::experimental::source_location loc = + std::experimental::source_location::current()) { + std::string const field_location_str = field_location; - using ValueType = std::decay_t; + check(object.contains(field_location), + fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), + error_v, -1, loc); + + return object[field_location]; +} + +/// Wraps reference access with type checking and error management. +template +inline ReferenceType +json_at_ref(grapher::json_t const &object, LocType const &field_location, + const std::experimental::source_location loc = + std::experimental::source_location::current()) { + + using ValueType = std::decay_t; std::string const field_location_str = field_location; @@ -40,60 +55,60 @@ json_value(grapher::json_t const &object, LocType const &field_location, fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - if constexpr (std::is_same::value) { - check(object[field_location].is_string(), + // number_unsigned_t + if constexpr (std::is_same::value) { + check(object[field_location].type() == json_t::value_t::number_unsigned, fmt::format("Invalid field {}, expected string:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - - return object[field_location]; } - else if constexpr (std::is_same::value) { - check(object[field_location].is_array(), - fmt::format("Invalid field {}, expected array:\n{}", + // number_integer_t + else if constexpr (std::is_same::value) { + check(object[field_location].type() == json_t::value_t::number_integer, + fmt::format("Invalid field {}, expected number:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - - return object[field_location]; } - else if constexpr (std::is_same::value) { - check(object.contains(field_location) && - object[field_location].is_boolean(), - fmt::format("Invalid field {}, expected bool:\n{}", + check(object[field_location].type() == json_t::value_t::number_float, + fmt::format("Invalid field {}, expected number:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); + } - return object[field_location]; + // array_t + else if constexpr (std::is_same::value) { + check(object[field_location].type() == json_t::value_t::array, + fmt::format("Invalid field {}, expected array:\n{}", + field_location_str, object.dump(2)), + error_v, -1, loc); } - else if constexpr (std::is_same::value) { - check(object[field_location].is_number(), - fmt::format("Invalid field {}, expected number:\n{}", + check(object[field_location].type() == json_t::value_t::boolean, + fmt::format("Invalid field {}, expected bool:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - - return object[field_location]; } - // double - else if constexpr (std::is_same::value) { - check(object[field_location].is_number(), - fmt::format("Invalid field {}, expected number:\n{}", + check(object[field_location].type() == json_t::value_t::object, + fmt::format("Invalid field {}, expected JSON object:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); - - return object[field_location]; } - // Anything else - else { - return object[field_location]; - } + return object[field_location].template get_ref(); } } // namespace grapher From 5decd88649affb48e2f89fae6fbba876876d6982 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:26:49 +0200 Subject: [PATCH 15/59] Replaced JSON value and reference access with json_at and json_at_ref calls for more consistent and safer JSON reading --- grapher/grapher-plot.cpp | 3 +- grapher/include/grapher/utils/config.hpp | 21 +++++++---- grapher/lib/grapher/plotters/compare.cpp | 4 +- grapher/lib/grapher/plotters/stack.cpp | 2 +- grapher/lib/grapher/predicates.cpp | 47 ++++++++++++------------ grapher/lib/grapher/utils/config.cpp | 23 ++++++------ grapher/lib/grapher/utils/json.cpp | 3 +- 7 files changed, 56 insertions(+), 47 deletions(-) diff --git a/grapher/grapher-plot.cpp b/grapher/grapher-plot.cpp index 3ebabd4..7781ae3 100644 --- a/grapher/grapher-plot.cpp +++ b/grapher/grapher-plot.cpp @@ -47,7 +47,8 @@ int main(int argc, char const *argv[]) { // Acquire plotter grapher::plotter_t plotter = grapher::plotter_type_to_plotter(grapher::string_to_plotter_type( - grapher::json_value(config, "plotter"))); + grapher::json_at_ref(config, + "plotter"))); // Build cats grapher::benchmark_set_t bset = diff --git a/grapher/include/grapher/utils/config.hpp b/grapher/include/grapher/utils/config.hpp index d0d0d5c..8ee920f 100644 --- a/grapher/include/grapher/utils/config.hpp +++ b/grapher/include/grapher/utils/config.hpp @@ -15,25 +15,30 @@ namespace grapher { /// Named set of constraint. struct group_descriptor_t { std::string name; - std::vector predicates; + grapher::json_t::array_t predicates; }; +/// Returns a default group descriptor as an example. group_descriptor_t get_default_group_descriptor(); +/// Extracts predicates from a group descriptor. std::vector get_predicates(group_descriptor_t const &descriptor); -std::vector -extract_group(group_descriptor_t const &descriptor, - std::vector const &events); - -group_descriptor_t json_to_group_descriptor(grapher::json_t const &j); +grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, + grapher::json_t::array_t const &events); +/// Exports a single group descriptor into a JSON object. grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor); -std::vector +/// Exports a vector of group descriptors into a JSON object. +grapher::json_t::array_t write_descriptors(std::vector const &descriptors); +/// Reads a single descriptor. +group_descriptor_t read_descriptor(grapher::json_t const &j); + +/// Reads descriptors from a predicate list. std::vector -read_descriptors(std::vector const &list); +read_descriptors(grapher::json_t::array_t const &list); } // namespace grapher diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 7a49abe..0c90441 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -49,7 +49,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, // Config grapher::json_t::json_pointer value_json_pointer( - json_value(config, "value_json_pointer")); + json_at_ref(config, "value_json_pointer")); bool draw_average = config.value("draw_average", true); bool draw_points = config.value("draw_points", true); @@ -57,7 +57,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, std::string plot_file_extension = config.value("plot_file_extension", ".svg"); std::vector group_descriptors = read_descriptors( - json_value(config, "group_descriptors")); + json_at_ref(config, "group_descriptors")); // Drawing diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 372544a..bdd1f34 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -55,7 +55,7 @@ void plotter_stack_t::plot(benchmark_set_t const &bset, std::string plot_file_extension = config.value("plot_file_extension", ".svg"); std::vector descriptors = read_descriptors( - json_value>(config, "group_descriptors")); + json_at_ref(config, "group_descriptors")); // Drawing diff --git a/grapher/lib/grapher/predicates.cpp b/grapher/lib/grapher/predicates.cpp index dbc028e..4e99c0a 100644 --- a/grapher/lib/grapher/predicates.cpp +++ b/grapher/lib/grapher/predicates.cpp @@ -28,15 +28,17 @@ namespace grapher::predicates { /// ``` inline auto regex(grapher::json_t const &constraint) { // Validating pointer parameter - return [pointer = grapher::json_t::json_pointer{json_value( - constraint, "pointer")}, - regex = std::regex(json_value(constraint, "regex"))]( - grapher::json_t const &value) -> bool { + return [pointer = + grapher::json_t::json_pointer{ + json_at_ref(constraint, "pointer")}, + regex = std::regex(json_at_ref( + constraint, "regex"))](grapher::json_t const &value) -> bool { if (!value.contains(pointer) || !value[pointer].is_string()) { return false; } - return std::regex_match(json_value(value, pointer), regex); + return std::regex_match( + json_at_ref(value, pointer), regex); }; } @@ -81,8 +83,7 @@ inline auto regex(grapher::json_t const &constraint) { /// } /// ``` inline auto match(grapher::json_t const &constraint) { - return [matcher_flat = - json_value(constraint, "matcher").flatten(), + return [matcher_flat = json_at(constraint, "matcher").flatten(), regex_match_opt = constraint.value("regex", false)]( grapher::json_t const &value) -> bool { auto items_iteration_proxy = matcher_flat.items(); @@ -121,9 +122,10 @@ inline auto match(grapher::json_t const &constraint) { /// } /// ``` inline auto streq(grapher::json_t const &constraint) { - return [pointer = grapher::json_t::json_pointer{json_value( - constraint, "pointer")}, - str = json_value(constraint, "string")]( + return [pointer = + grapher::json_t::json_pointer{ + json_at_ref(constraint, "pointer")}, + str = json_at_ref(constraint, "string")]( grapher::json_t const &value) -> bool { if (!value.contains(pointer) || !value[pointer].is_string()) { return false; @@ -156,12 +158,11 @@ inline auto streq(grapher::json_t const &constraint) { /// } /// ``` inline auto op_or(grapher::json_t const &constraint) { - return - [first = get_predicate(json_value(constraint, "first")), - second = get_predicate(json_value( - constraint, "second"))](grapher::json_t const &value) -> bool { - return first(value) || second(value); - }; + return [first = get_predicate(json_at(constraint, "first")), + second = get_predicate(json_at(constraint, "second"))]( + grapher::json_t const &value) -> bool { + return first(value) || second(value); + }; } /// \ingroup predicates @@ -186,12 +187,11 @@ inline auto op_or(grapher::json_t const &constraint) { /// } /// ``` inline auto op_and(grapher::json_t const &constraint) { - return - [first = get_predicate(json_value(constraint, "first")), - second = get_predicate(json_value( - constraint, "second"))](grapher::json_t const &value) -> bool { - return first(value) && second(value); - }; + return [first = get_predicate(json_at(constraint, "first")), + second = get_predicate(json_at(constraint, "second"))]( + grapher::json_t const &value) -> bool { + return first(value) && second(value); + }; } /// \ingroup predicates @@ -227,7 +227,8 @@ namespace grapher { /// \ingroup predicates /// Builds predicate and stores it in an std::function object. predicate_t get_predicate(grapher::json_t const &constraint) { - std::string constraint_type = json_value(constraint, "type"); + std::string constraint_type = + json_at_ref(constraint, "type"); #define REGISTER_PREDICATE(name) \ if (constraint_type == #name) { \ diff --git a/grapher/lib/grapher/utils/config.cpp b/grapher/lib/grapher/utils/config.cpp index 15177c0..54ab45b 100644 --- a/grapher/lib/grapher/utils/config.cpp +++ b/grapher/lib/grapher/utils/config.cpp @@ -10,6 +10,7 @@ #include #include +#include "grapher/core.hpp" #include "grapher/predicates.hpp" #include "grapher/utils/json.hpp" @@ -33,12 +34,11 @@ std::vector get_predicates(group_descriptor_t const &descriptor) { return predicates; } -std::vector -extract_group(group_descriptor_t const &descriptor, - std::vector const &events) { +grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, + grapher::json_t::array_t const &events) { std::vector predicates = get_predicates(descriptor); - std::vector res; + grapher::json_t::array_t res; std::ranges::copy_if( events, std::back_inserter(res), [&](grapher::json_t const &event) { @@ -49,11 +49,12 @@ extract_group(group_descriptor_t const &descriptor, return res; } -group_descriptor_t json_to_group_descriptor(grapher::json_t const &j) { - return {.name = json_value(j, "name"), +group_descriptor_t read_descriptor(grapher::json_t const &j) { + return {.name = json_at_ref(j, "name"), .predicates = - json_value>(j, "predicates")}; + json_at_ref(j, "predicates")}; } + grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor) { return { {"name", descriptor.name}, @@ -61,9 +62,9 @@ grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor) { }; } -std::vector +grapher::json_t::array_t write_descriptors(std::vector const &descriptors) { - std::vector res; + grapher::json_t::array_t res; res.reserve(descriptors.size()); for (group_descriptor_t const &d : descriptors) { @@ -73,11 +74,11 @@ write_descriptors(std::vector const &descriptors) { } std::vector -read_descriptors(std::vector const &list) { +read_descriptors(grapher::json_t::array_t const &list) { std::vector res; res.reserve(list.size()); std::transform(list.begin(), list.end(), std::back_inserter(res), - &json_to_group_descriptor); + &read_descriptor); return res; } diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index a2e644e..6ffe812 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -1,4 +1,5 @@ #include "grapher/utils/json.hpp" +#include "grapher/core.hpp" #include "grapher/predicates.hpp" #include "grapher/utils/config.hpp" @@ -36,7 +37,7 @@ std::vector get_values(benchmark_iteration_t const &iteration, for (grapher::json_t const &event : events) { if (std::all_of(predicates.begin(), predicates.end(), [&](predicate_t const &p) -> bool { return p(event); })) { - val += json_value(event, value_jptr); + val += json_at_ref(event, value_jptr); } } return val; From 98c3aab17879ea04d9ca33d132550126383722dc Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:28:00 +0200 Subject: [PATCH 16/59] Bump to v0.1.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e98fd4d..4a74e76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -project(ctbench VERSION 0.0.2) +project(ctbench VERSION 0.1.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) From 0eae4cb4f697b2fc82ed1d14afbd3cf34e2b9f3f Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:30:40 +0200 Subject: [PATCH 17/59] Added partial implementation for compare_all --- .../include/grapher/plotters/compare_all.hpp | 18 +++ grapher/lib/grapher/plotters/compare_all.cpp | 109 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 grapher/include/grapher/plotters/compare_all.hpp create mode 100644 grapher/lib/grapher/plotters/compare_all.cpp diff --git a/grapher/include/grapher/plotters/compare_all.hpp b/grapher/include/grapher/plotters/compare_all.hpp new file mode 100644 index 0000000..1e52eb0 --- /dev/null +++ b/grapher/include/grapher/plotters/compare_all.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "grapher/plotters/plotter_i.hpp" + +namespace grapher::plotters { + +/// \ingroup plotters + +struct plotter_compare_all_t : plotter_i { + void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, + grapher::json_t const &config) const override; + + std::string_view get_help() const override; + + grapher::json_t get_default_config() const override; +}; + +} // namespace grapher::plotters diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_all.cpp new file mode 100644 index 0000000..c5e3aba --- /dev/null +++ b/grapher/lib/grapher/plotters/compare_all.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "grapher/core.hpp" +#include "grapher/plotters/compare_all.hpp" +#include "grapher/utils/config.hpp" +#include "grapher/utils/error.hpp" +#include "grapher/utils/json.hpp" +#include "grapher/utils/plot.hpp" + +namespace grapher::plotters { + +std::string_view plotter_compare_all_t::get_help() const { + return "Compares all traceEvents that have a matching name."; +} + +grapher::json_t plotter_compare_all_t::get_default_config() const { + grapher::json_t res = grapher::base_default_config(); + + res["plotter"] = "compare"; + + res["value_json_pointer"] = "/dur"; + res["draw_average"] = true; + res["draw_points"] = true; + + res["plot_file_extension"] = grapher::json_t::array({".svg", ".png"}); + + return res; +} + +// Point aggregate (multiple Y coordinates) +using point_data_t = std::vector; + +// Curve: X -> vec +using benchmark_curve_t = map_t; + +// Benchmark name -> Curve +using curve_aggregate_t = map_t; + +// Feature -> Benchmark aggregate +using curve_aggregate_map_t = map_t; + +/// Wrangles data into a structure that's easier to work with for plotting. +curve_aggregate_map_t +get_bench_curves(benchmark_set_t const &bset, + grapher::json_t::json_pointer const &key_ptr, + grapher::json_t::json_pointer const &value_ptr) { + namespace fs = std::filesystem; + + curve_aggregate_map_t res; + + for (benchmark_case_t const &bench_case : bset) { + + // std::size_t const iteration_count = bench_case.iterations.size(); + + for (benchmark_iteration_t const &iteration : bench_case.iterations) { + for (fs::path const &sample : iteration.samples) { + grapher::json_t sample_json; + { + std::ifstream sample_ifstream(sample); + sample_ifstream >> sample_json; + } + + for (grapher::json_t const &event : + json_at_ref(sample_json, "traceEvents")) { + grapher::json_t::string_t const &key = + json_at_ref(event, key_ptr); + + double value = json_at(event, value_ptr); + + res[key][bench_case.name][iteration.size].push_back(value); + } // sample_json["traceEvents"] + } // iteration.samples + } // bench_case.iterations + } // bset + + return res; +} + +void plotter_compare_all_t::plot(benchmark_set_t const & /*bset*/, + std::filesystem::path const & /*dest*/, + grapher::json_t const &config) const { + // Config + + grapher::json_t::json_pointer value_json_pointer( + json_at_ref(config, "value_json_pointer")); + + // bool draw_average = config.value("draw_average", true); + // bool draw_points = config.value("draw_points", true); + + std::vector plot_file_extensions = config.value( + "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); + + std::string key_ptr = config.value("key_ptr", "/name"); + + std::vector group_descriptors = read_descriptors( + json_at_ref(config, "group_descriptors")); +} + +} // namespace grapher::plotters From aabe4a4fcfc107f92dd7b25ab37cd2c65aa98a0d Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 12:33:35 +0200 Subject: [PATCH 18/59] Replaced .get_ref with json_at_ref --- grapher/lib/grapher/utils/json.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index 6ffe812..8b2c7d8 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -24,13 +24,8 @@ std::vector get_values(benchmark_iteration_t const &iteration, repetition_ifstream >> j; } - if (!j.contains("traceEvents") || !j["traceEvents"].is_array() || - j["traceEvents"].empty()) { - return 0.; - } - grapher::json_t::array_t const &events = - j["traceEvents"].get_ref(); + json_at_ref(j, "traceEvents"); // Accumulate double val = 0.; From de213d1f3867b362afa55b2c66c03fa01ba0146d Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 17:32:41 +0200 Subject: [PATCH 19/59] Made json_at an inline function --- grapher/include/grapher/utils/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 2f3e68d..8d05e3e 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -27,7 +27,7 @@ grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b); /// Wraps json_t object access with error management. template -grapher::json_t::const_reference +inline grapher::json_t::const_reference json_at(grapher::json_t const &object, LocType const &field_location, const std::experimental::source_location loc = std::experimental::source_location::current()) { From 3f31cee5578976d0f71f5832295688203db533bc Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 10 May 2022 17:34:35 +0200 Subject: [PATCH 20/59] compare_all progress: data wrangling and curve vector building now finished, the only things that remain now are plot building and saving --- grapher/lib/grapher/plotters/compare_all.cpp | 77 +++++++++++++++----- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_all.cpp index c5e3aba..5575917 100644 --- a/grapher/lib/grapher/plotters/compare_all.cpp +++ b/grapher/lib/grapher/plotters/compare_all.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -37,16 +38,18 @@ grapher::json_t plotter_compare_all_t::get_default_config() const { return res; } -// Point aggregate (multiple Y coordinates) +// Plot-friendly data structures + +/// Point aggregate (multiple Y coordinates) using point_data_t = std::vector; -// Curve: X -> vec +/// Curve: X -> vec using benchmark_curve_t = map_t; -// Benchmark name -> Curve +/// Benchmark name -> Curve using curve_aggregate_t = map_t; -// Feature -> Benchmark aggregate +/// Feature -> Benchmark aggregate using curve_aggregate_map_t = map_t; /// Wrangles data into a structure that's easier to work with for plotting. @@ -72,38 +75,74 @@ get_bench_curves(benchmark_set_t const &bset, for (grapher::json_t const &event : json_at_ref(sample_json, "traceEvents")) { - grapher::json_t::string_t const &key = - json_at_ref(event, key_ptr); - double value = json_at(event, value_ptr); + if ((!event.contains(key_ptr) || !event[key_ptr].is_string()) || + (!event.contains(value_ptr) || !event[value_ptr].is_number())) { + continue; + } - res[key][bench_case.name][iteration.size].push_back(value); - } // sample_json["traceEvents"] - } // iteration.samples - } // bench_case.iterations - } // bset + res[event[key_ptr].get_ref()] + [bench_case.name][iteration.size] + .push_back(event[value_ptr]); + } + } + } + } return res; } -void plotter_compare_all_t::plot(benchmark_set_t const & /*bset*/, - std::filesystem::path const & /*dest*/, +void plotter_compare_all_t::plot(benchmark_set_t const &bset, + std::filesystem::path const &/*dest*/, grapher::json_t const &config) const { // Config grapher::json_t::json_pointer value_json_pointer( json_at_ref(config, "value_json_pointer")); - // bool draw_average = config.value("draw_average", true); - // bool draw_points = config.value("draw_points", true); + bool draw_average = config.value("draw_average", true); + bool draw_points = config.value("draw_points", true); std::vector plot_file_extensions = config.value( "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); - std::string key_ptr = config.value("key_ptr", "/name"); + json_t::json_pointer key_ptr = + config.value("key_ptr", json_t::json_pointer("/name")); + + json_t::json_pointer value_ptr = + config.value("value_ptr", json_t::json_pointer("/dur")); + + // Wrangling + + curve_aggregate_map_t curve_aggregate_map = + get_bench_curves(bset, key_ptr, value_ptr); + + // Drawing + + for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { + for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { + + std::vector x_curve, y_curve, x_points, y_points; + + for (auto const &[x_value, y_values] : benchmark_curve) { + // ... + if (draw_average && !y_values.empty()) { + x_curve.push_back(x_value); + y_curve.push_back(std::reduce(y_values.begin(), y_values.end()) / + y_values.size()); + } + + if (draw_points) { + for (double y_value : y_values) { + x_points.push_back(x_value); + y_points.push_back(y_value); + } + } + } - std::vector group_descriptors = read_descriptors( - json_at_ref(config, "group_descriptors")); + // Configure + draw + save plot(s) + } + } } } // namespace grapher::plotters From d128fb27b0d9a8d404b6b28e34443964863c5d84 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 16:01:52 +0200 Subject: [PATCH 21/59] Added plot drawing, to be improved by adding legends and so on --- grapher/lib/grapher/plotters/compare_all.cpp | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_all.cpp index 5575917..cdc9f12 100644 --- a/grapher/lib/grapher/plotters/compare_all.cpp +++ b/grapher/lib/grapher/plotters/compare_all.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -93,8 +94,10 @@ get_bench_curves(benchmark_set_t const &bset, } void plotter_compare_all_t::plot(benchmark_set_t const &bset, - std::filesystem::path const &/*dest*/, + std::filesystem::path const & /*dest*/, grapher::json_t const &config) const { + namespace sp = sciplot; + // Config grapher::json_t::json_pointer value_json_pointer( @@ -124,6 +127,7 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, std::vector x_curve, y_curve, x_points, y_points; + // Build point & curve vectors for (auto const &[x_value, y_values] : benchmark_curve) { // ... if (draw_average && !y_values.empty()) { @@ -140,7 +144,21 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, } } - // Configure + draw + save plot(s) + // Configure + draw + save plots + sp::Plot plot; + + if (draw_average && !x_curve.empty()) { + plot.drawCurve(x_curve, y_curve); + } + + if (draw_points && !x_points.empty()) { + plot.drawPoints(x_points, y_points); + } + + for (std::string const &extension : plot_file_extensions) { + namespace fs = std::filesystem; + plot.save(fs::path{feature_name} / (bench_name + extension)); + } } } } From 6459ce36d13987e177816e7f1ee3181cd33d50a4 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 16:31:08 +0200 Subject: [PATCH 22/59] Added compare_all to exposed plotters, disabled grouped_histogram --- grapher/include/grapher/plotters/plotters.hpp | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/grapher/include/grapher/plotters/plotters.hpp b/grapher/include/grapher/plotters/plotters.hpp index fa3967c..4b29be8 100644 --- a/grapher/include/grapher/plotters/plotters.hpp +++ b/grapher/include/grapher/plotters/plotters.hpp @@ -5,8 +5,9 @@ #include #include "grapher/plotters/compare.hpp" +#include "grapher/plotters/compare_all.hpp" #include "grapher/plotters/debug.hpp" -#include "grapher/plotters/grouped_histogram.hpp" +//#include "grapher/plotters/grouped_histogram.hpp" #include "grapher/plotters/stack.hpp" namespace grapher { @@ -14,16 +15,18 @@ namespace grapher { /// Plotter type enumeration. One per plotter. enum plotter_type_t { compare_v, + compare_all_v, debug_v, - grouped_histogram_v, + // grouped_histogram_v, stack_v, }; /// String to plotter type map. inline const std::map plotter_name_map = { {"compare", compare_v}, + {"compare_all", compare_all_v}, {"debug", debug_v}, - {"grouped_histogram", grouped_histogram_v}, + // {"grouped_histogram", grouped_histogram_v}, {"stack", stack_v}, }; @@ -31,27 +34,32 @@ inline const std::map plotter_name_map = { inline const llvm::cl::ValuesClass plotter_cl_values{ llvm::cl::OptionEnumValue{"compare", compare_v, "Compare benchmarks feature by feature."}, + llvm::cl::OptionEnumValue{"compare_all", compare_all_v, + "Stack features for each benchmark."}, llvm::cl::OptionEnumValue{"debug", debug_v, "Output category stats for debug."}, - llvm::cl::OptionEnumValue{"grouped_histogram", grouped_histogram_v, - "Stack features for groups of symbols."}, + // llvm::cl::OptionEnumValue{"grouped_histogram", grouped_histogram_v, + // "Stack features for groups of symbols."}, llvm::cl::OptionEnumValue{"stack", stack_v, - "Stack features for each benchmark."}}; + "Stack features for each benchmark."}, +}; /// Converts a plotter type to a plotter. inline plotter_t plotter_type_to_plotter(plotter_type_t type) { switch (type) { case compare_v: - return std::make_unique(); + return std::make_unique(); + case compare_all_v: + return std::make_unique(); case debug_v: - return std::make_unique(); - case grouped_histogram_v: - return std::make_unique(); + return std::make_unique(); + // case grouped_histogram_v: + // return std::make_unique(); case stack_v: - return std::make_unique(); + return std::make_unique(); } - return std::make_unique(); + return std::make_unique(); } /// Converts a string to a plotter type. From fdbbaae9af00f5f6044f419a5860cb10791489d8 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 17:21:37 +0200 Subject: [PATCH 23/59] Fixed json_pointer constructions and split curve vector declarations for better readability --- grapher/lib/grapher/plotters/compare_all.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_all.cpp index cdc9f12..57c0d7c 100644 --- a/grapher/lib/grapher/plotters/compare_all.cpp +++ b/grapher/lib/grapher/plotters/compare_all.cpp @@ -22,7 +22,7 @@ namespace grapher::plotters { std::string_view plotter_compare_all_t::get_help() const { - return "Compares all traceEvents that have a matching name."; + return "Compares all traceEvents with a matching feature."; } grapher::json_t plotter_compare_all_t::get_default_config() const { @@ -109,11 +109,8 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, std::vector plot_file_extensions = config.value( "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); - json_t::json_pointer key_ptr = - config.value("key_ptr", json_t::json_pointer("/name")); - - json_t::json_pointer value_ptr = - config.value("value_ptr", json_t::json_pointer("/dur")); + json_t::json_pointer key_ptr(config.value("key_ptr", "/name")); + json_t::json_pointer value_ptr(config.value("value_ptr", "/dur")); // Wrangling @@ -124,8 +121,10 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { - - std::vector x_curve, y_curve, x_points, y_points; + std::vector x_curve; + std::vector y_curve; + std::vector x_points; + std::vector y_points; // Build point & curve vectors for (auto const &[x_value, y_values] : benchmark_curve) { From c021c0ef9610f98aa0d75db219b7fa0f61d35062 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 17:21:58 +0200 Subject: [PATCH 24/59] Added fallback return statement in to_string --- grapher/include/grapher/utils/error.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/grapher/include/grapher/utils/error.hpp b/grapher/include/grapher/utils/error.hpp index 03ca453..4cb4b66 100644 --- a/grapher/include/grapher/utils/error.hpp +++ b/grapher/include/grapher/utils/error.hpp @@ -23,6 +23,7 @@ inline std::string to_string(error_level_t error_level) { case info_v: return "INFO"; } + return ""; } /// Prints a warning From 99c9f62e3e624c23789b55cd8fd62823247fc2e4 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 17:22:52 +0200 Subject: [PATCH 25/59] Added CMakePresets.json file, three presets are available including one that is specifically made for development as it provides compile_commands.json and has clang-tidy enabled --- CMakePresets.json | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..922bf22 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,57 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "configurePresets": [ + { + "name": "dev", + "displayName": "Development", + "description": "Development build, provides compile_commands.json", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_CLANG_TIDY": "clang-tidy;-checks=-*,readability-*" + } + }, + { + "name": "release", + "displayName": "Release", + "description": "Release build", + "binaryDir": "${sourceDir}/builds/release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "debug", + "inherits": "release", + "displayName": "Debug", + "description": "Debug build", + "binaryDir": "${sourceDir}/builds/debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + } + ], + "buildPresets": [ + { + "name": "dev", + "configurePreset": "dev" + }, + { + "name": "release", + "configurePreset": "release" + }, + { + "name": "debug", + "configurePreset": "debug" + } + ] +} From 8959d764187c7c52bc9040f48be95e568f601c6f Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 11 May 2022 17:23:36 +0200 Subject: [PATCH 26/59] Added git exception for builds where non-dev builds are compiled --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f5111f5..49a9144 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .cache/ generated-docs/ build/ +builds/ From 616c78c0ea792dc653c3e13ab5a994342b628973 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 11:03:16 +0200 Subject: [PATCH 27/59] Generating one plot per feature instead of one plot per feature+benchmark --- grapher/lib/grapher/plotters/compare_all.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_all.cpp index 57c0d7c..38b9090 100644 --- a/grapher/lib/grapher/plotters/compare_all.cpp +++ b/grapher/lib/grapher/plotters/compare_all.cpp @@ -120,6 +120,9 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, // Drawing for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { + // Configure + draw + save plots + sp::Plot plot; + for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { std::vector x_curve; std::vector y_curve; @@ -143,21 +146,17 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, } } - // Configure + draw + save plots - sp::Plot plot; - if (draw_average && !x_curve.empty()) { - plot.drawCurve(x_curve, y_curve); + plot.drawCurve(x_curve, y_curve).label(bench_name + " average"); } if (draw_points && !x_points.empty()) { - plot.drawPoints(x_points, y_points); + plot.drawPoints(x_points, y_points).label(bench_name + " points"); } + } - for (std::string const &extension : plot_file_extensions) { - namespace fs = std::filesystem; - plot.save(fs::path{feature_name} / (bench_name + extension)); - } + for (std::string const &extension : plot_file_extensions) { + plot.save(feature_name + extension); } } } From e8f51b4f4894cad242efe18bc7aa5c1a5029104c Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 11:07:01 +0200 Subject: [PATCH 28/59] Added exception for CMakeUserPresets.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 49a9144..e6e4da9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ generated-docs/ build/ builds/ +CMakeUserPresets.json From 0930d22dc8243563afff63f46c33ef59c321edc3 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:16:47 +0200 Subject: [PATCH 29/59] Error management fix: warning no longer terminates execution. Condition value is also passed through --- grapher/include/grapher/utils/error.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grapher/include/grapher/utils/error.hpp b/grapher/include/grapher/utils/error.hpp index 4cb4b66..d233d63 100644 --- a/grapher/include/grapher/utils/error.hpp +++ b/grapher/include/grapher/utils/error.hpp @@ -38,16 +38,18 @@ inline void warn(std::string_view explain, /// Error management: if the condition is false, it will print a warning or /// error message and termineate the program if error_level is error_v. -inline void check(bool condition, std::string_view explain, +/// Condition value is then returned (useful for warnings). +inline bool check(bool condition, std::string_view explain, error_level_t error_level = error_v, int err_code = -1, std::experimental::source_location loc = std::experimental::source_location::current()) { if (!condition) { warn(explain, error_level, loc); - if (error_level) { + if (error_level == error_v) { std::exit(err_code); } } + return condition; } } // namespace grapher From 5ac2d475dcf09ad594b52e1ddfacdd4a6fe52e93 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:17:23 +0200 Subject: [PATCH 30/59] compare_all renamed to compare_by, error reporting improved --- .../{compare_all.hpp => compare_by.hpp} | 2 +- grapher/include/grapher/plotters/plotters.hpp | 12 ++-- .../{compare_all.cpp => compare_by.cpp} | 57 ++++++++++++------- 3 files changed, 44 insertions(+), 27 deletions(-) rename grapher/include/grapher/plotters/{compare_all.hpp => compare_by.hpp} (89%) rename grapher/lib/grapher/plotters/{compare_all.cpp => compare_by.cpp} (67%) diff --git a/grapher/include/grapher/plotters/compare_all.hpp b/grapher/include/grapher/plotters/compare_by.hpp similarity index 89% rename from grapher/include/grapher/plotters/compare_all.hpp rename to grapher/include/grapher/plotters/compare_by.hpp index 1e52eb0..3c949ea 100644 --- a/grapher/include/grapher/plotters/compare_all.hpp +++ b/grapher/include/grapher/plotters/compare_by.hpp @@ -6,7 +6,7 @@ namespace grapher::plotters { /// \ingroup plotters -struct plotter_compare_all_t : plotter_i { +struct plotter_compare_by_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/plotters.hpp b/grapher/include/grapher/plotters/plotters.hpp index 4b29be8..6ab9f8b 100644 --- a/grapher/include/grapher/plotters/plotters.hpp +++ b/grapher/include/grapher/plotters/plotters.hpp @@ -5,7 +5,7 @@ #include #include "grapher/plotters/compare.hpp" -#include "grapher/plotters/compare_all.hpp" +#include "grapher/plotters/compare_by.hpp" #include "grapher/plotters/debug.hpp" //#include "grapher/plotters/grouped_histogram.hpp" #include "grapher/plotters/stack.hpp" @@ -15,7 +15,7 @@ namespace grapher { /// Plotter type enumeration. One per plotter. enum plotter_type_t { compare_v, - compare_all_v, + compare_by_v, debug_v, // grouped_histogram_v, stack_v, @@ -24,7 +24,7 @@ enum plotter_type_t { /// String to plotter type map. inline const std::map plotter_name_map = { {"compare", compare_v}, - {"compare_all", compare_all_v}, + {"compare_by", compare_by_v}, {"debug", debug_v}, // {"grouped_histogram", grouped_histogram_v}, {"stack", stack_v}, @@ -34,7 +34,7 @@ inline const std::map plotter_name_map = { inline const llvm::cl::ValuesClass plotter_cl_values{ llvm::cl::OptionEnumValue{"compare", compare_v, "Compare benchmarks feature by feature."}, - llvm::cl::OptionEnumValue{"compare_all", compare_all_v, + llvm::cl::OptionEnumValue{"compare_by", compare_by_v, "Stack features for each benchmark."}, llvm::cl::OptionEnumValue{"debug", debug_v, "Output category stats for debug."}, @@ -49,8 +49,8 @@ inline plotter_t plotter_type_to_plotter(plotter_type_t type) { switch (type) { case compare_v: return std::make_unique(); - case compare_all_v: - return std::make_unique(); + case compare_by_v: + return std::make_unique(); case debug_v: return std::make_unique(); // case grouped_histogram_v: diff --git a/grapher/lib/grapher/plotters/compare_all.cpp b/grapher/lib/grapher/plotters/compare_by.cpp similarity index 67% rename from grapher/lib/grapher/plotters/compare_all.cpp rename to grapher/lib/grapher/plotters/compare_by.cpp index 38b9090..1b64992 100644 --- a/grapher/lib/grapher/plotters/compare_all.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -13,7 +13,7 @@ #include #include "grapher/core.hpp" -#include "grapher/plotters/compare_all.hpp" +#include "grapher/plotters/compare_by.hpp" #include "grapher/utils/config.hpp" #include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" @@ -21,16 +21,18 @@ namespace grapher::plotters { -std::string_view plotter_compare_all_t::get_help() const { +std::string_view plotter_compare_by_t::get_help() const { return "Compares all traceEvents with a matching feature."; } -grapher::json_t plotter_compare_all_t::get_default_config() const { +grapher::json_t plotter_compare_by_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); - res["plotter"] = "compare"; + res["plotter"] = "compare_by"; + + res["key_ptr"] = "/name"; + res["value_ptr"] = "/dur"; - res["value_json_pointer"] = "/dur"; res["draw_average"] = true; res["draw_points"] = true; @@ -57,7 +59,7 @@ using curve_aggregate_map_t = map_t; curve_aggregate_map_t get_bench_curves(benchmark_set_t const &bset, grapher::json_t::json_pointer const &key_ptr, - grapher::json_t::json_pointer const &value_ptr) { + grapher::json_t::json_pointer const &val_ptr) { namespace fs = std::filesystem; curve_aggregate_map_t res; @@ -77,14 +79,28 @@ get_bench_curves(benchmark_set_t const &bset, for (grapher::json_t const &event : json_at_ref(sample_json, "traceEvents")) { - if ((!event.contains(key_ptr) || !event[key_ptr].is_string()) || - (!event.contains(value_ptr) || !event[value_ptr].is_number())) { - continue; + // Key/value presence and type checks + if (check(event.contains(key_ptr), + fmt::format("No matching key at {}:\n{}", + key_ptr.to_string(), event.dump(2)), + warning_v) && + check(event[key_ptr].is_string(), + fmt::format("Key at {} is not a string:\n{}", + key_ptr.to_string(), event.dump(2)), + warning_v) && + check(event.contains(val_ptr), + fmt::format("No matching value at {}:\n{}", + val_ptr.to_string(), event.dump(2)), + warning_v) && + check(event[val_ptr].is_number(), + fmt::format("Value at {} is not an integer:\n{}", + val_ptr.to_string(), event.dump(2)), + warning_v)) { + // Adding value + res[event[key_ptr].get_ref()] + [bench_case.name][iteration.size] + .push_back(event[val_ptr]); } - - res[event[key_ptr].get_ref()] - [bench_case.name][iteration.size] - .push_back(event[value_ptr]); } } } @@ -93,16 +109,14 @@ get_bench_curves(benchmark_set_t const &bset, return res; } -void plotter_compare_all_t::plot(benchmark_set_t const &bset, - std::filesystem::path const & /*dest*/, - grapher::json_t const &config) const { +void plotter_compare_by_t::plot(benchmark_set_t const &bset, + std::filesystem::path const &dest, + grapher::json_t const &config) const { namespace sp = sciplot; + namespace fs = std::filesystem; // Config - grapher::json_t::json_pointer value_json_pointer( - json_at_ref(config, "value_json_pointer")); - bool draw_average = config.value("draw_average", true); bool draw_points = config.value("draw_points", true); @@ -117,11 +131,14 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, curve_aggregate_map_t curve_aggregate_map = get_bench_curves(bset, key_ptr, value_ptr); + fs::create_directories(dest); + // Drawing for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { // Configure + draw + save plots sp::Plot plot; + apply_config(plot, config); for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { std::vector x_curve; @@ -156,7 +173,7 @@ void plotter_compare_all_t::plot(benchmark_set_t const &bset, } for (std::string const &extension : plot_file_extensions) { - plot.save(feature_name + extension); + plot.save(fs::path{dest} / (feature_name + extension)); } } } From 979561f5271b1ebb28090aea5aaf2726728a62f2 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:17:48 +0200 Subject: [PATCH 31/59] release/debug builds are now inside of build instead of builds --- CMakePresets.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 922bf22..0d607e6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,7 +24,7 @@ "name": "release", "displayName": "Release", "description": "Release build", - "binaryDir": "${sourceDir}/builds/release", + "binaryDir": "${sourceDir}/build/release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } @@ -34,7 +34,7 @@ "inherits": "release", "displayName": "Debug", "description": "Debug build", - "binaryDir": "${sourceDir}/builds/debug", + "binaryDir": "${sourceDir}/build/debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } From 4898a217dcbf82ac9f7f0fa4236670dcbb238577 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:38:52 +0200 Subject: [PATCH 32/59] Added log error level (like info but will be enabled with a verbose flag) --- grapher/include/grapher/utils/error.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/grapher/include/grapher/utils/error.hpp b/grapher/include/grapher/utils/error.hpp index d233d63..812c922 100644 --- a/grapher/include/grapher/utils/error.hpp +++ b/grapher/include/grapher/utils/error.hpp @@ -12,7 +12,7 @@ namespace grapher { -enum error_level_t : std::uint8_t { error_v, warning_v, info_v }; +enum error_level_t : std::uint8_t { error_v, warning_v, info_v, log_v }; inline std::string to_string(error_level_t error_level) { switch (error_level) { @@ -22,6 +22,8 @@ inline std::string to_string(error_level_t error_level) { return "WARNING"; case info_v: return "INFO"; + case log_v: + return "LOG"; } return ""; } @@ -31,9 +33,9 @@ inline void warn(std::string_view explain, error_level_t error_level = warning_v, std::experimental::source_location loc = std::experimental::source_location::current()) { - llvm::errs() << fmt::format("{} {}, {}:{}:{} - {}\n", to_string(error_level), - loc.file_name(), loc.function_name(), loc.line(), - loc.column(), explain); + llvm::errs() << fmt::format( + "[{}] {}:{}:{} ({}) - {}\n", to_string(error_level), loc.file_name(), + loc.line(), loc.column(), loc.function_name(), explain); } /// Error management: if the condition is false, it will print a warning or From 0998187d432e9c867dd616e788e386555fa6746c Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:42:37 +0200 Subject: [PATCH 33/59] JSON dump format is now a single line for more compact info reports --- grapher/lib/grapher/plotters/compare_by.cpp | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 1b64992..c0f2f6b 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -81,21 +81,21 @@ get_bench_curves(benchmark_set_t const &bset, // Key/value presence and type checks if (check(event.contains(key_ptr), - fmt::format("No matching key at {}:\n{}", - key_ptr.to_string(), event.dump(2)), - warning_v) && + fmt::format("No matching key at {}: {}", + key_ptr.to_string(), event.dump()), + info_v) && check(event[key_ptr].is_string(), - fmt::format("Key at {} is not a string:\n{}", - key_ptr.to_string(), event.dump(2)), - warning_v) && + fmt::format("Key at {} is not a string: {}", + key_ptr.to_string(), event.dump()), + info_v) && check(event.contains(val_ptr), - fmt::format("No matching value at {}:\n{}", - val_ptr.to_string(), event.dump(2)), - warning_v) && + fmt::format("No matching value at {}: {}", + val_ptr.to_string(), event.dump()), + info_v) && check(event[val_ptr].is_number(), - fmt::format("Value at {} is not an integer:\n{}", - val_ptr.to_string(), event.dump(2)), - warning_v)) { + fmt::format("Value at {} is not an integer: {}", + val_ptr.to_string(), event.dump()), + info_v)) { // Adding value res[event[key_ptr].get_ref()] [bench_case.name][iteration.size] From 87bc74809391e350f3fcbf1037e2c7a14eeb149b Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:44:51 +0200 Subject: [PATCH 34/59] Error message simplification --- grapher/lib/grapher/plotters/compare_by.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index c0f2f6b..cbd120b 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -81,7 +81,7 @@ get_bench_curves(benchmark_set_t const &bset, // Key/value presence and type checks if (check(event.contains(key_ptr), - fmt::format("No matching key at {}: {}", + fmt::format("No key at {}: {}", key_ptr.to_string(), event.dump()), info_v) && check(event[key_ptr].is_string(), @@ -89,7 +89,7 @@ get_bench_curves(benchmark_set_t const &bset, key_ptr.to_string(), event.dump()), info_v) && check(event.contains(val_ptr), - fmt::format("No matching value at {}: {}", + fmt::format("No value at {}: {}", val_ptr.to_string(), event.dump()), info_v) && check(event[val_ptr].is_number(), From 7d84267455dc266682f210d86d4ef67e82b738b3 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 13:45:17 +0200 Subject: [PATCH 35/59] clang-format --- grapher/lib/grapher/plotters/compare_by.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index cbd120b..5de673e 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -81,16 +81,16 @@ get_bench_curves(benchmark_set_t const &bset, // Key/value presence and type checks if (check(event.contains(key_ptr), - fmt::format("No key at {}: {}", - key_ptr.to_string(), event.dump()), + fmt::format("No key at {}: {}", key_ptr.to_string(), + event.dump()), info_v) && check(event[key_ptr].is_string(), fmt::format("Key at {} is not a string: {}", key_ptr.to_string(), event.dump()), info_v) && check(event.contains(val_ptr), - fmt::format("No value at {}: {}", - val_ptr.to_string(), event.dump()), + fmt::format("No value at {}: {}", val_ptr.to_string(), + event.dump()), info_v) && check(event[val_ptr].is_number(), fmt::format("Value at {} is not an integer: {}", From 1fe7e7de2ba02a29fed81e6fc03dae323dfc1cd5 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 14:12:41 +0200 Subject: [PATCH 36/59] Added plot saving helper function to manage multiple extensions more easily --- grapher/include/grapher/utils/plot.hpp | 4 ++++ grapher/lib/grapher/utils/plot.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/grapher/include/grapher/utils/plot.hpp b/grapher/include/grapher/utils/plot.hpp index 909b028..426a26b 100644 --- a/grapher/include/grapher/utils/plot.hpp +++ b/grapher/include/grapher/utils/plot.hpp @@ -14,4 +14,8 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config); /// Returns the default configuration for apply_config. grapher::json_t base_default_config(); +/// Plot saving helper function. +void save_plot(sciplot::Plot const &plot, std::string const &dest, + grapher::json_t const &config); + } // namespace grapher diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index eca1363..507dd73 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -3,6 +3,7 @@ #include #include +#include "grapher/core.hpp" #include "grapher/plotters/plotter_i.hpp" namespace grapher { @@ -14,6 +15,7 @@ grapher::json_t const default_config = { {"legend_title", "Timings"}, {"xlabel", "Benchmark size factor"}, {"ylabel", "Time (µs)"}, + {"plot_file_extensions", grapher::json_t::array({".svg", ".png"})}, }; sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { @@ -40,4 +42,14 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { grapher::json_t base_default_config() { return default_config; } +void save_plot(sciplot::Plot const &plot, std::string const &dest, + grapher::json_t const &config) { + std::vector plot_file_extensions = config.value( + "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); + + for (std::string const &extension : plot_file_extensions) { + plot.save(dest + extension); + } +} + } // namespace grapher From dacac45ef96b0b9faa439ea9f5f54ea9e35f34d6 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Thu, 12 May 2022 14:15:33 +0200 Subject: [PATCH 37/59] Using new save_plot function across all plotters --- grapher/lib/grapher/plotters/compare.cpp | 4 +--- grapher/lib/grapher/plotters/compare_by.cpp | 25 +++++++++++++-------- grapher/lib/grapher/plotters/stack.cpp | 3 +-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 0c90441..4cc38f7 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -35,8 +35,6 @@ grapher::json_t plotter_compare_t::get_default_config() const { res["draw_average"] = true; res["draw_points"] = true; - res["plot_file_extension"] = ".svg"; - res["group_descriptors"] = write_descriptors({get_default_group_descriptor()}); @@ -118,7 +116,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, // Saving plot std::filesystem::create_directories(dest); - plot.save(dest / (std::move(descriptor.name) + plot_file_extension)); + save_plot(plot, dest / std::move(descriptor.name), config); } } diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 5de673e..9204260 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -28,16 +28,19 @@ std::string_view plotter_compare_by_t::get_help() const { grapher::json_t plotter_compare_by_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); + // Plotter name res["plotter"] = "compare_by"; + // Pointer to the grouping key res["key_ptr"] = "/name"; + // Pointer to the values res["value_ptr"] = "/dur"; + // Draw average curve res["draw_average"] = true; + // Draw value points res["draw_points"] = true; - res["plot_file_extension"] = grapher::json_t::array({".svg", ".png"}); - return res; } @@ -116,7 +119,6 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, namespace fs = std::filesystem; // Config - bool draw_average = config.value("draw_average", true); bool draw_points = config.value("draw_points", true); @@ -127,13 +129,13 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, json_t::json_pointer value_ptr(config.value("value_ptr", "/dur")); // Wrangling - curve_aggregate_map_t curve_aggregate_map = get_bench_curves(bset, key_ptr, value_ptr); + // Ensure the destination folder exists fs::create_directories(dest); - // Drawing + // Drawing, ie. unwrapping the nested maps and drawing curves + saving plots for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { // Configure + draw + save plots @@ -141,21 +143,26 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, apply_config(plot, config); for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { + // The following vectors store point coordinates for average curve and + // individual point drawing + std::vector x_curve; std::vector y_curve; + std::vector x_points; std::vector y_points; // Build point & curve vectors for (auto const &[x_value, y_values] : benchmark_curve) { - // ... if (draw_average && !y_values.empty()) { + // Computing and drawing average x_curve.push_back(x_value); y_curve.push_back(std::reduce(y_values.begin(), y_values.end()) / y_values.size()); } if (draw_points) { + // Drawing points for (double y_value : y_values) { x_points.push_back(x_value); y_points.push_back(y_value); @@ -164,17 +171,17 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, } if (draw_average && !x_curve.empty()) { + // Draw average curve plot.drawCurve(x_curve, y_curve).label(bench_name + " average"); } if (draw_points && !x_points.empty()) { + // Draw points plot.drawPoints(x_points, y_points).label(bench_name + " points"); } } - for (std::string const &extension : plot_file_extensions) { - plot.save(fs::path{dest} / (feature_name + extension)); - } + save_plot(plot, dest, config); } } diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index bdd1f34..777fafb 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -32,7 +32,6 @@ grapher::json_t plotter_stack_t::get_default_config() const { // Basic values, probably no need to change them res["value_json_pointer"] = "/dur"; res["name_json_pointer"] = "/name"; - res["plot_file_extension"] = ".svg"; // Some matchers as an example... res["group_descriptors"] = @@ -127,7 +126,7 @@ void plotter_stack_t::plot(benchmark_set_t const &bset, std::filesystem::create_directories(dest); for (std::size_t i = 0; i < bset.size(); i++) { plots[i].yrange(0., max_y_val); - plots[i].save(dest / (bset[i].name + plot_file_extension)); + save_plot(plots[i], dest / bset[i].name, config); } } From 962eca2010fc12eb8b419baf7185f6f2da711b2c Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 13 May 2022 10:51:43 +0200 Subject: [PATCH 38/59] Changed x/ylabel to x_/y_label for parameter name style consistency, added a shameful fix for filenames being too long until a better solution is found --- grapher/lib/grapher/utils/plot.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index 507dd73..8d6f97f 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -1,5 +1,6 @@ #include "grapher/utils/plot.hpp" +#include #include #include @@ -13,8 +14,8 @@ grapher::json_t const default_config = { {"width", 1500}, {"height", 500}, {"legend_title", "Timings"}, - {"xlabel", "Benchmark size factor"}, - {"ylabel", "Time (µs)"}, + {"x_label", "Benchmark size factor"}, + {"y_label", "Time (µs)"}, {"plot_file_extensions", grapher::json_t::array({".svg", ".png"})}, }; @@ -29,12 +30,12 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { plot.legend().atOutsideRightTop().title(config["legend_title"]); } - if (config.contains("xlabel")) { - plot.xlabel(config["xlabel"]); + if (config.contains("x_label")) { + plot.xlabel(config["x_label"]); } if (config.contains("ylabel")) { - plot.ylabel(config["ylabel"]); + plot.ylabel(config["y_label"]); } return plot; @@ -44,10 +45,22 @@ grapher::json_t base_default_config() { return default_config; } void save_plot(sciplot::Plot const &plot, std::string const &dest, grapher::json_t const &config) { + namespace fs = std::filesystem; std::vector plot_file_extensions = config.value( "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); + // Saving file for all extensions for (std::string const &extension : plot_file_extensions) { + fs::path file_dest = dest + extension; + fs::create_directories(file_dest.parent_path()); + + // Avoid filename hitting OS filename size limit (yes, this is bad) + if (file_dest.filename().string().size() > 256) { + std::string new_filename = file_dest.stem(); + new_filename.resize(256 - extension.size()); + file_dest.replace_filename(new_filename); + } + plot.save(dest + extension); } } From 1ad344af3d37b0fc750633cb4638b202657050db Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 13:00:38 +0200 Subject: [PATCH 39/59] get_help() return type is now std::string instead of std::string_view --- grapher/include/grapher/plotters/plotter_i.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grapher/include/grapher/plotters/plotter_i.hpp b/grapher/include/grapher/plotters/plotter_i.hpp index 14fab28..a6cfc0a 100644 --- a/grapher/include/grapher/plotters/plotter_i.hpp +++ b/grapher/include/grapher/plotters/plotter_i.hpp @@ -26,7 +26,7 @@ namespace grapher { /// Interface for plotters. Plotters should be able to: /// - Plot a ctbench::category_t with a grapher::json_t configuration object, -/// - Output help as a std::string_view, +/// - Output help as a std::string, /// - Output a default config as a grapher::json_t object. struct plotter_i { virtual ~plotter_i() = default; @@ -38,7 +38,7 @@ struct plotter_i { grapher::json_t const &config) const = 0; /// Returns a help message for end-users. - virtual std::string_view get_help() const = 0; + virtual std::string get_help() const = 0; /// Returns a default config for end-users. virtual grapher::json_t get_default_config() const = 0; From 1e76b0ad71f2ac53525c71d88fea8373c33b16cc Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 13:01:11 +0200 Subject: [PATCH 40/59] Changed return type of get_help to std::string --- grapher/include/grapher/plotters/compare.hpp | 2 +- grapher/include/grapher/plotters/compare_by.hpp | 2 +- grapher/include/grapher/plotters/debug.hpp | 2 +- grapher/include/grapher/plotters/grouped_histogram.hpp | 2 +- grapher/include/grapher/plotters/stack.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/grapher/include/grapher/plotters/compare.hpp b/grapher/include/grapher/plotters/compare.hpp index 9813abf..2127342 100644 --- a/grapher/include/grapher/plotters/compare.hpp +++ b/grapher/include/grapher/plotters/compare.hpp @@ -10,7 +10,7 @@ struct plotter_compare_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string_view get_help() const override; + std::string get_help() const override; grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/compare_by.hpp b/grapher/include/grapher/plotters/compare_by.hpp index 3c949ea..e7797d8 100644 --- a/grapher/include/grapher/plotters/compare_by.hpp +++ b/grapher/include/grapher/plotters/compare_by.hpp @@ -10,7 +10,7 @@ struct plotter_compare_by_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string_view get_help() const override; + std::string get_help() const override; grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/debug.hpp b/grapher/include/grapher/plotters/debug.hpp index 20c6532..adc9f05 100644 --- a/grapher/include/grapher/plotters/debug.hpp +++ b/grapher/include/grapher/plotters/debug.hpp @@ -10,7 +10,7 @@ struct plotter_debug_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string_view get_help() const override; + std::string get_help() const override; grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/grouped_histogram.hpp b/grapher/include/grapher/plotters/grouped_histogram.hpp index a458443..aeaa0d2 100644 --- a/grapher/include/grapher/plotters/grouped_histogram.hpp +++ b/grapher/include/grapher/plotters/grouped_histogram.hpp @@ -10,7 +10,7 @@ struct plotter_grouped_histogram_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string_view get_help() const override; + std::string get_help() const override; grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/stack.hpp b/grapher/include/grapher/plotters/stack.hpp index a58f565..9195293 100644 --- a/grapher/include/grapher/plotters/stack.hpp +++ b/grapher/include/grapher/plotters/stack.hpp @@ -12,7 +12,7 @@ struct plotter_stack_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string_view get_help() const override; + std::string get_help() const override; grapher::json_t get_default_config() const override; }; From 2b76d9fdfffb3524c33e6dbcf0a01bdd6cfc0826 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 13:02:26 +0200 Subject: [PATCH 41/59] Changed return type of get_help to std::string --- grapher/lib/grapher/plotters/compare.cpp | 2 +- grapher/lib/grapher/plotters/debug.cpp | 2 +- grapher/lib/grapher/plotters/grouped_histogram.cpp | 2 +- grapher/lib/grapher/plotters/stack.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 4cc38f7..df006f6 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -21,7 +21,7 @@ namespace grapher::plotters { -std::string_view plotter_compare_t::get_help() const { +std::string plotter_compare_t::get_help() const { return "For each group descriptor, generates a graph comparing all " "benchmark cases in the set."; } diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index 245f005..1f84bd0 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -5,7 +5,7 @@ namespace grapher::plotters { -std::string_view plotter_debug_t::get_help() const { +std::string plotter_debug_t::get_help() const { return "Debug plotter. Outputs various statistics on benchmark categories to " "debug category building or traversal issues."; } diff --git a/grapher/lib/grapher/plotters/grouped_histogram.cpp b/grapher/lib/grapher/plotters/grouped_histogram.cpp index 8be36a2..5ef4dd1 100644 --- a/grapher/lib/grapher/plotters/grouped_histogram.cpp +++ b/grapher/lib/grapher/plotters/grouped_histogram.cpp @@ -7,7 +7,7 @@ namespace grapher::plotters { -std::string_view plotter_grouped_histogram_t::get_help() const { +std::string plotter_grouped_histogram_t::get_help() const { // TODO: Add doc return "TODO"; } diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 777fafb..59b1d5a 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -18,7 +18,7 @@ namespace grapher::plotters { -std::string_view plotter_stack_t::get_help() const { +std::string plotter_stack_t::get_help() const { return "For each benchmark in the category, generates a stakcked curve graph " "where each curve corresponds to a matcher in the \'matchers\' JSON " "field."; From 0c91fcad02e1faff743675a480844b01a825c021 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 13:03:16 +0200 Subject: [PATCH 42/59] Max filename limit made a tiny bit cleaner (just a tiny bit) --- grapher/lib/grapher/utils/plot.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index 8d6f97f..c9ba802 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -1,11 +1,11 @@ -#include "grapher/utils/plot.hpp" - #include + #include #include #include "grapher/core.hpp" #include "grapher/plotters/plotter_i.hpp" +#include "grapher/utils/plot.hpp" namespace grapher { @@ -54,10 +54,12 @@ void save_plot(sciplot::Plot const &plot, std::string const &dest, fs::path file_dest = dest + extension; fs::create_directories(file_dest.parent_path()); + constexpr std::size_t max_filename_size = 256; + // Avoid filename hitting OS filename size limit (yes, this is bad) - if (file_dest.filename().string().size() > 256) { + if (file_dest.filename().string().size() > max_filename_size) { std::string new_filename = file_dest.stem(); - new_filename.resize(256 - extension.size()); + new_filename.resize(max_filename_size - extension.size()); file_dest.replace_filename(new_filename); } From 027a880b6bdf5074b6eb5f0c0e5ef704aecd9be5 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 13:04:22 +0200 Subject: [PATCH 43/59] Refactoring, added C++ symbol name demangling, more comments, more help... --- grapher/lib/grapher/plotters/compare_by.cpp | 172 +++++++++++++------- 1 file changed, 109 insertions(+), 63 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 9204260..0b0c285 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -1,11 +1,12 @@ +#include #include #include -#include -#include #include -#include #include +#include + +#include #include #include @@ -21,28 +22,8 @@ namespace grapher::plotters { -std::string_view plotter_compare_by_t::get_help() const { - return "Compares all traceEvents with a matching feature."; -} - -grapher::json_t plotter_compare_by_t::get_default_config() const { - grapher::json_t res = grapher::base_default_config(); - - // Plotter name - res["plotter"] = "compare_by"; - - // Pointer to the grouping key - res["key_ptr"] = "/name"; - // Pointer to the values - res["value_ptr"] = "/dur"; - - // Draw average curve - res["draw_average"] = true; - // Draw value points - res["draw_points"] = true; - - return res; -} +// ============================================================================= +// AUXILIARY // Plot-friendly data structures @@ -55,14 +36,17 @@ using benchmark_curve_t = map_t; /// Benchmark name -> Curve using curve_aggregate_t = map_t; +/// Value key type. Contains multiple values to group by a tuple of parameters +using key_t = boost::container::small_vector; + /// Feature -> Benchmark aggregate -using curve_aggregate_map_t = map_t; +using curve_aggregate_map_t = map_t; /// Wrangles data into a structure that's easier to work with for plotting. curve_aggregate_map_t get_bench_curves(benchmark_set_t const &bset, - grapher::json_t::json_pointer const &key_ptr, - grapher::json_t::json_pointer const &val_ptr) { + std::vector const &key_ptrs, + json_t::json_pointer const &val_ptr) { namespace fs = std::filesystem; curve_aggregate_map_t res; @@ -82,16 +66,16 @@ get_bench_curves(benchmark_set_t const &bset, for (grapher::json_t const &event : json_at_ref(sample_json, "traceEvents")) { + // Building key from JSON pointers + key_t key; + for (json_t::json_pointer const &key_ptr : key_ptrs) { + if (event.contains(key_ptr) && event[key_ptr].is_string()) { + key.push_back(event[key_ptr]); + } + } + // Key/value presence and type checks - if (check(event.contains(key_ptr), - fmt::format("No key at {}: {}", key_ptr.to_string(), - event.dump()), - info_v) && - check(event[key_ptr].is_string(), - fmt::format("Key at {} is not a string: {}", - key_ptr.to_string(), event.dump()), - info_v) && - check(event.contains(val_ptr), + if (check(event.contains(val_ptr), fmt::format("No value at {}: {}", val_ptr.to_string(), event.dump()), info_v) && @@ -100,9 +84,7 @@ get_bench_curves(benchmark_set_t const &bset, val_ptr.to_string(), event.dump()), info_v)) { // Adding value - res[event[key_ptr].get_ref()] - [bench_case.name][iteration.size] - .push_back(event[val_ptr]); + res[key][bench_case.name][iteration.size].push_back(event[val_ptr]); } } } @@ -112,64 +94,128 @@ get_bench_curves(benchmark_set_t const &bset, return res; } +/// Transforms a key into a string that's usable as a path. +std::string to_string(key_t const &key, bool demangle = true) { + if (key.size() == 0) { + return "empty"; + } + + std::string res = demangle ? llvm::demangle(key[0]) : key[0]; + std::for_each(key.begin() + 1, key.end(), [&](std::string const &part) { + res += '/'; + for (char const c : demangle ? llvm::demangle(part) : part) { + res += c == '/' ? '_' : c; + } + }); + + return res; +} + +// ============================================================================= +// OVERRIDES + +std::string_view plotter_compare_by_t::get_help() const { + return "Compares all traceEvents with a matching feature.\n" + "- key_ptrs (string array): Array\n" + "- value_ptr (string): Pointer to the JSON value to measure\n" + "- draw_average (bool): Enable average curve drawing\n" + "- draw_points (bool): Enable value point drawing\n" + "- demangle (bool): Demangle C++ symbol names\n"; +} + +grapher::json_t plotter_compare_by_t::get_default_config() const { + grapher::json_t res = grapher::base_default_config(); + + // Plotter name + res["plotter"] = "compare_by"; + + // List of pointers to generate a key + res["key_ptrs"] = json_t::array({"/name", "/args/detail"}); + + // Pointer to the values + res["value_ptr"] = "/dur"; + + // Draw average curve + res["draw_average"] = true; + // Draw value points + res["draw_points"] = true; + + // Demangle or not + res["demangle"] = true; + + return res; +} + void plotter_compare_by_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { namespace sp = sciplot; namespace fs = std::filesystem; - // Config - bool draw_average = config.value("draw_average", true); - bool draw_points = config.value("draw_points", true); + // Config reading - std::vector plot_file_extensions = config.value( - "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); + std::vector key_strs = + config.value("key_ptrs", json_t::array({"/name", "/args/detail"})); - json_t::json_pointer key_ptr(config.value("key_ptr", "/name")); json_t::json_pointer value_ptr(config.value("value_ptr", "/dur")); + bool draw_average = config.value("draw_average", true); + bool draw_points = config.value("draw_points", true); + bool demangle = config.value("demangle", true); + + std::vector key_ptrs; + std::transform(key_strs.begin(), key_strs.end(), std::back_inserter(key_ptrs), + [](std::string const &s) -> json_t::json_pointer { + return json_t::json_pointer{s}; + }); + // Wrangling curve_aggregate_map_t curve_aggregate_map = - get_bench_curves(bset, key_ptr, value_ptr); + get_bench_curves(bset, key_ptrs, value_ptr); // Ensure the destination folder exists fs::create_directories(dest); // Drawing, ie. unwrapping the nested maps and drawing curves + saving plots - for (auto const &[feature_name, curve_aggregate] : curve_aggregate_map) { - // Configure + draw + save plots + for (auto const &[key, curve_aggregate] : curve_aggregate_map) { + // Plot init sp::Plot plot; apply_config(plot, config); for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { - // The following vectors store point coordinates for average curve and - // individual point drawing - + // Average curve coord vectors std::vector x_curve; std::vector y_curve; + // Point coord vectors std::vector x_points; std::vector y_points; // Build point & curve vectors - for (auto const &[x_value, y_values] : benchmark_curve) { - if (draw_average && !y_values.empty()) { - // Computing and drawing average - x_curve.push_back(x_value); - y_curve.push_back(std::reduce(y_values.begin(), y_values.end()) / - y_values.size()); + for (auto const &[x, y_vec] : benchmark_curve) { + // Building average curve vector + if (draw_average && !y_vec.empty()) { + double const sum = std::reduce(y_vec.begin(), y_vec.end()); + std::size_t const n = y_vec.size(); + + double const y = sum / n; + + x_curve.push_back(x); + y_curve.push_back(y); } + // Building point vector if (draw_points) { - // Drawing points - for (double y_value : y_values) { - x_points.push_back(x_value); - y_points.push_back(y_value); + for (double y : y_vec) { + x_points.push_back(x); + y_points.push_back(y); } } } + // Plot drawing + if (draw_average && !x_curve.empty()) { // Draw average curve plot.drawCurve(x_curve, y_curve).label(bench_name + " average"); @@ -181,7 +227,7 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, } } - save_plot(plot, dest, config); + save_plot(plot, dest / to_string(key, demangle), config); } } From 90458d5676c89fafdb4f9297eb26a43c45edfaba Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 14:58:25 +0200 Subject: [PATCH 44/59] Added getter for default plot options explainer --- grapher/include/grapher/utils/plot.hpp | 3 +++ grapher/lib/grapher/utils/plot.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/grapher/include/grapher/utils/plot.hpp b/grapher/include/grapher/utils/plot.hpp index 426a26b..6871b74 100644 --- a/grapher/include/grapher/utils/plot.hpp +++ b/grapher/include/grapher/utils/plot.hpp @@ -14,6 +14,9 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config); /// Returns the default configuration for apply_config. grapher::json_t base_default_config(); +/// Returns help for base default config. +std::string base_default_config_help(); + /// Plot saving helper function. void save_plot(sciplot::Plot const &plot, std::string const &dest, grapher::json_t const &config); diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index c9ba802..bb8e849 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -19,6 +19,17 @@ grapher::json_t const default_config = { {"plot_file_extensions", grapher::json_t::array({".svg", ".png"})}, }; +std::string base_default_config_help() { + return "General plot parameters:\n" + "- width (int): output width\n" + "- height (int): output height\n" + "- legend_title (string): legend title\n" + "- x_label (string): x axis label\n" + "- y_label (string): y axis label\n" + "- plot_file_extensions (array of string): list of extensions for " + "the export\n"; +} + sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { // Dimensions if (config.contains("width") && config.contains("height")) { From b306cc4a2eab78db93ad3d05914d22c23badad54 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 14:58:58 +0200 Subject: [PATCH 45/59] Small refactoring, better explainer --- grapher/lib/grapher/plotters/compare_by.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 0b0c285..8aee664 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -52,9 +52,6 @@ get_bench_curves(benchmark_set_t const &bset, curve_aggregate_map_t res; for (benchmark_case_t const &bench_case : bset) { - - // std::size_t const iteration_count = bench_case.iterations.size(); - for (benchmark_iteration_t const &iteration : bench_case.iterations) { for (fs::path const &sample : iteration.samples) { grapher::json_t sample_json; @@ -96,7 +93,7 @@ get_bench_curves(benchmark_set_t const &bset, /// Transforms a key into a string that's usable as a path. std::string to_string(key_t const &key, bool demangle = true) { - if (key.size() == 0) { + if (key.empty()) { return "empty"; } @@ -114,9 +111,9 @@ std::string to_string(key_t const &key, bool demangle = true) { // ============================================================================= // OVERRIDES -std::string_view plotter_compare_by_t::get_help() const { - return "Compares all traceEvents with a matching feature.\n" - "- key_ptrs (string array): Array\n" +std::string plotter_compare_by_t::get_help() const { + return "Compares all traceEvents of matching keys with a matching feature.\n" + "- key_ptrs (string array): Pointers to JSON values to use as a key\n" "- value_ptr (string): Pointer to the JSON value to measure\n" "- draw_average (bool): Enable average curve drawing\n" "- draw_points (bool): Enable value point drawing\n" From b78198ab72d494cd02691b1ff1aa194b4747bd83 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:23:35 +0200 Subject: [PATCH 46/59] Removed llvm-timescopes documentation as the file will likely remain unmaintained --- docs/llvm-timescopes.md | 55 ----------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 docs/llvm-timescopes.md diff --git a/docs/llvm-timescopes.md b/docs/llvm-timescopes.md deleted file mode 100644 index 46adf24..0000000 --- a/docs/llvm-timescopes.md +++ /dev/null @@ -1,55 +0,0 @@ -# LLVM Timescopes - -Quick summary of what different Clang/LLVM's TimeScopes measure. - -- ExecuteCompiler - -Complete compiler execution time. - -- Frontend - -Files: `clang/lib/CodeGen/CodeGenAction.cpp`, `clang/lib/Parse/ParseAST.cpp` - -- Source - -File: `clang/lib/Sema/Sema.cpp` - -The Source timer measures pre-processing time. It can be used to ensure that -benchmark generation using macros has a negligible impact on final benchmark -results. - -- ParseClass - -File: `clang/lib/Parse/ParseDeclCXX.cpp` - -- InstantiateClass - -File: `clang/lib/Sema/SemaTemplateInstantiate.cpp` - -- Backend - -File: `clang/lib/CodeGen/BackendUtil.cpp` - -- ParseTemplate - -File: `clang/lib/Parse/ParseTemplate.cpp` - -- OptModule - -File: `llvm/lib/IR/LegacyPassManager.cpp` - -- CodeGenPasses - -File: `clang/lib/CodeGen/BackendUtil.cpp` - -- PerModulePasses - -File: `clang/lib/CodeGen/BackendUtil.cpp` - -- PerFunctionPasses - -File: `clang/lib/CodeGen/BackendUtil.cpp` - -- PerformPendingInstantiations - -File: `clang/lib/Sema/Sema.cpp` From 16888da6788ff1c31c3e2b45ea2bf1393c95de25 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:24:14 +0200 Subject: [PATCH 47/59] ENABLE_DOCS is now a cache variable --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a74e76..55fa03b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(ctbench VERSION 0.1.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) +set(ENABLE_DOCS ON CACHE BOOL "Enable documentation target") + if(${ENABLE_CLANG_TIDY}) set(CMAKE_CXX_CLANG_TIDY clang-tidy -checks=-*,readability-*) endif() From a689173451bb6ab6fb4c910811632203bc34ec2f Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:24:54 +0200 Subject: [PATCH 48/59] Removed get_help, plotter documentation will be moved to doxygen --- grapher/include/grapher/plotters/plotter_i.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/grapher/include/grapher/plotters/plotter_i.hpp b/grapher/include/grapher/plotters/plotter_i.hpp index a6cfc0a..8d3f89d 100644 --- a/grapher/include/grapher/plotters/plotter_i.hpp +++ b/grapher/include/grapher/plotters/plotter_i.hpp @@ -37,9 +37,6 @@ struct plotter_i { std::filesystem::path const &dest, grapher::json_t const &config) const = 0; - /// Returns a help message for end-users. - virtual std::string get_help() const = 0; - /// Returns a default config for end-users. virtual grapher::json_t get_default_config() const = 0; }; From 6403b29feaa3049e4683125168eceb2cc48fcf70 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:25:13 +0200 Subject: [PATCH 49/59] Removed help command from grapher-utils --- grapher/grapher-utils.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/grapher/grapher-utils.cpp b/grapher/grapher-utils.cpp index 4aa4e83..6dc359f 100644 --- a/grapher/grapher-utils.cpp +++ b/grapher/grapher-utils.cpp @@ -14,16 +14,13 @@ lc::opt plotter_opt("plotter", lc::Required, enum command_enum_t { generate_config_v, - help_v, }; -lc::opt command_opt( - "command", lc::Required, lc::desc("Command:"), - lc::values(lc::OptionEnumValue{"get-help", command_enum_t::help_v, - "Get plotter help."}, - lc::OptionEnumValue{"get-default-config", - command_enum_t::generate_config_v, - "Output plotter default config."})); +lc::opt + command_opt("command", lc::Required, lc::desc("Command:"), + lc::values(lc::OptionEnumValue{ + "get-default-config", command_enum_t::generate_config_v, + "Output plotter default config."})); } // namespace cli @@ -38,9 +35,6 @@ int main(int argc, char const *argv[]) { case cli::generate_config_v: llvm::outs() << plotter->get_default_config().dump(2) << '\n'; break; - case cli::help_v: - llvm::outs() << plotter->get_help() << '\n'; - break; } return 0; From 862ea43cfb8883cc64593d84f4728f3b2cce27ab Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:25:56 +0200 Subject: [PATCH 50/59] Removed get_help declarations from plotter declarations --- grapher/include/grapher/plotters/compare.hpp | 2 -- grapher/include/grapher/plotters/compare_by.hpp | 2 -- grapher/include/grapher/plotters/debug.hpp | 2 -- grapher/include/grapher/plotters/grouped_histogram.hpp | 2 -- grapher/include/grapher/plotters/stack.hpp | 2 -- 5 files changed, 10 deletions(-) diff --git a/grapher/include/grapher/plotters/compare.hpp b/grapher/include/grapher/plotters/compare.hpp index 2127342..cd42906 100644 --- a/grapher/include/grapher/plotters/compare.hpp +++ b/grapher/include/grapher/plotters/compare.hpp @@ -10,8 +10,6 @@ struct plotter_compare_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string get_help() const override; - grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/compare_by.hpp b/grapher/include/grapher/plotters/compare_by.hpp index e7797d8..55b5c73 100644 --- a/grapher/include/grapher/plotters/compare_by.hpp +++ b/grapher/include/grapher/plotters/compare_by.hpp @@ -10,8 +10,6 @@ struct plotter_compare_by_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string get_help() const override; - grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/debug.hpp b/grapher/include/grapher/plotters/debug.hpp index adc9f05..6945edf 100644 --- a/grapher/include/grapher/plotters/debug.hpp +++ b/grapher/include/grapher/plotters/debug.hpp @@ -10,8 +10,6 @@ struct plotter_debug_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string get_help() const override; - grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/grouped_histogram.hpp b/grapher/include/grapher/plotters/grouped_histogram.hpp index aeaa0d2..5e2c9e8 100644 --- a/grapher/include/grapher/plotters/grouped_histogram.hpp +++ b/grapher/include/grapher/plotters/grouped_histogram.hpp @@ -10,8 +10,6 @@ struct plotter_grouped_histogram_t : public plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string get_help() const override; - grapher::json_t get_default_config() const override; }; diff --git a/grapher/include/grapher/plotters/stack.hpp b/grapher/include/grapher/plotters/stack.hpp index 9195293..dee06f5 100644 --- a/grapher/include/grapher/plotters/stack.hpp +++ b/grapher/include/grapher/plotters/stack.hpp @@ -12,8 +12,6 @@ struct plotter_stack_t : plotter_i { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; - std::string get_help() const override; - grapher::json_t get_default_config() const override; }; From 93acc980046e6d39631b408ed81026ef89d3d1c5 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:26:27 +0200 Subject: [PATCH 51/59] Replaced get_help functions with doxygen paragraphs --- grapher/lib/grapher/plotters/compare.cpp | 15 ++++++++++----- grapher/lib/grapher/plotters/compare_by.cpp | 18 +++++++++--------- grapher/lib/grapher/plotters/debug.cpp | 8 +++----- .../lib/grapher/plotters/grouped_histogram.cpp | 5 ----- grapher/lib/grapher/plotters/stack.cpp | 9 +++------ 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index df006f6..e571b35 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -21,11 +21,6 @@ namespace grapher::plotters { -std::string plotter_compare_t::get_help() const { - return "For each group descriptor, generates a graph comparing all " - "benchmark cases in the set."; -} - grapher::json_t plotter_compare_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); @@ -41,6 +36,16 @@ grapher::json_t plotter_compare_t::get_default_config() const { return res; } +/// For each group descriptor, generates a graph comparing all benchmark cases +/// in the set. +/// +/// JSON config parameters: +/// - value_json_pointer (string): pointer to JSON value to measure +/// - draw_average (bool): Enable average curve drawing +/// - draw_points (bool): Enable point value drawing +/// - group_descriptors (group descriptors): See group_descriptor_t +/// documentation + void plotter_compare_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 8aee664..4f69d2f 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -111,15 +111,6 @@ std::string to_string(key_t const &key, bool demangle = true) { // ============================================================================= // OVERRIDES -std::string plotter_compare_by_t::get_help() const { - return "Compares all traceEvents of matching keys with a matching feature.\n" - "- key_ptrs (string array): Pointers to JSON values to use as a key\n" - "- value_ptr (string): Pointer to the JSON value to measure\n" - "- draw_average (bool): Enable average curve drawing\n" - "- draw_points (bool): Enable value point drawing\n" - "- demangle (bool): Demangle C++ symbol names\n"; -} - grapher::json_t plotter_compare_by_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); @@ -143,6 +134,15 @@ grapher::json_t plotter_compare_by_t::get_default_config() const { return res; } +/// Compares all traceEvents of matching keys with a matching feature. +/// +/// JSON config parameters: +/// - key_ptrs (string array): pointers to JSON values to use as a key +/// - value_ptr (string): pointer to the JSON value to measure +/// - draw_average (bool): enable average curve drawing +/// - draw_points (bool): enable value point drawing +/// - demangle (bool): demangle C++ symbol names + void plotter_compare_by_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index 1f84bd0..f4604ff 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -5,17 +5,15 @@ namespace grapher::plotters { -std::string plotter_debug_t::get_help() const { - return "Debug plotter. Outputs various statistics on benchmark categories to " - "debug category building or traversal issues."; -} - grapher::json_t plotter_debug_t::get_default_config() const { grapher::json_t res; res["plotter"] = "debug"; return res; } +/// Debug plotter. Outputs various statistics on benchmark categories to debug +/// category building or traversal issues. + void plotter_debug_t::plot(const benchmark_set_t &bset, const std::filesystem::path &dest, const grapher::json_t & /* config */) const { diff --git a/grapher/lib/grapher/plotters/grouped_histogram.cpp b/grapher/lib/grapher/plotters/grouped_histogram.cpp index 5ef4dd1..0cd79fa 100644 --- a/grapher/lib/grapher/plotters/grouped_histogram.cpp +++ b/grapher/lib/grapher/plotters/grouped_histogram.cpp @@ -7,11 +7,6 @@ namespace grapher::plotters { -std::string plotter_grouped_histogram_t::get_help() const { - // TODO: Add doc - return "TODO"; -} - grapher::json_t plotter_grouped_histogram_t::get_default_config() const { // TODO return grapher::base_default_config(); diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 59b1d5a..6420d8d 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -18,12 +18,6 @@ namespace grapher::plotters { -std::string plotter_stack_t::get_help() const { - return "For each benchmark in the category, generates a stakcked curve graph " - "where each curve corresponds to a matcher in the \'matchers\' JSON " - "field."; -} - grapher::json_t plotter_stack_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); @@ -40,6 +34,9 @@ grapher::json_t plotter_stack_t::get_default_config() const { return res; } +/// For each benchmark in the category, generates a stakcked curve graph where +/// each curve corresponds to a matcher in the matchers JSON field. + void plotter_stack_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { From 1f1ea64d00324eed0e4e1a4e57760e89cf76a15b Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Mon, 16 May 2022 15:34:15 +0200 Subject: [PATCH 52/59] Renamed plotter_i to plotter_base_t --- grapher/grapher-utils.cpp | 1 - grapher/include/grapher/plotters/compare.hpp | 4 ++-- grapher/include/grapher/plotters/compare_by.hpp | 4 ++-- grapher/include/grapher/plotters/debug.hpp | 4 ++-- .../include/grapher/plotters/grouped_histogram.hpp | 4 ++-- .../plotters/{plotter_i.hpp => plotter_base.hpp} | 13 ++++++------- grapher/include/grapher/plotters/stack.hpp | 4 ++-- grapher/lib/grapher/plotters/plotters.cpp | 2 +- grapher/lib/grapher/utils/plot.cpp | 2 +- 9 files changed, 18 insertions(+), 20 deletions(-) rename grapher/include/grapher/plotters/{plotter_i.hpp => plotter_base.hpp} (78%) diff --git a/grapher/grapher-utils.cpp b/grapher/grapher-utils.cpp index 6dc359f..98d28a1 100644 --- a/grapher/grapher-utils.cpp +++ b/grapher/grapher-utils.cpp @@ -1,7 +1,6 @@ #include #include -#include "grapher/plotters/plotter_i.hpp" #include "grapher/plotters/plotters.hpp" namespace cli { diff --git a/grapher/include/grapher/plotters/compare.hpp b/grapher/include/grapher/plotters/compare.hpp index cd42906..cd97f9f 100644 --- a/grapher/include/grapher/plotters/compare.hpp +++ b/grapher/include/grapher/plotters/compare.hpp @@ -1,12 +1,12 @@ #pragma once -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher::plotters { /// \ingroup plotters -struct plotter_compare_t : plotter_i { +struct plotter_compare_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/compare_by.hpp b/grapher/include/grapher/plotters/compare_by.hpp index 55b5c73..a2a9265 100644 --- a/grapher/include/grapher/plotters/compare_by.hpp +++ b/grapher/include/grapher/plotters/compare_by.hpp @@ -1,12 +1,12 @@ #pragma once -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher::plotters { /// \ingroup plotters -struct plotter_compare_by_t : plotter_i { +struct plotter_compare_by_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/debug.hpp b/grapher/include/grapher/plotters/debug.hpp index 6945edf..8feb90d 100644 --- a/grapher/include/grapher/plotters/debug.hpp +++ b/grapher/include/grapher/plotters/debug.hpp @@ -1,12 +1,12 @@ #pragma once -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher::plotters { /// \ingroup plotters /// Debug plotter, outputs statistics on benchmark categories -struct plotter_debug_t : public plotter_i { +struct plotter_debug_t : public plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/grouped_histogram.hpp b/grapher/include/grapher/plotters/grouped_histogram.hpp index 5e2c9e8..ebdc33a 100644 --- a/grapher/include/grapher/plotters/grouped_histogram.hpp +++ b/grapher/include/grapher/plotters/grouped_histogram.hpp @@ -1,12 +1,12 @@ #pragma once -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher::plotters { /// \ingroup plotters /// Display bars -struct plotter_grouped_histogram_t : public plotter_i { +struct plotter_grouped_histogram_t : public plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/plotter_i.hpp b/grapher/include/grapher/plotters/plotter_base.hpp similarity index 78% rename from grapher/include/grapher/plotters/plotter_i.hpp rename to grapher/include/grapher/plotters/plotter_base.hpp index 8d3f89d..9fa5312 100644 --- a/grapher/include/grapher/plotters/plotter_i.hpp +++ b/grapher/include/grapher/plotters/plotter_base.hpp @@ -12,9 +12,9 @@ namespace grapher { /// \addtogroup plotters /// -/// Plotters are objects that inherit the plotter_i virtual interface, and thus -/// override the plotter_i::plot, plotter_i::get_help, and -/// plotter_i::get_default_config methods. +/// Plotters are objects that inherit the plotter_base_t virtual interface, and +/// thus override the plotter_base_t::plot, and +/// plotter_base_t::get_default_config methods. /// /// They're used to generate plots from a grapher::category_t object and a /// grapher::json_t object for configuration. @@ -26,10 +26,9 @@ namespace grapher { /// Interface for plotters. Plotters should be able to: /// - Plot a ctbench::category_t with a grapher::json_t configuration object, -/// - Output help as a std::string, /// - Output a default config as a grapher::json_t object. -struct plotter_i { - virtual ~plotter_i() = default; +struct plotter_base_t { + virtual ~plotter_base_t() = default; /// Plots a given ctbench::category_t at the given destination. /// It receives a grapher::json_t object as a config. @@ -42,6 +41,6 @@ struct plotter_i { }; /// Polymorphic representation of a plotter. -using plotter_t = std::unique_ptr; +using plotter_t = std::unique_ptr; } // namespace grapher diff --git a/grapher/include/grapher/plotters/stack.hpp b/grapher/include/grapher/plotters/stack.hpp index dee06f5..ac87cdd 100644 --- a/grapher/include/grapher/plotters/stack.hpp +++ b/grapher/include/grapher/plotters/stack.hpp @@ -1,6 +1,6 @@ #pragma once -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher::plotters { @@ -8,7 +8,7 @@ namespace grapher::plotters { /// Generates one plot per benchmark where all the targeted features are /// visualized as stacked curves. -struct plotter_stack_t : plotter_i { +struct plotter_stack_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/lib/grapher/plotters/plotters.cpp b/grapher/lib/grapher/plotters/plotters.cpp index 6e8ab43..f160f23 100644 --- a/grapher/lib/grapher/plotters/plotters.cpp +++ b/grapher/lib/grapher/plotters/plotters.cpp @@ -1,5 +1,5 @@ #include "grapher/plotters/plotters.hpp" -#include "grapher/plotters/plotter_i.hpp" +#include "grapher/plotters/plotter_base.hpp" namespace grapher { diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp index bb8e849..0114b6d 100644 --- a/grapher/lib/grapher/utils/plot.cpp +++ b/grapher/lib/grapher/utils/plot.cpp @@ -1,10 +1,10 @@ #include #include + #include #include "grapher/core.hpp" -#include "grapher/plotters/plotter_i.hpp" #include "grapher/utils/plot.hpp" namespace grapher { From 5857044cd3faa021ec6d4772acad559141401afa Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Tue, 17 May 2022 15:24:20 +0200 Subject: [PATCH 53/59] Fused utils/config and utils/plot into utils/json, improved documentation by adding a page for JSON configs --- grapher/configs/readme.md | 39 ----- grapher/include/grapher/plotters/compare.hpp | 43 ++++- .../include/grapher/plotters/compare_by.hpp | 35 +++- grapher/include/grapher/plotters/debug.hpp | 12 +- .../grapher/plotters/grouped_histogram.hpp | 2 - .../include/grapher/plotters/plotter_base.hpp | 8 +- grapher/include/grapher/plotters/plotters.hpp | 10 ++ grapher/include/grapher/plotters/stack.hpp | 42 ++++- grapher/include/grapher/utils/config.hpp | 44 ----- grapher/include/grapher/utils/json.hpp | 49 +++++- grapher/include/grapher/utils/plot.hpp | 24 --- grapher/lib/grapher/plotters/compare.cpp | 14 -- grapher/lib/grapher/plotters/compare_by.cpp | 19 --- grapher/lib/grapher/plotters/debug.cpp | 3 - .../grapher/plotters/grouped_histogram.cpp | 1 - grapher/lib/grapher/plotters/stack.cpp | 19 +-- grapher/lib/grapher/utils/config.cpp | 85 ---------- grapher/lib/grapher/utils/json.cpp | 150 +++++++++++++++++- grapher/lib/grapher/utils/plot.cpp | 81 ---------- 19 files changed, 335 insertions(+), 345 deletions(-) delete mode 100644 grapher/configs/readme.md delete mode 100644 grapher/include/grapher/utils/config.hpp delete mode 100644 grapher/include/grapher/utils/plot.hpp delete mode 100644 grapher/lib/grapher/utils/config.cpp delete mode 100644 grapher/lib/grapher/utils/plot.cpp diff --git a/grapher/configs/readme.md b/grapher/configs/readme.md deleted file mode 100644 index dcecc63..0000000 --- a/grapher/configs/readme.md +++ /dev/null @@ -1,39 +0,0 @@ -# Useful configs - -Useful configs to break down time-trace data. - -## `feature_comparison.json` - -Generates comparison graphs for every major compile pass, namely: - -* `ExecuteCompiler` -* `Frontend` -* `Backend` -* `ModuleToFunctionPassAdaptor` -* `ModuleInlinerWrapperPass` -* `OptModule` -* `Source` -* `ParseClass` -* `ParseTemplate` -* `InstantiateClass` -* `InstantiateFunction` -* `CodeGen Function` -* `PerformPendingInstantiations` - -## `ExecuteCompiler-stacked.json` - * `Frontend` - * `Backend` - -## `Backend-stacked.json` - * `ModuleToFunctionPassAdaptor` - * `ModuleInlinerWrapperPass` - * `OptModule` - -## `Frontend-stacked.json` - * `Source` - * `ParseClass` - * `ParseTemplate` - * `InstantiateClass` - * `InstantiateFunction` - * `CodeGen Function` - * `PerformPendingInstantiations` diff --git a/grapher/include/grapher/plotters/compare.hpp b/grapher/include/grapher/plotters/compare.hpp index cd97f9f..2978f72 100644 --- a/grapher/include/grapher/plotters/compare.hpp +++ b/grapher/include/grapher/plotters/compare.hpp @@ -4,7 +4,48 @@ namespace grapher::plotters { -/// \ingroup plotters +/// For each group descriptor, generates a graph comparing all benchmark cases +/// in the set. +/// +/// Plotter-specific JSON parameters: +/// - `value_json_pointer` (`string`): pointer to JSON value to measure +/// - `draw_average` (`bool`): enable average curve drawing +/// - `draw_points` (`bool`): enable point value drawing +/// - `group_descriptors` (group descriptors): see group_descriptor_t +/// documentation +/// +/// \copydetails base_default_config +/// +/// Example config: +/// \code{.json} +/// { +/// "draw_average": true, +/// "draw_points": true, +/// "group_descriptors": [ +/// { +/// "name": "All", +/// "predicates": [ +/// { +/// "pointer": "/name", +/// "regex": "*", +/// "type": "regex" +/// } +/// ] +/// } +/// ], +/// "height": 500, +/// "legend_title": "Timings", +/// "plot_file_extensions": [ +/// ".svg", +/// ".png" +/// ], +/// "plotter": "compare", +/// "value_json_pointer": "/dur", +/// "width": 1500, +/// "x_label": "Benchmark size factor", +/// "y_label": "Time (µs)" +/// } +/// \endcode struct plotter_compare_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, diff --git a/grapher/include/grapher/plotters/compare_by.hpp b/grapher/include/grapher/plotters/compare_by.hpp index a2a9265..fcde533 100644 --- a/grapher/include/grapher/plotters/compare_by.hpp +++ b/grapher/include/grapher/plotters/compare_by.hpp @@ -4,7 +4,40 @@ namespace grapher::plotters { -/// \ingroup plotters +/// Generates a benchmark comparison graph for every matching key built from the +/// list of JSON pointers. +/// +/// JSON config parameters: +/// - `key_ptrs` (string array): pointers to JSON values to use as a key +/// - `value_ptr` (`string`): pointer to the JSON value to measure +/// - `draw_average` (`bool`): enable average curve drawing +/// - `draw_points` (`bool`): enable value point drawing +/// - `demangle` (`bool`): demangle C++ symbol names +/// +/// \copydoc base_default_config +/// +/// Example config: +/// \code{.json} +/// { +/// "draw_average": true, +/// "draw_points": true, +/// "height": 500, +/// "key_ptrs": [ +/// "/name", +/// "/args/detail" +/// ], +/// "legend_title": "Timings", +/// "plot_file_extensions": [ +/// ".svg", +/// ".png" +/// ], +/// "plotter": "compare_by", +/// "value_ptr": "/dur", +/// "width": 1500, +/// "x_label": "Benchmark size factor", +/// "y_label": "Time (µs)" +/// } +/// \endcode struct plotter_compare_by_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, diff --git a/grapher/include/grapher/plotters/debug.hpp b/grapher/include/grapher/plotters/debug.hpp index 8feb90d..0dadb08 100644 --- a/grapher/include/grapher/plotters/debug.hpp +++ b/grapher/include/grapher/plotters/debug.hpp @@ -4,8 +4,16 @@ namespace grapher::plotters { -/// \ingroup plotters -/// Debug plotter, outputs statistics on benchmark categories +/// Debug plotter. Outputs various statistics on benchmark categories to debug +/// category building or traversal issues. +/// +/// Example config: +/// \code{.json} +/// { +/// "plotter": "debug" +/// } +/// \endcode + struct plotter_debug_t : public plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/grouped_histogram.hpp b/grapher/include/grapher/plotters/grouped_histogram.hpp index ebdc33a..4f75659 100644 --- a/grapher/include/grapher/plotters/grouped_histogram.hpp +++ b/grapher/include/grapher/plotters/grouped_histogram.hpp @@ -4,8 +4,6 @@ namespace grapher::plotters { -/// \ingroup plotters -/// Display bars struct plotter_grouped_histogram_t : public plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/plotters/plotter_base.hpp b/grapher/include/grapher/plotters/plotter_base.hpp index 9fa5312..d71b8c4 100644 --- a/grapher/include/grapher/plotters/plotter_base.hpp +++ b/grapher/include/grapher/plotters/plotter_base.hpp @@ -8,10 +8,6 @@ namespace grapher { -/// \defgroup plotters Plot generators - -/// \addtogroup plotters -/// /// Plotters are objects that inherit the plotter_base_t virtual interface, and /// thus override the plotter_base_t::plot, and /// plotter_base_t::get_default_config methods. @@ -21,9 +17,7 @@ namespace grapher { /// /// The plotter interface can also be used to implement other exportation modes /// such as CSV, plain text, debug, or even HTML export if you want. - -/// \ingroup plotters - +/// /// Interface for plotters. Plotters should be able to: /// - Plot a ctbench::category_t with a grapher::json_t configuration object, /// - Output a default config as a grapher::json_t object. diff --git a/grapher/include/grapher/plotters/plotters.hpp b/grapher/include/grapher/plotters/plotters.hpp index 6ab9f8b..bc861b8 100644 --- a/grapher/include/grapher/plotters/plotters.hpp +++ b/grapher/include/grapher/plotters/plotters.hpp @@ -12,6 +12,16 @@ namespace grapher { +/// \page plotter_config Plotter configuration documentation +/// # compare +/// \copydoc grapher::plotters::plotter_compare_t +/// # compare_by +/// \copydoc grapher::plotters::plotter_compare_by_t +/// # debug +/// \copydoc grapher::plotters::plotter_debug_t +/// # stack +/// \copydoc grapher::plotters::plotter_stack_t + /// Plotter type enumeration. One per plotter. enum plotter_type_t { compare_v, diff --git a/grapher/include/grapher/plotters/stack.hpp b/grapher/include/grapher/plotters/stack.hpp index ac87cdd..bef1304 100644 --- a/grapher/include/grapher/plotters/stack.hpp +++ b/grapher/include/grapher/plotters/stack.hpp @@ -4,10 +4,46 @@ namespace grapher::plotters { -/// \ingroup plotters +/// For each benchmark in the category, generates a stakcked curve graph +/// where each curve corresponds to a matcher in the matchers JSON field. +/// +/// Plotter-specific JSON parameters: +/// - `value_json_pointer` (`string`): pointer to JSON value to measure +/// - `group_descriptors` (group descriptors): see group_descriptor_t +/// documentation +/// +/// \copydetails base_default_config +/// +/// Example config: +/// \code{.json} +/// { +/// "group_descriptors": [ +/// { +/// "name": "All", +/// "predicates": [ +/// { +/// "pointer": "/name", +/// "regex": "*", +/// "type": "regex" +/// } +/// ] +/// } +/// ], +/// "height": 500, +/// "legend_title": "Timings", +/// "name_json_pointer": "/name", +/// "plot_file_extensions": [ +/// ".svg", +/// ".png" +/// ], +/// "plotter": "stack", +/// "value_json_pointer": "/dur", +/// "width": 1500, +/// "x_label": "Benchmark size factor", +/// "y_label": "Time (µs)" +/// } +/// \endcode -/// Generates one plot per benchmark where all the targeted features are -/// visualized as stacked curves. struct plotter_stack_t : plotter_base_t { void plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const override; diff --git a/grapher/include/grapher/utils/config.hpp b/grapher/include/grapher/utils/config.hpp deleted file mode 100644 index 8ee920f..0000000 --- a/grapher/include/grapher/utils/config.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include - -#include - -/// \file -/// Common structure and function definitions that can be used for plotter -/// configuration. - -namespace grapher { - -/// Named set of constraint. -struct group_descriptor_t { - std::string name; - grapher::json_t::array_t predicates; -}; - -/// Returns a default group descriptor as an example. -group_descriptor_t get_default_group_descriptor(); - -/// Extracts predicates from a group descriptor. -std::vector get_predicates(group_descriptor_t const &descriptor); - -grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, - grapher::json_t::array_t const &events); - -/// Exports a single group descriptor into a JSON object. -grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor); - -/// Exports a vector of group descriptors into a JSON object. -grapher::json_t::array_t -write_descriptors(std::vector const &descriptors); - -/// Reads a single descriptor. -group_descriptor_t read_descriptor(grapher::json_t const &j); - -/// Reads descriptors from a predicate list. -std::vector -read_descriptors(grapher::json_t::array_t const &list); - -} // namespace grapher diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 8d05e3e..01e3902 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -9,8 +9,10 @@ #include +#include + #include "grapher/core.hpp" -#include "grapher/utils/config.hpp" +#include "grapher/predicates.hpp" #include "grapher/utils/error.hpp" namespace grapher { @@ -111,4 +113,49 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, return object[field_location].template get_ref(); } +// ============================================================================= +// Group descriptors + +/// Named set of constraint. +struct group_descriptor_t { + std::string name; + grapher::json_t::array_t predicates; +}; + +/// Returns a default group descriptor as an example. +group_descriptor_t get_default_group_descriptor(); + +/// Extracts predicates from a group descriptor. +std::vector get_predicates(group_descriptor_t const &descriptor); + +grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, + grapher::json_t::array_t const &events); + +/// Exports a single group descriptor into a JSON object. +grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor); + +/// Exports a vector of group descriptors into a JSON object. +grapher::json_t::array_t +write_descriptors(std::vector const &descriptors); + +/// Reads a single descriptor. +group_descriptor_t read_descriptor(grapher::json_t const &j); + +/// Reads descriptors from a predicate list. +std::vector +read_descriptors(grapher::json_t::array_t const &list); + +// ============================================================================= +// Plotter configuration + +/// Plot saving helper function. +void save_plot(sciplot::Plot const &plot, std::string const &dest, + grapher::json_t const &config); + +/// Returns the default configuration for apply_config. +grapher::json_t base_default_config(); + +/// Apply config to plot. +sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config); + } // namespace grapher diff --git a/grapher/include/grapher/utils/plot.hpp b/grapher/include/grapher/utils/plot.hpp deleted file mode 100644 index 6871b74..0000000 --- a/grapher/include/grapher/utils/plot.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include - -#include "grapher/core.hpp" - -namespace grapher { - -/// Apply config to plot. -sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config); - -/// Returns the default configuration for apply_config. -grapher::json_t base_default_config(); - -/// Returns help for base default config. -std::string base_default_config_help(); - -/// Plot saving helper function. -void save_plot(sciplot::Plot const &plot, std::string const &dest, - grapher::json_t const &config); - -} // namespace grapher diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index e571b35..0bfb40c 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -14,10 +14,8 @@ #include "grapher/core.hpp" #include "grapher/plotters/compare.hpp" #include "grapher/predicates.hpp" -#include "grapher/utils/config.hpp" #include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" -#include "grapher/utils/plot.hpp" namespace grapher::plotters { @@ -36,16 +34,6 @@ grapher::json_t plotter_compare_t::get_default_config() const { return res; } -/// For each group descriptor, generates a graph comparing all benchmark cases -/// in the set. -/// -/// JSON config parameters: -/// - value_json_pointer (string): pointer to JSON value to measure -/// - draw_average (bool): Enable average curve drawing -/// - draw_points (bool): Enable point value drawing -/// - group_descriptors (group descriptors): See group_descriptor_t -/// documentation - void plotter_compare_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { @@ -57,8 +45,6 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, bool draw_average = config.value("draw_average", true); bool draw_points = config.value("draw_points", true); - std::string plot_file_extension = config.value("plot_file_extension", ".svg"); - std::vector group_descriptors = read_descriptors( json_at_ref(config, "group_descriptors")); diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 4f69d2f..7dde257 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -15,10 +15,8 @@ #include "grapher/core.hpp" #include "grapher/plotters/compare_by.hpp" -#include "grapher/utils/config.hpp" #include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" -#include "grapher/utils/plot.hpp" namespace grapher::plotters { @@ -117,32 +115,15 @@ grapher::json_t plotter_compare_by_t::get_default_config() const { // Plotter name res["plotter"] = "compare_by"; - // List of pointers to generate a key res["key_ptrs"] = json_t::array({"/name", "/args/detail"}); - - // Pointer to the values res["value_ptr"] = "/dur"; - - // Draw average curve res["draw_average"] = true; - // Draw value points res["draw_points"] = true; - - // Demangle or not res["demangle"] = true; return res; } -/// Compares all traceEvents of matching keys with a matching feature. -/// -/// JSON config parameters: -/// - key_ptrs (string array): pointers to JSON values to use as a key -/// - value_ptr (string): pointer to the JSON value to measure -/// - draw_average (bool): enable average curve drawing -/// - draw_points (bool): enable value point drawing -/// - demangle (bool): demangle C++ symbol names - void plotter_compare_by_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index f4604ff..ec58cf1 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -11,9 +11,6 @@ grapher::json_t plotter_debug_t::get_default_config() const { return res; } -/// Debug plotter. Outputs various statistics on benchmark categories to debug -/// category building or traversal issues. - void plotter_debug_t::plot(const benchmark_set_t &bset, const std::filesystem::path &dest, const grapher::json_t & /* config */) const { diff --git a/grapher/lib/grapher/plotters/grouped_histogram.cpp b/grapher/lib/grapher/plotters/grouped_histogram.cpp index 0cd79fa..7b042fa 100644 --- a/grapher/lib/grapher/plotters/grouped_histogram.cpp +++ b/grapher/lib/grapher/plotters/grouped_histogram.cpp @@ -3,7 +3,6 @@ #include "grapher/plotters/grouped_histogram.hpp" #include "grapher/plotters/plotters.hpp" #include "grapher/utils/json.hpp" -#include "grapher/utils/plot.hpp" namespace grapher::plotters { diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index 6420d8d..b6ab8ef 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -11,10 +11,8 @@ #include "grapher/core.hpp" #include "grapher/plotters/stack.hpp" #include "grapher/predicates.hpp" -#include "grapher/utils/config.hpp" #include "grapher/utils/error.hpp" #include "grapher/utils/json.hpp" -#include "grapher/utils/plot.hpp" namespace grapher::plotters { @@ -22,34 +20,21 @@ grapher::json_t plotter_stack_t::get_default_config() const { grapher::json_t res = grapher::base_default_config(); res["plotter"] = "stack"; - - // Basic values, probably no need to change them res["value_json_pointer"] = "/dur"; - res["name_json_pointer"] = "/name"; - - // Some matchers as an example... res["group_descriptors"] = write_descriptors({get_default_group_descriptor()}); return res; } -/// For each benchmark in the category, generates a stakcked curve graph where -/// each curve corresponds to a matcher in the matchers JSON field. - void plotter_stack_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { - // Config + // Config reading grapher::json_t::json_pointer feature_value_jptr( config.value("value_json_pointer", "/dur")); - grapher::json_t::json_pointer feature_name_jptr( - config.value("name_json_pointer", "/name")); - - std::string plot_file_extension = config.value("plot_file_extension", ".svg"); - std::vector descriptors = read_descriptors( json_at_ref(config, "group_descriptors")); @@ -57,7 +42,7 @@ void plotter_stack_t::plot(benchmark_set_t const &bset, std::vector plots; - // Saving max y value for normalization + // Storing max y value for normalization double max_y_val = 0.; /// Draws a stacked curve graph for a given benchmark diff --git a/grapher/lib/grapher/utils/config.cpp b/grapher/lib/grapher/utils/config.cpp deleted file mode 100644 index 54ab45b..0000000 --- a/grapher/lib/grapher/utils/config.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "grapher/utils/config.hpp" - -#include -#include -#include -#include - -#include - -#include -#include - -#include "grapher/core.hpp" -#include "grapher/predicates.hpp" -#include "grapher/utils/json.hpp" - -namespace grapher { - -group_descriptor_t get_default_group_descriptor() { - return {.name = "All", - .predicates = grapher::json_t::array({grapher::json_t{ - {"type", "regex"}, - {"pointer", "/name"}, - {"regex", "*"}, - }})}; -} - -std::vector get_predicates(group_descriptor_t const &descriptor) { - std::vector predicates; - - predicates.reserve(descriptor.predicates.size()); - std::ranges::transform(descriptor.predicates, std::back_inserter(predicates), - get_predicate); - return predicates; -} - -grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, - grapher::json_t::array_t const &events) { - std::vector predicates = get_predicates(descriptor); - - grapher::json_t::array_t res; - - std::ranges::copy_if( - events, std::back_inserter(res), [&](grapher::json_t const &event) { - return std::ranges::all_of( - predicates, [&](predicate_t const &p) { return p(event); }); - }); - - return res; -} - -group_descriptor_t read_descriptor(grapher::json_t const &j) { - return {.name = json_at_ref(j, "name"), - .predicates = - json_at_ref(j, "predicates")}; -} - -grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor) { - return { - {"name", descriptor.name}, - {"predicates", descriptor.predicates}, - }; -} - -grapher::json_t::array_t -write_descriptors(std::vector const &descriptors) { - grapher::json_t::array_t res; - res.reserve(descriptors.size()); - - for (group_descriptor_t const &d : descriptors) { - res.push_back(group_descriptor_json(d)); - } - return res; -} - -std::vector -read_descriptors(grapher::json_t::array_t const &list) { - std::vector res; - res.reserve(list.size()); - std::transform(list.begin(), list.end(), std::back_inserter(res), - &read_descriptor); - return res; -} - -} // namespace grapher diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index 8b2c7d8..d0860a1 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -1,7 +1,6 @@ #include "grapher/utils/json.hpp" #include "grapher/core.hpp" #include "grapher/predicates.hpp" -#include "grapher/utils/config.hpp" #include #include @@ -11,6 +10,91 @@ namespace grapher { +/// Default group descriptor values: +/// +/// \code{.js} +/// { +/// "group_descriptors": [ +/// { +/// "name": "All", +/// "predicates": [ +/// { +/// "pointer": "/name", +/// "regex": "*", +/// "type": "regex" +/// } +/// ] +/// } +/// ] +/// } +/// \endcode + +group_descriptor_t get_default_group_descriptor() { + return {.name = "All", + .predicates = grapher::json_t::array({grapher::json_t{ + {"type", "regex"}, + {"pointer", "/name"}, + {"regex", "*"}, + }})}; +} + +std::vector get_predicates(group_descriptor_t const &descriptor) { + std::vector predicates; + + predicates.reserve(descriptor.predicates.size()); + std::ranges::transform(descriptor.predicates, std::back_inserter(predicates), + get_predicate); + return predicates; +} + +grapher::json_t::array_t extract_group(group_descriptor_t const &descriptor, + grapher::json_t::array_t const &events) { + std::vector predicates = get_predicates(descriptor); + + grapher::json_t::array_t res; + + std::ranges::copy_if( + events, std::back_inserter(res), [&](grapher::json_t const &event) { + return std::ranges::all_of( + predicates, [&](predicate_t const &p) { return p(event); }); + }); + + return res; +} + +group_descriptor_t read_descriptor(grapher::json_t const &j) { + return {.name = json_at_ref(j, "name"), + .predicates = + json_at_ref(j, "predicates")}; +} + +grapher::json_t group_descriptor_json(group_descriptor_t const &descriptor) { + return { + {"name", descriptor.name}, + {"predicates", descriptor.predicates}, + }; +} + +grapher::json_t::array_t +write_descriptors(std::vector const &descriptors) { + grapher::json_t::array_t res; + res.reserve(descriptors.size()); + + for (group_descriptor_t const &d : descriptors) { + res.push_back(group_descriptor_json(d)); + } + return res; +} + +std::vector +read_descriptors(grapher::json_t::array_t const &list) { + std::vector res; + res.reserve(list.size()); + std::transform(list.begin(), list.end(), std::back_inserter(res), + &read_descriptor); + return res; +} + std::vector get_values(benchmark_iteration_t const &iteration, std::vector const &predicates, grapher::json_t::json_pointer value_jptr) { @@ -52,4 +136,68 @@ grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b) { return a; } +void save_plot(sciplot::Plot const &plot, std::string const &dest, + grapher::json_t const &config) { + namespace fs = std::filesystem; + std::vector plot_file_extensions = config.value( + "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); + + // Saving file for all extensions + for (std::string const &extension : plot_file_extensions) { + fs::path file_dest = dest + extension; + fs::create_directories(file_dest.parent_path()); + + constexpr std::size_t max_filename_size = 256; + + // Avoid filename hitting OS filename size limit (yes, this is bad) + if (file_dest.filename().string().size() > max_filename_size) { + std::string new_filename = file_dest.stem(); + new_filename.resize(max_filename_size - extension.size()); + file_dest.replace_filename(new_filename); + } + + plot.save(dest + extension); + } +} + +sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { + // Dimensions + if (config.contains("width") && config.contains("height")) { + plot.size(config["width"], config["height"]); + } + + // Labels + if (config.contains("legend_title")) { + plot.legend().atOutsideRightTop().title(config["legend_title"]); + } + + if (config.contains("x_label")) { + plot.xlabel(config["x_label"]); + } + + if (config.contains("ylabel")) { + plot.ylabel(config["y_label"]); + } + + return plot; +} + +grapher::json_t const default_config = { + {"width", 1500}, + {"height", 500}, + {"legend_title", "Timings"}, + {"x_label", "Benchmark size factor"}, + {"y_label", "Time (µs)"}, + {"plot_file_extensions", grapher::json_t::array({".svg", ".png"})}, +}; + +/// Common plot JSON parameters: +/// - `width` (`int`): Graph width +/// - `height` (`int`): Graph height +/// - `legend_title` (`string`): Graph legend title +/// - `x_label` (`string`): X axis label +/// - `y_label` (`string`): Y axis label +/// - `plot_file_extensions` (string array): List of extensions for the export +grapher::json_t base_default_config() { return default_config; } + } // namespace grapher diff --git a/grapher/lib/grapher/utils/plot.cpp b/grapher/lib/grapher/utils/plot.cpp deleted file mode 100644 index 0114b6d..0000000 --- a/grapher/lib/grapher/utils/plot.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include - -#include - -#include "grapher/core.hpp" -#include "grapher/utils/plot.hpp" - -namespace grapher { - -/// Default config file for plots -grapher::json_t const default_config = { - {"width", 1500}, - {"height", 500}, - {"legend_title", "Timings"}, - {"x_label", "Benchmark size factor"}, - {"y_label", "Time (µs)"}, - {"plot_file_extensions", grapher::json_t::array({".svg", ".png"})}, -}; - -std::string base_default_config_help() { - return "General plot parameters:\n" - "- width (int): output width\n" - "- height (int): output height\n" - "- legend_title (string): legend title\n" - "- x_label (string): x axis label\n" - "- y_label (string): y axis label\n" - "- plot_file_extensions (array of string): list of extensions for " - "the export\n"; -} - -sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { - // Dimensions - if (config.contains("width") && config.contains("height")) { - plot.size(config["width"], config["height"]); - } - - // Labels - if (config.contains("legend_title")) { - plot.legend().atOutsideRightTop().title(config["legend_title"]); - } - - if (config.contains("x_label")) { - plot.xlabel(config["x_label"]); - } - - if (config.contains("ylabel")) { - plot.ylabel(config["y_label"]); - } - - return plot; -} - -grapher::json_t base_default_config() { return default_config; } - -void save_plot(sciplot::Plot const &plot, std::string const &dest, - grapher::json_t const &config) { - namespace fs = std::filesystem; - std::vector plot_file_extensions = config.value( - "plot_file_extensions", grapher::json_t::array({".svg", ".png"})); - - // Saving file for all extensions - for (std::string const &extension : plot_file_extensions) { - fs::path file_dest = dest + extension; - fs::create_directories(file_dest.parent_path()); - - constexpr std::size_t max_filename_size = 256; - - // Avoid filename hitting OS filename size limit (yes, this is bad) - if (file_dest.filename().string().size() > max_filename_size) { - std::string new_filename = file_dest.stem(); - new_filename.resize(max_filename_size - extension.size()); - file_dest.replace_filename(new_filename); - } - - plot.save(dest + extension); - } -} - -} // namespace grapher From c40a05e15638b84c41fa91ab1d301db855f68453 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 24 Jun 2022 01:07:09 +0200 Subject: [PATCH 54/59] Improved debug messages for json ref getter --- grapher/include/grapher/utils/json.hpp | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index 01e3902..fd7e893 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -61,7 +61,7 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, if constexpr (std::is_same::value) { check(object[field_location].type() == json_t::value_t::number_unsigned, - fmt::format("Invalid field {}, expected string:\n{}", + fmt::format("Invalid field {}, expected unsigned number:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); } @@ -70,7 +70,7 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, else if constexpr (std::is_same::value) { check(object[field_location].type() == json_t::value_t::number_integer, - fmt::format("Invalid field {}, expected number:\n{}", + fmt::format("Invalid field {}, expected integer number:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); } @@ -79,7 +79,7 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, else if constexpr (std::is_same::value) { check(object[field_location].type() == json_t::value_t::number_float, - fmt::format("Invalid field {}, expected number:\n{}", + fmt::format("Invalid field {}, expected float number:\n{}", field_location_str, object.dump(2)), error_v, -1, loc); } @@ -116,7 +116,30 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, // ============================================================================= // Group descriptors -/// Named set of constraint. +/// Describes a group of events with a name and a set of constraints. Group +/// descriptors are used by some plotters to target and aggregate trace events +/// for data collection. +/// +/// For example, this could be a group descriptor for collecting data about +/// Source trace events that are related to Boost include files: +/// +/// \code{.json} +/// { +/// "name": "Boost sources events", +/// "predicates": [ +/// { +/// "type": "match", +/// "regex_match": true, +/// "matcher": { +/// "name": "Source", +/// "args": { +/// "details": "/usr/include/boost/*" +/// } +/// } +/// } +/// ] +/// } +/// \endcode struct group_descriptor_t { std::string name; grapher::json_t::array_t predicates; From 8cdcb1b8ef6c8ab11b67e75237d7d6aba4f36953 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 24 Jun 2022 01:07:48 +0200 Subject: [PATCH 55/59] Removed useless header --- grapher/lib/grapher/plotters/debug.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/grapher/lib/grapher/plotters/debug.cpp b/grapher/lib/grapher/plotters/debug.cpp index ec58cf1..f973a50 100644 --- a/grapher/lib/grapher/plotters/debug.cpp +++ b/grapher/lib/grapher/plotters/debug.cpp @@ -1,7 +1,6 @@ #include "grapher/plotters/debug.hpp" #include -#include namespace grapher::plotters { From 38649609e86e50698e5a26e714999f4a6d460ba3 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 24 Jun 2022 01:08:15 +0200 Subject: [PATCH 56/59] Fix ref type for value computation --- grapher/lib/grapher/utils/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index d0860a1..f5d6c85 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -116,7 +116,7 @@ std::vector get_values(benchmark_iteration_t const &iteration, for (grapher::json_t const &event : events) { if (std::all_of(predicates.begin(), predicates.end(), [&](predicate_t const &p) -> bool { return p(event); })) { - val += json_at_ref(event, value_jptr); + val += json_at_ref(event, value_jptr); } } return val; From e0e8224ff6719d733f1de01ddd9223e882a99955 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Fri, 24 Jun 2022 11:31:08 +0200 Subject: [PATCH 57/59] Fixed y_label value getting for plot config --- grapher/lib/grapher/utils/json.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index f5d6c85..f423d07 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -116,7 +116,8 @@ std::vector get_values(benchmark_iteration_t const &iteration, for (grapher::json_t const &event : events) { if (std::all_of(predicates.begin(), predicates.end(), [&](predicate_t const &p) -> bool { return p(event); })) { - val += json_at_ref(event, value_jptr); + val += + json_at_ref(event, value_jptr); } } return val; @@ -175,7 +176,7 @@ sciplot::Plot &apply_config(sciplot::Plot &plot, grapher::json_t config) { plot.xlabel(config["x_label"]); } - if (config.contains("ylabel")) { + if (config.contains("y_label")) { plot.ylabel(config["y_label"]); } From a671230f1208460474548b73fdafd30d3ea57161 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 3 Aug 2022 16:36:17 +0200 Subject: [PATCH 58/59] Adapted to new Sciplot API --- grapher/lib/grapher/plotters/compare.cpp | 2 +- grapher/lib/grapher/plotters/compare_by.cpp | 15 ++++++++++++--- grapher/lib/grapher/plotters/stack.cpp | 9 ++++----- grapher/lib/grapher/utils/json.cpp | 12 +++++++----- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/grapher/lib/grapher/plotters/compare.cpp b/grapher/lib/grapher/plotters/compare.cpp index 0bfb40c..77d99c0 100644 --- a/grapher/lib/grapher/plotters/compare.cpp +++ b/grapher/lib/grapher/plotters/compare.cpp @@ -52,7 +52,7 @@ void plotter_compare_t::plot(benchmark_set_t const &bset, for (group_descriptor_t const &descriptor : group_descriptors) { // Plot init - sciplot::Plot plot; + sciplot::Plot2D plot; apply_config(plot, config); // Generating predicates diff --git a/grapher/lib/grapher/plotters/compare_by.cpp b/grapher/lib/grapher/plotters/compare_by.cpp index 7dde257..bcb0908 100644 --- a/grapher/lib/grapher/plotters/compare_by.cpp +++ b/grapher/lib/grapher/plotters/compare_by.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -127,7 +128,6 @@ grapher::json_t plotter_compare_by_t::get_default_config() const { void plotter_compare_by_t::plot(benchmark_set_t const &bset, std::filesystem::path const &dest, grapher::json_t const &config) const { - namespace sp = sciplot; namespace fs = std::filesystem; // Config reading @@ -156,9 +156,11 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, // Drawing, ie. unwrapping the nested maps and drawing curves + saving plots + std::vector thread_pool; + for (auto const &[key, curve_aggregate] : curve_aggregate_map) { // Plot init - sp::Plot plot; + sciplot::Plot2D plot; apply_config(plot, config); for (auto const &[bench_name, benchmark_curve] : curve_aggregate) { @@ -205,7 +207,14 @@ void plotter_compare_by_t::plot(benchmark_set_t const &bset, } } - save_plot(plot, dest / to_string(key, demangle), config); + // Writing in parallel + thread_pool.emplace_back(&save_plot, std::move(plot), + dest / to_string(key, demangle), config); + } + + // Joining before returning + for (std::thread &t : thread_pool) { + t.join(); } } diff --git a/grapher/lib/grapher/plotters/stack.cpp b/grapher/lib/grapher/plotters/stack.cpp index b6ab8ef..a88b4a8 100644 --- a/grapher/lib/grapher/plotters/stack.cpp +++ b/grapher/lib/grapher/plotters/stack.cpp @@ -6,6 +6,7 @@ #include +#include #include #include "grapher/core.hpp" @@ -40,16 +41,14 @@ void plotter_stack_t::plot(benchmark_set_t const &bset, // Drawing - std::vector plots; + std::vector plots; // Storing max y value for normalization double max_y_val = 0.; /// Draws a stacked curve graph for a given benchmark - auto draw_plot = [&](benchmark_case_t const &bench) -> sciplot::Plot { - namespace sp = sciplot; - - sp::Plot plot; + auto draw_plot = [&](benchmark_case_t const &bench) -> sciplot::Plot2D { + sciplot::Plot2D plot; apply_config(plot, config); // x axis diff --git a/grapher/lib/grapher/utils/json.cpp b/grapher/lib/grapher/utils/json.cpp index f423d07..e5643a8 100644 --- a/grapher/lib/grapher/utils/json.cpp +++ b/grapher/lib/grapher/utils/json.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include namespace grapher { @@ -80,9 +82,9 @@ write_descriptors(std::vector const &descriptors) { grapher::json_t::array_t res; res.reserve(descriptors.size()); - for (group_descriptor_t const &d : descriptors) { - res.push_back(group_descriptor_json(d)); - } + std::transform(descriptors.begin(), descriptors.end(), + std::back_inserter(res), &group_descriptor_json); + return res; } @@ -137,7 +139,7 @@ grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b) { return a; } -void save_plot(sciplot::Plot const &plot, std::string const &dest, +void save_plot(sciplot::Plot2D const &plot, std::string const &dest, grapher::json_t const &config) { namespace fs = std::filesystem; std::vector plot_file_extensions = config.value( @@ -157,7 +159,7 @@ void save_plot(sciplot::Plot const &plot, std::string const &dest, file_dest.replace_filename(new_filename); } - plot.save(dest + extension); + sciplot::Canvas{{sciplot::Figure{{plot}}}}.save(dest + extension); } } From f13fe7c6d52422f7e7dfa572c6ce9223b90923c8 Mon Sep 17 00:00:00 2001 From: Jules P?nuchot Date: Wed, 3 Aug 2022 17:09:16 +0200 Subject: [PATCH 59/59] Adapted to other Sciplot and Nlohmann JSON API changes --- grapher/include/grapher/utils/json.hpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/grapher/include/grapher/utils/json.hpp b/grapher/include/grapher/utils/json.hpp index fd7e893..dbf1a61 100644 --- a/grapher/include/grapher/utils/json.hpp +++ b/grapher/include/grapher/utils/json.hpp @@ -27,13 +27,25 @@ std::vector get_values(benchmark_iteration_t const &iteration, /// present in b share the same key. grapher::json_t merge_into(grapher::json_t a, grapher::json_t const &b); +/// Generic conversion of a JSON field location to a std::string +template +inline std::string field_loc_to_string(T &&field_location) { + return std::string{std::forward(field_location)}; +} + +/// Specialized conversion of a JSON field location to a std::string +inline std::string +field_loc_to_string(grapher::json_t::json_pointer const &json_ptr) { + return json_ptr.to_string(); +} + /// Wraps json_t object access with error management. template inline grapher::json_t::const_reference json_at(grapher::json_t const &object, LocType const &field_location, const std::experimental::source_location loc = std::experimental::source_location::current()) { - std::string const field_location_str = field_location; + std::string const field_location_str = field_loc_to_string(field_location); check(object.contains(field_location), fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), @@ -51,7 +63,7 @@ json_at_ref(grapher::json_t const &object, LocType const &field_location, using ValueType = std::decay_t; - std::string const field_location_str = field_location; + std::string const field_location_str = field_loc_to_string(field_location); check(object.contains(field_location), fmt::format("Empty field {}:\n{}", field_location_str, object.dump(2)), @@ -172,7 +184,7 @@ read_descriptors(grapher::json_t::array_t const &list); // Plotter configuration /// Plot saving helper function. -void save_plot(sciplot::Plot const &plot, std::string const &dest, +void save_plot(sciplot::Plot2D const &plot, std::string const &dest, grapher::json_t const &config); /// Returns the default configuration for apply_config.