Binary instrumentation: more robust exclusion of functions used internally (#238)
## Overview
This PR attempts to increase the stability of binary rewrite and runtime instrumentation.
### Improved protection against self-instrumentation
Using ~~the binary analysis capabilities added from #229~~ the Dyninst SymtabAPI, OmniTrace now does a much better job of avoiding instrumentation of functions which are internally called by OmniTrace:
- The `omnitrace` executable searches for and parses the symbols of various libraries which are known to cause problems when instrumented
- GNU libraries which are common to nearly every library, e.g., `"libc.so.6"`, `"libdl.so.2"`, etc., and thus are outside the scope of the users optimizations efforts
- Libraries which OmniTrace depends on for functionality, e.g. `"libunwind.so"`, `"libgotcha.so"`, `"libroctracer64.so"`, etc.
- OmniTrace skips instrumenting any `module_function` instance when it's member `module_name` or `function_name` variable matches the library name, source file, or function name found for that symbol (unless the user explicitly requests that it be eligible for instrumentation)
- Note: the parsing of the "internal" libraries may result in longer instrumentation time and higher memory usage. Please file an issue if either of these is found to be excessive.
### Function filters based on linkage and visibility
Added options to restrict instrumentation to certain linkage types (e.g. avoid instrumenting weak symbols) and visibility types (e.g. avoid instrumenting hidden symbols).
### Function filters based on instructions
In the past, after instrumentation, some applications instrumented by Dyninst would fail with a trap signal (e.g. #147). In several cases, it was found that this occurred whenever certain instructions were present in the function so an option was added to exclude functions based on one or more regex patterns was added.
## Details
- generates list of "internal" libraries and attempts to find the first match via:
- the library is already open, e.g. `dlopen(<libname>, RTLD_LAZY | RTLD_NOLOAD)`
- searching for the library in `LD_LIBRARY_PATH`
- searching for the library in `OMNITRACE_ROCM_PATH`, `ROCM_PATH`
- searching the folders from `/sbin/ldconfig -p`
- searching for the library in common places such as `/usr/local/lib`
- provides new `--linkage` command line option to restrict instrumentation to functions with particular type(s) of linkage
- Linkage types: `unknown`, `global`, `local`, `weak`, `unique`
- provides new `--visibility` command line option to restrict instrumentation to functions with particular type(s) of visibility
- Visibility types: `unknown`, `default`, `hidden`, `protected`, `internal`
- provides new `--internal-module-include` and `--internal-function-include` command line regex options to bypass automatic exclusion from instrumentation
- provides new `--internal-library-append` command line option to specify a library should be considered internal
- provides new `--internal-library-remove` command line option to specify a library should not be considered internal
- provides new `--instruction-exclude` command line regex option to exclude functions which contain matching instructions
- provides new `--internal-library-deps` command line option to treat libraries linked to internal libraries as internal libraries
- generally, this will only be helpful during runtime instrumentation when OmniTrace is built with an external dyninst library which is dynamically linked to boost libraries and the application is using the same boost libraries
- relaxed restrictions in `module_function::is_module_constrained()`
- relaxed restrictions in `module_function::is_routine_constrained()`
- added a few miscellaneous nullptr checks
## Miscellaneous
- Fix `LD_PRELOAD` + `OMNITRACE_DL_VERBOSE=3` issue
- Adds a sampling offload verbose message
- Improves MPI send-recv.cpp example error message
- Minor tweaks to binary library
- `binary::get_linked_path` returns `std::optional<string>`
- renamed `binary::symbol::read_bfd` to `binary::symbol::read_bfd_line_info`
- `binary::get_binary_info` has param options for reading line info and included undefined symbols
- fixed another edge case instance of resource deadlock during first call to configure_settings
- improved the error log printing in `omnitrace` (does not print repeated messages)
* fix OMNITRACE_DL_VERBOSE=3 + preload issue
- join needs to handle nullptr
* sampling offload verbose message
* mpi-send-recv error message
* binary updates
- get_linked_path returns std::optional<string>
- get_binary_info accepts include_undef flag
- renamed symbol::read_bfd to symbol::read_bfd_line_info
- get_binary_info has param options for reading line info and included undefined symbols
* config updates (initialization)
- fixed another instance of resource deadlock during first call to configure_settings
* Testing fix for HIP w/o rocprofiler support
- disable rocprofiler tests when HIP enabled but OMNITRACE_USE_ROCPROFILER=OFF
* omnitrace exe: insert_instr nullptr check
* omnitrace exe: new method for determining internal constraints
- added internal-libs.cpp
- using binary::get_binary_info on various known libs used by omnitrace
- any matching func/file from symbols found in known internal libs are excluded
- relaxed restrictions in is_module_constrained
- relaxed restrictions in is_routine_constrained
- added a few safety checks
* internal libs append/remove
- options to change which libs are considered internal libraries
* omnitrace exe instruction exclude
- regex option for excluding functions containing specific instructions
* fix is_internal_constrained
* binary link map verbose message
* support constraints on linkage and visibility of symbols
* misc fixes
- fix compiler error for Ubuntu Jammy + GCC 12
- dlopen + libtbbmalloc_proxy appears to be causing issues on OpenSUSE
* Performance details + MT
- multithread processing internal info
- report timing info
* Defer parsing internal data
- wait until after address space is created
* Performance improvement finding for get_symtab_function
* fix data race in get_binary_info
* remove set_default for linkage and visibility argparse
* Parse internal libs with Dyninst::Symtab instead of binary reader
- conflicting versions of libraries for binary analysis causes problems
- expanded whole function restrictions
- expanded module_function::is_routine_constrained regex
* internal lib updates
- include memory usage info
- option to read libraries linked against internal libs: --internal-library-deps
- defer parsing internal libs data to when processing modules
[ROCm/rocprofiler-systems commit: 0da62c980e]
Este commit está contenido en:
cometido por
GitHub
padre
b2bedda138
commit
f597b5fe9d
@@ -27,7 +27,7 @@ main(int argc, char** argv)
|
||||
// We are assuming 2 processes for this task
|
||||
if(world_size != 2)
|
||||
{
|
||||
fprintf(stderr, "World size must be two for %s\n", argv[0]);
|
||||
fprintf(stderr, "World size must be two for %s, not %i\n", argv[0], world_size);
|
||||
MPI_Abort(MPI_COMM_WORLD, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,17 +10,19 @@ add_executable(omnitrace-exe)
|
||||
|
||||
target_sources(
|
||||
omnitrace-exe
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/details.cpp
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/details.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/function_signature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/log.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/module_function.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/fwd.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/function_signature.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/fwd.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/info.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal_libs.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal_libs.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/log.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/log.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/module_function.hpp)
|
||||
${CMAKE_CURRENT_LIST_DIR}/module_function.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/module_function.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp)
|
||||
|
||||
target_link_libraries(
|
||||
omnitrace-exe
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "log.hpp"
|
||||
#include "omnitrace.hpp"
|
||||
|
||||
#include <timemory/components/rusage/components.hpp>
|
||||
#include <timemory/components/timing/wall_clock.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -39,17 +42,24 @@ get_whole_function_names()
|
||||
"sem_init", "sem_destroy", "sem_open", "sem_close", "sem_post", "sem_wait",
|
||||
"sem_getvalue", "sem_clockwait", "sem_timedwait", "sem_trywait", "sem_unlink",
|
||||
"fork", "do_futex_wait", "dl_iterate_phdr", "dlinfo", "dlopen", "dlmopen",
|
||||
"dlvsym", "dlsym", "getenv", "setenv", "unsetenv", "printf", "fprintf", "fflush",
|
||||
"malloc", "malloc_stats", "malloc_trim", "mallopt", "calloc", "free", "pvalloc",
|
||||
"valloc", "mmap", "munmap", "fopen", "fclose", "fmemopen", "fmemclose",
|
||||
"backtrace", "backtrace_symbols", "backtrace_symbols_fd", "sigaddset",
|
||||
"sigandset", "sigdelset", "sigemptyset", "sigfillset", "sighold", "sigisemptyset",
|
||||
"sigismember", "sigorset", "sigrelse", "sigvec", "strtok", "strstr", "sbrk",
|
||||
"strxfrm", "atexit", "ompt_start_tool", "nanosleep", "cfree", "tolower",
|
||||
"toupper", "fileno", "fileno_unlocked", "exit", "quick_exit", "abort", "mbind",
|
||||
"migrate_pages", "move_pages", "numa_migrate_pages", "numa_move_pages",
|
||||
"numa_alloc", "numa_alloc_local", "numa_alloc_interleaved", "numa_alloc_onnode",
|
||||
"numa_realloc", "numa_free",
|
||||
"dlvsym", "dlsym", "dlerror", "dladdr", "_dl_sym", "_dl_vsym", "_dl_addr",
|
||||
"getenv", "setenv", "unsetenv", "printf", "fprintf", "vprintf",
|
||||
"buffered_vfprintf", "vfprintf", "printf_positional", "puts", "fputs", "vfputs",
|
||||
"fflush", "fwrite", "malloc", "malloc_stats", "malloc_trim", "mallopt", "calloc",
|
||||
"free", "pvalloc", "valloc", "sysmalloc", "posix_memalign", "freehook",
|
||||
"mallochook", "memalignhook", "mprobe", "reallochook", "mmap", "munmap", "fopen",
|
||||
"fclose", "fmemopen", "fmemclose", "backtrace", "backtrace_symbols",
|
||||
"backtrace_symbols_fd", "sigaddset", "sigandset", "sigdelset", "sigemptyset",
|
||||
"sigfillset", "sighold", "sigisemptyset", "sigismember", "sigorset", "sigrelse",
|
||||
"sigvec", "strtok", "strstr", "sbrk", "strxfrm", "atexit", "ompt_start_tool",
|
||||
"nanosleep", "cfree", "tolower", "toupper", "fileno", "fileno_unlocked", "exit",
|
||||
"quick_exit", "abort", "mbind", "migrate_pages", "move_pages",
|
||||
"numa_migrate_pages", "numa_move_pages", "numa_alloc", "numa_alloc_local",
|
||||
"numa_alloc_interleaved", "numa_alloc_onnode", "numa_realloc", "numa_free",
|
||||
"round_and_return", "_init", "_fini", "_start", "__do_global_dtors_aux",
|
||||
"__libc_csu_init", "__libc_csu_fini", "__hip_module_ctor", "__hip_module_dtor",
|
||||
"__hipRegisterManagedVar", "__hipRegisterFunction", "__hipPushCallConfiguration",
|
||||
"__hipPopCallConfiguration", "hipApiName", "enlarge_userbuf",
|
||||
// below are functions which never terminate
|
||||
"rocr::core::Signal::WaitAny", "rocr::core::Runtime::AsyncEventsLoop",
|
||||
"rocr::core::BusyWaitSignal::WaitAcquire",
|
||||
@@ -108,6 +118,59 @@ get_name(module_t* _module)
|
||||
return _v.at(_module);
|
||||
}
|
||||
|
||||
symtab_func_t*
|
||||
get_symtab_function(procedure_t* _func)
|
||||
{
|
||||
static auto _v = std::unordered_map<procedure_t*, symtab_func_t*>{};
|
||||
|
||||
auto itr = _v.find(_func);
|
||||
if(itr == _v.end())
|
||||
{
|
||||
auto _name = _func->getName();
|
||||
{
|
||||
auto nitr = symtab_data.mangled_symbol_names.find(_name);
|
||||
if(nitr != symtab_data.mangled_symbol_names.end())
|
||||
{
|
||||
_v.emplace(_func, nitr->second->getFunction());
|
||||
return _v.at(_func);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& fitr : symtab_data.symbols)
|
||||
{
|
||||
if(_name == fitr.first->getName())
|
||||
{
|
||||
_v.emplace(_func, fitr.first);
|
||||
return _v.at(_func);
|
||||
}
|
||||
}
|
||||
|
||||
auto _dname = _func->getDemangledName();
|
||||
|
||||
{
|
||||
auto nitr = symtab_data.typed_func_names.find(_dname);
|
||||
if(nitr != symtab_data.typed_func_names.end())
|
||||
{
|
||||
_v.emplace(_func, nitr->second);
|
||||
return _v.at(_func);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto nitr = symtab_data.typed_symbol_names.find(_dname);
|
||||
if(nitr != symtab_data.typed_symbol_names.end())
|
||||
{
|
||||
_v.emplace(_func, nitr->second->getFunction());
|
||||
return _v.at(_func);
|
||||
}
|
||||
}
|
||||
|
||||
if(_v.find(_func) == _v.end()) _v.emplace(_func, nullptr);
|
||||
}
|
||||
|
||||
return _v.at(_func);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string
|
||||
@@ -390,7 +453,7 @@ find_function(image_t* app_image, const std::string& _name, const strset_t& _ext
|
||||
|
||||
auto _find = [app_image](const std::string& _f) -> procedure_t* {
|
||||
// Extract the vector of functions
|
||||
bpvector_t<procedure_t*> _found;
|
||||
std::vector<procedure_t*> _found;
|
||||
auto* ret = app_image->findFunction(_f.c_str(), _found, false, true, true);
|
||||
if(ret == nullptr || _found.empty()) return nullptr;
|
||||
return _found.at(0);
|
||||
@@ -488,6 +551,83 @@ error_func_fake(error_level_t level, int num, const char* const* params)
|
||||
.force(level < BPatchInfo);
|
||||
}
|
||||
|
||||
#include "internal_libs.hpp"
|
||||
|
||||
#include <timemory/components/timing/wall_clock.hpp>
|
||||
#include <timemory/utility/join.hpp>
|
||||
|
||||
using ::timemory::join::join;
|
||||
|
||||
//======================================================================================//
|
||||
//
|
||||
// Read the symtab data from Dyninst
|
||||
//
|
||||
void
|
||||
process_modules(const std::vector<module_t*>& _app_modules)
|
||||
{
|
||||
parse_internal_libs_data();
|
||||
|
||||
auto _wc = tim::component::wall_clock{};
|
||||
auto _pr = tim::component::peak_rss{};
|
||||
_wc.start();
|
||||
_pr.start();
|
||||
|
||||
for(auto* itr : _app_modules)
|
||||
{
|
||||
auto* _module = SymTab::convert(itr);
|
||||
if(_module) symtab_data.modules.emplace_back(_module);
|
||||
}
|
||||
|
||||
verbprintf(0, "Processing %zu modules...\n", symtab_data.modules.size());
|
||||
|
||||
const auto& _data = get_internal_libs_data();
|
||||
auto _names = std::set<std::string_view>{};
|
||||
for(const auto& itr : _data)
|
||||
{
|
||||
_names.emplace(itr.first);
|
||||
for(const auto& ditr : itr.second)
|
||||
_names.emplace(ditr.first);
|
||||
}
|
||||
|
||||
for(auto* itr : symtab_data.modules)
|
||||
{
|
||||
const auto* _base_name = tim::filepath::basename(itr->fullName());
|
||||
auto _real_name = tim::filepath::realpath(itr->fullName(), nullptr, false);
|
||||
|
||||
if(_names.count(_base_name) == 0 && _names.count(_real_name) == 0)
|
||||
{
|
||||
verbprintf(2, "Processing symbol table for module '%s'...\n",
|
||||
itr->fullName().c_str());
|
||||
}
|
||||
|
||||
symtab_data.functions.emplace(itr, std::vector<symtab_func_t*>{});
|
||||
itr->getAllFunctions(symtab_data.functions.at(itr));
|
||||
for(auto* fitr : symtab_data.functions.at(itr))
|
||||
{
|
||||
symtab_data.typed_func_names[tim::demangle(fitr->getName())] = fitr;
|
||||
|
||||
symtab_data.symbols.emplace(fitr, std::vector<symtab_symbol_t*>{});
|
||||
fitr->getSymbols(symtab_data.symbols.at(fitr));
|
||||
for(auto* sitr : symtab_data.symbols.at(fitr))
|
||||
{
|
||||
symtab_data.mangled_symbol_names[sitr->getMangledName()] = sitr;
|
||||
symtab_data.typed_symbol_names[sitr->getTypedName()] = sitr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pr.stop();
|
||||
_wc.stop();
|
||||
verbprintf(0, "Processing %zu modules... Done (%.3f %s, %.3f %s)\n",
|
||||
_app_modules.size(), _wc.get(), _wc.display_unit().c_str(), _pr.get(),
|
||||
_pr.display_unit().c_str());
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
//
|
||||
// I/O assistance
|
||||
//
|
||||
|
||||
namespace std
|
||||
{
|
||||
std::string
|
||||
@@ -538,4 +678,87 @@ to_string(error_level_t _level)
|
||||
return JOIN("", tim::log::color::warning(), "UnknownErrorLevel",
|
||||
static_cast<int>(_level));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string&&
|
||||
to_lower(std::string&& _v)
|
||||
{
|
||||
for(auto& itr : std::move(_v))
|
||||
itr = tolower(itr);
|
||||
return std::move(_v);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string
|
||||
to_string(symbol_visibility_t _v)
|
||||
{
|
||||
return to_lower(SymTab::Symbol::symbolVisibility2Str(_v) + 3);
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string(symbol_linkage_t _v)
|
||||
{
|
||||
return to_lower(SymTab::Symbol::symbolLinkage2Str(_v) + 3);
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
template <typename Tp>
|
||||
Tp
|
||||
from_string(std::string_view _v)
|
||||
{
|
||||
if constexpr(std::is_same<Tp, symbol_visibility_t>::value)
|
||||
{
|
||||
for(const auto& itr :
|
||||
{ SV_UNKNOWN, SV_DEFAULT, SV_INTERNAL, SV_HIDDEN, SV_PROTECTED })
|
||||
if(_v == std::to_string(itr)) return itr;
|
||||
return SV_UNKNOWN;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, symbol_linkage_t>::value)
|
||||
{
|
||||
for(const auto& itr : { SL_UNKNOWN, SL_GLOBAL, SL_LOCAL, SL_WEAK, SL_UNIQUE })
|
||||
if(_v == std::to_string(itr)) return itr;
|
||||
return SL_UNKNOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::is_empty<Tp>::value, "Error! not defined");
|
||||
return Tp{};
|
||||
}
|
||||
}
|
||||
|
||||
template symbol_visibility_t
|
||||
from_string<symbol_visibility_t>(std::string_view _v);
|
||||
|
||||
template symbol_linkage_t
|
||||
from_string<symbol_linkage_t>(std::string_view _v);
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& _os, symbol_linkage_t _v)
|
||||
{
|
||||
return (_os << std::to_string(_v));
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& _os, symbol_visibility_t _v)
|
||||
{
|
||||
return (_os << std::to_string(_v));
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream& _is, symbol_linkage_t& _v)
|
||||
{
|
||||
auto _v_s = std::string{};
|
||||
_is >> _v_s;
|
||||
_v = from_string<symbol_linkage_t>(_v_s);
|
||||
return _is;
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream& _is, symbol_visibility_t& _v)
|
||||
{
|
||||
auto _v_s = std::string{};
|
||||
_is >> _v_s;
|
||||
_v = from_string<symbol_visibility_t>(_v_s);
|
||||
return _is;
|
||||
}
|
||||
|
||||
@@ -49,8 +49,10 @@
|
||||
#include <BPatch_process.h>
|
||||
#include <BPatch_snippet.h>
|
||||
#include <BPatch_statement.h>
|
||||
#include <Function.h>
|
||||
#include <Instruction.h>
|
||||
#include <InstructionCategories.h>
|
||||
#include <Module.h>
|
||||
#include <Symtab.h>
|
||||
#include <SymtabReader.h>
|
||||
#include <dyntypes.h>
|
||||
@@ -61,6 +63,7 @@
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
@@ -88,9 +91,6 @@ struct function_signature;
|
||||
struct basic_block_signature;
|
||||
struct module_function;
|
||||
|
||||
template <typename Tp>
|
||||
using bpvector_t = BPatch_Vector<Tp>;
|
||||
|
||||
using string_t = std::string;
|
||||
using string_view_t = std::string_view;
|
||||
using stringstream_t = std::stringstream;
|
||||
@@ -127,14 +127,40 @@ using snippet_handle_t = BPatchSnippetHandle;
|
||||
using patch_pointer_t = std::shared_ptr<patch_t>;
|
||||
using snippet_pointer_t = std::shared_ptr<snippet_t>;
|
||||
using call_expr_pointer_t = std::shared_ptr<call_expr_t>;
|
||||
using snippet_vec_t = bpvector_t<snippet_t*>;
|
||||
using procedure_vec_t = bpvector_t<procedure_t*>;
|
||||
using snippet_vec_t = std::vector<snippet_t*>;
|
||||
using procedure_vec_t = std::vector<procedure_t*>;
|
||||
using basic_block_set_t = std::set<basic_block_t*>;
|
||||
using basic_loop_vec_t = bpvector_t<basic_loop_t*>;
|
||||
using basic_loop_vec_t = std::vector<basic_loop_t*>;
|
||||
using snippet_pointer_vec_t = std::vector<snippet_pointer_t>;
|
||||
using instruction_t = Dyninst::InstructionAPI::Instruction;
|
||||
using instruction_category_t = Dyninst::InstructionAPI::InsnCategory;
|
||||
|
||||
namespace SymTab = ::Dyninst::SymtabAPI;
|
||||
using symtab_t = SymTab::Symtab;
|
||||
using symtab_module_t = SymTab::Module;
|
||||
using symtab_symbol_t = SymTab::Symbol;
|
||||
using symtab_func_t = SymTab::Function;
|
||||
using symbol_linkage_t = SymTab::Symbol::SymbolLinkage;
|
||||
using symbol_visibility_t = SymTab::Symbol::SymbolVisibility;
|
||||
|
||||
constexpr auto SL_UNKNOWN = symtab_symbol_t::SL_UNKNOWN;
|
||||
constexpr auto SL_GLOBAL = symtab_symbol_t::SL_GLOBAL;
|
||||
constexpr auto SL_LOCAL = symtab_symbol_t::SL_LOCAL;
|
||||
constexpr auto SL_WEAK = symtab_symbol_t::SL_WEAK;
|
||||
constexpr auto SL_UNIQUE = symtab_symbol_t::SL_UNIQUE;
|
||||
|
||||
constexpr auto SV_UNKNOWN = symtab_symbol_t::SV_UNKNOWN;
|
||||
constexpr auto SV_DEFAULT = symtab_symbol_t::SV_DEFAULT;
|
||||
constexpr auto SV_INTERNAL = symtab_symbol_t::SV_INTERNAL;
|
||||
constexpr auto SV_HIDDEN = symtab_symbol_t::SV_HIDDEN;
|
||||
constexpr auto SV_PROTECTED = symtab_symbol_t::SV_PROTECTED;
|
||||
|
||||
constexpr auto SL_END_V =
|
||||
std::max({ SL_UNKNOWN, SL_GLOBAL, SL_LOCAL, SL_WEAK, SL_UNIQUE }) + 1;
|
||||
|
||||
constexpr auto SV_END_V =
|
||||
std::max({ SV_UNKNOWN, SV_DEFAULT, SV_INTERNAL, SV_HIDDEN, SV_PROTECTED }) + 1;
|
||||
|
||||
void
|
||||
omnitrace_prefork_callback(thread_t* parent, thread_t* child);
|
||||
|
||||
@@ -165,6 +191,7 @@ extern bool loop_level_instr;
|
||||
extern bool instr_dynamic_callsites;
|
||||
extern bool instr_traps;
|
||||
extern bool instr_loop_traps;
|
||||
extern bool parse_all_modules;
|
||||
extern size_t min_address_range;
|
||||
extern size_t min_loop_address_range;
|
||||
extern size_t min_instructions;
|
||||
@@ -182,6 +209,7 @@ extern int num_log_entries;
|
||||
//
|
||||
extern bool simulate;
|
||||
extern bool include_uninstr;
|
||||
extern bool include_internal_linked_libs;
|
||||
//
|
||||
// string settings
|
||||
//
|
||||
@@ -209,7 +237,26 @@ extern regexvec_t file_exclude;
|
||||
extern regexvec_t file_restrict;
|
||||
extern regexvec_t func_restrict;
|
||||
extern regexvec_t caller_include;
|
||||
extern regexvec_t func_internal_include;
|
||||
extern regexvec_t file_internal_include;
|
||||
extern regexvec_t instruction_exclude;
|
||||
extern CodeCoverageMode coverage_mode;
|
||||
//
|
||||
// symtab variables
|
||||
//
|
||||
struct symtab_data_s
|
||||
{
|
||||
std::vector<symtab_module_t*> modules = {};
|
||||
std::map<symtab_module_t*, std::vector<symtab_func_t*>> functions = {};
|
||||
std::map<symtab_func_t*, std::vector<symtab_symbol_t*>> symbols = {};
|
||||
std::unordered_map<std::string, symtab_symbol_t*> mangled_symbol_names = {};
|
||||
std::unordered_map<std::string, symtab_func_t*> typed_func_names = {};
|
||||
std::unordered_map<std::string, symtab_symbol_t*> typed_symbol_names = {};
|
||||
};
|
||||
|
||||
extern symtab_data_s symtab_data;
|
||||
extern std::set<symbol_linkage_t> enabled_linkage;
|
||||
extern std::set<symbol_visibility_t> enabled_visibility;
|
||||
|
||||
// logging
|
||||
extern std::unique_ptr<std::ofstream> log_ofs;
|
||||
@@ -267,6 +314,9 @@ consume_parameters(T&&...)
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
process_modules(const std::vector<module_t*>&);
|
||||
|
||||
strset_t
|
||||
get_whole_function_names();
|
||||
|
||||
@@ -293,7 +343,7 @@ query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc, flow_graph_t* cf
|
||||
|
||||
template <typename Tp>
|
||||
bool
|
||||
insert_instr(address_space_t* mutatee, const bpvector_t<point_t*>& _points, Tp traceFunc,
|
||||
insert_instr(address_space_t* mutatee, const std::vector<point_t*>& _points, Tp traceFunc,
|
||||
procedure_loc_t traceLoc, bool allow_traps = instr_traps);
|
||||
|
||||
template <typename Tp>
|
||||
@@ -317,13 +367,33 @@ void
|
||||
error_func_fake(error_level_t level, int num, const char* const* params);
|
||||
|
||||
std::string_view
|
||||
get_name(procedure_t* _module);
|
||||
get_name(procedure_t*);
|
||||
|
||||
std::string_view
|
||||
get_name(module_t* _module);
|
||||
get_name(module_t*);
|
||||
|
||||
symtab_func_t*
|
||||
get_symtab_function(procedure_t*);
|
||||
|
||||
namespace std
|
||||
{
|
||||
std::string to_string(instruction_category_t);
|
||||
std::string to_string(error_level_t);
|
||||
std::string to_string(symbol_visibility_t);
|
||||
std::string to_string(symbol_linkage_t);
|
||||
} // namespace std
|
||||
|
||||
template <typename Tp>
|
||||
Tp from_string(std::string_view);
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream&, symbol_linkage_t);
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream&, symbol_visibility_t);
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream&, symbol_linkage_t&);
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream&, symbol_visibility_t&);
|
||||
|
||||
@@ -0,0 +1,592 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "internal_libs.hpp"
|
||||
#include "binary/analysis.hpp"
|
||||
#include "binary/binary_info.hpp"
|
||||
#include "binary/link_map.hpp"
|
||||
#include "binary/scope_filter.hpp"
|
||||
#include "binary/symbol.hpp"
|
||||
#include "common/defines.h"
|
||||
#include "core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include <timemory/components/rusage/components.hpp>
|
||||
#include <timemory/components/timing/wall_clock.hpp>
|
||||
#include <timemory/environment/types.hpp>
|
||||
#include <timemory/log/macros.hpp>
|
||||
#include <timemory/utility/demangle.hpp>
|
||||
#include <timemory/utility/filepath.hpp>
|
||||
#include <timemory/utility/join.hpp>
|
||||
#include <timemory/utility/types.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <dlfcn.h>
|
||||
#include <initializer_list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace filepath = ::tim::filepath;
|
||||
using ::tim::delimit;
|
||||
using ::tim::get_env;
|
||||
using ::timemory::join::join;
|
||||
using strview_init_t = std::initializer_list<std::string_view>;
|
||||
using strview_set_t = std::set<std::string_view>;
|
||||
using open_modes_vec_t = std::vector<int>;
|
||||
|
||||
auto
|
||||
get_exe_realpath()
|
||||
{
|
||||
return filepath::realpath("/proc/self/exe", nullptr, false);
|
||||
}
|
||||
|
||||
auto&
|
||||
get_symtab_file_cache()
|
||||
{
|
||||
static auto _cache = std::unordered_map<std::string, std::pair<symtab_t*, bool>>{};
|
||||
return _cache;
|
||||
}
|
||||
|
||||
symtab_t*
|
||||
get_symtab_file(const std::string& _name)
|
||||
{
|
||||
auto& _cache = get_symtab_file_cache();
|
||||
auto itr = _cache.find(_name);
|
||||
if(itr == _cache.end())
|
||||
{
|
||||
symtab_t* _v = SymTab::Symtab::findOpenSymtab(_name);
|
||||
bool _closable = (_v == nullptr);
|
||||
if(!_v) SymTab::Symtab::openFile(_v, _name);
|
||||
|
||||
TIMEMORY_PREFER(_v != nullptr)
|
||||
<< "Warning! Dyninst could not open a Symtab instance for file '" << _name
|
||||
<< "'\n";
|
||||
_cache.emplace(_name, std::make_pair(_v, _closable));
|
||||
}
|
||||
|
||||
return _cache.at(_name).first;
|
||||
}
|
||||
|
||||
bool
|
||||
close_symtab_file(const std::string& _name)
|
||||
{
|
||||
auto& _cache = get_symtab_file_cache();
|
||||
auto itr = _cache.find(_name);
|
||||
if(itr != _cache.end())
|
||||
{
|
||||
symtab_t* _symtab = itr->second.first;
|
||||
bool _closable = itr->second.second;
|
||||
if(_symtab && _closable) SymTab::Symtab::closeSymtab(_symtab);
|
||||
_cache.erase(itr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <template <typename, typename...> class ContainerT, typename... TailT>
|
||||
bool
|
||||
check_regex_restrictions(const ContainerT<std::string, TailT...>& _names,
|
||||
const regexvec_t& _regexes)
|
||||
{
|
||||
for(const auto& nitr : _names)
|
||||
for(const auto& ritr : _regexes)
|
||||
if(std::regex_search(nitr, ritr)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
get_linked_path(const char* _name,
|
||||
open_modes_vec_t&& _open_modes = { (RTLD_LAZY | RTLD_NOLOAD) })
|
||||
{
|
||||
void* _handle = nullptr;
|
||||
bool _noload = false;
|
||||
for(auto _mode : _open_modes)
|
||||
{
|
||||
_handle = dlopen(_name, _mode);
|
||||
_noload = (_mode & RTLD_NOLOAD) == RTLD_NOLOAD;
|
||||
if(_handle) break;
|
||||
}
|
||||
|
||||
tim::scope::destructor _dtor{ [&_noload, &_handle]() {
|
||||
if(_noload == false) dlclose(_handle);
|
||||
} };
|
||||
|
||||
if(_handle)
|
||||
{
|
||||
struct link_map* _link_map = nullptr;
|
||||
dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map);
|
||||
if(_link_map != nullptr && !std::string_view{ _link_map->l_name }.empty())
|
||||
{
|
||||
return filepath::realpath(_link_map->l_name, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
return std::optional<std::string>{};
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
get_link_map(const std::string& _lib,
|
||||
open_modes_vec_t&& _open_modes = { (RTLD_LAZY | RTLD_NOLOAD) })
|
||||
{
|
||||
void* _handle = nullptr;
|
||||
bool _noload = false;
|
||||
for(auto _mode : _open_modes)
|
||||
{
|
||||
_handle = dlopen(_lib.c_str(), _mode);
|
||||
_noload = (_mode & RTLD_NOLOAD) == RTLD_NOLOAD;
|
||||
if(_handle) break;
|
||||
}
|
||||
|
||||
auto _chain = std::set<std::string>{};
|
||||
if(_handle)
|
||||
{
|
||||
struct link_map* _link_map = nullptr;
|
||||
dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map);
|
||||
struct link_map* _next = _link_map;
|
||||
while(_next)
|
||||
{
|
||||
if(!std::string_view{ _next->l_name }.empty() &&
|
||||
std::string_view{ _next->l_name } != _lib)
|
||||
{
|
||||
_chain.emplace(filepath::realpath(_next->l_name, nullptr, false));
|
||||
}
|
||||
_next = _next->l_next;
|
||||
}
|
||||
|
||||
if(_noload == false) dlclose(_handle);
|
||||
}
|
||||
return _chain;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
get_library_search_paths_impl()
|
||||
{
|
||||
auto _paths = std::vector<std::string>{};
|
||||
|
||||
auto _path_exists = [](const std::string& _filename) {
|
||||
struct stat dummy;
|
||||
return (_filename.empty()) ? false : (stat(_filename.c_str(), &dummy) == 0);
|
||||
};
|
||||
|
||||
auto _emplace_if_exists = [&_paths, _path_exists](const std::string& _directory) {
|
||||
if(_path_exists(_directory)) _paths.emplace_back(_directory);
|
||||
};
|
||||
|
||||
// search paths from environment variables
|
||||
for(const auto& itr : delimit(get_env("LD_LIBRARY_PATH", std::string{}, false), ":"))
|
||||
_emplace_if_exists(itr);
|
||||
|
||||
for(const auto& itr : { get_env<std::string>("OMNITRACE_ROCM_PATH", ""),
|
||||
get_env<std::string>("ROCM_PATH", ""),
|
||||
std::string{ OMNITRACE_DEFAULT_ROCM_PATH } })
|
||||
{
|
||||
if(!itr.empty())
|
||||
{
|
||||
for(const auto& ditr : delimit(itr, ":"))
|
||||
{
|
||||
_emplace_if_exists(join('/', ditr, "lib"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search ld.so.cache
|
||||
// apparently ubuntu doesn't like pclosing NULL, so a shared pointer custom
|
||||
// destructor is out. Ugh.
|
||||
FILE* ldconfig = popen("/sbin/ldconfig -p", "r");
|
||||
if(ldconfig)
|
||||
{
|
||||
constexpr size_t buffer_size = 512;
|
||||
char buffer[buffer_size];
|
||||
// ignore first line
|
||||
if(fgets(buffer, buffer_size, ldconfig))
|
||||
{
|
||||
// each line constaining relevant info should be in form:
|
||||
// <LIBRARY_BASENAME> (...) => <RESOLVED_ABSOLUTE_PATH>
|
||||
// example:
|
||||
// libz.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so
|
||||
auto _get_entry = [](const std::string& _inp) {
|
||||
auto _paren_pos = _inp.find('(');
|
||||
auto _arrow_pos = _inp.find("=>", _paren_pos);
|
||||
if(_arrow_pos == std::string::npos || _paren_pos == std::string::npos)
|
||||
return std::string{};
|
||||
if(_arrow_pos + 2 < _inp.length())
|
||||
{
|
||||
auto _pos = _inp.find_first_not_of(" \t", _arrow_pos + 2);
|
||||
if(_pos < _inp.length()) return _inp.substr(_pos);
|
||||
}
|
||||
return std::string{};
|
||||
};
|
||||
|
||||
auto _data = std::stringstream{};
|
||||
while(fgets(buffer, buffer_size, ldconfig) != nullptr)
|
||||
{
|
||||
_data << buffer;
|
||||
auto _len = strnlen(buffer, buffer_size);
|
||||
if(_len > 0 && buffer[_len - 1] == '\n')
|
||||
{
|
||||
auto _v = _data.str();
|
||||
if(!_v.empty())
|
||||
{
|
||||
_v = _v.substr(_v.find_first_not_of(" \t"));
|
||||
if(_v.length() > 1)
|
||||
{
|
||||
auto _entry = _get_entry(_v.substr(0, _v.length() - 1));
|
||||
if(!_entry.empty()) _emplace_if_exists(_entry);
|
||||
}
|
||||
}
|
||||
_data = std::stringstream{};
|
||||
}
|
||||
}
|
||||
}
|
||||
pclose(ldconfig);
|
||||
}
|
||||
|
||||
// search hard-coded system paths
|
||||
for(const char* itr : { "/usr/local/lib", "/usr/share/lib", "/usr/lib", "/usr/lib64",
|
||||
"/usr/lib/x86_64-linux-gnu", "/lib", "/lib64",
|
||||
"/lib/x86_64-linux-gnu", "/usr/lib/i386-linux-gnu" })
|
||||
{
|
||||
_emplace_if_exists(itr);
|
||||
}
|
||||
|
||||
return _paths;
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
get_internal_basic_libs_impl()
|
||||
{
|
||||
auto _libs = std::set<std::string>{};
|
||||
const auto _exclude = strview_set_t{ LIBM_SO, LIBMVEC_SO };
|
||||
|
||||
// GNU libraries likely to be used by instrumentation
|
||||
const auto _gnu_libs = strview_init_t{ LD_LINUX_X86_64_SO, LD_SO,
|
||||
LIBANL_SO, LIBBROKENLOCALE_SO,
|
||||
LIBCRYPT_SO, LIBC_SO,
|
||||
LIBDL_SO, LIBGCC_S_SO,
|
||||
LIBMVEC_SO, LIBM_SO,
|
||||
LIBNSL_SO, LIBNSS_COMPAT_SO,
|
||||
LIBNSS_DB_SO, LIBNSS_DNS_SO,
|
||||
LIBNSS_FILES_SO, LIBNSS_HESIOD_SO,
|
||||
LIBNSS_LDAP_SO, LIBNSS_NISPLUS_SO,
|
||||
LIBNSS_NIS_SO, LIBNSS_TEST1_SO,
|
||||
LIBNSS_TEST2_SO, LIBPTHREAD_SO,
|
||||
LIBRESOLV_SO, LIBRT_SO,
|
||||
LIBTHREAD_DB_SO, LIBUTIL_SO };
|
||||
|
||||
// shared libraries used by or provided by dyninst
|
||||
const auto _dyn_libs = strview_init_t{ "libdyninstAPI_RT.so",
|
||||
"libcommon.so",
|
||||
"libbfd.so",
|
||||
"libelf.so",
|
||||
"libdwarf.so",
|
||||
"libdw.so",
|
||||
"libtbb.so",
|
||||
"libtbbmalloc.so",
|
||||
"libtbbmalloc_proxy.so",
|
||||
"libz.so",
|
||||
"libzstd.so",
|
||||
"libbz2.so",
|
||||
"liblzma.so" };
|
||||
|
||||
// shared libraries used by omnitrace
|
||||
const auto _omni_libs = strview_init_t{
|
||||
"libstdc++.so.6", "libgotcha.so", "libunwind-coredump.so",
|
||||
"libunwind-generic.so", "libunwind-ptrace.so", "libunwind-setjmp.so",
|
||||
"libunwind.so", "libunwind-x86_64.so", "librocm_smi64.so",
|
||||
"libroctx64.so", "librocmtools.so", "libroctracer64.so",
|
||||
"librocprofiler64.so", "libpapi.so", "libpfm.so"
|
||||
};
|
||||
|
||||
// shared libraries potentially used by timemory
|
||||
const auto _3rdparty_libs = strview_init_t{ "libcaliper.so",
|
||||
"liblikwid.so",
|
||||
"libprofiler.so",
|
||||
"libtcmalloc.so",
|
||||
"libtcmalloc_and_profiler.so",
|
||||
"libtcmalloc_debug.so",
|
||||
"libtcmalloc_minimal.so",
|
||||
"libtcmalloc_minimal_debug.so" };
|
||||
|
||||
for(const auto& gitr : { _gnu_libs, _dyn_libs, _omni_libs, _3rdparty_libs })
|
||||
{
|
||||
for(auto itr : gitr)
|
||||
{
|
||||
if(!itr.empty() && _exclude.count(itr) == 0) _libs.emplace(itr);
|
||||
}
|
||||
}
|
||||
|
||||
// auto _link_map = binary::get_link_map(nullptr, "", "", { (RTLD_LAZY | RTLD_NOLOAD)
|
||||
// }); for(const auto& itr : _link_map)
|
||||
// _libs.emplace(itr.real());
|
||||
|
||||
return _libs;
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
get_internal_libs_impl()
|
||||
{
|
||||
auto _libs = get_internal_basic_libs();
|
||||
for(auto itr : get_internal_basic_libs())
|
||||
{
|
||||
if(!itr.empty())
|
||||
{
|
||||
if(parse_all_modules)
|
||||
{
|
||||
auto _lib_v = find_libraries(itr);
|
||||
if(!_lib_v.empty())
|
||||
{
|
||||
for(const auto& litr : _lib_v)
|
||||
{
|
||||
verbprintf(2, "Library '%s' found: %s\n", itr.data(),
|
||||
litr.c_str());
|
||||
_libs.emplace(litr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
verbprintf(2, "Library '%s' not found\n", itr.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto _lib_v = find_library(itr);
|
||||
if(_lib_v)
|
||||
{
|
||||
verbprintf(2, "Library '%s' found: '%s'\n", itr.data(),
|
||||
_lib_v->c_str());
|
||||
_libs.emplace(*_lib_v);
|
||||
if(include_internal_linked_libs)
|
||||
{
|
||||
for(auto&& litr : get_link_map(*_lib_v))
|
||||
{
|
||||
verbprintf(2, "Library '%s' found: '%s' (linked by '%s')\n",
|
||||
itr.data(), litr.c_str(), _lib_v->c_str());
|
||||
_libs.emplace(litr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
verbprintf(2, "Library '%s' not found\n", itr.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _libs;
|
||||
}
|
||||
|
||||
library_module_map_t
|
||||
get_internal_libs_data_impl()
|
||||
{
|
||||
auto _wc = tim::component::wall_clock{};
|
||||
auto _pr = tim::component::peak_rss{};
|
||||
_wc.start();
|
||||
_pr.start();
|
||||
|
||||
auto _libs_v = get_internal_libs();
|
||||
auto _libs = std::vector<std::string>{};
|
||||
_libs.assign(_libs_v.begin(), _libs_v.end());
|
||||
|
||||
auto _omnitrace_base_path = filepath::dirname(
|
||||
filepath::dirname(filepath::realpath("/proc/self/exe", nullptr, false)));
|
||||
auto _omnitrace_lib_path = std::string{};
|
||||
|
||||
for(const auto* itr : { "lib", "lib64" })
|
||||
{
|
||||
for(const auto* litr :
|
||||
{ "libomnitrace-dl.so", "libomnitrace-user.so", "libomnitrace-rt.so" })
|
||||
{
|
||||
auto _libpath = join('/', _omnitrace_base_path, itr, litr);
|
||||
if(filepath::exists(_libpath))
|
||||
{
|
||||
_libs.emplace_back(filepath::realpath(_libpath, nullptr, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
omnitrace::utility::filter_sort_unique(
|
||||
_libs, [](const auto& itr) { return itr.empty() || !filepath::exists(itr); });
|
||||
|
||||
auto _data = library_module_map_t{};
|
||||
for(const auto& itr : _libs)
|
||||
{
|
||||
auto _fpath = filepath::realpath(itr, nullptr, false);
|
||||
// allow the user to request this library be considered for instrumentation
|
||||
if(check_regex_restrictions(strvec_t{ itr, _fpath }, file_internal_include))
|
||||
continue;
|
||||
|
||||
_data.emplace(_fpath, module_func_map_t{});
|
||||
}
|
||||
|
||||
auto _odata = ordered(_data);
|
||||
for(const auto& itr : _odata)
|
||||
{
|
||||
symtab_t* _symtab = get_symtab_file(itr.first);
|
||||
if(!_symtab) continue;
|
||||
|
||||
verbprintf(0, "[internal] parsing library: '%s'...\n", itr.first.c_str());
|
||||
|
||||
auto _wc_v = tim::component::wall_clock{};
|
||||
auto _pr_v = tim::component::peak_rss{};
|
||||
_wc_v.start();
|
||||
_pr_v.start();
|
||||
|
||||
auto _modules = std::vector<symtab_module_t*>{};
|
||||
_symtab->getAllModules(_modules);
|
||||
|
||||
for(const auto& mitr : _modules)
|
||||
{
|
||||
const auto& _mname = mitr->fileName();
|
||||
const auto& _mpath = mitr->fullName();
|
||||
// allow the user to request this library be considered for instrumentation
|
||||
if(check_regex_restrictions(strvec_t{ _mname, _mpath },
|
||||
file_internal_include))
|
||||
continue;
|
||||
|
||||
verbprintf(2, "[internal] parsing module: '%s' (via '%s')...\n",
|
||||
_mname.c_str(), filepath::basename(itr.first));
|
||||
|
||||
_data[itr.first].emplace(_mpath, func_set_t{});
|
||||
_data[itr.first].emplace(_mname, func_set_t{});
|
||||
|
||||
auto _funcs = std::vector<symtab_func_t*>{};
|
||||
mitr->getAllFunctions(_funcs);
|
||||
|
||||
for(const auto& fitr : _funcs)
|
||||
{
|
||||
auto _fname = fitr->getName();
|
||||
auto _dname = tim::demangle(_fname);
|
||||
|
||||
_data[itr.first][_mpath].emplace(_fname);
|
||||
_data[itr.first][_mpath].emplace(_dname);
|
||||
}
|
||||
}
|
||||
|
||||
_pr_v.stop();
|
||||
_wc_v.stop();
|
||||
verbprintf(1, "[internal] parsing library: '%s'... Done (%.3f %s, %.3f %s)\n",
|
||||
itr.first.c_str(), _wc_v.get(), _wc_v.display_unit().c_str(),
|
||||
_pr_v.get(), _pr_v.display_unit().c_str());
|
||||
|
||||
// close_symtab_file(itr.first);
|
||||
}
|
||||
|
||||
_pr.stop();
|
||||
_wc.stop();
|
||||
verbprintf(0, "[internal] binary info processing required %.3f %s and %.3f %s\n",
|
||||
_wc.get(), _wc.display_unit().c_str(), _pr.get(),
|
||||
_pr.display_unit().c_str());
|
||||
|
||||
return _data;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename Tp, typename... TailT>
|
||||
std::set<Tp>
|
||||
ordered(const std::unordered_set<Tp, TailT...>& _unordered)
|
||||
{
|
||||
auto _ordered = std::set<Tp>{};
|
||||
for(const auto& itr : _unordered)
|
||||
_ordered.emplace(itr);
|
||||
return _ordered;
|
||||
}
|
||||
|
||||
template <typename KeyT, typename MappedT, typename... TailT>
|
||||
std::map<KeyT, MappedT>
|
||||
ordered(const std::unordered_map<KeyT, MappedT, TailT...>& _unordered)
|
||||
{
|
||||
auto _ordered = std::map<KeyT, MappedT>{};
|
||||
for(const auto& itr : _unordered)
|
||||
_ordered.emplace(itr.first, itr.second);
|
||||
return _ordered;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
find_library(std::string_view _lib_v)
|
||||
{
|
||||
auto _lib = get_linked_path(_lib_v.data(), { (RTLD_LAZY | RTLD_NOLOAD) });
|
||||
if(_lib) return _lib;
|
||||
|
||||
for(const auto& itr : get_library_search_paths())
|
||||
{
|
||||
auto _path = join('/', itr, _lib_v);
|
||||
if(filepath::exists(_path)) return std::optional<std::string>{ _path };
|
||||
}
|
||||
|
||||
return std::optional<std::string>{};
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
find_libraries(std::string_view _lib_v)
|
||||
{
|
||||
auto _libs = std::vector<std::string>{};
|
||||
|
||||
auto _lib = get_linked_path(_lib_v.data(), { (RTLD_LAZY | RTLD_NOLOAD) });
|
||||
if(_lib) _libs.emplace_back(*_lib);
|
||||
|
||||
for(const auto& itr : get_library_search_paths())
|
||||
{
|
||||
auto _path = join('/', itr, _lib_v);
|
||||
if(filepath::exists(_path)) _libs.emplace_back(_path);
|
||||
}
|
||||
|
||||
return _libs;
|
||||
}
|
||||
|
||||
const std::vector<std::string>&
|
||||
get_library_search_paths()
|
||||
{
|
||||
static auto _v = get_library_search_paths_impl();
|
||||
return _v;
|
||||
}
|
||||
|
||||
std::set<std::string>&
|
||||
get_internal_basic_libs()
|
||||
{
|
||||
static auto _v = get_internal_basic_libs_impl();
|
||||
return _v;
|
||||
}
|
||||
|
||||
std::set<std::string>&
|
||||
get_internal_libs()
|
||||
{
|
||||
static auto _v = get_internal_libs_impl();
|
||||
return _v;
|
||||
}
|
||||
|
||||
const library_module_map_t&
|
||||
get_internal_libs_data()
|
||||
{
|
||||
static auto _v = get_internal_libs_data_impl();
|
||||
return _v;
|
||||
}
|
||||
|
||||
void
|
||||
parse_internal_libs_data()
|
||||
{
|
||||
(void) get_internal_libs_data();
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
#if !defined(LD_LINUX_X86_64_SO)
|
||||
# define LD_LINUX_X86_64_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LD_SO)
|
||||
# define LD_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBANL_SO)
|
||||
# define LIBANL_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBBROKENLOCALE_SO)
|
||||
# define LIBBROKENLOCALE_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBCRYPT_SO)
|
||||
# define LIBCRYPT_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBC_SO)
|
||||
# define LIBC_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBDL_SO)
|
||||
# define LIBDL_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBGCC_S_SO)
|
||||
# define LIBGCC_S_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBMVEC_SO)
|
||||
# define LIBMVEC_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBM_SO)
|
||||
# define LIBM_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSL_SO)
|
||||
# define LIBNSL_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_COMPAT_SO)
|
||||
# define LIBNSS_COMPAT_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_DB_SO)
|
||||
# define LIBNSS_DB_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_DNS_SO)
|
||||
# define LIBNSS_DNS_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_FILES_SO)
|
||||
# define LIBNSS_FILES_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_HESIOD_SO)
|
||||
# define LIBNSS_HESIOD_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_LDAP_SO)
|
||||
# define LIBNSS_LDAP_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_NISPLUS_SO)
|
||||
# define LIBNSS_NISPLUS_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_NIS_SO)
|
||||
# define LIBNSS_NIS_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_TEST1_SO)
|
||||
# define LIBNSS_TEST1_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBNSS_TEST2_SO)
|
||||
# define LIBNSS_TEST2_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBPTHREAD_SO)
|
||||
# define LIBPTHREAD_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBRESOLV_SO)
|
||||
# define LIBRESOLV_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBRT_SO)
|
||||
# define LIBRT_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBTHREAD_DB_SO)
|
||||
# define LIBTHREAD_DB_SO ""
|
||||
#endif
|
||||
|
||||
#if !defined(LIBUTIL_SO)
|
||||
# define LIBUTIL_SO ""
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using func_set_t = std::unordered_set<std::string>;
|
||||
using module_func_map_t = std::unordered_map<std::string, func_set_t>;
|
||||
using library_module_map_t = std::unordered_map<std::string, module_func_map_t>;
|
||||
|
||||
template <typename Tp, typename... TailT>
|
||||
std::set<Tp>
|
||||
ordered(const std::unordered_set<Tp, TailT...>&);
|
||||
|
||||
template <typename KeyT, typename MappedT, typename... TailT>
|
||||
std::map<KeyT, MappedT>
|
||||
ordered(const std::unordered_map<KeyT, MappedT, TailT...>&);
|
||||
|
||||
std::optional<std::string> find_library(std::string_view);
|
||||
|
||||
std::vector<std::string> find_libraries(std::string_view);
|
||||
|
||||
const std::vector<std::string>&
|
||||
get_library_search_paths();
|
||||
|
||||
std::set<std::string>&
|
||||
get_internal_basic_libs();
|
||||
|
||||
std::set<std::string>&
|
||||
get_internal_libs();
|
||||
|
||||
const library_module_map_t&
|
||||
get_internal_libs_data();
|
||||
|
||||
void
|
||||
parse_internal_libs_data();
|
||||
@@ -121,16 +121,40 @@ print_log_entries(std::ostream& _os, int64_t _count,
|
||||
}
|
||||
|
||||
// the requested number of log entries
|
||||
auto _last = std::string{};
|
||||
size_t _last_i = 0;
|
||||
size_t _last_n = 0;
|
||||
for(size_t i = i0; i < log_entries.size(); ++i)
|
||||
{
|
||||
auto& itr = log_entries.at(i);
|
||||
|
||||
if(!_condition || _condition(itr))
|
||||
{
|
||||
_os << "[" << _color << std::setw(_w) << i << "/" << log_entries.size()
|
||||
<< _end << "]"
|
||||
<< ((_color_entries) ? itr.as_string() : itr.as_string("", "", ""))
|
||||
<< "\n";
|
||||
auto _msg = ((_color_entries) ? itr.as_string() : itr.as_string("", "", ""));
|
||||
if(_msg != _last)
|
||||
{
|
||||
if(_last_n > 0 && !_last.empty())
|
||||
{
|
||||
_os << "[" << _color << std::setw(_w) << _last_i << "/"
|
||||
<< log_entries.size() << _end << "] ... repeated " << _last_n
|
||||
<< " times ...\n";
|
||||
}
|
||||
_last_n = 0;
|
||||
_last_i = i;
|
||||
_last = _msg;
|
||||
_os << "[" << _color << std::setw(_w) << i << "/" << log_entries.size()
|
||||
<< _end << "]" << _msg << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
++_last_n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_last_n > 0)
|
||||
{
|
||||
_os << "[" << _color << std::setw(_w) << _last_i << "/" << log_entries.size()
|
||||
<< _end << "] ... repeated " << _last_n << " times ...\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,12 @@
|
||||
#include "module_function.hpp"
|
||||
#include "InstructionCategories.h"
|
||||
#include "fwd.hpp"
|
||||
#include "internal_libs.hpp"
|
||||
#include "log.hpp"
|
||||
#include "omnitrace.hpp"
|
||||
|
||||
#include <timemory/utility/join.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
module_function::width_t&
|
||||
@@ -56,6 +59,7 @@ module_function::update_width(const module_function& rhs)
|
||||
module_function::module_function(module_t* mod, procedure_t* proc)
|
||||
: module{ mod }
|
||||
, function{ proc }
|
||||
, symtab_function{ proc->isInstrumentable() ? get_symtab_function(proc) : nullptr }
|
||||
, flow_graph{ proc->getCFG() }
|
||||
, module_name{ get_name(module) }
|
||||
, function_name{ get_name(function) }
|
||||
@@ -145,6 +149,8 @@ module_function::write_header(std::ostream& os)
|
||||
<< " " << std::setw(14) << "AddressRange"
|
||||
<< " " << std::setw(14) << "#Instructions"
|
||||
<< " " << std::setw(6) << "Ratio"
|
||||
<< " " << std::setw(7) << "Linkage"
|
||||
<< " " << std::setw(10) << "Visibility"
|
||||
<< " " << std::setw(w0 + 8) << std::left << "Module"
|
||||
<< " " << std::setw(w1 + 8) << std::left << "Function"
|
||||
<< " " << std::setw(w2 + 8) << std::left << "FunctionSignature"
|
||||
@@ -164,6 +170,7 @@ module_function::should_coverage_instrument() const
|
||||
// hard constraints
|
||||
if(!is_instrumentable()) return false;
|
||||
if(!can_instrument_entry()) return false;
|
||||
if(is_internal_constrained()) return false;
|
||||
if(is_module_constrained()) return false;
|
||||
if(is_routine_constrained()) return false;
|
||||
|
||||
@@ -190,6 +197,7 @@ module_function::should_coverage_instrument() const
|
||||
|
||||
if(is_address_range_constrained()) return false;
|
||||
if(is_num_instructions_constrained()) return false;
|
||||
if(is_instruction_constrained()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -201,6 +209,7 @@ module_function::should_instrument(bool coverage) const
|
||||
if(!is_instrumentable()) return false;
|
||||
if(!can_instrument_entry()) return false;
|
||||
if(!coverage && !can_instrument_exit()) return false;
|
||||
if(is_internal_constrained()) return false;
|
||||
if(is_module_constrained()) return false;
|
||||
if(is_routine_constrained()) return false;
|
||||
|
||||
@@ -230,8 +239,16 @@ module_function::should_instrument(bool coverage) const
|
||||
if(!file_restrict.empty() || !func_restrict.empty()) return !is_user_restricted();
|
||||
if(is_user_included()) return true;
|
||||
|
||||
// do not apply visibility and linkage constraints to code coverage
|
||||
if(!coverage)
|
||||
{
|
||||
if(is_linkage_constrained()) return false;
|
||||
if(is_visibility_constrained()) return false;
|
||||
}
|
||||
|
||||
if(is_address_range_constrained()) return false;
|
||||
if(is_num_instructions_constrained()) return false;
|
||||
if(is_instruction_constrained()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -375,6 +392,100 @@ module_function::is_overlapping() const
|
||||
return function->findOverlapping(_overlapping);
|
||||
}
|
||||
|
||||
symbol_linkage_t
|
||||
module_function::get_linkage() const
|
||||
{
|
||||
constexpr auto unknown_v = SymTab::Symbol::SL_UNKNOWN;
|
||||
|
||||
if(symtab_function == nullptr) return unknown_v;
|
||||
symbol_linkage_t _v = unknown_v;
|
||||
for(const auto& itr : symtab_data.symbols.at(symtab_function))
|
||||
{
|
||||
auto litr = itr->getLinkage();
|
||||
if(litr > unknown_v) _v = (_v == unknown_v) ? litr : std::min(_v, litr);
|
||||
}
|
||||
return _v;
|
||||
}
|
||||
|
||||
symbol_visibility_t
|
||||
module_function::get_visibility() const
|
||||
{
|
||||
constexpr auto unknown_v = SymTab::Symbol::SV_UNKNOWN;
|
||||
|
||||
if(symtab_function == nullptr) return unknown_v;
|
||||
symbol_visibility_t _v = unknown_v;
|
||||
for(const auto& itr : symtab_data.symbols.at(symtab_function))
|
||||
{
|
||||
auto litr = itr->getVisibility();
|
||||
if(litr > unknown_v) _v = (_v == unknown_v) ? litr : std::min(_v, litr);
|
||||
}
|
||||
return _v;
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_internal_constrained() const
|
||||
{
|
||||
using ::timemory::join::join;
|
||||
auto _basename = [](std::string_view _v) {
|
||||
return std::string{ tim::filepath::basename(_v) };
|
||||
};
|
||||
auto _realpath = [](const std::string& _v) {
|
||||
return tim::filepath::realpath(_v, nullptr, false);
|
||||
};
|
||||
|
||||
auto _report = [&](const string_t& _action, const std::string& _type,
|
||||
const string_t& _reason, int _lvl) {
|
||||
messages.emplace_back(_lvl, _action, _type, _reason, module_name);
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto& _gnu_libs = get_internal_libs_data();
|
||||
|
||||
auto _module_base = _basename(module_name);
|
||||
auto _module_real = _realpath(module_name);
|
||||
|
||||
if(std::regex_search(module_name, std::regex{ "lib(omnitrace|timemory|perfetto)" }))
|
||||
return _report("Excluding", "module", "omnitrace", 3);
|
||||
else if(std::regex_match(module_name,
|
||||
std::regex{ ".*/source/lib/"
|
||||
"(core|common|binary|omnitrace|omnitrace-dl|"
|
||||
"omnitrace-user)/.*/.*\\.(h|c|cpp|hpp)$" }))
|
||||
return _report("Excluding", "module", "omnitrace", 3);
|
||||
|
||||
if(std::regex_search(function_name, std::regex{ "9omnitrace|omnitrace(::|_)" }))
|
||||
return _report("Excluding", "function", "omnitrace", 3);
|
||||
else if(std::regex_search(function_name, std::regex{ "3tim|tim::|timemory(::|_)" }))
|
||||
return _report("Excluding", "function", "timemory", 3);
|
||||
else if(std::regex_search(function_name, std::regex{ "9perfetto|perfetto(::|_)" }))
|
||||
return _report("Excluding", "function", "perfetto", 3);
|
||||
|
||||
if(_gnu_libs.find(module_name) != _gnu_libs.end() ||
|
||||
_gnu_libs.find(_module_real) != _gnu_libs.end() ||
|
||||
_gnu_libs.find(_module_base) != _gnu_libs.end())
|
||||
return _report("Excluding", "module", "internal library", 3);
|
||||
|
||||
for(const auto& litr : _gnu_libs)
|
||||
{
|
||||
if(_module_base == _basename(litr.first) ||
|
||||
litr.second.find(_module_base) != litr.second.end() ||
|
||||
_module_real == litr.first ||
|
||||
litr.second.find(_module_real) != litr.second.end() ||
|
||||
litr.second.find(module_name) != litr.second.end())
|
||||
return _report("Excluding", "module",
|
||||
join(" ", "internal library", litr.first), 3);
|
||||
|
||||
for(const auto& fitr : litr.second)
|
||||
{
|
||||
using ::timemory::join::join;
|
||||
if(fitr.second.find(function_name) != fitr.second.end())
|
||||
return _report("Excluding", "function",
|
||||
join(" ", "internal library", litr.first), 3);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_module_constrained() const
|
||||
{
|
||||
@@ -401,12 +512,8 @@ module_function::is_module_constrained() const
|
||||
static std::regex core_cmod_regex{
|
||||
"^(malloc|(f|)lock|sig|sem)[a-z_]+(|64|_r|_l)\\.c$"
|
||||
};
|
||||
static std::regex core_lib_regex{
|
||||
"^(lib|)(c|dl|dw|pthread|tcmalloc|profiler|"
|
||||
"tbbmalloc|tbbmalloc_proxy|malloc|stdc\\+\\+)(-|\\.)",
|
||||
regex_opts
|
||||
};
|
||||
static std::regex prefix_regex{ "^(_|\\.[a-zA-Z0-9])", regex_opts };
|
||||
static std::regex core_lib_regex{ "lib(elf)(-|\\.)", regex_opts };
|
||||
// static std::regex prefix_regex{ "^(_|\\.[a-zA-Z0-9])", regex_opts };
|
||||
|
||||
// file extensions that should not be instrumented
|
||||
if(std::regex_search(module_name, ext_regex))
|
||||
@@ -432,8 +539,8 @@ module_function::is_module_constrained() const
|
||||
|
||||
// known set of modules whose starting sequence of characters suggest it should not be
|
||||
// instrumented (wastes time)
|
||||
if(std::regex_search(module_name, prefix_regex))
|
||||
return _report("Excluding", "prefix match", 3);
|
||||
// if(std::regex_search(module_name, prefix_regex))
|
||||
// return _report("Excluding", "prefix match", 3);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -461,18 +568,21 @@ module_function::is_routine_constrained() const
|
||||
|
||||
static std::regex exclude(
|
||||
"(omnitrace|tim::|MPI_Init|MPI_Finalize|dyninst|DYNINST|tm_clones)", regex_opts);
|
||||
static std::regex exclude_printf("(|v|f)printf$", regex_opts);
|
||||
// static std::regex exclude_printf("(|v|f)printf$", regex_opts);
|
||||
static std::regex exclude_cxx(
|
||||
"(std::_Sp_counted_base|std::(use|has)_facet|std::locale|::sentry|^std::_|::_(M|"
|
||||
"S)_|::basic_string[a-zA-Z,<>: ]+::_M_create|::__|::_(Alloc|State)|"
|
||||
"std::(basic_|)(ifstream|ios|istream|ostream|stream))",
|
||||
regex_opts);
|
||||
static std::regex leading(
|
||||
"^(_|\\.|frame_dummy|transaction clone|virtual thunk|non-virtual thunk|"
|
||||
"\\(|targ|kmp_threadprivate_|Kokkos::Profiling::|dlopen|dlsym)",
|
||||
"^(\\.|frame_dummy|transaction clone|virtual thunk|non-virtual thunk|"
|
||||
"\\(|targ|kmp_threadprivate_|Kokkos::Profiling::|_IO_|___|"
|
||||
"__(GI|cxa|libc|IO|rpc|run|call|pthread|dl|nl|nss|new|old|internal|argp|malloc|"
|
||||
"libio|printf)_)",
|
||||
regex_opts);
|
||||
static std::regex trailing(
|
||||
"(_|\\.part\\.[0-9]+|\\.constprop\\.[0-9]+|\\.|\\.[0-9]+)$", regex_opts);
|
||||
static std::regex trailing("(_internal)$", regex_opts);
|
||||
// static std::regex trailing(
|
||||
// "(_|\\.part\\.[0-9]+|\\.constprop\\.[0-9]+|\\.|\\.[0-9]+)$", regex_opts);
|
||||
static strset_t whole = []() {
|
||||
auto _v = get_whole_function_names();
|
||||
auto _ret = _v;
|
||||
@@ -489,10 +599,10 @@ module_function::is_routine_constrained() const
|
||||
return _report("Excluding", "critical", 3);
|
||||
}
|
||||
|
||||
if(std::regex_search(function_name, exclude_printf))
|
||||
{
|
||||
return _report("Excluding", "critical-printf", 3);
|
||||
}
|
||||
// if(std::regex_search(function_name, exclude_printf))
|
||||
//{
|
||||
// return _report("Excluding", "critical-printf", 3);
|
||||
//}
|
||||
|
||||
if(whole.count(function_name) > 0)
|
||||
{
|
||||
@@ -539,7 +649,7 @@ module_function::contains_user_callsite() const
|
||||
{
|
||||
if(caller_include.empty()) return false;
|
||||
|
||||
bpvector_t<BPatch_point*> call_points;
|
||||
std::vector<BPatch_point*> call_points;
|
||||
function->getCallPoints(call_points);
|
||||
for(const auto& call_point : call_points)
|
||||
{
|
||||
@@ -582,6 +692,33 @@ module_function::is_address_range_constrained() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_instruction_constrained() const
|
||||
{
|
||||
if(!instruction_exclude.empty())
|
||||
{
|
||||
for(auto&& itr : instructions)
|
||||
{
|
||||
auto _instrss = std::stringstream{};
|
||||
for(auto&& iitr : itr)
|
||||
_instrss << " " << iitr.first.format();
|
||||
|
||||
auto _instr = _instrss.str();
|
||||
if(!_instr.empty())
|
||||
{
|
||||
_instr = _instr.substr(1);
|
||||
if(check_regex_restrictions(_instr, instruction_exclude))
|
||||
{
|
||||
messages.emplace_back(2, "Skipping", "function",
|
||||
"instruction-exclude-regex", function_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_loop_address_range_constrained() const
|
||||
{
|
||||
@@ -627,6 +764,22 @@ module_function::is_loop_num_instructions_constrained() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_visibility_constrained() const
|
||||
{
|
||||
auto _visibility = get_visibility();
|
||||
return (_visibility != SV_UNKNOWN &&
|
||||
enabled_visibility.find(_visibility) == enabled_visibility.end());
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::is_linkage_constrained() const
|
||||
{
|
||||
auto _linkage = get_linkage();
|
||||
return (_linkage != SL_UNKNOWN &&
|
||||
enabled_linkage.find(_linkage) == enabled_linkage.end());
|
||||
}
|
||||
|
||||
bool
|
||||
module_function::can_instrument_entry() const
|
||||
{
|
||||
@@ -709,6 +862,8 @@ module_function::operator()(address_space_t* _addr_space, procedure_t* _entr_tra
|
||||
{
|
||||
std::pair<size_t, size_t> _count = { 0, 0 };
|
||||
|
||||
if(!function || !module) return _count;
|
||||
|
||||
auto _name = signature.get();
|
||||
auto _trace_entr = omnitrace_call_expr(_name.c_str());
|
||||
auto _trace_exit = omnitrace_call_expr(_name.c_str());
|
||||
@@ -726,6 +881,7 @@ module_function::operator()(address_space_t* _addr_space, procedure_t* _entr_tra
|
||||
for(size_t i = 0; i < loop_blocks.size(); ++i)
|
||||
{
|
||||
if(!loop_level_instr) continue;
|
||||
if(!flow_graph) continue;
|
||||
|
||||
auto* itr = loop_blocks.at(i);
|
||||
auto _is_constrained = [this](bool _v, const std::string& _label,
|
||||
|
||||
@@ -66,11 +66,12 @@ struct module_function
|
||||
bool should_coverage_instrument() const;
|
||||
|
||||
// hard constraints
|
||||
bool is_instrumentable() const; // checks whether can instrument
|
||||
bool can_instrument_entry() const; // checks for entry points
|
||||
bool can_instrument_exit() const; // checks for exit points
|
||||
bool is_module_constrained() const; // checks module constraints
|
||||
bool is_routine_constrained() const; // checks function constraints
|
||||
bool is_instrumentable() const; // checks whether can instrument
|
||||
bool can_instrument_entry() const; // checks for entry points
|
||||
bool can_instrument_exit() const; // checks for exit points
|
||||
bool is_internal_constrained() const; // checks internal usage constraint
|
||||
bool is_module_constrained() const; // checks module constraints
|
||||
bool is_routine_constrained() const; // checks function constraints
|
||||
|
||||
// user bypass of heuristics
|
||||
bool is_user_restricted() const; // checks user restrict regexes
|
||||
@@ -85,15 +86,22 @@ struct module_function
|
||||
// applied before address range and # instruction constraints
|
||||
bool is_dynamic_callsite_forced() const; // checks dynamic callsites
|
||||
|
||||
// user exclusion based on instructions
|
||||
bool is_instruction_constrained() const;
|
||||
|
||||
// estimate the size/work of the function
|
||||
bool is_address_range_constrained() const; // checks address range constraint
|
||||
bool is_num_instructions_constrained() const; // check # instructions constraint
|
||||
|
||||
bool is_visibility_constrained() const;
|
||||
bool is_linkage_constrained() const;
|
||||
|
||||
size_t start_address = 0;
|
||||
uint64_t address_range = 0;
|
||||
uint64_t num_instructions = 0;
|
||||
module_t* module = nullptr;
|
||||
procedure_t* function = nullptr;
|
||||
symtab_func_t* symtab_function = nullptr;
|
||||
flow_graph_t* flow_graph = nullptr;
|
||||
string_t module_name = {};
|
||||
string_t function_name = {};
|
||||
@@ -108,6 +116,8 @@ struct module_function
|
||||
bool is_overlapping() const; // checks if func overlaps
|
||||
|
||||
private:
|
||||
symbol_linkage_t get_linkage() const;
|
||||
symbol_visibility_t get_visibility() const;
|
||||
bool is_loop_num_instructions_constrained() const; // checks loop instr constraint
|
||||
bool is_loop_address_range_constrained() const; // checks loop addr range constraint
|
||||
bool contains_dynamic_callsites() const;
|
||||
@@ -120,18 +130,18 @@ public:
|
||||
|
||||
friend bool operator<(const module_function& lhs, const module_function& rhs)
|
||||
{
|
||||
return std::tie(lhs.module_name, lhs.start_address, lhs.function_name,
|
||||
lhs.address_range, lhs.num_instructions, lhs.signature) <
|
||||
std::tie(rhs.module_name, rhs.start_address, rhs.function_name,
|
||||
rhs.address_range, rhs.num_instructions, rhs.signature);
|
||||
return std::tie(lhs.module_name, lhs.function_name, lhs.start_address,
|
||||
lhs.address_range, lhs.num_instructions) <
|
||||
std::tie(rhs.module_name, rhs.function_name, rhs.start_address,
|
||||
rhs.address_range, rhs.num_instructions);
|
||||
}
|
||||
|
||||
friend bool operator==(const module_function& lhs, const module_function& rhs)
|
||||
{
|
||||
return std::tie(lhs.module_name, lhs.start_address, lhs.function_name,
|
||||
lhs.address_range, lhs.num_instructions, lhs.signature) ==
|
||||
std::tie(rhs.module_name, rhs.start_address, rhs.function_name,
|
||||
rhs.address_range, rhs.num_instructions, rhs.signature);
|
||||
return std::tie(lhs.start_address, lhs.address_range, lhs.num_instructions,
|
||||
lhs.module_name, lhs.function_name) ==
|
||||
std::tie(rhs.start_address, rhs.address_range, rhs.num_instructions,
|
||||
rhs.module_name, rhs.function_name);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const module_function& rhs)
|
||||
@@ -155,6 +165,8 @@ public:
|
||||
<< std::setw(14) << rhs.address_range << " "
|
||||
<< std::setw(14) << rhs.num_instructions << " "
|
||||
<< std::setw(6) << std::setprecision(2) << std::fixed << (rhs.address_range / static_cast<double>(rhs.num_instructions)) << " "
|
||||
<< std::setw(7) << std::to_string(rhs.get_linkage()) << " "
|
||||
<< std::setw(10) << std::to_string(rhs.get_visibility()) << " "
|
||||
<< std::setw(w0 + 8) << std::left << _get_str(rhs.module_name) << " "
|
||||
<< std::setw(w1 + 8) << std::left << _get_str(rhs.function_name) << " "
|
||||
<< std::setw(w2 + 8) << std::left << _get_str(rhs.signature.get());
|
||||
@@ -185,7 +197,9 @@ module_function::serialize(ArchiveT& ar, const unsigned)
|
||||
|
||||
if constexpr(tim::concepts::is_output_archive<ArchiveT>::value)
|
||||
{
|
||||
ar(cereal::make_nvp("num_basic_blocks", basic_blocks.size()),
|
||||
ar(cereal::make_nvp("linkage", std::to_string(get_linkage())),
|
||||
cereal::make_nvp("visibility", std::to_string(get_visibility())),
|
||||
cereal::make_nvp("num_basic_blocks", basic_blocks.size()),
|
||||
cereal::make_nvp("num_outer_loops", loop_blocks.size()));
|
||||
ar.setNextName("heuristics");
|
||||
ar.startNode();
|
||||
@@ -195,6 +209,7 @@ module_function::serialize(ArchiveT& ar, const unsigned)
|
||||
cereal::make_nvp("can_instrument_entry", can_instrument_entry()),
|
||||
cereal::make_nvp("can_instrument_exit", can_instrument_exit()),
|
||||
cereal::make_nvp("contains_dynamic_callsites", contains_dynamic_callsites()),
|
||||
cereal::make_nvp("is_internal_constrained", is_internal_constrained()),
|
||||
cereal::make_nvp("is_module_constrained", is_module_constrained()),
|
||||
cereal::make_nvp("is_routine_constrained", is_routine_constrained()),
|
||||
cereal::make_nvp("is_user_restricted", is_user_restricted()),
|
||||
@@ -205,10 +220,13 @@ module_function::serialize(ArchiveT& ar, const unsigned)
|
||||
cereal::make_nvp("is_entry_trap_constrained", is_entry_trap_constrained()),
|
||||
cereal::make_nvp("is_exit_trap_constrained", is_exit_trap_constrained()),
|
||||
cereal::make_nvp("is_dynamic_callsite_forced", is_dynamic_callsite_forced()),
|
||||
cereal::make_nvp("is_linkage_constrained", is_linkage_constrained()),
|
||||
cereal::make_nvp("is_visibility_constrained", is_visibility_constrained()),
|
||||
cereal::make_nvp("is_address_range_constrained",
|
||||
is_address_range_constrained()),
|
||||
cereal::make_nvp("is_num_instructions_constrained",
|
||||
is_num_instructions_constrained()),
|
||||
cereal::make_nvp("is_instruction_constrained", is_instruction_constrained()),
|
||||
cereal::make_nvp("is_loop_address_range_constrained",
|
||||
is_loop_address_range_constrained()),
|
||||
cereal::make_nvp("is_loop_num_instructions_constrained",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "omnitrace.hpp"
|
||||
#include "common/defines.h"
|
||||
#include "fwd.hpp"
|
||||
#include "internal_libs.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include <timemory/backends/process.hpp>
|
||||
@@ -81,31 +82,33 @@ get_default_min_address_range()
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool use_return_info = false;
|
||||
bool use_args_info = false;
|
||||
bool use_file_info = false;
|
||||
bool use_line_info = false;
|
||||
bool allow_overlapping = false;
|
||||
bool loop_level_instr = false;
|
||||
bool instr_dynamic_callsites = false;
|
||||
bool instr_traps = false;
|
||||
bool instr_loop_traps = false;
|
||||
size_t min_address_range = get_default_min_address_range(); // 4096
|
||||
size_t min_loop_address_range = get_default_min_address_range(); // 4096
|
||||
size_t min_instructions = get_default_min_instructions(); // 1024
|
||||
size_t min_loop_instructions = get_default_min_instructions(); // 1024
|
||||
bool werror = false;
|
||||
bool debug_print = false;
|
||||
bool instr_print = false;
|
||||
bool simulate = false;
|
||||
bool include_uninstr = false;
|
||||
int verbose_level = tim::get_env<int>("OMNITRACE_VERBOSE_INSTRUMENT", 0);
|
||||
int num_log_entries = tim::get_env<int>("OMNITRACE_LOG_COUNT", 20);
|
||||
string_t main_fname = "main";
|
||||
string_t argv0 = {};
|
||||
string_t cmdv0 = {};
|
||||
string_t default_components = "wall_clock";
|
||||
string_t prefer_library = {};
|
||||
bool use_return_info = false;
|
||||
bool use_args_info = false;
|
||||
bool use_file_info = false;
|
||||
bool use_line_info = false;
|
||||
bool allow_overlapping = false;
|
||||
bool loop_level_instr = false;
|
||||
bool instr_dynamic_callsites = false;
|
||||
bool instr_traps = false;
|
||||
bool instr_loop_traps = false;
|
||||
bool parse_all_modules = false;
|
||||
size_t min_address_range = get_default_min_address_range(); // 4096
|
||||
size_t min_loop_address_range = get_default_min_address_range(); // 4096
|
||||
size_t min_instructions = get_default_min_instructions(); // 1024
|
||||
size_t min_loop_instructions = get_default_min_instructions(); // 1024
|
||||
bool werror = false;
|
||||
bool debug_print = false;
|
||||
bool instr_print = false;
|
||||
bool simulate = false;
|
||||
bool include_uninstr = false;
|
||||
bool include_internal_linked_libs = false;
|
||||
int verbose_level = tim::get_env<int>("OMNITRACE_VERBOSE_INSTRUMENT", 0);
|
||||
int num_log_entries = tim::get_env<int>("OMNITRACE_LOG_COUNT", 20);
|
||||
string_t main_fname = "main";
|
||||
string_t argv0 = {};
|
||||
string_t cmdv0 = {};
|
||||
string_t default_components = "wall_clock";
|
||||
string_t prefer_library = {};
|
||||
//
|
||||
// global variables
|
||||
//
|
||||
@@ -126,8 +129,16 @@ regexvec_t file_exclude = {};
|
||||
regexvec_t file_restrict = {};
|
||||
regexvec_t func_restrict = {};
|
||||
regexvec_t caller_include = {};
|
||||
regexvec_t func_internal_include = {};
|
||||
regexvec_t file_internal_include = {};
|
||||
regexvec_t instruction_exclude = {};
|
||||
CodeCoverageMode coverage_mode = CODECOV_NONE;
|
||||
|
||||
symtab_data_s symtab_data = {};
|
||||
std::set<symbol_linkage_t> enabled_linkage = { SL_GLOBAL, SL_LOCAL, SL_UNIQUE };
|
||||
std::set<symbol_visibility_t> enabled_visibility = { SV_DEFAULT, SV_HIDDEN, SV_INTERNAL,
|
||||
SV_PROTECTED };
|
||||
|
||||
std::unique_ptr<std::ofstream> log_ofs = {};
|
||||
|
||||
namespace
|
||||
@@ -143,7 +154,6 @@ bool is_attached = false;
|
||||
bool use_mpi = false;
|
||||
bool is_static_exe = false;
|
||||
bool force_config = false;
|
||||
bool parse_all_modules = false;
|
||||
size_t batch_size = 50;
|
||||
strset_t extra_libs = {};
|
||||
std::vector<std::pair<uint64_t, string_t>> hash_ids = {};
|
||||
@@ -211,9 +221,6 @@ activate_signal_handlers(const std::vector<sys_signal>& _signals)
|
||||
stderr, "omnitrace exited with signal %i :: %s\n", nsig,
|
||||
signal_settings::str(static_cast<sys_signal>(nsig)).c_str());
|
||||
|
||||
// print the last log entries
|
||||
print_log_entries(std::cerr, num_log_entries);
|
||||
|
||||
// print any forced entries
|
||||
print_log_entries(
|
||||
std::cerr, -1, [](const auto& _v) { return _v.forced(); },
|
||||
@@ -222,6 +229,9 @@ activate_signal_handlers(const std::vector<sys_signal>& _signals)
|
||||
<< "\n[omnitrace][exe] Potentially important log entries:\n\n";
|
||||
});
|
||||
|
||||
// print the last log entries
|
||||
print_log_entries(std::cerr, num_log_entries);
|
||||
|
||||
TIMEMORY_PRINTF_FATAL(stderr, "\n");
|
||||
TIMEMORY_PRINTF_FATAL(
|
||||
stderr,
|
||||
@@ -406,7 +416,7 @@ main(int argc, char** argv)
|
||||
"{available,instrumented,excluded,overlapping} module "
|
||||
"function lists, e.g. available.txt")
|
||||
.max_count(1)
|
||||
.dtype("bool")
|
||||
.dtype("boolean")
|
||||
.action([](parser_t& p) { simulate = p.get<bool>("simulate"); });
|
||||
parser
|
||||
.add_argument({ "--print-format" },
|
||||
@@ -620,7 +630,7 @@ main(int argc, char** argv)
|
||||
{ "--all-functions" },
|
||||
"When finding functions, include the functions which are not instrumentable. "
|
||||
"This is purely diagnostic for the available/excluded functions output")
|
||||
.dtype("bool")
|
||||
.dtype("boolean")
|
||||
.max_count(1)
|
||||
.action([](parser_t& p) { include_uninstr = p.get<bool>("all-functions"); });
|
||||
|
||||
@@ -646,6 +656,102 @@ main(int argc, char** argv)
|
||||
parser.add_argument({ "-MR", "--module-restrict" },
|
||||
"Regex(es) for restricting modules/files/libraries only to those "
|
||||
"that match the provided regular-expressions");
|
||||
parser.add_argument({ "--internal-function-include" },
|
||||
"Regex(es) for including functions which are (likely) utilized "
|
||||
"by omnitrace itself. Use this option with care.");
|
||||
parser.add_argument(
|
||||
{ "--internal-module-include" },
|
||||
"Regex(es) for including modules/libraries which are (likely) utilized "
|
||||
"by omnitrace itself. Use this option with care.");
|
||||
parser.add_argument(
|
||||
{ "--instruction-exclude" },
|
||||
"Regex(es) for excluding functions containing certain instructions");
|
||||
|
||||
parser
|
||||
.add_argument({ "--internal-library-deps" },
|
||||
"Treat the libraries linked to the internal libraries as internal "
|
||||
"libraries. This increase the internal library processing time and "
|
||||
"consume more memory (so use with care) but may be useful when the "
|
||||
"application uses Boost libraries and Dyninst is dynamically "
|
||||
"linked against the same boost libraries")
|
||||
.min_count(0)
|
||||
.max_count(1)
|
||||
.dtype("boolean")
|
||||
.action([](parser_t& p) {
|
||||
include_internal_linked_libs = p.get<bool>("internal-library-deps");
|
||||
});
|
||||
|
||||
auto _internal_libs = get_internal_basic_libs();
|
||||
|
||||
parser
|
||||
.add_argument({ "--internal-library-append" },
|
||||
"Append to the list of libraries which omnitrace treats as being "
|
||||
"used internally, e.g. OmniTrace will find all the symbols in "
|
||||
"this library and prevent them from being instrumented.")
|
||||
.action([](parser_t& p) {
|
||||
for(const auto& itr : p.get<strvec_t>("internal-library-append"))
|
||||
get_internal_basic_libs().emplace(itr);
|
||||
});
|
||||
|
||||
parser
|
||||
.add_argument({ "--internal-library-remove" },
|
||||
"Remove the specified libraries from being treated as being "
|
||||
"used internally, e.g. OmniTrace will permit all the symbols in "
|
||||
"these libraries to be eligible for instrumentation.")
|
||||
.choices(_internal_libs)
|
||||
.action([](parser_t& p) {
|
||||
auto _remove = p.get<strset_t>("internal-library-remove");
|
||||
auto& _internal = get_internal_basic_libs();
|
||||
for(const auto& itr : _remove)
|
||||
_internal.erase(itr);
|
||||
});
|
||||
|
||||
using timemory::join::array_config;
|
||||
using timemory::join::join;
|
||||
|
||||
auto available_linkage = std::vector<symbol_linkage_t>{};
|
||||
auto available_visibility = std::vector<symbol_visibility_t>{};
|
||||
|
||||
for(int i = SL_UNKNOWN; i < SL_END_V; ++i)
|
||||
available_linkage.emplace_back(static_cast<symbol_linkage_t>(i));
|
||||
for(int i = SV_UNKNOWN; i < SV_END_V; ++i)
|
||||
available_visibility.emplace_back(static_cast<symbol_visibility_t>(i));
|
||||
|
||||
auto _get_strvec = [](const auto& _inp) {
|
||||
auto _ret = std::vector<std::string>{};
|
||||
_ret.reserve(_inp.size());
|
||||
for(const auto& itr : _inp)
|
||||
_ret.emplace_back(std::to_string(itr));
|
||||
return _ret;
|
||||
};
|
||||
|
||||
parser
|
||||
.add_argument({ "--linkage" },
|
||||
join("",
|
||||
"Only instrument functions with specified linkage (default: ",
|
||||
join(array_config{ ", ", "", "" }, enabled_linkage), ")"))
|
||||
.min_count(1)
|
||||
.choices(available_linkage)
|
||||
.set_default(_get_strvec(enabled_linkage))
|
||||
.action([](parser_t& p) {
|
||||
enabled_linkage.clear();
|
||||
for(const auto& itr : p.get<std::set<std::string>>("linkage"))
|
||||
enabled_linkage.emplace(from_string<symbol_linkage_t>(itr));
|
||||
});
|
||||
|
||||
parser
|
||||
.add_argument(
|
||||
{ "--visibility" },
|
||||
join("", "Only instrument functions with specified visibility (default: ",
|
||||
join(array_config{ ", ", "", "" }, enabled_visibility), ")"))
|
||||
.min_count(1)
|
||||
.choices(available_visibility)
|
||||
.set_default(_get_strvec(enabled_visibility))
|
||||
.action([](parser_t& p) {
|
||||
enabled_visibility.clear();
|
||||
for(const auto& itr : p.get<std::set<std::string>>("visibility"))
|
||||
enabled_visibility.emplace(from_string<symbol_visibility_t>(itr));
|
||||
});
|
||||
|
||||
parser.add_argument({ "" }, "");
|
||||
parser.add_argument({ "[RUNTIME OPTIONS]" }, "");
|
||||
@@ -805,7 +911,7 @@ main(int argc, char** argv)
|
||||
"ensure the instrumentation fits. In this case, Dyninst replaces the "
|
||||
"instruction with a single-byte instruction that generates a trap.")
|
||||
.max_count(1)
|
||||
.dtype("bool")
|
||||
.dtype("boolean")
|
||||
.set_default(instr_traps)
|
||||
.action([](parser_t& p) { instr_traps = p.get<bool>("traps"); });
|
||||
parser
|
||||
@@ -813,7 +919,7 @@ main(int argc, char** argv)
|
||||
"Instrument points within a loop which require using a trap (only "
|
||||
"relevant when --instrument-loops is enabled).")
|
||||
.max_count(1)
|
||||
.dtype("bool")
|
||||
.dtype("boolean")
|
||||
.set_default(instr_loop_traps)
|
||||
.action([](parser_t& p) { instr_loop_traps = p.get<bool>("loop-traps"); });
|
||||
parser
|
||||
@@ -1111,6 +1217,8 @@ main(int argc, char** argv)
|
||||
add_regex(func_restrict, tim::get_env<string_t>("OMNITRACE_REGEX_RESTRICT", ""));
|
||||
add_regex(caller_include,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_CALLER_INCLUDE"));
|
||||
add_regex(func_internal_include,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_INTERNAL_INCLUDE", ""));
|
||||
|
||||
add_regex(file_include,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_MODULE_INCLUDE", ""));
|
||||
@@ -1118,6 +1226,11 @@ main(int argc, char** argv)
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_MODULE_EXCLUDE", ""));
|
||||
add_regex(file_restrict,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_MODULE_RESTRICT", ""));
|
||||
add_regex(file_internal_include,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_MODULE_INTERNAL_INCLUDE", ""));
|
||||
|
||||
add_regex(instruction_exclude,
|
||||
tim::get_env<string_t>("OMNITRACE_REGEX_INSTRUCTION_EXCLUDE", ""));
|
||||
|
||||
// Helper function for parsing the regex options
|
||||
auto _parse_regex_option = [&parser, &add_regex](const string_t& _option,
|
||||
@@ -1134,9 +1247,12 @@ main(int argc, char** argv)
|
||||
_parse_regex_option("function-exclude", func_exclude);
|
||||
_parse_regex_option("function-restrict", func_restrict);
|
||||
_parse_regex_option("caller-include", caller_include);
|
||||
_parse_regex_option("internal-function-include", func_internal_include);
|
||||
_parse_regex_option("module-include", file_include);
|
||||
_parse_regex_option("module-exclude", file_exclude);
|
||||
_parse_regex_option("module-restrict", file_restrict);
|
||||
_parse_regex_option("internal-module-include", file_internal_include);
|
||||
_parse_regex_option("instruction-exclude", instruction_exclude);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------//
|
||||
@@ -1253,11 +1369,13 @@ main(int argc, char** argv)
|
||||
|
||||
// get image
|
||||
verbprintf(1, "Getting the address space image, modules, and procedures...\n");
|
||||
image_t* app_image = addr_space->getImage();
|
||||
bpvector_t<module_t*>* app_modules = app_image->getModules();
|
||||
bpvector_t<procedure_t*>* app_functions = app_image->getProcedures(include_uninstr);
|
||||
std::set<module_t*> modules = {};
|
||||
std::set<procedure_t*> functions = {};
|
||||
image_t* app_image = addr_space->getImage();
|
||||
std::vector<module_t*>* app_modules = app_image->getModules();
|
||||
std::vector<procedure_t*>* app_functions = app_image->getProcedures(include_uninstr);
|
||||
std::set<module_t*> modules = {};
|
||||
std::set<procedure_t*> functions = {};
|
||||
|
||||
if(app_modules) process_modules(*app_modules);
|
||||
|
||||
//----------------------------------------------------------------------------------//
|
||||
//
|
||||
@@ -1659,8 +1777,8 @@ main(int argc, char** argv)
|
||||
//
|
||||
//----------------------------------------------------------------------------------//
|
||||
|
||||
bpvector_t<point_t*>* main_entr_points = nullptr;
|
||||
bpvector_t<point_t*>* main_exit_points = nullptr;
|
||||
std::vector<point_t*>* main_entr_points = nullptr;
|
||||
std::vector<point_t*>* main_exit_points = nullptr;
|
||||
|
||||
if(main_func)
|
||||
{
|
||||
@@ -2324,7 +2442,7 @@ query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc, flow_graph_t* cf
|
||||
module_t* module = funcToInstr->getModule();
|
||||
if(!module) return false;
|
||||
|
||||
bpvector_t<point_t*>* _points = nullptr;
|
||||
std::vector<point_t*>* _points = nullptr;
|
||||
|
||||
if(cfGraph && loopToInstrument)
|
||||
{
|
||||
@@ -2362,7 +2480,7 @@ query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc, flow_graph_t* cf
|
||||
|
||||
if(!cfGraph) cfGraph = funcToInstr->getCFG();
|
||||
|
||||
bpvector_t<point_t*>* _points = nullptr;
|
||||
std::vector<point_t*>* _points = nullptr;
|
||||
|
||||
if((cfGraph && loopToInstrument) ||
|
||||
(traceLoc == BPatch_locLoopEntry || traceLoc == BPatch_locLoopExit))
|
||||
|
||||
@@ -327,7 +327,7 @@ omnitrace_fork_callback(thread_t* parent, thread_t* child)
|
||||
//
|
||||
template <typename Tp>
|
||||
bool
|
||||
insert_instr(address_space_t* mutatee, const bpvector_t<point_t*>& _points, Tp traceFunc,
|
||||
insert_instr(address_space_t* mutatee, const std::vector<point_t*>& _points, Tp traceFunc,
|
||||
procedure_loc_t, bool allow_traps)
|
||||
{
|
||||
if(!traceFunc || _points.empty()) return false;
|
||||
@@ -378,11 +378,12 @@ insert_instr(address_space_t* mutatee, procedure_t* funcToInstr, Tp traceFunc,
|
||||
procedure_loc_t traceLoc, flow_graph_t* cfGraph,
|
||||
basic_loop_t* loopToInstrument, bool allow_traps)
|
||||
{
|
||||
if(!funcToInstr) return false;
|
||||
module_t* module = funcToInstr->getModule();
|
||||
if(!module || !traceFunc) return false;
|
||||
|
||||
bpvector_t<point_t*>* _points = nullptr;
|
||||
auto _trace = traceFunc.get();
|
||||
std::vector<point_t*>* _points = nullptr;
|
||||
auto _trace = traceFunc.get();
|
||||
|
||||
OMNITRACE_ADD_LOG_ENTRY("Searching for loop instrumentation points in function",
|
||||
get_name(funcToInstr));
|
||||
|
||||
@@ -64,14 +64,15 @@ namespace binary
|
||||
namespace
|
||||
{
|
||||
binary_info
|
||||
parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
parse_line_info(const std::string& _name, bool _process_dwarf, bool _process_bfd,
|
||||
bool _include_all)
|
||||
{
|
||||
auto _info = binary_info{};
|
||||
|
||||
auto& _bfd = _info.bfd;
|
||||
_bfd = std::make_shared<bfd_file>(_name);
|
||||
|
||||
OMNITRACE_VERBOSE(0, "[binary] Reading line info for '%s'...\n", _name.c_str());
|
||||
OMNITRACE_BASIC_VERBOSE(0, "[binary] Reading line info for '%s'...\n", _name.c_str());
|
||||
|
||||
if(_bfd && _bfd->is_good())
|
||||
{
|
||||
@@ -80,7 +81,7 @@ parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
auto _processed = std::set<uintptr_t>{};
|
||||
for(auto&& itr : _bfd->get_symbols())
|
||||
{
|
||||
if(itr.symsize == 0) continue;
|
||||
if(!_include_all && itr.symsize == 0) continue;
|
||||
auto& _sym = _info.symbols.emplace_back(symbol{ itr });
|
||||
// if(itr.symsize == 0) continue;
|
||||
auto* _section = static_cast<asection*>(itr.section);
|
||||
@@ -88,7 +89,7 @@ parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
_processed.emplace(itr.address);
|
||||
_info.ranges.emplace_back(
|
||||
address_range{ itr.address, itr.address + itr.symsize });
|
||||
_sym.read_bfd(*_bfd);
|
||||
if(_process_bfd) _sym.read_bfd_line_info(*_bfd);
|
||||
}
|
||||
|
||||
for(auto* itr : _section_set)
|
||||
@@ -101,7 +102,7 @@ parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
_section_map[_section_range] = _section;
|
||||
}
|
||||
|
||||
TIMEMORY_REQUIRE(_section_set.size() == _section_map.size())
|
||||
TIMEMORY_REQUIRE(_include_all || _section_set.size() == _section_map.size())
|
||||
<< "section set size (" << _section_set.size() << ") != section map size ("
|
||||
<< _section_map.size() << ")\n";
|
||||
|
||||
@@ -120,8 +121,8 @@ parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
_info.sort();
|
||||
}
|
||||
|
||||
OMNITRACE_VERBOSE(1, "[binary] Reading line info for '%s'... %zu entries\n",
|
||||
_bfd->name.c_str(), _info.symbols.size());
|
||||
OMNITRACE_BASIC_VERBOSE(1, "[binary] Reading line info for '%s'... %zu entries\n",
|
||||
_bfd->name.c_str(), _info.symbols.size());
|
||||
|
||||
return _info;
|
||||
}
|
||||
@@ -129,7 +130,8 @@ parse_line_info(const std::string& _name, bool _process_dwarf)
|
||||
|
||||
std::vector<binary_info>
|
||||
get_binary_info(const std::vector<std::string>& _files,
|
||||
const std::vector<scope_filter>& _filters, bool _process_dwarf)
|
||||
const std::vector<scope_filter>& _filters, bool _process_dwarf,
|
||||
bool _process_bfd, bool _include_all)
|
||||
{
|
||||
auto _satisfies_filter = [&_filters](auto _scope, const std::string& _value) {
|
||||
for(const auto& itr : _filters) // NOLINT
|
||||
@@ -164,14 +166,15 @@ get_binary_info(const std::vector<std::string>& _files,
|
||||
if(filepath::exists(_filename) && _satisfies_binary_filter(_filename) &&
|
||||
_exists.find(_filename) == _exists.end())
|
||||
{
|
||||
_data.emplace_back(parse_line_info(_filename, _process_dwarf));
|
||||
_data.emplace_back(parse_line_info(_filename, _process_dwarf,
|
||||
_process_bfd, _include_all));
|
||||
_exists.emplace(_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get the memory maps
|
||||
auto _maps = procfs::get_contiguous_maps(process::get_id(), _filter, true);
|
||||
auto _maps = procfs::get_contiguous_maps(process::get_id(), _filter, false);
|
||||
|
||||
for(auto& itr : _data)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,7 @@ using hash_value_t = ::tim::hash_value_t;
|
||||
|
||||
std::vector<binary_info>
|
||||
get_binary_info(const std::vector<std::string>&, const std::vector<scope_filter>&,
|
||||
bool _process_dwarf = true);
|
||||
bool _process_dwarf = true, bool _process_bfd = true,
|
||||
bool _include_all = false);
|
||||
} // namespace binary
|
||||
} // namespace omnitrace
|
||||
|
||||
@@ -45,14 +45,13 @@ const open_modes_vec_t default_link_open_modes = { (RTLD_LAZY | RTLD_NOLOAD),
|
||||
(RTLD_LAZY | RTLD_LOCAL) };
|
||||
}
|
||||
|
||||
std::string
|
||||
std::optional<std::string>
|
||||
get_linked_path(const char* _name, open_modes_vec_t&& _open_modes)
|
||||
{
|
||||
if(_name == nullptr) return config::get_exe_realpath();
|
||||
|
||||
if(_open_modes.empty()) _open_modes = default_link_open_modes;
|
||||
|
||||
auto _lib = std::string{ _name };
|
||||
void* _handle = nullptr;
|
||||
bool _noload = false;
|
||||
for(auto _mode : _open_modes)
|
||||
@@ -68,11 +67,12 @@ get_linked_path(const char* _name, open_modes_vec_t&& _open_modes)
|
||||
dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map);
|
||||
if(_link_map != nullptr && !std::string_view{ _link_map->l_name }.empty())
|
||||
{
|
||||
_lib = filepath::realpath(_link_map->l_name, nullptr, false);
|
||||
return filepath::realpath(_link_map->l_name, nullptr, false);
|
||||
}
|
||||
if(_noload == false) dlclose(_handle);
|
||||
}
|
||||
return _lib;
|
||||
|
||||
return std::optional<std::string>{};
|
||||
}
|
||||
|
||||
std::set<link_file>
|
||||
@@ -139,14 +139,14 @@ get_link_map(const char* _lib, const std::string& _exclude_linked_by,
|
||||
auto _name = (!_lib) ? config::get_exe_realpath() : std::string{ _lib };
|
||||
for(const auto& itr : _fini_chain)
|
||||
{
|
||||
OMNITRACE_VERBOSE(2, "[linkmap][%s]: %s\n", filepath::basename(_name),
|
||||
itr.real().c_str());
|
||||
OMNITRACE_BASIC_VERBOSE(2, "[linkmap][%s]: %s\n", filepath::basename(_name),
|
||||
itr.real().c_str());
|
||||
}
|
||||
|
||||
for(const auto& itr : _excl_chain)
|
||||
{
|
||||
OMNITRACE_VERBOSE(3, "[linkmap][%s]: %s\n", _exclude_linked_by.c_str(),
|
||||
link_file{ itr }.real().c_str());
|
||||
OMNITRACE_BASIC_VERBOSE(3, "[linkmap][%s]: %s\n", _exclude_linked_by.c_str(),
|
||||
link_file{ itr }.real().c_str());
|
||||
}
|
||||
|
||||
return _fini_chain;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <dlfcn.h>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -49,7 +50,7 @@ struct link_file
|
||||
};
|
||||
|
||||
// helper function for translating generic lib name to resolved path
|
||||
std::string
|
||||
std::optional<std::string>
|
||||
get_linked_path(const char*, open_modes_vec_t&& = {});
|
||||
|
||||
// default parameters: get the linked binaries for the exe but exclude the linked binaries
|
||||
|
||||
@@ -83,6 +83,7 @@ read_inliner_info(bfd* _inp)
|
||||
symbol::symbol(const base_type& _v)
|
||||
: base_type{ _v }
|
||||
, address{ _v.address, _v.address + _v.symsize }
|
||||
, func{ std::string{ base_type::name } }
|
||||
{}
|
||||
|
||||
bool
|
||||
@@ -188,7 +189,7 @@ symbol::read_dwarf_breakpoints(const std::vector<uintptr_t>& _bkpts)
|
||||
}
|
||||
|
||||
bool
|
||||
symbol::read_bfd(bfd_file& _bfd)
|
||||
symbol::read_bfd_line_info(bfd_file& _bfd)
|
||||
{
|
||||
auto* _section = static_cast<asection*>(section);
|
||||
bfd_vma _vma = bfd_section_vma(_section);
|
||||
|
||||
@@ -66,7 +66,7 @@ struct symbol : private tim::unwind::bfd_file::symbol
|
||||
symbol& operator+=(const symbol&);
|
||||
explicit operator bool() const;
|
||||
|
||||
bool read_bfd(bfd_file&);
|
||||
bool read_bfd_line_info(bfd_file&);
|
||||
size_t read_dwarf_entries(const std::deque<dwarf_entry>&);
|
||||
size_t read_dwarf_breakpoints(const std::vector<uintptr_t>&);
|
||||
address_range ipaddr() const { return address + load_address; }
|
||||
|
||||
@@ -69,7 +69,15 @@ template <typename ArgT>
|
||||
auto
|
||||
as_string(ArgT&& _v, std::enable_if_t<is_string<ArgT>::value, int> = 0)
|
||||
{
|
||||
return std::string{ "\"" } + _v + std::string{ "\"" };
|
||||
if constexpr(std::is_pointer<std::decay_t<ArgT>>::value)
|
||||
{
|
||||
return (_v == nullptr) ? std::string{ "\"\"" }
|
||||
: (std::string{ "\"" } + _v + std::string{ "\"" });
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string{ "\"" } + _v + std::string{ "\"" };
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArgT>
|
||||
|
||||
@@ -1030,7 +1030,6 @@ configure_settings(bool _init)
|
||||
using argparser_t = tim::argparse::argument_parser;
|
||||
argparser_t _parser{ _exe };
|
||||
tim::timemory_init(_cmd, _parser, "omnitrace-");
|
||||
_settings_are_configured() = true;
|
||||
}
|
||||
|
||||
#if !defined(OMNITRACE_USE_MPI) && !defined(OMNITRACE_USE_MPI_HEADERS)
|
||||
@@ -1076,15 +1075,17 @@ configure_settings(bool _init)
|
||||
trait::runtime_enabled<comp::papi_vector>::set(false);
|
||||
}
|
||||
|
||||
configure_mode_settings();
|
||||
configure_signal_handler();
|
||||
configure_disabled_settings();
|
||||
configure_mode_settings(_config);
|
||||
configure_signal_handler(_config);
|
||||
configure_disabled_settings(_config);
|
||||
|
||||
OMNITRACE_VERBOSE(2, "configuration complete\n");
|
||||
OMNITRACE_BASIC_VERBOSE(2, "configuration complete\n");
|
||||
|
||||
_settings_are_configured() = true;
|
||||
}
|
||||
|
||||
void
|
||||
configure_mode_settings()
|
||||
configure_mode_settings(const std::shared_ptr<settings>& _config)
|
||||
{
|
||||
auto _set = [](const std::string& _name, bool _v) {
|
||||
if(!set_setting_value(_name, _v))
|
||||
@@ -1150,7 +1151,7 @@ configure_mode_settings()
|
||||
_set("OMNITRACE_USE_ROCM_SMI", false);
|
||||
}
|
||||
|
||||
if(get_use_kokkosp())
|
||||
if(_config->get<bool>("OMNITRACE_USE_KOKKOSP"))
|
||||
{
|
||||
auto _current_kokkosp_lib = tim::get_env<std::string>("KOKKOS_PROFILE_LIBRARY");
|
||||
if(_current_kokkosp_lib.find("libomnitrace-dl.so") == std::string::npos &&
|
||||
@@ -1171,10 +1172,10 @@ configure_mode_settings()
|
||||
}
|
||||
|
||||
// recycle all subsequent thread ids
|
||||
threading::recycle_ids() =
|
||||
tim::get_env<bool>("OMNITRACE_RECYCLE_TIDS", !get_use_sampling());
|
||||
threading::recycle_ids() = tim::get_env<bool>(
|
||||
"OMNITRACE_RECYCLE_TIDS", !_config->get<bool>("OMNITRACE_USE_SAMPLING"));
|
||||
|
||||
if(!get_config()->get_enabled())
|
||||
if(!_config->get_enabled())
|
||||
{
|
||||
_set("OMNITRACE_USE_PERFETTO", false);
|
||||
_set("OMNITRACE_USE_TIMEMORY", false);
|
||||
@@ -1257,9 +1258,8 @@ set_signal_handler(signal_handler_t _func)
|
||||
}
|
||||
|
||||
void
|
||||
configure_signal_handler()
|
||||
configure_signal_handler(const std::shared_ptr<settings>& _config)
|
||||
{
|
||||
auto _config = settings::shared_instance();
|
||||
auto _ignore_dyninst_trampoline =
|
||||
tim::get_env("OMNITRACE_IGNORE_DYNINST_TRAMPOLINE", false);
|
||||
// this is how dyninst looks up the env variable
|
||||
@@ -1321,9 +1321,8 @@ std::set<int> get_sampling_signals(int64_t)
|
||||
}
|
||||
|
||||
void
|
||||
configure_disabled_settings()
|
||||
configure_disabled_settings(const std::shared_ptr<settings>& _config)
|
||||
{
|
||||
auto _config = settings::shared_instance();
|
||||
auto _handle_use_option = [_config](const std::string& _opt,
|
||||
const std::string& _category) {
|
||||
if(!_config->get<bool>(_opt))
|
||||
|
||||
@@ -55,10 +55,13 @@ void
|
||||
configure_settings(bool _init = true);
|
||||
|
||||
void
|
||||
configure_mode_settings();
|
||||
configure_mode_settings(const std::shared_ptr<settings>&);
|
||||
|
||||
void
|
||||
configure_signal_handler();
|
||||
configure_signal_handler(const std::shared_ptr<settings>&);
|
||||
|
||||
void
|
||||
configure_disabled_settings(const std::shared_ptr<settings>&);
|
||||
|
||||
int
|
||||
get_realtime_signal();
|
||||
@@ -69,9 +72,6 @@ get_cputime_signal();
|
||||
std::set<int>
|
||||
get_sampling_signals(int64_t _tid = 0);
|
||||
|
||||
void
|
||||
configure_disabled_settings();
|
||||
|
||||
void
|
||||
finalize();
|
||||
|
||||
|
||||
@@ -400,7 +400,8 @@ offload_buffer(int64_t _seq, sampler_buffer_t&& _buf)
|
||||
<< "Error! sampling allocator tried to offload buffer of samples but the "
|
||||
"offload file does not exist\n";
|
||||
|
||||
OMNITRACE_VERBOSE_F(3, "Saving sampling buffer for thread %li...\n", _seq);
|
||||
OMNITRACE_VERBOSE_F(2, "Offloading %zu samples for thread %li to %s...\n",
|
||||
_buf.count(), _seq, _file->filename.c_str());
|
||||
auto& _fs = _file->stream;
|
||||
|
||||
OMNITRACE_REQUIRE(_fs.good())
|
||||
|
||||
@@ -121,35 +121,37 @@ set(OMNITRACE_ROCM_EVENTS_TEST
|
||||
"GRBM_COUNT,GPUBusy,SQ_WAVES,SQ_INSTS_VALU,VALUInsts,TCC_HIT_sum,TA_TA_BUSY[0]:device=0,TA_TA_BUSY[11]:device=0"
|
||||
)
|
||||
|
||||
omnitrace_add_test(
|
||||
SKIP_BASELINE SKIP_SAMPLING SKIP_RUNTIME
|
||||
NAME transpose-rocprofiler
|
||||
TARGET transpose
|
||||
LABELS "rocprofiler"
|
||||
MPI ${TRANSPOSE_USE_MPI}
|
||||
GPU ON
|
||||
NUM_PROCS ${NUM_PROCS}
|
||||
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
|
||||
ENVIRONMENT
|
||||
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
|
||||
REWRITE_RUN_PASS_REGEX
|
||||
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
|
||||
)
|
||||
if(OMNITRACE_USE_ROCPROFILER)
|
||||
omnitrace_add_test(
|
||||
SKIP_BASELINE SKIP_SAMPLING SKIP_RUNTIME
|
||||
NAME transpose-rocprofiler
|
||||
TARGET transpose
|
||||
LABELS "rocprofiler"
|
||||
MPI ${TRANSPOSE_USE_MPI}
|
||||
GPU ON
|
||||
NUM_PROCS ${NUM_PROCS}
|
||||
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
|
||||
ENVIRONMENT
|
||||
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
|
||||
REWRITE_RUN_PASS_REGEX
|
||||
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
|
||||
)
|
||||
|
||||
omnitrace_add_test(
|
||||
SKIP_BASELINE SKIP_SAMPLING SKIP_RUNTIME
|
||||
NAME transpose-rocprofiler-no-roctracer
|
||||
TARGET transpose
|
||||
LABELS "rocprofiler"
|
||||
MPI ${TRANSPOSE_USE_MPI}
|
||||
GPU ON
|
||||
NUM_PROCS ${NUM_PROCS}
|
||||
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
|
||||
ENVIRONMENT
|
||||
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_ROCTRACER=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
|
||||
REWRITE_RUN_PASS_REGEX
|
||||
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
|
||||
REWRITE_RUN_FAIL_REGEX "roctracer.txt")
|
||||
omnitrace_add_test(
|
||||
SKIP_BASELINE SKIP_SAMPLING SKIP_RUNTIME
|
||||
NAME transpose-rocprofiler-no-roctracer
|
||||
TARGET transpose
|
||||
LABELS "rocprofiler"
|
||||
MPI ${TRANSPOSE_USE_MPI}
|
||||
GPU ON
|
||||
NUM_PROCS ${NUM_PROCS}
|
||||
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
|
||||
ENVIRONMENT
|
||||
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_ROCTRACER=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
|
||||
REWRITE_RUN_PASS_REGEX
|
||||
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
|
||||
REWRITE_RUN_FAIL_REGEX "roctracer.txt")
|
||||
endif()
|
||||
|
||||
omnitrace_add_test(
|
||||
NAME parallel-overhead
|
||||
|
||||
Referencia en una nueva incidencia
Block a user