User API + reorganized lib folders (#30)

* User API + reorganized lib folders

- omnitrace_user_start_trace
- omnitrace_user_stop_trace
- omnitrace_user_start_thread_trace
- omnitrace_user_stop_thread_trace
- omnitrace_user_push_region
- omnitrace_user_pop_region

* New OpenMP examples/tests

* Fix to KokkosP

* OMPT support

- fixed omnitrace instrumenting reporting
- common invoke improvements
- component::user_region

* exclude kmp_threadprivate_

* Separate omnitrace into multiple files

* PTL and timemory submodule updates

* Active guards + USE_OMPT guards in omnitrace-dl

* Tweak transpose default iterations

* omnitrace-precommit build target

* Omnitrace exe restructuring pt 2

- Never instrument functions with less than 4 instructions
- Never instrument ompt_start_tool or nanosleep
- module_function serializes heuristics
- removed hash stuff from omnitrace
- removed instr_procedures lambda
- WAITPID_DEBUG_MESSAGE

* set_state, "_hidden" fix, CI exceptions, backtrace fix

- set_state function
- fixed "_hidden" from appearing in print macros using __FUNCTION__
- OMNITRACE_CI_THROW
- more CI checks in library
- fixed backtrace init value sample issue being ignored

* Tweaks to OMPT tests

* cmake-formatting

* Removed debug output from backtrace processing

* Fix warnings and verbosity

* omnitrace-dl fix for libomp

* omnitrace-avail fixes

- remove second omnitrace_init_library call
- fix -r option not working

* Additional testing

- source/bin/tests
- tests for omnitrace-exe
- tests for omnitrace-avail

* cmake-format

* Reduce runtime of openmp-lu

* Update openmp-lu and tests timeout

* openmp-lu and CI tweaks

- decrease iterations
- OMP_NUM_THREADS=2
- install clang and libomp-dev in linux-ci
- fix data-files in linux-ci
This commit is contained in:
Jonathan R. Madsen authored and GitHub committed 2022-03-07 20:40:48 -06:00
1 والد 2acaa7aa9f
کامیت d80752bc69
106 files changed
+9180 -1947

No files matched your search

+10
مشاهده پرونده
@@ -12,3 +12,13 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
add_subdirectory(lib)
add_subdirectory(bin)
if(OMNITRACE_BUILD_DEVELOPER)
add_custom_target(omnitrace-precommit)
foreach(_TARGET format-omnitrace-source format-omnitrace-cmake format-timemory-source
format-timemory-cmake)
if(TARGET ${_TARGET})
add_dependencies(omnitrace-precommit ${_TARGET})
endif()
endforeach()
endif()
@@ -1,3 +1,7 @@
add_subdirectory(omnitrace-avail)
add_subdirectory(omnitrace-critical-trace)
add_subdirectory(omnitrace)
if(OMNITRACE_BUILD_TESTING)
add_subdirectory(tests)
endif()
@@ -30,6 +30,7 @@
#include "library/components/omnitrace.hpp"
#include "library/components/pthread_gotcha.hpp"
#include "library/components/roctracer.hpp"
#include "library/components/user_region.hpp"
#include "library/config.hpp"
#include <timemory/components.hpp>
@@ -613,8 +614,6 @@ main(int argc, char** argv)
if(!os) os = &std::cout;
omnitrace_init_library();
if(include_components) write_component_info(*os, options, use_mark, fields);
dump_log();
@@ -766,7 +765,9 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
_mark.at(i));
}
_selected += (is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
if(!category_regex_keys.empty())
_selected +=
(is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
if(_selected == 0) continue;
}
@@ -834,7 +835,8 @@ write_component_info(std::ostream& os, const array_t<bool, N>& options,
_mark.at(i));
}
_selected += (is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
if(!category_regex_keys.empty())
_selected += (is_category_selected(std::get<2>(itr).at(CATEGORY))) ? 1 : 0;
if(_selected > 0)
{
@@ -4,10 +4,19 @@
#
# ------------------------------------------------------------------------------#
add_executable(
add_executable(omnitrace-exe ${_EXCLUDE})
target_sources(
omnitrace-exe
${_EXCLUDE} ${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp
${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp ${CMAKE_CURRENT_LIST_DIR}/details.cpp)
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp
${CMAKE_CURRENT_LIST_DIR}/details.cpp
${CMAKE_CURRENT_LIST_DIR}/function_signature.cpp
${CMAKE_CURRENT_LIST_DIR}/module_function.cpp
${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp
${CMAKE_CURRENT_LIST_DIR}/info.hpp
${CMAKE_CURRENT_LIST_DIR}/fwd.hpp
${CMAKE_CURRENT_LIST_DIR}/function_signature.hpp
${CMAKE_CURRENT_LIST_DIR}/module_function.hpp)
target_link_libraries(
omnitrace-exe
@@ -40,7 +40,7 @@ get_whole_function_names()
"backtrace", "backtrace_symbols", "backtrace_symbols_fd", "sigaddset",
"sigandset", "sigdelset", "sigemptyset", "sigfillset", "sighold", "sigisemptyset",
"sigismember", "sigorset", "sigrelse", "sigvec", "strtok", "strstr", "sbrk",
"strxfrm",
"strxfrm", "atexit", "ompt_start_tool", "nanosleep",
// below are functions which never terminate
"rocr::core::Signal::WaitAny", "rocr::core::Runtime::AsyncEventsLoop",
"rocr::core::BusyWaitSignal::WaitAcquire",
@@ -525,10 +525,32 @@ are_file_include_exclude_lists_empty()
// the instrumented loop and formats it properly.
//
function_signature
get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t* cfGraph,
get_loop_file_line_info(module_t* module, procedure_t* func, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument)
{
if(!cfGraph || !loopToInstrument || !f) return function_signature{ "", "", "" };
if(!cfGraph || !loopToInstrument || !func) return function_signature{ "", "", "" };
std::vector<BPatch_basicBlock*> basic_blocks{};
loopToInstrument->getLoopBasicBlocksExclusive(basic_blocks);
if(basic_blocks.empty()) return function_signature{ "", "", "" };
auto base_addr = basic_blocks.front()->getStartAddress();
auto last_addr = basic_blocks.front()->getEndAddress();
basic_block_t* block = basic_blocks.front();
for(const auto& itr : basic_blocks)
{
if(itr == block) continue;
if(itr->dominates(block))
{
base_addr = itr->getStartAddress();
last_addr = itr->getEndAddress();
block = itr;
}
}
verbprintf(4, "Loop: size = %lu: base_addr = %lu, last_addr = %lu\n",
(unsigned long) (last_addr - base_addr), base_addr, last_addr);
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
@@ -537,32 +559,14 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
memset(fname, '\0', FUNCNAMELEN + 1);
memset(mname, '\0', FUNCNAMELEN + 1);
mutatee_module->getName(mname, FUNCNAMELEN);
module->getName(mname, FUNCNAMELEN);
func->getName(fname, FUNCNAMELEN);
bpvector_t<point_t*>* loopStartInst =
cfGraph->findLoopInstPoints(BPatch_locLoopStartIter, loopToInstrument);
bpvector_t<point_t*>* loopExitInst =
cfGraph->findLoopInstPoints(BPatch_locLoopEndIter, loopToInstrument);
auto* returnType = func->getReturnType();
if(!loopStartInst || !loopExitInst) return function_signature{ "", "", "" };
if(returnType) typeName = returnType->getName();
unsigned long baseAddr = (unsigned long) (*loopStartInst)[0]->getAddress();
unsigned long lastAddr =
(unsigned long) (*loopExitInst)[loopExitInst->size() - 1]->getAddress();
verbprintf(3, "Loop: size of lastAddr = %lu: baseAddr = %lu, lastAddr = %lu\n",
(unsigned long) loopExitInst->size(), (unsigned long) baseAddr,
(unsigned long) lastAddr);
f->getName(fname, FUNCNAMELEN);
auto* returnType = f->getReturnType();
if(returnType)
{
typeName = returnType->getName();
}
auto* params = f->getParams();
auto* params = func->getParams();
std::vector<string_t> _params;
if(params)
{
@@ -574,36 +578,51 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
}
}
bpvector_t<BPatch_statement> lines;
bpvector_t<BPatch_statement> linesEnd;
bpvector_t<BPatch_statement> lines{};
bpvector_t<BPatch_statement> linesEnd{};
bool info1 = mutatee_module->getSourceLines(baseAddr, lines);
bool info1 = module->getSourceLines(base_addr, lines);
string_t filename = mname;
if(info1)
{
// filename = lines[0].fileName();
auto row1 = lines[0].lineNumber();
auto col1 = lines[0].lineOffset();
int row1 = 0;
int col1 = 0;
for(auto& itr : lines)
{
if(itr.lineNumber() > 0)
{
row1 = itr.lineNumber();
col1 = itr.lineOffset();
break;
}
}
if(row1 == 0 && col1 == 0)
return function_signature(typeName, fname, filename, _params);
int row2 = 0;
int col2 = 0;
for(auto& itr : lines)
{
row2 = std::max(row2, itr.lineNumber());
col2 = std::max(col2, itr.lineOffset());
}
if(col1 < 0) col1 = 0;
// This following section is attempting to remedy the limitations of
// getSourceLines for loops. As the program goes through the loop, the resulting
// lines go from the loop head, through the instructions present in the loop, to
// the last instruction in the loop, back to the loop head, then to the next
// instruction outside of the loop. What this section does is starts at the last
// instruction in the loop, then goes through the addresses until it reaches the
// next instruction outside of the loop. We then bump back a line. This is not a
// perfect solution, but we will work with the Dyninst team to find something
// better.
bool info2 = mutatee_module->getSourceLines((unsigned long) lastAddr, linesEnd);
verbprintf(3, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size());
bool info2 = module->getSourceLines(last_addr, linesEnd);
verbprintf(4, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size());
if(info2)
{
auto row2 = linesEnd[0].lineNumber();
auto col2 = linesEnd[0].lineOffset();
for(auto& itr : linesEnd)
{
row2 = std::max(row2, itr.lineNumber());
col2 = std::max(col2, itr.lineOffset());
}
if(col2 < 0) col2 = 0;
if(row2 < row1) row1 = row2; // Fix for wrong line numbers
@@ -627,35 +646,30 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
// We create a new name that embeds the file and line information in the name
//
function_signature
get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
get_func_file_line_info(module_t* module, procedure_t* func)
{
bool info1, info2;
unsigned long baseAddr, lastAddr;
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
int row1, col1, row2, col2;
string_t filename = {};
string_t typeName = {};
using address_t = Dyninst::Address;
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
string_t typeName = {};
memset(fname, '\0', FUNCNAMELEN + 1);
memset(mname, '\0', FUNCNAMELEN + 1);
mutatee_module->getName(mname, FUNCNAMELEN);
module->getName(mname, FUNCNAMELEN);
func->getName(fname, FUNCNAMELEN);
baseAddr = (unsigned long) (f->getBaseAddr());
f->getAddressRange(baseAddr, lastAddr);
bpvector_t<BPatch_statement> lines;
f->getName(fname, FUNCNAMELEN);
address_t base_addr{};
address_t last_addr{};
func->getAddressRange(base_addr, last_addr);
auto* returnType = f->getReturnType();
auto* returnType = func->getReturnType();
if(returnType)
{
typeName = returnType->getName();
}
if(returnType) typeName = returnType->getName();
auto* params = f->getParams();
std::vector<string_t> _params;
auto* params = func->getParams();
std::vector<string_t> _params = {};
if(params)
{
for(auto* itr : *params)
@@ -666,32 +680,16 @@ get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
}
}
info1 = mutatee_module->getSourceLines((unsigned long) baseAddr, lines);
bpvector_t<BPatch_statement> lines = {};
bool info = module->getSourceLines(base_addr, lines);
filename = mname;
string_t filename = mname;
if(info1)
if(info && !lines.empty())
{
// filename = lines[0].fileName();
row1 = lines[0].lineNumber();
col1 = lines[0].lineOffset();
if(col1 < 0) col1 = 0;
info2 = mutatee_module->getSourceLines((unsigned long) (lastAddr - 1), lines);
if(info2)
{
row2 = lines[1].lineNumber();
col2 = lines[1].lineOffset();
if(col2 < 0) col2 = 0;
if(row2 < row1) row1 = row2;
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ 0, 0 }, false, info1, info2);
}
else
{
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ 0, 0 }, false, info1, info2);
}
auto row = lines.front().lineNumber();
return function_signature(typeName, fname, filename, _params, { row, 0 },
{ 0, 0 }, false, info, false);
}
else
{
@@ -0,0 +1,99 @@
// 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 "function_signature.hpp"
function_signature::function_signature(string_t _ret, const string_t& _name,
string_t _file, location_t _row, location_t _col,
bool _loop, bool _info_beg, bool _info_end)
: m_loop(_loop)
, m_info_beg(_info_beg)
, m_info_end(_info_end)
, m_row(std::move(_row))
, m_col(std::move(_col))
, m_return(std::move(_ret))
, m_name(tim::demangle(_name))
, m_file(std::move(_file))
{
if(m_file.find('/') != string_t::npos)
m_file = m_file.substr(m_file.find_last_of('/') + 1);
}
function_signature::function_signature(const string_t& _ret, const string_t& _name,
const string_t& _file,
const std::vector<string_t>& _params,
location_t _row, location_t _col, bool _loop,
bool _info_beg, bool _info_end)
: function_signature(_ret, _name, _file, _row, _col, _loop, _info_beg, _info_end)
{
m_params = "(";
for(const auto& itr : _params)
m_params.append(itr + ", ");
if(!_params.empty()) m_params = m_params.substr(0, m_params.length() - 2);
m_params += ")";
}
string_t
function_signature::get(function_signature& sig)
{
return sig.get();
}
string_t
function_signature::get() const
{
std::stringstream ss;
if(use_return_info && !m_return.empty()) ss << m_return << " ";
ss << m_name;
if(use_args_info) ss << m_params;
if(m_loop && m_info_beg)
{
auto _row_col_str = [](unsigned long _row, unsigned long _col) {
std::stringstream _ss{};
if(_row == 0 && _col == 0) return std::string{};
if(_col > 0)
_ss << "{" << _row << "," << _col << "}";
else
_ss << "{" << _row << "}";
return _ss.str();
};
auto _rc1 = _row_col_str(m_row.first, m_col.first);
auto _rc2 = _row_col_str(m_row.second, m_col.second);
if(m_info_end && !_rc1.empty() && !_rc2.empty() && _rc1 != _rc2)
ss << " [" << _rc1 << "-" << _rc2 << "]";
else if(m_info_end && !_rc1.empty() && !_rc2.empty() && _rc1 == _rc2)
ss << " [" << _rc1 << "]";
else if(m_info_end && !_rc1.empty() && _rc2.empty())
ss << " [" << _rc1 << "]";
else if(!m_info_end && !_rc1.empty())
ss << " [" << _rc1 << "]";
else
errprintf(1, "loop line info is empty!");
}
if(use_file_info && m_file.length() > 0) ss << " [" << m_file;
if(use_line_info && m_row.first > 0) ss << ":" << m_row.first;
if(use_file_info && m_file.length() > 0) ss << "]";
m_signature = ss.str();
return m_signature;
}
@@ -0,0 +1,74 @@
// 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.
#pragma once
#include "fwd.hpp"
struct function_signature
{
using location_t = std::pair<unsigned long, unsigned long>;
TIMEMORY_DEFAULT_OBJECT(function_signature)
function_signature(string_t _ret, const string_t& _name, string_t _file,
location_t _row = { 0, 0 }, location_t _col = { 0, 0 },
bool _loop = false, bool _info_beg = false,
bool _info_end = false);
function_signature(const string_t& _ret, const string_t& _name, const string_t& _file,
const std::vector<string_t>& _params, location_t _row = { 0, 0 },
location_t _col = { 0, 0 }, bool _loop = false,
bool _info_beg = false, bool _info_end = false);
static string_t get(function_signature& sig);
string_t get() const;
bool m_loop = false;
bool m_info_beg = false;
bool m_info_end = false;
location_t m_row = { 0, 0 };
location_t m_col = { 0, 0 };
string_t m_return = {};
string_t m_name = {};
string_t m_params = "()";
string_t m_file = {};
mutable string_t m_signature = {};
friend bool operator==(const function_signature& lhs, const function_signature& rhs)
{
return lhs.get() == rhs.get();
}
template <typename ArchiveT>
void serialize(ArchiveT& _ar, const unsigned)
{
namespace cereal = tim::cereal;
(void) get();
_ar(cereal::make_nvp("loop", m_loop), cereal::make_nvp("info_beg", m_info_beg),
cereal::make_nvp("info_end", m_info_end), cereal::make_nvp("row", m_row),
cereal::make_nvp("col", m_col), cereal::make_nvp("return", m_return),
cereal::make_nvp("name", m_name), cereal::make_nvp("params", m_params),
cereal::make_nvp("file", m_file), cereal::make_nvp("signature", m_signature));
(void) get();
}
};
@@ -0,0 +1,273 @@
// 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.
#pragma once
#include <string_view>
#include <timemory/backends/process.hpp>
#include <timemory/environment.hpp>
#include <timemory/mpl/apply.hpp>
#include <timemory/mpl/concepts.hpp>
#include <timemory/mpl/policy.hpp>
#include <timemory/tpls/cereal/archives.hpp>
#include <timemory/tpls/cereal/cereal.hpp>
#include <timemory/utility/argparse.hpp>
#include <timemory/utility/demangle.hpp>
#include <timemory/utility/popen.hpp>
#include <timemory/variadic/macros.hpp>
#include <BPatch.h>
#include <BPatch_Vector.h>
#include <BPatch_addressSpace.h>
#include <BPatch_basicBlock.h>
#include <BPatch_basicBlockLoop.h>
#include <BPatch_callbacks.h>
#include <BPatch_function.h>
#include <BPatch_instruction.h>
#include <BPatch_point.h>
#include <BPatch_process.h>
#include <BPatch_snippet.h>
#include <BPatch_statement.h>
#include <Instruction.h>
#include <dyntypes.h>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <exception>
#include <fstream>
#include <limits>
#include <memory>
#include <numeric>
#include <ostream>
#include <regex>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>
#include <vector>
#define MUTNAMELEN 1024
#define FUNCNAMELEN 32 * 1024
#define NO_ERROR -1
#define TIMEMORY_BIN_DIR "bin"
#if !defined(PATH_MAX)
# define PATH_MAX std::numeric_limits<int>::max();
#endif
struct function_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;
using strvec_t = std::vector<string_t>;
using strset_t = std::set<string_t>;
using regexvec_t = std::vector<std::regex>;
using fmodset_t = std::set<module_function>;
using fixed_modset_t = std::map<fmodset_t*, bool>;
using exec_callback_t = BPatchExecCallback;
using exit_callback_t = BPatchExitCallback;
using fork_callback_t = BPatchForkCallback;
using patch_t = BPatch;
using process_t = BPatch_process;
using thread_t = BPatch_thread;
using binary_edit_t = BPatch_binaryEdit;
using image_t = BPatch_image;
using module_t = BPatch_module;
using procedure_t = BPatch_function;
using snippet_t = BPatch_snippet;
using call_expr_t = BPatch_funcCallExpr;
using address_space_t = BPatch_addressSpace;
using flow_graph_t = BPatch_flowGraph;
using basic_block_t = BPatch_basicBlock;
using basic_loop_t = BPatch_basicBlockLoop;
using procedure_loc_t = BPatch_procedureLocation;
using point_t = BPatch_point;
using local_var_t = BPatch_localVar;
using const_expr_t = BPatch_constExpr;
using error_level_t = BPatchErrorLevel;
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 basic_block_set_t = std::set<basic_block_t*>;
using basic_loop_vec_t = bpvector_t<basic_loop_t*>;
using snippet_pointer_vec_t = std::vector<snippet_pointer_t>;
using instruction_t = Dyninst::InstructionAPI::Instruction;
void
omnitrace_prefork_callback(thread_t* parent, thread_t* child);
//======================================================================================//
//
// Global Variables
//
//======================================================================================//
//
// label settings
//
extern bool use_return_info;
extern bool use_args_info;
extern bool use_file_info;
extern bool use_line_info;
//
// heuristic settings
//
extern bool allow_overlapping;
extern bool loop_level_instr;
extern bool instr_dynamic_callsites;
extern bool instr_traps;
extern bool instr_loop_traps;
extern size_t min_address_range;
extern size_t min_loop_address_range;
extern size_t min_instructions;
//
// debug settings
//
extern bool werror;
extern bool debug_print;
extern int verbose_level;
//
// string settings
//
extern string_t main_fname;
extern string_t argv0;
extern string_t cmdv0;
extern string_t default_components;
extern string_t prefer_library;
//
// global variables
//
extern patch_pointer_t bpatch;
extern call_expr_t* terminate_expr;
extern snippet_vec_t init_names;
extern snippet_vec_t fini_names;
extern fmodset_t available_module_functions;
extern fmodset_t instrumented_module_functions;
extern fmodset_t overlapping_module_functions;
extern fmodset_t excluded_module_functions;
extern fixed_modset_t fixed_module_functions;
extern regexvec_t func_include;
extern regexvec_t func_exclude;
extern regexvec_t file_include;
extern regexvec_t file_exclude;
extern regexvec_t file_restrict;
extern regexvec_t func_restrict;
//
//======================================================================================//
// control debug printf statements
#define errprintf(LEVEL, ...) \
{ \
if(werror || LEVEL < 0) \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stderr, "[omnitrace][exe] Error! " __VA_ARGS__); \
char _buff[FUNCNAMELEN]; \
sprintf(_buff, "[omnitrace][exe] Error! " __VA_ARGS__); \
throw std::runtime_error(std::string{ _buff }); \
} \
else \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stderr, "[omnitrace][exe] Warning! " __VA_ARGS__); \
} \
fflush(stderr); \
}
// control verbose printf statements
#define verbprintf(LEVEL, ...) \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stdout, "[omnitrace][exe] " __VA_ARGS__); \
fflush(stdout); \
}
#define verbprintf_bare(LEVEL, ...) \
{ \
if(debug_print || verbose_level >= LEVEL) fprintf(stdout, __VA_ARGS__); \
fflush(stdout); \
}
//======================================================================================//
template <typename... T>
void
consume_parameters(T&&...)
{}
//======================================================================================//
extern "C"
{
bool are_file_include_exclude_lists_empty();
bool instrument_module(const string_t& file_name);
bool instrument_entity(const string_t& function_name);
bool module_constraint(string_view_t fname);
bool routine_constraint(string_view_t fname);
}
//======================================================================================//
strset_t
get_whole_function_names();
function_signature
get_func_file_line_info(module_t* mutatee_module, procedure_t* f);
function_signature
get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument);
std::tuple<size_t, size_t>
query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc,
flow_graph_t* cfGraph = nullptr, basic_loop_t* loopToInstrument = nullptr);
bool
query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument, bool allow_traps);
template <typename Tp>
bool
insert_instr(address_space_t* mutatee, procedure_t* funcToInstr, Tp traceFunc,
procedure_loc_t traceLoc, flow_graph_t* cfGraph = nullptr,
basic_loop_t* loopToInstrument = nullptr, bool allow_traps = true);
void
errorFunc(error_level_t level, int num, const char** params);
procedure_t*
find_function(image_t* appImage, const string_t& functionName, const strset_t& = {});
void
error_func_real(error_level_t level, int num, const char* const* params);
void
error_func_fake(error_level_t level, int num, const char* const* params);
@@ -0,0 +1,251 @@
// 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.
#pragma once
#include "fwd.hpp"
#include "module_function.hpp"
static inline void
dump_info(std::ostream& _os, const fmodset_t& _data)
{
module_function::reset_width();
for(const auto& itr : _data)
module_function::update_width(itr);
module_function::write_header(_os);
for(const auto& itr : _data)
_os << itr << '\n';
module_function::reset_width();
}
//
template <typename ArchiveT,
std::enable_if_t<tim::concepts::is_archive<ArchiveT>::value, int> = 0>
static inline void
dump_info(ArchiveT& _ar, const fmodset_t& _data)
{
_ar(tim::cereal::make_nvp("module_functions", _data));
}
//
static inline void
dump_info(const string_t& _label, string_t _oname, const string_t& _ext,
const fmodset_t& _data, int _level, bool _fail)
{
namespace cereal = tim::cereal;
namespace policy = tim::policy;
_oname += "." + _ext;
auto _handle_error = [&]() {
std::stringstream _msg{};
_msg << "[dump_info] Error opening '" << _oname << " for output";
verbprintf(_level, "%s\n", _msg.str().c_str());
if(_fail)
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
};
if(!debug_print && verbose_level < _level) return;
if(_ext == "txt")
{
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
dump_info(ofs, _data);
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else if(_ext == "xml")
{
std::stringstream oss{};
{
using output_policy = policy::output_archive<cereal::XMLOutputArchive>;
output_policy::indent() = true;
auto ar = output_policy::get(oss);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
ofs << oss.str() << std::endl;
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else if(_ext == "json")
{
std::stringstream oss{};
{
using output_policy = policy::output_archive<cereal::PrettyJSONOutputArchive>;
auto ar = output_policy::get(oss);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
ofs << oss.str() << std::endl;
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else
{
throw std::runtime_error(TIMEMORY_JOIN(
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _oname,
"' does not have one of recognized file extensions: txt, json, xml"));
}
}
//
static inline void
dump_info(const string_t& _oname, const fmodset_t& _data, int _level, bool _fail,
const string_t& _type, const strset_t& _ext)
{
for(const auto& itr : _ext)
dump_info(_type, _oname, itr, _data, _level, _fail);
}
//
static inline void
load_info(const string_t& _label, const string_t& _iname, fmodset_t& _data, int _level)
{
namespace cereal = tim::cereal;
namespace policy = tim::policy;
auto _pos = _iname.find_last_of('.');
std::string _ext = {};
if(_pos != std::string::npos) _ext = _iname.substr(_pos + 1, _iname.length());
auto _handle_error = [&]() {
std::stringstream _msg{};
_msg << "[load_info] Error opening '" << _iname << " for input";
verbprintf(_level, "%s\n", _msg.str().c_str());
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
};
if(_ext == "xml")
{
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
std::ifstream ifs{ _iname };
if(!ifs)
_handle_error();
else
{
using input_policy = policy::input_archive<cereal::XMLInputArchive>;
auto ar = input_policy::get(ifs);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
verbprintf_bare(_level, "Done\n");
ifs.close();
}
else if(_ext == "json")
{
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
std::ifstream ifs{ _iname };
if(!ifs)
_handle_error();
else
{
using input_policy = policy::input_archive<cereal::JSONInputArchive>;
auto ar = input_policy::get(ifs);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
verbprintf_bare(_level, "Done\n");
ifs.close();
}
else
{
throw std::runtime_error(TIMEMORY_JOIN(
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _iname,
"' does not have one of recognized extentions: txt, json, xml :: ", _ext));
}
}
//
static inline void
load_info(const string_t& _inp, std::map<std::string, fmodset_t*>& _data, int _level)
{
std::vector<std::string> _exceptions{};
_exceptions.reserve(_data.size());
for(auto& itr : _data)
{
try
{
fmodset_t _tmp{};
load_info(itr.first, _inp, _tmp, _level);
// add to the existing
itr.second->insert(_tmp.begin(), _tmp.end());
// if it did not throw it was successfully loaded
_exceptions.clear();
break;
} catch(std::exception& _e)
{
_exceptions.emplace_back(_e.what());
}
}
if(!_exceptions.empty())
{
std::stringstream _msg{};
for(auto& itr : _exceptions)
{
_msg << "[omnitrace][exe] " << itr << "\n";
}
throw std::runtime_error(_msg.str());
}
}
@@ -0,0 +1,511 @@
// 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 "module_function.hpp"
#include "fwd.hpp"
#include "omnitrace.hpp"
module_function::width_t&
module_function::get_width()
{
static width_t _instance = []() {
width_t _tmp;
_tmp.fill(0);
return _tmp;
}();
return _instance;
}
void
module_function::reset_width()
{
get_width().fill(0);
}
void
module_function::update_width(const module_function& rhs)
{
get_width()[0] = std::max<size_t>(get_width()[0], rhs.module_name.length());
get_width()[1] = std::max<size_t>(get_width()[1], rhs.function_name.length());
get_width()[2] = std::max<size_t>(get_width()[2], rhs.signature.get().length());
}
module_function::module_function(module_t* mod, procedure_t* proc)
: module{ mod }
, function{ proc }
, flow_graph{ proc->getCFG() }
{
if(flow_graph)
{
flow_graph->getAllBasicBlocks(basic_blocks);
flow_graph->getOuterLoops(loop_blocks);
}
for(const auto& itr : basic_blocks)
{
std::vector<instruction_t> instructions{};
itr->getInstructions(instructions);
num_instructions += instructions.size();
}
char modname[FUNCNAMELEN];
char fname[FUNCNAMELEN];
module->getFullName(modname, FUNCNAMELEN);
function->getName(fname, FUNCNAMELEN);
module_name = modname;
function_name = fname;
signature = get_func_file_line_info(module, function);
if(!function->isInstrumentable())
{
verbprintf(0,
"Warning! module function generated for un-instrumentable "
"function: %s [%s]\n",
function_name.c_str(), module_name.c_str());
}
std::pair<address_t, address_t> _range{};
if(function->getAddressRange(_range.first, _range.second))
address_range = _range.second - _range.first;
}
void
module_function::write_header(std::ostream& os)
{
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
auto w1 = std::min<size_t>(get_width()[1], absolute_max_width);
auto w2 = std::min<size_t>(get_width()[2], absolute_max_width);
std::stringstream ss;
ss << std::setw(14) << "AddressRange"
<< " " << std::setw(14) << "#Instructions"
<< " " << std::setw(6) << "Ratio"
<< " " << std::setw(w0 + 8) << std::left << "Module"
<< " " << std::setw(w1 + 8) << std::left << "Function"
<< " " << std::setw(w2 + 8) << std::left << "FunctionSignature"
<< "\n";
os << ss.str();
}
bool
module_function::should_instrument() const
{
// hard constraints
if(!is_instrumentable()) return false;
if(!can_instrument_entry()) return false;
if(!can_instrument_exit()) return false;
if(is_module_constrained()) return false;
if(is_routine_constrained()) return false;
// should be before user selection
constexpr int absolute_min_instructions = 4;
if(num_instructions < absolute_min_instructions)
{
messages.emplace_back(
2, "Skipping", "function",
TIMEMORY_JOIN("-", "less-than", absolute_min_instructions, "instructions"));
return false;
}
// user selection
if(is_user_excluded()) return false;
if(is_user_restricted()) return true;
if(is_user_included()) return true;
// should be applied before dynamic-callsite check
if(is_overlapping_constrained()) return false;
if(is_entry_trap_constrained()) return false;
if(is_exit_trap_constrained()) return false;
// needs to be applied before address range and number of instruction constraints
if(is_dynamic_callsite_forced()) return true;
if(is_address_range_constrained()) return false;
if(is_num_instructions_constrained()) return false;
return true;
}
bool
module_function::is_instrumentable() const
{
if(!function->isInstrumentable())
{
messages.emplace_back(2, "Skipping", "module", "not-instrumentable");
return false;
}
return true;
}
namespace
{
bool
check_regex_restrictions(const std::string& _name, const regexvec_t& _regexes)
{
// NOLINTNEXTLINE
for(auto& itr : _regexes)
if(std::regex_search(_name, itr)) return true;
return false;
}
} // namespace
bool
module_function::is_user_restricted() const
{
if(!file_restrict.empty())
{
if(check_regex_restrictions(module_name, file_restrict))
{
messages.emplace_back(2, "Forcing", "module", "module-restrict-regex");
return false;
}
else
{
messages.emplace_back(3, "Skipping", "module", "module-restrict-regex");
return true;
}
}
if(!func_restrict.empty())
{
if(check_regex_restrictions(module_name, func_restrict))
{
messages.emplace_back(2, "Forcing", "function", "function-restrict-regex");
return false;
}
else if(check_regex_restrictions(signature.get(), func_restrict))
{
messages.emplace_back(2, "Forcing", "function", "function-restrict-regex");
return false;
}
else
{
messages.emplace_back(3, "Skipping", "function", "function-restrict-regex");
return true;
}
}
return false;
}
bool
module_function::is_user_included() const
{
if(!file_include.empty())
{
if(check_regex_restrictions(module_name, file_include))
{
messages.emplace_back(2, "Forcing", "module", "module-include-regex");
return true;
}
}
if(!func_include.empty())
{
if(check_regex_restrictions(function_name, func_include))
{
messages.emplace_back(2, "Forcing", "function", "function-include-regex");
return true;
}
else if(check_regex_restrictions(signature.get(), func_include))
{
messages.emplace_back(2, "Forcing", "function", "function-include-regex");
return true;
}
}
return false;
}
bool
module_function::is_user_excluded() const
{
if(!file_exclude.empty())
{
if(check_regex_restrictions(module_name, file_exclude))
{
messages.emplace_back(2, "Skipping", "module", "module-exclude-regex");
return true;
}
}
if(!func_exclude.empty())
{
if(check_regex_restrictions(function_name, func_exclude))
{
messages.emplace_back(2, "Skipping", "function", "function-exclude-regex");
return true;
}
else if(check_regex_restrictions(signature.get(), func_exclude))
{
messages.emplace_back(2, "Skipping", "function", "function-exclude-regex");
return true;
}
}
return false;
}
bool
module_function::is_overlapping() const
{
procedure_vec_t _overlapping{};
return function->findOverlapping(_overlapping);
}
bool
module_function::is_module_constrained() const
{
if(!instrument_module(module_name) || module_constraint(module_name.c_str()))
{
messages.emplace_back(2, "Skipping", "module", "module-constraint");
return true;
}
return false;
}
bool
module_function::is_routine_constrained() const
{
if(!instrument_entity(function_name) || !instrument_entity(signature.get()) ||
routine_constraint(function_name) || routine_constraint(signature.get()))
{
messages.emplace_back(2, "Skipping", "function", "function-constraint");
return true;
}
return false;
}
bool
module_function::is_overlapping_constrained() const
{
if(!allow_overlapping && is_overlapping())
{
messages.emplace_back(2, "Skipping", "function", "overlapping");
return true;
}
return false;
}
bool
module_function::contains_dynamic_callsites() const
{
if(flow_graph) return flow_graph->containsDynamicCallsites();
return false;
}
bool
module_function::is_dynamic_callsite_forced() const
{
if(instr_dynamic_callsites && contains_dynamic_callsites())
{
messages.emplace_back(2, "Forcing", "function", "dynamic-callsites");
return true;
}
return false;
}
bool
module_function::is_address_range_constrained() const
{
if(!loop_blocks.empty()) return is_loop_address_range_constrained();
if(address_range < min_address_range)
{
messages.emplace_back(2, "Skipping", "function", "min-address-range");
return true;
}
return false;
}
bool
module_function::is_loop_address_range_constrained() const
{
if(loop_blocks.empty()) return false;
if(address_range < min_loop_address_range)
{
messages.emplace_back(2, "Skipping", "function", "min-address-range-loop");
return true;
}
return false;
}
bool
module_function::is_num_instructions_constrained() const
{
if(num_instructions < min_instructions)
{
messages.emplace_back(2, "Skipping", "function", "min-instructions");
return true;
}
return false;
}
bool
module_function::can_instrument_entry() const
{
size_t _num_points = 0;
size_t _num_traps = 0;
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_entry);
if(_num_points == 0)
{
messages.emplace_back(3, "Skipping", "function", "no-instrumentable-entry-point");
return false;
}
return true;
}
bool
module_function::can_instrument_exit() const
{
size_t _num_points = 0;
size_t _num_traps = 0;
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_exit);
if(_num_points == 0)
{
messages.emplace_back(3, "Skipping", "function", "no-instrumentable-exit-point");
return false;
}
return true;
}
bool
module_function::is_entry_trap_constrained() const
{
if(instr_traps) return false;
size_t _num_points = 0;
size_t _num_traps = 0;
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_entry);
if(!instr_traps && (_num_points - _num_traps) == 0)
{
messages.emplace_back(3, "Skipping", "function",
"entry-point-trap-instrumentation");
return true;
}
return false;
}
bool
module_function::is_exit_trap_constrained() const
{
if(instr_traps) return false;
size_t _num_points = 0;
size_t _num_traps = 0;
std::tie(_num_points, _num_traps) = query_instr(function, BPatch_exit);
if((_num_points - _num_traps) == 0)
{
messages.emplace_back(3, "Skipping", "function",
"exit-point-trap-instrumentation");
return true;
}
return false;
}
std::pair<size_t, size_t>
module_function::operator()(address_space_t* _addr_space, procedure_t* _entr_trace,
procedure_t* _exit_trace) const
{
std::pair<size_t, size_t> _count = { 0, 0 };
auto _name = signature.get();
auto _trace_entr = omnitrace_call_expr(_name.c_str());
auto _trace_exit = omnitrace_call_expr(_name.c_str());
auto _entr = _trace_entr.get(_entr_trace);
auto _exit = _trace_exit.get(_exit_trace);
if(insert_instr(_addr_space, function, _entr, BPatch_entry, nullptr, nullptr,
instr_traps) &&
insert_instr(_addr_space, function, _exit, BPatch_exit, nullptr, nullptr,
instr_traps))
{
messages.emplace_back(1, "Instrumenting", "function", "no-constraint");
++_count.first;
}
for(auto* itr : loop_blocks)
{
if(!loop_level_instr) continue;
auto _is_constrained = [this](bool _v, const std::string& _label) {
if(!_v)
{
messages.emplace_back(3, "Skipping", "function", _label);
return true;
}
return false;
};
size_t _points = 0;
size_t _ntraps = 0;
std::tie(_points, _ntraps) = query_instr(function, BPatch_entry, flow_graph, itr);
if(_is_constrained(_points == 0, "no-instrumentable-loop-entry-point")) continue;
if(_is_constrained(!instr_traps && (_points - _ntraps) == 0,
"loop-entry-point-trap-instrumentation"))
continue;
std::tie(_points, _ntraps) = query_instr(function, BPatch_exit, flow_graph, itr);
if(_is_constrained(_points == 0, "no-instrumentable-loop-exit-point")) continue;
if(_is_constrained(!instr_traps && (_points - _ntraps) == 0,
"loop-exit-point-trap-instrumentation"))
continue;
auto lname = get_loop_file_line_info(module, function, flow_graph, itr);
auto _lname = lname.get();
messages.emplace_back(1, "Loop Instrumenting", "function", "no-constraint");
++_count.second;
auto _ltrace_entr = omnitrace_call_expr(_lname.c_str());
auto _ltrace_exit = omnitrace_call_expr(_lname.c_str());
auto _lentr = _ltrace_entr.get(_entr_trace);
auto _lexit = _ltrace_exit.get(_exit_trace);
insert_instr(_addr_space, function, _lentr, BPatch_entry, flow_graph, itr,
instr_loop_traps);
insert_instr(_addr_space, function, _lexit, BPatch_exit, flow_graph, itr,
instr_loop_traps);
}
return _count;
}
@@ -0,0 +1,185 @@
// 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.
#pragma once
#include "function_signature.hpp"
#include "fwd.hpp"
#include <timemory/mpl/concepts.hpp>
#include <timemory/tpls/cereal/cereal/cereal.hpp>
struct module_function
{
using width_t = std::array<size_t, 4>;
using address_t = Dyninst::Address;
static constexpr size_t absolute_max_width = 80;
static width_t& get_width();
static void reset_width();
static void update_width(const module_function& rhs);
static void write_header(std::ostream& os);
TIMEMORY_DEFAULT_OBJECT(module_function)
module_function(module_t* mod, procedure_t* proc);
std::pair<size_t, size_t> operator()(address_space_t* _addr_space,
procedure_t* _entr_trace,
procedure_t* _exit_trace) const;
// applies logic for all "is_*" and "can_*" checks below
bool should_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
// user bypass of heuristics
bool is_user_restricted() const; // checks user restrict regexes
bool is_user_included() const; // checks user include regexes
bool is_user_excluded() const; // checks user exclude regexes
// applied before dynamic-callsite constraint
bool is_overlapping_constrained() const; // checks overlapping constrains
bool is_entry_trap_constrained() const; // checks entry trap constraint
bool is_exit_trap_constrained() const; // checks exit trap constraint
// applied before address range and # instruction constraints
bool is_dynamic_callsite_forced() const; // checks dynamic callsites
// 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
uint64_t address_range = 0;
uint64_t num_instructions = 0;
module_t* module = nullptr;
procedure_t* function = nullptr;
flow_graph_t* flow_graph = nullptr;
string_t module_name = {};
string_t function_name = {};
function_signature signature = {};
basic_block_set_t basic_blocks = {};
basic_loop_vec_t loop_blocks = {};
using str_msg_t = std::tuple<int, string_t, string_t, string_t>;
using str_msg_vec_t = std::vector<str_msg_t>;
mutable str_msg_vec_t messages = {};
bool is_overlapping() const; // checks if func overlaps
private:
bool is_loop_address_range_constrained() const; // checks loop addr range constraint
bool contains_dynamic_callsites() const;
public:
template <typename ArchiveT>
void serialize(ArchiveT& ar, const unsigned);
friend bool operator<(const module_function& lhs, const module_function& rhs)
{
return (lhs.module_name == rhs.module_name)
? ((lhs.function_name == rhs.function_name)
? (lhs.signature.get() < rhs.signature.get())
: (lhs.function_name < rhs.function_name))
: (lhs.module_name < rhs.module_name);
}
friend bool operator==(const module_function& lhs, const module_function& rhs)
{
return std::tie(lhs.module_name, lhs.function_name, lhs.signature,
lhs.address_range, lhs.num_instructions) ==
std::tie(rhs.module_name, rhs.function_name, rhs.signature,
rhs.address_range, rhs.num_instructions);
}
friend std::ostream& operator<<(std::ostream& os, const module_function& rhs)
{
std::stringstream ss;
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
auto w1 = std::min<size_t>(get_width()[1], absolute_max_width);
auto w2 = std::min<size_t>(get_width()[2], absolute_max_width);
auto _get_str = [](const std::string& _inc) {
if(_inc.length() > absolute_max_width)
return _inc.substr(0, absolute_max_width - 3) + "...";
return _inc;
};
// clang-format off
ss << 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(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());
// clang-format on
os << ss.str();
return os;
}
};
template <typename ArchiveT>
void
module_function::serialize(ArchiveT& ar, const unsigned)
{
namespace cereal = tim::cereal;
ar(cereal::make_nvp("address_range", address_range),
cereal::make_nvp("instructions", num_instructions),
cereal::make_nvp("module", module_name),
cereal::make_nvp("function", function_name),
cereal::make_nvp("signature", signature));
if constexpr(tim::concepts::is_output_archive<ArchiveT>::value)
{
ar.setNextName("heuristics");
ar.startNode();
ar(cereal::make_nvp("should_instrument", should_instrument()),
cereal::make_nvp("is_instrumentable", is_instrumentable()),
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_module_constrained", is_module_constrained()),
cereal::make_nvp("is_routine_constrained", is_routine_constrained()),
cereal::make_nvp("is_user_restricted", is_user_restricted()),
cereal::make_nvp("is_user_included", is_user_included()),
cereal::make_nvp("is_user_excluded", is_user_excluded()),
cereal::make_nvp("is_overlapping_constrained", is_overlapping_constrained()),
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_address_range_constrained",
is_address_range_constrained()),
cereal::make_nvp("is_loop_address_range_constrained",
is_loop_address_range_constrained()),
cereal::make_nvp("is_num_instructions_constrained",
is_num_instructions_constrained()));
ar.finishNode();
}
}
File diff suppressed because it is too large. Load diff
@@ -22,231 +22,10 @@
#pragma once
#include <timemory/backends/process.hpp>
#include <timemory/environment.hpp>
#include <timemory/mpl/apply.hpp>
#include <timemory/mpl/concepts.hpp>
#include <timemory/mpl/policy.hpp>
#include <timemory/tpls/cereal/archives.hpp>
#include <timemory/tpls/cereal/cereal.hpp>
#include <timemory/utility/argparse.hpp>
#include <timemory/utility/demangle.hpp>
#include <timemory/utility/popen.hpp>
#include <timemory/variadic/macros.hpp>
#include <BPatch.h>
#include <BPatch_Vector.h>
#include <BPatch_addressSpace.h>
#include <BPatch_basicBlockLoop.h>
#include <BPatch_callbacks.h>
#include <BPatch_function.h>
#include <BPatch_point.h>
#include <BPatch_process.h>
#include <BPatch_snippet.h>
#include <BPatch_statement.h>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <exception>
#include <fstream>
#include <limits>
#include <memory>
#include <numeric>
#include <ostream>
#include <regex>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>
#include <vector>
#define MUTNAMELEN 1024
#define FUNCNAMELEN 32 * 1024
#define NO_ERROR -1
#define TIMEMORY_BIN_DIR "bin"
#if !defined(PATH_MAX)
# define PATH_MAX std::numeric_limits<int>::max();
#endif
struct function_signature;
struct module_function;
template <typename Tp>
using bpvector_t = BPatch_Vector<Tp>;
using string_t = std::string;
using stringstream_t = std::stringstream;
using strvec_t = std::vector<string_t>;
using strset_t = std::set<string_t>;
using regexvec_t = std::vector<std::regex>;
using fmodset_t = std::set<module_function>;
using fixed_modset_t = std::map<fmodset_t*, bool>;
using exec_callback_t = BPatchExecCallback;
using exit_callback_t = BPatchExitCallback;
using fork_callback_t = BPatchForkCallback;
using patch_t = BPatch;
using process_t = BPatch_process;
using thread_t = BPatch_thread;
using binary_edit_t = BPatch_binaryEdit;
using image_t = BPatch_image;
using module_t = BPatch_module;
using procedure_t = BPatch_function;
using snippet_t = BPatch_snippet;
using call_expr_t = BPatch_funcCallExpr;
using address_space_t = BPatch_addressSpace;
using flow_graph_t = BPatch_flowGraph;
using basic_loop_t = BPatch_basicBlockLoop;
using procedure_loc_t = BPatch_procedureLocation;
using point_t = BPatch_point;
using local_var_t = BPatch_localVar;
using const_expr_t = BPatch_constExpr;
using error_level_t = BPatchErrorLevel;
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 basic_loop_vec_t = bpvector_t<basic_loop_t*>;
using snippet_pointer_vec_t = std::vector<snippet_pointer_t>;
void
omnitrace_prefork_callback(thread_t* parent, thread_t* child);
//======================================================================================//
//
// Global Variables
//
//======================================================================================//
//
// boolean settings
//
static bool use_return_info = false;
static bool use_args_info = false;
static bool use_file_info = false;
static bool use_line_info = false;
//
// integral settings
//
extern bool debug_print;
extern int verbose_level;
//
// string settings
//
static string_t main_fname = "main";
static string_t argv0 = {};
static string_t cmdv0 = {};
static string_t default_components = "wall_clock";
static string_t prefer_library = {};
//
// global variables
//
static patch_pointer_t bpatch = {};
static call_expr_t* terminate_expr = nullptr;
static snippet_vec_t init_names = {};
static snippet_vec_t fini_names = {};
static fmodset_t available_module_functions = {};
static fmodset_t instrumented_module_functions = {};
static fmodset_t overlapping_module_functions = {};
static fmodset_t excluded_module_functions = {};
static fixed_modset_t fixed_module_functions = {};
static regexvec_t func_include = {};
static regexvec_t func_exclude = {};
static regexvec_t file_include = {};
static regexvec_t file_exclude = {};
static regexvec_t file_restrict = {};
static regexvec_t func_restrict = {};
//
//======================================================================================//
// control debug printf statements
#define errprintf(LEVEL, ...) \
{ \
if(werror || LEVEL < 0) \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stderr, "[omnitrace][exe] Error! " __VA_ARGS__); \
char _buff[FUNCNAMELEN]; \
sprintf(_buff, "[omnitrace][exe] Error! " __VA_ARGS__); \
throw std::runtime_error(std::string{ _buff }); \
} \
else \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stderr, "[omnitrace][exe] Warning! " __VA_ARGS__); \
} \
fflush(stderr); \
}
// control verbose printf statements
#define verbprintf(LEVEL, ...) \
{ \
if(debug_print || verbose_level >= LEVEL) \
fprintf(stdout, "[omnitrace][exe] " __VA_ARGS__); \
fflush(stdout); \
}
#define verbprintf_bare(LEVEL, ...) \
{ \
if(debug_print || verbose_level >= LEVEL) fprintf(stdout, __VA_ARGS__); \
fflush(stdout); \
}
//======================================================================================//
template <typename... T>
void
consume_parameters(T&&...)
{}
//======================================================================================//
extern "C"
{
bool are_file_include_exclude_lists_empty();
bool instrument_module(const string_t& file_name);
bool instrument_entity(const string_t& function_name);
bool module_constraint(char* fname);
bool routine_constraint(const char* fname);
}
//======================================================================================//
strset_t
get_whole_function_names();
function_signature
get_func_file_line_info(module_t* mutatee_module, procedure_t* f);
function_signature
get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument);
bool
query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc,
flow_graph_t* cfGraph = nullptr, basic_loop_t* loopToInstrument = nullptr,
bool allow_traps = true);
template <typename Tp>
bool
insert_instr(address_space_t* mutatee, procedure_t* funcToInstr, Tp traceFunc,
procedure_loc_t traceLoc, flow_graph_t* cfGraph = nullptr,
basic_loop_t* loopToInstrument = nullptr, bool allow_traps = true);
void
errorFunc(error_level_t level, int num, const char** params);
procedure_t*
find_function(image_t* appImage, const string_t& functionName, const strset_t& = {});
void
error_func_real(error_level_t level, int num, const char* const* params);
void
error_func_fake(error_level_t level, int num, const char* const* params);
#include "function_signature.hpp"
#include "fwd.hpp"
#include "info.hpp"
#include "module_function.hpp"
//======================================================================================//
@@ -285,465 +64,6 @@ to_lower(string_t s)
//
//======================================================================================//
//
struct function_signature
{
using location_t = std::pair<unsigned long, unsigned long>;
bool m_loop = false;
bool m_info_beg = false;
bool m_info_end = false;
location_t m_row = { 0, 0 };
location_t m_col = { 0, 0 };
string_t m_return = {};
string_t m_name = {};
string_t m_params = "()";
string_t m_file = {};
mutable string_t m_signature = {};
TIMEMORY_DEFAULT_OBJECT(function_signature)
template <typename ArchiveT>
void serialize(ArchiveT& _ar, const unsigned)
{
namespace cereal = tim::cereal;
(void) get();
_ar(cereal::make_nvp("loop", m_loop), cereal::make_nvp("info_beg", m_info_beg),
cereal::make_nvp("info_end", m_info_end), cereal::make_nvp("row", m_row),
cereal::make_nvp("col", m_col), cereal::make_nvp("return", m_return),
cereal::make_nvp("name", m_name), cereal::make_nvp("params", m_params),
cereal::make_nvp("file", m_file), cereal::make_nvp("signature", m_signature));
(void) get();
}
function_signature(string_t _ret, const string_t& _name, string_t _file,
location_t _row = { 0, 0 }, location_t _col = { 0, 0 },
bool _loop = false, bool _info_beg = false, bool _info_end = false)
: m_loop(_loop)
, m_info_beg(_info_beg)
, m_info_end(_info_end)
, m_row(std::move(_row))
, m_col(std::move(_col))
, m_return(std::move(_ret))
, m_name(tim::demangle(_name))
, m_file(std::move(_file))
{
if(m_file.find('/') != string_t::npos)
m_file = m_file.substr(m_file.find_last_of('/') + 1);
}
function_signature(const string_t& _ret, const string_t& _name, const string_t& _file,
const std::vector<string_t>& _params, location_t _row = { 0, 0 },
location_t _col = { 0, 0 }, bool _loop = false,
bool _info_beg = false, bool _info_end = false)
: function_signature(_ret, _name, _file, _row, _col, _loop, _info_beg, _info_end)
{
m_params = "(";
for(const auto& itr : _params)
m_params.append(itr + ", ");
if(!_params.empty()) m_params = m_params.substr(0, m_params.length() - 2);
m_params += ")";
}
friend bool operator==(const function_signature& lhs, const function_signature& rhs)
{
return lhs.get() == rhs.get();
}
static auto get(function_signature& sig) { return sig.get(); }
string_t get() const
{
std::stringstream ss;
if(use_return_info && !m_return.empty()) ss << m_return << " ";
ss << m_name;
if(use_args_info) ss << m_params;
if(m_loop && m_info_beg)
{
if(m_info_end)
{
ss << " [{" << m_row.first << "," << m_col.first << "}-{" << m_row.second
<< "," << m_col.second << "}]";
}
else
{
ss << "[{" << m_row.first << "," << m_col.first << "}]";
}
}
if(use_file_info && m_file.length() > 0) ss << " [" << m_file;
if(use_line_info && m_row.first > 0) ss << ":" << m_row.first;
if(use_file_info && m_file.length() > 0) ss << "]";
m_signature = ss.str();
return m_signature;
}
};
//
//======================================================================================//
//
struct module_function
{
using width_t = std::array<size_t, 3>;
using address_t = Dyninst::Address;
static constexpr size_t absolute_max_width = 80;
static auto& get_width()
{
static width_t _instance = []() {
width_t _tmp;
_tmp.fill(0);
return _tmp;
}();
return _instance;
}
TIMEMORY_DEFAULT_OBJECT(module_function)
static void reset_width() { get_width().fill(0); }
static void update_width(const module_function& rhs)
{
get_width()[0] = std::max<size_t>(get_width()[0], rhs.module.length());
get_width()[1] = std::max<size_t>(get_width()[1], rhs.function.length());
get_width()[2] = std::max<size_t>(get_width()[2], rhs.signature.get().length());
}
module_function(string_t _module, string_t _func, function_signature _sign,
procedure_t* proc)
: module(std::move(_module))
, function(std::move(_func))
, signature(std::move(_sign))
{
if(proc)
{
std::pair<address_t, address_t> _range{};
if(proc->getAddressRange(_range.first, _range.second))
address_range = _range.second - _range.first;
}
}
module_function(module_t* mod, procedure_t* proc)
{
char modname[FUNCNAMELEN];
char fname[FUNCNAMELEN];
mod->getFullName(modname, FUNCNAMELEN);
proc->getName(fname, FUNCNAMELEN);
module = modname;
function = fname;
signature = get_func_file_line_info(mod, proc);
if(!proc->isInstrumentable())
{
verbprintf(0,
"Warning! module function generated for un-instrumentable "
"function: %s [%s]\n",
function.c_str(), module.c_str());
}
std::pair<address_t, address_t> _range{};
if(proc->getAddressRange(_range.first, _range.second))
address_range = _range.second - _range.first;
}
friend bool operator<(const module_function& lhs, const module_function& rhs)
{
return (lhs.module == rhs.module)
? ((lhs.function == rhs.function)
? (lhs.signature.get() < rhs.signature.get())
: (lhs.function < rhs.function))
: (lhs.module < rhs.module);
}
friend bool operator==(const module_function& lhs, const module_function& rhs)
{
return std::tie(lhs.module, lhs.function, lhs.signature, lhs.address_range) ==
std::tie(rhs.module, rhs.function, rhs.signature, rhs.address_range);
}
static void write_header(std::ostream& os)
{
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
auto w1 = std::min<size_t>(get_width()[1], absolute_max_width);
auto w2 = std::min<size_t>(get_width()[2], absolute_max_width);
std::stringstream ss;
ss << std::setw(14) << "AddressRange"
<< " " << std::setw(w0 + 8) << std::left << "Module"
<< " " << std::setw(w1 + 8) << std::left << "Function"
<< " " << std::setw(w2 + 8) << std::left << "FunctionSignature"
<< "\n";
os << ss.str();
}
friend std::ostream& operator<<(std::ostream& os, const module_function& rhs)
{
std::stringstream ss;
auto w0 = std::min<size_t>(get_width()[0], absolute_max_width);
auto w1 = std::min<size_t>(get_width()[1], absolute_max_width);
auto w2 = std::min<size_t>(get_width()[2], absolute_max_width);
auto _get_str = [](const std::string& _inc) {
if(_inc.length() > absolute_max_width)
return _inc.substr(0, absolute_max_width - 3) + "...";
return _inc;
};
// clang-format off
ss << std::setw(14) << rhs.address_range << " "
<< std::setw(w0 + 8) << std::left << _get_str(rhs.module) << " "
<< std::setw(w1 + 8) << std::left << _get_str(rhs.function) << " "
<< std::setw(w2 + 8) << std::left << _get_str(rhs.signature.get());
// clang-format on
os << ss.str();
return os;
}
size_t address_range = 0;
string_t module = {};
string_t function = {};
function_signature signature = {};
template <typename ArchiveT>
void serialize(ArchiveT& _ar, const unsigned)
{
namespace cereal = tim::cereal;
_ar(cereal::make_nvp("address_range", address_range),
cereal::make_nvp("module", module), cereal::make_nvp("function", function),
cereal::make_nvp("signature", signature));
}
};
//
//======================================================================================//
//
static inline void
dump_info(std::ostream& _os, const fmodset_t& _data)
{
module_function::reset_width();
for(const auto& itr : _data)
module_function::update_width(itr);
module_function::write_header(_os);
for(const auto& itr : _data)
_os << itr << '\n';
module_function::reset_width();
}
//
template <typename ArchiveT,
std::enable_if_t<tim::concepts::is_archive<ArchiveT>::value, int> = 0>
static inline void
dump_info(ArchiveT& _ar, const fmodset_t& _data)
{
_ar(tim::cereal::make_nvp("module_functions", _data));
}
//
static inline void
dump_info(const string_t& _label, string_t _oname, const string_t& _ext,
const fmodset_t& _data, int _level, bool _fail)
{
namespace cereal = tim::cereal;
namespace policy = tim::policy;
_oname += "." + _ext;
auto _handle_error = [&]() {
std::stringstream _msg{};
_msg << "[dump_info] Error opening '" << _oname << " for output";
verbprintf(_level, "%s\n", _msg.str().c_str());
if(_fail)
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
};
if(!debug_print && verbose_level < _level) return;
if(_ext == "txt")
{
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
dump_info(ofs, _data);
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else if(_ext == "xml")
{
std::stringstream oss{};
{
using output_policy = policy::output_archive<cereal::XMLOutputArchive>;
output_policy::indent() = true;
auto ar = output_policy::get(oss);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
ofs << oss.str() << std::endl;
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else if(_ext == "json")
{
std::stringstream oss{};
{
using output_policy = policy::output_archive<cereal::PrettyJSONOutputArchive>;
auto ar = output_policy::get(oss);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
std::ofstream ofs{};
if(!tim::filepath::open(ofs, _oname))
_handle_error();
else
{
verbprintf(_level, "Outputting '%s'... ", _oname.c_str());
ofs << oss.str() << std::endl;
verbprintf_bare(_level, "Done\n");
}
ofs.close();
}
else
{
throw std::runtime_error(TIMEMORY_JOIN(
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _oname,
"' does not have one of recognized file extensions: txt, json, xml"));
}
}
//
static inline void
dump_info(const string_t& _oname, const fmodset_t& _data, int _level, bool _fail,
const string_t& _type, const strset_t& _ext)
{
for(const auto& itr : _ext)
dump_info(_type, _oname, itr, _data, _level, _fail);
}
//
static inline void
load_info(const string_t& _label, const string_t& _iname, fmodset_t& _data, int _level)
{
namespace cereal = tim::cereal;
namespace policy = tim::policy;
auto _pos = _iname.find_last_of('.');
std::string _ext = {};
if(_pos != std::string::npos) _ext = _iname.substr(_pos + 1, _iname.length());
auto _handle_error = [&]() {
std::stringstream _msg{};
_msg << "[load_info] Error opening '" << _iname << " for input";
verbprintf(_level, "%s\n", _msg.str().c_str());
throw std::runtime_error(std::string{ "[omnitrace][exe]" } + _msg.str());
};
if(_ext == "xml")
{
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
std::ifstream ifs{ _iname };
if(!ifs)
_handle_error();
else
{
using input_policy = policy::input_archive<cereal::XMLInputArchive>;
auto ar = input_policy::get(ifs);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
verbprintf_bare(_level, "Done\n");
ifs.close();
}
else if(_ext == "json")
{
verbprintf(_level, "Reading '%s'... ", _iname.c_str());
std::ifstream ifs{ _iname };
if(!ifs)
_handle_error();
else
{
using input_policy = policy::input_archive<cereal::JSONInputArchive>;
auto ar = input_policy::get(ifs);
ar->setNextName("omnitrace");
ar->startNode();
ar->setNextName(_label.c_str());
ar->startNode();
(*ar)(cereal::make_nvp("module_functions", _data));
ar->finishNode();
ar->finishNode();
}
verbprintf_bare(_level, "Done\n");
ifs.close();
}
else
{
throw std::runtime_error(TIMEMORY_JOIN(
"", "[omnitrace][exe] Error in ", __FUNCTION__, " :: filename '", _iname,
"' does not have one of recognized extentions: txt, json, xml :: ", _ext));
}
}
//
static inline void
load_info(const string_t& _inp, std::map<std::string, fmodset_t*>& _data, int _level)
{
std::vector<std::string> _exceptions{};
_exceptions.reserve(_data.size());
for(auto& itr : _data)
{
try
{
fmodset_t _tmp{};
load_info(itr.first, _inp, _tmp, _level);
// add to the existing
itr.second->insert(_tmp.begin(), _tmp.end());
// if it did not throw it was successfully loaded
_exceptions.clear();
break;
} catch(std::exception& _e)
{
_exceptions.emplace_back(_e.what());
}
}
if(!_exceptions.empty())
{
std::stringstream _msg{};
for(auto& itr : _exceptions)
{
_msg << "[omnitrace][exe] " << itr << "\n";
}
throw std::runtime_error(_msg.str());
}
}
//
//======================================================================================//
//
template <typename Tp, std::enable_if_t<!std::is_same<Tp, std::string>::value, int> = 0>
snippet_pointer_t
get_snippet(Tp arg)
@@ -962,4 +282,79 @@ omnitrace_fork_callback(thread_t* parent, thread_t* child)
}
//
//======================================================================================//
// insert_instr -- generic insert instrumentation function
//
template <typename Tp>
bool
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)
{
module_t* module = funcToInstr->getModule();
if(!module || !traceFunc) return false;
bpvector_t<point_t*>* _points = nullptr;
auto _trace = traceFunc.get();
if(cfGraph && loopToInstrument)
{
if(traceLoc == BPatch_entry)
_points = cfGraph->findLoopInstPoints(BPatch_locLoopEntry, loopToInstrument);
else if(traceLoc == BPatch_exit)
_points = cfGraph->findLoopInstPoints(BPatch_locLoopExit, loopToInstrument);
}
else
{
_points = funcToInstr->findPoint(traceLoc);
}
if(_points == nullptr) return false;
if(_points->empty()) return false;
/*if(loop_level_instr)
{
flow_graph_t* flow = funcToInstr->getCFG();
bpvector_t<basic_loop_t*> basicLoop;
flow->getOuterLoops(basicLoop);
for(auto litr = basicLoop.begin(); litr != basicLoop.end(); ++litr)
{
bpvector_t<point_t*>* _tmp;
if(traceLoc == BPatch_entry)
_tmp = cfGraph->findLoopInstPoints(BPatch_locLoopEntry, *litr);
else if(traceLoc == BPatch_exit)
_tmp = cfGraph->findLoopInstPoints(BPatch_locLoopExit, *litr);
if(!_tmp)
continue;
for(auto& itr : *_tmp)
_points->push_back(itr);
}
}*/
// verbprintf(0, "Instrumenting |> [ %s ]\n", name.m_name.c_str());
std::set<point_t*> _traps{};
if(!allow_traps)
{
for(auto& itr : *_points)
{
if(itr && itr->usesTrap_NP()) _traps.insert(itr);
}
}
size_t _n = 0;
for(auto& itr : *_points)
{
if(!itr || _traps.count(itr) > 0)
continue;
else if(traceLoc == BPatch_entry)
mutatee->insertSnippet(*_trace, *itr, BPatch_callBefore, BPatch_firstSnippet);
// else if(traceLoc == BPatch_exit)
// mutatee->insertSnippet(*_trace, *itr, BPatch_callAfter,
// BPatch_firstSnippet);
else
mutatee->insertSnippet(*_trace, *itr);
++_n;
}
return (_n > 0);
}
@@ -0,0 +1,149 @@
# adds a ctest for executable
function(OMNITRACE_ADD_BIN_TEST)
cmake_parse_arguments(
TEST
"" # options
"NAME;TARGET;TIMEOUT;WORKING_DIRECTORY" # single value args
"ARGS;ENVIRONMENT;LABELS;PROPERTIES;PASS_REGULAR_EXPRESSION;FAIL_REGULAR_EXPRESSION;SKIP_REGULAR_EXPRESSION;DEPENDS;COMMAND" # multiple
# value args
${ARGN})
if(NOT OMNITRACE_DYNINST_API_RT_DIR AND OMNITRACE_DYNINST_API_RT)
get_filename_component(OMNITRACE_DYNINST_API_RT_DIR "${OMNITRACE_DYNINST_API_RT}"
DIRECTORY)
endif()
if(OMNITRACE_BUILD_DYNINST)
set(OMNITRACE_DYNINST_API_RT_DIR
"${PROJECT_BINARY_DIR}/external/dyninst/dyninstAPI_RT:${PROJECT_BINARY_DIR}/external/dyninst/dyninstAPI"
)
endif()
if(NOT TEST_ENVIRONMENT)
set(TEST_ENVIRONMENT
"OMNITRACE_USE_PERFETTO=ON"
"OMNITRACE_USE_TIMEMORY=ON"
"OMNITRACE_USE_SAMPLING=ON"
"OMNITRACE_TIME_OUTPUT=OFF"
"LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}"
)
endif()
list(APPEND TEST_ENVIRONMENT "OMNITRACE_CI=ON"
"OMNITRACE_OUTPUT_PATH=omnitrace-tests-output"
"OMNITRACE_OUTPUT_PREFIX=${TEST_NAME}/")
if(TEST_COMMAND)
add_test(
NAME ${TEST_NAME}
COMMAND ${TEST_COMMAND} ${TEST_ARGS}
WORKING_DIRECTORY ${TEST_WORKING_DIRECTORY})
set_tests_properties(
${TEST_NAME}
PROPERTIES ENVIRONMENT
"${TEST_ENVIRONMENT}"
TIMEOUT
${TEST_TIMEOUT}
LABELS
"omnitrace-bin;${TEST_LABELS}"
PASS_REGULAR_EXPRESSION
"${TEST_PASS_REGULAR_EXPRESSION}"
FAIL_REGULAR_EXPRESSION
"${TEST_FAIL_REGULAR_EXPRESSION}"
SKIP_REGULAR_EXPRESSION
"${TEST_SKIP_REGULAR_EXPRESSION}"
${TEST_PROPERTIES})
elseif(TARGET ${TEST_TARGET})
add_test(
NAME ${TEST_NAME}
COMMAND $<TARGET_FILE:${TEST_TARGET}> ${TEST_ARGS}
WORKING_DIRECTORY $<TARGET_FILE_DIR:${TEST_TARGET}>)
set_tests_properties(
${TEST_NAME}
PROPERTIES ENVIRONMENT
"${TEST_ENVIRONMENT}"
TIMEOUT
${TEST_TIMEOUT}
LABELS
"omnitrace-bin;${TEST_LABELS}"
PASS_REGULAR_EXPRESSION
"${TEST_PASS_REGULAR_EXPRESSION}"
FAIL_REGULAR_EXPRESSION
"${TEST_FAIL_REGULAR_EXPRESSION}"
SKIP_REGULAR_EXPRESSION
"${TEST_SKIP_REGULAR_EXPRESSION}"
${TEST_PROPERTIES})
elseif(OMNITRACE_BUILD_TESTING)
message(FATAL_ERROR "Error! ${TEST_TARGET} does not exist")
endif()
endfunction()
omnitrace_add_bin_test(
NAME omnitrace-exe-help
TARGET omnitrace-exe
ARGS --help
LABELS omnitrace-exe
TIMEOUT 15
PASS_REGULAR_EXPRESSION
".*\\\[omnitrace\\\] Usage:.*\\\[DEBUG OPTIONS\\\].*\\\[MODE OPTIONS\\\].*\\\[LIBRARY OPTIONS\\\].*\\\[SYMBOL SELECTION OPTIONS\\\].*\\\[RUNTIME OPTIONS\\\].*\\\[GRANULARITY OPTIONS\\\].*\\\[DYNINST OPTIONS\\\].*"
)
omnitrace_add_bin_test(
NAME omnitrace-exe-simulate-ls
TARGET omnitrace-exe
ARGS --simulate --print-format json txt xml -- ls
TIMEOUT 60)
omnitrace_add_bin_test(
NAME omnitrace-exe-simulate-ls-check
DEPENDS omnitrace-exe-simulate-ls
COMMAND ls
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}/omnitrace-tests-output/omnitrace-exe-simulate-ls
TIMEOUT 30
PASS_REGULAR_EXPRESSION
".*available-instr.json.*available-instr.txt.*available-instr.xml.*excluded-instr.json.*excluded-instr.txt.*excluded-instr.xml.*instrumented-instr.json.*instrumented-instr.txt.*instrumented-instr.xml.*overlapping-instr.json.*overlapping-instr.txt.*overlapping-instr.xml.*"
)
omnitrace_add_bin_test(
NAME omnitrace-avail-help
TARGET omnitrace-avail
ARGS --help
LABELS omnitrace-avail
TIMEOUT 15
PASS_REGULAR_EXPRESSION
".*\\\[omnitrace-avail\\\] Usage:.*\\\[CATEGORIES\\\].*\\\[VIEW OPTIONS\\\].*\\\[COLUMN OPTIONS\\\].*\\\[WIDTH OPTIONS\\\].*\\\[OUTPUT OPTIONS\\\].*"
)
omnitrace_add_bin_test(
NAME omnitrace-avail-filter-wall-clock-available
TARGET omnitrace-avail
ARGS -r wall_clock -C --available
LABELS omnitrace-avail
TIMEOUT 15
PASS_REGULAR_EXPRESSION
"\\\|[-]+\\\|\n\\\|[ ]+COMPONENT[ ]+\\\|\n\\\|[-]+\\\|\n\\\| (wall_clock)[ ]+\\\|\n\\\| (sampling_wall_clock)[ ]+\\\|\n\\\|[-]+\\\|"
)
omnitrace_add_bin_test(
NAME omnitrace-avail-category-filer-omnitrace
TARGET omnitrace-avail
ARGS --categories settings::omnitrace --brief
LABELS omnitrace-avail
TIMEOUT 15
PASS_REGULAR_EXPRESSION "OMNITRACE_(SETTINGS_DESC|OUTPUT_FILE|OUTPUT_PREFIX)"
FAIL_REGULAR_EXPRESSION
"OMNITRACE_(ADD_SECONDARY|SCIENTIFIC|PRECISION|MEMORY_PRECISION|TIMING_PRECISION)"
)
omnitrace_add_bin_test(
NAME omnitrace-avail-category-filer-timemory
TARGET omnitrace-avail
ARGS --categories settings::timemory --brief
LABELS omnitrace-avail
TIMEOUT 15
PASS_REGULAR_EXPRESSION
"OMNITRACE_(ADD_SECONDARY|SCIENTIFIC|PRECISION|MEMORY_PRECISION|TIMING_PRECISION)"
FAIL_REGULAR_EXPRESSION "OMNITRACE_(SETTINGS_DESC|OUTPUT_FILE)")
+9 -181
مشاهده پرونده
@@ -1,186 +1,14 @@
# ------------------------------------------------------------------------------#
# ----------------------------------------------------------------------------- #
#
# omnitrace interface library
# omnitrace: contains all instrumentation functionality
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-interface-library INTERFACE)
add_library(omnitrace::omnitrace-interface-library ALIAS omnitrace-interface-library)
target_include_directories(
omnitrace-interface-library INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/include)
target_include_directories(omnitrace-interface-library SYSTEM
INTERFACE ${perfetto_DIR}/sdk)
target_compile_definitions(
omnitrace-interface-library
INTERFACE OMNITRACE_MAX_THREADS=${OMNITRACE_MAX_THREADS}
$<IF:$<BOOL:${OMNITRACE_CUSTOM_DATA_SOURCE}>,CUSTOM_DATA_SOURCE,>)
target_link_libraries(
omnitrace-interface-library
INTERFACE $<BUILD_INTERFACE:omnitrace::omnitrace-headers>
$<BUILD_INTERFACE:omnitrace::omnitrace-threading>
$<BUILD_INTERFACE:omnitrace::omnitrace-compile-options>
$<BUILD_INTERFACE:omnitrace::omnitrace-hip>
$<BUILD_INTERFACE:omnitrace::omnitrace-roctracer>
$<BUILD_INTERFACE:omnitrace::omnitrace-rocm-smi>
$<BUILD_INTERFACE:omnitrace::omnitrace-mpi>
$<BUILD_INTERFACE:omnitrace::omnitrace-ptl>
$<BUILD_INTERFACE:timemory::timemory-headers>
$<BUILD_INTERFACE:timemory::timemory-gotcha>
$<BUILD_INTERFACE:timemory::timemory-cxx-static>
$<IF:$<BOOL:${OMNITRACE_USE_SANITIZER}>,omnitrace::omnitrace-sanitizer,>)
# ------------------------------------------------------------------------------#
# omnitrace-dl: contains minimal symbols and dlopen's omnitrace
#
# omnitrace object library
# omnitrace-user: contains symbols for user API
#
# ------------------------------------------------------------------------------#
# ----------------------------------------------------------------------------- #
add_library(omnitrace-object-library OBJECT)
add_library(omnitrace::omnitrace-object-library ALIAS omnitrace-object-library)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/library/defines.hpp.in
${CMAKE_CURRENT_BINARY_DIR}/include/library/defines.hpp @ONLY)
set(library_sources
${CMAKE_CURRENT_LIST_DIR}/src/library.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/api.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/config.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/cpu_freq.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/critical_trace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/kokkosp.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/gpu.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/perfetto.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/ptl.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/sampling.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/state.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/thread_data.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/thread_sampler.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/timemory.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/backtrace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/fork_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/mpi_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/omnitrace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/pthread_gotcha.cpp
${perfetto_DIR}/sdk/perfetto.cc)
set(library_headers
${CMAKE_CURRENT_LIST_DIR}/include/library.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/api.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/config.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/common.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/cpu_freq.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/critical_trace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/debug.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/gpu.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/perfetto.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/ptl.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/sampling.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/state.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/thread_data.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/thread_sampler.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/timemory.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/fwd.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/backtrace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/fork_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/functors.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/mpi_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/omnitrace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/rocm_smi.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/roctracer.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/roctracer_callbacks.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/pthread_gotcha.hpp
${perfetto_DIR}/sdk/perfetto.h)
target_sources(omnitrace-object-library PRIVATE ${library_sources} ${library_headers})
if(OMNITRACE_USE_ROCTRACER)
target_sources(
omnitrace-object-library
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/library/components/roctracer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/roctracer_callbacks.cpp)
endif()
if(OMNITRACE_USE_ROCM_SMI)
target_sources(omnitrace-object-library
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/library/components/rocm_smi.cpp)
endif()
target_link_libraries(omnitrace-object-library PRIVATE omnitrace-interface-library)
if(OMNITRACE_DYNINST_API_RT)
get_filename_component(OMNITRACE_DYNINST_API_RT_DIR "${OMNITRACE_DYNINST_API_RT}"
DIRECTORY)
endif()
# ------------------------------------------------------------------------------#
#
# omnitrace shared library
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-library SHARED $<TARGET_OBJECTS:omnitrace-object-library>)
add_library(omnitrace::omnitrace-library ALIAS omnitrace-library)
target_link_libraries(omnitrace-library PRIVATE omnitrace-interface-library)
set_target_properties(
omnitrace-library
PROPERTIES OUTPUT_NAME omnitrace
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
INSTALL_RPATH
"\$ORIGIN:\$ORIGIN/timemory/libunwind:\$ORIGIN/dyninst-tpls/libs")
install(
TARGETS omnitrace-library
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
# ------------------------------------------------------------------------------#
#
# omnitrace dl library
#
# ------------------------------------------------------------------------------#
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_SKIP_RPATH OFF)
set(BUILD_RPATH_USE_ORIGIN ON)
add_library(omnitrace-dl-library SHARED)
add_library(omnitrace::omnitrace-dl-library ALIAS omnitrace-dl-library)
target_sources(omnitrace-dl-library PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/dl.cpp)
target_link_libraries(omnitrace-dl-library PRIVATE ${dl_LIBRARY})
check_cxx_compiler_flag("-fno-exceptions" omnitrace_dl_library_fno_exceptions)
check_cxx_compiler_flag("-ftls-model=local-dynamic"
omnitrace_dl_library_ftls_module_local_dynamic)
if(OMNITRACE_BUILD_DEVELOPER)
if(omnitrace_dl_library_fno_exceptions)
target_compile_options(omnitrace-dl-library PRIVATE -fno-exceptions)
endif()
if(omnitrace_dl_library_ftls_module_local_dynamic)
target_compile_options(omnitrace-dl-library PRIVATE -ftls-model=local-dynamic)
endif()
endif()
set_target_properties(
omnitrace-dl-library
PROPERTIES OUTPUT_NAME omnitrace-dl
CXX_VISIBILITY_PRESET "protected"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH "\$ORIGIN"
INSTALL_RPATH "\$ORIGIN")
install(
TARGETS omnitrace-dl-library
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
add_subdirectory(common)
add_subdirectory(omnitrace)
add_subdirectory(omnitrace-dl)
add_subdirectory(omnitrace-user)
@@ -0,0 +1,22 @@
# ------------------------------------------------------------------------------#
#
# omnitrace common headers
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-common-library INTERFACE)
add_library(omnitrace::common-library ALIAS omnitrace-common-library)
target_sources(
omnitrace-common-library
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/defines.h
${CMAKE_CURRENT_SOURCE_DIR}/delimit.hpp
${CMAKE_CURRENT_SOURCE_DIR}/environment.hpp
${CMAKE_CURRENT_SOURCE_DIR}/invoke.hpp
${CMAKE_CURRENT_SOURCE_DIR}/join.hpp)
get_filename_component(COMMON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" DIRECTORY)
target_include_directories(omnitrace-common-library INTERFACE ${COMMON_INCLUDE_DIR})
target_compile_definitions(omnitrace-common-library
INTERFACE $<BUILD_INTERFACE:OMNITRACE_INTERNAL_BUILD>)
@@ -0,0 +1,36 @@
// 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.
#pragma once
#define OMNITRACE_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#define OMNITRACE_VISIBILITY(MODE) OMNITRACE_ATTRIBUTE(visibility(MODE))
#define OMNITRACE_PUBLIC_API OMNITRACE_VISIBILITY("default")
#define OMNITRACE_HIDDEN_API OMNITRACE_VISIBILITY("hidden")
#define OMNITRACE_WEAK_API OMNITRACE_ATTRIBUTE(weak)
#define OMNITRACE_INLINE OMNITRACE_ATTRIBUTE(__always_inline__)
#if defined(__cplusplus)
# if !defined(OMNITRACE_FOLD_EXPRESSION)
# define OMNITRACE_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
# endif
#endif
@@ -0,0 +1,65 @@
// 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.
#pragma once
#include <string>
#include <vector>
namespace omnitrace
{
inline namespace common
{
namespace
{
template <typename ContainerT = std::vector<std::string>>
inline ContainerT
delimit(const std::string& line, const char* delimiters = "\"',;: ");
template <typename ContainerT>
inline ContainerT
delimit(const std::string& line, const char* delimiters)
{
ContainerT _result{};
size_t _beginp = 0; // position that is the beginning of the new string
size_t _delimp = 0; // position of the delimiter in the string
while(_beginp < line.length() && _delimp < line.length())
{
// find the first character (starting at _delimp) that is not a delimiter
_beginp = line.find_first_not_of(delimiters, _delimp);
// if no a character after or at _end that is not a delimiter is not found
// then we are done
if(_beginp == std::string::npos) break;
// starting at the position of the new string, find the next delimiter
_delimp = line.find_first_of(delimiters, _beginp);
std::string _tmp{};
// starting at the position of the new string, get the characters
// between this position and the next delimiter
_tmp = line.substr(_beginp, _delimp - _beginp);
// don't add empty strings
if(!_tmp.empty()) _result.emplace(_result.end(), _tmp);
}
return _result;
}
} // namespace
} // namespace common
} // namespace omnitrace
@@ -0,0 +1,77 @@
// 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.
#pragma once
#include <cstdlib>
#include <cstring>
#include <string>
#include <string_view>
namespace omnitrace
{
inline namespace common
{
namespace
{
inline std::string
get_env(const char* env_id, const char* _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var) return std::string{ env_var };
return _default;
}
inline int
get_env(const char* env_id, int _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var) return std::stoi(env_var);
return _default;
}
inline bool
get_env(const char* env_id, bool _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var)
{
if(std::string_view{ env_var }.find_first_not_of("0123456789") ==
std::string_view::npos)
return static_cast<bool>(std::stoi(env_var));
else
{
for(size_t i = 0; i < strlen(env_var); ++i)
env_var[i] = tolower(env_var[i]);
for(const auto& itr : { "off", "false", "no", "n", "f", "0" })
if(strcmp(env_var, itr) == 0) return false;
}
return true;
}
return _default;
}
} // namespace
} // namespace common
} // namespace omnitrace
@@ -0,0 +1,114 @@
// 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.
#pragma once
#include "common/defines.h"
#include "common/join.hpp"
#include <atomic>
#include <cstring>
#include <functional>
#include <string>
#if !defined(OMNITRACE_COMMON_LIBRARY_NAME)
# define OMNITRACE_COMMON_LIBRARY_NAME "common"
# error OMNITRACE_COMMON_LIBRARY_NAME must be defined
#endif
namespace omnitrace
{
inline namespace common
{
namespace
{
template <typename FuncT, typename... Args>
inline auto
invoke(const char* _name, FuncT&& _func, Args... _args) OMNITRACE_HIDDEN_API;
inline int32_t&
get_guard()
{
static thread_local int32_t _v = 0;
return _v;
}
inline int64_t
get_thread_index()
{
static std::atomic<int64_t> _c{ 0 };
static thread_local auto _v = _c++;
return _v;
}
template <typename FuncT, typename... Args>
auto
invoke(const char* _name, int _verbose, FuncT&& _func, Args... _args)
{
if(_func)
{
struct decrement_guard
{
// decrement the guard as it exits the scope
~decrement_guard() { --get_guard(); }
} _unlk{};
// if _lk is ever greater than zero on the same thread, this
// means a function within the current function is calling
// our instrumentation so we ignore the call
int32_t _lk = get_guard()++;
if(_lk == 0)
{
if(_verbose > 3)
{
fflush(stderr);
fprintf(stderr,
"[omnitrace][" OMNITRACE_COMMON_LIBRARY_NAME "][%li] %s(%s)\n",
get_thread_index(), _name, join(", ", _args...).c_str());
fflush(stderr);
}
return std::invoke(std::forward<FuncT>(_func), _args...);
}
else if(_verbose > 2)
{
fflush(stderr);
fprintf(stderr,
"[omnitrace][" OMNITRACE_COMMON_LIBRARY_NAME
"][%li] %s(%s) was guarded :: value = %i\n",
get_thread_index(), _name, join(", ", _args...).c_str(), _lk);
fflush(stderr);
}
}
else if(_verbose >= 0)
{
fprintf(stderr,
"[omnitrace][" OMNITRACE_COMMON_LIBRARY_NAME
"][%li] %s(%s) ignored :: null function pointer\n",
get_thread_index(), _name, join(", ", _args...).c_str());
}
using return_type = decltype(std::invoke(std::forward<FuncT>(_func), _args...));
if constexpr(!std::is_void<return_type>::value) return return_type();
}
} // namespace
} // namespace common
} // namespace omnitrace
@@ -0,0 +1,55 @@
// 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.
#pragma once
#include <sstream>
#include <string>
#if !defined(OMNITRACE_FOLD_EXPRESSION)
# define OMNITRACE_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
#endif
namespace omnitrace
{
inline namespace common
{
namespace
{
template <typename DelimT, typename... Args>
auto
join(DelimT&& _delim, Args&&... _args)
{
std::stringstream _ss{};
OMNITRACE_FOLD_EXPRESSION(_ss << _delim << _args);
if constexpr(std::is_same<DelimT, char>::value)
{
return _ss.str().substr(1);
}
else
{
return _ss.str().substr(std::string{ _delim }.length());
}
}
} // namespace
} // namespace common
} // namespace omnitrace
@@ -0,0 +1,55 @@
# ------------------------------------------------------------------------------#
#
# omnitrace dl library
#
# ------------------------------------------------------------------------------#
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_SKIP_RPATH OFF)
set(BUILD_RPATH_USE_ORIGIN ON)
add_library(omnitrace-dl-library SHARED)
add_library(omnitrace::omnitrace-dl-library ALIAS omnitrace-dl-library)
target_sources(omnitrace-dl-library PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/dl.cpp)
target_link_libraries(omnitrace-dl-library PRIVATE ${dl_LIBRARY}
omnitrace::common-library)
check_cxx_compiler_flag("-fno-exceptions" omnitrace_dl_library_fno_exceptions)
check_cxx_compiler_flag("-ftls-model=local-dynamic"
omnitrace_dl_library_ftls_module_local_dynamic)
if(OMNITRACE_BUILD_DEVELOPER)
if(omnitrace_dl_library_fno_exceptions)
target_compile_options(omnitrace-dl-library PRIVATE -fno-exceptions)
endif()
if(omnitrace_dl_library_ftls_module_local_dynamic)
target_compile_options(omnitrace-dl-library PRIVATE -ftls-model=local-dynamic)
endif()
endif()
omnitrace_target_compile_definitions(
omnitrace-dl-library PRIVATE OMNITRACE_USE_OMPT=$<BOOL:${OMNITRACE_USE_OMPT}>)
set_target_properties(
omnitrace-dl-library
PROPERTIES OUTPUT_NAME omnitrace-dl
CXX_VISIBILITY_PRESET "protected"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH "\$ORIGIN"
INSTALL_RPATH "\$ORIGIN")
install(
TARGETS omnitrace-dl-library
EXPORT omnitrace-dl-library-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
install(
EXPORT omnitrace-dl-library-targets
FILE omnitrace-dl-library-targets.cmake
NAMESPACE omnitrace::
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/omnitrace)
@@ -22,6 +22,15 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#define OMNITRACE_COMMON_LIBRARY_NAME "dl"
#include "common/defines.h"
#include "common/delimit.hpp"
#include "common/environment.hpp"
#include "common/invoke.hpp"
#include "common/join.hpp"
#include <atomic>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -38,15 +47,15 @@
#include <sys/stat.h>
#include <unistd.h>
#define OMNITRACE_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
#define OMNITRACE_VISIBLE __attribute__((visibility("default")))
#define OMNITRACE_HIDDEN __attribute__((visibility("internal")))
#define OMNITRACE_INLINE __attribute__((__always_inline__))
#if !defined(OMNITRACE_USE_OMPT)
# define OMNITRACE_USE_OMPT 0
#endif
#define OMNITRACE_DLSYM(VARNAME, HANDLE, FUNCNAME) \
if(HANDLE) \
{ \
*(void**) (&VARNAME) = dlsym(HANDLE, FUNCNAME); \
if(VARNAME == nullptr && _omnitrace_dl_verbose >= 0) \
if(VARNAME == nullptr && _omnitrace_dl_verbose >= _warn_verbose) \
{ \
fprintf(stderr, "[omnitrace][dl][pid=%i]> %s :: %s\n", getpid(), FUNCNAME, \
dlerror()); \
@@ -61,50 +70,45 @@
extern "C"
{
void omnitrace_init_library(void) OMNITRACE_VISIBLE;
void omnitrace_init(const char*, bool, const char*) OMNITRACE_VISIBLE;
void omnitrace_finalize(void) OMNITRACE_VISIBLE;
void omnitrace_set_env(const char* env_name, const char* env_val) OMNITRACE_VISIBLE;
void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_VISIBLE;
void omnitrace_push_trace(const char* name) OMNITRACE_VISIBLE;
void omnitrace_pop_trace(const char* name) OMNITRACE_VISIBLE;
struct ompt_start_tool_result_t;
void omnitrace_init_library(void) OMNITRACE_PUBLIC_API;
void omnitrace_init(const char*, bool, const char*) OMNITRACE_PUBLIC_API;
void omnitrace_finalize(void) OMNITRACE_PUBLIC_API;
void omnitrace_set_env(const char* env_name,
const char* env_val) OMNITRACE_PUBLIC_API;
void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_PUBLIC_API;
void omnitrace_push_trace(const char* name) OMNITRACE_PUBLIC_API;
void omnitrace_pop_trace(const char* name) OMNITRACE_PUBLIC_API;
void omnitrace_user_start_trace_dl(void) OMNITRACE_HIDDEN_API;
void omnitrace_user_stop_trace_dl(void) OMNITRACE_HIDDEN_API;
void omnitrace_user_start_thread_trace_dl(void) OMNITRACE_HIDDEN_API;
void omnitrace_user_stop_thread_trace_dl(void) OMNITRACE_HIDDEN_API;
void omnitrace_user_push_region_dl(const char*) OMNITRACE_HIDDEN_API;
void omnitrace_user_pop_region_dl(const char*) OMNITRACE_HIDDEN_API;
ompt_start_tool_result_t* ompt_start_tool(unsigned int,
const char*) OMNITRACE_PUBLIC_API;
}
//--------------------------------------------------------------------------------------//
inline namespace omnitrace
namespace omnitrace
{
inline namespace dl
{
namespace
{
inline int
get_omnitrace_env();
bool
get_env(const char* env_id, bool _default);
std::string
get_env(const char* env_id, const char* _default);
int
get_env(const char* env_id, int _default);
template <typename DelimT, typename... Args>
auto
join(DelimT&& _delim, Args&&... _args)
get_omnitrace_env()
{
std::stringstream _ss{};
OMNITRACE_FOLD_EXPRESSION(_ss << _delim << _args);
if constexpr(std::is_same<DelimT, char>::value)
{
return _ss.str().substr(1);
}
else
{
return _ss.str().substr(std::string{ _delim }.length());
}
auto&& _debug = get_env("OMNITRACE_DEBUG", false);
return get_env("OMNITRACE_VERBOSE", (_debug) ? 100 : 0);
}
// environment priority:
// - OMNITRACE_DL_DEBUG
// - OMNITRACE_DL_VERBOSE
@@ -114,10 +118,6 @@ int _omnitrace_dl_verbose = get_env("OMNITRACE_DL_DEBUG", false)
? 100
: get_env("OMNITRACE_DL_VERBOSE", get_omnitrace_env());
template <typename ContainerT = std::vector<std::string>>
inline ContainerT
delimit(const std::string& line, const char* delimiters = "\"',;: ");
// The docs for dlopen suggest that the combination of RTLD_LOCAL + RTLD_DEEPBIND
// (when available) helps ensure that the symbols in the instrumentation library
// libomnitrace.so will use it's own symbols... not symbols that are potentially
@@ -162,39 +162,38 @@ const char* _omnitrace_dl_dlopen_descr = "RTLD_LAZY | RTLD_LOCAL";
#endif
/// This class contains function pointers for omnitrace's instrumentation functions
struct OMNITRACE_HIDDEN indirect
struct OMNITRACE_HIDDEN_API indirect
{
explicit OMNITRACE_INLINE indirect(std::string libpath)
: m_libpath{ find_path(std::move(libpath)) }
OMNITRACE_INLINE indirect(std::string omnilib, std::string userlib)
: m_omnilib{ find_path(std::move(omnilib)) }
, m_userlib{ find_path(std::move(userlib)) }
{
if(_omnitrace_dl_verbose > 0)
{
fprintf(stderr, "[omnitrace][dl][pid=%i] libomnitrace.so resolved to '%s'\n",
getpid(), m_libpath.c_str());
getpid(), m_omnilib.c_str());
}
auto _omni_hsa_lib = m_libpath;
auto _omni_hsa_lib = m_omnilib;
const char* _hsa_lib = getenv("HSA_TOOLS_LIB");
if(_hsa_lib) _omni_hsa_lib.append(":").append(_hsa_lib);
setenv("HSA_TOOLS_LIB", _omni_hsa_lib.c_str(), 1);
open();
m_omnihandle = open(m_omnilib);
m_userhandle = open(m_userlib);
init();
}
OMNITRACE_INLINE ~indirect() { dlclose(m_libhandle); }
OMNITRACE_INLINE ~indirect() { dlclose(m_omnihandle); }
OMNITRACE_INLINE void open()
static OMNITRACE_INLINE void* open(const std::string& _lib)
{
if(m_libhandle) return;
auto* libhandle = dlopen(m_libpath.c_str(), _omnitrace_dl_dlopen_flags);
auto* libhandle = dlopen(_lib.c_str(), _omnitrace_dl_dlopen_flags);
if(libhandle)
{
m_libhandle = libhandle;
if(_omnitrace_dl_verbose > 0)
{
fprintf(stderr, "[omnitrace][dl][pid=%i] dlopen(%s, %s) :: success\n",
getpid(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr);
getpid(), _lib.c_str(), _omnitrace_dl_dlopen_descr);
}
}
else
@@ -203,26 +202,48 @@ struct OMNITRACE_HIDDEN indirect
{
perror("dlopen");
fprintf(stderr, "[omnitrace][dl][pid=%i] dlopen(%s, %s) :: %s\n",
getpid(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr,
dlerror());
getpid(), _lib.c_str(), _omnitrace_dl_dlopen_descr, dlerror());
}
}
dlerror(); // Clear any existing error
return libhandle;
}
OMNITRACE_INLINE void init()
{
if(!m_libhandle) open();
if(!m_omnihandle) m_omnihandle = open(m_omnilib);
int _warn_verbose = 0;
// Initialize all pointers
OMNITRACE_DLSYM(omnitrace_init_library_f, m_libhandle, "omnitrace_init_library");
OMNITRACE_DLSYM(omnitrace_init_f, m_libhandle, "omnitrace_init");
OMNITRACE_DLSYM(omnitrace_finalize_f, m_libhandle, "omnitrace_finalize");
OMNITRACE_DLSYM(omnitrace_set_env_f, m_libhandle, "omnitrace_set_env");
OMNITRACE_DLSYM(omnitrace_set_mpi_f, m_libhandle, "omnitrace_set_mpi");
OMNITRACE_DLSYM(omnitrace_push_trace_f, m_libhandle, "omnitrace_push_trace");
OMNITRACE_DLSYM(omnitrace_pop_trace_f, m_libhandle, "omnitrace_pop_trace");
OMNITRACE_DLSYM(omnitrace_init_library_f, m_omnihandle, "omnitrace_init_library");
OMNITRACE_DLSYM(omnitrace_init_f, m_omnihandle, "omnitrace_init");
OMNITRACE_DLSYM(omnitrace_finalize_f, m_omnihandle, "omnitrace_finalize");
OMNITRACE_DLSYM(omnitrace_set_env_f, m_omnihandle, "omnitrace_set_env");
OMNITRACE_DLSYM(omnitrace_set_mpi_f, m_omnihandle, "omnitrace_set_mpi");
OMNITRACE_DLSYM(omnitrace_push_trace_f, m_omnihandle, "omnitrace_push_trace");
OMNITRACE_DLSYM(omnitrace_pop_trace_f, m_omnihandle, "omnitrace_pop_trace");
OMNITRACE_DLSYM(omnitrace_push_region_f, m_omnihandle, "omnitrace_push_region");
OMNITRACE_DLSYM(omnitrace_pop_region_f, m_omnihandle, "omnitrace_pop_region");
#if OMNITRACE_USE_OMPT == 0
_warn_verbose = 5;
#endif
OMNITRACE_DLSYM(ompt_start_tool_f, m_omnihandle, "ompt_start_tool");
if(!m_userhandle) m_userhandle = open(m_userlib);
_warn_verbose = 0;
OMNITRACE_DLSYM(omnitrace_user_configure_f, m_userhandle,
"omnitrace_user_configure");
if(omnitrace_user_configure_f)
{
(*omnitrace_user_configure_f)(
&omnitrace_user_start_trace_dl, &omnitrace_user_stop_trace_dl,
&omnitrace_user_start_thread_trace_dl,
&omnitrace_user_stop_thread_trace_dl, &omnitrace_user_push_region_dl,
&omnitrace_user_pop_region_dl);
}
}
static OMNITRACE_INLINE std::string find_path(std::string&& _path)
@@ -246,196 +267,170 @@ struct OMNITRACE_HIDDEN indirect
}
public:
void (*omnitrace_init_library_f)(void) = nullptr;
void (*omnitrace_init_f)(const char*, bool, const char*) = nullptr;
void (*omnitrace_finalize_f)(void) = nullptr;
void (*omnitrace_set_env_f)(const char*, const char*) = nullptr;
void (*omnitrace_set_mpi_f)(bool, bool) = nullptr;
void (*omnitrace_push_trace_f)(const char*) = nullptr;
void (*omnitrace_pop_trace_f)(const char*) = nullptr;
void (*omnitrace_init_library_f)(void) = nullptr;
void (*omnitrace_init_f)(const char*, bool, const char*) = nullptr;
void (*omnitrace_finalize_f)(void) = nullptr;
void (*omnitrace_set_env_f)(const char*, const char*) = nullptr;
void (*omnitrace_set_mpi_f)(bool, bool) = nullptr;
void (*omnitrace_push_trace_f)(const char*) = nullptr;
void (*omnitrace_pop_trace_f)(const char*) = nullptr;
void (*omnitrace_push_region_f)(const char*) = nullptr;
void (*omnitrace_pop_region_f)(const char*) = nullptr;
void (*omnitrace_user_configure_f)(void (*)(void), void (*)(void), void (*)(void),
void (*)(void), void (*)(const char*),
void (*)(const char*)) = nullptr;
ompt_start_tool_result_t* (*ompt_start_tool_f)(unsigned int, const char*);
private:
void* m_libhandle = nullptr;
std::string m_libpath = {};
void* m_omnihandle = nullptr;
void* m_userhandle = nullptr;
std::string m_omnilib = {};
std::string m_userlib = {};
};
inline indirect&
get_indirect() OMNITRACE_HIDDEN;
get_indirect() OMNITRACE_HIDDEN_API;
template <typename FuncT, typename... Args>
inline void
invoke(const char* _name, FuncT&& _func, Args... _args) OMNITRACE_HIDDEN;
indirect&
get_indirect()
{
static auto _v =
indirect{ get_env("OMNITRACE_LIBRARY", "libomnitrace.so"),
get_env("OMNITRACE_USER_LIBRARY", "libomnitrace-user.so") };
return _v;
}
auto&
get_active()
{
static bool _v = false;
return _v;
}
auto&
get_enabled()
{
static std::atomic<bool> _v{ get_env("OMNITRACE_INIT_ENABLED", true) };
return _v;
}
auto&
get_thread_enabled()
{
static thread_local bool _v = get_enabled();
return _v;
}
auto&
get_count()
{
static std::atomic<int64_t> _v{ 0 };
return _v;
}
auto&
get_thread_count()
{
static thread_local int64_t _v = 0;
return _v;
}
} // namespace
} // namespace dl
} // namespace omnitrace
//--------------------------------------------------------------------------------------//
#define OMNITRACE_DL_INVOKE(...) \
::omnitrace::common::invoke(__FUNCTION__, ::omnitrace::dl::_omnitrace_dl_verbose, \
__VA_ARGS__)
using omnitrace::get_indirect;
namespace dl = omnitrace::dl;
extern "C"
{
void omnitrace_init_library(void)
{
invoke(__FUNCTION__, get_indirect().omnitrace_init_library_f);
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_init_library_f);
}
void omnitrace_init(const char* a, bool b, const char* c)
{
invoke(__FUNCTION__, get_indirect().omnitrace_init_f, a, b, c);
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_init_f, a, b, c);
dl::get_active() = true;
}
void omnitrace_finalize(void)
{
invoke(__FUNCTION__, get_indirect().omnitrace_finalize_f);
dl::get_active() = false;
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_finalize_f);
}
void omnitrace_push_trace(const char* name)
{
invoke(__FUNCTION__, get_indirect().omnitrace_push_trace_f, name);
if(!dl::get_active()) return;
if(dl::get_thread_enabled())
{
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_trace_f, name);
}
else
{
++dl::get_thread_count();
}
}
void omnitrace_pop_trace(const char* name)
{
invoke(__FUNCTION__, get_indirect().omnitrace_pop_trace_f, name);
if(!dl::get_active()) return;
if(dl::get_thread_enabled())
{
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_trace_f, name);
}
else
{
if(dl::get_thread_count()-- == 0) omnitrace_user_start_thread_trace_dl();
}
}
void omnitrace_set_env(const char* a, const char* b)
{
setenv(a, b, 0);
invoke(__FUNCTION__, get_indirect().omnitrace_set_env_f, a, b);
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_set_env_f, a, b);
}
void omnitrace_set_mpi(bool a, bool b)
{
invoke(__FUNCTION__, get_indirect().omnitrace_set_mpi_f, a, b);
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_set_mpi_f, a, b);
}
}
//--------------------------------------------------------------------------------------//
void omnitrace_user_start_trace_dl(void) { dl::get_enabled().store(true); }
void omnitrace_user_stop_trace_dl(void) { dl::get_enabled().store(false); }
void omnitrace_user_start_thread_trace_dl(void) { dl::get_thread_enabled() = true; }
void omnitrace_user_stop_thread_trace_dl(void) { dl::get_thread_enabled() = false; }
inline namespace omnitrace
{
inline namespace dl
{
namespace
{
template <typename ContainerT>
inline ContainerT
delimit(const std::string& line, const char* delimiters)
{
ContainerT _result{};
size_t _beginp = 0; // position that is the beginning of the new string
size_t _delimp = 0; // position of the delimiter in the string
while(_beginp < line.length() && _delimp < line.length())
void omnitrace_user_push_region_dl(const char* name)
{
// find the first character (starting at _delimp) that is not a delimiter
_beginp = line.find_first_not_of(delimiters, _delimp);
// if no a character after or at _end that is not a delimiter is not found
// then we are done
if(_beginp == std::string::npos) break;
// starting at the position of the new string, find the next delimiter
_delimp = line.find_first_of(delimiters, _beginp);
std::string _tmp{};
// starting at the position of the new string, get the characters
// between this position and the next delimiter
_tmp = line.substr(_beginp, _delimp - _beginp);
// don't add empty strings
if(!_tmp.empty()) _result.emplace(_result.end(), _tmp);
if(!dl::get_active()) return;
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_region_f, name);
}
return _result;
}
std::string
get_env(const char* env_id, const char* _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var) return std::string{ env_var };
return _default;
}
int
get_env(const char* env_id, int _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var) return std::stoi(env_var);
return _default;
}
bool
get_env(const char* env_id, bool _default)
{
if(strlen(env_id) == 0) return _default;
char* env_var = ::std::getenv(env_id);
if(env_var)
void omnitrace_user_pop_region_dl(const char* name)
{
if(std::string{ env_var }.find_first_not_of("0123456789") == std::string::npos)
return static_cast<bool>(std::stoi(env_var));
else
{
for(size_t i = 0; i < strlen(env_var); ++i)
env_var[i] = tolower(env_var[i]);
for(const auto& itr : { "off", "false", "no", "n", "f", "0" })
if(strcmp(env_var, itr) == 0) return false;
}
return true;
if(!dl::get_active()) return;
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_region_f, name);
}
return _default;
}
int
get_omnitrace_env()
{
auto&& _debug = get_env("OMNITRACE_DEBUG", false);
return get_env("OMNITRACE_VERBOSE", (_debug) ? 100 : 0);
}
indirect&
get_indirect()
{
static auto _v = indirect{ get_env("OMNITRACE_LIBRARY", "libomnitrace.so") };
return _v;
}
int32_t&
get_guard()
{
static thread_local int32_t _v = 0;
return _v;
}
template <typename FuncT, typename... Args>
void
invoke(const char* _name, FuncT&& _func, Args... _args)
{
if(_func)
ompt_start_tool_result_t* ompt_start_tool(unsigned int omp_version,
const char* runtime_version)
{
// if _lk is ever greater than zero on the same thread, this
// means a function within the current function is calling
// our instrumentation so we ignore the call
int32_t _lk = get_guard()++;
if(_lk == 0)
{
std::invoke(std::forward<FuncT>(_func), _args...);
}
else if(_omnitrace_dl_verbose > 2)
{
fflush(stderr);
fprintf(stderr, "[omnitrace][dl] call to %s was guarded :: value = %i\n",
_name, _lk);
fflush(stderr);
}
// decrement the guard as it exits the scope
--get_guard();
}
else if(_omnitrace_dl_verbose >= 0)
{
fprintf(stderr, "[omnitrace][dl] %s\n",
join("", "null function pointer to ", _name, ". Ignoring ", _name, "(",
_args..., ")")
.c_str());
#if OMNITRACE_USE_OMPT == 0
(void) omp_version;
(void) runtime_version;
return nullptr;
#else
if(!omnitrace::common::get_env("OMNITRACE_USE_OMPT", true)) return nullptr;
return OMNITRACE_DL_INVOKE(get_indirect().ompt_start_tool_f, omp_version,
runtime_version);
#endif
}
}
} // namespace
} // namespace dl
} // namespace omnitrace
@@ -0,0 +1,61 @@
# ------------------------------------------------------------------------------#
#
# omnitrace user library
#
# ------------------------------------------------------------------------------#
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_SKIP_RPATH OFF)
set(BUILD_RPATH_USE_ORIGIN ON)
set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
add_library(omnitrace-user-library SHARED)
add_library(omnitrace::omnitrace-user-library ALIAS omnitrace-user-library)
target_sources(
omnitrace-user-library PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/user.cpp
${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/user.h)
target_include_directories(
omnitrace-user-library PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
check_cxx_compiler_flag("-fno-exceptions" omnitrace_user_library_fno_exceptions)
check_cxx_compiler_flag("-ftls-model=local-dynamic"
omnitrace_user_library_ftls_module_local_dynamic)
if(OMNITRACE_BUILD_DEVELOPER)
if(omnitrace_user_library_fno_exceptions)
target_compile_options(omnitrace-user-library PRIVATE -fno-exceptions)
endif()
if(omnitrace_user_library_ftls_module_local_dynamic)
target_compile_options(omnitrace-user-library PRIVATE -ftls-model=local-dynamic)
endif()
endif()
set_target_properties(
omnitrace-user-library
PROPERTIES OUTPUT_NAME omnitrace-user
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH "\$ORIGIN"
INSTALL_RPATH "\$ORIGIN")
install(
TARGETS omnitrace-user-library
EXPORT omnitrace-user-library-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
install(
FILES ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/user.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/omnitrace
OPTIONAL)
install(
EXPORT omnitrace-user-library-targets
FILE omnitrace-user-library-targets.cmake
NAMESPACE omnitrace::
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/omnitrace)
@@ -0,0 +1,50 @@
// 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.
#ifndef OMNITRACE_USER_H_
#define OMNITRACE_USER_H_ 1
#define OMNITRACE_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#define OMNITRACE_VISIBILITY(MODE) OMNITRACE_ATTRIBUTE(visibility(MODE))
#define OMNITRACE_PUBLIC_API OMNITRACE_VISIBILITY("default")
#define OMNITRACE_HIDDEN_API OMNITRACE_VISIBILITY("hidden")
#if defined(__cplusplus)
extern "C"
{
#endif
extern void omnitrace_user_start_trace(void) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_stop_trace(void) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_start_thread_trace(void) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_stop_thread_trace(void) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_push_region(const char*) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_pop_region(const char*) OMNITRACE_PUBLIC_API;
extern void omnitrace_user_configure(void (*)(void), void (*)(void), void (*)(void),
void (*)(void), void (*)(const char*),
void (*)(const char*)) OMNITRACE_PUBLIC_API;
#if defined(__cplusplus)
}
#endif
#endif // OMNITRACE_USER_H_
@@ -0,0 +1,84 @@
// 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.
#define OMNITRACE_SOURCE 1
#include "omnitrace/user.h"
#include <cstdio>
namespace
{
using void_func_t = void (*)(void);
using region_func_t = void (*)(const char*);
void_func_t _start_trace = nullptr;
void_func_t _stop_trace = nullptr;
void_func_t _start_thread_trace = nullptr;
void_func_t _stop_thread_trace = nullptr;
region_func_t _push_region = nullptr;
region_func_t _pop_region = nullptr;
} // namespace
extern "C"
{
void omnitrace_user_start_trace(void)
{
if(_start_trace) (*_start_trace)();
}
void omnitrace_user_stop_trace(void)
{
if(_stop_trace) (*_stop_trace)();
}
void omnitrace_user_start_thread_trace(void)
{
if(_start_thread_trace) (*_start_thread_trace)();
}
void omnitrace_user_stop_thread_trace(void)
{
if(_stop_thread_trace) (*_stop_thread_trace)();
}
void omnitrace_user_push_region(const char* name)
{
if(_push_region) (*_push_region)(name);
}
void omnitrace_user_pop_region(const char* name)
{
if(_pop_region) (*_pop_region)(name);
}
void omnitrace_user_configure(void (*_a)(), void (*_b)(), void (*_c)(), void (*_d)(),
void (*_e)(const char*), void (*_f)(const char*))
{
_start_trace = _a;
_stop_trace = _b;
_start_thread_trace = _c;
_stop_thread_trace = _d;
_push_region = _e;
_pop_region = _f;
}
}
@@ -0,0 +1,145 @@
# ------------------------------------------------------------------------------#
#
# omnitrace interface library
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-interface-library INTERFACE)
add_library(omnitrace::omnitrace-interface-library ALIAS omnitrace-interface-library)
target_include_directories(
omnitrace-interface-library INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/include)
target_include_directories(omnitrace-interface-library SYSTEM
INTERFACE ${perfetto_DIR}/sdk)
target_compile_definitions(
omnitrace-interface-library
INTERFACE OMNITRACE_MAX_THREADS=${OMNITRACE_MAX_THREADS}
$<IF:$<BOOL:${OMNITRACE_CUSTOM_DATA_SOURCE}>,CUSTOM_DATA_SOURCE,>)
target_link_libraries(
omnitrace-interface-library
INTERFACE $<BUILD_INTERFACE:omnitrace::omnitrace-headers>
$<BUILD_INTERFACE:omnitrace::omnitrace-threading>
$<BUILD_INTERFACE:omnitrace::omnitrace-compile-options>
$<BUILD_INTERFACE:omnitrace::omnitrace-hip>
$<BUILD_INTERFACE:omnitrace::omnitrace-roctracer>
$<BUILD_INTERFACE:omnitrace::omnitrace-rocm-smi>
$<BUILD_INTERFACE:omnitrace::omnitrace-mpi>
$<BUILD_INTERFACE:omnitrace::omnitrace-ptl>
$<BUILD_INTERFACE:timemory::timemory-headers>
$<BUILD_INTERFACE:timemory::timemory-gotcha>
$<BUILD_INTERFACE:timemory::timemory-cxx-static>
$<IF:$<BOOL:${OMNITRACE_USE_SANITIZER}>,omnitrace::omnitrace-sanitizer,>)
# ------------------------------------------------------------------------------#
#
# omnitrace object library
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-object-library OBJECT)
add_library(omnitrace::omnitrace-object-library ALIAS omnitrace-object-library)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/library/defines.hpp.in
${CMAKE_CURRENT_BINARY_DIR}/include/library/defines.hpp @ONLY)
set(library_sources
${CMAKE_CURRENT_LIST_DIR}/src/library.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/api.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/config.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/cpu_freq.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/critical_trace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/kokkosp.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/gpu.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/ompt.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/perfetto.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/ptl.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/sampling.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/state.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/thread_data.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/thread_sampler.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/timemory.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/backtrace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/fork_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/mpi_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/omnitrace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/pthread_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/user_region.cpp
${perfetto_DIR}/sdk/perfetto.cc)
set(library_headers
${CMAKE_CURRENT_LIST_DIR}/include/library.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/api.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/config.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/common.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/cpu_freq.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/critical_trace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/debug.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/gpu.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/ompt.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/perfetto.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/ptl.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/sampling.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/state.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/thread_data.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/thread_sampler.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/timemory.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/fwd.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/backtrace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/fork_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/functors.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/mpi_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/omnitrace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/rocm_smi.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/roctracer.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/roctracer_callbacks.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/pthread_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/components/user_region.hpp
${perfetto_DIR}/sdk/perfetto.h)
target_sources(omnitrace-object-library PRIVATE ${library_sources} ${library_headers})
if(OMNITRACE_USE_ROCTRACER)
target_sources(
omnitrace-object-library
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/library/components/roctracer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/components/roctracer_callbacks.cpp)
endif()
if(OMNITRACE_USE_ROCM_SMI)
target_sources(omnitrace-object-library
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/library/components/rocm_smi.cpp)
endif()
target_link_libraries(omnitrace-object-library PRIVATE omnitrace-interface-library)
if(OMNITRACE_DYNINST_API_RT)
get_filename_component(OMNITRACE_DYNINST_API_RT_DIR "${OMNITRACE_DYNINST_API_RT}"
DIRECTORY)
endif()
# ------------------------------------------------------------------------------#
#
# omnitrace shared library
#
# ------------------------------------------------------------------------------#
add_library(omnitrace-library SHARED $<TARGET_OBJECTS:omnitrace-object-library>)
add_library(omnitrace::omnitrace-library ALIAS omnitrace-library)
target_link_libraries(omnitrace-library PRIVATE omnitrace-interface-library)
set_target_properties(
omnitrace-library
PROPERTIES OUTPUT_NAME omnitrace
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
INSTALL_RPATH
"\$ORIGIN:\$ORIGIN/timemory/libunwind:\$ORIGIN/dyninst-tpls/libs")
install(
TARGETS omnitrace-library
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
@@ -51,6 +51,12 @@ extern "C"
/// stops an instrumentation region
void omnitrace_pop_trace(const char* name) OMNITRACE_PUBLIC_API;
/// starts an instrumentation region (user-defined)
void omnitrace_push_region(const char* name) OMNITRACE_PUBLIC_API;
/// stops an instrumentation region (user-defined)
void omnitrace_pop_region(const char* name) OMNITRACE_PUBLIC_API;
// these are the real implementations for internal calling convention
void omnitrace_init_library_hidden(void) OMNITRACE_HIDDEN_API;
void omnitrace_init_hidden(const char*, bool, const char*) OMNITRACE_HIDDEN_API;
@@ -60,4 +66,6 @@ extern "C"
void omnitrace_set_mpi_hidden(bool use, bool attached) OMNITRACE_HIDDEN_API;
void omnitrace_push_trace_hidden(const char* name) OMNITRACE_HIDDEN_API;
void omnitrace_pop_trace_hidden(const char* name) OMNITRACE_HIDDEN_API;
void omnitrace_push_region_hidden(const char* name) OMNITRACE_HIDDEN_API;
void omnitrace_pop_region_hidden(const char* name) OMNITRACE_HIDDEN_API;
}
@@ -68,6 +68,7 @@ using functor_t = std::function<void(Tp...)>;
using default_functor_t = functor_t<const char*>;
struct omnitrace;
struct user_region;
struct backtrace;
struct backtrace_wall_clock
{};
@@ -126,6 +127,8 @@ TIMEMORY_DEFINE_CONCRETE_TRAIT(is_available, omnitrace::component::sampling_gpu_
TIMEMORY_SET_COMPONENT_API(omnitrace::component::omnitrace, project::omnitrace,
category::dynamic_instrumentation, os::supports_linux)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::user_region, project::omnitrace,
os::supports_linux)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::roctracer, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux,
category::external)
@@ -154,6 +157,8 @@ TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_temp, project::omn
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::omnitrace, OMNITRACE_COMPONENT,
"omnitrace", "omnitrace_component")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::user_region, OMNITRACE_USER_REGION,
"user_region", "omnitrace_user_region")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::roctracer, OMNITRACE_ROCTRACER,
"roctracer", "omnitrace_roctracer")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_wall_clock,
@@ -173,6 +178,15 @@ TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_power,
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_temp,
OMNITRACE_SAMPLING_GPU_TEMP, "sampling_gpu_temp", "")
TIMEMORY_METADATA_SPECIALIZATION(
omnitrace::component::omnitrace, "omnitrace",
"Invokes instrumentation functions 'omnitrace_push_trace' and 'omnitrace_pop_trace'",
"Used by gotcha wrappers")
TIMEMORY_METADATA_SPECIALIZATION(
omnitrace::component::user_region, "user_region",
"Invokes instrumentation functions 'omnitrace_user_push_region' and "
"'omnitrace_user_pop_region'",
"Used by OMPT")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::roctracer, "roctracer",
"High-precision ROCm API and kernel tracing", "")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_wall_clock,
@@ -43,8 +43,3 @@ private:
};
} // namespace component
} // namespace omnitrace
TIMEMORY_METADATA_SPECIALIZATION(
omnitrace::component::omnitrace, "omnitrace",
"Invokes instrumentation functions 'omnitrace_push_trace' and 'omnitrace_pop_trace'",
"Used by gotcha wrappers")
@@ -0,0 +1,56 @@
// 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.
#pragma once
#include "library/defines.hpp"
#include "library/timemory.hpp"
namespace omnitrace
{
namespace component
{
// timemory component which calls omnitrace functions
// (used in gotcha wrappers)
struct user_region : comp::base<user_region, void>
{
static std::string label() { return "user_region"; }
void start();
void stop();
void set_prefix(const char*);
private:
const char* m_prefix = nullptr;
};
} // namespace component
} // namespace omnitrace
TIMEMORY_COMPONENT_ALIAS(omnitrace_user_region, omnitrace::component::user_region)
#if !defined(OMNITRACE_EXTERN_COMPONENTS) || \
(defined(OMNITRACE_EXTERN_COMPONENTS) && OMNITRACE_EXTERN_COMPONENTS > 0)
# include <timemory/operations.hpp>
TIMEMORY_DECLARE_EXTERN_COMPONENT(omnitrace_user_region, false, void)
#endif
@@ -171,6 +171,9 @@ get_use_critical_trace();
bool
get_use_kokkosp();
bool
get_use_ompt();
bool
get_timeline_sampling();
@@ -245,6 +248,9 @@ get_critical_trace_per_row();
State&
get_state();
/// returns old state
State set_state(State);
std::unique_ptr<main_bundle_t>&
get_main_bundle();
@@ -30,6 +30,9 @@
#include <timemory/utility/utility.hpp>
#include <cstdio>
#include <cstring>
#include <string_view>
#include <utility>
namespace omnitrace
{
@@ -47,8 +50,32 @@ get_debug_pid();
bool
get_critical_trace_debug();
} // namespace config
namespace debug
{
namespace
{
template <typename T, size_t... Idx>
auto get_chars(std::index_sequence<Idx...>)
{
static const char _v[sizeof...(Idx) + 1] = { T::get()[Idx]..., '\0' };
return _v;
}
template <typename T>
auto
get_chars()
{
return get_chars<T>(typename T::sequence{});
}
} // namespace
} // namespace debug
} // namespace omnitrace
#define OMNITRACE_VAR_NAME_COMBINE(X, Y) X##Y
#define OMNITRACE_LINESTR TIMEMORY_STRINGIZE(__LINE__)
#define OMNITRACE_VARIABLE(LABEL) OMNITRACE_VAR_NAME_COMBINE(_omni_var_, LABEL)
#if defined(TIMEMORY_USE_MPI)
# define OMNITRACE_PROCESS_IDENTIFIER static_cast<int>(::tim::dmp::rank())
#elif defined(TIMEMORY_USE_MPI_HEADERS)
@@ -59,6 +86,26 @@ get_critical_trace_debug();
# define OMNITRACE_PROCESS_IDENTIFIER static_cast<int>(::tim::process::get_id())
#endif
#define OMNITRACE_FUNCTION \
std::string{ __FUNCTION__ } \
.substr(0, std::string_view{ __FUNCTION__ }.find("_hidden")) \
.c_str()
#define OMNITRACE_CT_FUNCTION(VAR, STR) \
static constexpr auto OMNITRACE_VARIABLE(__LINE__) = std::string_view{ STR }; \
VAR = OMNITRACE_CT_FUNCTION_IMPL(OMNITRACE_VARIABLE(__LINE__));
#define OMNITRACE_CT_FUNCTION_IMPL(STR) \
[]() { \
struct wrapper \
{ \
static constexpr const char* get() { return STR.data(); } \
using sequence = \
std::make_index_sequence<std::min(STR.find("_hidden"), STR.length())>; \
}; \
return ::omnitrace::debug::get_chars<wrapper>(); \
}();
#define OMNITRACE_CONDITIONAL_PRINT(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
@@ -89,7 +136,7 @@ get_critical_trace_debug();
fflush(stderr); \
tim::auto_lock_t _lk{ tim::type_mutex<decltype(std::cerr)>() }; \
fprintf(stderr, "[omnitrace][%i][%li][%s] ", OMNITRACE_PROCESS_IDENTIFIER, \
tim::threading::get_id(), __FUNCTION__); \
tim::threading::get_id(), OMNITRACE_FUNCTION); \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
@@ -100,7 +147,7 @@ get_critical_trace_debug();
{ \
fflush(stderr); \
tim::auto_lock_t _lk{ tim::type_mutex<decltype(std::cerr)>() }; \
fprintf(stderr, "[omnitrace][%s] ", __FUNCTION__); \
fprintf(stderr, "[omnitrace][%s] ", OMNITRACE_FUNCTION); \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
@@ -110,7 +157,8 @@ get_critical_trace_debug();
{ \
char _msg_buffer[2048]; \
snprintf(_msg_buffer, 2048, "[omnitrace][%i][%li][%s] ", \
OMNITRACE_PROCESS_IDENTIFIER, tim::threading::get_id(), __FUNCTION__); \
OMNITRACE_PROCESS_IDENTIFIER, tim::threading::get_id(), \
OMNITRACE_FUNCTION); \
auto len = strlen(_msg_buffer); \
snprintf(_msg_buffer + len, 2048 - len, __VA_ARGS__); \
throw std::runtime_error(_msg_buffer); \
@@ -120,12 +168,20 @@ get_critical_trace_debug();
if(COND) \
{ \
char _msg_buffer[2048]; \
snprintf(_msg_buffer, 2048, "[omnitrace][%s] ", __FUNCTION__); \
snprintf(_msg_buffer, 2048, "[omnitrace][%s] ", OMNITRACE_FUNCTION); \
auto len = strlen(_msg_buffer); \
snprintf(_msg_buffer + len, 2048 - len, __VA_ARGS__); \
throw std::runtime_error(_msg_buffer); \
}
#define OMNITRACE_CI_THROW(COND, ...) \
OMNITRACE_CONDITIONAL_THROW(::omnitrace::get_is_continuous_integration() && (COND), \
__VA_ARGS__)
#define OMNITRACE_CI_BASIC_THROW(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_THROW( \
::omnitrace::get_is_continuous_integration() && (COND), __VA_ARGS__)
#define OMNITRACE_STRINGIZE(...) #__VA_ARGS__
#define OMNITRACE_ESC(...) __VA_ARGS__
@@ -36,12 +36,14 @@
// clang-format on
#define TIMEMORY_USER_COMPONENT_ENUM \
OMNITRACE_COMPONENT_idx, OMNITRACE_ROCTRACER_idx, OMNITRACE_SAMPLING_WALL_CLOCK_idx, \
OMNITRACE_SAMPLING_CPU_CLOCK_idx, OMNITRACE_SAMPLING_PERCENT_idx, \
OMNITRACE_SAMPLING_GPU_POWER_idx, OMNITRACE_SAMPLING_GPU_TEMP_idx, \
OMNITRACE_SAMPLING_GPU_BUSY_idx, OMNITRACE_SAMPLING_GPU_MEMORY_USAGE_idx,
OMNITRACE_COMPONENT_idx, OMNITRACE_USER_REGION_idx, OMNITRACE_ROCTRACER_idx, \
OMNITRACE_SAMPLING_WALL_CLOCK_idx, OMNITRACE_SAMPLING_CPU_CLOCK_idx, \
OMNITRACE_SAMPLING_PERCENT_idx, OMNITRACE_SAMPLING_GPU_POWER_idx, \
OMNITRACE_SAMPLING_GPU_TEMP_idx, OMNITRACE_SAMPLING_GPU_BUSY_idx, \
OMNITRACE_SAMPLING_GPU_MEMORY_USAGE_idx,
#define OMNITRACE_COMPONENT OMNITRACE_COMPONENT_idx
#define OMNITRACE_USER_REGION OMNITRACE_USER_REGION_idx
#define OMNITRACE_ROCTRACER OMNITRACE_ROCTRACER_idx
#define OMNITRACE_SAMPLING_WALL_CLOCK OMNITRACE_SAMPLING_WALL_CLOCK_idx
#define OMNITRACE_SAMPLING_CPU_CLOCK OMNITRACE_SAMPLING_CPU_CLOCK_idx
@@ -0,0 +1,35 @@
// 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.
#pragma once
namespace omnitrace
{
namespace ompt
{
void
setup();
void
shutdown();
} // namespace ompt
} // namespace omnitrace
@@ -33,6 +33,7 @@
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing"), \
perfetto::Category("user").SetDescription("User-defined regions"), \
perfetto::Category("rocm_smi").SetDescription("Device-level metrics"), \
perfetto::Category("sampling") \
.SetDescription("Metrics derived from sampling"), \
@@ -46,6 +47,7 @@
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing"), \
perfetto::Category("user").SetDescription("User-defined regions"), \
perfetto::Category("rocm_smi").SetDescription("Device-level metrics"), \
perfetto::Category("sampling") \
.SetDescription("Metrics derived from sampling"), \
@@ -32,6 +32,7 @@
#include "library/debug.hpp"
#include "library/defines.hpp"
#include "library/gpu.hpp"
#include "library/ompt.hpp"
#include "library/ptl.hpp"
#include "library/sampling.hpp"
#include "library/thread_data.hpp"
@@ -46,10 +47,22 @@ using namespace omnitrace;
//======================================================================================//
using library_functors = omnitrace::component::functors<omnitrace::api::omnitrace>;
namespace
{
struct omni_regions
{};
struct user_regions
{};
} // namespace
TIMEMORY_DEFINE_NAME_TRAIT("cpu_instrumentation", library_functors);
TIMEMORY_INVOKE_PREINIT(library_functors)
using omni_functors = omnitrace::component::functors<omni_regions>;
using user_functors = omnitrace::component::functors<user_regions>;
// TIMEMORY_DEFINE_NAME_TRAIT("host", omni_functors);
// TIMEMORY_DEFINE_NAME_TRAIT("user", user_functors);
TIMEMORY_INVOKE_PREINIT(omni_functors)
TIMEMORY_INVOKE_PREINIT(user_functors)
//======================================================================================//
@@ -159,6 +172,9 @@ pop_count()
}
auto _debug_push = tim::get_env("OMNITRACE_DEBUG_PUSH", false) && !get_debug_env();
auto _debug_pop = tim::get_env("OMNITRACE_DEBUG_POP", false) && !get_debug_env();
auto _debug_user =
tim::get_env("OMNITRACE_DEBUG_USER_REGIONS", false) && !get_debug_env();
} // namespace
//======================================================================================//
@@ -172,11 +188,11 @@ omnitrace_push_trace_hidden(const char* name)
if(get_state() == State::Finalized)
{
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug_push, "%s(%s) called during finalization\n", __FUNCTION__, name);
_debug_push, "omnitrace_push_trace(%s) called during finalization\n", name);
return;
}
OMNITRACE_CONDITIONAL_BASIC_PRINT(_debug_push, "%s(%s)\n", __FUNCTION__, name);
OMNITRACE_CONDITIONAL_BASIC_PRINT(_debug_push, "omnitrace_push_trace(%s)\n", name);
// the expectation here is that if the state is not active then the call
// to omnitrace_init_tooling_hidden will activate all the appropriate
@@ -184,12 +200,13 @@ omnitrace_push_trace_hidden(const char* name)
if(get_state() != State::Active && !omnitrace_init_tooling_hidden())
{
static auto _debug = get_debug_env() || get_debug_init();
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(_debug, "%s :: not active. state = %s\n",
name, std::to_string(get_state()).c_str());
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug, "omnitrace_push_trace(%s) ignored :: not active. state = %s\n", name,
std::to_string(get_state()).c_str());
return;
}
OMNITRACE_DEBUG_F("%s\n", name);
OMNITRACE_DEBUG("omnitrace_push_trace(%s)\n", name);
static auto _sample_rate = std::max<size_t>(get_instrumentation_interval(), 1);
static thread_local size_t _sample_idx = 0;
@@ -197,7 +214,7 @@ omnitrace_push_trace_hidden(const char* name)
auto _enabled = (_sample_idx++ % _sample_rate == 0);
_interval->emplace_back(_enabled);
if(_enabled) library_functors::start(name);
if(_enabled) omni_functors::start(name);
if(get_use_critical_trace())
{
uint64_t _cid = 0;
@@ -222,15 +239,17 @@ omnitrace_pop_trace_hidden(const char* name)
{
++pop_count();
OMNITRACE_CONDITIONAL_BASIC_PRINT(_debug_pop, "omnitrace_pop_trace(%s)\n", name);
// only execute when active
if(get_state() == State::Active)
{
OMNITRACE_DEBUG_F("%s\n", name);
OMNITRACE_DEBUG("omnitrace_pop_trace(%s)\n", name);
auto& _interval_data = get_interval_data();
if(!_interval_data->empty())
{
if(_interval_data->back()) library_functors::stop(name);
if(_interval_data->back()) omni_functors::stop(name);
_interval_data->pop_back();
}
@@ -255,9 +274,64 @@ omnitrace_pop_trace_hidden(const char* name)
else
{
static auto _debug = get_debug_env();
OMNITRACE_CONDITIONAL_BASIC_PRINT(_debug, "[%s] %s ignored :: state = %s\n",
__FUNCTION__, name,
std::to_string(get_state()).c_str());
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug, "omnitrace_pop_trace(%s) ignored :: state = %s\n", name,
std::to_string(get_state()).c_str());
}
}
//======================================================================================//
///
///
///
//======================================================================================//
extern "C" void
omnitrace_push_region_hidden(const char* name)
{
// unconditionally return if finalized
if(get_state() == State::Finalized)
{
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug_user, "omnitrace_push_region(%s) called during finalization\n", name);
return;
}
OMNITRACE_CONDITIONAL_BASIC_PRINT(_debug_push, "omnitrace_push_region(%s)\n", name);
// the expectation here is that if the state is not active then the call
// to omnitrace_init_tooling_hidden will activate all the appropriate
// tooling one time and as it exits set it to active and return true.
if(get_state() != State::Active && !omnitrace_init_tooling_hidden())
{
static auto _debug = get_debug_env() || get_debug_init();
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug, "omnitrace_push_region(%s) ignored :: not active. state = %s\n", name,
std::to_string(get_state()).c_str());
return;
}
OMNITRACE_DEBUG("omnitrace_push_region(%s)\n", name);
user_functors::start(name);
}
//======================================================================================//
extern "C" void
omnitrace_pop_region_hidden(const char* name)
{
// only execute when active
if(get_state() == State::Active)
{
OMNITRACE_DEBUG("omnitrace_pop_region(%s)\n", name);
user_functors::stop(name);
}
else
{
static auto _debug = get_debug_env();
OMNITRACE_CONDITIONAL_BASIC_PRINT(
_debug, "omnitrace_pop_region(%s) ignored :: state = %s\n", name,
std::to_string(get_state()).c_str());
}
}
@@ -271,7 +345,7 @@ extern "C" void
omnitrace_set_env_hidden(const char* env_name, const char* env_val)
{
// just search env to avoid initializing the settings
OMNITRACE_CONDITIONAL_PRINT(get_debug_env() || get_verbose_env() > 2,
OMNITRACE_CONDITIONAL_PRINT(get_debug_init() || get_verbose_env() > 2,
"[%s] Setting env: %s=%s\n", __FUNCTION__, env_name,
env_val);
@@ -279,9 +353,10 @@ omnitrace_set_env_hidden(const char* env_name, const char* env_val)
OMNITRACE_CONDITIONAL_THROW(
get_state() >= State::Init &&
(config::get_is_continuous_integration() || get_debug_env()),
"%s(\"%s\", \"%s\") called after omnitrace was initialized. state = %s",
__FUNCTION__, env_name, env_val, std::to_string(get_state()).c_str());
(config::get_is_continuous_integration() || get_debug_init()),
"omnitrace_set_env(\"%s\", \"%s\") called after omnitrace was initialized. state "
"= %s",
env_name, env_val, std::to_string(get_state()).c_str());
}
//======================================================================================//
@@ -300,7 +375,7 @@ extern "C" void
omnitrace_set_mpi_hidden(bool use, bool attached)
{
// just search env to avoid initializing the settings
OMNITRACE_CONDITIONAL_PRINT(get_debug_env() || get_verbose_env() > 2,
OMNITRACE_CONDITIONAL_PRINT(get_debug_init() || get_verbose_env() > 2,
"[%s] use: %s, attached: %s\n", __FUNCTION__,
(use) ? "y" : "n", (attached) ? "y" : "n");
@@ -319,9 +394,10 @@ omnitrace_set_mpi_hidden(bool use, bool attached)
OMNITRACE_CONDITIONAL_THROW(
get_state() >= State::Init &&
(config::get_is_continuous_integration() || get_debug_env()),
"%s(use=%s, attached=%s) called after omnitrace was initialized. state = %s",
__FUNCTION__, std::to_string(use).c_str(), std::to_string(attached).c_str(),
(config::get_is_continuous_integration() || get_debug_init()),
"omnitrace_set_mpi(use=%s, attached=%s) called after omnitrace was initialized. "
"state = %s",
std::to_string(use).c_str(), std::to_string(attached).c_str(),
std::to_string(get_state()).c_str());
_start_gotcha_callback();
@@ -335,23 +411,37 @@ omnitrace_init_library_hidden()
auto _tid = threading::get_id();
(void) _tid;
auto _mode = get_mode();
auto _debug_init = get_debug_init();
static bool _once = false;
auto _mode = get_mode();
auto _debug_init = get_debug_init();
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(_debug_init, "State is %s...\n",
std::to_string(get_state()).c_str());
OMNITRACE_CI_THROW(get_state() != State::PreInit, "State is not PreInit :: %s",
std::to_string(get_state()).c_str());
if(get_state() != State::PreInit || get_state() == State::Init || _once) return;
_once = true;
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(_debug_init, "State is %s. Setting to %s...\n",
std::to_string(get_state()).c_str(),
std::to_string(State::Init).c_str());
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(
_debug_init, "Calling backtrace once so that the one-time call of malloc in "
"glibc's backtrace() occurs...\n");
{
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(
_debug_init, "Calling backtrace once so that the one-time call of malloc in "
"glibc's backtrace() occurs...\n");
std::stringstream _ss{};
tim::print_backtrace<64>(_ss);
(void) _ss;
}
get_state() = State::Init;
set_state(State::Init);
OMNITRACE_CI_THROW(get_state() != State::Init,
"set_state(State::Init) failed. state is %s",
std::to_string(get_state()).c_str());
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(_debug_init, "Configuring settings...\n");
@@ -395,8 +485,9 @@ omnitrace_init_library_hidden()
if(get_use_kokkosp())
{
auto _force = 0;
if(tim::get_env<std::string>("KOKKOS_PROFILE_LIBRARY") == "libtimemory.so")
auto _force = 0;
auto _current_kokkosp_lib = tim::get_env<std::string>("KOKKOS_PROFILE_LIBRARY");
if(std::regex_search(_current_kokkosp_lib, std::regex{ "libtimemory\\." }))
_force = 1;
tim::set_env("KOKKOS_PROFILE_LIBRARY", "libomnitrace.so", _force);
}
@@ -537,8 +628,12 @@ omnitrace_init_tooling_hidden()
return true;
}();
static thread_local auto _dtor = scope::destructor{ []() {
if(get_use_sampling()) sampling::shutdown();
thread_data<omnitrace_thread_bundle_t>::instance()->stop();
if(get_state() != State::Finalized)
{
if(get_use_sampling()) sampling::shutdown();
if(thread_data<omnitrace_thread_bundle_t>::instance())
thread_data<omnitrace_thread_bundle_t>::instance()->stop();
}
} };
(void) _thread_setup;
(void) _dtor;
@@ -555,7 +650,7 @@ omnitrace_init_tooling_hidden()
(void) _v;
};
// functors for starting and stopping timemory
// functors for starting and stopping timemory omni functors
auto _push_timemory = [](const char* name) {
auto& _data = get_instrumentation_bundles();
// this generates a hash for the raw string array
@@ -566,11 +661,6 @@ omnitrace_init_tooling_hidden()
_bundle->start();
};
auto _push_perfetto = [](const char* name) {
uint64_t _ts = comp::wall_clock::record();
TRACE_EVENT_BEGIN("host", perfetto::StaticString(name), _ts);
};
auto _pop_timemory = [](const char* name) {
auto _hash = tim::hash::get_hash_id(tim::string_view_t{ name });
auto& _data = get_instrumentation_bundles();
@@ -593,14 +683,33 @@ omnitrace_init_tooling_hidden()
}
};
// functors for starting and stopping perfetto omni functors
auto _push_perfetto = [](const char* name) {
uint64_t _ts = comp::wall_clock::record();
TRACE_EVENT_BEGIN("host", perfetto::StaticString(name), _ts);
};
auto _pop_perfetto = [](const char*) {
uint64_t _ts = comp::wall_clock::record();
TRACE_EVENT_END("host", _ts);
};
// functors for starting and stopping perfetto user functors
auto _push_user_perfetto = [](const char* name) {
uint64_t _ts = comp::wall_clock::record();
TRACE_EVENT_BEGIN("user", nullptr, _ts, [name](perfetto::EventContext& _ctx) {
_ctx.event()->set_name(name);
});
};
auto _pop_user_perfetto = [](const char*) {
uint64_t _ts = comp::wall_clock::record();
TRACE_EVENT_END("user", _ts);
};
if(get_use_perfetto() && get_use_timemory())
{
library_functors::configure(
omni_functors::configure(
[=](const char* name) {
_thread_init();
_push_perfetto(name);
@@ -611,20 +720,44 @@ omnitrace_init_tooling_hidden()
_pop_timemory(name);
_pop_perfetto(name);
});
user_functors::configure(
[=](const char* name) {
_thread_init();
_push_user_perfetto(name);
_push_timemory(name);
},
[=](const char* name) {
_pop_timemory(name);
_pop_user_perfetto(name);
});
}
else if(get_use_perfetto())
{
library_functors::configure(
omni_functors::configure(
[=](const char* name) {
_thread_init();
_push_perfetto(name);
_setup_thread_sampling();
},
[=](const char* name) { _pop_perfetto(name); });
user_functors::configure(
[=](const char* name) {
_thread_init();
_push_user_perfetto(name);
_setup_thread_sampling();
},
[=](const char* name) { _pop_user_perfetto(name); });
}
else if(get_use_timemory())
{
library_functors::configure(
omni_functors::configure(
[=](const char* name) {
_thread_init();
_push_timemory(name);
_setup_thread_sampling();
},
[=](const char* name) { _pop_timemory(name); });
user_functors::configure(
[=](const char* name) {
_thread_init();
_push_timemory(name);
@@ -633,6 +766,8 @@ omnitrace_init_tooling_hidden()
[=](const char* name) { _pop_timemory(name); });
}
ompt::setup();
if(get_use_perfetto() && !is_system_backend())
{
#if defined(CUSTOM_DATA_SOURCE)
@@ -676,9 +811,16 @@ omnitrace_init_hidden(const char* _mode, bool _is_binary_rewrite, const char* _a
(void) pop_count();
get_finalization_functions().emplace_back([_argv0]() {
// if main hasn't been popped yet, pop it
OMNITRACE_BASIC_PRINT("Running omnitrace_pop_trace(%s)...\n", _argv0);
omnitrace_pop_trace_hidden(_argv0);
OMNITRACE_CI_THROW(get_state() != State::Active,
"Finalizer function for popping main invoked in non-active "
"state :: state = %s\n",
std::to_string(get_state()).c_str());
if(get_state() == State::Active)
{
// if main hasn't been popped yet, pop it
OMNITRACE_BASIC_VERBOSE(2, "Running omnitrace_pop_trace(%s)...\n", _argv0);
omnitrace_pop_trace_hidden(_argv0);
}
});
std::atexit([]() {
@@ -740,9 +882,10 @@ omnitrace_finalize_hidden(void)
}
}
get_state() = State::Finalized;
set_state(State::Finalized);
library_functors::configure([](const char*) {}, [](const char*) {});
omni_functors::configure([](const char*) {}, [](const char*) {});
user_functors::configure([](const char*) {}, [](const char*) {});
pthread_gotcha::push_enable_sampling_on_child_threads(false);
pthread_gotcha::set_sampling_on_all_future_threads(false);
@@ -785,6 +928,8 @@ omnitrace_finalize_hidden(void)
}
}
ompt::shutdown();
OMNITRACE_DEBUG_F("Stopping and destroying instrumentation bundles...\n");
for(auto& itr : instrumentation_bundles::instances())
{
@@ -34,6 +34,18 @@ omnitrace_pop_trace(const char* _name)
omnitrace_pop_trace_hidden(_name);
}
extern "C" void
omnitrace_push_region(const char* _name)
{
omnitrace_push_region_hidden(_name);
}
extern "C" void
omnitrace_pop_region(const char* _name)
{
omnitrace_pop_region_hidden(_name);
}
extern "C" void
omnitrace_init_library(void)
{
@@ -231,7 +231,7 @@ backtrace::get_thread_cpu_timestamp() const
void
backtrace::sample(int signum)
{
if(get_state() != State::Active)
if(signum != -1 && get_state() != State::Active)
{
OMNITRACE_CONDITIONAL_PRINT(
get_debug_sampling(),
@@ -341,7 +341,6 @@ backtrace::configure(bool _setup, int64_t _tid)
OMNITRACE_DEBUG("Configuring sampler for thread %lu...\n", _tid);
sampler_running_instances::construct(true);
backtrace_init_instances::construct();
sampling::sampler_instances::construct("omnitrace", _tid, *_signal_types);
_sampler->set_signals(*_signal_types);
_sampler->set_flags(SA_RESTART);
@@ -363,6 +362,7 @@ backtrace::configure(bool _setup, int64_t _tid)
_sampler->get_rate(units::sec));
// (void) sampling::sampler_t::get_samplers(_tid);
backtrace_init_instances::construct();
get_backtrace_init(_tid)->sample();
_sampler->configure(false);
_sampler->start();
@@ -617,6 +617,8 @@ backtrace::post_process(int64_t _tid)
auto* _bt = ditr->get<backtrace>();
if(_bt->m_ts < _last_wall_ts) continue;
double _elapsed_wc = (_bt->m_ts - _last_wall_ts).count();
double _elapsed_cc = (_bt->m_thr_cpu_ts - _last_cpu_ts);
@@ -86,8 +86,7 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***)
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_debug_env(), "[%s] %s(int*, char***)\n",
__FUNCTION__, _data.tool_id.c_str());
if(get_state() == ::omnitrace::State::DelayedInit)
get_state() = ::omnitrace::State::PreInit;
if(get_state() < ::omnitrace::State::Init) set_state(::omnitrace::State::PreInit);
omnitrace_push_trace_hidden(_data.tool_id.c_str());
#if !defined(TIMEMORY_USE_MPI) && defined(TIMEMORY_USE_MPI_HEADERS)
@@ -102,8 +101,8 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***, in
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_debug_env(),
"[%s] %s(int*, char***, int, int*)\n", __FUNCTION__,
_data.tool_id.c_str());
if(get_state() == ::omnitrace::State::DelayedInit)
get_state() = ::omnitrace::State::PreInit;
if(get_state() < ::omnitrace::State::Init) set_state(::omnitrace::State::PreInit);
omnitrace_push_trace_hidden(_data.tool_id.c_str());
#if !defined(TIMEMORY_USE_MPI) && defined(TIMEMORY_USE_MPI_HEADERS)
@@ -140,6 +140,8 @@ pthread_gotcha::wrapper::operator()() const
{
_tid = threading::get_id();
threading::set_thread_name(TIMEMORY_JOIN(" ", "Thread", _tid).c_str());
// initialize thread-local statics
(void) tim::get_unw_backtrace<12, 1, false>();
{
std::unique_lock<std::mutex> _lk{ bundles_mutex };
if(comp::roctracer::is_setup())
@@ -86,7 +86,7 @@ check_error(rsmi_status_t ec)
}
std::atomic<State>&
get_rocm_smi_state()
get_state()
{
static std::atomic<State> _v{ State::PreInit };
return _v;
@@ -151,7 +151,7 @@ config()
void
sample()
{
if(get_rocm_smi_state() != State::Active) return;
if(rocm_smi::get_state() != State::Active) return;
for(auto itr : data::device_list)
{
@@ -168,63 +168,9 @@ sample()
void
set_state(State _v)
{
get_rocm_smi_state().store(_v);
rocm_smi::get_state().store(_v);
}
/*
void
data::poll(std::atomic<State>* _state, nsec_t _interval, promise_t* _ready)
{
threading::set_thread_name("omni.rocm_smi");
// notify thread started
if(_ready) _ready->set_value();
std::vector<std::unique_ptr<bundle_t>*> _bundle_data{};
_bundle_data.resize(device_count, nullptr);
for(size_t i = 0; i < device_count; ++i)
{
if(device_list.count(i) > 0)
{
_bundle_data.at(i) = &sampler_instances::instances().at(i);
if(!*_bundle_data.at(i)) *_bundle_data.at(i) = std::make_unique<bundle_t>();
}
}
OMNITRACE_CONDITIONAL_BASIC_PRINT(
get_verbose() > 0 || get_debug(),
"Polling rocm-smi for %zu device(s) at an interval of %f seconds...\n",
device_list.size(),
std::chrono::duration_cast<std::chrono::duration<double>>(_interval).count());
get_initial().resize(device_count);
for(auto itr : device_list)
get_initial().at(itr).sample(itr);
auto _now = std::chrono::steady_clock::now();
while(_state && _state->load() != State::Finalized && get_state() != State::Finalized)
{
std::this_thread::sleep_until(_now);
if(_state->load() != State::Active) continue;
for(auto itr : device_list)
{
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_debug(),
"Polling rocm-smi for device %u...\n", itr);
auto& _data = *_bundle_data.at(itr);
if(!_data) continue;
_data->emplace_back(data{ itr });
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_debug(), " %s\n",
TIMEMORY_JOIN("", _data->back()).c_str());
}
while(_now < std::chrono::steady_clock::now())
_now += _interval;
}
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_debug(), "Polling rocm-smi completed...\n");
if(polling_finished) polling_finished->set_value();
}
*/
std::vector<data>&
data::get_initial()
{
@@ -236,7 +182,7 @@ bool
data::setup()
{
perfetto_counter_track<data>::init();
set_state(State::PreInit);
rocm_smi::set_state(State::PreInit);
return true;
}
@@ -244,7 +190,7 @@ bool
data::shutdown()
{
OMNITRACE_DEBUG("Shutting down rocm-smi...\n");
set_state(State::Finalized);
rocm_smi::set_state(State::Finalized);
return true;
}
@@ -0,0 +1,52 @@
// 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 "library/components/user_region.hpp"
#include "library/api.hpp"
#include "library/components/fwd.hpp"
namespace omnitrace
{
namespace component
{
void
user_region::start()
{
if(m_prefix) omnitrace_push_region_hidden(m_prefix);
}
void
user_region::stop()
{
if(m_prefix) omnitrace_pop_region_hidden(m_prefix);
}
void
user_region::set_prefix(const char* _prefix)
{
m_prefix = _prefix;
}
} // namespace component
} // namespace omnitrace
TIMEMORY_INITIALIZE_STORAGE(omnitrace::component::user_region)
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(omnitrace_user_region, false, void)
@@ -150,6 +150,12 @@ configure_settings()
"Enable support for Kokkos Tools", false, "kokkos",
"backend");
#if defined(TIMEMORY_USE_OMPT)
OMNITRACE_CONFIG_SETTING(bool, "OMNITRACE_USE_OMPT",
"Enable support for OpenMP-Tools", true, "openmp", "ompt",
"backend");
#endif
OMNITRACE_CONFIG_SETTING(size_t, "OMNITRACE_INSTRUMENTATION_INTERVAL",
"Instrumentation only takes measurements once every N "
"function calls (not statistical)",
@@ -736,6 +742,17 @@ get_use_kokkosp()
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_ompt()
{
#if defined(TIMEMORY_USE_OMPT)
static auto _v = get_config()->find("OMNITRACE_USE_OMPT");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
#else
return false;
#endif
}
bool
get_critical_trace_debug()
{
@@ -956,6 +973,20 @@ get_state()
return _v;
}
State
set_state(State _n)
{
auto _o = get_state();
OMNITRACE_CONDITIONAL_PRINT_F(get_debug_init(), "Setting state :: %s -> %s\n",
std::to_string(_o).c_str(), std::to_string(_n).c_str());
// state should always be increased, not decreased
OMNITRACE_CI_BASIC_THROW(_n < _o,
"State is being assigned to a lesser value :: %s -> %s",
std::to_string(_o).c_str(), std::to_string(_n).c_str());
get_state() = _n;
return _o;
}
std::atomic<uint64_t>&
get_cpu_cid()
{
@@ -22,10 +22,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// used by Kokkos decls
#if !defined(TIMEMORY_LIBRARY_SOURCE)
# define TIMEMORY_LIBRARY_SOURCE 1
#endif
#include "library/defines.hpp"
#define TIMEMORY_KOKKOSP_POSTFIX OMNITRACE_PUBLIC_API
#include "library/components/omnitrace.hpp"
#include "library/config.hpp"
@@ -0,0 +1,114 @@
// MIT License
//
// Copyright (c) 2020, The Regents of the University of California,
// through Lawrence Berkeley National Laboratory (subject to receipt of any
// required approvals from the U.S. Dept. of Energy). 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 "library/defines.hpp"
#include <timemory/defines.h>
#if defined(TIMEMORY_USE_OMPT)
# include "library/components/fwd.hpp"
# include "library/components/user_region.hpp"
# include "library/config.hpp"
# include "library/debug.hpp"
# include <timemory/components/ompt.hpp>
# include <timemory/components/ompt/extern.hpp>
# include <timemory/timemory.hpp>
# include <memory>
using api_t = TIMEMORY_API;
using ompt_handle_t = tim::component::ompt_handle<api_t>;
using ompt_context_t = tim::openmp::context_handler<api_t>;
using ompt_toolset_t = typename ompt_handle_t::toolset_type;
using ompt_bundle_t = tim::component_tuple<ompt_handle_t>;
extern "C"
{
ompt_start_tool_result_t* ompt_start_tool(unsigned int,
const char*) OMNITRACE_PUBLIC_API;
}
namespace omnitrace
{
namespace ompt
{
namespace
{
std::unique_ptr<ompt_bundle_t> f_bundle = {};
bool _init_toolset_off = (trait::runtime_enabled<ompt_toolset_t>::set(false), true);
} // namespace
void
setup()
{
OMNITRACE_VERBOSE(1, "Setting up OMPT...\n");
trait::runtime_enabled<ompt_toolset_t>::set(config::get_use_ompt());
comp::user_ompt_bundle::global_init();
comp::user_ompt_bundle::reset();
// provide environment variable for enabling/disabling
if(config::get_use_ompt())
{
tim::auto_lock_t lk{ tim::type_mutex<ompt_handle_t>() };
comp::user_ompt_bundle::configure<omnitrace::component::user_region>();
f_bundle =
std::make_unique<ompt_bundle_t>("ompt", quirk::config<quirk::auto_start>{});
}
}
void
shutdown()
{
OMNITRACE_VERBOSE(1, "Shutting down OMPT...\n");
if(f_bundle)
{
f_bundle->stop();
ompt_context_t::cleanup();
trait::runtime_enabled<ompt_toolset_t>::set(false);
}
f_bundle.reset();
}
} // namespace ompt
} // namespace omnitrace
// include the ompt_start_tool definition
# include <timemory/components/ompt/start_tool.hpp>
#else
namespace omnitrace
{
namespace ompt
{
void
setup()
{}
void
shutdown()
{}
} // namespace ompt
} // namespace omnitrace
#endif