omnitrace-sample (#169)

- `omnitrace-sample` executable which executes sampling (no
instrumentation)
- fixes bug with OMPT ignoring value of `OMNITRACE_USE_OMPT`
- fixes some issues with sampling duration
- new `OMNITRACE_SAMPLING_INCLUDE_INLINES` configuration variable
- restricts process-sampling to 100 interrupts/sec when inheriting value
from `OMNITRACE_SAMPLING_FREQ`
- `OMNITRACE_PROCESS_SAMPLING_FREQ` still supports up to 1000
interrupts/sec
- fixes bug with colorized log not truly being disabled in all instances
- adds tests for `omnitrace-sample`
- adds tests for sampling duration
- settings ROCP_TOOL_LIB to libomnitrace-dl throws error
  - rocprofiler does not configure correctly when this is done
- Quiet numa_gotcha warnings
- Fixed some shadowed variables

[ROCm/rocprofiler-systems commit: 79a8f16646]
This commit is contained in:
Jonathan R. Madsen
2022-09-30 10:47:07 -05:00
کامیت شده توسط GitHub
والد 07e3cf256a
کامیت 5973299ccd
29فایلهای تغییر یافته به همراه1266 افزوده شده و 158 حذف شده
@@ -21,6 +21,7 @@ parse:
omnitrace_add_test:
flags:
- SKIP_BASELINE
- SKIP_PRELOAD
- SKIP_REWRITE
- SKIP_RUNTIME
- SKIP_SAMPLING
@@ -32,16 +33,21 @@ parse:
NUM_PROCS: '*'
REWRITE_TIMEOUT: '*'
RUNTIME_TIMEOUT: '*'
PRELOAD_TIMEOUT: '*'
REWRITE_ARGS: '*'
RUNTIME_ARGS: '*'
RUN_ARGS: '*'
ENVIRONMENT: '*'
LABELS: '*'
PROPERTIES: '*'
PRELOAD_PASS_REGEX: '*'
PRELOAD_FAIL_REGEX: '*'
RUNTIME_PASS_REGEX: '*'
RUNTIME_FAIL_REGEX: '*'
REWRITE_PASS_REGEX: '*'
REWRITE_FAIL_REGEX: '*'
BASELINE_PASS_REGEX: '*'
BASELINE_FAIL_REGEX: '*'
REWRITE_RUN_PASS_REGEX: '*'
REWRITE_RUN_FAIL_REGEX: '*'
omnitrace_target_compile_definitions:
+4 -4
مشاهده پرونده
@@ -78,7 +78,7 @@ jobs:
timeout-minutes: 10
uses: actions/upload-artifact@v2
with:
name: ubuntu-stgz-installers
name: ubuntu-${{ matrix.os }}-rocm-${{ matrix.rocm-version }}-stgz-installers
path: |
build-release/stgz/*.sh
@@ -86,7 +86,7 @@ jobs:
timeout-minutes: 10
uses: actions/upload-artifact@v2
with:
name: ubuntu-deb-installers
name: ubuntu-${{ matrix.os }}-rocm-${{ matrix.rocm-version }}-deb-installers
path: |
build-release/deb/*.deb
@@ -187,7 +187,7 @@ jobs:
timeout-minutes: 10
uses: actions/upload-artifact@v2
with:
name: opensuse-stgz-installers
name: opensuse-${{ matrix.os }}-rocm-${{ matrix.rocm-version }}-stgz-installers
path: |
build-release/stgz/*.sh
@@ -195,7 +195,7 @@ jobs:
timeout-minutes: 10
uses: actions/upload-artifact@v2
with:
name: opensuse-rpm-installers
name: opensuse-${{ matrix.os }}-rocm-${{ matrix.rocm-version }}-rpm-installers
path: |
build-release/rpm/*.rpm
@@ -90,8 +90,46 @@ if(DEFINED CMAKE_INSTALL_LIBDIR AND NOT DEFINED CMAKE_DEFAULT_INSTALL_LIBDIR)
CACHE STRING "Object code libraries" FORCE)
endif()
if(NOT "$ENV{OMNITRACE_CI}" STREQUAL "")
set(CI_BUILD $ENV{OMNITRACE_CI})
else()
set(CI_BUILD OFF)
endif()
include(GNUInstallDirs) # install directories
include(MacroUtilities) # various functions and macros
if(CI_BUILD)
omnitrace_add_option(OMNITRACE_BUILD_CI "Enable internal asserts, etc." ON ADVANCED
NO_FEATURE)
omnitrace_add_option(OMNITRACE_BUILD_TESTING "Enable building the testing suite" ON
ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_DEBUG
"Enable building with extensive debug symbols" OFF ADVANCED)
omnitrace_add_option(OMNITRACE_CUSTOM_DATA_SOURCE "Enable custom data source" OFF
ADVANCED)
omnitrace_add_option(
OMNITRACE_BUILD_HIDDEN_VISIBILITY
"Build with hidden visibility (disable for Debug builds)" OFF ADVANCED)
omnitrace_add_option(OMNITRACE_STRIP_LIBRARIES "Strip the libraries" OFF ADVANCED)
else()
omnitrace_add_option(OMNITRACE_BUILD_CI "Enable internal asserts, etc." OFF ADVANCED
NO_FEATURE)
omnitrace_add_option(OMNITRACE_BUILD_EXAMPLES "Enable building the examples" OFF
ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_TESTING "Enable building the testing suite" OFF
ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_DEBUG
"Enable building with extensive debug symbols" OFF ADVANCED)
omnitrace_add_option(OMNITRACE_CUSTOM_DATA_SOURCE "Enable custom data source" OFF
ADVANCED)
omnitrace_add_option(
OMNITRACE_BUILD_HIDDEN_VISIBILITY
"Build with hidden visibility (disable for Debug builds)" ON ADVANCED)
omnitrace_add_option(OMNITRACE_STRIP_LIBRARIES "Strip the libraries"
${_STRIP_LIBRARIES_DEFAULT} ADVANCED)
endif()
include(Compilers) # compiler identification
include(BuildSettings) # compiler flags
@@ -135,22 +173,8 @@ omnitrace_add_option(OMNITRACE_USE_OMPT "Enable OpenMP tools support" ON)
omnitrace_add_option(OMNITRACE_USE_PYTHON "Enable Python support" OFF)
omnitrace_add_option(OMNITRACE_BUILD_DYNINST "Build dyninst from submodule" OFF)
omnitrace_add_option(OMNITRACE_BUILD_LIBUNWIND "Build libunwind from submodule" ON)
omnitrace_add_option(OMNITRACE_BUILD_EXAMPLES "Enable building the examples" OFF ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_TESTING "Enable building the testing suite" OFF
ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_DEBUG "Enable building with extensive debug symbols"
OFF ADVANCED)
omnitrace_add_option(OMNITRACE_CUSTOM_DATA_SOURCE "Enable custom data source" OFF
ADVANCED)
omnitrace_add_option(
OMNITRACE_BUILD_HIDDEN_VISIBILITY
"Build with hidden visibility (disable for Debug builds)" ON ADVANCED)
omnitrace_add_option(OMNITRACE_BUILD_CI "Enable internal asserts, etc." OFF ADVANCED
NO_FEATURE)
omnitrace_add_option(OMNITRACE_INSTALL_PERFETTO_TOOLS
"Install perfetto tools (i.e. traced, perfetto, etc.)" OFF)
omnitrace_add_option(OMNITRACE_STRIP_LIBRARIES "Strip the libraries"
${_STRIP_LIBRARIES_DEFAULT} ADVANCED)
if(OMNITRACE_USE_PAPI)
omnitrace_add_option(OMNITRACE_BUILD_PAPI "Build PAPI from submodule" ON)
@@ -161,16 +185,6 @@ if(OMNITRACE_USE_PYTHON)
"Build python bindings with internal pybind11" ON)
endif()
if(NOT "$ENV{OMNITRACE_CI}" STREQUAL "")
message(
AUTHOR_WARNING
"OMNITRACE_CI environment variable ($ENV{OMNITRACE_CI}) is overridding the OMNITRACE_BUILD_CI cache value"
)
set(OMNITRACE_BUILD_CI
"$ENV{OMNITRACE_CI}"
CACHE BOOL "Enable internal asserts, etc" FORCE)
endif()
if(NOT OMNITRACE_USE_HIP)
set(OMNITRACE_USE_ROCTRACER
OFF
@@ -12,8 +12,9 @@ include(Compilers)
include(FindPackageHandleStandardArgs)
include(MacroUtilities)
omnitrace_add_option(OMNITRACE_BUILD_DEVELOPER
"Extra build flags for development like -Werror" OFF)
omnitrace_add_option(
OMNITRACE_BUILD_DEVELOPER "Extra build flags for development like -Werror"
${OMNITRACE_BUILD_CI})
omnitrace_add_option(OMNITRACE_BUILD_EXTRA_OPTIMIZATIONS "Extra optimization flags" OFF)
omnitrace_add_option(OMNITRACE_BUILD_LTO "Build with link-time optimization" OFF)
omnitrace_add_option(OMNITRACE_USE_COMPILE_TIMING
Submodule projects/rocprofiler-systems/external/timemory updated: a781a21695...98e2306ca9
@@ -16,6 +16,7 @@ endif()
# executables
add_subdirectory(omnitrace-avail)
add_subdirectory(omnitrace-critical-trace)
add_subdirectory(omnitrace-sample)
add_subdirectory(omnitrace)
if(OMNITRACE_BUILD_TESTING OR "$ENV{OMNITRACE_CI}" MATCHES "[1-9]+|ON|on|y|yes")
@@ -0,0 +1,22 @@
# ------------------------------------------------------------------------------#
#
# omnitrace-sample target
#
# ------------------------------------------------------------------------------#
add_executable(omnitrace-sample ${CMAKE_CURRENT_LIST_DIR}/omnitrace-sample.cpp
${CMAKE_CURRENT_LIST_DIR}/impl.cpp)
target_include_directories(omnitrace-sample PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(
omnitrace-sample
PRIVATE omnitrace::omnitrace-compile-definitions omnitrace::omnitrace-headers
omnitrace::omnitrace-common-library)
set_target_properties(
omnitrace-sample PROPERTIES BUILD_RPATH "\$ORIGIN:\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}"
INSTALL_RPATH "${OMNITRACE_EXE_INSTALL_RPATH}")
install(
TARGETS omnitrace-sample
DESTINATION ${CMAKE_INSTALL_BINDIR}
OPTIONAL)
@@ -0,0 +1,676 @@
// 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 "omnitrace-sample.hpp"
#include "common/delimit.hpp"
#include "common/environment.hpp"
#include "common/join.hpp"
#include "common/setup.hpp"
#include <timemory/environment.hpp>
#include <timemory/log/color.hpp>
#include <timemory/utility/argparse.hpp>
#include <timemory/utility/console.hpp>
#include <timemory/utility/join.hpp>
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string_view>
#include <unistd.h>
#include <vector>
namespace color = tim::log::color;
using tim::log::stream;
using namespace timemory::join;
using tim::get_env;
namespace
{
int verbose = 0;
}
std::string
get_command(const char* _argv0)
{
return omnitrace::path::find_path(_argv0, 0, omnitrace::common::get_env("PATH", ""));
}
std::string
get_realpath(const std::string& _v)
{
auto* _tmp = realpath(_v.c_str(), nullptr);
auto _ret = std::string{ _tmp };
free(_tmp);
return _ret;
}
void
print_command(const std::vector<char*>& _argv)
{
if(verbose >= 1)
stream(std::cout, color::info())
<< "Executing '" << join(array_config{ " " }, _argv) << "'...\n";
}
std::vector<char*>
get_initial_environment()
{
std::vector<char*> _env;
if(environ != nullptr)
{
int idx = 0;
while(environ[idx] != nullptr)
_env.emplace_back(strdup(environ[idx++]));
}
update_env(_env, "LD_PRELOAD",
get_realpath(get_internal_libpath("libomnitrace-dl.so")), true);
auto* _dl_libpath =
realpath(get_internal_libpath("libomnitrace-dl.so").c_str(), nullptr);
auto* _omni_libpath =
realpath(get_internal_libpath("libomnitrace.so").c_str(), nullptr);
update_env(_env, "OMNITRACE_USE_SAMPLING", true);
update_env(_env, "OMNITRACE_CRITICAL_TRACE", false);
update_env(_env, "OMNITRACE_USE_PROCESS_SAMPLING", false);
// update_env(_env, "OMNITRACE_USE_PID", false);
// update_env(_env, "OMNITRACE_TIME_OUTPUT", false);
// update_env(_env, "OMNITRACE_OUTPUT_PATH", "omnitrace-output/%tag%/%launch_time%");
#if defined(OMNITRACE_USE_ROCTRACER) || defined(OMNITRACE_USE_ROCPROFILER)
update_env(_env, "HSA_TOOLS_LIB", _dl_libpath);
update_env(_env, "HSA_TOOLS_REPORT_LOAD_FAILURE", "1");
#endif
#if defined(OMNITRACE_USE_ROCPROFILER)
update_env(_env, "ROCP_TOOL_LIB", _omni_libpath);
update_env(_env, "ROCP_HSA_INTERCEPT", "1");
#endif
#if defined(OMNITRACE_USE_OMPT)
update_env(_env, "OMP_TOOL_LIBRARIES", _dl_libpath);
#endif
free(_dl_libpath);
free(_omni_libpath);
return _env;
}
std::string
get_internal_libpath(const std::string& _lib)
{
auto _exe = std::string_view{ realpath("/proc/self/exe", nullptr) };
auto _pos = _exe.find_last_of('/');
auto _dir = std::string{ "./" };
if(_pos != std::string_view::npos) _dir = _exe.substr(0, _pos);
return omnitrace::common::join("/", _dir, "..", "lib", _lib);
}
template <typename Tp>
void
update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_val,
bool _append)
{
auto _key = join("", _env_var, "=");
for(auto& itr : _environ)
{
if(!itr) continue;
if(std::string_view{ itr }.find(_key) == 0)
{
if(_append)
{
auto _val = std::string{ itr }.substr(_key.length());
free(itr);
itr = strdup(
omnitrace::common::join('=', _env_var, join(":", _env_val, _val))
.c_str());
}
else
{
free(itr);
itr = strdup(omnitrace::common::join('=', _env_var, _env_val).c_str());
}
return;
}
}
_environ.emplace_back(
strdup(omnitrace::common::join('=', _env_var, _env_val).c_str()));
}
std::vector<char*>
parse_args(int argc, char** argv, std::vector<char*>& _env)
{
using parser_t = tim::argparse::argument_parser;
using parser_err_t = typename parser_t::result_type;
auto help_check = [](parser_t& p, int _argc, char** _argv) {
std::set<std::string> help_args = { "-h", "--help", "-?" };
return (p.exists("help") || _argc == 1 ||
(_argc > 1 && help_args.find(_argv[1]) != help_args.end()));
};
auto _pec = EXIT_SUCCESS;
auto help_action = [&_pec, argc, argv](parser_t& p) {
if(_pec != EXIT_SUCCESS)
{
std::stringstream msg;
msg << "Error in command:";
for(int i = 0; i < argc; ++i)
msg << " " << argv[i];
msg << "\n\n";
stream(std::cerr, color::fatal()) << msg.str();
std::cerr << std::flush;
}
p.print_help();
exit(_pec);
};
auto parser = parser_t(argv[0]);
parser.on_error([](parser_t&, const parser_err_t& _err) {
stream(std::cerr, color::fatal()) << _err << "\n";
exit(EXIT_FAILURE);
});
const auto* _cputime_desc =
R"(Sample based on a CPU-clock timer (default). Accepts zero or more arguments:
%{INDENT}%0. Enables sampling based on CPU-clock timer.
%{INDENT}%1. Interrupts per second. E.g., 100 == sample every 10 milliseconds of CPU-time.
%{INDENT}%2. Delay (in seconds of CPU-clock time). I.e., how long each thread should wait before taking first sample.
%{INDENT}%3+ Thread IDs to target for sampling, starting at 0 (the main thread).
%{INDENT}% May be specified as index or range, e.g., '0 2-4' will be interpreted as:
%{INDENT}% sample the main thread (0), do not sample the first child thread but sample the 2nd, 3rd, and 4th child threads)";
const auto* _realtime_desc =
R"(Sample based on a real-clock timer. Accepts zero or more arguments:
%{INDENT}%0. Enables sampling based on real-clock timer.
%{INDENT}%1. Interrupts per second. E.g., 100 == sample every 10 milliseconds of realtime.
%{INDENT}%2. Delay (in seconds of real-clock time). I.e., how long each thread should wait before taking first sample.
%{INDENT}%3+ Thread IDs to target for sampling, starting at 0 (the main thread).
%{INDENT}% May be specified as index or range, e.g., '0 2-4' will be interpreted as:
%{INDENT}% sample the main thread (0), do not sample the first child thread but sample the 2nd, 3rd, and 4th child threads
%{INDENT}% When sampling with a real-clock timer, please note that enabling this will cause threads which are typically "idle"
%{INDENT}% to consume more resources since, while idle, the real-clock time increases (and therefore triggers taking samples)
%{INDENT}% whereas the CPU-clock time does not.)";
const auto* _hsa_interrupt_desc =
R"(Set the value of the HSA_ENABLE_INTERRUPT environment variable.
%{INDENT}% ROCm version 5.2 and older have a bug which will cause a deadlock if a sample is taken while waiting for the signal
%{INDENT}% that a kernel completed -- which happens when sampling with a real-clock timer. We require this option to be set to
%{INDENT}% when --realtime is specified to make users aware that, while this may fix the bug, it can have a negative impact on
%{INDENT}% performance.
%{INDENT}% Values:
%{INDENT}% 0 avoid triggering the bug, potentially at the cost of reduced performance
%{INDENT}% 1 do not modify how ROCm is notified about kernel completion)";
auto _realtime_reqs = (get_env("HSA_ENABLE_INTERRUPT", std::string{}, false).empty())
? std::initializer_list<std::string>{ "hsa-interrupt" }
: std::initializer_list<std::string>{};
const auto* _trace_policy_desc =
R"(Policy for new data when the buffer size limit is reached:
%{INDENT}%- discard : new data is ignored
%{INDENT}%- ring_buffer : new data overwrites oldest data)";
auto _add_separator = [&](std::string _v, const std::string& _desc) {
parser.add_argument({ "" }, "");
parser
.add_argument({ join("", "[", _v, "]") },
(_desc.empty()) ? _desc : join({ "", "(", ")" }, _desc))
.color(tim::log::color::info());
parser.add_argument({ "" }, "");
};
parser.enable_help();
auto _cols = std::get<0>(tim::utility::console::get_columns());
if(_cols > parser.get_help_width() + 8)
parser.set_description_width(
std::min<int>(_cols - parser.get_help_width() - 8, 120));
_add_separator("DEBUG OPTIONS", "");
parser.add_argument({ "--monochrome" }, "Disable colorized output")
.max_count(1)
.dtype("bool")
.action([&](parser_t& p) {
auto _colorized = !p.get<bool>("monochrome");
p.set_use_color(_colorized);
update_env(_env, "OMNITRACE_COLORIZED_LOG", (_colorized) ? "1" : "0");
update_env(_env, "COLORIZED_LOG", (_colorized) ? "1" : "0");
});
parser.add_argument({ "--debug" }, "Debug output")
.max_count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_DEBUG", p.get<bool>("debug"));
});
parser.add_argument({ "-v", "--verbose" }, "Verbose output")
.count(1)
.action([&](parser_t& p) {
auto _v = p.get<int>("verbose");
verbose = _v;
update_env(_env, "OMNITRACE_VERBOSE", _v);
});
_add_separator("GENERAL OPTIONS", "");
parser.add_argument({ "-c", "--config" }, "Configuration file")
.min_count(0)
.dtype("filepath")
.action([&](parser_t& p) {
update_env(
_env, "OMNITRACE_CONFIG_FILE",
join(array_config{ ":" }, p.get<std::vector<std::string>>("config")));
});
parser
.add_argument({ "-o", "--output" },
"Output path. Accepts 1-2 parameters corresponding to the output "
"path and the output prefix")
.min_count(1)
.max_count(2)
.action([&](parser_t& p) {
auto _v = p.get<std::vector<std::string>>("output");
update_env(_env, "OMNITRACE_OUTPUT_PATH", _v.at(0));
if(_v.size() > 1) update_env(_env, "OMNITRACE_OUTPUT_PREFIX", _v.at(1));
});
parser
.add_argument({ "-T", "--trace" }, "Generate a detailed trace (perfetto output)")
.max_count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_USE_PERFETTO", p.get<bool>("trace"));
});
parser
.add_argument(
{ "-P", "--profile" },
"Generate a call-stack-based profile (conflicts with --flat-profile)")
.max_count(1)
.conflicts({ "flat-profile" })
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_USE_TIMEMORY", p.get<bool>("profile"));
});
parser
.add_argument({ "-F", "--flat-profile" },
"Generate a flat profile (conflicts with --profile)")
.max_count(1)
.conflicts({ "profile" })
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_USE_TIMEMORY", p.get<bool>("flat-profile"));
update_env(_env, "OMNITRACE_FLAT_PROFILE", p.get<bool>("flat-profile"));
});
parser
.add_argument({ "-H", "--host" },
"Enable sampling host-based metrics for the process. E.g. CPU "
"frequency, memory usage, etc.")
.max_count(1)
.action([&](parser_t& p) {
auto _h = p.get<bool>("host");
auto _d = p.get<bool>("device");
update_env(_env, "OMNITRACE_USE_PROCESS_SAMPLING", _h || _d);
update_env(_env, "OMNITRACE_CPU_FREQ_ENABLED", _h);
});
parser
.add_argument({ "-D", "--device" },
"Enable sampling device-based metrics for the process. E.g. GPU "
"temperature, memory usage, etc.")
.max_count(1)
.action([&](parser_t& p) {
auto _h = p.get<bool>("host");
auto _d = p.get<bool>("device");
update_env(_env, "OMNITRACE_USE_PROCESS_SAMPLING", _h || _d);
update_env(_env, "OMNITRACE_USE_ROCM_SMI", _d);
});
_add_separator("TRACING OPTIONS", "");
parser
.add_argument({ "--trace-file" },
"Specify the trace output filename. Relative filepath will be with "
"respect to output path and output prefix.")
.count(1)
.dtype("filepath")
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_PERFETTO_FILE", p.get<int64_t>("trace-file"));
});
parser
.add_argument({ "--trace-buffer-size" },
"Size limit for the trace output (in KB)")
.count(1)
.dtype("KB")
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_PERFETTO_BUFFER_SIZE_KB",
p.get<int64_t>("trace-buffer-size"));
});
parser.add_argument({ "--trace-fill-policy" }, _trace_policy_desc)
.count(1)
.choices({ "discard", "ring_buffer" })
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_PERFETTO_FILL_POLICY",
p.get<std::string>("trace-fill-policy"));
});
_add_separator("PROFILE OPTIONS", "");
parser.add_argument({ "--profile-format" }, "Data formats for profiling results")
.min_count(1)
.max_count(3)
.requires({ "profile|flat-profile" })
.choices({ "text", "json", "console" })
.action([&](parser_t& p) {
auto _v = p.get<std::set<std::string>>("profile");
update_env(_env, "OMNITRACE_USE_TIMEMORY", true);
if(!_v.empty())
{
update_env(_env, "OMNITRACE_TEXT_OUTPUT", _v.count("text") != 0);
update_env(_env, "OMNITRACE_JSON_OUTPUT", _v.count("json") != 0);
update_env(_env, "OMNITRACE_COUT_OUTPUT", _v.count("console") != 0);
}
});
parser
.add_argument({ "--profile-diff" },
"Generate a diff output b/t the profile collected and an existing "
"profile from another run Accepts 1-2 parameters corresponding to "
"the input path and the input prefix")
.min_count(1)
.max_count(2)
.action([&](parser_t& p) {
auto _v = p.get<std::vector<std::string>>("profile-diff");
update_env(_env, "OMNITRACE_DIFF_OUTPUT", true);
update_env(_env, "OMNITRACE_INPUT_PATH", _v.at(0));
if(_v.size() > 1) update_env(_env, "OMNITRACE_INPUT_PREFIX", _v.at(1));
});
_add_separator("HOST/DEVICE (PROCESS SAMPLING) OPTIONS", "");
parser
.add_argument({ "--process-freq" },
"Set the default host/device sampling frequency "
"(number of interrupts per second)")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_PROCESS_SAMPLING_FREQ",
p.get<double>("process-freq"));
});
parser
.add_argument({ "--process-wait" }, "Set the default wait time (i.e. delay) "
"before taking first host/device sample "
"(in seconds of realtime)")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_PROCESS_SAMPLING_DELAY",
p.get<double>("process-wait"));
});
parser
.add_argument(
{ "--process-duration" },
"Set the duration of the host/device sampling (in seconds of realtime)")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_PROCESS_DURATION",
p.get<double>("process-duration"));
});
parser
.add_argument({ "--cpus" },
"CPU IDs for frequency sampling. Supports integers and/or ranges")
.dtype("int or range")
.requires({ "host" })
.action([&](parser_t& p) {
update_env(
_env, "OMNITRACE_PROCESS_SAMPLING_CPUS",
join(array_config{ "," }, p.get<std::vector<std::string>>("cpus")));
});
parser
.add_argument({ "--gpus" },
"GPU IDs for SMI queries. Supports integers and/or ranges")
.dtype("int or range")
.requires({ "device" })
.action([&](parser_t& p) {
update_env(
_env, "OMNITRACE_PROCESS_SAMPLING_GPUS",
join(array_config{ "," }, p.get<std::vector<std::string>>("gpus")));
});
_add_separator("GENERAL SAMPLING OPTIONS", "");
parser
.add_argument({ "-f", "--freq" }, "Set the default sampling frequency "
"(number of interrupts per second)")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_FREQ", p.get<double>("freq"));
});
parser
.add_argument(
{ "-w", "--wait" },
"Set the default wait time (i.e. delay) before taking first sample "
"(in seconds). This delay time is based on the clock of the sampler, i.e., a "
"delay of 1 second for CPU-clock sampler may not equal 1 second of realtime")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_DELAY", p.get<double>("wait"));
});
parser
.add_argument(
{ "-d", "--duration" },
"Set the duration of the sampling (in seconds of realtime). I.e., it is "
"possible (currently) to set a CPU-clock time delay that exceeds the "
"real-time duration... resulting in zero samples being taken")
.count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_DURATION", p.get<double>("duration"));
});
parser
.add_argument({ "-t", "--tids" },
"Specify the default thread IDs for sampling, where 0 (zero) is "
"the main thread and each thread created by the target application "
"is assigned an atomically incrementing value.")
.min_count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_TIDS",
join(array_config{ ", " }, p.get<std::vector<int64_t>>("tids")));
});
_add_separator("SAMPLING TIMER OPTIONS", "");
parser.add_argument({ "--cputime" }, _cputime_desc)
.min_count(0)
.action([&](parser_t& p) {
auto _v = p.get<std::deque<std::string>>("cputime");
update_env(_env, "OMNITRACE_SAMPLING_CPUTIME", true);
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_CPUTIME_FREQ", _v.front());
_v.pop_front();
}
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_CPUTIME_DELAY", _v.front());
_v.pop_front();
}
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_CPUTIME_TIDS",
join(array_config{ "," }, _v));
}
});
parser.add_argument({ "--realtime" }, _realtime_desc)
.min_count(0)
.requires(_realtime_reqs)
.action([&](parser_t& p) {
auto _v = p.get<std::deque<std::string>>("realtime");
update_env(_env, "OMNITRACE_SAMPLING_REALTIME", true);
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_REALTIME_FREQ", _v.front());
_v.pop_front();
}
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_REALTIME_DELAY", _v.front());
_v.pop_front();
}
if(!_v.empty())
{
update_env(_env, "OMNITRACE_SAMPLING_REALTIME_TIDS",
join(array_config{ "," }, _v));
}
});
std::set<std::string> _backend_choices = { "all", "kokkosp", "mpip",
"ompt", "rcclp", "rocm-smi",
"roctracer", "rocprofiler", "roctx",
"mutex-locks", "spin-locks", "rw-locks" };
#if !defined(OMNITRACE_USE_MPI) && !defined(OMNITRACE_USE_MPI_HEADERS)
_backend_choices.erase("mpip");
#endif
#if !defined(OMNITRACE_USE_OMPT)
_backend_choices.erase("ompt");
#endif
#if !defined(OMNITRACE_USE_RCCL)
_backend_choices.erase("rcclp");
#endif
#if !defined(OMNITRACE_USE_ROCM_SMI)
_backend_choices.erase("rocm-smi");
#endif
#if !defined(OMNITRACE_USE_ROCTRACER)
_backend_choices.erase("roctracer");
_backend_choices.erase("roctx");
#endif
#if !defined(OMNITRACE_USE_ROCPROFILER)
_backend_choices.erase("rocprofiler");
#endif
_add_separator("BACKEND OPTIONS", "These options control region information captured "
"w/o sampling or instrumentation");
parser.add_argument({ "-I", "--include" }, "Include data from these backends")
.choices(_backend_choices)
.action([&](parser_t& p) {
auto _v = p.get<std::set<std::string>>("include");
auto _update = [&](const auto& _opt, bool _cond) {
if(_cond || _v.count("all") > 0) update_env(_env, _opt, true);
};
_update("OMNITRACE_USE_KOKKOSP", _v.count("kokkosp") > 0);
_update("OMNITRACE_USE_MPIP", _v.count("mpip") > 0);
_update("OMNITRACE_USE_OMPT", _v.count("ompt") > 0);
_update("OMNITRACE_USE_RCCLP", _v.count("rcclp") > 0);
_update("OMNITRACE_USE_ROCTX", _v.count("roctx") > 0);
_update("OMNITRACE_USE_ROCM_SMI", _v.count("rocm-smi") > 0);
_update("OMNITRACE_USE_ROCTRACER", _v.count("roctracer") > 0);
_update("OMNITRACE_USE_ROCPROFILER", _v.count("rocprofiler") > 0);
_update("OMNITRACE_TRACE_THREAD_LOCKS", _v.count("mutex-locks") > 0);
_update("OMNITRACE_TRACE_THREAD_RW_LOCKS", _v.count("rw-locks") > 0);
_update("OMNITRACE_TRACE_THREAD_SPIN_LOCKS", _v.count("spin-locks") > 0);
});
parser.add_argument({ "-E", "--exclude" }, "Exclude data from these backends")
.choices(_backend_choices)
.action([&](parser_t& p) {
auto _v = p.get<std::set<std::string>>("exclude");
auto _update = [&](const auto& _opt, bool _cond) {
if(_cond || _v.count("all") > 0) update_env(_env, _opt, false);
};
_update("OMNITRACE_USE_KOKKOSP", _v.count("kokkosp") > 0);
_update("OMNITRACE_USE_MPIP", _v.count("mpip") > 0);
_update("OMNITRACE_USE_OMPT", _v.count("ompt") > 0);
_update("OMNITRACE_USE_RCCLP", _v.count("rcclp") > 0);
_update("OMNITRACE_USE_ROCTX", _v.count("roctx") > 0);
_update("OMNITRACE_USE_ROCM_SMI", _v.count("rocm-smi") > 0);
_update("OMNITRACE_USE_ROCTRACER", _v.count("roctracer") > 0);
_update("OMNITRACE_USE_ROCPROFILER", _v.count("rocprofiler") > 0);
_update("OMNITRACE_TRACE_THREAD_LOCKS", _v.count("mutex-locks") > 0);
_update("OMNITRACE_TRACE_THREAD_RW_LOCKS", _v.count("rw-locks") > 0);
_update("OMNITRACE_TRACE_THREAD_SPIN_LOCKS", _v.count("spin-locks") > 0);
});
_add_separator("HARDWARE COUNTER OPTIONS", "");
parser
.add_argument({ "-C", "--cpu-events" },
"Set the CPU hardware counter events to record (ref: "
"`omnitrace-avail -H -c CPU`)")
.set_default(std::set<std::string>{})
.action([&](parser_t& p) {
auto _events =
join(array_config{ "," }, p.get<std::vector<std::string>>("cpu-events"));
update_env(_env, "OMNITRACE_PAPI_EVENTS", _events);
});
#if defined(OMNITRACE_USE_ROCPROFILER)
parser
.add_argument({ "-G", "--gpu-events" },
"Set the GPU hardware counter events to record (ref: "
"`omnitrace-avail -H -c GPU`)")
.set_default(std::set<std::string>{})
.action([&](parser_t& p) {
auto _events =
join(array_config{ "," }, p.get<std::vector<std::string>>("gpu-events"));
update_env(_env, "OMNITRACE_ROCM_EVENTS", _events);
});
#endif
_add_separator("MISCELLANEOUS OPTIONS", "");
parser
.add_argument({ "-i", "--inlines" },
"Include inline info in output when available")
.max_count(1)
.action([&](parser_t& p) {
update_env(_env, "OMNITRACE_SAMPLING_INCLUDE_INLINES",
p.get<bool>("inlines"));
});
parser.add_argument({ "--hsa-interrupt" }, _hsa_interrupt_desc)
.count(1)
.dtype("int")
.choices({ 0, 1 })
.action([&](parser_t& p) {
update_env(_env, "HSA_ENABLE_INTERRUPT", p.get<int>("hsa-interrupt"));
});
auto _args = parser.parse_known_args(argc, argv);
auto _cerr = std::get<0>(_args);
auto _cmdc = std::get<1>(_args);
auto* _cmdv = std::get<2>(_args);
if(parser.exists("realtime") && !parser.exists("cputime"))
update_env(_env, "OMNITRACE_SAMPLING_CPUTIME", false);
if(parser.exists("profile") && parser.exists("flat-profile"))
throw std::runtime_error(
"Error! '--profile' argument conflicts with '--flat-profile' argument");
if(help_check(parser, _cmdc, _cmdv)) help_action(parser);
if(_cerr) throw std::runtime_error(_cerr.what());
std::vector<char*> _argv = {};
_argv.reserve(_cmdc);
for(int i = 1; i < _cmdc; ++i)
_argv.emplace_back(_cmdv[i]);
return _argv;
}
@@ -0,0 +1,75 @@
// 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 "omnitrace-sample.hpp"
#include <algorithm>
#include <iostream>
#include <string_view>
#include <unistd.h>
int
main(int argc, char** argv)
{
auto _env = get_initial_environment();
bool _has_double_hyphen = false;
for(int i = 1; i < argc; ++i)
{
auto _arg = std::string_view{ argv[i] };
if(_arg == "--" || _arg == "-?" || _arg == "-h" || _arg == "--help")
_has_double_hyphen = true;
}
std::vector<char*> _argv = {};
if(_has_double_hyphen)
{
auto _size = _env.size();
_argv = parse_args(argc, argv, _env);
}
else
{
_argv.reserve(argc);
for(int i = 1; i < argc; ++i)
_argv.emplace_back(argv[i]);
}
std::sort(_env.begin(), _env.end(), [](auto* _lhs, auto* _rhs) {
if(!_lhs) return false;
if(!_rhs) return true;
return std::string_view{ _lhs } < std::string_view{ _rhs };
});
for(auto* itr : _env)
if(itr != nullptr && std::string_view{ itr }.find("OMNITRACE") == 0)
std::cout << itr << "\n";
if(!_argv.empty())
{
std::string _argv0 = get_command(_argv[0]);
print_command(_argv);
_argv.emplace_back(nullptr);
_env.emplace_back(nullptr);
return execve(_argv0.c_str(), _argv.data(), _env.data());
}
}
@@ -0,0 +1,49 @@
// 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 <string_view>
#include <vector>
std::string
get_command(const char*);
std::string
get_realpath(const std::string&);
void
print_command(const std::vector<char*>& _argv);
std::vector<char*>
get_initial_environment();
std::string
get_internal_libpath(const std::string& _lib);
template <typename Tp>
void
update_env(std::vector<char*>&, std::string_view, Tp&&, bool _append = false);
std::vector<char*>
parse_args(int argc, char** argv, std::vector<char*>&);
@@ -6,25 +6,48 @@
:maxdepth: 4
```
## Overview
> ***[Omnitrace](https://github.com/AMDResearch/omnitrace) is an AMD open source research project and is not supported as part of the ROCm software stack.***
[Browse Omnitrace source code on Github](https://github.com/AMDResearch/omnitrace)
[Omnitrace](https://github.com/AMDResearch/omnitrace) is designed for both high-level and
comprehensive application tracing and profiling on both the CPU and GPU.
[Omnitrace](https://github.com/AMDResearch/omnitrace) supports both binary instrumentation
and sampling as a means of collecting various metrics.
[Omnitrace](https://github.com/AMDResearch/omnitrace) is designed for both high-level profiling and
comprehensive tracing of applications running on the CPU or the CPU+GPU via dynamic binary instrumentation,
call-stack sampling, and various other means for determining currently executing function and line information.
Visualization of the comprehensive omnitrace results can be viewed in any modern web browser by visiting [ui.perfetto.dev](https://ui.perfetto.dev/)
and loading the perfetto output (`.proto` files) produced by omnitrace.
Visualization of the comprehensive omnitrace results can be viewed in any modern web browser by visiting
[ui.perfetto.dev](https://ui.perfetto.dev/) and loading the perfetto output (`.proto` files) produced by omnitrace.
Aggregated high-level results are available in text files for human consumption and JSON files for programmatic analysis.
The JSON output files are compatible with the python package [hatchet](https://github.com/hatchet/hatchet) which converts
the performance data into pandas dataframes and facilitate multi-run comparisons, filtering, visualization in Jupyter notebooks, and much more.
the performance data into pandas dataframes and facilitate multi-run comparisons, filtering, visualization in Jupyter notebooks,
and much more.
[Omnitrace](https://github.com/AMDResearch/omnitrace) has two distinct configuration steps:
[Omnitrace](https://github.com/AMDResearch/omnitrace) has two distinct configuration steps when instrumenting:
1. Configuring which functions and modules are instrumented in the target binaries (i.e. executable and/or libraries)
- [Instrumenting with Omnitrace](instrumenting.md)
2. Configuring what the instrumentation does happens when the instrumented binaries are executed
- [Customizing Omnitrace Runtime](runtime.md)
## Omnitrace Use Cases
When analyzing the performance of an application, ***it is always best to NOT assume you know where the performance bottlenecks are***
***and why they are happening.*** Omnitrace is a ***tool for the entire execution of application***. It is the sort of tool which is
ideal for *characterizing* where optimization would have the greatest impact on the end-to-end execution of the application and/or
viewing what else is happening on the system during a performance bottleneck.
Especially when GPUs are involved, there is a tendency to assume that the quickest path to performance improvement is minimizing
the runtime of the GPU kernels. This is a highly flawed assumption: if you optimize the runtime of a kernel from 1 millisecond
to 1 microsecond (1000x speed-up) but the original application *never spent time waiting* for kernel(s) to complete,
you will see zero statistically significant speed-up in end-to-end runtime of your application. In other words, it does not matter
how fast or slow the code on GPU is if the application is not bottlenecked waiting on the GPU.
Use Omnitrace to obtain a high-level view of the entire application. Use it to determine where the performance bottlenecks are and
obtain clues to why these bottlenecks are happening. If you want ***extensive*** insight into the execution of individual kernels
on the GPU, AMD Research is working on another tool for this but you should start with the tool which characterizes the
broad picture: Omnitrace.
With regard to the CPU, Omnitrace does not target any specific vendor, it works just as well with non-AMD CPUs as with AMD CPUs.
With regard to the GPU, Omnitrace is currently restricted to the HIP and HSA APIs and kernels executing on AMD GPUs.
@@ -248,7 +248,7 @@ OMNITRACE_STRICT_CONFIG = true
OMNITRACE_SUPPRESS_CONFIG = true
OMNITRACE_SUPPRESS_PARSING = true
OMNITRACE_TEXT_OUTPUT = true
OMNITRACE_TIME_FORMAT = %F_%I.%M_%p
OMNITRACE_TIME_FORMAT = %F_%H.%M
OMNITRACE_TIMELINE_PROFILE = false
OMNITRACE_TIMING_PRECISION = 6
OMNITRACE_TIMING_SCIENTIFIC = false
@@ -98,9 +98,9 @@ get_omnitrace_dl_env()
inline bool
get_omnitrace_preload()
{
auto&& _preload = get_env("OMNITRACE_PRELOAD", false);
auto&& _preload = get_env("OMNITRACE_PRELOAD", true);
auto&& _preload_libs = get_env("LD_PRELOAD", std::string{});
return (_preload || _preload_libs.find("libomnitrace-dl.so") != std::string::npos);
return (_preload && _preload_libs.find("libomnitrace-dl.so") != std::string::npos);
}
// environment priority:
@@ -381,8 +381,8 @@ public:
// ROCP functions
#if OMNITRACE_USE_ROCPROFILER > 0
void (*rocp_on_load_tool_prop_f)(rocprofiler_settings* settings) = nullptr;
void (*rocp_on_unload_tool_f)() = nullptr;
void (*rocp_on_load_tool_prop_f)(void* settings) = nullptr;
void (*rocp_on_unload_tool_f)() = nullptr;
#endif
// OpenMP functions
@@ -408,6 +408,8 @@ get_indirect() OMNITRACE_HIDDEN_API;
indirect&
get_indirect()
{
omnitrace_preinit_library();
static auto _libomni = get_env("OMNITRACE_LIBRARY", "libomnitrace.so");
static auto _libuser = get_env("OMNITRACE_USER_LIBRARY", "libomnitrace-user.so");
static auto _libdlib = get_env("OMNITRACE_DL_LIBRARY", "libomnitrace-dl.so");
@@ -503,6 +505,17 @@ namespace dl = omnitrace::dl;
extern "C"
{
void omnitrace_preinit_library(void)
{
if(!omnitrace::common::get_env("OMNITRACE_COLORIZED_LOG", tim::log::colorized()))
tim::log::colorized() = false;
}
int omnitrace_preload_library(void)
{
return (::omnitrace::dl::get_omnitrace_preload()) ? 1 : 0;
}
void omnitrace_init_library(void)
{
OMNITRACE_DL_INVOKE(get_indirect().omnitrace_init_library_f);
@@ -873,9 +886,15 @@ extern "C"
//
//----------------------------------------------------------------------------------//
#if OMNITRACE_USE_ROCTRACER > 0
void OnLoadToolProp(rocprofiler_settings* settings)
#if OMNITRACE_USE_ROCPROFILER > 0
void OnLoadToolProp(void* settings)
{
OMNITRACE_DL_LOG(-16,
"invoking %s(rocprofiler_settings_t*) within omnitrace-dl.so "
"will cause a silent failure for rocprofiler. ROCP_TOOL_LIB "
"should be set to libomnitrace.so\n",
__FUNCTION__);
abort();
return OMNITRACE_DL_INVOKE(get_indirect().rocp_on_load_tool_prop_f, settings);
}
@@ -913,16 +932,16 @@ omnitrace_preload() OMNITRACE_HIDDEN_API;
bool
omnitrace_preload()
{
auto _preloaded = get_omnitrace_preload();
auto _enabled = get_env("OMNITRACE_ENABLED", true);
auto _preload = get_omnitrace_preload() && get_env("OMNITRACE_ENABLED", true);
static bool _once = false;
if(_once) return _preloaded;
if(_once) return _preload;
_once = true;
if(_preloaded && _enabled)
if(_preload)
{
OMNITRACE_DL_LOG(0, "[%s] invoking %s(%s)\n", __FUNCTION__, "omnitrace_init",
omnitrace_preinit_library();
OMNITRACE_DL_LOG(1, "[%s] invoking %s(%s)\n", __FUNCTION__, "omnitrace_init",
::omnitrace::join(::omnitrace::QuoteStrings{}, ", ", "sampling",
false, "main")
.c_str());
@@ -930,7 +949,7 @@ omnitrace_preload()
omnitrace_init_tooling();
}
return _preloaded;
return _preload;
}
bool _handle_preload = omnitrace::dl::omnitrace_preload();
@@ -87,6 +87,9 @@ extern "C"
size_t address) OMNITRACE_PUBLIC_API;
#if defined(OMNITRACE_DL_SOURCE) && (OMNITRACE_DL_SOURCE > 0)
void omnitrace_preinit_library(void) OMNITRACE_HIDDEN_API;
int omnitrace_preload_library(void) OMNITRACE_HIDDEN_API;
int omnitrace_user_start_trace_dl(void) OMNITRACE_HIDDEN_API;
int omnitrace_user_stop_trace_dl(void) OMNITRACE_HIDDEN_API;
@@ -164,8 +167,7 @@ extern "C"
# if OMNITRACE_USE_ROCPROFILER > 0
// ROCP
struct rocprofiler_settings;
void OnLoadToolProp(rocprofiler_settings* settings) OMNITRACE_PUBLIC_API;
void OnLoadToolProp(void* settings) OMNITRACE_PUBLIC_API;
void OnUnloadTool() OMNITRACE_PUBLIC_API;
# endif
#endif
@@ -29,6 +29,9 @@
#include <string.h>
#include <stdbool.h>
extern int
omnitrace_preload_library(void);
extern void
omnitrace_finalize(void);
@@ -84,6 +87,8 @@ __libc_start_main(int (*_main)(int, char**, char**), int _argc, char** _argv,
int (*_init)(int, char**, char**), void (*_fini)(void),
void (*_rtld_fini)(void), void* _stack_end)
{
int _preload = omnitrace_preload_library();
// prevent re-entry
static int _reentry = 0;
if(_reentry > 0) return -1;
@@ -98,14 +103,23 @@ __libc_start_main(int (*_main)(int, char**, char**), int _argc, char** _argv,
// Find the real __libc_start_main()
omnitrace_libc_start_main user_main = dlsym(RTLD_NEXT, "__libc_start_main");
// disable future LD_PRELOADs
setenv("OMNITRACE_PRELOAD", "0", 1);
if(user_main && user_main != _this_func)
{
//if(strcmp(_argv[0], "mpirun") == 0)
// return user_main(_main, _argc, _argv, _init, _fini, _rtld_fini,
// _stack_end);
//else
if(_preload == 0)
{
// call original main
return user_main(main_real, _argc, _argv, _init, _fini, _rtld_fini,
_stack_end);
}
else
{
// call omnitrace main function wrapper
return user_main(omnitrace_main, _argc, _argv, _init, _fini, _rtld_fini, _stack_end);
return user_main(omnitrace_main, _argc, _argv, _init, _fini, _rtld_fini,
_stack_end);
}
}
else
{
@@ -20,6 +20,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// clang-format off
#include <timemory/log/color.hpp>
// clang-format on
#include "api.hpp"
#include "common/setup.hpp"
#include "library/components/category_region.hpp"
@@ -331,6 +335,8 @@ omnitrace_init_library_hidden()
extern "C" bool
omnitrace_init_tooling_hidden()
{
if(!get_env("OMNITRACE_COLORIZED_LOG", true, false)) tim::log::colorized() = false;
if(!tim::get_env("OMNITRACE_INIT_TOOLING", true))
{
omnitrace_init_library_hidden();
@@ -604,8 +610,14 @@ omnitrace_finalize_hidden(void)
auto& _thread_bundle = thread_data<thread_bundle_t>::instance();
if(_thread_bundle) _thread_bundle->stop();
if(dmp::rank() == 0 && get_verbose() >= 0) fprintf(stderr, "\n");
if(get_verbose() > 0 || get_debug()) config::print_settings();
if(get_verbose() >= 1 || get_debug())
{
if(dmp::rank() == 0)
{
fprintf(stderr, "\n");
config::print_settings();
}
}
OMNITRACE_VERBOSE_F(1, "omnitrace_push_trace :: called %zux\n", _push_count);
OMNITRACE_VERBOSE_F(1, "omnitrace_pop_trace :: called %zux\n", _pop_count);
@@ -45,6 +45,7 @@ fork_gotcha::configure()
void
fork_gotcha::audit(const gotcha_data_t&, audit::incoming)
{
tim::set_env("OMNITRACE_PRELOAD", "0", 1);
OMNITRACE_VERBOSE(1, "fork() called on PID %i (rank: %i), TID %li\n",
process::get_id(), dmp::rank(), threading::get_id());
OMNITRACE_BASIC_DEBUG(
@@ -61,6 +61,16 @@ get_numa_gotcha()
void
numa_gotcha::configure()
{
// don't emit warnings for missing MPI functions unless debug or verbosity >= 3
if(get_verbose_env() < 3 && !get_debug_env())
{
for(size_t i = 0; i < numa_gotcha_t::capacity(); ++i)
{
auto* itr = numa_gotcha_t::at(i);
if(itr) itr->verbose = -1;
}
}
numa_gotcha_t::get_initializer() = []() {
numa_gotcha_t::configure<0, long, void*, unsigned long, int, const unsigned long*,
unsigned long, unsigned>("mbind");
@@ -289,11 +289,18 @@ pthread_create_gotcha::shutdown()
bundles->clear();
OMNITRACE_BASIC_VERBOSE(
1,
// 2 && _ndangling > 0,
"[pthread_create_gotcha::shutdown] cleaned up %lu dangling bundles\n",
_ndangling);
if(config::settings_are_configured())
{
OMNITRACE_VERBOSE(2 && _ndangling > 0,
"[pthread_create_gotcha] cleaned up %lu dangling bundles\n",
_ndangling);
}
else
{
OMNITRACE_BASIC_VERBOSE(
2 && _ndangling > 0,
"[pthread_create_gotcha] cleaned up %lu dangling bundles\n", _ndangling);
}
}
void
@@ -94,8 +94,7 @@ rocm_event::rocm_event(uint32_t _dev, uint32_t _thr, uint32_t _queue,
feature_values.emplace_back(rocm_feature_value{ p->data.result_int32 });
break;
case ROCPROFILER_DATA_KIND_FLOAT:
feature_values.emplace_back(
rocm_feature_value{ static_cast<double>(p->data.result_float) });
feature_values.emplace_back(rocm_feature_value{ p->data.result_float });
break;
case ROCPROFILER_DATA_KIND_DOUBLE:
feature_values.emplace_back(rocm_feature_value{ p->data.result_double });
@@ -53,7 +53,7 @@ namespace component
{
using rocm_metric_type = unsigned long long;
using rocm_info_entry = ::tim::hardware_counters::info;
using rocm_feature_value = std::variant<uint32_t, uint64_t, double>;
using rocm_feature_value = std::variant<uint32_t, float, uint64_t, double>;
struct rocm_counter
{
@@ -210,7 +210,7 @@ configure_settings(bool _init)
if(_once) return;
_once = true;
if(get_state() < State::Init)
if(get_is_continuous_integration() && get_state() < State::Init)
{
timemory_print_demangled_backtrace<64>();
OMNITRACE_THROW("config::configure_settings() called before "
@@ -467,6 +467,10 @@ configure_settings(bool _init)
"filter out internal routines from the sampling call-stacks",
true, "sampling", "data", "advanced");
OMNITRACE_CONFIG_SETTING(bool, "OMNITRACE_SAMPLING_INCLUDE_INLINES",
"Create entries for inlined functions when available", false,
"sampling", "data", "advanced");
OMNITRACE_CONFIG_SETTING(
bool, "OMNITRACE_SAMPLING_REALTIME",
"Enable sampling frequency via a wall-clock timer on child threads. This may "
@@ -812,7 +816,7 @@ configure_settings(bool _init)
configure_signal_handler();
configure_disabled_settings();
OMNITRACE_VERBOSE(1, "configuration complete\n");
OMNITRACE_VERBOSE(2, "configuration complete\n");
}
void
@@ -827,8 +831,10 @@ configure_mode_settings()
}
else
{
bool _changed = get_setting_value<bool>(_name).second != _v;
OMNITRACE_VERBOSE(
1, "[configure_mode_settings] Overriding %s to %s in %s mode...\n",
1 && _changed,
"[configure_mode_settings] Overriding %s to %s in %s mode...\n",
_name.c_str(), JOIN("", std::boolalpha, _v).c_str(),
std::to_string(get_mode()).c_str());
}
@@ -1812,6 +1818,13 @@ get_sampling_real_tids()
static_cast<tim::tsettings<std::string>&>(*_v->second).get(), "thread IDs");
}
bool
get_sampling_include_inlines()
{
static auto _v = get_config()->find("OMNITRACE_SAMPLING_INCLUDE_INLINES");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
int64_t
get_critical_trace_count()
{
@@ -1825,7 +1838,7 @@ get_process_sampling_freq()
static auto _v = get_config()->find("OMNITRACE_PROCESS_SAMPLING_FREQ");
auto _val =
std::min<double>(static_cast<tim::tsettings<double>&>(*_v->second).get(), 1000.0);
if(_val < 1.0e-9) return get_sampling_freq();
if(_val < 1.0e-9) return std::min<double>(get_sampling_freq(), 100.0);
return _val;
}
@@ -298,6 +298,9 @@ get_sampling_cpu_tids();
std::set<int64_t>
get_sampling_real_tids();
bool
get_sampling_include_inlines();
double
get_process_sampling_freq();
@@ -78,8 +78,8 @@ FILE*
get_file()
{
static FILE* _v = []() {
auto&& _fname = tim::get_env<std::string>("OMNITRACE_LOG_FILE", "");
tim::log::colorized() = _fname.empty();
auto&& _fname = tim::get_env<std::string>("OMNITRACE_LOG_FILE", "");
if(!_fname.empty()) tim::log::colorized() = false;
return (_fname.empty()) ? stderr : tim::filepath::fopen(_fname, "w");
}();
return _v;
@@ -20,6 +20,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "api.hpp"
#include "library/common.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/defines.hpp"
#include <timemory/defines.h>
@@ -97,19 +101,37 @@ ompt_start_tool(unsigned int omp_version, const char* runtime_version)
OMNITRACE_METADATA("OMP_VERSION", omp_version);
OMNITRACE_METADATA("OMP_RUNTIME_VERSION", runtime_version);
if(!omnitrace::settings_are_configured())
{
OMNITRACE_BASIC_WARNING(
0,
"[%s] invoked before omnitrace was initialized. In instrumentation mode, "
"settings exported to the environment have not been propagated yet...\n",
__FUNCTION__);
omnitrace::configure_settings();
}
static bool _use_ompt = omnitrace::config::get_use_ompt();
static auto ompt_initialize = [](ompt_function_lookup_t lookup,
int initial_device_num,
ompt_data_t* tool_data) -> int {
TIMEMORY_PRINTF(stderr, "OpenMP-tools configuring for initial device %i\n\n",
initial_device_num);
tim::ompt::configure<TIMEMORY_OMPT_API_TAG>(lookup, initial_device_num,
tool_data);
_use_ompt = omnitrace::config::get_use_ompt();
if(_use_ompt)
{
TIMEMORY_PRINTF(stderr, "OpenMP-tools configuring for initial device %i\n\n",
initial_device_num);
tim::ompt::configure<TIMEMORY_OMPT_API_TAG>(lookup, initial_device_num,
tool_data);
}
return 1; // success
};
static auto ompt_finalize = [](ompt_data_t* tool_data) {
TIMEMORY_PRINTF(stderr, "OpenMP-tools finalized\n\n");
tim::consume_parameters(tool_data);
if(_use_ompt)
{
TIMEMORY_PRINTF(stderr, "OpenMP-tools finalized\n\n");
tim::consume_parameters(tool_data);
}
};
static auto data = ompt_start_tool_result_t{ ompt_initialize, ompt_finalize, { 0 } };
@@ -572,8 +572,15 @@ post_process_perfetto()
{
for(size_t i = 0; i < _n; ++i)
{
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
auto _plus = [](auto& _lhs, auto&& _rhs) { _lhs += _rhs; };
std::visit(_plus, _values.at(i), vitr->feature_values.at(i));
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
}
}
}
@@ -103,6 +103,9 @@ namespace sampling
{
namespace
{
std::set<int>
configure(bool _setup, int64_t _tid = threading::get_id());
template <typename... Args>
void
thread_sigmask(Args... _args)
@@ -163,6 +166,20 @@ get_sampler_running(int64_t _tid)
return _v.at(_tid);
}
auto&
get_duration_disabled()
{
static auto _v = std::atomic<bool>{ false };
return _v;
}
auto&
get_is_duration_thread()
{
static thread_local auto _v = false;
return _v;
}
auto&
get_duration_cv()
{
@@ -170,6 +187,13 @@ get_duration_cv()
return _v;
}
auto&
get_duration_mutex()
{
static auto _v = std::mutex{};
return _v;
}
auto&
get_duration_thread()
{
@@ -177,6 +201,28 @@ get_duration_thread()
return _v;
}
auto
notify_duration_thread()
{
if(get_duration_thread() && !get_is_duration_thread())
{
std::unique_lock<std::mutex> _lk{ get_duration_mutex(), std::defer_lock };
if(!_lk.owns_lock()) _lk.lock();
get_duration_cv().notify_all();
}
}
void
stop_duration_thread()
{
if(get_duration_thread() && !get_is_duration_thread())
{
notify_duration_thread();
get_duration_thread()->join();
get_duration_thread().reset();
}
}
void
start_duration_thread()
{
@@ -195,12 +241,14 @@ start_duration_thread()
config::get_sampling_duration() * units::sec) };
auto _func = [_end]() {
thread_info::init(true);
std::mutex _mutex{};
bool _wait = true;
threading::set_thread_name("omni.samp.dur");
get_is_duration_thread() = true;
bool _wait = true;
while(_wait)
{
_wait = false;
std::unique_lock<std::mutex> _lk{ _mutex };
std::unique_lock<std::mutex> _lk{ get_duration_mutex(), std::defer_lock };
if(!_lk.owns_lock()) _lk.lock();
get_duration_cv().wait_until(_lk, _end);
auto _premature = (std::chrono::steady_clock::now() < _end);
auto _finalized = (get_state() == State::Finalized);
@@ -218,11 +266,12 @@ start_duration_thread()
}
else
{
get_duration_disabled().store(true);
OMNITRACE_VERBOSE(1,
"Sampling duration of %f seconds has elapsed. "
"Shutting down sampling...\n",
config::get_sampling_duration());
shutdown();
configure(false, 0);
}
}
};
@@ -237,7 +286,7 @@ start_duration_thread()
}
std::set<int>
configure(bool _setup, int64_t _tid = threading::get_id())
configure(bool _setup, int64_t _tid)
{
const auto& _info = thread_info::get(_tid, SequentTID);
auto& _sampler = sampling::get_sampler(_tid);
@@ -266,6 +315,8 @@ configure(bool _setup, int64_t _tid = threading::get_id())
if(_setup && !_sampler && !_is_running && !_signal_types->empty())
{
if(get_duration_disabled()) return std::set<int>{};
// if this thread has an offset ID, that means it was created internally
// and is probably here bc it called a function which was instrumented.
// thus we should not start a sampler for it
@@ -356,7 +407,8 @@ configure(bool _setup, int64_t _tid = threading::get_id())
sampling::block_signals(*_signal_types);
}
get_duration_cv().notify_one();
notify_duration_thread();
if(_tid == 0)
{
// this propagates to all threads
@@ -371,11 +423,7 @@ configure(bool _setup, int64_t _tid = threading::get_id())
}
}
if(get_duration_thread())
{
get_duration_thread()->join();
get_duration_thread().reset();
}
stop_duration_thread();
}
_sampler->stop();
@@ -416,7 +464,9 @@ setup()
std::set<int>
shutdown()
{
return configure(false);
auto _v = configure(false);
if(utility::get_thread_index() == 0) stop_duration_thread();
return _v;
}
void
@@ -534,10 +584,10 @@ post_process()
if(_data.empty())
{
OMNITRACE_VERBOSE(
3 || get_debug_sampling(),
"Sampler data for thread %lu has %zu valid entries... (skipped)\n", i,
_raw_data.size());
OMNITRACE_VERBOSE(2 || get_debug_sampling(),
"Sampler data for thread %lu has zero valid entries out of "
"%zu... (skipped)\n",
i, _raw_data.size());
continue;
}
@@ -619,35 +669,64 @@ post_process_perfetto(int64_t _tid, const bundle_t* _init,
static std::set<std::string> _static_strings{};
for(const auto& iitr : backtrace::filter_and_patch(_bt_cs->get()))
{
const auto* _name = _static_strings.emplace(iitr.name).first->c_str();
uint64_t _beg = _last_ts;
uint64_t _end = _bt_ts->get_timestamp();
uint64_t _beg = _last_ts;
uint64_t _end = _bt_ts->get_timestamp();
if(!_thread_info->is_valid_lifetime({ _beg, _end })) continue;
tracing::push_perfetto_ts(
category::sampling{}, _name, _beg, [&](perfetto::EventContext ctx) {
tracing::add_perfetto_annotation(ctx, "begin_ns", _beg);
tracing::add_perfetto_annotation(ctx, "file", iitr.location);
tracing::add_perfetto_annotation(ctx, "pc",
_as_hex(iitr.address));
tracing::add_perfetto_annotation(ctx, "line_address",
_as_hex(iitr.line_address));
if(iitr.lineinfo)
{
size_t _n = 0;
for(const auto& litr : iitr.lineinfo.lines)
{
auto _label = JOIN('-', "lineinfo", _n++);
tracing::add_perfetto_annotation(
ctx, _label.c_str(),
JOIN('@', demangle(litr.name),
JOIN(':', litr.location, litr.line)));
}
}
});
if(get_sampling_include_inlines() && iitr.lineinfo)
{
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& litr : _lines)
{
const auto* _name =
_static_strings.emplace(demangle(litr.name)).first->c_str();
auto _info = JOIN(':', litr.location, litr.line);
tracing::push_perfetto_ts(
category::sampling{}, _name, _beg,
[&](perfetto::EventContext ctx) {
tracing::add_perfetto_annotation(ctx, "begin_ns", _beg);
tracing::add_perfetto_annotation(ctx, "lineinfo", _info);
tracing::add_perfetto_annotation(ctx, "inlined",
(_n++ > 0));
});
tracing::pop_perfetto_ts(category::sampling{}, _name, _end,
"end_ns", _end);
}
}
else
{
const auto* _name = _static_strings.emplace(iitr.name).first->c_str();
tracing::push_perfetto_ts(
category::sampling{}, _name, _beg,
[&](perfetto::EventContext ctx) {
tracing::add_perfetto_annotation(ctx, "begin_ns", _beg);
tracing::add_perfetto_annotation(ctx, "file", iitr.location);
tracing::add_perfetto_annotation(ctx, "pc",
_as_hex(iitr.address));
tracing::add_perfetto_annotation(ctx, "line_address",
_as_hex(iitr.line_address));
tracing::pop_perfetto_ts(category::sampling{}, _name, _end, "end_ns",
_end);
if(iitr.lineinfo)
{
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& litr : _lines)
{
auto _label = JOIN('-', "lineinfo", _n++);
tracing::add_perfetto_annotation(
ctx, _label.c_str(),
JOIN('@', demangle(litr.name),
JOIN(':', litr.location, litr.line)));
}
}
});
tracing::pop_perfetto_ts(category::sampling{}, _name, _end, "end_ns",
_end);
}
}
_last_ts = _bt_ts->get_timestamp();
}
@@ -53,17 +53,20 @@ init_index_data(int64_t _tid, bool _offset = false)
if(!itr)
{
threading::offset_this_id(_offset);
itr = thread_index_data{};
itr = thread_index_data{};
int _verb = 2;
// if thread created using finalization, bump up the minimum verbosity level
if(get_state() == State::Finalized && _offset) _verb += 2;
if(!config::settings_are_configured())
{
OMNITRACE_BASIC_VERBOSE_F(
2, "Thread %li on PID %i (rank: %i) assigned omnitrace TID %li\n",
_verb, "Thread %li on PID %i (rank: %i) assigned omnitrace TID %li\n",
itr->system_value, process::get_id(), dmp::rank(), itr->sequent_value);
}
else
{
OMNITRACE_VERBOSE_F(
2, "Thread %li on PID %i (rank: %i) assigned omnitrace TID %li\n",
_verb, "Thread %li on PID %i (rank: %i) assigned omnitrace TID %li\n",
itr->system_value, process::get_id(), dmp::rank(), itr->sequent_value);
}
}
@@ -149,10 +152,12 @@ thread_info::set_stop(uint64_t _ts)
{
for(auto& itr : thread_info_data_t::instances())
{
if(itr && itr->index_data && itr->index_data->internal_value > _tid)
if(itr && itr->index_data && itr->index_data->internal_value != _tid)
{
if(itr->lifetime.second > _v->lifetime.second)
itr->lifetime.second = _v->lifetime.second;
else if(itr->lifetime.second == 0)
itr->lifetime.second = _v->lifetime.second;
}
}
}
@@ -47,6 +47,7 @@ set(_flat_environment
"OMNITRACE_TIMELINE_PROFILE=OFF"
"OMNITRACE_COLLAPSE_PROCESSES=ON"
"OMNITRACE_COLLAPSE_THREADS=ON"
"OMNITRACE_SAMPLING_FREQ=50"
"OMNITRACE_TIMEMORY_COMPONENTS=wall_clock,trip_count"
"${_test_openmp_env}"
"${_test_library_path}")
@@ -54,7 +55,7 @@ set(_flat_environment
set(_lock_environment
"OMNITRACE_USE_SAMPLING=ON"
"OMNITRACE_USE_PROCESS_SAMPLING=OFF"
"OMNITRACE_SAMPLING_FREQ=250"
"OMNITRACE_SAMPLING_FREQ=750"
"OMNITRACE_CRITICAL_TRACE=ON"
"OMNITRACE_COLLAPSE_THREADS=ON"
"OMNITRACE_TRACE_THREAD_LOCKS=ON"
@@ -233,7 +234,7 @@ endfunction()
# -------------------------------------------------------------------------------------- #
function(OMNITRACE_ADD_TEST)
foreach(_PREFIX RUNTIME REWRITE REWRITE_RUN BASELINE)
foreach(_PREFIX PRELOAD RUNTIME REWRITE REWRITE_RUN BASELINE)
foreach(_TYPE PASS FAIL SKIP)
list(APPEND _REGEX_OPTS "${_PREFIX}_${_TYPE}_REGEX")
endforeach()
@@ -243,10 +244,9 @@ function(OMNITRACE_ADD_TEST)
cmake_parse_arguments(
TEST
"SKIP_BASELINE;SKIP_REWRITE;SKIP_RUNTIME;SKIP_SAMPLING;FORCE_SAMPLING" # options
"NAME;TARGET;MPI;GPU;NUM_PROCS;REWRITE_TIMEOUT;RUNTIME_TIMEOUT" # single value
# args
"${_KWARGS}" # multiple value args
"SKIP_BASELINE;SKIP_PRELOAD;SKIP_REWRITE;SKIP_RUNTIME;SKIP_SAMPLING;FORCE_SAMPLING"
"NAME;TARGET;MPI;GPU;NUM_PROCS;REWRITE_TIMEOUT;RUNTIME_TIMEOUT;PRELOAD"
"${_KWARGS}"
${ARGN})
if(TEST_GPU AND NOT _VALID_GPU)
@@ -278,6 +278,10 @@ function(OMNITRACE_ADD_TEST)
set(TEST_RUNTIME_TIMEOUT 300)
endif()
if(NOT TEST_PRELOAD_TIMEOUT)
set(TEST_PRELOAD_TIMEOUT 120)
endif()
if(NOT DEFINED TEST_ENVIRONMENT OR "${TEST_ENVIRONMENT}" STREQUAL "")
set(TEST_ENVIRONMENT "${_test_environment}")
endif()
@@ -308,6 +312,14 @@ function(OMNITRACE_ADD_TEST)
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
endif()
if(NOT TEST_SKIP_PRELOAD)
add_test(
NAME ${TEST_NAME}-preload
COMMAND ${COMMAND_PREFIX} $<TARGET_FILE:omnitrace-sample> --
$<TARGET_FILE:${TEST_TARGET}> ${TEST_RUN_ARGS}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
endif()
if(NOT TEST_SKIP_REWRITE)
add_test(
NAME ${TEST_NAME}-binary-rewrite
@@ -370,27 +382,29 @@ function(OMNITRACE_ADD_TEST)
foreach(
_TEST
baseline binary-rewrite binary-rewrite-run binary-rewrite-sampling
baseline preload binary-rewrite binary-rewrite-run binary-rewrite-sampling
binary-rewrite-sampling-run runtime-instrument runtime-instrument-sampling)
string(REGEX REPLACE "-run(-|/)" "\\1" _prefix "${TEST_NAME}-${_TEST}/")
set(_environ "${TEST_ENVIRONMENT}")
set(_labels "${_TEST}")
set(_timeout ${TEST_REWRITE_TIMEOUT})
list(APPEND _environ "OMNITRACE_OUTPUT_PATH=omnitrace-tests-output"
"OMNITRACE_OUTPUT_PREFIX=${_prefix}")
set(_labels "${TEST_LABELS}" "${_TEST}")
string(REPLACE "-run" "" _labels "${_TEST}")
string(REPLACE "-sampling" ";sampling" _labels "${_labels}")
if(TEST_TARGET)
list(APPEND _labels "${TEST_TARGET}")
endif()
if("${_TEST}" MATCHES "runtime-instrument")
set(_environ
"${TEST_ENVIRONMENT}" "OMNITRACE_OUTPUT_PATH=omnitrace-tests-output"
"OMNITRACE_OUTPUT_PREFIX=${_prefix}")
set(_timeout ${TEST_REWRITE_TIMEOUT})
if("${_TEST}" MATCHES "preload")
set(_timeout ${TEST_PRELOAD_TIMEOUT})
elseif("${_TEST}" MATCHES "runtime-instrument")
set(_timeout ${TEST_RUNTIME_TIMEOUT})
endif()
if("${_TEST}" MATCHES "binary-rewrite-run")
list(APPEND _labels "binary-rewrite-run")
endif()
set(_props)
if("${_TEST}" MATCHES "run|baseline")
if("${_TEST}" MATCHES "run|preload|baseline")
set(_props ${TEST_PROPERTIES})
if(NOT "RUN_SERIAL" IN_LIST _props)
list(APPEND _props RUN_SERIAL ON)
@@ -405,6 +419,8 @@ function(OMNITRACE_ADD_TEST)
set(_REGEX_VAR REWRITE)
elseif("${_TEST}" MATCHES "baseline")
set(_REGEX_VAR BASELINE)
elseif("${_TEST}" MATCHES "preload")
set(_REGEX_VAR PRELOAD)
else()
set(_REGEX_VAR)
endif()
@@ -426,7 +442,7 @@ function(OMNITRACE_ADD_TEST)
TIMEOUT
${_timeout}
LABELS
"${_labels};${TEST_LABELS}"
"${_labels}"
PASS_REGULAR_EXPRESSION
"${${_PASS_REGEX}}"
FAIL_REGULAR_EXPRESSION
@@ -647,7 +663,7 @@ omnitrace_add_test(
NUM_PROCS ${NUM_PROCS}
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
ENVIRONMENT
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_COUT_OUTPUT=ON;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
REWRITE_RUN_PASS_REGEX
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
)
@@ -662,7 +678,7 @@ omnitrace_add_test(
NUM_PROCS ${NUM_PROCS}
REWRITE_ARGS -e -v 2 -E uniform_int_distribution
ENVIRONMENT
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_COUT_OUTPUT=ON;OMNITRACE_USE_ROCTRACER=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_ROCTRACER=OFF;OMNITRACE_ROCM_EVENTS=${OMNITRACE_ROCM_EVENTS_TEST}"
REWRITE_RUN_PASS_REGEX
"rocprof-device-0-GRBM_COUNT.txt(.*)rocprof-device-0-GPUBusy.txt(.*)rocprof-device-0-SQ_WAVES.txt(.*)rocprof-device-0-SQ_INSTS_VALU.txt(.*)rocprof-device-0-VALUInsts.txt(.*)rocprof-device-0-TCC_HIT_sum.txt(.*)rocprof-device-0-TA_TA_BUSY_0.txt(.*)rocprof-device-0-TA_TA_BUSY_11.txt"
REWRITE_RUN_FAIL_REGEX "roctracer.txt")
@@ -782,7 +798,6 @@ if(OMNITRACE_USE_MPI OR OMNITRACE_USE_MPI_HEADERS)
--label
file
line
return
args
--min-instructions
0
@@ -806,7 +821,6 @@ if(OMNITRACE_USE_MPI OR OMNITRACE_USE_MPI_HEADERS)
--label
file
line
return
args
--min-instructions
0
@@ -836,9 +850,9 @@ omnitrace_add_test(
-ME
[==[lib(gomp|m-)]==]
LABELS "kokkos;kokkos-profile-library"
RUN_ARGS -i 10 -s 20 -p
RUN_ARGS -i 25 -s 20 -p
ENVIRONMENT
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;KOKKOS_PROFILE_LIBRARY=libomnitrace-dl.so"
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;OMNITRACE_SAMPLING_FREQ=50;KOKKOS_PROFILE_LIBRARY=libomnitrace-dl.so"
REWRITE_RUN_PASS_REGEX "\\|_\\[kokkos\\]"
RUNTIME_PASS_REGEX "\\|_\\[kokkos\\]")
@@ -852,9 +866,8 @@ omnitrace_add_test(
LABELS "kokkos;kokkos-profile-library"
RUN_ARGS -i 10 -s 20 -p
ENVIRONMENT
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;KOKKOS_PROFILE_LIBRARY=libomnitrace.so"
BASELINE_PASS_REGEX
"\\|_\\[kokkos\\]")
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;OMNITRACE_SAMPLING_FREQ=50;KOKKOS_PROFILE_LIBRARY=libomnitrace.so"
BASELINE_PASS_REGEX "\\|_\\[kokkos\\]")
omnitrace_add_test(
SKIP_RUNTIME SKIP_REWRITE
@@ -866,9 +879,8 @@ omnitrace_add_test(
LABELS "kokkos;kokkos-profile-library"
RUN_ARGS -i 10 -s 20 -p
ENVIRONMENT
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;KOKKOS_PROFILE_LIBRARY=libomnitrace-dl.so"
BASELINE_PASS_REGEX
"\\|_\\[kokkos\\]")
"${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF;OMNITRACE_USE_KOKKOSP=ON;OMNITRACE_COUT_OUTPUT=ON;OMNITRACE_SAMPLING_FREQ=50;KOKKOS_PROFILE_LIBRARY=libomnitrace-dl.so"
BASELINE_PASS_REGEX "\\|_\\[kokkos\\]")
omnitrace_add_test(
SKIP_BASELINE
@@ -972,10 +984,46 @@ omnitrace_add_test(
REWRITE_TIMEOUT 180
RUNTIME_TIMEOUT 360
ENVIRONMENT
"${_ompt_environment};OMNITRACE_USE_SAMPLING=ON;OMNITRACE_SAMPLING_FREQ=100;OMNITRACE_COUT_OUTPUT=ON"
"${_ompt_environment};OMNITRACE_USE_SAMPLING=ON;OMNITRACE_SAMPLING_FREQ=50;OMNITRACE_COUT_OUTPUT=ON"
REWRITE_RUN_PASS_REGEX "${_OMPT_PASS_REGEX}"
REWRITE_FAIL_REGEX "0 instrumented loops in procedure")
set(_ompt_preload_environ
"${_ompt_environment}"
"OMNITRACE_USE_OMPT=OFF"
"OMNITRACE_USE_SAMPLING=ON"
"OMNITRACE_USE_PROCESS_SAMPLING=OFF"
"OMNITRACE_SAMPLING_FREQ=100"
"OMNITRACE_SAMPLING_DELAY=0.1"
"OMNITRACE_SAMPLING_DURATION=0.25"
"OMNITRACE_SAMPLING_CPUTIME=ON"
"OMNITRACE_SAMPLING_REALTIME=ON"
"OMNITRACE_SAMPLING_CPUTIME_FREQ=1000"
"OMNITRACE_SAMPLING_REALTIME_FREQ=500")
set(_ompt_preload_samp_regex
"Sampler for thread 0 will be triggered 1000.0x per second of CPU-time(.*)Sampler for thread 0 will be triggered 500.0x per second of wall-time(.*)Sampling will be disabled after 0.250000 seconds(.*)Sampling duration of 0.250000 seconds has elapsed. Shutting down sampling"
)
set(_ompt_preload_file_regex
"sampling-duration-preload/sampling_percent.(json|txt)(.*)sampling-duration-preload/sampling_cpu_clock.(json|txt)(.*)sampling-duration-preload/sampling_wall_clock.(json|txt)"
)
omnitrace_add_test(
SKIP_BASELINE SKIP_RUNTIME SKIP_REWRITE SKIP_SAMPLING
NAME openmp-cg-sampling-duration
TARGET openmp-cg
LABELS "openmp;sampling-duration"
ENVIRONMENT "${_ompt_preload_environ}"
PRELOAD_PASS_REGEX "${_ompt_preload_samp_regex}(.*)${_ompt_preload_file_regex}")
omnitrace_add_test(
SKIP_BASELINE SKIP_RUNTIME SKIP_REWRITE SKIP_SAMPLING
NAME openmp-lu-sampling-duration
TARGET openmp-lu
LABELS "openmp;sampling-duration"
ENVIRONMENT "${_ompt_preload_environ}"
PRELOAD_PASS_REGEX "${_ompt_preload_samp_regex}(.*)${_ompt_preload_file_regex}")
omnitrace_add_test(
SKIP_BASELINE SKIP_SAMPLING
NAME code-coverage