Update to use rocprofiler-sdk (#55)
- Renames the CMake option "ROCPROFSYS_USE_HIP" to "ROCPROFSYS_USE_ROCM" - Remove the "ROCPROFSYS_USE_ROCM_SMI option. Controlled with the "ROCPROFSYS_USE_ROCM" option, instead. - Runtime configuration can still toggle ROCPROFSYS_USE_ROCM_SMI to disable the sampling. - Rename ROCPROFSYS_HIP_VERSION macro to ROCPROFSYS_ROCM_VERSION and remove blocks for `ROCPROFSYS_ROCM_VERSION < 60000` - Remove ROCPROFSYS_USE_ROCTRACER and ROCPROFSYS_USE_ROCPROFILER - Update test cases - Update docker files and workflows to install cmake 3.21, which is required for the rocprofiler-sdk findPackage script. - Removed rocm-6.2 from workflows due to a rocprofiler-sdk API change.
このコミットが含まれているのは:
@@ -28,8 +28,6 @@ set(component_headers
|
||||
${CMAKE_CURRENT_LIST_DIR}/mpi_gotcha.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/numa_gotcha.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/rcclp.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/rocprofiler.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/roctracer.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/pthread_gotcha.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/pthread_create_gotcha.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/pthread_mutex_gotcha.hpp)
|
||||
@@ -37,16 +35,6 @@ set(component_headers
|
||||
target_sources(rocprofiler-systems-object-library PRIVATE ${component_sources}
|
||||
${component_headers})
|
||||
|
||||
if(ROCPROFSYS_USE_ROCPROFILER)
|
||||
target_sources(rocprofiler-systems-object-library
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/rocprofiler.cpp)
|
||||
endif()
|
||||
|
||||
if(ROCPROFSYS_USE_ROCTRACER)
|
||||
target_sources(rocprofiler-systems-object-library
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/roctracer.cpp)
|
||||
endif()
|
||||
|
||||
if(ROCPROFSYS_USE_RCCL)
|
||||
target_sources(rocprofiler-systems-object-library
|
||||
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/rcclp.cpp)
|
||||
|
||||
@@ -64,13 +64,13 @@ using tim::type_list;
|
||||
// these categories increment push/pop counts, which are used for sanity checks since
|
||||
// they should ALWAYS be popped if they were pushed
|
||||
using tracing_count_categories_t =
|
||||
type_list<category::host, category::mpi, category::pthread, category::rocm_hip,
|
||||
category::rocm_hsa, category::rocm_rccl>;
|
||||
type_list<category::host, category::mpi, category::pthread, category::rocm_hip_api,
|
||||
category::rocm_hsa_api, category::rocm_rccl>;
|
||||
|
||||
// convert these categories to throughput points
|
||||
using causal_throughput_categories_t =
|
||||
type_list<category::host, category::kokkos, category::ompt, category::rocm_hip,
|
||||
category::rocm_hsa, category::rocm_rccl, category::rocm_roctx>;
|
||||
type_list<category::host, category::kokkos, category::ompt, category::rocm_hip_api,
|
||||
category::rocm_hsa_api, category::rocm_rccl, category::rocm_marker_api>;
|
||||
|
||||
// define this outside of category region functions so that the
|
||||
// static thread_local is global instead of per-template instantiation
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "core/utility.hpp"
|
||||
#include "library/causal/delay.hpp"
|
||||
#include "library/components/category_region.hpp"
|
||||
#include "library/components/roctracer.hpp"
|
||||
#include "library/runtime.hpp"
|
||||
#include "library/sampling.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
@@ -61,7 +60,7 @@ shutdown();
|
||||
|
||||
namespace component
|
||||
{
|
||||
using bundle_t = tim::lightweight_tuple<comp::wall_clock, comp::roctracer_data>;
|
||||
using bundle_t = tim::lightweight_tuple<comp::wall_clock>;
|
||||
using category_region_t = tim::lightweight_tuple<category_region<category::pthread>>;
|
||||
|
||||
namespace
|
||||
@@ -82,7 +81,6 @@ inline void
|
||||
start_bundle(bundle_t& _bundle, int64_t _tid, Args&&... _args)
|
||||
{
|
||||
if(!get_use_timemory() && !get_use_perfetto()) return;
|
||||
trait::runtime_enabled<comp::roctracer_data>::set(get_use_roctracer());
|
||||
ROCPROFSYS_BASIC_VERBOSE_F(3, "starting bundle '%s' in thread %li...\n",
|
||||
_bundle.key().c_str(), _tid);
|
||||
if constexpr(sizeof...(Args) > 0)
|
||||
@@ -619,5 +617,3 @@ pthread_create_gotcha::operator()(pthread_t* thread, const pthread_attr_t* attr,
|
||||
}
|
||||
} // namespace component
|
||||
} // namespace rocprofsys
|
||||
|
||||
TIMEMORY_INITIALIZE_STORAGE(component::roctracer_data)
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "library/components/rocprofiler.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "core/config.hpp"
|
||||
#include "core/debug.hpp"
|
||||
#include "core/defines.hpp"
|
||||
#include "core/dynamic_library.hpp"
|
||||
#include "core/perfetto.hpp"
|
||||
#include "core/redirect.hpp"
|
||||
#include "library/rocprofiler.hpp"
|
||||
#include "library/sampling.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
|
||||
#include <timemory/storage/types.hpp>
|
||||
#include <timemory/utility/types.hpp>
|
||||
#include <timemory/variadic/functional.hpp>
|
||||
#include <timemory/variadic/lightweight_tuple.hpp>
|
||||
|
||||
#include <rocprofiler.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rocprofsys
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
namespace
|
||||
{
|
||||
auto&
|
||||
rocprofiler_activity_count()
|
||||
{
|
||||
static std::atomic<int64_t> _v{ 0 };
|
||||
return _v;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
unique_ptr_t<rocm_data_t>&
|
||||
rocm_data(int64_t _tid)
|
||||
{
|
||||
using thread_data_t = thread_data<rocm_data_t, rocm_event>;
|
||||
return thread_data_t::instance(construct_on_thread{ _tid });
|
||||
}
|
||||
|
||||
rocm_event::rocm_event(uint32_t _dev, uint32_t _thr, uint32_t _queue,
|
||||
std::string _event_name, rocm_metric_type _begin,
|
||||
rocm_metric_type _end, uint32_t _feature_count, void* _features_v)
|
||||
: device_id{ _dev }
|
||||
, thread_id{ _thr }
|
||||
, queue_id{ _queue }
|
||||
, entry{ _begin }
|
||||
, exit{ _end }
|
||||
, name(std::move(_event_name))
|
||||
{
|
||||
feature_values.reserve(_feature_count);
|
||||
feature_names.reserve(_feature_count);
|
||||
auto* _features = static_cast<rocprofiler_feature_t*>(_features_v);
|
||||
for(uint32_t i = 0; i < _feature_count; ++i)
|
||||
{
|
||||
const rocprofiler_feature_t* p = &_features[i];
|
||||
feature_names.emplace_back(i);
|
||||
switch(p->data.kind)
|
||||
{
|
||||
// Output metrics results
|
||||
case ROCPROFILER_DATA_KIND_UNINIT: break;
|
||||
case ROCPROFILER_DATA_KIND_BYTES:
|
||||
feature_values.emplace_back(
|
||||
rocm_feature_value{ p->data.result_bytes.size });
|
||||
break;
|
||||
case ROCPROFILER_DATA_KIND_INT32:
|
||||
feature_values.emplace_back(rocm_feature_value{ p->data.result_int32 });
|
||||
break;
|
||||
case ROCPROFILER_DATA_KIND_FLOAT:
|
||||
feature_values.emplace_back(rocm_feature_value{ p->data.result_float });
|
||||
break;
|
||||
case ROCPROFILER_DATA_KIND_DOUBLE:
|
||||
feature_values.emplace_back(rocm_feature_value{ p->data.result_double });
|
||||
break;
|
||||
case ROCPROFILER_DATA_KIND_INT64:
|
||||
feature_values.emplace_back(rocm_feature_value{ p->data.result_int64 });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
rocm_event::as_string() const
|
||||
{
|
||||
std::stringstream _ss{};
|
||||
_ss << name << ", device: " << device_id << ", queue: " << queue_id
|
||||
<< ", thread: " << thread_id << ", entry: " << entry << ", exit = " << exit;
|
||||
_ss.precision(3);
|
||||
_ss << std::fixed;
|
||||
for(size_t i = 0; i < feature_names.size(); ++i)
|
||||
{
|
||||
auto _name = rocprofsys::rocprofiler::get_data_labels().at(device_id).at(
|
||||
feature_names.at(i));
|
||||
_ss << ", " << _name << " = ";
|
||||
auto _as_string = [&_ss](auto&& itr) { _ss << std::setw(4) << itr; };
|
||||
std::visit(_as_string, feature_values.at(i));
|
||||
}
|
||||
return _ss.str();
|
||||
}
|
||||
|
||||
void
|
||||
rocprofiler::preinit()
|
||||
{
|
||||
rocprofiler_data::label() = "rocprofiler";
|
||||
rocprofiler_data::description() = "ROCm hardware counters";
|
||||
}
|
||||
|
||||
void
|
||||
rocprofiler::start()
|
||||
{
|
||||
if(tracker_type::start() == 0) setup();
|
||||
}
|
||||
|
||||
void
|
||||
rocprofiler::stop()
|
||||
{
|
||||
if(tracker_type::stop() == 0) shutdown();
|
||||
}
|
||||
|
||||
bool
|
||||
rocprofiler::is_setup()
|
||||
{
|
||||
return rocprofsys::rocprofiler::is_setup();
|
||||
}
|
||||
|
||||
void
|
||||
rocprofiler::add_setup(const std::string&, std::function<void()>&&)
|
||||
{}
|
||||
|
||||
void
|
||||
rocprofiler::add_shutdown(const std::string&, std::function<void()>&&)
|
||||
{}
|
||||
|
||||
void
|
||||
rocprofiler::remove_setup(const std::string&)
|
||||
{}
|
||||
|
||||
void
|
||||
rocprofiler::remove_shutdown(const std::string&)
|
||||
{}
|
||||
|
||||
void
|
||||
rocprofiler::setup()
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(1, "rocprofiler is setup\n");
|
||||
}
|
||||
|
||||
void
|
||||
rocprofiler::shutdown()
|
||||
{
|
||||
rocprofsys::rocprofiler::post_process();
|
||||
rocprofsys::rocprofiler::rocm_cleanup();
|
||||
ROCPROFSYS_VERBOSE_F(1, "rocprofiler is shutdown\n");
|
||||
}
|
||||
|
||||
scope::transient_destructor
|
||||
rocprofiler::protect_flush_activity()
|
||||
{
|
||||
return scope::transient_destructor([]() { --rocprofiler_activity_count(); },
|
||||
[]() { ++rocprofiler_activity_count(); });
|
||||
}
|
||||
} // namespace component
|
||||
} // namespace rocprofsys
|
||||
|
||||
ROCPROFSYS_INSTANTIATE_EXTERN_COMPONENT(rocprofiler, false, void)
|
||||
ROCPROFSYS_INSTANTIATE_EXTERN_COMPONENT(rocprofiler_data, true,
|
||||
tim::component::rocprofiler_value)
|
||||
@@ -1,241 +0,0 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/components/fwd.hpp"
|
||||
#include "core/defines.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
|
||||
#include <timemory/api.hpp>
|
||||
#include <timemory/backends/hardware_counters.hpp>
|
||||
#include <timemory/components/base.hpp>
|
||||
#include <timemory/components/data_tracker/components.hpp>
|
||||
#include <timemory/components/macros.hpp>
|
||||
#include <timemory/enum.h>
|
||||
#include <timemory/macros.hpp>
|
||||
#include <timemory/macros/os.hpp>
|
||||
#include <timemory/mpl/concepts.hpp>
|
||||
#include <timemory/mpl/macros.hpp>
|
||||
#include <timemory/mpl/type_traits.hpp>
|
||||
#include <timemory/mpl/types.hpp>
|
||||
#include <timemory/utility/transient_function.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofsys
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
using rocm_metric_type = unsigned long long;
|
||||
using rocm_info_entry = ::tim::hardware_counters::info;
|
||||
using rocm_feature_value = std::variant<uint32_t, float, uint64_t, double>;
|
||||
|
||||
struct rocm_counter
|
||||
{
|
||||
std::array<rocm_metric_type, ROCPROFSYS_ROCM_MAX_COUNTERS> counters;
|
||||
};
|
||||
|
||||
struct rocm_event
|
||||
{
|
||||
using value_type = rocm_feature_value;
|
||||
|
||||
uint32_t device_id = 0;
|
||||
uint32_t thread_id = 0;
|
||||
uint32_t queue_id = 0;
|
||||
rocm_metric_type entry = 0;
|
||||
rocm_metric_type exit = 0;
|
||||
std::string name = {};
|
||||
std::vector<size_t> feature_names = {};
|
||||
std::vector<rocm_feature_value> feature_values = {};
|
||||
|
||||
rocm_event() = default;
|
||||
rocm_event(uint32_t _dev, uint32_t _thr, uint32_t _queue, std::string _event_name,
|
||||
rocm_metric_type begin, rocm_metric_type end, uint32_t _feature_count,
|
||||
void* _features);
|
||||
|
||||
std::string as_string() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& _os, const rocm_event& _v)
|
||||
{
|
||||
return (_os << _v.as_string());
|
||||
}
|
||||
|
||||
friend bool operator<(const rocm_event& _lhs, const rocm_event& _rhs)
|
||||
{
|
||||
return std::tie(_lhs.device_id, _lhs.queue_id, _lhs.entry, _lhs.thread_id) <
|
||||
std::tie(_rhs.device_id, _rhs.queue_id, _rhs.entry, _rhs.thread_id);
|
||||
}
|
||||
};
|
||||
|
||||
using rocm_data_t = std::vector<rocm_event>;
|
||||
using rocm_data_tracker = data_tracker<rocm_feature_value, rocm_event>;
|
||||
|
||||
rocprofsys::unique_ptr_t<rocm_data_t>&
|
||||
rocm_data(int64_t _tid = threading::get_id());
|
||||
|
||||
using rocprofiler_value = typename rocm_event::value_type;
|
||||
using rocprofiler_data = data_tracker<rocprofiler_value, rocprofiler>;
|
||||
|
||||
struct rocprofiler
|
||||
: base<rocprofiler, void>
|
||||
, private policy::instance_tracker<rocprofiler, false>
|
||||
{
|
||||
using value_type = void;
|
||||
using base_type = base<rocprofiler, void>;
|
||||
using tracker_type = policy::instance_tracker<rocprofiler, false>;
|
||||
|
||||
ROCPROFSYS_DEFAULT_OBJECT(rocprofiler)
|
||||
|
||||
static void preinit();
|
||||
static void global_init() { setup(); }
|
||||
static void global_finalize() { shutdown(); }
|
||||
|
||||
static bool is_setup();
|
||||
static void setup();
|
||||
static void shutdown();
|
||||
static void add_setup(const std::string&, std::function<void()>&&);
|
||||
static void add_shutdown(const std::string&, std::function<void()>&&);
|
||||
static void remove_setup(const std::string&);
|
||||
static void remove_shutdown(const std::string&);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
// this function protects rocprofiler_flush_activty from being called
|
||||
// when rocprof-sys exits during a callback
|
||||
[[nodiscard]] static scope::transient_destructor protect_flush_activity();
|
||||
};
|
||||
|
||||
#if !defined(ROCPROFSYS_USE_ROCPROFILER)
|
||||
inline void
|
||||
rocprofiler::setup()
|
||||
{}
|
||||
|
||||
inline void
|
||||
rocprofiler::shutdown()
|
||||
{}
|
||||
|
||||
inline bool
|
||||
rocprofiler::is_setup()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
} // namespace component
|
||||
} // namespace rocprofsys
|
||||
|
||||
namespace tim
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
using ::rocprofsys::component::rocm_data_tracker;
|
||||
using ::rocprofsys::component::rocm_feature_value;
|
||||
using ::rocprofsys::component::rocprofiler_data;
|
||||
using ::rocprofsys::component::rocprofiler_value;
|
||||
} // namespace component
|
||||
} // namespace tim
|
||||
|
||||
namespace tim
|
||||
{
|
||||
namespace operation
|
||||
{
|
||||
template <>
|
||||
struct set_storage<component::rocm_data_tracker>
|
||||
{
|
||||
using T = component::rocm_data_tracker;
|
||||
static constexpr size_t max_threads = 4096;
|
||||
using type = T;
|
||||
using storage_array_t = std::array<storage<type>*, max_threads>;
|
||||
friend struct get_storage<component::rocm_data_tracker>;
|
||||
|
||||
ROCPROFSYS_DEFAULT_OBJECT(set_storage)
|
||||
|
||||
auto operator()(storage<type>*, size_t) const {}
|
||||
auto operator()(type&, size_t) const {}
|
||||
auto operator()(storage<type>* _v) const { get().fill(_v); }
|
||||
|
||||
private:
|
||||
static storage_array_t& get()
|
||||
{
|
||||
static storage_array_t _v = { nullptr };
|
||||
return _v;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_storage<component::rocm_data_tracker>
|
||||
{
|
||||
using type = component::rocm_data_tracker;
|
||||
|
||||
ROCPROFSYS_DEFAULT_OBJECT(get_storage)
|
||||
|
||||
auto operator()(const type&) const
|
||||
{
|
||||
return operation::set_storage<type>::get().at(0);
|
||||
}
|
||||
|
||||
auto operator()() const
|
||||
{
|
||||
type _obj{};
|
||||
return (*this)(_obj);
|
||||
}
|
||||
|
||||
auto operator()(size_t _idx) const
|
||||
{
|
||||
return operation::set_storage<type>::get().at(_idx);
|
||||
}
|
||||
|
||||
auto operator()(type&, size_t _idx) const { return (*this)(_idx); }
|
||||
};
|
||||
} // namespace operation
|
||||
} // namespace tim
|
||||
|
||||
#if !defined(ROCPROFSYS_USE_ROCPROFILER)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(is_available, component::rocprofiler_data, false_type)
|
||||
#endif
|
||||
|
||||
TIMEMORY_SET_COMPONENT_API(component::rocprofiler_data, project::timemory,
|
||||
category::timing, os::supports_unix)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(is_timing_category, component::rocprofiler_data,
|
||||
false_type)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(uses_timing_units, component::rocprofiler_data,
|
||||
false_type)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(report_units, component::rocprofiler_data, false_type)
|
||||
TIMEMORY_STATISTICS_TYPE(component::rocprofiler_data, component::rocprofiler_value)
|
||||
TIMEMORY_STATISTICS_TYPE(component::rocm_data_tracker, component::rocm_feature_value)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(report_units, component::rocm_data_tracker, false_type)
|
||||
|
||||
#if !defined(ROCPROFSYS_EXTERN_COMPONENTS) || \
|
||||
(defined(ROCPROFSYS_EXTERN_COMPONENTS) && ROCPROFSYS_EXTERN_COMPONENTS > 0)
|
||||
|
||||
# include <timemory/operations.hpp>
|
||||
|
||||
ROCPROFSYS_DECLARE_EXTERN_COMPONENT(rocprofiler, false, void)
|
||||
ROCPROFSYS_DECLARE_EXTERN_COMPONENT(rocprofiler_data, true, double)
|
||||
|
||||
#endif
|
||||
@@ -1,396 +0,0 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "library/components/roctracer.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "core/config.hpp"
|
||||
#include "core/debug.hpp"
|
||||
#include "core/defines.hpp"
|
||||
#include "core/dynamic_library.hpp"
|
||||
#include "core/redirect.hpp"
|
||||
#include "library/roctracer.hpp"
|
||||
#include "library/runtime.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
#include "library/thread_info.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <roctracer.h>
|
||||
|
||||
#define HIP_PROF_HIP_API_STRING 1
|
||||
|
||||
#include <roctracer_ext.h>
|
||||
#include <roctracer_hip.h>
|
||||
|
||||
#if ROCPROFSYS_HIP_VERSION < 50300
|
||||
# include <roctracer_hcc.h>
|
||||
#endif
|
||||
|
||||
#define AMD_INTERNAL_BUILD 1
|
||||
#include <roctracer_hsa.h>
|
||||
|
||||
namespace rocprofsys
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
namespace
|
||||
{
|
||||
auto&
|
||||
roctracer_activity_count()
|
||||
{
|
||||
static std::atomic<int64_t> _v{ 0 };
|
||||
return _v;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void
|
||||
roctracer::preinit()
|
||||
{
|
||||
roctracer_data::label() = "roctracer";
|
||||
roctracer_data::description() = "ROCm tracer (activity API)";
|
||||
}
|
||||
|
||||
void
|
||||
roctracer::start()
|
||||
{
|
||||
if(tracker_type::start() == 0) setup(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
roctracer::stop()
|
||||
{
|
||||
if(tracker_type::stop() == 0) shutdown();
|
||||
}
|
||||
|
||||
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_shutdown(const std::string& _lbl, std::function<void()>&& _func)
|
||||
{
|
||||
roctracer_shutdown_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_shutdown(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(void* table, bool on_load_trace)
|
||||
{
|
||||
if(!get_use_roctracer()) return;
|
||||
|
||||
auto_lock_t _lk{ type_mutex<roctracer>() };
|
||||
if(roctracer_is_setup()) return;
|
||||
roctracer_is_setup() = true;
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(1, "setting up roctracer...\n");
|
||||
ROCPROFSYS_SCOPED_SAMPLING_ON_CHILD_THREADS(false);
|
||||
|
||||
dynamic_library _amdhip64{ "ROCPROFSYS_ROCTRACER_LIBAMDHIP64",
|
||||
find_library_path("libamdhip64.so",
|
||||
{ "ROCPROFSYS_ROCM_PATH", "ROCM_PATH" },
|
||||
{ ROCPROFSYS_DEFAULT_ROCM_PATH }) };
|
||||
|
||||
#if ROCPROFSYS_HIP_VERSION_MAJOR == 4 && ROCPROFSYS_HIP_VERSION_MINOR < 4
|
||||
dynamic_library _kfdwrapper{
|
||||
"ROCPROFSYS_ROCTRACER_LIBKFDWRAPPER",
|
||||
find_library_path("libkfdwrapper64.so", { "ROCPROFSYS_ROCM_PATH", "ROCM_PATH" },
|
||||
{ ROCPROFSYS_DEFAULT_ROCM_PATH },
|
||||
{ "roctracer/lib", "roctracer/lib64", "lib", "lib64" })
|
||||
};
|
||||
#endif
|
||||
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_set_properties(ACTIVITY_DOMAIN_HIP_API, nullptr));
|
||||
|
||||
// Allocating tracing pool
|
||||
roctracer_properties_t properties{};
|
||||
memset(&properties, 0, sizeof(roctracer_properties_t));
|
||||
// properties.mode = 0x1000;
|
||||
properties.buffer_size = 0x100;
|
||||
properties.buffer_callback_fun = hip_activity_callback;
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_open_pool(&properties));
|
||||
|
||||
#if ROCPROFSYS_HIP_VERSION_MAJOR == 4 && ROCPROFSYS_HIP_VERSION_MINOR >= 4
|
||||
// HIP 4.5.0 has an invalid warning
|
||||
redirect _rd{ std::cerr, "roctracer_enable_callback(), get_op_end(), invalid domain "
|
||||
"ID(4) in: roctracer_enable_callback(hip_api_callback, "
|
||||
"nullptr)roctracer_enable_activity_expl(), get_op_end(), "
|
||||
"invalid domain ID(4) in: roctracer_enable_activity()" };
|
||||
#endif
|
||||
|
||||
if(get_trace_hip_api())
|
||||
{
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_enable_domain_callback(
|
||||
ACTIVITY_DOMAIN_HIP_API, hip_api_callback, nullptr));
|
||||
}
|
||||
|
||||
if(get_use_roctx())
|
||||
{
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_enable_domain_callback(
|
||||
ACTIVITY_DOMAIN_ROCTX, roctx_api_callback, nullptr));
|
||||
}
|
||||
|
||||
if(get_trace_hip_activity())
|
||||
{
|
||||
// Enable HIP activity tracing
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_enable_domain_activity(ACTIVITY_DOMAIN_HIP_OPS));
|
||||
}
|
||||
|
||||
if(table != nullptr)
|
||||
{
|
||||
ROCPROFSYS_VERBOSE(1 || on_load_trace, "[OnLoad] setting up HSA...\n");
|
||||
|
||||
bool trace_hsa_api = get_trace_hsa_api();
|
||||
|
||||
// Enable HSA API callbacks/activity
|
||||
if(trace_hsa_api)
|
||||
{
|
||||
std::vector<std::string> hsa_api_vec =
|
||||
tim::delimit(get_trace_hsa_api_types());
|
||||
|
||||
// initialize HSA tracing
|
||||
roctracer_set_properties(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_API), (void*) table);
|
||||
|
||||
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();
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_op_code(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_API), api,
|
||||
&cid, nullptr));
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_enable_op_callback(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_API), cid,
|
||||
hsa_api_callback, nullptr));
|
||||
|
||||
ROCPROFSYS_VERBOSE(1 || on_load_trace, " HSA-trace(%s)", api);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCPROFSYS_VERBOSE(1 || on_load_trace, " HSA-trace()\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_enable_domain_callback(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_API),
|
||||
hsa_api_callback, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
bool trace_hsa_activity = get_trace_hsa_activity();
|
||||
// Enable HSA GPU activity
|
||||
if(trace_hsa_activity)
|
||||
{
|
||||
#if ROCPROFSYS_HIP_VERSION < 50300
|
||||
using namespace roctracer;
|
||||
// initialize HSA tracing
|
||||
const char* output_prefix = nullptr;
|
||||
hsa_ops_properties_t ops_properties{
|
||||
table, reinterpret_cast<activity_async_callback_t>(hsa_activity_callback),
|
||||
nullptr, output_prefix
|
||||
};
|
||||
#elif ROCPROFSYS_HIP_VERSION < 50301
|
||||
hsa_ops_properties_t ops_properties;
|
||||
ops_properties.table = table;
|
||||
ops_properties.reserved1[0] = reinterpret_cast<void*>(&hsa_activity_callback);
|
||||
ops_properties.reserved1[1] = nullptr;
|
||||
ops_properties.reserved1[2] = nullptr;
|
||||
#else
|
||||
hsa_ops_properties_t ops_properties{
|
||||
table, reinterpret_cast<void*>(&hsa_activity_callback), nullptr, nullptr
|
||||
};
|
||||
#endif
|
||||
roctracer_set_properties(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_OPS), &ops_properties);
|
||||
|
||||
ROCPROFSYS_VERBOSE(1 || on_load_trace, " HSA-activity-trace()\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_enable_op_activity(
|
||||
static_cast<activity_domain_t>(ACTIVITY_DOMAIN_HSA_OPS), HSA_OP_ID_COPY));
|
||||
}
|
||||
}
|
||||
|
||||
// callback for HSA
|
||||
for(auto& itr : roctracer_setup_routines())
|
||||
itr.second();
|
||||
|
||||
// make sure all async callbacks are allocated
|
||||
for(size_t i = 0; i < thread_info::get_peak_num_threads(); ++i)
|
||||
hip_exec_activity_callbacks(i);
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(1, "roctracer is setup\n");
|
||||
}
|
||||
|
||||
void
|
||||
roctracer::flush()
|
||||
{
|
||||
auto wait_for_activity_flush_completion = []() {
|
||||
uint16_t nitr = 0;
|
||||
while(roctracer_activity_count() > 0 && nitr++ < 10)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
|
||||
};
|
||||
|
||||
// a flush may already be happening
|
||||
wait_for_activity_flush_completion();
|
||||
|
||||
if(roctracer_activity_count() == 0)
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(2, "executing roctracer_flush_activity()...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(roctracer_flush_activity());
|
||||
// wait to make sure flush completes
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
|
||||
wait_for_activity_flush_completion();
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCPROFSYS_CI_FAIL(true,
|
||||
"roctracer_activity_count() != 0 (== %li). "
|
||||
"roctracer::shutdown() most likely called during abort",
|
||||
roctracer_activity_count().load());
|
||||
}
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(2, "executing hip_exec_activity_callbacks(0..%zu)\n",
|
||||
thread_info::get_peak_num_threads());
|
||||
// make sure all async operations are executed
|
||||
for(size_t i = 0; i < thread_info::get_peak_num_threads(); ++i)
|
||||
hip_exec_activity_callbacks(i);
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(2, "roctracer flush completed\n");
|
||||
}
|
||||
|
||||
void
|
||||
roctracer::shutdown()
|
||||
{
|
||||
auto_lock_t _lk{ type_mutex<roctracer>() };
|
||||
if(!roctracer_is_setup()) return;
|
||||
|
||||
roctracer_is_setup() = false;
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(1, "shutting down roctracer...\n");
|
||||
|
||||
// callback for hsa
|
||||
ROCPROFSYS_VERBOSE_F(2, "executing %zu roctracer_shutdown_routines...\n",
|
||||
roctracer_shutdown_routines().size());
|
||||
for(auto& itr : roctracer_shutdown_routines())
|
||||
itr.second();
|
||||
|
||||
#if ROCPROFSYS_HIP_VERSION_MAJOR == 4 && ROCPROFSYS_HIP_VERSION_MINOR >= 4
|
||||
ROCPROFSYS_DEBUG_F("redirecting roctracer warnings\n");
|
||||
// HIP 4.5.0 has an invalid warning
|
||||
redirect _rd{
|
||||
std::cerr, "roctracer_disable_callback(), get_op_end(), invalid domain ID(4) "
|
||||
"in: roctracer_disable_callback()roctracer_disable_activity(), "
|
||||
"get_op_end(), invalid domain ID(4) in: roctracer_disable_activity()"
|
||||
};
|
||||
#endif
|
||||
|
||||
if(get_trace_hip_api())
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(
|
||||
2,
|
||||
"executing roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HIP_API)...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HIP_API));
|
||||
}
|
||||
|
||||
if(get_use_roctx())
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(
|
||||
2, "executing roctracer_disable_domain_activity(ACTIVITY_DOMAIN_ROCTX)...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_disable_domain_callback(ACTIVITY_DOMAIN_ROCTX));
|
||||
}
|
||||
|
||||
if(get_trace_hip_activity())
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(
|
||||
2,
|
||||
"executing roctracer_disable_domain_activity(ACTIVITY_DOMAIN_HIP_OPS)...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_disable_domain_activity(ACTIVITY_DOMAIN_HIP_OPS));
|
||||
}
|
||||
|
||||
if(get_trace_hsa_api())
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(
|
||||
2,
|
||||
"executing roctracer_disable_domain_activity(ACTIVITY_DOMAIN_HSA_API)...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API));
|
||||
}
|
||||
|
||||
if(get_trace_hsa_api())
|
||||
{
|
||||
ROCPROFSYS_VERBOSE_F(
|
||||
2, "executing roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, "
|
||||
"HSA_OP_ID_COPY)...\n");
|
||||
ROCPROFSYS_ROCTRACER_CALL(
|
||||
roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, HSA_OP_ID_COPY));
|
||||
}
|
||||
|
||||
ROCPROFSYS_VERBOSE_F(1, "roctracer is shutdown\n");
|
||||
}
|
||||
|
||||
scope::transient_destructor
|
||||
roctracer::protect_flush_activity()
|
||||
{
|
||||
return scope::transient_destructor([]() { --roctracer_activity_count(); },
|
||||
[]() { ++roctracer_activity_count(); });
|
||||
}
|
||||
} // namespace component
|
||||
} // namespace rocprofsys
|
||||
|
||||
ROCPROFSYS_INSTANTIATE_EXTERN_COMPONENT(roctracer, false, void)
|
||||
ROCPROFSYS_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
|
||||
@@ -1,117 +0,0 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/common.hpp"
|
||||
#include "core/components/fwd.hpp"
|
||||
#include "core/defines.hpp"
|
||||
|
||||
#include <timemory/api.hpp>
|
||||
#include <timemory/components/base.hpp>
|
||||
#include <timemory/components/data_tracker/components.hpp>
|
||||
#include <timemory/components/macros.hpp>
|
||||
#include <timemory/enum.h>
|
||||
#include <timemory/macros/os.hpp>
|
||||
#include <timemory/mpl/type_traits.hpp>
|
||||
#include <timemory/mpl/types.hpp>
|
||||
#include <timemory/utility/transient_function.hpp>
|
||||
|
||||
ROCPROFSYS_COMPONENT_ALIAS(roctracer_data,
|
||||
::tim::component::data_tracker<double, roctracer>)
|
||||
|
||||
namespace rocprofsys
|
||||
{
|
||||
namespace component
|
||||
{
|
||||
struct roctracer
|
||||
: base<roctracer, void>
|
||||
, private policy::instance_tracker<roctracer, false>
|
||||
{
|
||||
using value_type = void;
|
||||
using base_type = base<roctracer, void>;
|
||||
using tracker_type = policy::instance_tracker<roctracer, false>;
|
||||
|
||||
ROCPROFSYS_DEFAULT_OBJECT(roctracer)
|
||||
|
||||
static void preinit();
|
||||
static void global_finalize() { shutdown(); }
|
||||
|
||||
static bool is_setup();
|
||||
static void setup(void* hsa_api_table, bool on_load_trace = false);
|
||||
static void flush();
|
||||
static void shutdown();
|
||||
static void add_setup(const std::string&, std::function<void()>&&);
|
||||
static void add_shutdown(const std::string&, std::function<void()>&&);
|
||||
static void remove_setup(const std::string&);
|
||||
static void remove_shutdown(const std::string&);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
// this function protects roctracer_flush_activty from being called
|
||||
// when rocprof-sys exits during a callback
|
||||
[[nodiscard]] static scope::transient_destructor protect_flush_activity();
|
||||
};
|
||||
|
||||
#if !defined(ROCPROFSYS_USE_ROCTRACER)
|
||||
inline void
|
||||
roctracer::setup(void*, bool)
|
||||
{}
|
||||
|
||||
inline void
|
||||
roctracer::flush()
|
||||
{}
|
||||
|
||||
inline void
|
||||
roctracer::shutdown()
|
||||
{}
|
||||
|
||||
inline bool
|
||||
roctracer::is_setup()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
} // namespace component
|
||||
} // namespace rocprofsys
|
||||
|
||||
#if !defined(ROCPROFSYS_USE_ROCTRACER)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(is_available, component::roctracer_data, false_type)
|
||||
#endif
|
||||
|
||||
TIMEMORY_SET_COMPONENT_API(rocprofsys::component::roctracer_data, project::timemory,
|
||||
category::timing, os::supports_unix)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(is_timing_category, component::roctracer_data, true_type)
|
||||
ROCPROFSYS_DEFINE_CONCRETE_TRAIT(uses_timing_units, component::roctracer_data, true_type)
|
||||
|
||||
#if defined(ROCPROFSYS_USE_ROCTRACER) && ROCPROFSYS_USE_ROCTRACER > 0
|
||||
# if !defined(ROCPROFSYS_EXTERN_COMPONENTS) || \
|
||||
(defined(ROCPROFSYS_EXTERN_COMPONENTS) && ROCPROFSYS_EXTERN_COMPONENTS > 0)
|
||||
|
||||
# include <timemory/operations.hpp>
|
||||
|
||||
ROCPROFSYS_DECLARE_EXTERN_COMPONENT(roctracer, false, void)
|
||||
ROCPROFSYS_DECLARE_EXTERN_COMPONENT(roctracer_data, true, double)
|
||||
|
||||
# endif
|
||||
#endif
|
||||
新しいイシューから参照
ユーザーをブロックする