From 1877ebf47b673dc6efeb1fd00177ff406fe0624d Mon Sep 17 00:00:00 2001 From: "Jonathan R. Madsen" Date: Tue, 28 Jun 2022 01:36:04 -0500 Subject: [PATCH] omnitrace-avail generate config (#69) * Config updates - See PR #69 for details - change type of OMNITRACE_DL_VERBOSE - add "deprecated" category to OMNITRACE_ROCM_SMI_DEVICES - reduce size of perfetto shared memory size hint - deprecate OMNITRACE_OUTPUT_FILE in favor of OMNITRACE_PERFETTO_FILE - set papi event choices - read config file after reading command line - fix update of OMNITRACE_DL_VERBOSE - mark several settings as hidden - timemory update support hidden attribute for settings - rework get_perfetto_output_filename() - Hide settings from not available backends * Rework omnitrace-avail to support dumping configurations * Overwrite query, tests, output flag - Support using -O flag when dumping config - Support checking before overwriting existing config - Support --force to overwrite existing config - Fix get_component_info not including omnitrace components - Testing for dumping config * Update documentation on omnitrace-avail * Fix issue with timemory format + "/__w/" * Update output prefix keys docs * Rename --dump-config to --generate-config * Hide MPI related options - OMNITRACE_PERFETTO_COMBINE_TRACES and OMNITRACE_COLLAPSE_PROCESSES are hidden w/o MPI support --- README.md | 22 +- external/timemory | 2 +- source/bin/omnitrace-avail/CMakeLists.txt | 20 +- source/bin/omnitrace-avail/avail.cpp | 929 +++--------------- source/bin/omnitrace-avail/avail.hpp | 3 +- source/bin/omnitrace-avail/common.cpp | 393 ++++++++ source/bin/omnitrace-avail/common.hpp | 145 +++ .../omnitrace-avail/component_categories.hpp | 84 ++ source/bin/omnitrace-avail/defines.hpp | 29 + .../bin/omnitrace-avail/enumerated_list.hpp | 53 + .../bin/omnitrace-avail/generate_config.cpp | 437 ++++++++ .../bin/omnitrace-avail/generate_config.hpp | 32 + .../bin/omnitrace-avail/get_availability.hpp | 229 +++++ source/bin/omnitrace-avail/get_categories.hpp | 60 ++ source/bin/omnitrace-avail/info_type.cpp | 57 ++ source/bin/omnitrace-avail/info_type.hpp | 75 ++ source/bin/tests/CMakeLists.txt | 37 +- source/docs/output.md | 48 +- source/docs/runtime.md | 132 ++- source/lib/omnitrace/library.cpp | 2 - source/lib/omnitrace/library/config.cpp | 146 ++- source/lib/omnitrace/library/config.hpp | 2 +- 22 files changed, 2067 insertions(+), 870 deletions(-) create mode 100644 source/bin/omnitrace-avail/common.cpp create mode 100644 source/bin/omnitrace-avail/common.hpp create mode 100644 source/bin/omnitrace-avail/component_categories.hpp create mode 100644 source/bin/omnitrace-avail/defines.hpp create mode 100644 source/bin/omnitrace-avail/enumerated_list.hpp create mode 100644 source/bin/omnitrace-avail/generate_config.cpp create mode 100644 source/bin/omnitrace-avail/generate_config.hpp create mode 100644 source/bin/omnitrace-avail/get_availability.hpp create mode 100644 source/bin/omnitrace-avail/get_categories.hpp create mode 100644 source/bin/omnitrace-avail/info_type.cpp create mode 100644 source/bin/omnitrace-avail/info_type.hpp diff --git a/README.md b/README.md index aca42693ab..c71ecc1017 100755 --- a/README.md +++ b/README.md @@ -15,8 +15,26 @@ The full documentation for [omnitrace](https://github.com/AMDResearch/omnitrace) ### Omnitrace Settings -`omnitrace-avail -Sd` will provide a list of all the possible omnitrace settings, their current value, and a description of the setting -when running an instrumented binary. +Generate an omnitrace configuration file using `omnitrace-avail -D omnitrace.cfg`. Optionally, use `omnitrace-avail -D omnitrace.cfg --all` for +a verbose configuration file with descriptions, categories, etc. Modify the configuration file as desired, e.g. enable +[perfetto](https://perfetto.dev/), [timemory](https://github.com/NERSC/timemory), sampling, and process-level sampling by default +and tweak some sampling default values: + +```console +# ... +OMNITRACE_USE_PERFETTO = true +OMNITRACE_USE_TIMEMORY = true +OMNITRACE_USE_SAMPLING = true +OMNITRACE_USE_PROCESS_SAMPLING = true +# ... +OMNITRACE_SAMPLING_FREQ = 50 +OMNITRACE_SAMPLING_CPUS = all +OMNITRACE_SAMPLING_GPUS = $env:HIP_VISIBLE_DEVICES +``` + +Once the configuration file is adjusted to your preferences, either export the path to this file via `OMNITRACE_CONFIG_FILE=/path/to/omnitrace.cfg` +or place this file in `${HOME}/.omnitrace.cfg` to ensure these values are always read as the default. If you wish to change any of these settings, +you can override them via environment variables or by specifying an alternative `OMNITRACE_CONFIG_FILE`. ### Omnitrace Executable diff --git a/external/timemory b/external/timemory index 9b1e0c1560..ff2f23167b 160000 --- a/external/timemory +++ b/external/timemory @@ -1 +1 @@ -Subproject commit 9b1e0c15605a8b3bcc483f8f6c52932aae5e5fbd +Subproject commit ff2f23167be5434d1e4a04e1d1dfea9240356ce3 diff --git a/source/bin/omnitrace-avail/CMakeLists.txt b/source/bin/omnitrace-avail/CMakeLists.txt index 4fd5e02acc..983f7f4bda 100644 --- a/source/bin/omnitrace-avail/CMakeLists.txt +++ b/source/bin/omnitrace-avail/CMakeLists.txt @@ -4,10 +4,24 @@ # # ------------------------------------------------------------------------------# -add_executable( +add_executable(omnitrace-avail) + +target_sources( omnitrace-avail - ${CMAKE_CURRENT_LIST_DIR}/avail.cpp ${CMAKE_CURRENT_LIST_DIR}/avail.hpp - $) + PRIVATE ${CMAKE_CURRENT_LIST_DIR}/avail.cpp + ${CMAKE_CURRENT_LIST_DIR}/avail.hpp + ${CMAKE_CURRENT_LIST_DIR}/common.cpp + ${CMAKE_CURRENT_LIST_DIR}/common.hpp + ${CMAKE_CURRENT_LIST_DIR}/component_categories.hpp + ${CMAKE_CURRENT_LIST_DIR}/defines.hpp + ${CMAKE_CURRENT_LIST_DIR}/enumerated_list.hpp + ${CMAKE_CURRENT_LIST_DIR}/generate_config.cpp + ${CMAKE_CURRENT_LIST_DIR}/generate_config.hpp + ${CMAKE_CURRENT_LIST_DIR}/get_availability.hpp + ${CMAKE_CURRENT_LIST_DIR}/get_categories.hpp + ${CMAKE_CURRENT_LIST_DIR}/info_type.cpp + ${CMAKE_CURRENT_LIST_DIR}/info_type.hpp + $) target_include_directories(omnitrace-avail PRIVATE ${CMAKE_CURRENT_LIST_DIR}) target_compile_definitions(omnitrace-avail PRIVATE OMNITRACE_EXTERN_COMPONENTS=0) diff --git a/source/bin/omnitrace-avail/avail.cpp b/source/bin/omnitrace-avail/avail.cpp index 41b2542176..939cad710a 100644 --- a/source/bin/omnitrace-avail/avail.cpp +++ b/source/bin/omnitrace-avail/avail.cpp @@ -21,14 +21,14 @@ // SOFTWARE. #include "avail.hpp" -#include "library/api.hpp" -#include "library/components/backtrace.hpp" -#include "library/components/fork_gotcha.hpp" -#include "library/components/mpi_gotcha.hpp" -#include "library/components/omnitrace.hpp" -#include "library/components/pthread_gotcha.hpp" -#include "library/components/roctracer.hpp" -#include "library/components/user_region.hpp" +#include "common.hpp" +#include "component_categories.hpp" +#include "defines.hpp" +#include "enumerated_list.hpp" +#include "generate_config.hpp" +#include "get_availability.hpp" +#include "info_type.hpp" + #include "library/config.hpp" #include @@ -38,8 +38,8 @@ #include #include #include -#include #include +#include #include #include @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -65,143 +66,14 @@ using namespace tim; -template -using array_t = std::array; -using string_t = std::string; -using stringstream_t = std::stringstream; -using str_vec_t = std::vector; -using str_set_t = std::set; -using info_type_base = std::tuple; -using parser_t = tim::argparse::argument_parser; - -struct info_type : info_type_base -{ - TIMEMORY_DEFAULT_OBJECT(info_type) - - template - info_type(Args&&... _args) - : info_type_base{ std::forward(_args)... } - {} - - const auto& name() const { return std::get<0>(*this); } - auto is_available() const { return std::get<1>(*this); } - const auto& info() const { return std::get<2>(*this); } - const auto& data_type() const { return info().at(0); } - const auto& enum_type() const { return info().at(1); } - const auto& id_type() const { return info().at(2); } - const auto& id_strings() const { return info().at(3); } - const auto& label() const { return info().at(4); } - const auto& description() const { return info().at(5); } - const auto& categories() const { return info().at(6); } - - bool valid() const { return !name().empty() && info().size() >= 6; } - - bool operator<(const info_type& rhs) const { return name() < rhs.name(); } - bool operator!=(const info_type& rhs) const { return !(*this == rhs); } - bool operator==(const info_type& rhs) const - { - if(info().size() != rhs.info().size()) return false; - for(size_t i = 0; i < info().size(); ++i) - { - if(info().at(i) != rhs.info().at(i)) return false; - } - return name() == rhs.name() && is_available() == rhs.is_available(); - } -}; - -//--------------------------------------------------------------------------------------// - -enum -{ - VAL = 0, - ENUM = 1, - LANG = 2, - CID = 3, - FNAME = 4, - DESC = 5, - CATEGORY = 6, - TOTAL = 7 -}; - //--------------------------------------------------------------------------------------// namespace { -auto global_delim = std::string{ "|" }; -bool csv = false; -bool markdown = false; -bool alphabetical = false; -bool available_only = false; -bool all_info = false; -bool force_brief = false; -bool debug_msg = false; -bool case_insensitive = false; -bool regex_hl = false; -int32_t max_width = 0; -int32_t num_cols = 0; -int32_t min_width = 40; -int32_t padding = 4; -str_vec_t regex_keys = {}; -str_vec_t category_regex_keys = {}; -str_set_t category_view = {}; -constexpr size_t num_component_options = 7; -constexpr size_t num_settings_options = 4; -constexpr size_t num_hw_counter_options = 4; -auto lerr = std::stringstream{}; - -// explicit setting names to exclude -std::set settings_exclude = { - "OMNITRACE_ENVIRONMENT", "OMNITRACE_COMMAND_LINE", "cereal_class_version", "settings", -#if !defined(TIMEMORY_USE_CRAYPAT) - "OMNITRACE_CRAYPAT" -#endif -}; - -// exclude some timemory settings which are not relevant to omnitrace -// exact matches, e.g. OMNITRACE_BANNER -std::string settings_rexclude_exact = - "^OMNITRACE_(BANNER|DESTRUCTOR_REPORT|COMPONENTS|(GLOBAL|MPIP|NCCLP|OMPT|" - "PROFILER|TRACE|KOKKOS)_COMPONENTS|PYTHON_EXE|PAPI_ATTACH|PLOT_OUTPUT|SEPARATOR_" - "FREQ|" - "STACK_CLEARING|TARGET_PID|THROTTLE_(COUNT|VALUE)|(AUTO|FLAMEGRAPH)_OUTPUT|" - "(ENABLE|DISABLE)_ALL_SIGNALS|ALLOW_SIGNAL_HANDLER|CTEST_NOTES|INSTRUCTION_" - "ROOFLINE|ADD_SECONDARY)$"; - -// leading matches, e.g. OMNITRACE_MPI_[A-Z_]+ -std::string settings_rexclude_begin = - "^OMNITRACE_(ERT|DART|MPI|UPCXX|ROOFLINE|CUDA|NVTX|CUPTI)_[A-Z_]+$"; - -bool -exclude_setting(const std::string&); -} // namespace - -//--------------------------------------------------------------------------------------// - -void -dump_log() -{ - if(debug_msg) - { - std::cerr << lerr.str() << std::flush; - lerr = std::stringstream{}; - } -} - -void -dump_log_abort(int _v) -{ - fprintf(stderr, "\n[omnitrace-avail] Exiting with signal %i...\n", _v); - debug_msg = true; - dump_log(); -} - template -static IntArrayT +IntArrayT compute_max_columns(IntArrayT _widths, BoolArrayT _using); -string_t -remove(string_t inp, const std::set& entries); - template void write_entry(std::ostream& os, const Tp& _entry, int64_t _w, bool center, bool mark); @@ -209,15 +81,7 @@ write_entry(std::ostream& os, const Tp& _entry, int64_t _w, bool center, bool ma template string_t banner(IntArrayT _breaks, std::array _use, char filler = '-', char delim = '|'); - -bool -is_selected(const std::string& line); - -bool -is_category_selected(const std::string& _line); - -std::string -hl_selected(const std::string& line); +} // namespace template void @@ -234,123 +98,6 @@ void write_hw_counter_info(std::ostream&, const array_t& = {}, const array_t& = {}, const array_t& = {}); -template -struct get_availability; - -template -struct component_categories; - -void -process_categories(parser_t&, const str_set_t&); - -//--------------------------------------------------------------------------------------// - -template -struct get_availability -{ - using this_type = get_availability; - using metadata_t = component::metadata; - using property_t = component::properties; - - static info_type get_info(); - auto operator()() const { return get_info(); } -}; - -//--------------------------------------------------------------------------------------// - -template -struct get_availability> -{ - using data_type = std::vector; - - static data_type get_info(data_type& _v) - { - TIMEMORY_FOLD_EXPRESSION(_v.emplace_back(get_availability::get_info())); - return _v; - } - - static data_type get_info() - { - data_type _v{}; - return get_info(_v); - } - - template - decltype(auto) operator()(Args&&... _args) - { - return get_info(std::forward(_args)...); - } -}; - -//--------------------------------------------------------------------------------------// - -template <> -struct get_availability -{ - template - decltype(auto) operator()(tim::type_list, Args&&... _args) const - { - return get_availability>{}(std::forward(_args)...); - } - - template - decltype(auto) operator()(Args&&... _args) const - { - return get_availability>{}(std::forward(_args)...); - } -}; - -//--------------------------------------------------------------------------------------// - -template -struct component_categories -{ - template - void operator()(std::set& _v, type_list) const - { - // - auto _cleanup = [](std::string _type, const std::string& _pattern) { - auto _pos = std::string::npos; - while((_pos = _type.find(_pattern)) != std::string::npos) - _type.erase(_pos, _pattern.length()); - return _type; - }; - (void) _cleanup; // unused but set if sizeof...(Tp) == 0 - - TIMEMORY_FOLD_EXPRESSION(_v.emplace( - TIMEMORY_JOIN("::", "component", _cleanup(demangle(), "tim::")))); - } - - void operator()(std::set& _v) const - { - if constexpr(!concepts::is_placeholder::value) - (*this)(_v, trait::component_apis_t{}); - } -}; - -template <> -struct component_categories -{ - template - void operator()(std::set& _v, std::index_sequence) const - { - TIMEMORY_FOLD_EXPRESSION( - component_categories>{}(_v)); - } - - void operator()(std::set& _v) const - { - (*this)(_v, std::make_index_sequence{}); - } - - auto operator()() const - { - std::set _categories{}; - (*this)(_categories); - return _categories; - } -}; - //--------------------------------------------------------------------------------------// int @@ -494,6 +241,43 @@ main(int argc, char** argv) for(const auto& itr : _category_options) std::cout << " " << itr << "\n"; }); + parser.add_argument({ "--list-keys" }, "List the output keys") + .max_count(1) + .action([](parser_t& p) { + auto _list = p.get("list-keys"); + auto _show = p.get("expand-keys"); + if(_list) + { + auto _keys = tim::settings::output_keys( + tim::settings::shared_instance()->get_tag()); + std::pair _w = { 0, 0 }; + for(const auto& itr : _keys) + { + if(!is_selected(itr.first)) continue; + if(_show && !is_selected(itr.second)) continue; + _w.first = std::max(_w.first, itr.first.length()); + _w.second = std::max(_w.second, itr.second.length()); + } + std::stringstream _msg{}; + _msg << "Output Keys:\n" << std::left; + for(const auto& itr : _keys) + { + if(!is_selected(itr.first)) continue; + if(_show && !is_selected(itr.second)) continue; + if(_show) + _msg << " " << std::setw(_w.first) << itr.first + << " :: " << std::setw(_w.second) << itr.second << "\n"; + else + _msg << " " << std::setw(_w.first) << itr.first << "\n"; + } + std::cout << _msg.str(); + } + }); + parser + .add_argument({ "--expand-keys" }, + "Expand the output keys to their current values") + .max_count(1) + .action([](parser_t& p) { expand_keys = p.get("expand-keys"); }); parser.add_argument({ "" }, ""); parser.add_argument({ "[COLUMN OPTIONS]" }, ""); @@ -502,14 +286,6 @@ main(int argc, char** argv) .action([](parser_t& p) { force_brief = p.get("brief"); }); parser.add_argument({ "-d", "--description" }, "Display the component description") .max_count(1); - parser - .add_argument({ "--categories" }, - "Display the category information (use --list-categories to see " - "the available categories)") - .dtype("string") - .action([&_category_options](parser_t& p) { - process_categories(p, _category_options); - }); parser.add_argument({ "-s", "--string" }, "Display all acceptable string identifiers") .max_count(1); parser @@ -520,31 +296,72 @@ main(int argc, char** argv) .add_argument({ "-f", "--filename" }, "Display the output filename for the component") .max_count(1); + parser + .add_argument({ "--categories" }, + "Display the category information (use --list-categories to see " + "the available categories)") + .dtype("string") + .action([&_category_options](parser_t& p) { + process_categories(p, _category_options); + }); parser.add_argument({ "" }, ""); parser.add_argument({ "[WIDTH OPTIONS]" }, ""); parser - .add_argument({ "-w", "--width" }, + .add_argument({ "-w", "--column-width" }, "if w > 0, truncate any columns greater than this width") .count(1) .dtype("int") - .action([](parser_t& p) { max_width = p.get("width"); }); + .action([](parser_t& p) { max_width = p.get("column-width"); }); parser .add_argument( - { "-c", "--columns" }, - std::string{ "if c > 0, truncate the total width of all the columns to this " - "value. Set '-w 0 -c 0' to remove all truncation" } + + { "-W", "--max-total-width" }, + std::string{ "if W > 0, truncate the total width of all the columns to this " + "value. Set '-w 0 -W 0' to remove all truncation" } + col_msg) .set_default(num_cols) .count(1) .dtype("int") - .action([](parser_t& p) { num_cols = p.get("columns"); }); + .action([](parser_t& p) { num_cols = p.get("max-total-width"); }); + std::string _config_file = {}; + std::set _config_fmts = {}; parser.add_argument({ "" }, ""); parser.add_argument({ "[OUTPUT OPTIONS]" }, ""); + parser + .add_argument({ "-G", "--generate-config" }, + "Dump a configuration to a specified file.") + .max_count(1) + .dtype("filename") + .set_default(std::string{ "omnitrace-config" }) + .action([&_config_file](parser_t& _p) { + auto _out = + (_p.exists("output")) ? _p.get("output") : std::string{}; + if(_p.get_count("generate-config") == 0 && !_out.empty()) + _config_file = _out; + else + { + _config_file = _p.get("generate-config"); + if(get_bool(_config_file, false) && !_out.empty()) _config_file = _out; + } + }); + parser.add_argument({ "-F", "--config-format" }, "Configuration file format") + .min_count(1) + .max_count(3) + .set_default(std::set{ "txt" }) + .choices({ "txt", "json", "xml" }) + .dtype("filename") + .action([&_config_fmts](parser_t& _p) { + _config_fmts = _p.get>("config-format"); + }); parser.add_argument({ "-O", "--output" }, "Write results to file") .count(1) .dtype("filename"); + parser.add_argument({ "-t", "--tag" }, "Set the %tag% to a custom value") + .count(1) + .action([](parser_t& p) { + settings::instance()->set_tag(p.get("tag")); + }); parser.add_argument({ "-M", "--markdown" }, "Write data in markdown") .max_count(1) .action([](parser_t& p) { markdown = p.get("markdown"); }); @@ -559,6 +376,11 @@ main(int argc, char** argv) "Use the provided string instead of a ',' to separate values") .max_count(1) .action([](parser_t& p) { global_delim = p.get("csv-separator"); }); + parser + .add_argument({ "--force" }, + "Force the generation of an configuration file even if it exists") + .max_count(1) + .action([](parser_t& p) { force_config = p.get("force"); }); parser.add_positional_argument("REGEX_FILTER").set_default(std::string{}); @@ -577,13 +399,46 @@ main(int argc, char** argv) return EXIT_FAILURE; } + auto _parser_set_if_exists = [&parser](auto& _var, const std::string& _opt) { + using Tp = decay_t; + if(parser.exists(_opt)) _var = parser.get(_opt); + }; + + _parser_set_if_exists(options[FNAME], "filename"); + _parser_set_if_exists(options[DESC], "description"); + _parser_set_if_exists(options[VAL], "value"); + _parser_set_if_exists(options[CID], "string"); + _parser_set_if_exists(options[CATEGORY], "categories"); + _parser_set_if_exists(file, "output"); + _parser_set_if_exists(include_components, "components"); + _parser_set_if_exists(include_settings, "settings"); + _parser_set_if_exists(include_hw_counters, "hw-counters"); + + if(parser.exists("generate-config")) + { + if(_config_file.empty()) + throw std::runtime_error("Error! No config output file specified!"); + if(_config_fmts.empty()) + throw std::runtime_error("Error! No config output formats specified!"); + try + { + generate_config(_config_file, _config_fmts, options); + } catch(std::runtime_error& _e) + { + std::cerr << "[omnitrace-avail] " << _e.what() << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } + if(parser.exists("markdown") && parser.exists("csv")) { std::cerr << "Error! both '--markdown' and '--csv' options cannot be specified\n"; return EXIT_FAILURE; } - if(parser.exists("list-categories")) return EXIT_SUCCESS; + if(parser.exists("list-categories") || parser.exists("list-keys")) + return EXIT_SUCCESS; std::string _pos_regex{}; if(parser.get_positional_count() > 0) @@ -603,21 +458,6 @@ main(int argc, char** argv) category_regex_keys.emplace_back(_pos_regex); } - auto _parser_set_if_exists = [&parser](auto& _var, const std::string& _opt) { - using Tp = decay_t; - if(parser.exists(_opt)) _var = parser.get(_opt); - }; - - _parser_set_if_exists(options[FNAME], "filename"); - _parser_set_if_exists(options[DESC], "description"); - _parser_set_if_exists(options[VAL], "value"); - _parser_set_if_exists(options[CID], "string"); - _parser_set_if_exists(options[CATEGORY], "categories"); - _parser_set_if_exists(file, "output"); - _parser_set_if_exists(include_components, "components"); - _parser_set_if_exists(include_settings, "settings"); - _parser_set_if_exists(include_hw_counters, "hw-counters"); - if(category_view.empty()) category_view = _category_options; if(!include_components && !include_settings && !include_hw_counters) @@ -669,27 +509,6 @@ main(int argc, char** argv) return 0; } -//--------------------------------------------------------------------------------------// - -template -struct enumerated_list; - -template