Reorganization and critical trace support (#17)

* Roctracer wall clock integration (#16)

* Integrates roctracer values into wall-clock

* Fixed scoping + timemory roctracer

* Fixed data race in roctracer

* Synchronized HIP API on main thread

- Cache hip activity callbacks and execute on main thread
- Minor updates to transpose

* Debugging + MPI + transpose updates

* PTL + HSA and timemory + kernel timing

- PTL usage fixed HSA + timemory issues bc we could control the thread destruction
- Fixed laps counting in roctracer callbacks

* Ignore select HIP API types

- The ignored API types are ignored because there appears to be a bug
  which causes the "end" callback to be labeled as begin
- hipDeviceEnablePeerAccess
- hipImportExternalMemory
- hipDestroyExternalMemory

* Tweaks to PTL config

* Timemory update + pid-prefix w/ mpi headers

- %pid%- prefix with mpi headers
- timemory submodule update

* CMake + critical trace + reorganize library source

- clang-tidy tweaks
- cmake function updates to use hosttrace_ prefix
- update gitignore
- cmake HOSTTRACE_MAX_THREADS option
- Formatting.cmake
- cleaned up MacroUtilities.cmake
- PTL submodule + usage
- tweak to Findroctracer.cmake
- MT transpose
- Updated PTL submodule
- Updated timemory submodule
- fix to hosttrace return value type if type not found
- reorganized library source code
- support for critical trace

* Remove bits/stdint-uintn.h headers

* Rename + config + depth + critical path

- rename hosttrace_timemory_data to instrumentation_bundles
- rename hosttrace_bundle_t to main_bundle_t
- rename bundle_t to instrumentation_bundle_t
- rework of configuration setup
- critical_trace write directly to file option
- tweaked depth calculation
- updated timemory submodule
- improved parallel support in roctracer callbacks
- working critical_trace
- perfetto device-critical-trace and host-critical-trace categories
- made transpose example parallel
- made parallel-overhead example a bit uneven
- relocated LTO activation

* Fixed duplicates in perfetto critical-trace

* reworked critical trace support

- substantial perf improvement (30-45 min -> 30 sec)
- changes to configuration (new and removed options)

* Removed "%pid%-" output prefix in mpi_gotcha

* Update timemory submodule

[ROCm/rocprofiler-systems commit: 752424efc2]
Этот коммит содержится в:
Jonathan R. Madsen authored and GitHub committed 2021-11-23 02:53:14 -06:00
1 родитель cdd2707058
Коммит efb6d766af
52 files changed
+7785 -2394

No files matched your search

+19 -16
Просмотреть файл
@@ -1,27 +1,30 @@
// 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.
// Copyright (c) 2018 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
// with 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.
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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.
//
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "hosttrace.hpp"
@@ -1183,7 +1186,7 @@ main(int argc, char** argv)
auto mpie_fini_args = hosttrace_call_expr("HOSTTRACE_MPI_FINALIZE", "OFF");
auto trace_call_args =
hosttrace_call_expr("HOSTTRACE_COMPONENTS", default_components);
auto use_mpi_call_args = hosttrace_call_expr("HOSTTRACE_USE_MPI", "ON");
auto use_mpi_call_args = hosttrace_call_expr("HOSTTRACE_USE_PID", "ON");
auto use_mpip_call_args = hosttrace_call_expr(
"HOSTTRACE_USE_MPIP", (binary_rewrite && use_mpi && use_mpip) ? "ON" : "OFF");
auto none_call_args = hosttrace_call_expr();
@@ -1777,7 +1780,7 @@ main(int argc, char** argv)
const auto& outf = outfile;
if(outf.find('/') != string_t::npos)
{
auto outdir = outf.substr(0, outf.find_last_of('/') - 1);
auto outdir = outf.substr(0, outf.find_last_of('/'));
tim::makedir(outdir);
}
@@ -1,26 +1,30 @@
// 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.
// Copyright (c) 2018 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
// with 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.
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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.
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "hosttrace.hpp"
@@ -47,7 +51,7 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
const char* typeName = nullptr;
std::string typeName = {};
mutatee_module->getName(mname, MUTNAMELEN);
@@ -73,8 +77,6 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
@@ -148,8 +150,8 @@ get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
int row1, col1, row2, col2;
string_t filename;
string_t typeName;
string_t filename = {};
string_t typeName = {};
mutatee_module->getName(mname, MUTNAMELEN);
@@ -164,8 +166,6 @@ get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
+186 -152
Просмотреть файл
@@ -1,51 +1,39 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library.hpp"
bool
get_debug()
{
static bool _v = tim::get_env("HOSTTRACE_DEBUG", false);
return _v;
}
State&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
bool
get_use_perfetto()
{
// if using timemory, default to perfetto being off
static auto _default_v = !tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", false, false);
// explicit env control for using perfetto
static auto _v = tim::get_env<bool>("HOSTTRACE_USE_PERFETTO", _default_v);
return _v;
}
bool
get_use_timemory()
{
// default to opposite of whether perfetto setting
// to use both timemory and perfetto, both HOSTTRACE_USE_TIMEMORY and
// HOSTTRACE_USE_PERFETTO must be true
static auto _v = tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", !get_use_perfetto());
return _v;
}
//--------------------------------------------------------------------------------------//
#include "library/config.hpp"
#include "library/critical_trace.hpp"
#include "library/thread_data.hpp"
#include <string_view>
namespace
{
size_t&
get_sample_rate()
{
static auto _v = tim::get_env<size_t>("HOSTTRACE_SAMPLE_RATE", 1);
return _v;
}
std::vector<bool>&
get_sample_data()
{
@@ -53,17 +41,6 @@ get_sample_data()
return _v;
}
bool&
get_use_mpi()
{
#if defined(TIMEMORY_USE_MPI)
static bool _v = tim::get_env("HOSTTRACE_USE_MPI", false);
#else
static bool _v = false;
#endif
return _v;
}
void
setup_gotchas()
{
@@ -83,16 +60,17 @@ setup_gotchas()
mpi_gotcha_t::template configure<0, int, int*, char***>("MPI_Init");
mpi_gotcha_t::template configure<1, int, int*, char***, int, int*>(
"MPI_Init_thread");
#if defined(HOSTTRACE_USE_MPI_HEADERS)
mpi_gotcha_t::template configure<3, int>("MPI_Finalize");
#endif
};
}
auto
ensure_finalization()
ensure_finalization(bool _static_init = false)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
if(!_static_init)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
}
return scope::destructor{ []() { hosttrace_trace_finalize(); } };
}
@@ -103,45 +81,6 @@ get_trace_session()
return _session;
}
auto
get_perfetto_output_filename()
{
static auto _v = []() {
// default name: perfetto-trace.<pid>.proto or perfetto-trace.<rank>.proto
auto _default_fname = tim::settings::compose_output_filename(
JOIN('.', "perfetto-trace", (get_use_mpi()) ? "%rank%" : "%pid%"), "proto");
// have the default display the full path to the output file
return tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false), _default_fname));
}();
auto _tmp = _v;
auto _replace = [&_tmp](const std::string& _key, auto&& _val) {
auto _pos = _tmp.find(_key);
if(_pos != std::string::npos)
_tmp.replace(_pos, _key.length(), std::to_string(_val()));
};
_replace("%pid%", []() { return process::get_id(); });
_replace("%rank%", []() { return tim::mpi::rank(); });
// backwards compatibility
_replace("%p", []() { return process::get_id(); });
return _tmp;
}
auto&
get_backend()
{
// select inprocess, system, or both (i.e. all)
static auto _v = tim::get_env_choice<std::string>(
"HOSTTRACE_BACKEND",
tim::get_env("HOSTTRACE_BACKEND_SYSTEM", false, false)
? "system" // if HOSTTRACE_BACKEND_SYSTEM is true, default to system.
: "inprocess", // Otherwise, default to inprocess
{ "inprocess", "system", "all" });
return _v;
}
auto
is_system_backend()
{
@@ -150,10 +89,10 @@ is_system_backend()
}
auto&
get_timemory_data()
get_instrumentation_bundles()
{
static thread_local auto& _v =
hosttrace_timemory_data::instances().at(threading::get_id());
instrumentation_bundles::instances().at(threading::get_id());
return _v;
}
@@ -166,6 +105,17 @@ get_functors()
return _v;
}
auto&
get_cpu_cid_parents()
{
static thread_local auto _v =
std::unordered_map<uint64_t, std::tuple<uint64_t, uint16_t>>{};
return _v;
}
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
bool
hosttrace_init_tooling()
{
@@ -184,26 +134,17 @@ hosttrace_init_tooling()
return false;
}
// always initialize timemory because gotcha wrappers are always used
tim::settings::flamegraph_output() = false;
tim::settings::cout_output() = false;
tim::settings::file_output() = true;
tim::settings::enable_signal_handler() = true;
tim::settings::collapse_processes() = false;
tim::settings::collapse_threads() = false;
tim::settings::max_thread_bookmarks() = 1;
tim::settings::global_components() = tim::get_env<std::string>(
"HOSTTRACE_COMPONENTS", "wall_clock", get_use_timemory());
int _threadpool_verbose = (get_debug()) ? 4 : -1;
tasking::get_roctracer_thread_pool().set_verbose(_threadpool_verbose);
tasking::get_critical_trace_thread_pool().set_verbose(_threadpool_verbose);
// enable timestamp directories when perfetto + mpi is activated
if(get_use_perfetto() && get_use_mpi()) tim::settings::time_output() = true;
// below will effectively do:
// get_cpu_cid_stack(0)->emplace_back(-1);
// plus query some env variables
add_critical_trace<Device::CPU, Phase::NONE>(0, -1, 0, 0, 0, 0, 0, 0);
auto _cmd = tim::read_command_line(process::get_id());
auto _exe = (_cmd.empty()) ? "hosttrace" : _cmd.front();
auto _pos = _exe.find_last_of('/');
if(_pos < _exe.length() - 1) _exe = _exe.substr(_pos + 1);
tim::timemory_init({ _exe }, "hosttrace-");
// configure the settings
configure_settings();
if(get_sample_rate() < 1) get_sample_rate() = 1;
get_sample_data().reserve(512);
@@ -218,16 +159,18 @@ hosttrace_init_tooling()
if(_comps.size() == 1 && _comps.find(TIMEMORY_WALL_CLOCK) != _comps.end())
{
// using wall_clock directly is lower overhead than using it via user_bundle
bundle_t::get_initializer() = [](bundle_t& _bundle) {
_bundle.initialize<comp::wall_clock>();
};
instrumentation_bundle_t::get_initializer() =
[](instrumentation_bundle_t& _bundle) {
_bundle.initialize<comp::wall_clock>();
};
}
else if(!_comps.empty())
{
// use user_bundle for other than wall-clock
bundle_t::get_initializer() = [](bundle_t& _bundle) {
_bundle.initialize<comp::user_global_bundle>();
};
instrumentation_bundle_t::get_initializer() =
[](instrumentation_bundle_t& _bundle) {
_bundle.initialize<comp::user_global_bundle>();
};
}
else
{
@@ -252,9 +195,8 @@ hosttrace_init_tooling()
if(get_use_perfetto())
{
// environment settings
auto shmem_size_hint =
tim::get_env<size_t>("HOSTTRACE_SHMEM_SIZE_HINT_KB", 40960);
auto buffer_size = tim::get_env<size_t>("HOSTTRACE_BUFFER_SIZE_KB", 1024000);
auto shmem_size_hint = get_perfetto_shmem_size_hint();
auto buffer_size = get_perfetto_buffer_size();
auto* buffer_config = cfg.add_buffers();
buffer_config->set_size_kb(buffer_size);
@@ -276,6 +218,7 @@ hosttrace_init_tooling()
(void) get_perfetto_output_filename();
}
auto _exe = get_exe_name();
static auto _thread_init = [_exe]() {
hosttrace_thread_data<hosttrace_thread_bundle_t>::construct(
TIMEMORY_JOIN("", _exe, "/thread-", threading::get_id()),
@@ -285,10 +228,11 @@ hosttrace_init_tooling()
} };
(void) _dtor;
};
// functors for starting and stopping timemory
static auto _push_timemory = [](const char* name) {
_thread_init();
auto& _data = get_timemory_data();
auto& _data = get_instrumentation_bundles();
// this generates a hash for the raw string array
auto _hash = tim::add_hash_id(tim::string_view_t{ name });
auto* _bundle = _data.allocator.allocate(1);
@@ -311,7 +255,7 @@ hosttrace_init_tooling()
};
static auto _pop_timemory = [](const char* name) {
auto& _data = get_timemory_data();
auto& _data = get_instrumentation_bundles();
if(_data.bundles.empty())
{
HOSTTRACE_DEBUG("[%s] skipped %s :: empty bundle stack\n",
@@ -358,8 +302,22 @@ hosttrace_init_tooling()
if(dmp::rank() == 0)
{
tim::print_env(std::cerr,
[](const std::string& _v) { return _v.find("HOSTTRACE_") == 0; });
// generic filter for filtering relevant options
auto _is_hosttrace_option = [](const auto& _v) {
#if !defined(HOSTTRACE_USE_ROCTRACER)
if(_v.find("HOSTTRACE_ROCTRACER_") == 0) return false;
#endif
if(!get_use_critical_trace() && _v.find("HOSTTRACE_CRITICAL_TRACE_") == 0)
return false;
return (_v.find("HOSTTRACE_") == 0) ||
((_v.find("TIMEMORY_") != 0) && (_v.find("SIGNAL_") != 0));
};
tim::print_env(std::cerr, [_is_hosttrace_option](const std::string& _v) {
return _is_hosttrace_option(_v);
});
print_config_settings(std::cerr, _is_hosttrace_option);
}
if(get_use_perfetto() && !is_system_backend())
@@ -421,6 +379,21 @@ extern "C"
auto _enabled = (_sample_idx++ % _sample_rate == 0);
get_sample_data().emplace_back(_enabled);
if(_enabled) get_functors().first(name);
if(get_use_critical_trace())
{
auto _ts = comp::wall_clock::record();
auto _cid = get_cpu_cid()++;
uint16_t _depth = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->size()
: get_cpu_cid_stack()->size() - 1;
auto _parent_cid = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->back()
: get_cpu_cid_stack()->back();
get_cpu_cid_parents().emplace(_cid, std::make_tuple(_parent_cid, _depth));
add_critical_trace<Device::CPU, Phase::BEGIN>(
threading::get_id(), _cid, 0, _parent_cid, _ts, 0,
critical_trace::add_hash_id(name), _depth);
}
}
void hosttrace_pop_trace(const char* name)
@@ -434,6 +407,20 @@ extern "C"
if(_sample_data.back()) get_functors().second(name);
_sample_data.pop_back();
}
if(get_use_critical_trace())
{
if(get_cpu_cid_stack() && !get_cpu_cid_stack()->empty())
{
auto _ts = comp::wall_clock::record();
auto _cid = get_cpu_cid_stack()->back();
uint64_t _parent_cid = 0;
uint16_t _depth = 0;
std::tie(_parent_cid, _depth) = get_cpu_cid_parents().at(_cid);
add_critical_trace<Device::CPU, Phase::END>(
threading::get_id(), _cid, 0, _parent_cid, _ts, _ts,
critical_trace::add_hash_id(name), _depth);
}
}
}
else
{
@@ -463,15 +450,19 @@ extern "C"
comp::roctracer::tear_down();
#endif
// join extra thread(s) used by roctracer
HOSTTRACE_DEBUG("[%s] waiting for all roctracer tasks to complete...\n",
__FUNCTION__);
tasking::get_roctracer_task_group().join();
// stop the main bundle and report the high-level metrics
if(get_main_bundle())
{
get_main_bundle()->stop();
int64_t _id = (get_use_mpi()) ? dmp::rank() : process::get_id();
std::stringstream _ss{};
_ss << "[" << __FUNCTION__ << "][" << _id << "] " << *get_main_bundle()
<< "\n";
std::cerr << _ss.str();
std::string _msg = JOIN("", *get_main_bundle());
auto _pos = _msg.find(">>> ");
if(_pos != std::string::npos) _msg = _msg.substr(_pos + 5);
HOSTTRACE_PRINT("%s\n", _msg.c_str());
get_main_bundle().reset();
}
@@ -484,14 +475,15 @@ extern "C"
if(itr && itr->get<comp::wall_clock>() &&
!itr->get<comp::wall_clock>()->get_is_running())
{
std::stringstream _ss{};
_ss << *itr << "\n";
std::cerr << _ss.str();
std::string _msg = JOIN("", *itr);
auto _pos = _msg.find(">>> ");
if(_pos != std::string::npos) _msg = _msg.substr(_pos + 5);
HOSTTRACE_PRINT("%s\n", _msg.c_str());
}
}
// ensure that all the MT instances are flushed
for(auto& itr : hosttrace_timemory_data::instances())
for(auto& itr : instrumentation_bundles::instances())
{
while(!itr.bundles.empty())
{
@@ -503,6 +495,44 @@ extern "C"
}
}
if(get_use_critical_trace())
{
// increase the thread-pool size
tasking::get_critical_trace_thread_pool().initialize_threadpool(
get_critical_trace_num_threads());
for(size_t i = 0; i < max_supported_threads; ++i)
{
using critical_trace_hash_data =
hosttrace_thread_data<critical_trace::hash_ids, critical_trace::id>;
if(critical_trace_hash_data::instances().at(i))
critical_trace::add_hash_id(
*critical_trace_hash_data::instances().at(i));
}
for(size_t i = 0; i < max_supported_threads; ++i)
{
using critical_trace_chain_data =
hosttrace_thread_data<critical_trace::call_chain>;
if(critical_trace_chain_data::instances().at(i))
critical_trace::update(i); // launch update task
}
// make sure outstanding hash tasks completed before compute
HOSTTRACE_PRINT("[%s] waiting for all critical trace tasks to complete...\n",
__FUNCTION__);
tasking::get_critical_trace_task_group().join();
// launch compute task
HOSTTRACE_PRINT("[%s] launching critical trace compute task...\n",
__FUNCTION__);
critical_trace::compute();
}
tasking::get_critical_trace_task_group().join();
bool _perfetto_output_error = false;
if(get_use_perfetto() && !is_system_backend())
{
@@ -530,20 +560,27 @@ extern "C"
static_cast<double>(trace_data.size()) / units::KB,
static_cast<double>(trace_data.size()) / units::MB,
static_cast<double>(trace_data.size()) / units::GB);
std::ofstream output{};
output.open(get_perfetto_output_filename(), std::ios::out | std::ios::binary);
if(!output)
std::ofstream ofs{};
if(!tim::filepath::open(ofs, get_perfetto_output_filename(),
std::ios::out | std::ios::binary))
{
fprintf(stderr, "[%s]> Error opening '%s'...\n", __FUNCTION__,
get_perfetto_output_filename().c_str());
_perfetto_output_error = true;
}
else
output.write(&trace_data[0], trace_data.size());
output.close();
ofs.write(&trace_data[0], trace_data.size());
ofs.close();
}
// these should be destroyed before timemory is finalized, especially the
// roctracer thread-pool
tasking::get_roctracer_thread_pool().destroy_threadpool();
tasking::get_critical_trace_thread_pool().destroy_threadpool();
HOSTTRACE_DEBUG("Finalizing timemory...\n");
tim::timemory_finalize();
HOSTTRACE_DEBUG("Finalizing timemory... Done\n");
if(_perfetto_output_error)
throw std::runtime_error("Unable to create perfetto output file");
@@ -564,20 +601,17 @@ extern "C"
{
auto& _main_bundle = get_main_bundle();
_main_bundle->start();
#if defined(TIMEMORY_USE_MPI)
tim::set_env("HOSTTRACE_USE_MPI", "ON", 1);
get_use_mpi() = true;
#endif
get_state() = State::DelayedInit;
get_use_pid() = true;
get_state() = State::DelayedInit;
}
}
}
std::unique_ptr<hosttrace_bundle_t>&
std::unique_ptr<main_bundle_t>&
get_main_bundle()
{
static auto _v =
(setup_gotchas(), std::make_unique<hosttrace_bundle_t>(
(setup_gotchas(), std::make_unique<main_bundle_t>(
"hosttrace", quirk::config<quirk::auto_start>{}));
return _v;
}
@@ -587,5 +621,5 @@ namespace
// if static objects are destroyed randomly (relatively uncommon behavior)
// this might call finalization before perfetto ends the tracing session
// but static variable in hosttrace_init_tooling is more likely
auto _ensure_finalization = ensure_finalization();
auto _ensure_finalization = ensure_finalization(true);
} // namespace
+528
Просмотреть файл
@@ -0,0 +1,528 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/thread_data.hpp"
#include "timemory/backends/dmp.hpp"
#include "timemory/backends/process.hpp"
#include "timemory/settings/types.hpp"
#include "timemory/utility/argparse.hpp"
#include <array>
#include <cstdint>
#include <cstdlib>
#include <numeric>
#include <ostream>
#include <string>
#include <timemory/environment.hpp>
#include <timemory/settings.hpp>
using settings = tim::settings;
namespace
{
auto
get_config()
{
static auto _once = (configure_settings(), true);
return settings::shared_instance();
(void) _once;
}
#define HOSTTRACE_CONFIG_SETTING(TYPE, ENV_NAME, DESCRIPTION, INITIAL_VALUE) \
_config->insert<TYPE, TYPE>(ENV_NAME, ENV_NAME, DESCRIPTION, INITIAL_VALUE, \
std::vector<std::string>{})
} // namespace
void
configure_settings()
{
static bool _once = false;
if(_once) return;
_once = true;
static auto _config = settings::shared_instance();
// auto* _config = settings::instance();
// if using timemory, default to perfetto being off
auto _default_perfetto_v =
!tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", false, false);
auto _default_config_file =
JOIN("/", tim::get_env<std::string>("HOME", "."), "hosttrace.cfg");
auto _system_backend = tim::get_env("HOSTTRACE_BACKEND_SYSTEM", false, false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_CONFIG_FILE",
"Configuration file of hosttrace and timemory settings",
_default_config_file);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_DEBUG", "Enable debugging output",
_config->get_debug());
auto _hosttrace_debug = _config->get<bool>("HOSTTRACE_DEBUG");
if(_hosttrace_debug) tim::set_env("TIMEMORY_DEBUG_SETTINGS", "1", 0);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_USE_PERFETTO", "Enable perfetto backend",
_default_perfetto_v);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_USE_TIMEMORY", "Enable timemory backend",
!_config->get<bool>("HOSTTRACE_USE_PERFETTO"));
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_USE_PID",
"Enable tagging filenames with process identifier (either MPI rank or pid)",
true);
HOSTTRACE_CONFIG_SETTING(
size_t, "HOSTTRACE_SAMPLE_RATE",
"Counts every function call (N), only record function if (N % <VALUE> == 0)", 1);
auto _backend = tim::get_env_choice<std::string>(
"HOSTTRACE_BACKEND",
(_system_backend)
? "system" // if HOSTTRACE_BACKEND_SYSTEM is true, default to system.
: "inprocess", // Otherwise, default to inprocess
{ "inprocess", "system", "all" }, false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_BACKEND",
"Specify the perfetto backend to activate. Options are: "
"'inprocess', 'system', or 'all'",
_backend);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_CRITICAL_TRACE",
"Enable generation of the critical trace", false);
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_ROCTRACER_TIMELINE_PROFILE",
"Create unique entries for every kernel with timemory backend",
_config->get_timeline_profile());
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_ROCTRACER_FLAT_PROFILE",
"Ignore hierarchy in all kernels entries with timemory backend",
_config->get_flat_profile());
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_ROCTRACER_HSA_ACTIVITY",
"Enable HSA activity tracing support", false);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_ROCTRACER_HSA_API",
"Enable HSA API tracing support", false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_ROCTRACER_HSA_API_TYPES",
"HSA API type to collect", "");
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_CRITICAL_TRACE_DEBUG",
"Enable debugging for critical trace", _hosttrace_debug);
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_CRITICAL_TRACE_SERIALIZE_NAMES",
"Include names in serialization of critical trace (mainly for debugging)",
_hosttrace_debug);
HOSTTRACE_CONFIG_SETTING(size_t, "HOSTTRACE_SHMEM_SIZE_HINT_KB",
"Hint for shared-memory buffer size in perfetto (in KB)",
40960);
HOSTTRACE_CONFIG_SETTING(size_t, "HOSTTRACE_BUFFER_SIZE_KB",
"Size of perfetto buffer (in KB)", 1024000);
HOSTTRACE_CONFIG_SETTING(int64_t, "HOSTTRACE_CRITICAL_TRACE_COUNT",
"Number of critical trace to export (0 == all)", 0);
HOSTTRACE_CONFIG_SETTING(uint64_t, "HOSTTRACE_CRITICAL_TRACE_BUFFER_COUNT",
"Number of critical trace records to store in thread-local "
"memory before submitting to shared buffer",
2000);
HOSTTRACE_CONFIG_SETTING(
uint64_t, "HOSTTRACE_CRITICAL_TRACE_NUM_THREADS",
"Number of threads to use when generating the critical trace",
std::min<uint64_t>(8, std::thread::hardware_concurrency()));
HOSTTRACE_CONFIG_SETTING(
int64_t, "HOSTTRACE_CRITICAL_TRACE_PER_ROW",
"How many critical traces per row in perfetto (0 == all in one row)", 0);
HOSTTRACE_CONFIG_SETTING(
std::string, "HOSTTRACE_COMPONENTS",
"List of components to collect via timemory (see timemory-avail)", "wall_clock");
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_OUTPUT_FILE", "Perfetto filename",
"");
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_SETTINGS_DESC",
"Provide descriptions when printing settings", false);
_config->get_flamegraph_output() = false;
_config->get_cout_output() = false;
_config->get_file_output() = true;
_config->get_json_output() = true;
_config->get_tree_output() = true;
_config->get_enable_signal_handler() = true;
_config->get_collapse_processes() = false;
_config->get_collapse_threads() = false;
_config->get_stack_clearing() = false;
_config->get_time_output() = true;
_config->get_timing_precision() = 6;
for(auto&& itr :
tim::delimit(_config->get<std::string>("HOSTTRACE_CONFIG_FILE"), ";:"))
{
HOSTTRACE_CONDITIONAL_BASIC_PRINT(true, "Reading config file %s\n", itr.c_str());
_config->read(itr);
}
_config->get_global_components() = _config->get<std::string>("HOSTTRACE_COMPONENTS");
// always initialize timemory because gotcha wrappers are always used
auto _cmd = tim::read_command_line(process::get_id());
auto _exe = (_cmd.empty()) ? "exe" : _cmd.front();
auto _pos = _exe.find_last_of('/');
if(_pos < _exe.length() - 1) _exe = _exe.substr(_pos + 1);
get_exe_name() = _exe;
scope::get_fields()[scope::flat::value] = tim::settings::flat_profile();
scope::get_fields()[scope::timeline::value] = tim::settings::timeline_profile();
bool _found_sep = false;
for(const auto& itr : _cmd)
{
if(itr == "--") _found_sep = true;
}
if(!_found_sep && _cmd.size() > 1) _cmd.insert(_cmd.begin() + 1, "--");
using argparser_t = tim::argparse::argument_parser;
argparser_t _parser{ _exe };
tim::timemory_init(_cmd, _parser, "hosttrace-");
settings::suppress_parsing() = true;
settings::suppress_config() = true;
settings::use_output_suffix() = _config->get<bool>("HOSTTRACE_USE_PID");
}
void
print_config_settings(std::ostream& _os,
std::function<bool(const std::string_view&)>&& _filter)
{
auto _flags = _os.flags();
constexpr size_t nfields = 3;
using str_array_t = std::array<std::string, nfields>;
std::vector<str_array_t> _data{};
std::array<size_t, nfields> _widths{};
_widths.fill(0);
for(const auto& itr : *get_config())
{
if(_filter(itr.first))
{
auto _disp = itr.second->get_display(std::ios::boolalpha);
_data.emplace_back(str_array_t{ _disp.at("name"), _disp.at("value"),
_disp.at("description") });
for(size_t i = 0; i < nfields; ++i)
_widths.at(i) =
std::max<size_t>(_widths.at(i), _data.back().at(i).length());
}
}
std::sort(_data.begin(), _data.end(), [](const auto& lhs, const auto& rhs) {
auto _npos = std::string::npos;
// HOSTTRACE_CONFIG_FILE always first
if(lhs.at(0).find("HOSTTRACE_CONFIG") != _npos) return true;
if(rhs.at(0).find("HOSTTRACE_CONFIG") != _npos) return false;
// HOSTTRACE_USE_* prioritized
auto _lhs_use = lhs.at(0).find("HOSTTRACE_USE_");
auto _rhs_use = rhs.at(0).find("HOSTTRACE_USE_");
if(_lhs_use != _rhs_use && _lhs_use < _rhs_use) return true;
if(_lhs_use != _rhs_use && _lhs_use > _rhs_use) return false;
// length sort followed by alphabetical sort
return (lhs.at(0).length() == rhs.at(0).length())
? (lhs.at(0) < rhs.at(0))
: (lhs.at(0).length() < rhs.at(0).length());
});
bool _print_desc = get_debug() || get_config()->get<bool>("HOSTTRACE_SETTINGS_DESC");
auto tot_width = std::accumulate(_widths.begin(), _widths.end(), 0);
if(!_print_desc) tot_width -= _widths.back() + 4;
std::stringstream _spacer{};
_spacer.fill('-');
_spacer << "#" << std::setw(tot_width + 11) << ""
<< "#";
_os << _spacer.str() << "\n";
// _os << "# Hosttrace settings:" << std::setw(tot_width - 8) << "#" << "\n";
for(const auto& itr : _data)
{
_os << "# ";
for(size_t i = 0; i < nfields; ++i)
{
switch(i)
{
case 0: _os << std::left; break;
case 1: _os << std::left; break;
case 2: _os << std::left; break;
}
_os << std::setw(_widths.at(i)) << itr.at(i) << " ";
if(!_print_desc && i == 1) break;
switch(i)
{
case 0: _os << "= "; break;
case 1: _os << "[ "; break;
case 2: _os << "]"; break;
}
}
_os << " #\n";
}
_os << _spacer.str() << "\n";
_os.setf(_flags);
}
std::string&
get_exe_name()
{
static std::string _v = {};
return _v;
}
std::string
get_config_file()
{
static auto _v = get_config()->find("HOSTTRACE_CONFIG_FILE");
return static_cast<tim::tsettings<std::string>&>(*_v->second).get();
}
bool
get_debug()
{
static auto _v = get_config()->find("HOSTTRACE_DEBUG");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_perfetto()
{
static auto _v = get_config()->find("HOSTTRACE_USE_PERFETTO");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_timemory()
{
static auto _v = get_config()->find("HOSTTRACE_USE_TIMEMORY");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool&
get_use_pid()
{
static auto _v = get_config()->find("HOSTTRACE_USE_PID");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_mpip()
{
static bool _v = tim::get_env("HOSTTRACE_USE_MPIP", false, false);
return _v;
}
bool
get_use_critical_trace()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_critical_trace_debug()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_DEBUG");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_critical_trace_serialize_names()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_SERIALIZE_NAMES");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_roctracer_timeline_profile()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_TIMELINE_PROFILE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_roctracer_flat_profile()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_FLAT_PROFILE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_trace_hsa_api()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_HSA_API");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_trace_hsa_activity()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_HSA_ACTIVITY");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
int64_t
get_critical_trace_per_row()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_PER_ROW");
return static_cast<tim::tsettings<int64_t>&>(*_v->second).get();
}
size_t
get_perfetto_shmem_size_hint()
{
static auto _v = get_config()->find("HOSTTRACE_SHMEM_SIZE_HINT_KB");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
size_t
get_perfetto_buffer_size()
{
static auto _v = get_config()->find("HOSTTRACE_BUFFER_SIZE_KB");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
uint64_t
get_critical_trace_update_freq()
{
static uint64_t _v =
get_config()->get<uint64_t>("HOSTTRACE_CRITICAL_TRACE_BUFFER_COUNT");
return _v;
}
uint64_t
get_critical_trace_num_threads()
{
static uint64_t _v =
get_config()->get<uint64_t>("HOSTTRACE_CRITICAL_TRACE_NUM_THREADS");
return _v;
}
std::string
get_trace_hsa_api_types()
{
static std::string _v =
get_config()->get<std::string>("HOSTTRACE_ROCTRACER_HSA_API_TYPES");
return _v;
}
std::string&
get_backend()
{
// select inprocess, system, or both (i.e. all)
static auto _v = get_config()->find("HOSTTRACE_BACKEND");
return static_cast<tim::tsettings<std::string>&>(*_v->second).get();
}
std::string
get_perfetto_output_filename()
{
static auto _v = get_config()->find("HOSTTRACE_OUTPUT_FILE");
static auto& _t = static_cast<tim::tsettings<std::string>&>(*_v->second);
if(_t.get().empty())
{
// default name: perfetto-trace.<pid>.proto or perfetto-trace.<rank>.proto
auto _default_fname = settings::compose_output_filename(
"perfetto-trace", "proto", get_use_pid(),
(tim::dmp::is_initialized()) ? tim::dmp::rank() : process::get_id());
auto _pid_patch = std::string{ "/" } + std::to_string(tim::process::get_id()) +
"-perfetto-trace";
auto _dpos = _default_fname.find(_pid_patch);
if(_dpos != std::string::npos)
_default_fname =
_default_fname.replace(_dpos, _pid_patch.length(), "/perfetto-trace");
// have the default display the full path to the output file
_t.set(tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false), _default_fname),
false));
}
return _t.get();
}
size_t&
get_sample_rate()
{
static auto _v = get_config()->find("HOSTTRACE_SAMPLE_RATE");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
int64_t
get_critical_trace_count()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_COUNT");
return static_cast<tim::tsettings<int64_t>&>(*_v->second).get();
}
State&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
std::atomic<uint64_t>&
get_cpu_cid()
{
static std::atomic<uint64_t> _v{ 0 };
return _v;
}
std::unique_ptr<std::vector<uint64_t>>&
get_cpu_cid_stack(int64_t _tid)
{
struct hosttrace_cpu_cid_stack
{};
using thread_data_t =
hosttrace_thread_data<std::vector<uint64_t>, hosttrace_cpu_cid_stack>;
static auto& _v = thread_data_t::instances();
static thread_local auto _v_check = [_tid]() {
thread_data_t::construct((_tid > 0) ? *thread_data_t::instances().at(0)
: std::vector<uint64_t>{});
return true;
}();
return _v.at(_tid);
(void) _v_check;
}
File diff suppressed because it is too large. Load diff
+46
Просмотреть файл
@@ -0,0 +1,46 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/fork_gotcha.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
void
fork_gotcha::audit(const gotcha_data_t&, audit::incoming)
{
HOSTTRACE_DEBUG(
"Warning! Calling fork() within an OpenMPI application using libfabric "
"may result is segmentation fault\n");
TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(get_debug(), 16);
}
void
fork_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid)
{
HOSTTRACE_DEBUG("%s() return PID %i\n", _data.tool_id.c_str(), (int) _pid);
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/hosttrace_component.hpp"
#include "library/api.hpp"
void
hosttrace_component::start()
{
if(m_prefix) hosttrace_push_trace(m_prefix);
}
void
hosttrace_component::stop()
{
if(m_prefix) hosttrace_pop_trace(m_prefix);
}
void
hosttrace_component::set_prefix(const char* _prefix)
{
m_prefix = _prefix;
}
TIMEMORY_INITIALIZE_STORAGE(hosttrace_component)
@@ -1,14 +1,40 @@
#include "library.hpp"
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
//
// This file contains miscellaneous function definitions related to timemory
// placed in separate file so that, during development, the long compile-times
// arising from compiling timemory's gotcha wrappers are reduced
//
#include "library/mpi_gotcha.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/hosttrace_component.hpp"
namespace
{
uint64_t mpip_index = std::numeric_limits<uint64_t>::max();
uint64_t mpip_index = std::numeric_limits<uint64_t>::max();
std::string mpi_init_string = {};
// this ensures hosttrace_trace_finalize is called before MPI_Finalize
void
@@ -19,10 +45,12 @@ hosttrace_mpi_set_attr()
return MPI_SUCCESS;
};
static auto _mpi_fini = [](MPI_Comm, int, void*, void*) {
HOSTTRACE_DEBUG("MPI Comm attribute finalize\n");
if(mpip_index != std::numeric_limits<uint64_t>::max())
comp::deactivate_mpip<tim::component_tuple<hosttrace_component>, hosttrace>(
mpip_index);
hosttrace_pop_trace("MPI_Finalize()");
if(!mpi_init_string.empty()) hosttrace_pop_trace(mpi_init_string.c_str());
mpi_init_string = {};
hosttrace_trace_finalize();
return MPI_SUCCESS;
};
@@ -37,26 +65,15 @@ hosttrace_mpi_set_attr()
}
} // namespace
void
fork_gotcha::audit(const gotcha_data_t&, audit::incoming)
{
HOSTTRACE_DEBUG(
"Warning! Calling fork() within an OpenMPI application using libfabric "
"may result is segmentation fault\n");
TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(get_debug(), 16);
}
void
fork_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid)
{
HOSTTRACE_DEBUG("%s() return PID %i\n", _data.tool_id.c_str(), (int) _pid);
}
void
mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***)
{
HOSTTRACE_DEBUG("[%s] %s(int*, char***)\n", __FUNCTION__, _data.tool_id.c_str());
if(get_state() == ::State::DelayedInit) get_state() = ::State::PreInit;
if(get_state() == ::State::DelayedInit)
{
get_state() = ::State::PreInit;
mpi_init_string = _data.tool_id;
}
}
void
@@ -64,7 +81,11 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***, in
{
HOSTTRACE_DEBUG("[%s] %s(int*, char***, int, int*)\n", __FUNCTION__,
_data.tool_id.c_str());
if(get_state() == ::State::DelayedInit) get_state() = ::State::PreInit;
if(get_state() == ::State::DelayedInit)
{
get_state() = ::State::PreInit;
mpi_init_string = _data.tool_id;
}
}
void
@@ -80,7 +101,7 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, int _retval)
// being activated unwaringly during runtime instrumentation because that
// will result in double instrumenting the MPI functions (unless the MPI functions
// were excluded via a regex expression)
if(tim::get_env("HOSTTRACE_USE_MPIP", false, false))
if(get_use_mpip())
{
HOSTTRACE_DEBUG("[%s] Activating MPI wrappers...\n", __FUNCTION__);
comp::configure_mpip<tim::component_tuple<hosttrace_component>, hosttrace>();
@@ -98,39 +119,9 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming)
if(mpip_index != std::numeric_limits<uint64_t>::max())
comp::deactivate_mpip<tim::component_tuple<hosttrace_component>, hosttrace>(
mpip_index);
hosttrace_pop_trace("MPI_Finalize()");
if(!mpi_init_string.empty()) hosttrace_pop_trace(mpi_init_string.c_str());
mpi_init_string = {};
hosttrace_trace_finalize();
}
void
hosttrace_component::start()
{
if(m_prefix) hosttrace_push_trace(m_prefix);
}
void
hosttrace_component::stop()
{
if(m_prefix) hosttrace_pop_trace(m_prefix);
}
void
hosttrace_component::set_prefix(const char* _prefix)
{
m_prefix = _prefix;
}
hosttrace_timemory_data::instance_array_t&
hosttrace_timemory_data::instances()
{
static auto _v = instance_array_t{};
return _v;
}
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
TIMEMORY_INITIALIZE_STORAGE(fork_gotcha, mpi_gotcha, comp::wall_clock,
comp::user_global_bundle)
#if defined(CUSTOM_DATA_SOURCE)
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
TIMEMORY_INITIALIZE_STORAGE(mpi_gotcha)
+35
Просмотреть файл
@@ -0,0 +1,35 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/perfetto.hpp"
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
#if defined(CUSTOM_DATA_SOURCE)
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
+80
Просмотреть файл
@@ -0,0 +1,80 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/ptl.hpp"
namespace tasking
{
std::mutex&
get_roctracer_mutex()
{
static std::mutex _v{};
return _v;
}
PTL::ThreadPool&
get_roctracer_thread_pool()
{
static auto _v = PTL::ThreadPool{ 1 };
return _v;
}
PTL::TaskGroup<void>&
get_roctracer_task_group()
{
static PTL::TaskGroup<void> _v{ &get_roctracer_thread_pool() };
return _v;
}
std::mutex&
get_critical_trace_mutex()
{
static std::mutex _v{};
return _v;
}
PTL::ThreadPool&
get_critical_trace_thread_pool()
{
static auto _v = PTL::ThreadPool{ 1 };
return _v;
}
PTL::TaskGroup<void>&
get_critical_trace_task_group()
{
static PTL::TaskGroup<void> _v{ &get_critical_trace_thread_pool() };
return _v;
}
namespace
{
bool _ptl_initialized =
(get_roctracer_thread_pool(), get_critical_trace_thread_pool(), true);
}
} // namespace tasking
+283
Просмотреть файл
@@ -0,0 +1,283 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/roctracer.hpp"
#include "library/config.hpp"
#include "library/defines.hpp"
#include "library/roctracer_callbacks.hpp"
#include "library/thread_data.hpp"
namespace tim
{
namespace component
{
void
roctracer::preinit()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
roctracer_data::label() = "roctracer";
roctracer_data::description() = "ROCm tracer (activity API)";
}
bool
roctracer::is_setup()
{
return roctracer_is_setup();
}
void
roctracer::add_setup(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_setup_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::add_tear_down(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_tear_down_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::remove_setup(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::remove_tear_down(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::setup()
{
if(!get_use_timemory() && !get_use_perfetto()) return;
auto_lock_t _lk{ type_mutex<roctracer>() };
if(roctracer_is_setup()) return;
roctracer_is_setup() = true;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::set_env("HSA_TOOLS_LIB", "libhosttrace.so", 0);
auto _kfdwrapper = dynamic_library{ "HOSTTRACE_ROCTRACER_LIBKFDWRAPPER",
HOSTTRACE_ROCTRACER_LIBKFDWRAPPER };
ROCTRACER_CALL(roctracer_set_properties(ACTIVITY_DOMAIN_HIP_API, nullptr));
// if(roctracer_default_pool() == nullptr)
{
// Allocating tracing pool
roctracer_properties_t properties{};
memset(&properties, 0, sizeof(roctracer_properties_t));
properties.mode = 0x1000;
properties.buffer_size = 0x1000;
properties.buffer_callback_fun = hip_activity_callback;
ROCTRACER_CALL(roctracer_open_pool(&properties));
}
// Enable API callbacks, all domains
ROCTRACER_CALL(roctracer_enable_callback(hip_api_callback, nullptr));
// Enable activity tracing, all domains
ROCTRACER_CALL(roctracer_enable_activity());
// callback for HSA
for(auto& itr : roctracer_setup_routines())
itr.second();
}
void
roctracer::tear_down()
{
auto_lock_t _lk{ type_mutex<roctracer>() };
if(!roctracer_is_setup()) return;
roctracer_is_setup() = false;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// flush all the activity
if(roctracer_default_pool() != nullptr)
{
ROCTRACER_CALL(roctracer_flush_activity());
}
// flush all buffers
roctracer_flush_buf();
// make sure all async operations are executed
for(size_t i = 0; i < max_supported_threads; ++i)
hip_exec_activity_callbacks(i);
// callback for hsa
for(auto& itr : roctracer_tear_down_routines())
itr.second();
// Disable tracing and closing the pool
ROCTRACER_CALL(roctracer_disable_callback());
ROCTRACER_CALL(roctracer_disable_activity());
ROCTRACER_CALL(roctracer_close_pool());
}
void
roctracer::start()
{
if(tracker_type::start() == 0) setup();
}
void
roctracer::stop()
{
if(tracker_type::stop() == 0) tear_down();
}
} // namespace component
} // namespace tim
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer, false, void)
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
// HSA-runtime tool on-load method
extern "C"
{
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names) TIMEMORY_VISIBILITY("default");
void OnUnload() TIMEMORY_VISIBILITY("default");
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::consume_parameters(table, runtime_version, failed_tool_count,
failed_tool_names);
// ONLOAD_TRACE_BEG();
// on_exit(exit_handler, nullptr);
auto _setup = [=]() {
get_hsa_timer() =
std::make_unique<hsa_timer_t>(table->core_->hsa_system_get_info_fn);
// const char* output_prefix = getenv("ROCP_OUTPUT_DIR");
const char* output_prefix = nullptr;
// App begin timestamp begin_ts_file.txt
// begin_ts_file_handle = open_output_file(output_prefix,
// "begin_ts_file.txt"); const timestamp_t app_start_time =
// timer->timestamp_fn_ns(); fprintf(begin_ts_file_handle, "%lu\n",
// app_start_time);
bool trace_hsa_api = get_trace_hsa_api();
std::vector<std::string> hsa_api_vec =
tim::delimit(get_trace_hsa_api_types());
// Enable HSA API callbacks/activity
if(trace_hsa_api)
{
// hsa_api_file_handle = open_output_file(output_prefix,
// "hsa_api_trace.txt");
// initialize HSA tracing
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_API, (void*) table);
HOSTTRACE_DEBUG(" HSA-trace(");
if(!hsa_api_vec.empty())
{
for(const auto& itr : hsa_api_vec)
{
uint32_t cid = HSA_API_ID_NUMBER;
const char* api = itr.c_str();
ROCTRACER_CALL(roctracer_op_code(ACTIVITY_DOMAIN_HSA_API, api,
&cid, nullptr));
ROCTRACER_CALL(roctracer_enable_op_callback(
ACTIVITY_DOMAIN_HSA_API, cid, hsa_api_callback, nullptr));
HOSTTRACE_DEBUG(" %s", api);
}
}
else
{
ROCTRACER_CALL(roctracer_enable_domain_callback(
ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, nullptr));
}
HOSTTRACE_DEBUG("\n");
}
bool trace_hsa_activity = get_trace_hsa_activity();
// Enable HSA GPU activity
if(trace_hsa_activity)
{
// initialize HSA tracing
::roctracer::hsa_ops_properties_t ops_properties{
table,
reinterpret_cast<activity_async_callback_t>(hsa_activity_callback),
nullptr, output_prefix
};
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_OPS, &ops_properties);
HOSTTRACE_DEBUG(" HSA-activity-trace()\n");
ROCTRACER_CALL(roctracer_enable_op_activity(ACTIVITY_DOMAIN_HSA_OPS,
HSA_OP_ID_COPY));
}
};
auto _tear_down = []() {
ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API));
ROCTRACER_CALL(
roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, HSA_OP_ID_COPY));
};
if(comp::roctracer::is_setup()) _setup();
comp::roctracer::add_setup("hsa", std::move(_setup));
comp::roctracer::add_tear_down("hsa", std::move(_tear_down));
return true;
}
// HSA-runtime on-unload method
void OnUnload()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// ONLOAD_TRACE("");
}
}
+599
Просмотреть файл
@@ -0,0 +1,599 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/roctracer_callbacks.hpp"
#include "library.hpp"
#include "library/config.hpp"
#include "library/critical_trace.hpp"
#include "library/thread_data.hpp"
#include "timemory/backends/threading.hpp"
#include <cstdint>
TIMEMORY_DEFINE_API(roctracer)
namespace api = tim::api;
std::unordered_set<uint64_t>&
get_roctracer_kernels()
{
static auto _v = std::unordered_set<uint64_t>{};
return _v;
}
auto&
get_roctracer_hip_data(int64_t _tid = threading::get_id())
{
using data_t = std::unordered_map<uint64_t, roctracer_bundle_t>;
using thread_data_t = hosttrace_thread_data<data_t, api::roctracer>;
static auto& _v = thread_data_t::instances(thread_data_t::construct_on_init{});
return _v.at(_tid);
}
std::unordered_map<uint64_t, const char*>&
get_roctracer_key_data()
{
static auto _v = std::unordered_map<uint64_t, const char*>{};
return _v;
}
std::unordered_map<uint64_t, int64_t>&
get_roctracer_tid_data()
{
static auto _v = std::unordered_map<uint64_t, int64_t>{};
return _v;
}
using cid_tuple_t = std::tuple<uint64_t, uint64_t, uint16_t>;
std::unordered_map<uint64_t, cid_tuple_t>&
get_roctracer_cid_data()
{
static auto _v = std::unordered_map<uint64_t, cid_tuple_t>{};
return _v;
}
auto&
get_hip_activity_callbacks(int64_t _tid = threading::get_id())
{
using thread_data_t =
hosttrace_thread_data<std::vector<std::function<void()>>, api::roctracer>;
static auto& _v = thread_data_t::instances(thread_data_t::construct_on_init{});
return _v.at(_tid);
}
std::unique_ptr<hsa_timer_t>&
get_hsa_timer()
{
static auto _v = std::unique_ptr<hsa_timer_t>{};
return _v;
}
using hip_activity_mutex_t = std::decay_t<decltype(get_hip_activity_callbacks())>;
using key_data_mutex_t = std::decay_t<decltype(get_roctracer_key_data())>;
using hip_data_mutex_t = std::decay_t<decltype(get_roctracer_hip_data())>;
using cid_data_mutex_t = std::decay_t<decltype(get_roctracer_cid_data())>;
auto&
get_hip_activity_mutex(int64_t _tid = threading::get_id())
{
return tim::type_mutex<hip_activity_mutex_t, api::roctracer, max_supported_threads>(
_tid);
}
// HSA API callback function
void
hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
(void) arg;
const hsa_api_data_t* data = reinterpret_cast<const hsa_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
static thread_local timestamp_t begin_timestamp = 0;
static auto& timer = get_hsa_timer();
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
if(!timer) return;
switch(cid)
{
case HSA_API_ID_hsa_init:
case HSA_API_ID_hsa_shut_down:
case HSA_API_ID_hsa_agent_get_exception_policies:
case HSA_API_ID_hsa_agent_get_info:
case HSA_API_ID_hsa_amd_agent_iterate_memory_pools:
case HSA_API_ID_hsa_amd_agent_memory_pool_get_info:
case HSA_API_ID_hsa_amd_coherency_get_type:
case HSA_API_ID_hsa_amd_memory_pool_get_info:
case HSA_API_ID_hsa_amd_pointer_info:
case HSA_API_ID_hsa_amd_pointer_info_set_userdata:
case HSA_API_ID_hsa_amd_profiling_async_copy_enable:
case HSA_API_ID_hsa_amd_profiling_get_async_copy_time:
case HSA_API_ID_hsa_amd_profiling_get_dispatch_time:
case HSA_API_ID_hsa_amd_profiling_set_profiler_enabled:
case HSA_API_ID_hsa_cache_get_info:
case HSA_API_ID_hsa_code_object_get_info:
case HSA_API_ID_hsa_code_object_get_symbol:
case HSA_API_ID_hsa_code_object_get_symbol_from_name:
case HSA_API_ID_hsa_code_object_reader_create_from_memory:
case HSA_API_ID_hsa_code_symbol_get_info:
case HSA_API_ID_hsa_executable_create_alt:
case HSA_API_ID_hsa_executable_freeze:
case HSA_API_ID_hsa_executable_get_info:
case HSA_API_ID_hsa_executable_get_symbol:
case HSA_API_ID_hsa_executable_get_symbol_by_name:
case HSA_API_ID_hsa_executable_symbol_get_info:
case HSA_API_ID_hsa_extension_get_name:
case HSA_API_ID_hsa_ext_image_data_get_info:
case HSA_API_ID_hsa_ext_image_data_get_info_with_layout:
case HSA_API_ID_hsa_ext_image_get_capability:
case HSA_API_ID_hsa_ext_image_get_capability_with_layout:
case HSA_API_ID_hsa_isa_get_exception_policies:
case HSA_API_ID_hsa_isa_get_info:
case HSA_API_ID_hsa_isa_get_info_alt:
case HSA_API_ID_hsa_isa_get_round_method:
case HSA_API_ID_hsa_region_get_info:
case HSA_API_ID_hsa_system_extension_supported:
case HSA_API_ID_hsa_system_get_extension_table:
case HSA_API_ID_hsa_system_get_info:
case HSA_API_ID_hsa_system_get_major_extension_table:
case HSA_API_ID_hsa_wavefront_get_info: break;
default:
{
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
begin_timestamp = timer->timestamp_fn_ns();
}
else
{
const auto* _name = roctracer_op_string(domain, cid, 0);
const timestamp_t end_timestamp = (cid == HSA_API_ID_hsa_shut_down)
? begin_timestamp
: timer->timestamp_fn_ns();
if(begin_timestamp > end_timestamp) return;
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ _name },
begin_timestamp);
TRACE_EVENT_END("device", end_timestamp);
}
if(get_use_timemory())
{
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
auto _begin_ns = begin_timestamp;
auto _end_ns = end_timestamp;
tasking::get_roctracer_task_group().exec(
[_name, _begin_ns, _end_ns]() {
roctracer_hsa_bundle_t _bundle{ _name, _scope };
_bundle.start()
.store(std::plus<double>{},
static_cast<double>(_end_ns - _begin_ns))
.stop();
});
}
// timemory is disabled in this callback because collecting data in this
// thread causes strange segmentation faults
}
}
}
}
void
hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg)
{
static const char* copy_op_name = "hsa_async_copy";
static const char* dispatch_op_name = "hsa_dispatch";
static const char* barrier_op_name = "hsa_barrier";
const char** _name = nullptr;
switch(op)
{
case HSA_OP_ID_DISPATCH: _name = &dispatch_op_name; break;
case HSA_OP_ID_COPY: _name = &copy_op_name; break;
case HSA_OP_ID_BARRIER: _name = &barrier_op_name; break;
default: break;
}
if(!_name) return;
auto _begin_ns = record->begin_ns;
auto _end_ns = record->end_ns;
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
auto _func = [_begin_ns, _end_ns, _name]() {
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ *_name }, _begin_ns);
TRACE_EVENT_END("device", _end_ns);
}
if(get_use_timemory())
{
roctracer_hsa_bundle_t _bundle{ *_name, _scope };
_bundle.start()
.store(std::plus<double>{}, static_cast<double>(_end_ns - _begin_ns))
.stop();
}
};
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
tasking::get_roctracer_task_group().exec(_func);
// timemory is disabled in this callback because collecting data in this thread
// causes strange segmentation faults
tim::consume_parameters(arg);
}
void
hip_exec_activity_callbacks(int64_t _tid)
{
// ROCTRACER_CALL(roctracer_flush_activity());
tim::auto_lock_t _lk{ get_hip_activity_mutex(_tid) };
auto& _async_ops = get_hip_activity_callbacks(_tid);
for(auto& itr : *_async_ops)
itr();
_async_ops->clear();
}
namespace
{
thread_local std::unordered_map<size_t, size_t> gpu_cids = {};
}
// HIP API callback function
void
hip_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
const char* op_name = roctracer_op_string(domain, cid, 0);
if(op_name == nullptr) op_name = hip_api_name(cid);
if(op_name == nullptr) return;
const hip_api_data_t* data = reinterpret_cast<const hip_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n", op_name, cid,
data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
switch(cid)
{
case HIP_API_ID___hipPushCallConfiguration:
case HIP_API_ID___hipPopCallConfiguration:
case HIP_API_ID_hipDeviceEnablePeerAccess:
case HIP_API_ID_hipImportExternalMemory:
case HIP_API_ID_hipDestroyExternalMemory: return;
default: break;
}
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
switch(cid)
{
case HIP_API_ID_hipLaunchKernel:
case HIP_API_ID_hipLaunchCooperativeKernel:
{
const char* _name =
hipKernelNameRefByPtr(data->args.hipLaunchKernel.function_address,
data->args.hipLaunchKernel.stream);
if(_name != nullptr)
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, _name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
break;
}
case HIP_API_ID_hipModuleLaunchKernel:
{
const char* _name = hipKernelNameRef(data->args.hipModuleLaunchKernel.f);
if(_name != nullptr)
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, _name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
break;
}
default:
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, op_name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
}
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ op_name });
}
if(get_use_timemory())
{
get_roctracer_hip_data()->emplace(
data->correlation_id,
roctracer_bundle_t{ op_name, quirk::config<quirk::auto_start>{} });
}
if(get_use_critical_trace())
{
auto _cid = get_cpu_cid()++;
uint16_t _depth = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->size()
: get_cpu_cid_stack()->size() - 1;
auto _parent_cid = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->back()
: get_cpu_cid_stack()->back();
int64_t _ts = comp::wall_clock::record();
add_critical_trace<Device::GPU, Phase::BEGIN>(
threading::get_id(), _cid, data->correlation_id, _parent_cid, _ts, 0,
critical_trace::add_hash_id(op_name), _depth);
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
get_roctracer_cid_data().emplace(data->correlation_id,
cid_tuple_t{ _cid, _parent_cid, _depth });
}
hip_exec_activity_callbacks(threading::get_id());
}
else if(data->phase == ACTIVITY_API_PHASE_EXIT)
{
hip_exec_activity_callbacks(threading::get_id());
if(get_use_perfetto())
{
TRACE_EVENT_END("device");
}
if(get_use_timemory())
{
auto _stop = [data](int64_t _tid) {
auto& _data = get_roctracer_hip_data(_tid);
auto itr = _data->find(data->correlation_id);
if(itr != get_roctracer_hip_data()->end())
{
itr->second.stop().pop();
_data->erase(itr);
return true;
}
return false;
};
if(!_stop(threading::get_id()))
{
for(size_t i = 0; i < max_supported_threads; ++i)
{
if(_stop(i)) break;
}
}
}
if(get_use_critical_trace())
{
uint16_t _depth = 0;
uint64_t _cid = 0;
uint64_t _parent_cid = 0;
{
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
std::tie(_cid, _parent_cid, _depth) =
get_roctracer_cid_data().at(data->correlation_id);
}
int64_t _ts = comp::wall_clock::record();
add_critical_trace<Device::GPU, Phase::END>(
threading::get_id(), _cid, data->correlation_id, _parent_cid, _ts, _ts,
critical_trace::add_hash_id(op_name), _depth);
}
}
tim::consume_parameters(arg);
}
// Activity tracing callback
void
hip_activity_callback(const char* begin, const char* end, void*)
{
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
if(!trait::runtime_enabled<comp::roctracer>::get()) return;
static auto _kernel_names = std::unordered_map<const char*, std::string>{};
static auto _indexes = std::unordered_map<uint64_t, int>{};
const roctracer_record_t* record = reinterpret_cast<const roctracer_record_t*>(begin);
const roctracer_record_t* end_record =
reinterpret_cast<const roctracer_record_t*>(end);
HOSTTRACE_DEBUG("Activity records:\n");
while(record < end_record)
{
const char* op_name =
roctracer_op_string(record->domain, record->correlation_id, 0);
if(op_name == nullptr) op_name = hip_api_name(record->correlation_id);
if(op_name != nullptr)
{
HOSTTRACE_DEBUG("\t%-30s\tcorrelation_id(%6lu) time_ns(%12lu:%12lu) "
"delta_ns(%12lu) device_id(%d) "
"stream_id(%lu)\n",
op_name, record->correlation_id, record->begin_ns,
record->end_ns, (record->end_ns - record->begin_ns),
record->device_id, record->queue_id);
}
auto _begin_ns = record->begin_ns;
auto _end_ns = record->end_ns;
auto _corr_id = record->correlation_id;
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
auto& _keys = get_roctracer_key_data();
auto& _cids = get_roctracer_cid_data();
auto& _tids = get_roctracer_tid_data();
int16_t _depth = 0; // depth of kernel launch
int64_t _tid = 0; // thread id
uint64_t _cid = 0; // correlation id
uint64_t _pcid = 0; // parent corr_id
auto _laps = _indexes[_corr_id]++; // see note #1
const char* _name = nullptr;
bool _found = false;
bool _critical_trace = get_use_critical_trace();
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
if(_tids.find(_corr_id) != _tids.end())
{
_found = true;
_tid = _tids.at(_corr_id);
auto itr = _keys.find(_corr_id);
if(itr != _keys.end()) _name = itr->second;
}
}
if(_critical_trace)
{
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
if(_cids.find(_corr_id) != _cids.end())
std::tie(_cid, _pcid, _depth) = _cids.at(_corr_id);
else
_critical_trace = false;
}
auto _func = [_critical_trace, _depth, _tid, _cid, _laps, _begin_ns, _end_ns,
_corr_id, _name]() {
// NOTE #1: we get two measurements for 1 kernel so we need to
// tweak the number of laps for the wall-clock component
if(_name != nullptr)
{
if(get_use_perfetto())
{
if(_kernel_names.find(_name) == _kernel_names.end())
_kernel_names.emplace(_name, tim::demangle(_name));
TRACE_EVENT_BEGIN(
"device",
perfetto::StaticString{ _kernel_names.at(_name).c_str() },
_begin_ns);
TRACE_EVENT_END("device", _end_ns);
}
if(get_use_timemory())
{
roctracer_bundle_t _bundle{ _name, _scope };
_bundle.start()
.store(std::plus<double>{},
static_cast<double>(_end_ns - _begin_ns))
.stop()
.get<comp::wall_clock>([&](comp::wall_clock* wc) {
wc->set_value(_end_ns - _begin_ns);
wc->set_accum(_end_ns - _begin_ns);
if(_laps % 2 == 1)
{
// below is a hack bc we get two measurements for 1 kernel
wc->set_laps(0);
auto itr = wc->get_iterator();
if(itr && itr->data().get_laps() == 0)
{
wc->set_is_invalid(true);
itr->data().set_is_invalid(true);
}
}
return wc;
});
_bundle.pop();
}
if(_critical_trace)
{
auto _hash = critical_trace::add_hash_id(_name);
uint16_t _prio = _laps + 1; // priority
add_critical_trace<Device::GPU, Phase::DELTA, false>(
_tid, _cid, _corr_id, _cid, _begin_ns, _end_ns, _hash, _depth + 1,
_prio);
}
}
};
if(_found)
{
auto& _async_ops = get_hip_activity_callbacks(_tid);
tim::auto_lock_t _lk{ get_hip_activity_mutex(_tid) };
_async_ops->emplace_back(std::move(_func));
}
ROCTRACER_CALL(roctracer_next_record(record, &record));
}
}
bool&
roctracer_is_setup()
{
static bool _v = false;
return _v;
}
using roctracer_functions_t = std::vector<std::pair<std::string, std::function<void()>>>;
roctracer_functions_t&
roctracer_setup_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
roctracer_functions_t&
roctracer_tear_down_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
+36
Просмотреть файл
@@ -0,0 +1,36 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/thread_data.hpp"
instrumentation_bundles::instance_array_t&
instrumentation_bundles::instances()
{
static auto _v = instance_array_t{};
return _v;
}
+31
Просмотреть файл
@@ -0,0 +1,31 @@
// Copyright (c) 2018 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
// with 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:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// 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
// CONTRIBUTORS 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 WITH
// THE SOFTWARE.
#include "library/timemory.hpp"
TIMEMORY_INITIALIZE_STORAGE(comp::wall_clock, comp::user_global_bundle)
-645
Просмотреть файл
@@ -1,645 +0,0 @@
#include "roctracer.hpp"
#include "library.hpp"
#include <roctracer.h>
#include <roctracer_ext.h>
#include <roctracer_hcc.h>
#include <roctracer_hip.h>
#include <roctracer_kfd.h>
#define AMD_INTERNAL_BUILD 1
#include <ext/hsa_rt_utils.hpp>
#include <roctracer_hsa.h>
#include <atomic>
// Macro to check ROC-tracer calls status
#define ROCTRACER_CALL(call) \
do \
{ \
int err = call; \
if(err != 0) \
{ \
std::cerr << roctracer_error_string() << " in: " << #call << std::flush; \
} \
} while(0)
using roctracer_bundle_t = tim::component_tuple<comp::roctracer_data>;
namespace units = tim::units;
namespace
{
auto&
get_roctracer_kernels()
{
static auto _v = std::unordered_set<uint64_t>{};
return _v;
}
auto&
get_roctracer_hip_data()
{
static auto _v = std::unordered_map<uint64_t, roctracer_bundle_t>{};
return _v;
}
auto&
get_roctracer_key_data()
{
static auto _v = std::unordered_map<uint64_t, const char*>{};
return _v;
}
using data_type_mutex_t = std::decay_t<decltype(get_roctracer_hip_data())>;
using hsa_timer_t = hsa_rt_utils::Timer;
using timestamp_t = hsa_timer_t::timestamp_t;
auto&
get_hsa_timer()
{
static auto _v = std::unique_ptr<hsa_timer_t>{};
return _v;
}
// HSA API callback function
void
hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
(void) arg;
static auto _scope = scope::config{} + scope::flat{};
const hsa_api_data_t* data = reinterpret_cast<const hsa_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
static thread_local timestamp_t hsa_begin_timestamp = 0;
static auto& timer = get_hsa_timer();
if(!timer) return;
switch(cid)
{
case HSA_API_ID_hsa_init:
case HSA_API_ID_hsa_shut_down:
case HSA_API_ID_hsa_agent_get_exception_policies:
case HSA_API_ID_hsa_agent_get_info:
case HSA_API_ID_hsa_amd_agent_iterate_memory_pools:
case HSA_API_ID_hsa_amd_agent_memory_pool_get_info:
case HSA_API_ID_hsa_amd_coherency_get_type:
case HSA_API_ID_hsa_amd_memory_pool_get_info:
case HSA_API_ID_hsa_amd_pointer_info:
case HSA_API_ID_hsa_amd_pointer_info_set_userdata:
case HSA_API_ID_hsa_amd_profiling_async_copy_enable:
case HSA_API_ID_hsa_amd_profiling_get_async_copy_time:
case HSA_API_ID_hsa_amd_profiling_get_dispatch_time:
case HSA_API_ID_hsa_amd_profiling_set_profiler_enabled:
case HSA_API_ID_hsa_cache_get_info:
case HSA_API_ID_hsa_code_object_get_info:
case HSA_API_ID_hsa_code_object_get_symbol:
case HSA_API_ID_hsa_code_object_get_symbol_from_name:
case HSA_API_ID_hsa_code_object_reader_create_from_memory:
case HSA_API_ID_hsa_code_symbol_get_info:
case HSA_API_ID_hsa_executable_create_alt:
case HSA_API_ID_hsa_executable_freeze:
case HSA_API_ID_hsa_executable_get_info:
case HSA_API_ID_hsa_executable_get_symbol:
case HSA_API_ID_hsa_executable_get_symbol_by_name:
case HSA_API_ID_hsa_executable_symbol_get_info:
case HSA_API_ID_hsa_extension_get_name:
case HSA_API_ID_hsa_ext_image_data_get_info:
case HSA_API_ID_hsa_ext_image_data_get_info_with_layout:
case HSA_API_ID_hsa_ext_image_get_capability:
case HSA_API_ID_hsa_ext_image_get_capability_with_layout:
case HSA_API_ID_hsa_isa_get_exception_policies:
case HSA_API_ID_hsa_isa_get_info:
case HSA_API_ID_hsa_isa_get_info_alt:
case HSA_API_ID_hsa_isa_get_round_method:
case HSA_API_ID_hsa_region_get_info:
case HSA_API_ID_hsa_system_extension_supported:
case HSA_API_ID_hsa_system_get_extension_table:
case HSA_API_ID_hsa_system_get_info:
case HSA_API_ID_hsa_system_get_major_extension_table:
case HSA_API_ID_hsa_wavefront_get_info: break;
default:
{
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
hsa_begin_timestamp = timer->timestamp_fn_ns();
}
else
{
auto _name = roctracer_op_string(domain, cid, 0);
const timestamp_t end_timestamp = (cid == HSA_API_ID_hsa_shut_down)
? hsa_begin_timestamp
: timer->timestamp_fn_ns();
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ _name },
hsa_begin_timestamp);
TRACE_EVENT_END("device", end_timestamp);
}
/*if(get_use_timemory())
{
static auto _scope = scope::flat() + scope::timeline();
roctracer_bundle_t{ _name, _scope }
.start()
.store(end_timestamp - hsa_begin_timestamp)
.stop();
}*/
// timemory is disabled in this callback because collecting data in this
// thread causes strange segmentation faults
}
}
}
}
void
hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg)
{
static const char* copy_op_name = "hsa_async_copy";
static const char* dispatch_op_name = "hsa_dispatch";
static const char* barrier_op_name = "hsa_barrier";
const char** _name = nullptr;
switch(op)
{
case HSA_OP_ID_DISPATCH: _name = &dispatch_op_name; break;
case HSA_OP_ID_COPY: _name = &copy_op_name; break;
case HSA_OP_ID_BARRIER: _name = &barrier_op_name; break;
default: break;
}
if(!_name) return;
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ *_name }, record->begin_ns);
TRACE_EVENT_END("device", record->end_ns);
}
// timemory is disabled in this callback because collecting data in this thread
// causes strange segmentation faults
tim::consume_parameters(arg);
}
// HIP API callback function
void
hip_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
static auto _scope = scope::flat() + scope::timeline();
const hip_api_data_t* data = reinterpret_cast<const hip_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
switch(cid)
{
case HIP_API_ID___hipPushCallConfiguration:
case HIP_API_ID___hipPopCallConfiguration: break;
case HIP_API_ID_hipLaunchKernel:
{
const char* _name =
hipKernelNameRefByPtr(data->args.hipLaunchKernel.function_address,
data->args.hipLaunchKernel.stream);
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
get_roctracer_kernels().emplace(data->correlation_id);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
case HIP_API_ID_hipModuleLaunchKernel:
{
const char* _name = hipKernelNameRef(data->args.hipModuleLaunchKernel.f);
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
get_roctracer_kernels().emplace(data->correlation_id);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
default:
{
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
const char* _name = roctracer_op_string(domain, cid, 0);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
}
}
else if(data->phase == ACTIVITY_API_PHASE_EXIT)
{}
tim::consume_parameters(domain, arg);
}
// Activity tracing callback
void
hip_activity_callback(const char* begin, const char* end, void*)
{
if(!trait::runtime_enabled<comp::roctracer>::get()) return;
static auto _kernel_names = std::unordered_map<const char*, std::string>{};
const roctracer_record_t* record = reinterpret_cast<const roctracer_record_t*>(begin);
const roctracer_record_t* end_record =
reinterpret_cast<const roctracer_record_t*>(end);
std::unordered_set<uint64_t> _indexes{};
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
auto& _data = get_roctracer_hip_data();
auto& _keys = get_roctracer_key_data();
auto& _kernels = get_roctracer_kernels();
HOSTTRACE_DEBUG("Activity records:\n");
while(record < end_record)
{
HOSTTRACE_DEBUG("\t%-30s\tcorrelation_id(%lu) time_ns(%lu:%lu) device_id(%d) "
"stream_id(%lu)\n",
roctracer_op_string(record->domain, record->correlation_id, 0),
record->correlation_id, record->begin_ns, record->end_ns,
record->device_id, record->queue_id);
auto _is_kernel = _kernels.find(record->correlation_id) != _kernels.end();
if(_is_kernel && record->device_id != 0 && record->queue_id != 0)
{
// these are overheads associated with the kernel launch, not kernel runtime
ROCTRACER_CALL(roctracer_next_record(record, &record));
continue;
}
auto kitr =
(get_use_perfetto()) ? _keys.find(record->correlation_id) : _keys.end();
if(kitr != _keys.end())
{
if(_kernel_names.find(kitr->second) == _kernel_names.end())
_kernel_names.emplace(kitr->second, tim::demangle(kitr->second));
TRACE_EVENT_BEGIN(
"device",
perfetto::StaticString{ _kernel_names.at(kitr->second).c_str() },
record->begin_ns);
TRACE_EVENT_END("device", record->end_ns);
_indexes.emplace(kitr->first);
}
auto itr =
(get_use_timemory()) ? _data.find(record->correlation_id) : _data.end();
if(itr != _data.end())
{
itr->second.start()
.store(std::plus<double>{},
static_cast<double>(record->end_ns - record->begin_ns))
.stop();
_indexes.emplace(itr->first);
}
// code
ROCTRACER_CALL(roctracer_next_record(record, &record));
}
if(get_use_perfetto())
{
for(auto& itr : _indexes)
_keys.erase(itr);
}
if(get_use_timemory())
{
for(auto& itr : _indexes)
_data.erase(itr);
}
HOSTTRACE_DEBUG("[%s] recorded %lu phases\n", __FUNCTION__,
(unsigned long) _indexes.size());
}
bool&
roctracer_is_setup()
{
static bool _v = false;
return _v;
}
using roctracer_functions_t = std::vector<std::pair<std::string, std::function<void()>>>;
auto&
roctracer_setup_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
auto&
roctracer_tear_down_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
} // namespace
#if !defined(HOSTTRACE_ROCTRACER_LIBKFDWRAPPER)
# define HOSTTRACE_ROCTRACER_LIBKFDWRAPPER "/opt/rocm/roctracer/lib/libkfdwrapper64.so"
#endif
struct dynamic_library
{
dynamic_library() = delete;
dynamic_library(const dynamic_library&) = delete;
dynamic_library(dynamic_library&&) noexcept = default;
dynamic_library& operator=(const dynamic_library&) = delete;
dynamic_library& operator=(dynamic_library&&) noexcept = default;
dynamic_library(const char* _env, const char* _fname,
int _flags = (RTLD_NOW | RTLD_GLOBAL), bool _store = false)
: envname{ _env }
, filename{ tim::get_env<std::string>(_env, _fname, _store) }
, flags{ _flags }
{
handle = dlopen(filename.c_str(), flags);
if(!handle) fprintf(stderr, "%s\n", dlerror());
dlerror(); // Clear any existing error
}
~dynamic_library()
{
if(handle) dlclose(handle);
}
std::string envname = {};
std::string filename = {};
int flags = 0;
void* handle = nullptr;
};
namespace tim
{
namespace component
{
void
roctracer::preinit()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
roctracer_data::label() = "roctracer";
roctracer_data::description() = "ROCm tracer (activity API)";
}
bool
roctracer::is_setup()
{
return roctracer_is_setup();
}
void
roctracer::add_setup(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_setup_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::add_tear_down(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_tear_down_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::remove_setup(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::remove_tear_down(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::setup()
{
if(!get_use_timemory() && !get_use_perfetto()) return;
auto_lock_t _lk{ type_mutex<roctracer>() };
if(roctracer_is_setup()) return;
roctracer_is_setup() = true;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::set_env("HSA_TOOLS_LIB", "libhosttrace.so", 0);
auto _kfdwrapper = dynamic_library{ "HOSTTRACE_ROCTRACER_LIBKFDWRAPPER",
HOSTTRACE_ROCTRACER_LIBKFDWRAPPER };
ROCTRACER_CALL(roctracer_set_properties(ACTIVITY_DOMAIN_HIP_API, nullptr));
if(roctracer_default_pool() == nullptr)
{
// Allocating tracing pool
roctracer_properties_t properties{};
properties.buffer_size = 0x1000;
properties.buffer_callback_fun = hip_activity_callback;
ROCTRACER_CALL(roctracer_open_pool(&properties));
}
// Enable API callbacks, all domains
ROCTRACER_CALL(roctracer_enable_callback(hip_api_callback, nullptr));
// Enable activity tracing, all domains
ROCTRACER_CALL(roctracer_enable_activity());
// callback for HSA
for(auto& itr : roctracer_setup_routines())
itr.second();
}
void
roctracer::tear_down()
{
auto_lock_t _lk{ type_mutex<roctracer>() };
if(!roctracer_is_setup()) return;
roctracer_is_setup() = false;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// flush all the activity
if(roctracer_default_pool() != nullptr)
{
ROCTRACER_CALL(roctracer_flush_activity());
}
// flush all buffers
roctracer_flush_buf();
// callback for hsa
for(auto& itr : roctracer_tear_down_routines())
itr.second();
// Disable tracing and closing the pool
ROCTRACER_CALL(roctracer_disable_callback());
ROCTRACER_CALL(roctracer_disable_activity());
ROCTRACER_CALL(roctracer_close_pool());
}
void
roctracer::start()
{
if(tracker_type::start() == 0) setup();
}
void
roctracer::stop()
{
if(tracker_type::stop() == 0) tear_down();
}
} // namespace component
} // namespace tim
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer, false, void)
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
// HSA-runtime tool on-load method
extern "C"
{
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names) TIMEMORY_VISIBILITY("default");
void OnUnload() TIMEMORY_VISIBILITY("default");
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::consume_parameters(table, runtime_version, failed_tool_count,
failed_tool_names);
// ONLOAD_TRACE_BEG();
// on_exit(exit_handler, nullptr);
auto _setup = [=]() {
get_hsa_timer() =
std::make_unique<hsa_timer_t>(table->core_->hsa_system_get_info_fn);
// const char* output_prefix = getenv("ROCP_OUTPUT_DIR");
const char* output_prefix = nullptr;
// App begin timestamp begin_ts_file.txt
// begin_ts_file_handle = open_output_file(output_prefix,
// "begin_ts_file.txt"); const timestamp_t app_start_time =
// timer->timestamp_fn_ns(); fprintf(begin_ts_file_handle, "%lu\n",
// app_start_time);
bool trace_hsa_api = tim::get_env("HOSTTRACE_ROCTRACER_HSA_API", true);
std::vector<std::string> hsa_api_vec = tim::delimit(
tim::get_env<std::string>("HOSTTRACE_ROCTRACER_HSA_API_TYPES", ""));
// Enable HSA API callbacks/activity
if(trace_hsa_api)
{
// hsa_api_file_handle = open_output_file(output_prefix,
// "hsa_api_trace.txt");
// initialize HSA tracing
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_API, (void*) table);
HOSTTRACE_DEBUG(" HSA-trace(");
if(!hsa_api_vec.empty())
{
for(unsigned i = 0; i < hsa_api_vec.size(); ++i)
{
uint32_t cid = HSA_API_ID_NUMBER;
const char* api = hsa_api_vec[i].c_str();
ROCTRACER_CALL(roctracer_op_code(ACTIVITY_DOMAIN_HSA_API, api,
&cid, nullptr));
ROCTRACER_CALL(roctracer_enable_op_callback(
ACTIVITY_DOMAIN_HSA_API, cid, hsa_api_callback, nullptr));
HOSTTRACE_DEBUG(" %s", api);
}
}
else
{
ROCTRACER_CALL(roctracer_enable_domain_callback(
ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, nullptr));
}
HOSTTRACE_DEBUG("\n");
}
bool trace_hsa_activity =
tim::get_env("HOSTTRACE_ROCTRACER_HSA_ACTIVITY", true);
// Enable HSA GPU activity
if(trace_hsa_activity)
{
// initialize HSA tracing
roctracer::hsa_ops_properties_t ops_properties{
table,
reinterpret_cast<activity_async_callback_t>(hsa_activity_callback),
nullptr, output_prefix
};
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_OPS, &ops_properties);
HOSTTRACE_DEBUG(" HSA-activity-trace()\n");
ROCTRACER_CALL(roctracer_enable_op_activity(ACTIVITY_DOMAIN_HSA_OPS,
HSA_OP_ID_COPY));
}
};
auto _tear_down = []() {
ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API));
ROCTRACER_CALL(
roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, HSA_OP_ID_COPY));
};
if(comp::roctracer::is_setup()) _setup();
comp::roctracer::add_setup("hsa", std::move(_setup));
comp::roctracer::add_tear_down("hsa", std::move(_tear_down));
return true;
}
// HSA-runtime on-unload method
void OnUnload()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// ONLOAD_TRACE("");
}
}