omnitrace-dl-library (#25)
* timemory submodule update
* Visibility, setting categories, and task-group protection
- OMNITRACE_VISIBILITY instead of TIMEMORY_VISIBILITY
- increased task group data-race protection
- add omnitrace categories to settings
* set component_apis type-trait
* omnitrace-dl-library implementation
- this library dlopen + dlsym's libomnitrace
- significantly reduces the instrumentation time
* omnitrace-avail categories
- suppress AVAILABLE column when --available
* omnitrace-exe update
- uses omnitrace-dl
- adds --print-excluded option
- removes --jump option
- comments out --stubs option
- removes --stdlib option
- support for C++ STL functions not in libstdc++
- tweak the --print-* outputs
- significantly refactors instrument_module and instrument_entity
- removes unused c_stdlib_module_constraint
- removes unused c_stdlib_function_constraint
- decreases get_whole_function_names() coverage
* library.cpp updates
- OMNITRACE_DEBUG -> OMNITRACE_DEBUG_F
- omnitrace_finalize sets state earlier
- omnitrace_finalize clears push/pop functors
- increased tasking shutdown safety
* - fix critical-trace thread hierarchy
- signal handler calls omnitrace_finalize
- get_cpu_cid_stack supports parent tid
- interval data reserves
- omnitrace-avail serialization support for module_functions
- omnitrace --simulate option
- omnitrace --print-format option
- omnitrace --load-instr option
- omnitrace runtime-inst doesn't oneTimeCode
- updated regex
- expand get_whole_function_names()
- Test Install CI update
* fixes to last commit
- expand get_whole_function_names()
- ignore sig c modules
- kill process in signal handler
* Remove RTLD_DEEPBIND + more
- removed use of RTLD_DEEPBIND
- causes dyninst segfaults
- fixed signal handling
- updated timemory submodule
* Build/link static timemory libraries
* omnitrace --{module,function}-restrict option
- Added restrict regex options
- Reworked handling of regex options
- Reworked reporting of module/function skipping
- Handle -o w/o file specified
* timemory-avail
- category views
- backtrace::sample checks state
* get_debug_sampling()
[ROCm/rocprofiler-systems commit: 145a6ae06f]
This commit is contained in:
committed by
GitHub
parent
b99b153030
commit
8b058902a2
@@ -44,11 +44,15 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(TIMEMORY_UNIX)
|
||||
@@ -65,7 +69,9 @@ using array_t = std::array<Tp, N>;
|
||||
using string_t = std::string;
|
||||
using stringstream_t = std::stringstream;
|
||||
using str_vec_t = std::vector<string_t>;
|
||||
using str_set_t = std::set<string_t>;
|
||||
using info_type_base = std::tuple<string_t, bool, str_vec_t>;
|
||||
using parser_t = tim::argparse::argument_parser;
|
||||
|
||||
struct info_type : info_type_base
|
||||
{
|
||||
@@ -85,8 +91,9 @@ struct info_type : info_type_base
|
||||
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() >= 5; }
|
||||
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); }
|
||||
@@ -101,6 +108,22 @@ struct info_type : info_type_base
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
enum
|
||||
{
|
||||
VAL = 0,
|
||||
ENUM = 1,
|
||||
LANG = 2,
|
||||
CID = 3,
|
||||
FNAME = 4,
|
||||
DESC = 5,
|
||||
CATEGORY = 6,
|
||||
TOTAL = 7
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
namespace
|
||||
{
|
||||
char global_delim = '|';
|
||||
@@ -111,16 +134,43 @@ 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 = {};
|
||||
bool regex_hl = false;
|
||||
constexpr size_t num_component_options = 6;
|
||||
constexpr size_t num_settings_options = 3;
|
||||
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;
|
||||
std::stringstream lerr{};
|
||||
|
||||
// explicit setting names to exclude
|
||||
std::set<std::string> 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)$";
|
||||
|
||||
// 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
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -153,6 +203,9 @@ banner(IntArrayT _breaks, std::array<bool, N> _use, char filler = '-', char deli
|
||||
bool
|
||||
is_selected(const std::string& line);
|
||||
|
||||
bool
|
||||
is_category_selected(const std::string& _line);
|
||||
|
||||
std::string
|
||||
hl_selected(const std::string& line);
|
||||
|
||||
@@ -174,6 +227,12 @@ write_hw_counter_info(std::ostream&, const array_t<bool, N>& = {},
|
||||
template <typename Type = void>
|
||||
struct get_availability;
|
||||
|
||||
template <typename Type = void>
|
||||
struct component_categories;
|
||||
|
||||
void
|
||||
process_categories(parser_t&, const str_set_t&);
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
template <typename Type>
|
||||
@@ -233,15 +292,53 @@ struct get_availability<void>
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
enum
|
||||
template <typename Type>
|
||||
struct component_categories
|
||||
{
|
||||
VAL = 0,
|
||||
ENUM = 1,
|
||||
LANG = 2,
|
||||
CID = 3,
|
||||
FNAME = 4,
|
||||
DESC = 5,
|
||||
TOTAL = 6
|
||||
template <typename... Tp>
|
||||
void operator()(std::set<std::string>& _v, type_list<Tp...>) 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<Tp>(), "tim::"))));
|
||||
}
|
||||
|
||||
void operator()(std::set<std::string>& _v) const
|
||||
{
|
||||
if constexpr(!concepts::is_placeholder<Type>::value)
|
||||
(*this)(_v, trait::component_apis_t<Type>{});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct component_categories<void>
|
||||
{
|
||||
template <size_t... Idx>
|
||||
void operator()(std::set<std::string>& _v, std::index_sequence<Idx...>) const
|
||||
{
|
||||
TIMEMORY_FOLD_EXPRESSION(
|
||||
component_categories<component::enumerator_t<Idx>>{}(_v));
|
||||
}
|
||||
|
||||
void operator()(std::set<std::string>& _v) const
|
||||
{
|
||||
(*this)(_v, std::make_index_sequence<TIMEMORY_COMPONENTS_END>{});
|
||||
}
|
||||
|
||||
auto operator()() const
|
||||
{
|
||||
std::set<std::string> _categories{};
|
||||
(*this)(_categories);
|
||||
return _categories;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -249,28 +346,48 @@ enum
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
array_t<bool, 6> options = { false, false, false, false, false, false };
|
||||
array_t<string_t, 6> fields = {};
|
||||
array_t<bool, 6> use_mark = {};
|
||||
omnitrace_init_library();
|
||||
|
||||
std::set<std::string> _category_options = component_categories{}();
|
||||
{
|
||||
auto _settings = tim::settings::shared_instance();
|
||||
for(const auto& itr : *_settings)
|
||||
{
|
||||
if(exclude_setting(itr.second->get_env_name())) continue;
|
||||
for(const auto& eitr : itr.second->get_categories())
|
||||
{
|
||||
if(eitr == "native")
|
||||
_category_options.emplace("settings::timemory");
|
||||
else
|
||||
_category_options.emplace(TIMEMORY_JOIN("::", "settings", eitr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array_t<bool, TOTAL> options = { false, false, false, false, false, false, false };
|
||||
array_t<string_t, TOTAL> fields = {};
|
||||
array_t<bool, TOTAL> use_mark = {};
|
||||
|
||||
std::string cols_via{};
|
||||
std::tie(num_cols, cols_via) = tim::utility::console::get_columns();
|
||||
std::string col_msg =
|
||||
"(default: " + std::to_string(num_cols) + " [via " + cols_via + "])";
|
||||
|
||||
fields[VAL] = "VALUE_TYPE";
|
||||
fields[ENUM] = "ENUMERATION";
|
||||
fields[LANG] = "C++ ALIAS / PYTHON ENUMERATION";
|
||||
fields[FNAME] = "FILENAME";
|
||||
fields[CID] = "STRING_IDS";
|
||||
fields[DESC] = "DESCRIPTION";
|
||||
fields[VAL] = "VALUE_TYPE";
|
||||
fields[ENUM] = "ENUMERATION";
|
||||
fields[LANG] = "C++ ALIAS / PYTHON ENUMERATION";
|
||||
fields[FNAME] = "FILENAME";
|
||||
fields[CID] = "STRING_IDS";
|
||||
fields[DESC] = "DESCRIPTION";
|
||||
fields[CATEGORY] = "CATEGORY";
|
||||
|
||||
use_mark[VAL] = true;
|
||||
use_mark[ENUM] = true;
|
||||
use_mark[LANG] = true;
|
||||
use_mark[FNAME] = false;
|
||||
use_mark[CID] = false;
|
||||
use_mark[DESC] = false;
|
||||
use_mark[VAL] = true;
|
||||
use_mark[ENUM] = true;
|
||||
use_mark[LANG] = true;
|
||||
use_mark[FNAME] = false;
|
||||
use_mark[CID] = false;
|
||||
use_mark[DESC] = false;
|
||||
use_mark[CATEGORY] = false;
|
||||
|
||||
bool include_settings = false;
|
||||
bool include_components = false;
|
||||
@@ -278,7 +395,6 @@ main(int argc, char** argv)
|
||||
|
||||
std::string file = {};
|
||||
|
||||
using parser_t = tim::argparse::argument_parser;
|
||||
parser_t parser("omnitrace-avail");
|
||||
|
||||
parser.enable_help();
|
||||
@@ -329,6 +445,16 @@ main(int argc, char** argv)
|
||||
.min_count(1)
|
||||
.dtype("list of strings")
|
||||
.action([](parser_t& p) { regex_keys = p.get<str_vec_t>("filter"); });
|
||||
parser
|
||||
.add_argument({ "-R", "--category-filter" },
|
||||
"Filter the output according to provided regex w.r.t. the "
|
||||
"categories (egrep + "
|
||||
"case-sensitive) [e.g. -r \"true\"]")
|
||||
.min_count(1)
|
||||
.dtype("list of strings")
|
||||
.action([](parser_t& p) {
|
||||
category_regex_keys = p.get<str_vec_t>("category-filter");
|
||||
});
|
||||
parser.add_argument({ "-i", "--ignore-case" }, "Ignore case when filtering")
|
||||
.max_count(1)
|
||||
.dtype("bool")
|
||||
@@ -341,6 +467,15 @@ main(int argc, char** argv)
|
||||
parser.add_argument({ "--alphabetical" }, "Sort the output alphabetically")
|
||||
.max_count(1)
|
||||
.action([](parser_t& p) { alphabetical = p.get<bool>("alphabetical"); });
|
||||
parser
|
||||
.add_argument({ "--list-categories" },
|
||||
"List the available categories for --categories option")
|
||||
.count(0)
|
||||
.action([_category_options](parser_t&) {
|
||||
std::cout << "Categories:\n";
|
||||
for(const auto& itr : _category_options)
|
||||
std::cout << " " << itr << "\n";
|
||||
});
|
||||
|
||||
parser.add_argument({ "" }, "");
|
||||
parser.add_argument({ "[COLUMN OPTIONS]" }, "");
|
||||
@@ -349,6 +484,14 @@ main(int argc, char** argv)
|
||||
.action([](parser_t& p) { force_brief = p.get<bool>("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
|
||||
@@ -405,6 +548,8 @@ main(int argc, char** argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(parser.exists("list-categories")) return EXIT_SUCCESS;
|
||||
|
||||
std::string _pos_regex{};
|
||||
if(parser.get_positional_count() > 0)
|
||||
{
|
||||
@@ -417,7 +562,11 @@ main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
if(!_pos_regex.empty()) regex_keys.emplace_back(_pos_regex);
|
||||
if(!_pos_regex.empty())
|
||||
{
|
||||
regex_keys.emplace_back(_pos_regex);
|
||||
category_regex_keys.emplace_back(_pos_regex);
|
||||
}
|
||||
|
||||
auto _parser_set_if_exists = [&parser](auto& _var, const std::string& _opt) {
|
||||
using Tp = decay_t<decltype(_var)>;
|
||||
@@ -428,11 +577,16 @@ main(int argc, char** argv)
|
||||
_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(options[CATEGORY] && force_brief) options[CATEGORY] = false;
|
||||
|
||||
if(category_view.empty()) category_view = _category_options;
|
||||
|
||||
if(!include_components && !include_settings && !include_hw_counters)
|
||||
include_settings = true;
|
||||
|
||||
@@ -462,12 +616,14 @@ main(int argc, char** argv)
|
||||
dump_log();
|
||||
|
||||
if(include_settings)
|
||||
write_settings_info(*os, { options[VAL], options[LANG], options[DESC] });
|
||||
write_settings_info(
|
||||
*os, { options[VAL], options[LANG], options[DESC], options[CATEGORY] });
|
||||
|
||||
dump_log();
|
||||
|
||||
if(include_hw_counters)
|
||||
write_hw_counter_info(*os, { true, !force_brief, !options[DESC], options[DESC] });
|
||||
write_hw_counter_info(*os, { true, !force_brief && !available_only,
|
||||
!options[DESC], options[DESC] });
|
||||
|
||||
dump_log();
|
||||
|
||||
@@ -522,34 +678,42 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
|
||||
_info.erase(std::remove_if(_info.begin(), _info.end(),
|
||||
[](const auto& itr) {
|
||||
// NOLINTNEXTLINE
|
||||
for(const auto& nitr :
|
||||
{ "cuda", "cupti", "ompt", "roofline", "_bundle",
|
||||
{ "cuda", "cupti", "nvtx", "roofline", "_bundle",
|
||||
"data_integer", "data_unsigned", "data_floating",
|
||||
"printer" })
|
||||
{
|
||||
if(itr.name().find(nitr) != std::string::npos)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
auto _categories = tim::delimit(
|
||||
itr.categories(), ", ", [](const string_t& _v) {
|
||||
return "component::" + _v;
|
||||
});
|
||||
for(const auto& citr : _categories)
|
||||
if(category_view.count(citr) > 0) return false;
|
||||
return true;
|
||||
}),
|
||||
_info.end());
|
||||
|
||||
using width_type = std::vector<int64_t>;
|
||||
using width_bool = std::array<bool, N + 2>;
|
||||
|
||||
width_type _widths = width_type{ 30, 12, 20, 20, 20, 40, 20, 40 };
|
||||
width_bool _wusing = width_bool{ true, !force_brief };
|
||||
auto _available_column = !force_brief && !available_only;
|
||||
width_type _widths = width_type{ 30, 12, 20, 20, 20, 40, 20, 40, 10 };
|
||||
width_bool _wusing = width_bool{ true, _available_column };
|
||||
int64_t pad = padding;
|
||||
for(size_t i = 0; i < options.size(); ++i)
|
||||
_wusing[i + 2] = options[i];
|
||||
|
||||
int64_t pad = padding;
|
||||
|
||||
{
|
||||
constexpr size_t idx = 0;
|
||||
stringstream_t ss;
|
||||
write_entry(ss, "COMPONENT", _widths.at(0), false, true);
|
||||
_widths.at(idx) = std::max<int64_t>(ss.str().length() + pad, _widths.at(idx));
|
||||
}
|
||||
|
||||
{
|
||||
constexpr size_t idx = 1;
|
||||
stringstream_t ss;
|
||||
@@ -582,7 +746,7 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
std::stringstream ss;
|
||||
_selected += (is_selected(std::get<0>(itr))) ? 1 : 0;
|
||||
write_entry(ss, std::get<0>(itr), _widths.at(0), false, true);
|
||||
if(!force_brief)
|
||||
if(_available_column)
|
||||
{
|
||||
std::stringstream _avss{};
|
||||
_avss << std::boolalpha << std::get<1>(itr);
|
||||
@@ -597,6 +761,9 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
write_entry(ss, std::get<2>(itr).at(i), _widths.at(i + 2), center,
|
||||
_mark.at(i));
|
||||
}
|
||||
|
||||
_selected += (is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
|
||||
|
||||
if(_selected == 0) continue;
|
||||
}
|
||||
|
||||
@@ -632,7 +799,7 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
|
||||
os << global_delim;
|
||||
write_entry(os, "COMPONENT", _widths.at(0), true, false);
|
||||
if(!force_brief) write_entry(os, "AVAILABLE", _widths.at(1), true, false);
|
||||
if(_available_column) write_entry(os, "AVAILABLE", _widths.at(1), true, false);
|
||||
for(size_t i = 0; i < fields.size(); ++i)
|
||||
{
|
||||
if(!options[i]) continue;
|
||||
@@ -647,7 +814,7 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
std::stringstream ss;
|
||||
_selected += (is_selected(std::get<0>(itr))) ? 1 : 0;
|
||||
write_entry(ss, std::get<0>(itr), _widths.at(0), false, true);
|
||||
if(!force_brief)
|
||||
if(_available_column)
|
||||
{
|
||||
std::stringstream _avss{};
|
||||
_avss << std::boolalpha << std::get<1>(itr);
|
||||
@@ -663,6 +830,8 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
|
||||
_mark.at(i));
|
||||
}
|
||||
|
||||
_selected += (is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
|
||||
|
||||
if(_selected > 0)
|
||||
{
|
||||
os << global_delim;
|
||||
@@ -692,56 +861,83 @@ write_settings_info(std::ostream& os, const array_t<bool, N>& opts,
|
||||
{
|
||||
static_assert(N >= num_settings_options, "Error! Too few settings options + fields");
|
||||
|
||||
static constexpr size_t size = 7;
|
||||
static constexpr size_t size = 8;
|
||||
using archive_type = cereal::SettingsTextArchive;
|
||||
using array_type = typename archive_type::array_type;
|
||||
using unique_set = typename archive_type::unique_set;
|
||||
using width_type = array_t<int64_t, size>;
|
||||
using width_bool = array_t<bool, size>;
|
||||
|
||||
width_type _widths = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
width_type _widths = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
width_bool _wusing = {
|
||||
true, !force_brief, opts[0], opts[1], opts[1], opts[1], opts[2]
|
||||
true, !force_brief, opts[0], opts[1], opts[1], opts[1], opts[2], opts[3],
|
||||
};
|
||||
width_bool _mark = { false, false, false, true, true, true, false };
|
||||
width_bool _mark = { false, false, false, true, true, true, false, false };
|
||||
|
||||
// this settings has delayed initialization. make sure it is generated
|
||||
(void) omnitrace::config::get_perfetto_output_filename();
|
||||
|
||||
array_type _setting_output;
|
||||
unique_set _settings_exclude = { "OMNITRACE_ENVIRONMENT", "OMNITRACE_COMMAND_LINE",
|
||||
"cereal_class_version", "settings" };
|
||||
|
||||
#if !defined(TIMEMORY_USE_CRAYPAT)
|
||||
_settings_exclude.emplace("OMNITRACE_CRAYPAT");
|
||||
#endif
|
||||
|
||||
cereal::SettingsTextArchive settings_archive{ _setting_output, _settings_exclude };
|
||||
cereal::SettingsTextArchive settings_archive{ _setting_output, settings_exclude };
|
||||
settings::serialize_settings(settings_archive);
|
||||
|
||||
// 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)_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)$";
|
||||
// leading matches, e.g. OMNITRACE_MPI_[A-Z_]+
|
||||
std::string _settings_rexclude_begin =
|
||||
"^OMNITRACE_(ERT|DART|MPI|UPCXX|ROOFLINE|CUDA|NVTX|CUPTI)_[A-Z_]+$";
|
||||
_setting_output.erase(
|
||||
std::remove_if(_setting_output.begin(), _setting_output.end(),
|
||||
[](const auto& itr) { return itr.find("environ") == itr.end(); }),
|
||||
_setting_output.end());
|
||||
|
||||
// lambda for deciding which settings we want to restrict displaying
|
||||
auto&& _remove_conditions = [&_settings_exclude, &_settings_rexclude_exact,
|
||||
&_settings_rexclude_begin](const auto& itr) {
|
||||
auto&& _v = itr.find("environ")->second;
|
||||
bool _a = _settings_exclude.find(_v) != _settings_exclude.end();
|
||||
bool _b = std::regex_match(_v, std::regex(_settings_rexclude_exact));
|
||||
bool _c = std::regex_match(_v, std::regex(_settings_rexclude_begin));
|
||||
return (_a || _b || _c);
|
||||
};
|
||||
// patch up the categories
|
||||
str_set_t _not_in_category_view{};
|
||||
auto _settings = tim::settings::shared_instance();
|
||||
for(auto& itr : _setting_output)
|
||||
{
|
||||
auto _name = itr.find("environ")->second;
|
||||
auto sitr = _settings->find(_name);
|
||||
if(sitr != _settings->end())
|
||||
{
|
||||
str_set_t _categories{};
|
||||
for(const auto& citr : sitr->second->get_categories())
|
||||
{
|
||||
if(citr == "native")
|
||||
_categories.emplace("settings::timemory");
|
||||
else
|
||||
_categories.emplace(TIMEMORY_JOIN("::", "settings", citr));
|
||||
}
|
||||
bool _found = false;
|
||||
for(const auto& citr : _categories)
|
||||
{
|
||||
if(category_view.count(citr) > 0) _found = true;
|
||||
}
|
||||
if(!_found)
|
||||
{
|
||||
_not_in_category_view.emplace(_name);
|
||||
continue;
|
||||
}
|
||||
std::stringstream _ss{};
|
||||
for(const auto& citr : sitr->second->get_categories())
|
||||
_ss << ", " << citr;
|
||||
if(!_ss.str().empty())
|
||||
{
|
||||
itr["categories"] = _ss.str().substr(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// erase excluded settings and erase settings not in category view
|
||||
_setting_output.erase(
|
||||
std::remove_if(_setting_output.begin(), _setting_output.end(),
|
||||
[&_not_in_category_view](const auto& itr) {
|
||||
return (exclude_setting(itr.find("environ")->second) ||
|
||||
_not_in_category_view.count(
|
||||
itr.find("environ")->second) > 0);
|
||||
}),
|
||||
_setting_output.end());
|
||||
|
||||
_setting_output.erase(std::remove_if(_setting_output.begin(), _setting_output.end(),
|
||||
_remove_conditions),
|
||||
[](const auto& itr) {
|
||||
return !is_category_selected(
|
||||
itr.find("categories")->second);
|
||||
}),
|
||||
_setting_output.end());
|
||||
|
||||
if(alphabetical)
|
||||
@@ -753,14 +949,16 @@ write_settings_info(std::ostream& os, const array_t<bool, N>& opts,
|
||||
}
|
||||
|
||||
array_t<string_t, size> _labels = {
|
||||
"ENVIRONMENT VARIABLE", "VALUE", "DATA TYPE", "C++ STATIC ACCESSOR",
|
||||
"C++ MEMBER ACCESSOR", "Python ACCESSOR", "DESCRIPTION"
|
||||
"ENVIRONMENT VARIABLE", "VALUE", "DATA TYPE", "C++ STATIC ACCESSOR",
|
||||
"C++ MEMBER ACCESSOR", "Python ACCESSOR", "DESCRIPTION", "CATEGORIES",
|
||||
};
|
||||
array_t<string_t, size> _keys = { "environ", "value",
|
||||
"data_type", "static_accessor",
|
||||
"member_accessor", "python_accessor",
|
||||
"description" };
|
||||
array_t<bool, size> _center = { false, true, true, false, false, false, false };
|
||||
"description", "categories" };
|
||||
array_t<bool, size> _center = {
|
||||
false, true, true, false, false, false, false, false
|
||||
};
|
||||
|
||||
for(size_t i = 0; i < _widths.size(); ++i)
|
||||
{
|
||||
@@ -1039,11 +1237,42 @@ using component_value_type_t =
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
template <typename... Tp>
|
||||
auto get_categories(type_list<Tp...>)
|
||||
{
|
||||
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
|
||||
|
||||
auto _vec = str_vec_t{ _cleanup(demangle<Tp>(), "tim::")... };
|
||||
std::sort(_vec.begin(), _vec.end(), [](const auto& lhs, const auto& rhs) {
|
||||
// prioritize project category
|
||||
auto lpos = lhs.find("project::");
|
||||
auto rpos = rhs.find("project::");
|
||||
return (lpos == rpos) ? (lhs < rhs) : (lpos < rpos);
|
||||
});
|
||||
std::stringstream _ss{};
|
||||
for(auto&& itr : _vec)
|
||||
{
|
||||
_ss << ", " << itr;
|
||||
}
|
||||
std::string _v = _ss.str();
|
||||
if(!_v.empty()) return _v.substr(2);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
template <typename Type>
|
||||
info_type
|
||||
get_availability<Type>::get_info()
|
||||
{
|
||||
using value_type = component_value_type_t<Type>;
|
||||
using value_type = component_value_type_t<Type>;
|
||||
using category_types = typename trait::component_apis<Type>::type;
|
||||
|
||||
auto _cleanup = [](std::string _type, const std::string& _pattern) {
|
||||
auto _pos = std::string::npos;
|
||||
@@ -1080,22 +1309,26 @@ get_availability<Type>::get_info()
|
||||
id_type = "";
|
||||
ids_set.clear();
|
||||
}
|
||||
auto itr = ids_set.begin();
|
||||
string_t db = (markdown) ? "`\"" : "\"";
|
||||
string_t de = (markdown) ? "\"`" : "\"";
|
||||
if(has_metadata) description += ". " + metadata_t::extra_description();
|
||||
description += ".";
|
||||
while(itr->empty())
|
||||
++itr;
|
||||
string_t ids_str = {};
|
||||
if(itr != ids_set.end())
|
||||
ids_str = TIMEMORY_JOIN("", TIMEMORY_JOIN("", db, *itr++, de));
|
||||
for(; itr != ids_set.end(); ++itr)
|
||||
{
|
||||
if(!itr->empty())
|
||||
ids_str = TIMEMORY_JOIN(" ", ids_str, TIMEMORY_JOIN("", db, *itr, de));
|
||||
auto itr = ids_set.begin();
|
||||
string_t db = (markdown) ? "`\"" : "\"";
|
||||
string_t de = (markdown) ? "\"`" : "\"";
|
||||
if(has_metadata) description += ". " + metadata_t::extra_description();
|
||||
description += ".";
|
||||
while(itr->empty())
|
||||
++itr;
|
||||
if(itr != ids_set.end())
|
||||
ids_str = TIMEMORY_JOIN("", TIMEMORY_JOIN("", db, *itr++, de));
|
||||
for(; itr != ids_set.end(); ++itr)
|
||||
{
|
||||
if(!itr->empty())
|
||||
ids_str = TIMEMORY_JOIN(" ", ids_str, TIMEMORY_JOIN("", db, *itr, de));
|
||||
}
|
||||
}
|
||||
|
||||
string_t categories = get_categories(category_types{});
|
||||
|
||||
#if 0
|
||||
auto _remove_typelist = [](std::string _tmp) {
|
||||
if(_tmp.empty()) return _tmp;
|
||||
@@ -1120,7 +1353,7 @@ get_availability<Type>::get_info()
|
||||
data_type = _replace(_cleanup(data_type, "::__1"), "> >", ">>");
|
||||
return info_type{ name, is_available,
|
||||
str_vec_t{ data_type, enum_type, id_type, ids_str, label,
|
||||
description } };
|
||||
description, categories } };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -1393,6 +1626,65 @@ regex_replace(const std::string& _line)
|
||||
#endif
|
||||
return _line;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
get_category_regex_pattern()
|
||||
{
|
||||
static std::string _pattern = []() {
|
||||
std::string _v{};
|
||||
for(const auto& itr : category_regex_keys)
|
||||
{
|
||||
lerr << "Adding regex key: '" << itr << "'...\n";
|
||||
_v += "|" + itr;
|
||||
}
|
||||
return (_v.empty()) ? _v : _v.substr(1);
|
||||
}();
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
auto
|
||||
get_category_regex()
|
||||
{
|
||||
static auto _rc = std::regex(get_category_regex_pattern(), get_regex_constants());
|
||||
return _rc;
|
||||
}
|
||||
|
||||
bool
|
||||
category_regex_match(const std::string& _line)
|
||||
{
|
||||
if(get_regex_pattern().empty()) return true;
|
||||
|
||||
static size_t lerr_width = 0;
|
||||
lerr_width = std::max<size_t>(lerr_width, _line.length());
|
||||
std::stringstream _line_ss;
|
||||
_line_ss << "'" << _line << "'";
|
||||
|
||||
if(std::regex_match(_line, get_category_regex()))
|
||||
{
|
||||
lerr << std::left << std::setw(lerr_width) << _line_ss.str()
|
||||
<< " matched pattern '" << get_category_regex_pattern() << "'...\n";
|
||||
return true;
|
||||
}
|
||||
if(std::regex_search(_line, get_category_regex()))
|
||||
{
|
||||
lerr << std::left << std::setw(lerr_width) << _line_ss.str() << " found pattern '"
|
||||
<< get_category_regex_pattern() << "'...\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
lerr << std::left << std::setw(lerr_width) << _line_ss.str() << " missing pattern '"
|
||||
<< get_category_regex_pattern() << "'...\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
exclude_setting(const std::string& _v)
|
||||
{
|
||||
bool _a = settings_exclude.find(_v) != settings_exclude.end();
|
||||
bool _b = std::regex_match(_v, std::regex{ settings_rexclude_exact });
|
||||
bool _c = std::regex_match(_v, std::regex{ settings_rexclude_begin });
|
||||
return (_a || _b || _c);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -1405,6 +1697,14 @@ is_selected(const std::string& _line)
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
bool
|
||||
is_category_selected(const std::string& _line)
|
||||
{
|
||||
return category_regex_match(_line);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
std::string
|
||||
hl_selected(const std::string& _line)
|
||||
{
|
||||
@@ -1412,3 +1712,38 @@ hl_selected(const std::string& _line)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
void
|
||||
process_categories(parser_t& p, const str_set_t& _category_options)
|
||||
{
|
||||
category_view = p.get<str_set_t>("categories");
|
||||
std::vector<std::function<void()>> _shorthand_patches{};
|
||||
for(const auto& itr : category_view)
|
||||
{
|
||||
auto _is_shorthand = [&_shorthand_patches, &_category_options,
|
||||
itr](const std::string& _prefix) {
|
||||
auto _opt = TIMEMORY_JOIN("::", _prefix, itr);
|
||||
if(_category_options.count(_opt) > 0)
|
||||
{
|
||||
_shorthand_patches.emplace_back([itr, _opt]() {
|
||||
category_view.erase(itr);
|
||||
category_view.emplace(_opt);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if(_category_options.count(itr) == 0)
|
||||
{
|
||||
if(!_is_shorthand("component") && !_is_shorthand("settings"))
|
||||
throw std::runtime_error(
|
||||
itr + " is not a valid category. Use --list-categories to view "
|
||||
"valid categories");
|
||||
}
|
||||
}
|
||||
for(auto&& itr : _shorthand_patches)
|
||||
itr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
@@ -22,14 +22,65 @@
|
||||
|
||||
#include "omnitrace.hpp"
|
||||
|
||||
static int expect_error = NO_ERROR;
|
||||
static int error_print = 0;
|
||||
static auto regex_opts = std::regex_constants::egrep | std::regex_constants::optimize;
|
||||
static int expect_error = NO_ERROR;
|
||||
static int error_print = 0;
|
||||
|
||||
// set of whole function names to exclude
|
||||
strset_t
|
||||
get_whole_function_names()
|
||||
{
|
||||
#if 1
|
||||
return strset_t{ "sem_init",
|
||||
"sem_destroy",
|
||||
"sem_open",
|
||||
"sem_close",
|
||||
"sem_post",
|
||||
"sem_wait",
|
||||
"sem_getvalue",
|
||||
"sem_clockwait",
|
||||
"sem_timedwait",
|
||||
"sem_trywait",
|
||||
"do_futex_wait",
|
||||
"sem_unlink",
|
||||
"fork",
|
||||
"dl_iterate_phdr",
|
||||
"dlinfo",
|
||||
"dlopen",
|
||||
"dlmopen",
|
||||
"dlvsym",
|
||||
"dlsym",
|
||||
"getenv",
|
||||
"setenv",
|
||||
"unsetenv",
|
||||
"fflush",
|
||||
"malloc",
|
||||
"malloc_stats",
|
||||
"malloc_trim",
|
||||
"mallopt",
|
||||
"calloc",
|
||||
"free",
|
||||
"pvalloc",
|
||||
"valloc",
|
||||
"mmap",
|
||||
"munmap",
|
||||
"fmemopen",
|
||||
"fmemclose",
|
||||
"backtrace",
|
||||
"backtrace_symbols",
|
||||
"backtrace_symbols_fd",
|
||||
"sigaddset",
|
||||
"sigandset",
|
||||
"sigdelset",
|
||||
"sigemptyset",
|
||||
"sigfillset",
|
||||
"sighold",
|
||||
"sigisemptyset",
|
||||
"sigismember",
|
||||
"sigorset",
|
||||
"sigrelse",
|
||||
"sigvec" };
|
||||
#else
|
||||
// should hopefully be removed soon
|
||||
return strset_t{ "a64l",
|
||||
"advance",
|
||||
"aio_return",
|
||||
@@ -487,6 +538,7 @@ get_whole_function_names()
|
||||
"xencrypt",
|
||||
"xprt_register",
|
||||
"xprt_unregister" };
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -780,137 +832,3 @@ error_func_fake(error_level_t level, int num, const char* const* params)
|
||||
consume_parameters(level, num, params);
|
||||
// It does nothing.
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
//
|
||||
bool
|
||||
c_stdlib_module_constraint(const std::string& _file)
|
||||
{
|
||||
static std::regex _pattern(
|
||||
"^(a64l|accept4|alphasort|argp-help|argp-parse|asprintf|atof|atoi|atol|atoll|"
|
||||
"auth_des|auth_none|auth_unix|backtrace|backtracesyms|backtracesymsfd|c16rtomb|"
|
||||
"cacheinfo|canonicalize|carg|cargf|cargf128|cargl|"
|
||||
"catgets|cfmakeraw|cfsetspeed|check_pf|chflags|"
|
||||
"clearerr|clearerr_u|clnt_perr|clnt_raw|clnt_tcp|clnt_udp|clnt_unix"
|
||||
"settime|copy_file_range|"
|
||||
"creat64|ctermid|ctime|ctime_r|ctype|ctype-c99|ctype-c99_l|ctype-extn|ctype_l|"
|
||||
"cuserid|daemon|dcigettext|difftime|dirname|div|dl-error|dl-libc|dl-sym|dlerror|"
|
||||
"duplocale|dysize|endutxent|envz|epoll_wait|"
|
||||
"ether_aton|ether_aton_r|ether_hton|ether_line|ether_ntoa|ether_ntoh|eventfd_"
|
||||
"read|eventfd_write|execlp|execv|execvp|explicit_bzero|faccessat|fallocate64|"
|
||||
"fattach|fchflags|fchmodat|fdatasync|fdetach|fdopendir|fedisblxcpt|feenablxcpt|"
|
||||
"fegetexcept|fegetmode|feholdexcpt|feof_u|ferror_u|fesetenv|fesetexcept|"
|
||||
"fesetmode|fesetround|fetestexceptflag|fexecve|ffsll|fgetexcptflg|fgetgrent|"
|
||||
"fgetpwent|fgetsgent|fgetspent|fileno|fmemopen|fmtmsg|fnmatch|fprintf|fputc|"
|
||||
"fputc_u|fputwc|fputwc_u|freopen|freopen64|fscanf|fseeko|fsetexcptflg|fstab|"
|
||||
"fsync|ftello|ftime|ftok|fts|ftw|futimens|futimesat|fwide|fxprintf|gconv_conf|"
|
||||
"gconv_db|gconv_dl|genops|getaddrinfo|getaliasent|getaliasent_r|getaliasname|"
|
||||
"getauxval|getc|getchar|getchar_u|getdate|getdirentries|getdirname|getentropy|"
|
||||
"getenv|getgrent|getgrent_r|getgrgid|getgrnam|gethostid|gethstbyad|gethstbynm|"
|
||||
"gethstbynm2|gethstent|gethstent_r|getipv4sourcefilter|getloadavg|getlogin|"
|
||||
"getlogin_r|getmsg|getnameinfo|getnetbyad|getnetbynm|getnetent|getnetent_r|"
|
||||
"getnetgrent|getnetgrent_r|getopt|getopt1|getpass|getproto|getprtent|getprtent_r|"
|
||||
"getprtname|getpwent|getpwent_r|getpwnam|getpwnam_r|getpwuid|getrandom|"
|
||||
"getrpcbyname|getrpcbynumber|getrpcent|getrpcent_r|getrpcport|getservent|"
|
||||
"getservent_r|getsgent|getsgent_r|getsgnam|getsourcefilter|getspent|getspent_r|"
|
||||
"getspnam|getsrvbynm|getsrvbynm_r|getsrvbypt|getsubopt|getsysstats|getttyent|"
|
||||
"getusershell|getutent_r|getutline|getutmp|getutxent|getutxid|getutxline|getw|"
|
||||
"getwchar|getwchar_u|getwd|glob|gmon|gmtime|grantpt|group_member|gtty|herror|"
|
||||
"hsearch|hsearch_r|htons|iconv|iconv_close|iconv_open|idn-stub|if_index|ifaddrs|"
|
||||
"inet6_|inet_|inet_|initgroups|insremque|iofgets|iofgetws|iofgetws_u|iofputws|"
|
||||
"iofwide|iopopen|ioungetwc|isastream|isctype|isfdtype|key_call|key_prot|killpg|"
|
||||
"l64a|labs|lchmod|lckpwdf|lcong48|ldiv|llabs|lldiv|lockf|longjmp|lsearch|lutimes|"
|
||||
"makedev|malloc|mblen|mbrtoc16|mbsinit|mbstowcs|mbtowc|mcheck|memccpy|"
|
||||
"memchr|memcmp|memfrob|memmem|memset|memstream|mkdtemp|mkfifo|mkfifoat|mkostemp|"
|
||||
"mkostemps|mkstemp|mkstemps|mktemp|mlock2|mntent|mntent_r|mpa|"
|
||||
"msgctl|msgget|msgsnd|msort|msync|mtrace|netname|nice|nl_langinfo|nsap_addr|nscd_"
|
||||
"getgr_r|nscd_gethst_r|nscd_getpw_r|nscd_getserv_r|nscd_helper|"
|
||||
"nsswitch|ntp_gettime|ntp_gettimex|obprintf|obstack|oldfmemopen|open_by_handle_"
|
||||
"at|opendir|pathconf|pclose|perror|pkey_mprotect|pm_getmaps|pmap_prot|pmap_rmt|"
|
||||
"posix_fallocate|posix_fallocate64|preadv64|preadv64v2|printf-prs|printf_fp|"
|
||||
"printf_size|profil|psiginfo|psignal|ptrace|ptsname|putc_u|putchar|putchar_u|"
|
||||
"putenv|putgrent|putmsg|putpwent|putsgent|putspent|pututxline|putw|putwc_u|"
|
||||
"putwchar|putwchar_u|pwritev64|pwritev64v2|raise|rcmd|readv|"
|
||||
"reboot|recvfrom|recvmmsg|regex|regexp|remove|rename|renameat|res-close|res_"
|
||||
"hconf|res_init|resolv_conf|rexec|rpc_thread|rpmatch|ruserpass|scandir|sched_"
|
||||
"cpucount|sched_getaffinity|sched_getcpu|seed48|seekdir|semget|semop|semtimedop|"
|
||||
"sendmsg|setbuf|setegid|seteuid|sethostid|setipv4sourcefilter|setlinebuf|"
|
||||
"setlogin|setpgrp|setresuid|setrlimit64|setsourcefilter|setutxent|sgetsgent|"
|
||||
"sgetspent|shmat|shmdt|shmget|sigandset|sigdelset|siggetmask|sighold|sigignore|"
|
||||
"sigintr|sigisempty|signalfd|sigorset|sigpause|sigpending|sigrelse|sigset|"
|
||||
"sigstack|sockatmark|speed|splice|sprofil|sscanf|sstk|stime|strcasecmp|"
|
||||
"strcasestr|strcat|strchr|strcmp|strcpy|strcspn|strerror|strerror_l|strfmon|"
|
||||
"strfromd|strfromf|strfromf128|strfroml|strfry|strlen|strncase|strncat|strncmp|"
|
||||
"strncpy|strpbrk|strrchr|strsignal|strspn|strstr|strtod_l|strtof|strtof128_l|"
|
||||
"strtof_l|strtoimax|strtok|strtol_l|strtold_l|strtoul|strtoumax|strxfrm|stty|svc|"
|
||||
"svc_raw|svc_simple|svc_tcp|svc_udp|svc_unix|swab|sync_file_range|syslog|system|"
|
||||
"tcflow|tcflush|tcgetattr|tcgetsid|tcsendbrk|tcsetpgrp|tee|telldir|tempnam|"
|
||||
"tmpnam|tmpnam_r|tsearch|ttyname|ttyname_r|ttyslot|tzset|ualarm|ulimit|umount|"
|
||||
"unlockpt|updwtmpx|ustat|utimensat|utmp_file|utmpxname|version|"
|
||||
"versionsort|vfprintf|vfscanf|vfwscanf|vlimit|vmsplice|vprintf|vtimes|wait[0-9]|"
|
||||
"wcfuncs|wcfuncs_l|wcscpy|wcscspn|wcsdup|wcsncat|wcsncmp|wcsnrtombs|wcspbrk|"
|
||||
"wcsrchr|wcsstr|wcstod_l|wcstof|wcstoimax|wcstok|wcstold_l|wcstombs|wcstoumax|"
|
||||
"wcswidth|wcsxfrm|wctob|wctype_l|wcwidth|wfileops|wgenops|wmemcmp|wmemstream|"
|
||||
"wordexp|wstrops|x2y2m1l|xcrypt|xdr|xdr_float|xdr_intXX_t|xdr_mem|xdr_rec|xdr_"
|
||||
"ref|xdr_sizeof|xdr_stdio|mq_notify|aio_|timer_routines|nptl-|shm-|sem_close|"
|
||||
"setuid|pt-raise|x2y2)",
|
||||
regex_opts);
|
||||
|
||||
return std::regex_search(_file, _pattern);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
//
|
||||
bool
|
||||
c_stdlib_function_constraint(const std::string& _func)
|
||||
{
|
||||
static std::regex _pattern(
|
||||
"^(malloc|calloc|free|buffer|fscan|fstab|internal|gnu|fprint|isalnum|isalpha|"
|
||||
"isascii|isastream|isblank|isblank_l|iscntrl|isctype|isdigit|isdigit_l|isfdtype|"
|
||||
"isgraph|islower|islower_l|isprint|isprint_l|ispunct|isspace|isupper|isupper_l|"
|
||||
"iswprint|isxdigit|asprintf|atof|atoi|atol|atoll|memalign|memccpy|memcpy|memchr|"
|
||||
"memcmp|memfrob|memset|mkdtemp|mkfifo|mkfifoat|mkostemp64|mkostemps64|mkstemp|"
|
||||
"mkstemps64|mktemp|mlock2|monstartup|mprobe|mremap_chunk|get_current_dir_name|"
|
||||
"get_free_list|getaliasbyname|getaliasent|getauxval|getchar|getchar_unlocked|"
|
||||
"getdate|getdirentries|getentropy|getenv|getfs|getgrent|getgrgid|"
|
||||
"getgrnam|getgrouplist|gethostbyaddr|gethostbyname|gethostbyname2|gethostent|"
|
||||
"gethostid|getifaddrs|getifaddrs_internal|getipv4sourcefilter|getkeyserv_handle|"
|
||||
"getloadavg|getlogin|getlogin_fd0|getlogin_r_fd0|getmntent|getmsg|getnetbyaddr|"
|
||||
"getnetbyname|getnetent|getnetgrent|getopt|getopt_long|getopt_long_only|getpass|"
|
||||
"getprotobyname|getprotobynumber|getprotoent|getpwent|getpwnam|getpwnam_r|"
|
||||
"getpwuid|getrandom|getrpcbyname|getrpcbynumber|getrpcent|getrpcport|"
|
||||
"getservbyname|getservbyname_r|getservbyport|getservent|getsgent|getsgnam|"
|
||||
"getsourcefilter|getspent|getspnam|getsubopt|getttyname|getttyname_r|"
|
||||
"getusershell|getutent_r_file|getutent_r_unknown|getutid_r_file|getutid_r_"
|
||||
"unknown|getutline|getutline_r_file|getutline_r_unknown|getutmp|getutxent|"
|
||||
"getutxid|getutxline|getw|psiginfo|psignal|ptmalloc_init|ptrace|ptsname|putc_"
|
||||
"unlocked|putchar|putchar_unlocked|putenv|putgrent|putmsg|putpwent|putsgent|"
|
||||
"putspent|pututline_file|pututxline|putw|pw_map_free|pwritev|pwritev2|"
|
||||
"qsort|raise|rcmd|re_acquire_state|re_acquire_state_context|re_"
|
||||
"comp|re_compile_internal|re_dfa_add_node|re_exec|re_node_set_init_union|re_node_"
|
||||
"set_insert|re_node_set_merge|re_search_internal|re_search_stub|re_string_"
|
||||
"context_at|re_string_reconstruct|readtcp|readunix|readv|realloc|realpath|str_to_"
|
||||
"mpn|strcasecmp|strcat|strcmp|strcpy|strcspn|strerror|strerror_l|strerror_thread_"
|
||||
"freeres|strfmon|strfromd|strfromf|strfromf128|strfroml|strfry|strlen|"
|
||||
"strncasecmp|strncat|strncmp|strncpy|strpbrk|strrchr|strsignal|strspn|strtof32|"
|
||||
"strtoimax|strtok|strtol_l|strtold_l|strtoull|strtoumax|strxfrm|xdrstdio|xdrmem|"
|
||||
"inet_|inet6_|clock_|backtrace_|dummy_|fts_|fts64_|fexecv|execv|stime|ftime|"
|
||||
"gmtime|wcs|envz_|fmem|fputc|fgetc|fputwc|fgetwc|vprintf|feget|fetest|feenable|"
|
||||
"feset|fedisable|nscd_|fork|execl|tzset|ntp_|mtrace|tr_[a-z]+hook|mcheck_[a-z_]+"
|
||||
"ftell|fputs|fgets|siglongjmp|sigdelset|killpg|tolower|toupper|daemon|"
|
||||
"iconv_[a-z_]+|catopen|catgets|catclose|check_add_mapping$|sem_open|sem_close|"
|
||||
"sem_unlink|do_futex_wait|sem_timedwait|unwind_stop|unwind_cleanup|longjmp_"
|
||||
"compat|vfork_|elision_init|cr_|cri_|aio_|mq_|sem_init|waitpid$|sigcancel_"
|
||||
"handler|sighandler_setxid|start_thread$|clock$|semctl$|shm_open$|shm_unlink$|"
|
||||
"printf|dprintf|walker$|clear_once_control$|libcr_|sem_wait$|sem_trywait$|vfork|"
|
||||
"pause$|wait$|waitid$|msgrcv$|sigwait$|sigsuspend$|recvmsg$|sendmsg$|"
|
||||
"ftrylockfile$|funlockfile$|tee$|setbuf$|setbuffer$|enlarge_userbuf$|convert_and_"
|
||||
"print$|feraise|lio_|atomic_|err$|errx$|print_errno_message$|error_tail$|"
|
||||
"clntunix_|sem_destroy|setxid_mark_thread|feupdate|send$|connect$|longjmp|pwrite|"
|
||||
"accept$|stpncpy$|writeunix$|xflowf$|mbrlen$)",
|
||||
regex_opts);
|
||||
|
||||
return std::regex_search(_func, _pattern);
|
||||
}
|
||||
//======================================================================================//
|
||||
//
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,10 @@
|
||||
#include <timemory/backends/process.hpp>
|
||||
#include <timemory/environment.hpp>
|
||||
#include <timemory/mpl/apply.hpp>
|
||||
#include <timemory/mpl/concepts.hpp>
|
||||
#include <timemory/mpl/policy.hpp>
|
||||
#include <timemory/tpls/cereal/archives.hpp>
|
||||
#include <timemory/tpls/cereal/cereal.hpp>
|
||||
#include <timemory/utility/argparse.hpp>
|
||||
#include <timemory/utility/demangle.hpp>
|
||||
#include <timemory/utility/popen.hpp>
|
||||
@@ -45,12 +49,16 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <ostream>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
@@ -76,6 +84,7 @@ using strvec_t = std::vector<string_t>;
|
||||
using strset_t = std::set<string_t>;
|
||||
using regexvec_t = std::vector<std::regex>;
|
||||
using fmodset_t = std::set<module_function>;
|
||||
using fixed_modset_t = std::map<fmodset_t*, bool>;
|
||||
using exec_callback_t = BPatchExecCallback;
|
||||
using exit_callback_t = BPatchExitCallback;
|
||||
using fork_callback_t = BPatchForkCallback;
|
||||
@@ -142,10 +151,14 @@ static snippet_vec_t fini_names = {};
|
||||
static fmodset_t available_module_functions = {};
|
||||
static fmodset_t instrumented_module_functions = {};
|
||||
static fmodset_t overlapping_module_functions = {};
|
||||
static fmodset_t excluded_module_functions = {};
|
||||
static fixed_modset_t fixed_module_functions = {};
|
||||
static regexvec_t func_include = {};
|
||||
static regexvec_t func_exclude = {};
|
||||
static regexvec_t file_include = {};
|
||||
static regexvec_t file_exclude = {};
|
||||
static regexvec_t file_restrict = {};
|
||||
static regexvec_t func_restrict = {};
|
||||
//
|
||||
//======================================================================================//
|
||||
|
||||
@@ -217,12 +230,6 @@ error_func_real(error_level_t level, int num, const char* const* params);
|
||||
void
|
||||
error_func_fake(error_level_t level, int num, const char* const* params);
|
||||
|
||||
bool
|
||||
c_stdlib_module_constraint(const string_t& file);
|
||||
|
||||
bool
|
||||
c_stdlib_function_constraint(const string_t& func);
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
inline string_t
|
||||
@@ -277,6 +284,19 @@ struct function_signature
|
||||
|
||||
TIMEMORY_DEFAULT_OBJECT(function_signature)
|
||||
|
||||
template <typename ArchiveT>
|
||||
void serialize(ArchiveT& _ar, const unsigned)
|
||||
{
|
||||
namespace cereal = tim::cereal;
|
||||
(void) get();
|
||||
_ar(cereal::make_nvp("loop", m_loop), cereal::make_nvp("info_beg", m_info_beg),
|
||||
cereal::make_nvp("info_end", m_info_end), cereal::make_nvp("row", m_row),
|
||||
cereal::make_nvp("col", m_col), cereal::make_nvp("return", m_return),
|
||||
cereal::make_nvp("name", m_name), cereal::make_nvp("params", m_params),
|
||||
cereal::make_nvp("file", m_file), cereal::make_nvp("signature", m_signature));
|
||||
(void) get();
|
||||
}
|
||||
|
||||
function_signature(string_t _ret, const string_t& _name, string_t _file,
|
||||
location_t _row = { 0, 0 }, location_t _col = { 0, 0 },
|
||||
bool _loop = false, bool _info_beg = false, bool _info_end = false)
|
||||
@@ -294,8 +314,8 @@ struct function_signature
|
||||
}
|
||||
|
||||
function_signature(const string_t& _ret, const string_t& _name, const string_t& _file,
|
||||
const std::vector<string_t>& _params, location_t&& _row = { 0, 0 },
|
||||
location_t&& _col = { 0, 0 }, bool _loop = false,
|
||||
const std::vector<string_t>& _params, location_t _row = { 0, 0 },
|
||||
location_t _col = { 0, 0 }, bool _loop = false,
|
||||
bool _info_beg = false, bool _info_end = false)
|
||||
: function_signature(_ret, _name, _file, _row, _col, _loop, _info_beg, _info_end)
|
||||
{
|
||||
@@ -306,6 +326,11 @@ struct function_signature
|
||||
m_params += ")";
|
||||
}
|
||||
|
||||
friend bool operator==(const function_signature& lhs, const function_signature& rhs)
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
static auto get(function_signature& sig) { return sig.get(); }
|
||||
|
||||
string_t get() const
|
||||
@@ -354,6 +379,8 @@ struct module_function
|
||||
return _instance;
|
||||
}
|
||||
|
||||
TIMEMORY_DEFAULT_OBJECT(module_function)
|
||||
|
||||
static void reset_width() { get_width().fill(0); }
|
||||
|
||||
static void update_width(const module_function& rhs)
|
||||
@@ -409,6 +436,12 @@ struct module_function
|
||||
: (lhs.module < rhs.module);
|
||||
}
|
||||
|
||||
friend bool operator==(const module_function& lhs, const module_function& rhs)
|
||||
{
|
||||
return std::tie(lhs.module, lhs.function, lhs.signature, lhs.address_range) ==
|
||||
std::tie(rhs.module, rhs.function, rhs.signature, rhs.address_range);
|
||||
}
|
||||
|
||||
static void write_header(std::ostream& os)
|
||||
{
|
||||
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
|
||||
@@ -452,7 +485,16 @@ struct module_function
|
||||
size_t address_range = 0;
|
||||
string_t module = {};
|
||||
string_t function = {};
|
||||
function_signature signature;
|
||||
function_signature signature = {};
|
||||
|
||||
template <typename ArchiveT>
|
||||
void serialize(ArchiveT& _ar, const unsigned)
|
||||
{
|
||||
namespace cereal = tim::cereal;
|
||||
_ar(cereal::make_nvp("address_range", address_range),
|
||||
cereal::make_nvp("module", module), cereal::make_nvp("function", function),
|
||||
cereal::make_nvp("signature", signature));
|
||||
}
|
||||
};
|
||||
//
|
||||
//======================================================================================//
|
||||
@@ -471,26 +513,215 @@ dump_info(std::ostream& _os, const fmodset_t& _data)
|
||||
module_function::reset_width();
|
||||
}
|
||||
//
|
||||
template <typename ArchiveT,
|
||||
std::enable_if_t<tim::concepts::is_archive<ArchiveT>::value, int> = 0>
|
||||
static inline void
|
||||
dump_info(const string_t& _oname, const fmodset_t& _data, int _level, bool _fail)
|
||||
dump_info(ArchiveT& _ar, const fmodset_t& _data)
|
||||
{
|
||||
_ar(tim::cereal::make_nvp("module_functions", _data));
|
||||
}
|
||||
//
|
||||
static inline void
|
||||
dump_info(const string_t& _label, string_t _oname, const string_t& _ext,
|
||||
const fmodset_t& _data, int _level, bool _fail)
|
||||
{
|
||||
namespace cereal = tim::cereal;
|
||||
namespace policy = tim::policy;
|
||||
|
||||
_oname += "." + _ext;
|
||||
auto _handle_error = [&]() {
|
||||
std::stringstream _msg{};
|
||||
_msg << "[dump_info] Error opening '" << _oname << " for output";
|
||||
verbprintf(_level, "%s\n", _msg.str().c_str());
|
||||
if(_fail)
|
||||
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
|
||||
};
|
||||
|
||||
if(!debug_print && verbose_level < _level) return;
|
||||
|
||||
std::ofstream ofs{ _oname };
|
||||
if(ofs)
|
||||
if(_ext == "txt")
|
||||
{
|
||||
verbprintf(_level, "Dumping '%s'... ", _oname.c_str());
|
||||
dump_info(ofs, _data);
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
std::ofstream ofs{};
|
||||
if(!tim::filepath::open(ofs, _oname))
|
||||
_handle_error();
|
||||
else
|
||||
{
|
||||
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
|
||||
dump_info(ofs, _data);
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
else if(_ext == "xml")
|
||||
{
|
||||
std::stringstream oss{};
|
||||
{
|
||||
using output_policy = policy::output_archive<cereal::XMLOutputArchive>;
|
||||
output_policy::indent() = true;
|
||||
auto ar = output_policy::get(oss);
|
||||
|
||||
ar->setNextName("omnitrace");
|
||||
ar->startNode();
|
||||
ar->setNextName(_label.c_str());
|
||||
ar->startNode();
|
||||
(*ar)(cereal::make_nvp("module_functions", _data));
|
||||
ar->finishNode();
|
||||
ar->finishNode();
|
||||
}
|
||||
|
||||
std::ofstream ofs{};
|
||||
if(!tim::filepath::open(ofs, _oname))
|
||||
_handle_error();
|
||||
else
|
||||
{
|
||||
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
|
||||
ofs << oss.str() << std::endl;
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
else if(_ext == "json")
|
||||
{
|
||||
std::stringstream oss{};
|
||||
{
|
||||
using output_policy = policy::output_archive<cereal::PrettyJSONOutputArchive>;
|
||||
auto ar = output_policy::get(oss);
|
||||
|
||||
ar->setNextName("omnitrace");
|
||||
ar->startNode();
|
||||
ar->setNextName(_label.c_str());
|
||||
ar->startNode();
|
||||
(*ar)(cereal::make_nvp("module_functions", _data));
|
||||
ar->finishNode();
|
||||
ar->finishNode();
|
||||
}
|
||||
|
||||
std::ofstream ofs{};
|
||||
if(!tim::filepath::open(ofs, _oname))
|
||||
_handle_error();
|
||||
else
|
||||
{
|
||||
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
|
||||
ofs << oss.str() << std::endl;
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream _msg{};
|
||||
_msg << "[" << __FUNCTION__ << "] Error opening '" << _oname << " for output";
|
||||
verbprintf(_level, "%s\n", _msg.str().c_str());
|
||||
if(_fail) throw std::runtime_error(_msg.str());
|
||||
throw std::runtime_error(TIMEMORY_JOIN(
|
||||
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _oname,
|
||||
"' does not have one of recognized file extensions: txt, json, xml"));
|
||||
}
|
||||
}
|
||||
//
|
||||
static inline void
|
||||
dump_info(const string_t& _oname, const fmodset_t& _data, int _level, bool _fail,
|
||||
const string_t& _type, const strset_t& _ext)
|
||||
{
|
||||
for(const auto& itr : _ext)
|
||||
dump_info(_type, _oname, itr, _data, _level, _fail);
|
||||
}
|
||||
//
|
||||
static inline void
|
||||
load_info(const string_t& _label, const string_t& _iname, fmodset_t& _data, int _level)
|
||||
{
|
||||
namespace cereal = tim::cereal;
|
||||
namespace policy = tim::policy;
|
||||
|
||||
auto _pos = _iname.find_last_of('.');
|
||||
std::string _ext = {};
|
||||
if(_pos != std::string::npos) _ext = _iname.substr(_pos + 1, _iname.length());
|
||||
|
||||
auto _handle_error = [&]() {
|
||||
std::stringstream _msg{};
|
||||
_msg << "[load_info] Error opening '" << _iname << " for input";
|
||||
verbprintf(_level, "%s\n", _msg.str().c_str());
|
||||
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
|
||||
};
|
||||
|
||||
if(_ext == "xml")
|
||||
{
|
||||
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
|
||||
std::ifstream ifs{ _iname };
|
||||
if(!ifs)
|
||||
_handle_error();
|
||||
else
|
||||
{
|
||||
using input_policy = policy::input_archive<cereal::XMLInputArchive>;
|
||||
auto ar = input_policy::get(ifs);
|
||||
|
||||
ar->setNextName("omnitrace");
|
||||
ar->startNode();
|
||||
ar->setNextName(_label.c_str());
|
||||
ar->startNode();
|
||||
(*ar)(cereal::make_nvp("module_functions", _data));
|
||||
ar->finishNode();
|
||||
ar->finishNode();
|
||||
}
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
ifs.close();
|
||||
}
|
||||
else if(_ext == "json")
|
||||
{
|
||||
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
|
||||
std::ifstream ifs{ _iname };
|
||||
if(!ifs)
|
||||
_handle_error();
|
||||
else
|
||||
{
|
||||
using input_policy = policy::input_archive<cereal::JSONInputArchive>;
|
||||
auto ar = input_policy::get(ifs);
|
||||
|
||||
ar->setNextName("omnitrace");
|
||||
ar->startNode();
|
||||
ar->setNextName(_label.c_str());
|
||||
ar->startNode();
|
||||
(*ar)(cereal::make_nvp("module_functions", _data));
|
||||
ar->finishNode();
|
||||
ar->finishNode();
|
||||
}
|
||||
verbprintf_bare(_level, "Done\n");
|
||||
ifs.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(TIMEMORY_JOIN(
|
||||
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _iname,
|
||||
"' does not have one of recognized extentions: txt, json, xml :: ", _ext));
|
||||
}
|
||||
}
|
||||
//
|
||||
static inline void
|
||||
load_info(const string_t& _inp, std::map<std::string, fmodset_t*>& _data, int _level)
|
||||
{
|
||||
std::vector<std::string> _exceptions{};
|
||||
_exceptions.reserve(_data.size());
|
||||
for(auto& itr : _data)
|
||||
{
|
||||
try
|
||||
{
|
||||
fmodset_t _tmp{};
|
||||
load_info(itr.first, _inp, _tmp, _level);
|
||||
// add to the existing
|
||||
itr.second->insert(_tmp.begin(), _tmp.end());
|
||||
// if it did not throw it was successfully loaded
|
||||
_exceptions.clear();
|
||||
break;
|
||||
} catch(std::exception& _e)
|
||||
{
|
||||
_exceptions.emplace_back(_e.what());
|
||||
}
|
||||
}
|
||||
if(!_exceptions.empty())
|
||||
{
|
||||
std::stringstream _msg{};
|
||||
for(auto& itr : _exceptions)
|
||||
{
|
||||
_msg << "[omnitrace][exe] " << itr << "\n";
|
||||
}
|
||||
throw std::runtime_error(_msg.str());
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
//
|
||||
//======================================================================================//
|
||||
|
||||
Reference in New Issue
Block a user