restructure libomnitrace + tasking and omnitrace-causal updates (#237)

* restructured libomnitrace

- this is necessary to incorporate some of the binary analysis capabilities into omnitrace exe
- created libomnitrace-core (static)
- created libomnitrace-binary (static)
- created libomnitrace (static)
- omnitrace-avail links to libomnitrace.a
- omnitrace-critical-trace links to libomnitrace.a
- tweaked the testing
  - reduced verbosity on some of MPI tests
  - excluded trace-time-window from tests on Ubuntu 18.04
  - reduced causal e2e iterations
- minor tweak to tasking
  - manually create `PTL::UserTaskQueue` instance instead of relying on `PTL::ThreadPool` to create it

* Update formatting workflow

- source formatting uses ubuntu-22.04
- check-includes doesn't generate false positive for 'include "timemory.hpp"'

* omnitrace-causal --generate-configs

- fix config generation in omnitrace causal
- add test for omnitrace-causal + generating configs

* Fix omnitrace-object-library build

- accidentally included rocm sources in non-rocm builds

* Fix rocm compilation w/o rocprofiler

* update timemory submodule with mpi_get warning messages

* sampling offload file updates

- more verbose messages
- disable offload before stopping

* testing updates

- increase causal e2e iterations to 12
- increase lock_environment verbose to 2 (for sampling offload messages)
- fix return for omnitrace_add_validation_test
This commit is contained in:
Jonathan R. Madsen
2023-02-04 10:59:50 -06:00
committed by GitHub
parent 8feb6bf8b6
commit e7d3125459
164 changed files with 721 additions and 574 deletions
+52
View File
@@ -0,0 +1,52 @@
#
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/defines.hpp.in
${CMAKE_CURRENT_BINARY_DIR}/defines.hpp @ONLY)
set(core_sources
${CMAKE_CURRENT_LIST_DIR}/categories.cpp
${CMAKE_CURRENT_LIST_DIR}/config.cpp
${CMAKE_CURRENT_LIST_DIR}/constraint.cpp
${CMAKE_CURRENT_LIST_DIR}/debug.cpp
${CMAKE_CURRENT_LIST_DIR}/dynamic_library.cpp
${CMAKE_CURRENT_LIST_DIR}/exception.cpp
${CMAKE_CURRENT_LIST_DIR}/gpu.cpp
${CMAKE_CURRENT_LIST_DIR}/locking.cpp
${CMAKE_CURRENT_LIST_DIR}/mproc.cpp
${CMAKE_CURRENT_LIST_DIR}/perfetto.cpp
${CMAKE_CURRENT_LIST_DIR}/state.cpp
${CMAKE_CURRENT_LIST_DIR}/timemory.cpp)
set(core_headers
${CMAKE_CURRENT_LIST_DIR}/categories.hpp
${CMAKE_CURRENT_LIST_DIR}/common.hpp
${CMAKE_CURRENT_LIST_DIR}/concepts.hpp
${CMAKE_CURRENT_LIST_DIR}/config.hpp
${CMAKE_CURRENT_LIST_DIR}/constraint.hpp
${CMAKE_CURRENT_LIST_DIR}/debug.hpp
${CMAKE_CURRENT_LIST_DIR}/dynamic_library.hpp
${CMAKE_CURRENT_LIST_DIR}/exception.hpp
${CMAKE_CURRENT_LIST_DIR}/gpu.hpp
${CMAKE_CURRENT_LIST_DIR}/locking.hpp
${CMAKE_CURRENT_LIST_DIR}/mproc.hpp
${CMAKE_CURRENT_LIST_DIR}/perfetto.hpp
${CMAKE_CURRENT_LIST_DIR}/redirect.hpp
${CMAKE_CURRENT_LIST_DIR}/state.hpp
${CMAKE_CURRENT_LIST_DIR}/timemory.hpp
${CMAKE_CURRENT_LIST_DIR}/utility.hpp)
add_library(omnitrace-core-library STATIC)
add_library(omnitrace::omnitrace-core ALIAS omnitrace-core-library)
target_sources(omnitrace-core-library PRIVATE ${core_sources} ${core_headers}
${CMAKE_CURRENT_BINARY_DIR}/defines.hpp)
add_subdirectory(binary)
add_subdirectory(components)
add_subdirectory(containers)
target_include_directories(omnitrace-core-library BEFORE
PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(omnitrace-core-library
PRIVATE omnitrace::omnitrace-interface-library)
set_target_properties(omnitrace-core-library PROPERTIES OUTPUT_NAME omnitrace-core)
+7
View File
@@ -0,0 +1,7 @@
#
set(binary_sources ${CMAKE_CURRENT_LIST_DIR}/address_range.cpp)
set(binary_headers ${CMAKE_CURRENT_LIST_DIR}/address_range.hpp
${CMAKE_CURRENT_LIST_DIR}/fwd.hpp)
target_sources(omnitrace-core-library PRIVATE ${binary_sources} ${binary_headers})
+190
View File
@@ -0,0 +1,190 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "binary/address_range.hpp"
#include "debug.hpp"
namespace omnitrace
{
namespace binary
{
address_range::address_range(uintptr_t _v)
: low{ _v }
, high{ _v }
{}
address_range::address_range(uintptr_t _low, uintptr_t _high)
: low{ _low }
, high{ _high }
{
TIMEMORY_REQUIRE(high >= low)
<< "Error! address_range high must be >= low. low=" << as_hex(low)
<< ", high=" << as_hex(high) << "\n";
}
bool
address_range::is_range() const
{
return (low < high);
}
std::string
address_range::as_string(int _depth) const
{
std::stringstream _ss{};
_ss << std::hex;
_ss << std::setw(2 * _depth) << "";
_ss.fill('0');
_ss << "0x" << std::setw(16) << low << "-"
<< "0x" << std::setw(16) << high;
return _ss.str();
}
uintptr_t
address_range::size() const
{
return (low == high) ? 1 : (high > low) ? (high - low + 1) : (low - high + 1);
}
bool
address_range::is_valid() const
{
return (low <= high && (low + 1) > 1);
}
bool
address_range::contains(uintptr_t _v) const
{
return (is_range()) ? (low <= _v && high > _v) : (_v == low);
}
bool
address_range::contains(address_range _v) const
{
return (*this == _v) || (contains(_v.low) && contains(_v.high));
}
bool
address_range::overlaps(address_range _v) const
{
if(contains(_v)) return false;
int64_t _lhs_diff = (high - low);
int64_t _rhs_diff = (_v.high - _v.low);
int64_t _diff = (std::max(high, _v.high) - std::min(low, _v.low));
return (_diff < (_lhs_diff + _rhs_diff));
}
bool
address_range::contiguous_with(address_range _v) const
{
return (_v.low == high || low == _v.high);
}
bool
address_range::operator==(address_range _v) const
{
// if arg is range and this is not range, call this function with arg
// if(_v.is_range() && !is_range()) return false;
// check if arg is in range
// if(is_range() && !_v.is_range()) return false;
// both are ranges or both are just address
return std::tie(low, high) == std::tie(_v.low, _v.high);
}
bool
address_range::operator<(address_range _v) const
{
if(is_range() && !_v.is_range())
{
return (low == _v.low) ? true : (low < _v.low);
}
else if(!is_range() && _v.is_range())
{
return (low == _v.low) ? false : (low < _v.low);
}
else if(!is_range() && !_v.is_range())
{
return (low < _v.low);
}
return std::tie(low, high) < std::tie(_v.low, _v.high);
// if(_v.low == _v.high && _v.low >= low && _v.low < high) return false;
// return (low == _v.low) ? (high > _v.high) : (low < _v.low);
}
bool
address_range::operator>(address_range _v) const
{
return !(*this < _v) && !(*this == _v);
}
address_range&
address_range::operator+=(uintptr_t _v)
{
if(is_valid())
{
low += _v;
high += _v;
}
else
{
low = _v;
high = _v;
}
return *this;
}
address_range&
address_range::operator-=(uintptr_t _v)
{
if(is_valid())
{
low -= _v;
high -= _v;
}
else
{
low = _v;
high = _v;
}
return *this;
}
address_range&
address_range::operator+=(address_range _v)
{
if(!contiguous_with(_v))
throw exception<std::runtime_error>(
"attempting to add two address ranges that are not contiguous");
low = std::min(low, _v.low);
high = std::max(high, _v.high);
return *this;
}
hash_value_t
address_range::hash() const
{
return (is_range()) ? tim::get_combined_hash_id(hash_value_t{ low }, high)
: hash_value_t{ low };
}
} // namespace binary
} // namespace omnitrace
+104
View File
@@ -0,0 +1,104 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/binary/fwd.hpp"
#include "core/common.hpp"
#include "core/timemory.hpp"
#include <timemory/hash/types.hpp>
#include <timemory/utility/macros.hpp>
#include <cstdint>
#include <limits>
namespace omnitrace
{
namespace binary
{
struct address_range
{
// set to low to max and high to min to support std::min(...)
// and std::max(...) assignment
uintptr_t low = std::numeric_limits<uintptr_t>::max();
uintptr_t high = std::numeric_limits<uintptr_t>::min();
OMNITRACE_DEFAULT_OBJECT(address_range)
explicit address_range(uintptr_t _v);
address_range(uintptr_t _low, uintptr_t _high);
bool contains(uintptr_t) const;
bool contains(address_range) const;
bool overlaps(address_range) const;
bool contiguous_with(address_range) const;
bool operator==(address_range _v) const;
bool operator!=(address_range _v) const { return !(*this == _v); }
bool operator<(address_range _v) const;
bool operator>(address_range _v) const;
address_range& operator+=(uintptr_t);
address_range& operator-=(uintptr_t);
address_range& operator+=(address_range);
bool is_range() const;
hash_value_t hash() const;
std::string as_string(int _depth = 0) const;
bool is_valid() const;
uintptr_t size() const;
explicit operator bool() const { return is_valid(); }
template <typename ArchiveT>
void serialize(ArchiveT& ar, const unsigned)
{
ar(cereal::make_nvp("low", low));
ar(cereal::make_nvp("high", high));
}
};
} // namespace binary
inline binary::address_range
operator+(binary::address_range _lhs, uintptr_t _v)
{
return (_lhs += _v);
}
inline binary::address_range
operator+(uintptr_t _v, binary::address_range _lhs)
{
return (_lhs += _v);
}
} // namespace omnitrace
namespace std
{
template <>
struct hash<::omnitrace::binary::address_range>
{
using address_range_t = ::omnitrace::binary::address_range;
auto operator()(const address_range_t& _v) const { return _v.hash(); }
auto operator()(address_range_t&& _v) const { return _v.hash(); }
};
} // namespace std
+62
View File
@@ -0,0 +1,62 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common/defines.h"
#include "core/common.hpp"
#include "core/defines.hpp"
#include "core/exception.hpp"
#include <timemory/hash/types.hpp>
#include <timemory/mpl/concepts.hpp>
#include <timemory/tpls/cereal/cereal/cereal.hpp>
#include <timemory/unwind/bfd.hpp>
#include <timemory/unwind/types.hpp>
#include <timemory/utility/procfs/maps.hpp>
#include <cstdint>
#include <deque>
#include <map>
#include <memory>
#include <regex>
#include <string>
#include <tuple>
#include <variant>
namespace omnitrace
{
namespace binary
{
namespace procfs = ::tim::procfs; // NOLINT
using bfd_file = ::tim::unwind::bfd_file;
using hash_value_t = ::tim::hash_value_t;
struct address_range;
struct address_multirange;
struct scope_filter;
struct symbol;
struct dwarf_entry;
struct binary_info;
} // namespace binary
} // namespace omnitrace
+141
View File
@@ -0,0 +1,141 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "core/categories.hpp"
#include "core/common.hpp"
#include "core/config.hpp"
#include "core/constraint.hpp"
#include "core/debug.hpp"
#include "core/timemory.hpp"
#include "core/utility.hpp"
#include <set>
#include <string>
namespace omnitrace
{
namespace categories
{
namespace
{
template <typename Tp>
void
configure_categories(bool _enable, const std::set<std::string>& _categories)
{
auto _name = trait::name<Tp>::value;
if(_categories.count(_name) > 0)
{
OMNITRACE_VERBOSE_F(3, "%s category: %s\n", (_enable) ? "Enabling" : "Disabling",
_name);
trait::runtime_enabled<Tp>::set(_enable);
}
}
template <size_t... Idx>
void
configure_categories(bool _enable, const std::set<std::string>& _categories,
std::index_sequence<Idx...>)
{
(configure_categories<category_type_id_t<Idx>>(_enable, _categories), ...);
}
void
configure_categories(bool _enable, const std::set<std::string>& _categories)
{
OMNITRACE_VERBOSE_F(1, "%s categories...\n", (_enable) ? "Enabling" : "Disabling");
configure_categories(
_enable, _categories,
utility::make_index_sequence_range<1, OMNITRACE_CATEGORY_LAST>{});
}
} // namespace
void
enable_categories(const std::set<std::string>& _categories)
{
configure_categories(
true, _categories,
utility::make_index_sequence_range<1, OMNITRACE_CATEGORY_LAST>{});
}
void
disable_categories(const std::set<std::string>& _categories)
{
configure_categories(
false, _categories,
utility::make_index_sequence_range<1, OMNITRACE_CATEGORY_LAST>{});
}
void
setup()
{
// disable specified categories
disable_categories();
auto _trace_specs = constraint::get_trace_specs();
if(!_trace_specs.empty())
{
auto _trace_stages = constraint::get_trace_stages();
_trace_stages.init = [](const constraint::spec& _spec) {
if(_spec.delay > 1.0e-3) disable_categories(config::get_enabled_categories());
return get_state() < State::Finalized;
};
_trace_stages.start = [](const constraint::spec&) {
enable_categories(config::get_enabled_categories());
return get_state() < State::Finalized;
};
_trace_stages.stop = [](const constraint::spec&) {
// only disable categories if not finalized since this might run in background
// during finalization and disable output of data in those categories
if(get_state() < State::Finalized)
disable_categories(config::get_enabled_categories());
return get_state() < State::Finalized;
};
auto _promise = std::promise<void>();
std::thread{ [_trace_specs, _trace_stages](std::promise<void>* _prom) {
// ensure all categories are disabled before proceeding
// if a delay is requested
if(_trace_specs.front().delay > 1.0e-3)
disable_categories(config::get_enabled_categories());
_prom->set_value();
for(const auto& itr : _trace_specs)
itr(_trace_stages);
},
&_promise }
.detach();
_promise.get_future().wait_for(std::chrono::seconds{ 1 });
}
}
void
shutdown()
{
disable_categories(config::get_enabled_categories());
}
} // namespace categories
} // namespace omnitrace
+229
View File
@@ -0,0 +1,229 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common/join.hpp"
#include "defines.hpp"
#include "omnitrace/categories.h" // in omnitrace-user
#if defined(TIMEMORY_PERFETTO_CATEGORIES)
# error "TIMEMORY_PERFETTO_CATEGORIES is already defined. Please include \"" __FILE__ "\" before including any timemory files"
#endif
#include <timemory/api.hpp>
#include <timemory/api/macros.hpp>
#include <timemory/mpl/macros.hpp>
#include <timemory/mpl/types.hpp>
#define OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, ...) \
namespace tim \
{ \
namespace trait \
{ \
template <> \
struct perfetto_category<__VA_ARGS__> \
{ \
static constexpr auto value = NAME; \
static constexpr auto description = DESC; \
}; \
} \
}
namespace omnitrace
{
template <size_t>
struct category_type_id;
template <typename Tp>
struct category_enum_id;
template <size_t Idx>
using category_type_id_t = typename category_type_id<Idx>::type;
} // namespace omnitrace
#define OMNITRACE_DEFINE_CATEGORY_TRAIT(TYPE, ENUM) \
namespace omnitrace \
{ \
template <> \
struct category_type_id<ENUM> \
{ \
using type = TYPE; \
}; \
template <> \
struct category_enum_id<TYPE> \
{ \
static constexpr auto value = ENUM; \
}; \
}
#define OMNITRACE_DECLARE_CATEGORY(NS, VALUE, ENUM, NAME, DESC) \
TIMEMORY_DECLARE_NS_API(NS, VALUE) \
OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) \
OMNITRACE_DEFINE_CATEGORY_TRAIT(::tim::NS::VALUE, ENUM)
#define OMNITRACE_DEFINE_CATEGORY(NS, VALUE, ENUM, NAME, DESC) \
TIMEMORY_DEFINE_NS_API(NS, VALUE) \
OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) \
OMNITRACE_DEFINE_CATEGORY_TRAIT(::tim::NS::VALUE, ENUM)
// clang-format off
// these are defined by omnitrace
OMNITRACE_DEFINE_CATEGORY(project, omnitrace, OMNITRACE_CATEGORY_NONE, "omnitrace", "Omnitrace project")
OMNITRACE_DEFINE_CATEGORY(category, host, OMNITRACE_CATEGORY_HOST, "host", "Host-side function tracing")
OMNITRACE_DEFINE_CATEGORY(category, user, OMNITRACE_CATEGORY_USER, "user", "User-defined regions")
OMNITRACE_DEFINE_CATEGORY(category, python, OMNITRACE_CATEGORY_PYTHON, "python", "Python regions")
OMNITRACE_DEFINE_CATEGORY(category, device_hip, OMNITRACE_CATEGORY_DEVICE_HIP, "device_hip", "Device-side functions submitted via HIP API")
OMNITRACE_DEFINE_CATEGORY(category, device_hsa, OMNITRACE_CATEGORY_DEVICE_HSA, "device_hsa", "Device-side functions submitted via HSA API")
OMNITRACE_DEFINE_CATEGORY(category, rocm_hip, OMNITRACE_CATEGORY_ROCM_HIP, "rocm_hip", "Host-side HIP functions")
OMNITRACE_DEFINE_CATEGORY(category, rocm_hsa, OMNITRACE_CATEGORY_ROCM_HSA, "rocm_hsa", "Host-side HSA functions")
OMNITRACE_DEFINE_CATEGORY(category, rocm_roctx, OMNITRACE_CATEGORY_ROCM_ROCTX, "rocm_roctx", "ROCTx labels")
OMNITRACE_DEFINE_CATEGORY(category, rocm_smi, OMNITRACE_CATEGORY_ROCM_SMI, "rocm_smi", "rocm-smi data")
OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_busy, OMNITRACE_CATEGORY_ROCM_SMI_BUSY, "device_busy", "Busy percentage of a GPU device")
OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_temp, OMNITRACE_CATEGORY_ROCM_SMI_TEMP, "device_temp", "Temperature of a GPU device")
OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_power, OMNITRACE_CATEGORY_ROCM_SMI_POWER, "device_power", "Power consumption of a GPU device")
OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_memory_usage, OMNITRACE_CATEGORY_ROCM_SMI_MEMORY_USAGE, "device_memory_usage", "Memory usage of a GPU device")
OMNITRACE_DEFINE_CATEGORY(category, rocm_rccl, OMNITRACE_CATEGORY_ROCM_RCCL, "rccl", "ROCm Communication Collectives Library (RCCL) regions")
OMNITRACE_DEFINE_CATEGORY(category, roctracer, OMNITRACE_CATEGORY_ROCTRACER, "roctracer", "Kernel tracing provided by roctracer")
OMNITRACE_DEFINE_CATEGORY(category, rocprofiler, OMNITRACE_CATEGORY_ROCPROFILER, "rocprofiler", "HW counter data provided by rocprofiler")
OMNITRACE_DEFINE_CATEGORY(category, pthread, OMNITRACE_CATEGORY_PTHREAD, "pthread", "POSIX threading functions")
OMNITRACE_DEFINE_CATEGORY(category, kokkos, OMNITRACE_CATEGORY_KOKKOS, "kokkos", "KokkosTools regions")
OMNITRACE_DEFINE_CATEGORY(category, mpi, OMNITRACE_CATEGORY_MPI, "mpi", "MPI regions")
OMNITRACE_DEFINE_CATEGORY(category, ompt, OMNITRACE_CATEGORY_OMPT, "ompt", "OpenMP tools regions")
OMNITRACE_DEFINE_CATEGORY(category, process_sampling, OMNITRACE_CATEGORY_PROCESS_SAMPLING, "process_sampling", "Process-level data")
OMNITRACE_DEFINE_CATEGORY(category, comm_data, OMNITRACE_CATEGORY_COMM_DATA, "comm_data", "MPI/RCCL counters for tracking amount of data sent or received")
OMNITRACE_DEFINE_CATEGORY(category, critical_trace, OMNITRACE_CATEGORY_CRITICAL_TRACE, "critical-trace", "Critical trace data")
OMNITRACE_DEFINE_CATEGORY(category, host_critical_trace, OMNITRACE_CATEGORY_HOST_CRITICAL_TRACE, "host-critical-trace", "Host-side critical trace data")
OMNITRACE_DEFINE_CATEGORY(category, device_critical_trace, OMNITRACE_CATEGORY_DEVICE_CRITICAL_TRACE, "device-critical-trace", "Device-side critical trace data")
OMNITRACE_DEFINE_CATEGORY(category, causal, OMNITRACE_CATEGORY_CAUSAL, "causal", "Causal profiling data")
OMNITRACE_DEFINE_CATEGORY(category, cpu_freq, OMNITRACE_CATEGORY_CPU_FREQ, "cpu_frequency", "CPU frequency (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_page, OMNITRACE_CATEGORY_PROCESS_PAGE, "process_page_fault", "Memory page faults in process (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_virt, OMNITRACE_CATEGORY_PROCESS_VIRT, "process_virtual_memory", "Virtual memory usage in process in MB (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_peak, OMNITRACE_CATEGORY_PROCESS_PEAK, "process_memory_hwm", "Memory High-Water Mark i.e. peak memory usage (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_context_switch, OMNITRACE_CATEGORY_PROCESS_CONTEXT_SWITCH, "process_context_switch", "Context switches in process (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_page_fault, OMNITRACE_CATEGORY_PROCESS_PAGE_FAULT, "process_page_fault", "Memory page faults in process (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_user_mode_time, OMNITRACE_CATEGORY_PROCESS_USER_MODE_TIME, "process_user_cpu_time", "CPU time of functions executing in user-space in process in seconds (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, process_kernel_mode_time, OMNITRACE_CATEGORY_PROCESS_KERNEL_MODE_TIME, "process_kernel_cpu_time", "CPU time of functions executing in kernel-space in process in seconds (collected in background thread)")
OMNITRACE_DEFINE_CATEGORY(category, thread_wall_time, OMNITRACE_CATEGORY_THREAD_WALL_TIME, "thread_wall_time", "Wall-clock time on thread (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, thread_cpu_time, OMNITRACE_CATEGORY_THREAD_CPU_TIME, "thread_cpu_time", "CPU time on thread (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, thread_page_fault, OMNITRACE_CATEGORY_THREAD_PAGE_FAULT, "thread_page_fault", "Memory page faults on thread (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, thread_peak_memory, OMNITRACE_CATEGORY_THREAD_PEAK_MEMORY, "thread_peak_memory", "Peak memory usage on thread in MB (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, thread_context_switch, OMNITRACE_CATEGORY_THREAD_CONTEXT_SWITCH, "thread_context_switch", "Context switches on thread (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, thread_hardware_counter, OMNITRACE_CATEGORY_THREAD_HARDWARE_COUNTER, "thread_hardware_counter", "Hardware counter value on thread (derived from sampling)")
OMNITRACE_DEFINE_CATEGORY(category, kernel_hardware_counter, OMNITRACE_CATEGORY_KERNEL_HARDWARE_COUNTER, "kernel_hardware_counter", "Hardware counter value for kernel (deterministic)")
OMNITRACE_DEFINE_CATEGORY(category, numa, OMNITRACE_CATEGORY_NUMA, "numa", "Non-unified memory architecture")
OMNITRACE_DECLARE_CATEGORY(category, sampling, OMNITRACE_CATEGORY_SAMPLING, "sampling", "Host-side call-stack sampling")
// clang-format on
namespace tim
{
namespace trait
{
template <typename... Tp>
using name = perfetto_category<Tp...>;
}
} // namespace tim
#define OMNITRACE_PERFETTO_CATEGORY(TYPE) \
::perfetto::Category(::tim::trait::perfetto_category<::tim::TYPE>::value) \
.SetDescription(::tim::trait::perfetto_category<::tim::TYPE>::description)
#define OMNITRACE_PERFETTO_CATEGORIES \
OMNITRACE_PERFETTO_CATEGORY(category::host), \
OMNITRACE_PERFETTO_CATEGORY(category::user), \
OMNITRACE_PERFETTO_CATEGORY(category::python), \
OMNITRACE_PERFETTO_CATEGORY(category::sampling), \
OMNITRACE_PERFETTO_CATEGORY(category::device_hip), \
OMNITRACE_PERFETTO_CATEGORY(category::device_hsa), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_hip), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_hsa), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_roctx), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_smi), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_smi_busy), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_smi_temp), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_smi_power), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_smi_memory_usage), \
OMNITRACE_PERFETTO_CATEGORY(category::rocm_rccl), \
OMNITRACE_PERFETTO_CATEGORY(category::roctracer), \
OMNITRACE_PERFETTO_CATEGORY(category::rocprofiler), \
OMNITRACE_PERFETTO_CATEGORY(category::pthread), \
OMNITRACE_PERFETTO_CATEGORY(category::kokkos), \
OMNITRACE_PERFETTO_CATEGORY(category::mpi), \
OMNITRACE_PERFETTO_CATEGORY(category::ompt), \
OMNITRACE_PERFETTO_CATEGORY(category::sampling), \
OMNITRACE_PERFETTO_CATEGORY(category::process_sampling), \
OMNITRACE_PERFETTO_CATEGORY(category::comm_data), \
OMNITRACE_PERFETTO_CATEGORY(category::critical_trace), \
OMNITRACE_PERFETTO_CATEGORY(category::host_critical_trace), \
OMNITRACE_PERFETTO_CATEGORY(category::device_critical_trace), \
OMNITRACE_PERFETTO_CATEGORY(category::causal), \
OMNITRACE_PERFETTO_CATEGORY(category::cpu_freq), \
OMNITRACE_PERFETTO_CATEGORY(category::process_page), \
OMNITRACE_PERFETTO_CATEGORY(category::process_virt), \
OMNITRACE_PERFETTO_CATEGORY(category::process_peak), \
OMNITRACE_PERFETTO_CATEGORY(category::process_context_switch), \
OMNITRACE_PERFETTO_CATEGORY(category::process_page_fault), \
OMNITRACE_PERFETTO_CATEGORY(category::process_user_mode_time), \
OMNITRACE_PERFETTO_CATEGORY(category::process_kernel_mode_time), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_wall_time), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_cpu_time), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_page_fault), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_peak_memory), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_context_switch), \
OMNITRACE_PERFETTO_CATEGORY(category::thread_hardware_counter), \
OMNITRACE_PERFETTO_CATEGORY(category::kernel_hardware_counter), \
OMNITRACE_PERFETTO_CATEGORY(category::numa), \
::perfetto::Category("timemory").SetDescription("Events from the timemory API")
#if defined(TIMEMORY_USE_PERFETTO)
# define TIMEMORY_PERFETTO_CATEGORIES OMNITRACE_PERFETTO_CATEGORIES
#endif
#include <set>
#include <string>
namespace omnitrace
{
inline namespace config
{
std::set<std::string>
get_enabled_categories();
std::set<std::string>
get_disabled_categories();
} // namespace config
namespace categories
{
void
enable_categories(const std::set<std::string>& = config::get_enabled_categories());
void
disable_categories(const std::set<std::string>& = config::get_disabled_categories());
void
setup();
void
shutdown();
} // namespace categories
} // namespace omnitrace
+134
View File
@@ -0,0 +1,134 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "categories.hpp"
#include "common/join.hpp"
#include "concepts.hpp"
#include "defines.hpp"
#include <timemory/api.hpp>
#include <timemory/api/macros.hpp>
#include <timemory/backends/process.hpp>
#include <timemory/backends/threading.hpp>
#include <timemory/environment/types.hpp>
#include <timemory/mpl/types.hpp>
#include <timemory/utility/demangle.hpp>
#include <timemory/utility/filepath.hpp>
#include <timemory/utility/locking.hpp>
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <memory>
#include <mutex>
#include <string>
#include <sys/types.h>
#include <thread>
#include <unistd.h>
#include <utility>
#include <vector>
#define OMNITRACE_DECLARE_COMPONENT(NAME) \
namespace omnitrace \
{ \
namespace component \
{ \
struct NAME; \
} \
} \
namespace tim \
{ \
namespace trait \
{ \
template <> \
struct is_component<omnitrace::component::NAME> : true_type \
{}; \
} \
} \
namespace tim \
{ \
namespace component \
{ \
using ::omnitrace::component::NAME; \
} \
}
#define OMNITRACE_COMPONENT_ALIAS(NAME, ...) \
namespace omnitrace \
{ \
namespace component \
{ \
using NAME = __VA_ARGS__; \
} \
} \
namespace tim \
{ \
namespace component \
{ \
using ::omnitrace::component::NAME; \
} \
}
#define OMNITRACE_DEFINE_CONCRETE_TRAIT(TRAIT, TYPE, VALUE) \
namespace tim \
{ \
namespace trait \
{ \
template <> \
struct TRAIT<::omnitrace::TYPE> : VALUE \
{}; \
} \
}
namespace omnitrace
{
namespace api = ::tim::api; // NOLINT
namespace category = ::tim::category; // NOLINT
namespace filepath = ::tim::filepath; // NOLINT
namespace project = ::tim::project; // NOLINT
namespace process = ::tim::process; // NOLINT
namespace threading = ::tim::threading; // NOLINT
namespace scope = ::tim::scope; // NOLINT
namespace policy = ::tim::policy; // NOLINT
namespace trait = ::tim::trait; // NOLINT
namespace cereal = ::tim::cereal; // NOLINT
using ::tim::auto_lock_t; // NOLINT
using ::tim::demangle; // NOLINT
using ::tim::get_env; // NOLINT
using ::tim::set_env; // NOLINT
using ::tim::try_demangle; // NOLINT
using ::tim::type_mutex; // NOLINT
struct construct_on_thread
{
int64_t index = threading::get_id();
};
} // namespace omnitrace
// same sort of functionality as python's " ".join([...])
#if !defined(JOIN)
# define JOIN(...) ::omnitrace::common::join(__VA_ARGS__)
#endif
@@ -0,0 +1,6 @@
#
set(component_sources)
set(component_headers ${CMAKE_CURRENT_LIST_DIR}/fwd.hpp)
target_sources(omnitrace-core-library PRIVATE ${component_sources} ${component_headers})
+270
View File
@@ -0,0 +1,270 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/categories.hpp"
#include "core/common.hpp"
#include "core/defines.hpp"
#include <timemory/api.hpp>
#include <timemory/api/macros.hpp>
#include <timemory/components/base/types.hpp>
#include <timemory/components/data_tracker/types.hpp>
#include <timemory/components/macros.hpp>
#include <timemory/components/user_bundle/types.hpp>
#include <timemory/enum.h>
#include <timemory/mpl/concepts.hpp>
#include <timemory/mpl/type_traits.hpp>
#include <timemory/mpl/types.hpp>
#include <type_traits>
OMNITRACE_DECLARE_COMPONENT(roctracer)
OMNITRACE_DECLARE_COMPONENT(rocprofiler)
OMNITRACE_DECLARE_COMPONENT(rcclp_handle)
OMNITRACE_DECLARE_COMPONENT(comm_data)
OMNITRACE_COMPONENT_ALIAS(comm_data_tracker_t,
::tim::component::data_tracker<float, project::omnitrace>)
namespace omnitrace
{
namespace policy = ::tim::policy; // NOLINT
namespace comp = ::tim::component; // NOLINT
namespace component
{
template <typename Tp, typename ValueT>
using base = ::tim::component::base<Tp, ValueT>;
template <typename... Tp>
using data_tracker = tim::component::data_tracker<Tp...>;
template <typename... Tp>
using functor_t = std::function<void(Tp...)>;
using default_functor_t = functor_t<const char*>;
struct backtrace;
struct backtrace_metrics;
struct backtrace_timestamp;
struct backtrace_wall_clock
{};
struct backtrace_cpu_clock
{};
struct backtrace_fraction
{};
struct backtrace_gpu_busy
{};
struct backtrace_gpu_temp
{};
struct backtrace_gpu_power
{};
struct backtrace_gpu_memory
{};
using sampling_wall_clock = data_tracker<double, backtrace_wall_clock>;
using sampling_cpu_clock = data_tracker<double, backtrace_cpu_clock>;
using sampling_percent = data_tracker<double, backtrace_fraction>;
using sampling_gpu_busy = data_tracker<double, backtrace_gpu_busy>;
using sampling_gpu_temp = data_tracker<double, backtrace_gpu_temp>;
using sampling_gpu_power = data_tracker<double, backtrace_gpu_power>;
using sampling_gpu_memory = data_tracker<double, backtrace_gpu_memory>;
template <typename ApiT, typename StartFuncT = default_functor_t,
typename StopFuncT = default_functor_t>
struct functors;
} // namespace component
} // namespace omnitrace
#if !defined(OMNITRACE_USE_ROCTRACER)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::roctracer, false_type)
#endif
#if !defined(OMNITRACE_USE_ROCPROFILER)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::rocprofiler, false_type)
#endif
#if !defined(OMNITRACE_USE_RCCL)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, category::rocm_rccl, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::rcclp_handle, false_type)
#endif
#if !defined(OMNITRACE_USE_RCCL) && !defined(OMNITRACE_USE_MPI)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::comm_data_tracker_t, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::comm_data, false_type)
#endif
#if !defined(TIMEMORY_USE_LIBUNWIND)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, category::sampling, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::backtrace, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::backtrace_metrics, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::backtrace_timestamp, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_wall_clock, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_cpu_clock, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_percent, false_type)
#endif
#if !defined(TIMEMORY_USE_LIBUNWIND) || !defined(OMNITRACE_USE_ROCM_SMI)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_gpu_busy, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_gpu_temp, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_gpu_power, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_available, component::sampling_gpu_memory, false_type)
#endif
TIMEMORY_SET_COMPONENT_API(omnitrace::component::roctracer, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux,
category::external)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::rocprofiler, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux,
category::external, category::hardware_counter)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_wall_clock, project::omnitrace,
category::timing, os::supports_unix, category::sampling,
category::interrupt_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_cpu_clock, project::omnitrace,
category::timing, os::supports_unix, category::sampling,
category::interrupt_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_percent, project::omnitrace,
category::timing, os::supports_unix, category::sampling,
category::interrupt_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_busy, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux,
category::sampling, category::process_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_memory, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux, category::memory,
category::sampling, category::process_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_power, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux, category::power,
category::sampling, category::process_sampling)
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_temp, project::omnitrace,
tpls::rocm, device::gpu, os::supports_linux,
category::temperature, category::sampling,
category::process_sampling)
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::roctracer, OMNITRACE_ROCTRACER,
"roctracer", "omnitrace_roctracer")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::rocprofiler, OMNITRACE_ROCPROFILER,
"rocprofiler", "omnitrace_rocprofiler")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_wall_clock,
OMNITRACE_SAMPLING_WALL_CLOCK, "sampling_wall_clock", "")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_cpu_clock,
OMNITRACE_SAMPLING_CPU_CLOCK, "sampling_cpu_clock", "")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_percent,
OMNITRACE_SAMPLING_PERCENT, "sampling_percent", "")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_busy,
OMNITRACE_SAMPLING_GPU_BUSY, "sampling_gpu_busy",
"sampling_gpu_util")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_memory,
OMNITRACE_SAMPLING_GPU_MEMORY_USAGE,
"sampling_gpu_memory_usage", "")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_power,
OMNITRACE_SAMPLING_GPU_POWER, "sampling_gpu_power", "")
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::sampling_gpu_temp,
OMNITRACE_SAMPLING_GPU_TEMP, "sampling_gpu_temp", "")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::roctracer, "roctracer",
"High-precision ROCm API and kernel tracing", "")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::rocprofiler, "rocprofiler",
"ROCm kernel hardware counters", "")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_wall_clock,
"sampling_wall_clock", "Wall-clock timing",
"Derived from statistical sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_cpu_clock,
"sampling_cpu_clock", "CPU-clock timing",
"Derived from statistical sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_percent,
"sampling_percent",
"Fraction of wall-clock time spent in functions",
"Derived from statistical sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_gpu_busy,
"sampling_gpu_busy",
"GPU Utilization (% busy) via ROCm-SMI",
"Derived from sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_gpu_memory,
"sampling_gpu_memory_usage",
"GPU Memory Usage via ROCm-SMI", "Derived from sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_gpu_power,
"sampling_gpu_power", "GPU Power Usage via ROCm-SMI",
"Derived from sampling")
TIMEMORY_METADATA_SPECIALIZATION(omnitrace::component::sampling_gpu_temp,
"sampling_gpu_temp", "GPU Temperature via ROCm-SMI",
"Derived from sampling")
// statistics type
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_wall_clock, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_cpu_clock, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_gpu_busy, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_gpu_temp, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_gpu_power, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::sampling_gpu_memory, double)
TIMEMORY_STATISTICS_TYPE(omnitrace::component::comm_data_tracker_t, float)
// enable timing units
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_timing_category, component::sampling_wall_clock,
true_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_timing_category, component::sampling_cpu_clock,
true_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_timing_category, component::sampling_percent,
true_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(uses_timing_units, component::sampling_wall_clock,
true_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(uses_timing_units, component::sampling_cpu_clock,
true_type)
// enable percent units
OMNITRACE_DEFINE_CONCRETE_TRAIT(uses_percent_units, component::sampling_gpu_busy,
true_type)
// enable memory units
OMNITRACE_DEFINE_CONCRETE_TRAIT(is_memory_category, component::sampling_gpu_memory,
true_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(uses_memory_units, component::sampling_gpu_memory,
true_type)
// reporting categories (sum)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_sum, component::sampling_gpu_busy, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_sum, component::sampling_gpu_temp, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_sum, component::sampling_gpu_power, false_type)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_sum, component::sampling_gpu_memory, false_type)
// reporting categories (mean)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_mean, component::sampling_percent, false_type)
// reporting categories (stats)
OMNITRACE_DEFINE_CONCRETE_TRAIT(report_statistics, component::sampling_percent,
false_type)
#define OMNITRACE_DECLARE_EXTERN_COMPONENT(NAME, HAS_DATA, ...) \
TIMEMORY_DECLARE_EXTERN_TEMPLATE( \
struct tim::component::base<TIMEMORY_ESC(omnitrace::component::NAME), \
__VA_ARGS__>) \
TIMEMORY_DECLARE_EXTERN_OPERATIONS(TIMEMORY_ESC(omnitrace::component::NAME), \
HAS_DATA) \
TIMEMORY_DECLARE_EXTERN_STORAGE(TIMEMORY_ESC(omnitrace::component::NAME))
#define OMNITRACE_INSTANTIATE_EXTERN_COMPONENT(NAME, HAS_DATA, ...) \
TIMEMORY_INSTANTIATE_EXTERN_TEMPLATE( \
struct tim::component::base<TIMEMORY_ESC(omnitrace::component::NAME), \
__VA_ARGS__>) \
TIMEMORY_INSTANTIATE_EXTERN_OPERATIONS(TIMEMORY_ESC(omnitrace::component::NAME), \
HAS_DATA) \
TIMEMORY_INSTANTIATE_EXTERN_STORAGE(TIMEMORY_ESC(omnitrace::component::NAME))
+126
View File
@@ -0,0 +1,126 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "defines.hpp"
#include <timemory/mpl/concepts.hpp>
#include <timemory/utility/types.hpp>
#include <memory>
#include <optional>
#include <type_traits>
namespace omnitrace
{
namespace concepts = ::tim::concepts; // NOLINT
static constexpr size_t max_supported_threads = OMNITRACE_MAX_THREADS;
template <typename Tp>
struct thread_deleter;
// unique ptr type for omnitrace
template <typename Tp>
using unique_ptr_t = std::unique_ptr<Tp, thread_deleter<Tp>>;
using construct_on_init = std::true_type;
using tim::identity; // NOLINT
using tim::identity_t; // NOLINT
template <typename Tp>
struct use_placement_new_when_generating_unique_ptr : std::false_type
{};
} // namespace omnitrace
namespace tim
{
namespace concepts
{
template <typename Tp>
struct is_unique_pointer : std::false_type
{};
template <typename Tp>
struct is_unique_pointer<::omnitrace::unique_ptr_t<Tp>> : std::true_type
{};
template <typename Tp>
struct is_unique_pointer<std::unique_ptr<Tp>> : std::true_type
{};
template <typename Tp>
struct is_optional : std::false_type
{};
template <typename Tp>
struct is_optional<std::optional<Tp>> : std::true_type
{};
template <typename Tp>
struct can_stringify
{
private:
static constexpr auto sfinae(int)
-> decltype(std::declval<std::ostream&>() << std::declval<Tp>(), bool())
{
return true;
}
static constexpr auto sfinae(long) { return false; }
public:
static constexpr bool value = sfinae(0);
constexpr auto operator()() const { return sfinae(0); }
};
template <size_t N, typename Tp, bool>
struct tuple_element_impl;
template <size_t N, typename... Tp>
struct tuple_element_impl<N, std::tuple<Tp...>, true>
{
using type = typename std::tuple_element<N, std::tuple<Tp...>>::type;
};
template <size_t N, typename... Tp>
struct tuple_element_impl<N, std::tuple<Tp...>, false>
{
using type = void;
};
template <size_t N, typename Tp>
struct tuple_element;
template <size_t N, typename... Tp>
struct tuple_element<N, std::tuple<Tp...>>
{
using type =
typename tuple_element_impl<N, std::tuple<Tp...>, (N < sizeof...(Tp))>::type;
};
template <size_t N, typename Tp>
using tuple_element_t = typename tuple_element<N, Tp>::type;
} // namespace concepts
} // namespace tim
File diff suppressed because it is too large Load Diff
+433
View File
@@ -0,0 +1,433 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common.hpp"
#include "defines.hpp"
#include "state.hpp"
#include "timemory.hpp"
#include <timemory/backends/threading.hpp>
#include <timemory/macros/language.hpp>
#include <fstream>
#include <string>
#include <string_view>
#include <unordered_set>
namespace omnitrace
{
//
// Initialization routines
//
inline namespace config
{
using signal_handler_t = void (*)(void);
// if arg is nullptr, returns current signal handler
// if arg is non-null, returns replaced signal handler
signal_handler_t set_signal_handler(signal_handler_t);
bool
settings_are_configured() OMNITRACE_HOT;
void
configure_settings(bool _init = true);
void
configure_mode_settings();
void
configure_signal_handler();
int
get_realtime_signal();
int
get_cputime_signal();
std::set<int>
get_sampling_signals(int64_t _tid = 0);
void
configure_disabled_settings();
void
finalize();
void
handle_deprecated_setting(const std::string& _old, const std::string& _new,
int _verbose = 0);
void
print_banner(std::ostream& _os = std::cerr);
void
print_settings(
std::ostream& _os,
std::function<bool(const std::string_view&, const std::set<std::string>&)>&& _filter);
void
print_settings(bool include_env = true);
std::string&
get_exe_name();
std::string&
get_exe_realpath();
template <typename Tp>
bool
set_setting_value(const std::string& _name, Tp&& _v)
{
auto _instance = tim::settings::shared_instance();
auto _setting = _instance->find(_name);
if(_setting == _instance->end()) return false;
if(!_setting->second) return false;
return _setting->second->set(std::forward<Tp>(_v));
}
template <typename Tp>
bool
set_default_setting_value(const std::string& _name, Tp&& _v)
{
auto _instance = tim::settings::shared_instance();
auto _setting = _instance->find(_name);
if(_setting == _instance->end()) return false;
if(!_setting->second) return false;
if(_setting->second->get_config_updated() || _setting->second->get_environ_updated())
return false;
return _setting->second->set(std::forward<Tp>(_v));
}
template <typename Tp>
std::pair<bool, Tp>
get_setting_value(const std::string& _name)
{
auto _instance = tim::settings::shared_instance();
if(!_instance) return std::make_pair(false, Tp{});
auto _setting = _instance->find(_name);
if(_setting == _instance->end() || !_setting->second)
return std::make_pair(false, Tp{});
return _setting->second->get<Tp>();
}
//
// User-configurable settings
//
std::string
get_config_file();
Mode
get_mode();
bool&
is_attached();
bool&
is_binary_rewrite();
bool
get_is_continuous_integration() OMNITRACE_HOT;
bool
get_debug_env() OMNITRACE_HOT;
bool
get_debug_init();
bool
get_debug_finalize();
bool
get_debug() OMNITRACE_HOT;
bool
get_debug_sampling() OMNITRACE_HOT;
bool
get_debug_tid() OMNITRACE_HOT;
bool
get_debug_pid() OMNITRACE_HOT;
int
get_verbose_env() OMNITRACE_HOT;
int
get_verbose() OMNITRACE_HOT;
bool&
get_use_perfetto() OMNITRACE_HOT;
bool&
get_use_timemory() OMNITRACE_HOT;
bool&
get_use_causal() OMNITRACE_HOT;
bool
get_use_roctracer() OMNITRACE_HOT;
bool
get_use_rocprofiler() OMNITRACE_HOT;
bool
get_use_rocm_smi() OMNITRACE_HOT;
bool
get_use_roctx();
bool&
get_use_sampling() OMNITRACE_HOT;
bool&
get_use_process_sampling() OMNITRACE_HOT;
bool&
get_use_pid();
bool&
get_use_mpip();
bool&
get_use_critical_trace() OMNITRACE_HOT;
bool
get_use_kokkosp();
bool
get_use_kokkosp_kernel_logger();
bool
get_use_ompt();
bool
get_use_code_coverage();
bool
get_sampling_keep_internal();
bool
get_use_sampling_realtime();
bool
get_use_sampling_cputime();
int
get_sampling_rtoffset();
bool
get_use_rcclp();
bool
get_trace_hip_api();
bool
get_trace_hip_activity();
bool
get_trace_hsa_api();
bool
get_trace_hsa_activity();
bool
get_critical_trace_debug();
bool
get_critical_trace_serialize_names();
size_t
get_perfetto_shmem_size_hint();
size_t
get_perfetto_buffer_size();
bool
get_perfetto_combined_traces();
std::string
get_perfetto_fill_policy();
std::set<std::string>
get_enabled_categories();
std::set<std::string>
get_disabled_categories();
bool
get_perfetto_annotations() OMNITRACE_HOT;
uint64_t
get_critical_trace_update_freq();
uint64_t
get_thread_pool_size();
std::string
get_trace_hsa_api_types();
std::string&
get_backend();
// make this visible so omnitrace-avail can call it
std::string
get_perfetto_output_filename();
bool
get_perfetto_roctracer_per_stream() OMNITRACE_HOT;
int64_t
get_critical_trace_count();
double
get_trace_delay();
double
get_trace_duration();
double
get_sampling_freq();
double
get_sampling_cpu_freq();
double
get_sampling_real_freq();
double
get_sampling_delay();
double
get_sampling_cpu_delay();
double
get_sampling_real_delay();
double
get_sampling_duration();
std::string
get_sampling_cpus();
std::set<int64_t>
get_sampling_cpu_tids();
std::set<int64_t>
get_sampling_real_tids();
bool
get_sampling_include_inlines();
size_t
get_num_threads_hint();
size_t
get_sampling_allocator_size();
double
get_process_sampling_freq();
double
get_process_sampling_duration();
std::string
get_sampling_gpus();
int64_t
get_critical_trace_per_row();
bool
get_trace_thread_locks();
bool
get_trace_thread_rwlocks();
bool
get_trace_thread_spin_locks();
bool
get_trace_thread_barriers();
bool
get_trace_thread_join();
std::string
get_rocm_events();
bool
get_use_tmp_files();
std::string
get_tmpdir();
struct tmp_file
{
tmp_file(std::string);
~tmp_file();
void open(std::ios::openmode = std::ios::binary | std::ios::in | std::ios::out);
void close();
void remove();
explicit operator bool() const { return stream.is_open() && stream.good(); }
std::string filename = {};
std::fstream stream = {};
};
std::shared_ptr<tmp_file>
get_tmp_file(std::string _basename, std::string _ext = "dat");
CausalMode
get_causal_mode();
bool
get_causal_end_to_end();
std::vector<int64_t>
get_causal_fixed_speedup();
std::string
get_causal_output_filename();
std::vector<std::string>
get_causal_binary_scope();
std::vector<std::string>
get_causal_source_scope();
std::vector<std::string>
get_causal_function_scope();
std::vector<std::string>
get_causal_binary_exclude();
std::vector<std::string>
get_causal_source_exclude();
std::vector<std::string>
get_causal_function_exclude();
} // namespace config
} // namespace omnitrace
+349
View File
@@ -0,0 +1,349 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "constraint.hpp"
#include "config.hpp"
#include "debug.hpp"
#include "state.hpp"
#include "utility.hpp"
#include <timemory/units.hpp>
#include <timemory/utility/delimit.hpp>
#include <chrono>
#include <cstdint>
#include <ratio>
#include <string>
#include <thread>
#include <type_traits>
namespace omnitrace
{
namespace constraint
{
namespace
{
namespace units = ::tim::units;
using clock_type = std::chrono::high_resolution_clock;
using duration_type = std::chrono::duration<double, std::nano>;
#define OMNITRACE_CLOCK_IDENTIFIER(VAL) \
clock_identifier { #VAL, VAL }
auto
clock_name(std::string _v)
{
constexpr auto _clock_prefix = std::string_view{ "clock_" };
for(auto& itr : _v)
itr = tolower(itr);
auto _pos = _v.find(_clock_prefix);
if(_pos == 0) _v = _v.substr(_pos + _clock_prefix.length());
if(_v == "process_cputime_id") _v = "cputime";
return _v;
}
auto accepted_clock_ids =
std::set<clock_identifier>{ OMNITRACE_CLOCK_IDENTIFIER(CLOCK_REALTIME),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_MONOTONIC),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_PROCESS_CPUTIME_ID),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_MONOTONIC_RAW),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_REALTIME_COARSE),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_MONOTONIC_COARSE),
OMNITRACE_CLOCK_IDENTIFIER(CLOCK_BOOTTIME) };
template <typename Tp>
clock_identifier
find_clock_identifier(const Tp& _v)
{
const char* _descript = "";
if constexpr(std::is_integral<Tp>::value)
{
_descript = "value";
for(const auto& itr : accepted_clock_ids)
{
if(itr.value == _v)
{
return itr;
}
}
}
else
{
_descript = "name";
auto _clock_name = clock_name(_v);
for(const auto& itr : accepted_clock_ids)
{
if(itr.name == _clock_name || itr.raw_name == _v ||
std::to_string(itr.value) == _v)
{
return itr;
}
}
}
OMNITRACE_THROW("Unknown clock id %s: %s. Valid choices: %s\n", _descript,
timemory::join::join("", _v).c_str(),
timemory::join::join("", accepted_clock_ids).c_str());
}
void
sleep(uint64_t _n)
{
std::this_thread::sleep_for(std::chrono::nanoseconds{ _n });
}
timespec
get_timespec(clockid_t clock_id) noexcept
{
struct timespec _ts;
clock_gettime(clock_id, &_ts);
return _ts;
}
template <typename Tp = uint64_t, typename Precision = std::nano>
Tp
get_clock_now(clockid_t clock_id) noexcept
{
constexpr Tp factor = (Precision::den == std::nano::den)
? 1
: (Precision::den / static_cast<Tp>(std::nano::den));
auto _ts = get_timespec(clock_id);
return (_ts.tv_sec * std::nano::den + _ts.tv_nsec) * factor;
}
} // namespace
//--------------------------------------------------------------------------------------//
//
// stages implementation
//
//--------------------------------------------------------------------------------------//
stages::stages()
: init{ [](const spec&) { return get_state() < State::Finalized; } }
, wait{ [](const spec& _spec) {
sleep(std::min<uint64_t>(100 * units::msec, _spec.delay * units::sec));
return get_state() < State::Finalized;
} }
, start{ [](const spec&) { return get_state() < State::Finalized; } }
, collect{ [](const spec& _spec) {
sleep(std::min<uint64_t>(100 * units::msec, _spec.duration * units::sec));
return get_state() < State::Finalized;
} }
, stop{ [](const spec&) { return get_state() < State::Finalized; } }
{}
//--------------------------------------------------------------------------------------//
//
// clock identifier implementation
//
//--------------------------------------------------------------------------------------//
clock_identifier::clock_identifier(std::string_view _name, int _val)
: value{ _val }
, raw_name{ _name }
, name{ clock_name(std::string{ _name }) }
{}
bool
clock_identifier::operator<(const clock_identifier& _rhs) const
{
return value < _rhs.value;
}
bool
clock_identifier::operator==(const clock_identifier& _rhs) const
{
return std::tie(raw_name, value) == std::tie(_rhs.raw_name, _rhs.value);
}
bool
clock_identifier::operator==(int _rhs) const
{
return (value == _rhs);
}
bool
clock_identifier::operator==(std::string _rhs) const
{
return (raw_name == std::string_view{ _rhs }) ||
(name == clock_name(std::move(_rhs)));
}
std::string
clock_identifier::as_string() const
{
auto _name = name;
for(auto& itr : _name)
itr = tolower(itr);
auto _ss = std::stringstream{};
_ss << _name << "(id=" << raw_name << ", value=" << value << ")";
return _ss.str();
}
//--------------------------------------------------------------------------------------//
//
// spec implementation
//
//--------------------------------------------------------------------------------------//
spec::spec(clock_identifier _id, double _delay, double _dur, uint64_t _n, uint64_t _rep)
: delay{ _delay }
, duration{ _dur }
, count{ _n }
, repeat{ _rep }
, clock_id{ std::move(_id) }
{}
spec::spec(int _clock_id, double _delay, double _dur, uint64_t _n, uint64_t _rep)
: delay{ _delay }
, duration{ _dur }
, count{ _n }
, repeat{ _rep }
, clock_id{ find_clock_identifier(_clock_id) }
{}
spec::spec(const std::string& _clock_id, double _delay, double _dur, uint64_t _n,
uint64_t _rep)
: delay{ _delay }
, duration{ _dur }
, count{ _n }
, repeat{ _rep }
, clock_id{ find_clock_identifier(_clock_id) }
{}
spec::spec(const std::string& _line)
: spec{ config::get_setting_value<std::string>("OMNITRACE_TRACE_PERIOD_CLOCK_ID").second,
config::get_setting_value<double>("OMNITRACE_TRACE_DELAY").second,
config::get_setting_value<double>("OMNITRACE_TRACE_DURATION").second }
{
auto _delim = tim::delimit(_line, ":");
if(!_delim.empty()) delay = utility::convert<double>(_delim.at(0));
if(_delim.size() > 1) duration = utility::convert<double>(_delim.at(1));
if(_delim.size() > 2) repeat = utility::convert<uint64_t>(_delim.at(2));
if(_delim.size() > 3) clock_id = find_clock_identifier(_delim.at(3));
}
void
spec::operator()(const stages& _stages) const
{
auto _n = repeat;
if(_n < 1) _n = std::numeric_limits<uint64_t>::max();
while(get_state() < State::Active)
sleep(1 * units::usec);
for(uint64_t i = 0; i < _n; ++i)
{
auto _spec = spec{ clock_id, delay, duration, i, repeat };
auto _wait = [_spec](const auto& _func, auto _dur) {
auto _ret = true;
auto _now = get_clock_now(_spec.clock_id.value);
auto _del = (_dur * units::sec);
auto _end = _now + _del;
while(get_clock_now(_spec.clock_id.value) < _end && (_ret = _func(_spec)))
{}
return _ret;
};
OMNITRACE_VERBOSE(2,
"Executing constraint spec %lu of %lu :: delay: %6.3f, "
"duration: %6.3f, clock: %s\n",
i, _spec.repeat, _spec.delay, _spec.duration,
_spec.clock_id.as_string().c_str());
if(_stages.init(_spec) && _wait(_stages.wait, _spec.delay) &&
_stages.start(_spec) && _wait(_stages.collect, _spec.duration) &&
_stages.stop(_spec))
{}
else
{
break;
}
}
}
//--------------------------------------------------------------------------------------//
//
// global usage functions
//
//--------------------------------------------------------------------------------------//
const std::set<clock_identifier>&
get_valid_clock_ids()
{
return accepted_clock_ids;
}
std::vector<spec>
get_trace_specs()
{
auto _v = std::vector<constraint::spec>{};
{
auto _delay_v = config::get_setting_value<double>("OMNITRACE_TRACE_DELAY").second;
auto _duration_v =
config::get_setting_value<double>("OMNITRACE_TRACE_DURATION").second;
auto _clock_v = find_clock_identifier(
config::get_setting_value<std::string>("OMNITRACE_TRACE_PERIOD_CLOCK_ID")
.second);
if(_delay_v > 0.0 || _duration_v > 0.0)
{
_v.emplace_back(_clock_v, _delay_v, _duration_v);
}
}
{
auto _periods_v =
config::get_setting_value<std::string>("OMNITRACE_TRACE_PERIODS").second;
if(!_periods_v.empty())
{
for(auto itr : tim::delimit(_periods_v, " ;\t\n"))
_v.emplace_back(itr);
}
}
return _v;
}
stages
get_trace_stages()
{
auto _v = stages{};
_v.init = [](const spec&) { return get_state() < State::Finalized; };
_v.wait = [](const spec& _spec) {
sleep(std::min<uint64_t>(100 * units::msec, _spec.delay * units::sec));
return get_state() < State::Finalized;
};
_v.start = [](const spec&) { return get_state() < State::Finalized; };
_v.collect = [](const spec& _spec) {
sleep(std::min<uint64_t>(100 * units::msec, _spec.duration * units::sec));
return get_state() < State::Finalized;
};
_v.stop = [](const spec&) { return get_state() < State::Finalized; };
return _v;
}
} // namespace constraint
} // namespace omnitrace
+114
View File
@@ -0,0 +1,114 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
/// @file
/// This provides generic functionality for constraining data collection within
/// a windows of time. E.g., delay, delay + duration, (delay + duration) * nrepeat
///
/// @todo Migrate delay/duration for sampling, process sampling, and causal profiling
/// to use this
///
#include "defines.hpp"
#include <cstdint>
#include <ctime>
#include <functional>
#include <set>
#include <string>
#include <vector>
namespace omnitrace
{
namespace constraint
{
struct spec;
struct stages
{
using functor_t = std::function<bool(const spec&)>;
stages();
OMNITRACE_DEFAULT_COPY_MOVE(stages)
functor_t init = [](const spec&) { return true; };
functor_t wait = [](const spec&) { return true; };
functor_t start = [](const spec&) { return true; };
functor_t collect = [](const spec&) { return true; };
functor_t stop = [](const spec&) { return true; };
};
struct clock_identifier
{
int value = -1;
std::string_view raw_name = {};
std::string name = {};
clock_identifier();
clock_identifier(std::string_view, int);
OMNITRACE_DEFAULT_COPY_MOVE(clock_identifier)
std::string as_string() const;
bool operator<(const clock_identifier& _rhs) const;
bool operator==(const clock_identifier& _rhs) const;
bool operator==(int _rhs) const;
bool operator==(std::string _rhs) const;
friend std::ostream& operator<<(std::ostream& _os, const clock_identifier& _v)
{
return (_os << _v.as_string());
}
};
struct spec
{
spec(int, double, double, uint64_t = 0, uint64_t = 1);
spec(clock_identifier, double, double, uint64_t = 0, uint64_t = 1);
spec(const std::string&, double, double, uint64_t = 0, uint64_t = 1);
spec(const std::string&);
OMNITRACE_DEFAULT_COPY_MOVE(spec)
void operator()(const stages&) const;
double delay = 0.0;
double duration = 0.0;
uint64_t count = 0;
uint64_t repeat = 1;
clock_identifier clock_id = {};
};
const std::set<clock_identifier>&
get_valid_clock_ids();
std::vector<spec>
get_trace_specs();
stages
get_trace_stages();
} // namespace constraint
} // namespace omnitrace
@@ -0,0 +1,7 @@
#
set(containers_sources)
set(containers_headers ${CMAKE_CURRENT_LIST_DIR}/stable_vector.hpp
${CMAKE_CURRENT_LIST_DIR}/static_vector.hpp)
target_sources(omnitrace-core-library PRIVATE ${containers_sources} ${containers_headers})
+132
View File
@@ -0,0 +1,132 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/exception.hpp"
#include <array>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <vector>
namespace omnitrace
{
namespace container
{
template <typename Tp>
struct c_array
{
// Construct an array wrapper from a base pointer and array size
c_array(Tp* _base, size_t _size)
: m_base{ _base }
, m_size{ _size }
{}
~c_array() = default;
c_array(const c_array&) = default;
c_array& operator=(const c_array&) = default;
c_array& operator=(c_array&&) noexcept = default;
// Get the size of the wrapped array
size_t size() const { return m_size; }
// Access an element by index
Tp& operator[](size_t i) { return m_base[i]; }
// Access an element by index
const Tp& operator[](size_t i) const { return m_base[i]; }
// Access an element by index with bounds check
Tp& at(size_t i)
{
if(i < m_size) return m_base[i];
throw ::omnitrace::exception<std::out_of_range>(
std::string{ typeid(*this).name() } + std::to_string(i) + " exceeds size " +
std::to_string(m_size));
}
// Access an element by index with bounds check
const Tp& at(size_t i) const
{
if(i < m_size) return m_base[i];
throw ::omnitrace::exception<std::out_of_range>(
std::string{ typeid(*this).name() } + std::to_string(i) + " exceeds size " +
std::to_string(m_size));
}
// Get a slice of this array, from a start index (inclusive) to end index (exclusive)
c_array<Tp> slice(size_t start, size_t end)
{
return c_array<Tp>(&m_base[start], end - start);
}
operator Tp*() const { return m_base; }
// Iterator class for convenient range-based for loop support
template <typename Up>
struct iterator
{
// Start the iterator at a given pointer
iterator(Tp* p)
: m_ptr{ p }
{}
// Advance to the next element
void operator++() { ++m_ptr; }
void operator++(int) { m_ptr++; }
// Get the current element
Up& operator*() const { return *m_ptr; }
// Compare iterators
bool operator==(const iterator& rhs) const { return m_ptr == rhs.m_ptr; }
bool operator!=(const iterator& rhs) const { return m_ptr != rhs.m_ptr; }
private:
Tp* m_ptr = nullptr;
};
// Get an iterator positioned at the beginning of the wrapped array
iterator<Tp> begin() { return iterator<Tp>{ m_base }; }
iterator<const Tp> begin() const { return iterator<const Tp>{ m_base }; }
// Get an iterator positioned at the end of the wrapped array
iterator<Tp> end() { return iterator<Tp>{ &m_base[m_size] }; }
iterator<const Tp> end() const { return iterator<const Tp>{ &m_base[m_size] }; }
private:
Tp* m_base = nullptr;
size_t m_size = 0;
};
// Function for automatic template argument deduction
template <typename Tp>
c_array<Tp>
wrap_c_array(Tp* base, size_t size)
{
return c_array<Tp>(base, size);
}
} // namespace container
} // namespace omnitrace
+240
View File
@@ -0,0 +1,240 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/defines.hpp"
#include <iterator>
#include <type_traits>
#define OMNITRACE_IMPORT_TEMPLATE2(template_name)
#define OMNITRACE_IMPORT_TEMPLATE1(template_name)
// Import a 2-type-argument operator template into boost (if necessary) and
// provide a specialization of 'is_chained_base<>' for it.
#define OMNITRACE_OPERATOR_TEMPLATE2(template_name2) \
OMNITRACE_IMPORT_TEMPLATE2(template_name2) \
template <typename T, typename U, typename B> \
struct is_chained_base<::omnitrace::container::template_name2<T, U, B>> \
{ \
using value = ::omnitrace::container::true_t; \
};
// Import a 1-type-argument operator template into boost (if necessary) and
// provide a specialization of 'is_chained_base<>' for it.
#define OMNITRACE_OPERATOR_TEMPLATE1(template_name1) \
OMNITRACE_IMPORT_TEMPLATE1(template_name1) \
template <typename T, typename B> \
struct is_chained_base<::omnitrace::container::template_name1<T, B>> \
{ \
using value = ::omnitrace::container::true_t; \
};
#define OMNITRACE_OPERATOR_TEMPLATE(template_name) \
template <typename T, typename U = T, typename B = empty_base<T>, \
typename O = typename is_chained_base<U>::value> \
struct template_name; \
\
template <typename T, typename U, typename B> \
struct template_name<T, U, B, false_t> : template_name##2 < T \
, U \
, B > \
{}; \
\
template <typename T, typename U> \
struct template_name<T, U, empty_base<T>, true_t> : template_name##1 < T \
, U > \
{}; \
\
template <typename T, typename B> \
struct template_name<T, T, B, false_t> : template_name##1 < T \
, B > \
{}; \
\
template <typename T, typename U, typename B, typename O> \
struct is_chained_base<template_name<T, U, B, O>> \
{ \
using value = ::omnitrace::container::true_t; \
}; \
\
OMNITRACE_OPERATOR_TEMPLATE2(template_name##2) \
OMNITRACE_OPERATOR_TEMPLATE1(template_name##1)
#define OMNITRACE_BINARY_OPERATOR_COMMUTATIVE(NAME, OP) \
template <typename T, typename U, typename B = empty_base<T>> \
struct NAME##2 \
: B{ friend T operator OP(T lhs, const U& rhs){ return lhs OP## = rhs; \
} \
friend T operator OP(const U& lhs, T rhs) { return rhs OP## = lhs; } \
} \
; \
\
template <typename T, typename B = empty_base<T>> \
struct NAME##1 \
: B{ friend T operator OP(T lhs, const T& rhs){ return lhs OP## = rhs; \
} \
} \
;
#define OMNITRACE_BINARY_OPERATOR_NON_COMMUTATIVE(NAME, OP) \
template <typename T, typename U, typename B = empty_base<T>> \
struct NAME##2 \
: B{ friend T operator OP(T lhs, const U& rhs){ return lhs OP## = rhs; \
} \
} \
;
namespace omnitrace
{
namespace container
{
struct true_t
{};
struct false_t
{};
template <typename T>
class empty_base
{};
template <typename T>
struct is_chained_base
{
using value = true_t;
};
OMNITRACE_BINARY_OPERATOR_COMMUTATIVE(addable, +)
OMNITRACE_BINARY_OPERATOR_NON_COMMUTATIVE(subtractable, -)
OMNITRACE_OPERATOR_TEMPLATE(addable)
template <typename T, typename B = empty_base<T>>
struct incrementable : B
{
friend T operator++(T& x, int)
{
incrementable_type nrv(x);
++x;
return nrv;
}
private: // The use of this typedef works around a Borland bug
typedef T incrementable_type;
};
template <typename T, typename B = empty_base<T>>
struct decrementable : B
{
friend T operator--(T& x, int)
{
decrementable_type nrv(x);
--x;
return nrv;
}
private: // The use of this typedef works around a Borland bug
typedef T decrementable_type;
};
template <typename T, typename P, typename B = empty_base<T>>
struct dereferenceable : B
{
P operator->() const { return ::std::addressof(*static_cast<const T&>(*this)); }
};
template <typename T, typename I, typename R, typename B = empty_base<T>>
struct indexable : B
{
R operator[](I n) const { return *(static_cast<const T&>(*this) + n); }
};
template <typename T, typename B = empty_base<T>>
struct equality_comparable1 : B
{
friend bool operator!=(const T& x, const T& y) { return !static_cast<bool>(x == y); }
};
template <typename T, typename P, typename B = empty_base<T>>
struct input_iteratable
: equality_comparable1<T, incrementable<T, dereferenceable<T, P, B>>>
{};
template <typename T, typename B = empty_base<T>>
struct output_iteratable : incrementable<T, B>
{};
template <typename T, typename P, typename B = empty_base<T>>
struct forward_iteratable : input_iteratable<T, P, B>
{};
template <typename T, typename P, typename B = empty_base<T>>
struct bidirectional_iteratable : forward_iteratable<T, P, decrementable<T, B>>
{};
// template <typename T, typename U, typename B = empty_base<T>>
// struct subtractable2;
template <typename T, typename U, typename B = empty_base<T>>
struct additive2 : addable2<T, U, subtractable2<T, U, B>>
{};
template <typename T, typename B = empty_base<T>>
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
// To avoid repeated derivation from equality_comparable,
// which is an indirect base typename of bidirectional_iterable,
// random_access_iteratable must not be derived from totally_ordered1
// but from less_than_comparable1 only. (Helmut Zeisel, 02-Dec-2001)
template <typename T, typename P, typename D, typename R, typename B = empty_base<T>>
struct random_access_iteratable
: bidirectional_iteratable<
T, P, less_than_comparable1<T, additive2<T, D, indexable<T, D, R, B>>>>
{};
template <typename CategoryT, typename Tp, typename DistanceT = std::ptrdiff_t,
typename PointerT = Tp*, typename ReferenceT = Tp&>
struct iterator_helper
{
using iterator_category = CategoryT;
using value_type = Tp;
using difference_type = DistanceT;
using pointer = PointerT;
using reference = ReferenceT;
};
template <typename T, typename V, typename D = std::ptrdiff_t, typename P = V*,
typename R = V&>
struct random_access_iterator_helper
: random_access_iteratable<T, P, D, R,
iterator_helper<std::random_access_iterator_tag, V, D, P, R>>
{
friend D requires_difference_operator(const T& x, const T& y) { return x - y; }
}; // random_access_iterator_helper
} // namespace container
} // namespace omnitrace
@@ -0,0 +1,391 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/containers/operators.hpp"
#include "core/containers/static_vector.hpp"
#include "core/defines.hpp"
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <numeric>
#include <type_traits>
#include <vector>
namespace omnitrace
{
namespace container
{
template <typename Tp, size_t ChunkSizeV = OMNITRACE_MAX_THREADS>
class stable_vector
{
public:
using value_type = Tp;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
static constexpr const size_t chunk_size = ChunkSizeV;
private:
template <size_t N>
struct is_pow2
{
static constexpr bool value = (N & (N - 1)) == 0;
};
static_assert(ChunkSizeV > 0, "ChunkSize needs to be greater than zero");
static_assert(is_pow2<ChunkSizeV>::value, "ChunkSize needs to be a power of 2");
using this_type = stable_vector<Tp, ChunkSizeV>;
using const_this_type = const stable_vector<Tp, ChunkSizeV>;
template <typename ContainerT>
struct iterator_base
{
iterator_base(ContainerT* c = nullptr, size_type i = 0)
: m_container(c)
, m_index(i)
{}
iterator_base& operator+=(size_type i)
{
m_index += i;
return *this;
}
iterator_base& operator-=(size_type i)
{
m_index -= i;
return *this;
}
iterator_base& operator++()
{
++m_index;
return *this;
}
iterator_base& operator--()
{
--m_index;
return *this;
}
difference_type operator-(const iterator_base& it)
{
assert(m_container == it.m_container);
return m_index - it.m_index;
}
bool operator<(const iterator_base& it) const
{
assert(m_container == it.m_container);
return m_index < it.m_index;
}
bool operator==(const iterator_base& it) const
{
return m_container == it.m_container && m_index == it.m_index;
}
protected:
ContainerT* m_container;
size_type m_index;
};
public:
struct const_iterator;
struct iterator
: public iterator_base<this_type>
//, std::iterator<std::random_access_iterator_tag, value_type>
, public random_access_iterator_helper<iterator, value_type>
{
using iterator_base<this_type>::iterator_base;
friend struct const_iterator;
reference operator*() { return (*this->m_container)[this->m_index]; }
};
struct const_iterator
: public iterator_base<const_this_type>
//, std::iterator<std::random_access_iterator_tag, const value_type>
, public random_access_iterator_helper<const_iterator, const value_type>
{
using iterator_base<const_this_type>::iterator_base;
const_iterator(const iterator& it)
: iterator_base<const_this_type>(it.m_container, it.m_index)
{}
const_reference operator*() const { return (*this->m_container)[this->m_index]; }
bool operator==(const const_iterator& it) const
{
return iterator_base<const_this_type>::operator==(it);
}
friend bool operator==(const iterator& l, const const_iterator& r)
{
return r == l;
}
};
stable_vector() = default;
explicit stable_vector(size_type count, const Tp& value);
explicit stable_vector(size_type count);
template <typename InputItrT,
typename = std::enable_if_t<std::is_convertible<
typename std::iterator_traits<InputItrT>::iterator_category,
std::input_iterator_tag>::value>>
stable_vector(InputItrT first, InputItrT last);
stable_vector(std::initializer_list<Tp>);
stable_vector(const stable_vector& other);
stable_vector(stable_vector&& other) noexcept;
stable_vector& operator=(stable_vector v);
iterator begin() noexcept { return { this, 0 }; }
const_iterator begin() const noexcept { return { this, 0 }; }
const_iterator cbegin() const noexcept { return begin(); }
iterator end() noexcept { return { this, size() }; }
const_iterator end() const noexcept { return { this, size() }; }
const_iterator cend() const noexcept { return end(); }
size_type size() const noexcept
{
return empty() ? 0 : (m_chunks.size() - 1) * ChunkSizeV + m_chunks.back()->size();
}
size_type max_size() const noexcept { return std::numeric_limits<size_type>::max(); }
size_type capacity() const noexcept { return m_chunks.size() * ChunkSizeV; }
bool empty() const noexcept { return m_chunks.size() == 0; }
void reserve(size_type new_capacity);
void shrink_to_fit() noexcept {}
bool operator==(const this_type& c) const
{
return size() == c.size() && std::equal(cbegin(), cend(), c.cbegin());
}
bool operator!=(const this_type& c) const { return !operator==(c); }
void swap(this_type& v) { std::swap(m_chunks, v.m_chunks); }
friend void swap(this_type& l, this_type& r) { l.swap(r); }
reference front() { return m_chunks.front()->front(); }
const_reference front() const { return front(); }
reference back() { return m_chunks.back()->back(); }
const_reference back() const { return back(); }
void push_back(const Tp& t);
void push_back(Tp&& t);
template <typename... Args>
void emplace_back(Args&&... args);
reference operator[](size_type i);
const_reference operator[](size_type i) const;
reference at(size_type i);
const_reference at(size_type i) const;
private:
using chunk_type = container::static_vector<Tp, ChunkSizeV, true>;
using storage_type = std::vector<std::unique_ptr<chunk_type>>;
void add_chunk();
chunk_type& last_chunk();
storage_type m_chunks;
};
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>::stable_vector(size_type count, const Tp& value)
{
for(size_type i = 0; i < count; ++i)
{
push_back(value);
}
}
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>::stable_vector(size_type count)
{
for(size_type i = 0; i < count; ++i)
{
emplace_back();
}
}
template <typename Tp, size_t ChunkSizeV>
template <typename InputItrT, typename>
stable_vector<Tp, ChunkSizeV>::stable_vector(InputItrT first, InputItrT last)
{
for(; first != last; ++first)
{
push_back(*first);
}
}
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>::stable_vector(const stable_vector& other)
{
for(const auto& chunk : other.m_chunks)
{
m_chunks.emplace_back(std::make_unique<chunk_type>(*chunk));
}
}
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>::stable_vector(stable_vector&& other) noexcept
: m_chunks(std::move(other.m_chunks))
{}
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>::stable_vector(std::initializer_list<Tp> ilist)
{
for(const auto& t : ilist)
{
push_back(t);
}
}
template <typename Tp, size_t ChunkSizeV>
stable_vector<Tp, ChunkSizeV>&
stable_vector<Tp, ChunkSizeV>::operator=(stable_vector v)
{
swap(v);
return *this;
}
template <typename Tp, size_t ChunkSizeV>
void
stable_vector<Tp, ChunkSizeV>::add_chunk()
{
m_chunks.emplace_back(std::make_unique<chunk_type>());
}
template <typename Tp, size_t ChunkSizeV>
typename stable_vector<Tp, ChunkSizeV>::chunk_type&
stable_vector<Tp, ChunkSizeV>::last_chunk()
{
if(OMNITRACE_UNLIKELY(m_chunks.empty() || m_chunks.back()->size() == ChunkSizeV))
{
add_chunk();
}
return *m_chunks.back();
}
template <typename Tp, size_t ChunkSizeV>
void
stable_vector<Tp, ChunkSizeV>::reserve(size_type new_capacity)
{
const size_t initial_capacity = capacity();
for(difference_type i = new_capacity - initial_capacity; i > 0; i -= ChunkSizeV)
{
add_chunk();
}
}
template <typename Tp, size_t ChunkSizeV>
void
stable_vector<Tp, ChunkSizeV>::push_back(const Tp& t)
{
last_chunk().push_back(t);
}
template <typename Tp, size_t ChunkSizeV>
void
stable_vector<Tp, ChunkSizeV>::push_back(Tp&& t)
{
last_chunk().push_back(std::move(t));
}
template <typename Tp, size_t ChunkSizeV>
template <typename... Args>
void
stable_vector<Tp, ChunkSizeV>::emplace_back(Args&&... args)
{
last_chunk().emplace_back(std::forward<Args>(args)...);
}
template <typename Tp, size_t ChunkSizeV>
typename stable_vector<Tp, ChunkSizeV>::reference
stable_vector<Tp, ChunkSizeV>::operator[](size_type i)
{
return (*m_chunks[i / ChunkSizeV])[i % ChunkSizeV];
}
template <typename Tp, size_t ChunkSizeV>
typename stable_vector<Tp, ChunkSizeV>::const_reference
stable_vector<Tp, ChunkSizeV>::operator[](size_type i) const
{
return const_cast<this_type&>(*this)[i];
}
template <typename Tp, size_t ChunkSizeV>
typename stable_vector<Tp, ChunkSizeV>::reference
stable_vector<Tp, ChunkSizeV>::at(size_type i)
{
if(OMNITRACE_UNLIKELY(i >= size()))
{
throw ::omnitrace::exception<std::out_of_range>(
"stable_vector::at(" + std::to_string(i) + "). size is " +
std::to_string(size()));
}
return operator[](i);
}
template <typename Tp, size_t ChunkSizeV>
typename stable_vector<Tp, ChunkSizeV>::const_reference
stable_vector<Tp, ChunkSizeV>::at(size_type i) const
{
return const_cast<this_type&>(*this).at(i);
}
template <typename Tp, size_t ChunkSizeV, typename... Args>
auto
resize(stable_vector<Tp, ChunkSizeV>& _v, size_t _n, Args&&... args)
{
if(_n > _v.capacity()) _v.reserve(_n);
while(_v.size() < _n)
_v.emplace_back(std::forward<Args>(args)...);
return _v.size();
}
} // namespace container
} // namespace omnitrace
@@ -0,0 +1,194 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/common.hpp"
#include "core/debug.hpp"
#include "core/exception.hpp"
#include <timemory/utility/demangle.hpp>
#include <array>
#include <atomic>
#include <cstdlib>
namespace omnitrace
{
namespace container
{
template <typename Tp, size_t N, bool AtomicSizeV = false>
struct static_vector
{
using count_type = std::conditional_t<AtomicSizeV, std::atomic<size_t>, size_t>;
using this_type = static_vector<Tp, N>;
using value_type = Tp;
static_vector() = default;
static_vector(const static_vector&) = default;
static_vector(static_vector&&) noexcept = default;
static_vector& operator=(const static_vector&) = default;
static_vector& operator=(static_vector&&) noexcept = default;
static_vector(size_t _n, Tp _v = {});
static_vector& operator=(std::initializer_list<Tp>&& _v);
static_vector& operator=(std::pair<std::array<Tp, N>, size_t>&&);
template <typename... Args>
value_type& emplace_back(Args&&... _v);
template <typename Up>
decltype(auto) push_back(Up&& _v)
{
return emplace_back(Tp{ std::forward<Up>(_v) });
}
void pop_back() { --m_size; }
void clear();
void reserve(size_t) noexcept {}
void shrink_to_fit() noexcept {}
auto capacity() noexcept { return N; }
size_t size() const { return m_size; }
bool empty() const { return (size() == 0); }
auto begin() { return m_data.begin(); }
auto begin() const { return m_data.begin(); }
auto cbegin() const { return m_data.cbegin(); }
auto end() { return m_data.begin() + size(); }
auto end() const { return m_data.begin() + size(); }
auto cend() const { return m_data.cbegin() + size(); }
decltype(auto) operator[](size_t _idx) { return m_data[_idx]; }
decltype(auto) operator[](size_t _idx) const { return m_data[_idx]; }
decltype(auto) at(size_t _idx) { return m_data.at(_idx); }
decltype(auto) at(size_t _idx) const { return m_data.at(_idx); }
decltype(auto) front() { return m_data.front(); }
decltype(auto) front() const { return m_data.front(); }
decltype(auto) back() { return *(m_data.begin() + size() - 1); }
decltype(auto) back() const { return *(m_data.begin() + size() - 1); }
void swap(this_type& _v);
friend void swap(this_type& _lhs, this_type& _rhs) { _lhs.swap(_rhs); }
private:
count_type m_size = count_type{ 0 };
std::array<Tp, N> m_data = {};
};
template <typename Tp, size_t N, bool AtomicSizeV>
static_vector<Tp, N, AtomicSizeV>::static_vector(size_t _n, Tp _v)
{
m_size.store(_n);
m_data.fill(_v);
}
template <typename Tp, size_t N, bool AtomicSizeV>
static_vector<Tp, N, AtomicSizeV>&
static_vector<Tp, N, AtomicSizeV>::operator=(std::initializer_list<Tp>&& _v)
{
if(OMNITRACE_UNLIKELY(_v.size() > N))
{
throw exception<std::out_of_range>(
std::string{ "static_vector::operator=(initializer_list) size > " } +
std::to_string(N));
}
clear();
for(auto&& itr : _v)
m_data[m_size++] = itr;
return *this;
}
template <typename Tp, size_t N, bool AtomicSizeV>
static_vector<Tp, N, AtomicSizeV>&
static_vector<Tp, N, AtomicSizeV>::operator=(std::pair<std::array<Tp, N>, size_t>&& _v)
{
if constexpr(AtomicSizeV) m_size.store(0);
m_data = std::move(_v.first);
if constexpr(AtomicSizeV)
m_size.store(_v.second);
else
m_size = _v.second;
return *this;
}
template <typename Tp, size_t N, bool AtomicSizeV>
void
static_vector<Tp, N, AtomicSizeV>::clear()
{
if constexpr(AtomicSizeV)
m_size.store(0);
else
m_size = 0;
}
template <typename Tp, size_t N, bool AtomicSizeV>
void
static_vector<Tp, N, AtomicSizeV>::swap(this_type& _v)
{
if constexpr(AtomicSizeV)
{
auto _t_size = m_size;
auto _v_size = _v.m_size;
std::swap(m_data, _v.m_data);
m_size.store(_v_size);
_v.m_size.store(_t_size);
}
else
{
std::swap(m_size, _v.m_size);
std::swap(m_data, _v.m_data);
}
}
template <typename Tp, size_t N, bool AtomicSizeV>
template <typename... Args>
Tp&
static_vector<Tp, N, AtomicSizeV>::emplace_back(Args&&... _v)
{
auto _idx = m_size++;
if(_idx >= N)
{
throw exception<std::out_of_range>(
std::string{ "static_vector::emplace_back - reached capacity " } +
std::to_string(N));
}
if constexpr(std::is_assignable<Tp, decltype(std::forward<Args>(_v))...>::value)
m_data[_idx] = { std::forward<Args>(_v)... };
else
m_data[_idx] = Tp{ std::forward<Args>(_v)... };
return m_data[_idx];
}
} // namespace container
} // namespace omnitrace
+124
View File
@@ -0,0 +1,124 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "debug.hpp"
#include "binary/address_range.hpp"
#include "state.hpp"
#include <timemory/log/color.hpp>
#include <timemory/utility/filepath.hpp>
#include <iomanip>
#include <sstream>
#include <string>
namespace omnitrace
{
namespace debug
{
namespace
{
struct source_location_history
{
std::array<source_location, 10> data = {};
size_t size = 0;
};
auto&
get_source_location_history()
{
static thread_local auto _v = source_location_history{};
return _v;
}
auto _protect_lock = std::atomic<bool>{ false };
auto _protect_unlock = std::atomic<bool>{ false };
} // namespace
void
set_source_location(source_location&& _v)
{
auto& _hist = get_source_location_history();
auto _idx = _hist.size++;
_hist.data.at(_idx % _hist.data.size()) = _v;
}
lock::lock()
: m_lk{ tim::type_mutex<decltype(std::cerr)>(), std::defer_lock }
{
if(!m_lk.owns_lock() && !_protect_lock)
{
_protect_lock.store(true);
push_thread_state(ThreadState::Internal);
m_lk.lock();
_protect_lock.store(false);
}
}
lock::~lock()
{
if(m_lk.owns_lock() && !_protect_unlock)
{
_protect_unlock.store(true);
m_lk.unlock();
pop_thread_state();
_protect_unlock.store(false);
}
}
FILE*
get_file()
{
static FILE* _v = []() {
auto&& _fname = tim::get_env<std::string>("OMNITRACE_LOG_FILE", "");
if(!_fname.empty()) tim::log::monochrome() = true;
return (_fname.empty()) ? stderr : tim::filepath::fopen(_fname, "w");
}();
return _v;
}
} // namespace debug
template <typename Tp>
std::string
as_hex(Tp _v, size_t _width)
{
std::stringstream _ss;
_ss.fill('0');
_ss << "0x" << std::hex << std::setw(_width) << _v;
return _ss.str();
}
template <>
std::string
as_hex<address_range_t>(address_range_t _v, size_t _width)
{
return (_v.is_range()) ? JOIN('-', as_hex(_v.low, _width), as_hex(_v.high, _width))
: as_hex(_v.low, _width);
}
template std::string as_hex<int32_t>(int32_t, size_t);
template std::string as_hex<uint32_t>(uint32_t, size_t);
template std::string as_hex<int64_t>(int64_t, size_t);
template std::string as_hex<uint64_t>(uint64_t, size_t);
template std::string
as_hex<void*>(void*, size_t);
} // namespace omnitrace
+672
View File
@@ -0,0 +1,672 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "defines.hpp"
#include "exception.hpp"
#include <timemory/api.hpp>
#include <timemory/backends/dmp.hpp>
#include <timemory/backends/process.hpp>
#include <timemory/backends/threading.hpp>
#include <timemory/log/logger.hpp>
#include <timemory/mpl/concepts.hpp>
#include <timemory/signals/signal_handlers.hpp>
#include <timemory/utility/backtrace.hpp>
#include <timemory/utility/locking.hpp>
#include <timemory/utility/utility.hpp>
#include <array>
#include <cstdio>
#include <cstring>
#include <string_view>
#include <utility>
namespace omnitrace
{
inline namespace config
{
bool
get_debug() OMNITRACE_HOT;
int
get_verbose() OMNITRACE_HOT;
bool
get_debug_env() OMNITRACE_HOT;
int
get_verbose_env() OMNITRACE_HOT;
bool
get_is_continuous_integration() OMNITRACE_HOT;
bool
get_debug_tid() OMNITRACE_HOT;
bool
get_debug_pid() OMNITRACE_HOT;
bool
get_critical_trace_debug() OMNITRACE_HOT;
} // namespace config
namespace debug
{
struct source_location
{
std::string_view function = {};
std::string_view file = {};
int line = 0;
};
//
void
set_source_location(source_location&&);
//
FILE*
get_file();
//
inline void
flush()
{
fprintf(stdout, "%s", ::tim::log::color::end());
fflush(stdout);
std::cout << ::tim::log::color::end() << std::flush;
fprintf(::omnitrace::debug::get_file(), "%s", ::tim::log::color::end());
fflush(::omnitrace::debug::get_file());
std::cerr << ::tim::log::color::end() << std::flush;
}
//
struct lock
{
lock();
~lock();
private:
tim::auto_lock_t m_lk;
};
//
template <typename Arg, typename... Args>
bool
is_bracket(Arg&& _arg, Args&&...)
{
if constexpr(::tim::concepts::is_string_type<Arg>::value)
return (::std::string_view{ _arg }.empty()) ? false : _arg[0] == '[';
else
return false;
}
//
namespace
{
template <typename T, size_t... Idx>
auto
get_chars(T&& _c, std::index_sequence<Idx...>)
{
return std::array<const char, sizeof...(Idx) + 1>{ std::forward<T>(_c)[Idx]...,
'\0' };
}
} // namespace
} // namespace debug
namespace binary
{
struct address_range;
}
using address_range_t = binary::address_range;
template <typename Tp>
std::string
as_hex(Tp, size_t _wdith = 16);
template <>
std::string as_hex<address_range_t>(address_range_t, size_t);
extern template std::string as_hex<int32_t>(int32_t, size_t);
extern template std::string as_hex<uint32_t>(uint32_t, size_t);
extern template std::string as_hex<int64_t>(int64_t, size_t);
extern template std::string as_hex<uint64_t>(uint64_t, size_t);
extern template std::string
as_hex<void*>(void*, size_t);
} // namespace omnitrace
#if !defined(OMNITRACE_DEBUG_BUFFER_LEN)
# define OMNITRACE_DEBUG_BUFFER_LEN 1024
#endif
#if !defined(OMNITRACE_DEBUG_PROCESS_IDENTIFIER)
# if defined(TIMEMORY_USE_MPI)
# define OMNITRACE_DEBUG_PROCESS_IDENTIFIER static_cast<int>(::tim::dmp::rank())
# elif defined(TIMEMORY_USE_MPI_HEADERS)
# define OMNITRACE_DEBUG_PROCESS_IDENTIFIER \
(::tim::dmp::is_initialized()) ? static_cast<int>(::tim::dmp::rank()) \
: static_cast<int>(::tim::process::get_id())
# else
# define OMNITRACE_DEBUG_PROCESS_IDENTIFIER \
static_cast<int>(::tim::process::get_id())
# endif
#endif
#if !defined(OMNITRACE_DEBUG_THREAD_IDENTIFIER)
# define OMNITRACE_DEBUG_THREAD_IDENTIFIER ::tim::threading::get_id()
#endif
#if !defined(OMNITRACE_SOURCE_LOCATION)
# define OMNITRACE_SOURCE_LOCATION \
::omnitrace::debug::source_location { __PRETTY_FUNCTION__, __FILE__, __LINE__ }
#endif
#if !defined(OMNITRACE_RECORD_SOURCE_LOCATION)
# define OMNITRACE_RECORD_SOURCE_LOCATION \
::omnitrace::debug::set_source_location(OMNITRACE_SOURCE_LOCATION)
#endif
#if defined(__clang__) || (__GNUC__ < 9)
# define OMNITRACE_FUNCTION \
std::string{ __FUNCTION__ } \
.substr(0, std::string_view{ __FUNCTION__ }.find("_hidden")) \
.c_str()
# define OMNITRACE_PRETTY_FUNCTION \
std::string{ __PRETTY_FUNCTION__ } \
.substr(0, std::string_view{ __PRETTY_FUNCTION__ }.find("_hidden")) \
.c_str()
#else
# define OMNITRACE_FUNCTION \
::omnitrace::debug::get_chars( \
std::string_view{ __FUNCTION__ }, \
std::make_index_sequence<std::min( \
std::string_view{ __FUNCTION__ }.find("_hidden"), \
std::string_view{ __FUNCTION__ }.length())>{}) \
.data()
# define OMNITRACE_PRETTY_FUNCTION \
::omnitrace::debug::get_chars( \
std::string_view{ __PRETTY_FUNCTION__ }, \
std::make_index_sequence<std::min( \
std::string_view{ __PRETTY_FUNCTION__ }.find("_hidden"), \
std::string_view{ __PRETTY_FUNCTION__ }.length())>{}) \
.data()
#endif
//--------------------------------------------------------------------------------------//
#define OMNITRACE_FPRINTF_STDERR_COLOR(COLOR) \
fprintf(::omnitrace::debug::get_file(), "%s", ::tim::log::color::COLOR())
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_PRINT(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(info); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_BASIC_PRINT(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(info); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_PRINT_F(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(info); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_BASIC_PRINT_F(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(info); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_WARN(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(warning); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_BASIC_WARN(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(warning); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_WARN_F(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(warning); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
#define OMNITRACE_CONDITIONAL_BASIC_WARN_F(COND, ...) \
if((COND) && ::omnitrace::config::get_debug_tid() && \
::omnitrace::config::get_debug_pid()) \
{ \
::omnitrace::debug::flush(); \
::omnitrace::debug::lock _debug_lk{}; \
OMNITRACE_FPRINTF_STDERR_COLOR(warning); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
}
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_THROW_E(COND, TYPE, ...) \
if(COND) \
{ \
char _msg_buffer[OMNITRACE_DEBUG_BUFFER_LEN]; \
snprintf(_msg_buffer, OMNITRACE_DEBUG_BUFFER_LEN, "[omnitrace][%i][%li][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
auto len = strlen(_msg_buffer); \
snprintf(_msg_buffer + len, OMNITRACE_DEBUG_BUFFER_LEN - len, __VA_ARGS__); \
throw ::omnitrace::exception<TYPE>( \
::tim::log::string(::tim::log::color::fatal(), _msg_buffer)); \
}
#define OMNITRACE_CONDITIONAL_BASIC_THROW_E(COND, TYPE, ...) \
if(COND) \
{ \
char _msg_buffer[OMNITRACE_DEBUG_BUFFER_LEN]; \
snprintf(_msg_buffer, OMNITRACE_DEBUG_BUFFER_LEN, "[omnitrace][%i][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
auto len = strlen(_msg_buffer); \
snprintf(_msg_buffer + len, OMNITRACE_DEBUG_BUFFER_LEN - len, __VA_ARGS__); \
throw ::omnitrace::exception<TYPE>( \
::tim::log::string(::tim::log::color::fatal(), _msg_buffer)); \
}
#define OMNITRACE_CI_THROW_E(COND, TYPE, ...) \
OMNITRACE_CONDITIONAL_THROW_E( \
::omnitrace::get_is_continuous_integration() && (COND), TYPE, __VA_ARGS__)
#define OMNITRACE_CI_BASIC_THROW_E(COND, TYPE, ...) \
OMNITRACE_CONDITIONAL_BASIC_THROW_E( \
::omnitrace::get_is_continuous_integration() && (COND), TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_THROW(COND, ...) \
OMNITRACE_CONDITIONAL_THROW_E((COND), std::runtime_error, __VA_ARGS__)
#define OMNITRACE_CONDITIONAL_BASIC_THROW(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_THROW_E((COND), std::runtime_error, __VA_ARGS__)
#define OMNITRACE_CI_THROW(COND, ...) \
OMNITRACE_CI_THROW_E((COND), std::runtime_error, __VA_ARGS__)
#define OMNITRACE_CI_BASIC_THROW(COND, ...) \
OMNITRACE_CI_BASIC_THROW_E((COND), std::runtime_error, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_FAILURE(COND, METHOD, ...) \
if(COND) \
{ \
::omnitrace::debug::flush(); \
OMNITRACE_FPRINTF_STDERR_COLOR(fatal); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
::omnitrace::set_state(::omnitrace::State::Finalized); \
::tim::signals::disable_signal_detection(); \
timemory_print_demangled_backtrace<64>(); \
METHOD; \
}
#define OMNITRACE_CONDITIONAL_BASIC_FAILURE(COND, METHOD, ...) \
if(COND) \
{ \
::omnitrace::debug::flush(); \
OMNITRACE_FPRINTF_STDERR_COLOR(fatal); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
::omnitrace::set_state(::omnitrace::State::Finalized); \
::tim::signals::disable_signal_detection(); \
timemory_print_demangled_backtrace<64>(); \
METHOD; \
}
#define OMNITRACE_CONDITIONAL_FAILURE_F(COND, METHOD, ...) \
if(COND) \
{ \
::omnitrace::debug::flush(); \
OMNITRACE_FPRINTF_STDERR_COLOR(fatal); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%li][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_DEBUG_THREAD_IDENTIFIER, \
OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
::omnitrace::set_state(::omnitrace::State::Finalized); \
::tim::signals::disable_signal_detection(); \
timemory_print_demangled_backtrace<64>(); \
METHOD; \
}
#define OMNITRACE_CONDITIONAL_BASIC_FAILURE_F(COND, METHOD, ...) \
if(COND) \
{ \
::omnitrace::debug::flush(); \
OMNITRACE_FPRINTF_STDERR_COLOR(fatal); \
fprintf(::omnitrace::debug::get_file(), "[omnitrace][%i][%s]%s", \
OMNITRACE_DEBUG_PROCESS_IDENTIFIER, OMNITRACE_FUNCTION, \
::omnitrace::debug::is_bracket(__VA_ARGS__) ? "" : " "); \
fprintf(::omnitrace::debug::get_file(), __VA_ARGS__); \
::omnitrace::debug::flush(); \
::omnitrace::set_state(::omnitrace::State::Finalized); \
::tim::signals::disable_signal_detection(); \
timemory_print_demangled_backtrace<64>(); \
METHOD; \
}
#define OMNITRACE_CI_FAILURE(COND, METHOD, ...) \
OMNITRACE_CONDITIONAL_FAILURE( \
::omnitrace::get_is_continuous_integration() && (COND), METHOD, __VA_ARGS__)
#define OMNITRACE_CI_BASIC_FAILURE(COND, METHOD, ...) \
OMNITRACE_CONDITIONAL_BASIC_FAILURE( \
::omnitrace::get_is_continuous_integration() && (COND), METHOD, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_FAIL(COND, ...) \
OMNITRACE_CONDITIONAL_FAILURE(COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), \
__VA_ARGS__)
#define OMNITRACE_CONDITIONAL_BASIC_FAIL(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_FAILURE(COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), \
__VA_ARGS__)
#define OMNITRACE_CONDITIONAL_FAIL_F(COND, ...) \
OMNITRACE_CONDITIONAL_FAILURE_F(COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), \
__VA_ARGS__)
#define OMNITRACE_CONDITIONAL_BASIC_FAIL_F(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_FAILURE_F( \
COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), __VA_ARGS__)
#define OMNITRACE_CI_FAIL(COND, ...) \
OMNITRACE_CI_FAILURE(COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), __VA_ARGS__)
#define OMNITRACE_CI_BASIC_FAIL(COND, ...) \
OMNITRACE_CI_BASIC_FAILURE(COND, OMNITRACE_ESC(::std::exit(EXIT_FAILURE)), \
__VA_ARGS__)
//--------------------------------------------------------------------------------------//
#define OMNITRACE_CONDITIONAL_ABORT(COND, ...) \
OMNITRACE_CONDITIONAL_FAILURE(COND, OMNITRACE_ESC(::std::abort()), __VA_ARGS__)
#define OMNITRACE_CONDITIONAL_BASIC_ABORT(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_FAILURE(COND, OMNITRACE_ESC(::std::abort()), __VA_ARGS__)
#define OMNITRACE_CONDITIONAL_ABORT_F(COND, ...) \
OMNITRACE_CONDITIONAL_FAILURE_F(COND, OMNITRACE_ESC(::std::abort()), __VA_ARGS__)
#define OMNITRACE_CONDITIONAL_BASIC_ABORT_F(COND, ...) \
OMNITRACE_CONDITIONAL_BASIC_FAILURE_F(COND, OMNITRACE_ESC(::std::abort()), \
__VA_ARGS__)
#define OMNITRACE_CI_ABORT(COND, ...) \
OMNITRACE_CI_FAILURE(COND, OMNITRACE_ESC(::std::abort()), __VA_ARGS__)
#define OMNITRACE_CI_BASIC_ABORT(COND, ...) \
OMNITRACE_CI_BASIC_FAILURE(COND, OMNITRACE_ESC(::std::abort()), __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Debug macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_DEBUG(...) \
OMNITRACE_CONDITIONAL_PRINT(::omnitrace::get_debug(), __VA_ARGS__)
#define OMNITRACE_BASIC_DEBUG(...) \
OMNITRACE_CONDITIONAL_BASIC_PRINT(::omnitrace::get_debug_env(), __VA_ARGS__)
#define OMNITRACE_DEBUG_F(...) \
OMNITRACE_CONDITIONAL_PRINT_F(::omnitrace::get_debug(), __VA_ARGS__)
#define OMNITRACE_BASIC_DEBUG_F(...) \
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(::omnitrace::get_debug_env(), __VA_ARGS__)
#define OMNITRACE_CT_DEBUG(...) \
OMNITRACE_CONDITIONAL_PRINT(::omnitrace::get_critical_trace_debug(), __VA_ARGS__)
#define OMNITRACE_CT_DEBUG_F(...) \
OMNITRACE_CONDITIONAL_PRINT_F(::omnitrace::get_critical_trace_debug(), __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Verbose macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_VERBOSE(LEVEL, ...) \
OMNITRACE_CONDITIONAL_PRINT( \
::omnitrace::get_debug() || (::omnitrace::get_verbose() >= LEVEL), __VA_ARGS__)
#define OMNITRACE_BASIC_VERBOSE(LEVEL, ...) \
OMNITRACE_CONDITIONAL_BASIC_PRINT(::omnitrace::get_debug_env() || \
(::omnitrace::get_verbose_env() >= LEVEL), \
__VA_ARGS__)
#define OMNITRACE_VERBOSE_F(LEVEL, ...) \
OMNITRACE_CONDITIONAL_PRINT_F( \
::omnitrace::get_debug() || (::omnitrace::get_verbose() >= LEVEL), __VA_ARGS__)
#define OMNITRACE_BASIC_VERBOSE_F(LEVEL, ...) \
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(::omnitrace::get_debug_env() || \
(::omnitrace::get_verbose_env() >= LEVEL), \
__VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Warning macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_WARNING(LEVEL, ...) \
OMNITRACE_CONDITIONAL_WARN( \
::omnitrace::get_debug() || (::omnitrace::get_verbose() >= LEVEL), __VA_ARGS__)
#define OMNITRACE_BASIC_WARNING(LEVEL, ...) \
OMNITRACE_CONDITIONAL_BASIC_WARN(::omnitrace::get_debug_env() || \
(::omnitrace::get_verbose_env() >= LEVEL), \
__VA_ARGS__)
#define OMNITRACE_WARNING_F(LEVEL, ...) \
OMNITRACE_CONDITIONAL_WARN_F( \
::omnitrace::get_debug() || (::omnitrace::get_verbose() >= LEVEL), __VA_ARGS__)
#define OMNITRACE_BASIC_WARNING_F(LEVEL, ...) \
OMNITRACE_CONDITIONAL_BASIC_WARN_F(::omnitrace::get_debug_env() || \
(::omnitrace::get_verbose_env() >= LEVEL), \
__VA_ARGS__)
#define OMNITRACE_WARNING_IF(COND, ...) OMNITRACE_CONDITIONAL_WARN((COND), __VA_ARGS__)
#define OMNITRACE_WARNING_IF_F(COND, ...) \
OMNITRACE_CONDITIONAL_WARN_F((COND), __VA_ARGS__)
#define OMNITRACE_WARNING_OR_CI_THROW(LEVEL, ...) \
{ \
if(::omnitrace::get_is_continuous_integration()) \
{ \
OMNITRACE_CI_THROW(true, __VA_ARGS__); \
} \
else \
{ \
OMNITRACE_CONDITIONAL_WARN(::omnitrace::get_debug() || \
(::omnitrace::get_verbose() >= LEVEL), \
__VA_ARGS__) \
} \
}
#define OMNITRACE_REQUIRE(...) TIMEMORY_REQUIRE(__VA_ARGS__)
#define OMNITRACE_PREFER(COND) \
(COND) ? ::tim::log::base() \
: (::omnitrace::get_is_continuous_integration()) ? TIMEMORY_FATAL \
: TIMEMORY_WARNING
//--------------------------------------------------------------------------------------//
//
// Basic print macros (basic means it will not provide PID/RANK or TID) and will not
// initialize the settings.
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_BASIC_PRINT(...) OMNITRACE_CONDITIONAL_BASIC_PRINT(true, __VA_ARGS__)
#define OMNITRACE_BASIC_PRINT_F(...) \
OMNITRACE_CONDITIONAL_BASIC_PRINT_F(true, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Print macros. Will provide PID/RANK and TID (will initialize settings)
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_PRINT(...) OMNITRACE_CONDITIONAL_PRINT(true, __VA_ARGS__)
#define OMNITRACE_PRINT_F(...) OMNITRACE_CONDITIONAL_PRINT_F(true, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Throw macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_THROW(...) OMNITRACE_CONDITIONAL_THROW(true, __VA_ARGS__)
#define OMNITRACE_BASIC_THROW(...) OMNITRACE_CONDITIONAL_BASIC_THROW(true, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Fail macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_FAIL(...) OMNITRACE_CONDITIONAL_FAIL(true, __VA_ARGS__)
#define OMNITRACE_FAIL_F(...) OMNITRACE_CONDITIONAL_FAIL_F(true, __VA_ARGS__)
#define OMNITRACE_BASIC_FAIL(...) OMNITRACE_CONDITIONAL_BASIC_FAIL(true, __VA_ARGS__)
#define OMNITRACE_BASIC_FAIL_F(...) OMNITRACE_CONDITIONAL_BASIC_FAIL_F(true, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
//
// Abort macros
//
//--------------------------------------------------------------------------------------//
#define OMNITRACE_ABORT(...) OMNITRACE_CONDITIONAL_ABORT(true, __VA_ARGS__)
#define OMNITRACE_ABORT_F(...) OMNITRACE_CONDITIONAL_ABORT_F(true, __VA_ARGS__)
#define OMNITRACE_BASIC_ABORT(...) OMNITRACE_CONDITIONAL_BASIC_ABORT(true, __VA_ARGS__)
#define OMNITRACE_BASIC_ABORT_F(...) \
OMNITRACE_CONDITIONAL_BASIC_ABORT_F(true, __VA_ARGS__)
#include <string>
namespace std
{
inline std::string
to_string(bool _v)
{
return (_v) ? "true" : "false";
}
} // namespace std
+61
View File
@@ -0,0 +1,61 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common/defines.h"
#define TIMEMORY_USER_COMPONENT_ENUM \
OMNITRACE_ROCTRACER_idx, OMNITRACE_ROCPROFILER_idx, \
OMNITRACE_SAMPLING_WALL_CLOCK_idx, OMNITRACE_SAMPLING_CPU_CLOCK_idx, \
OMNITRACE_SAMPLING_PERCENT_idx, OMNITRACE_SAMPLING_GPU_POWER_idx, \
OMNITRACE_SAMPLING_GPU_TEMP_idx, OMNITRACE_SAMPLING_GPU_BUSY_idx, \
OMNITRACE_SAMPLING_GPU_MEMORY_USAGE_idx,
#define OMNITRACE_ROCTRACER OMNITRACE_ROCTRACER_idx
#define OMNITRACE_ROCPROFILER OMNITRACE_ROCPROFILER_idx
#define OMNITRACE_SAMPLING_WALL_CLOCK OMNITRACE_SAMPLING_WALL_CLOCK_idx
#define OMNITRACE_SAMPLING_CPU_CLOCK OMNITRACE_SAMPLING_CPU_CLOCK_idx
#define OMNITRACE_SAMPLING_PERCENT OMNITRACE_SAMPLING_PERCENT_idx
#define OMNITRACE_SAMPLING_GPU_POWER OMNITRACE_SAMPLING_GPU_POWER_idx
#define OMNITRACE_SAMPLING_GPU_TEMP OMNITRACE_SAMPLING_GPU_TEMP_idx
#define OMNITRACE_SAMPLING_GPU_BUSY OMNITRACE_SAMPLING_GPU_BUSY_idx
#define OMNITRACE_SAMPLING_GPU_MEMORY_USAGE OMNITRACE_SAMPLING_GPU_MEMORY_USAGE_idx
#define OMNITRACE_METADATA(...) ::tim::manager::add_metadata(__VA_ARGS__)
#if !defined(OMNITRACE_DEFAULT_OBJECT)
# define OMNITRACE_DEFAULT_OBJECT(NAME) \
NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) noexcept = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) noexcept = default;
#endif
#if !defined(OMNITRACE_DEFAULT_COPY_MOVE)
# define OMNITRACE_DEFAULT_COPY_MOVE(NAME) \
NAME(const NAME&) = default; \
NAME(NAME&&) noexcept = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) noexcept = default;
#endif
+152
View File
@@ -0,0 +1,152 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "dynamic_library.hpp"
#include "common.hpp"
#include "debug.hpp"
#include "defines.hpp"
#include <timemory/environment.hpp>
#include <timemory/utility/delimit.hpp>
#include <timemory/utility/filepath.hpp>
#include <timemory/utility/procfs/maps.hpp>
#include <string>
#include <utility>
namespace omnitrace
{
namespace procfs = ::tim::procfs;
std::string
find_library_path(const std::string& _name, const std::vector<std::string>& _env_vars,
const std::vector<std::string>& _hints,
const std::vector<std::string>& _path_suffixes)
{
if(_name.find('/') == 0) return _name;
for(const auto& itr : procfs::get_maps(process::get_id(), true))
{
auto&& _path = itr.pathname;
if(_path.find(_name) != std::string::npos && filepath::exists(_path))
return _path;
}
auto _paths = std::vector<std::string>{};
for(const std::string& itr : _env_vars)
{
auto _env_val = get_env(itr, std::string{});
for(auto vitr : tim::delimit(_env_val, ":"))
if(!vitr.empty()) _paths.emplace_back(vitr);
}
for(const std::string& itr : _hints)
{
if(!itr.empty()) _paths.emplace_back(itr);
}
for(auto& itr : _paths)
{
auto _v = JOIN('/', itr, _name);
if(filepath::exists(_v)) return _v;
for(const auto& litr : _path_suffixes)
{
_v = JOIN('/', itr, litr, _name);
if(filepath::exists(_v)) return _v;
}
}
return _name;
}
dynamic_library::dynamic_library(std::string _env, std::string _fname, int _flags,
bool _open, bool _query_env, bool _store)
: envname{ std::move(_env) }
, filename{ std::move(_fname) }
, flags{ _flags }
{
// check the memory maps
filename = find_library_path(filename, {}, {});
if(_query_env)
{
auto _env_val = get_env(envname, std::string{}, _store);
// if the environment variable is set to an absolute path that exists,
// override with value
if(!_env_val.empty())
{
if(_env_val.find('/') == 0 && filepath::exists(_env_val))
{
filename = _env_val;
}
else if(_env_val.find('/') == 0)
{
OMNITRACE_VERBOSE_F(1,
"Ignoring environment variable %s=\"%s\" because the "
"filepath does not exist. Using \"%s\" instead...\n",
envname.c_str(), _env_val.c_str(), filename.c_str())
}
else if(_env_val.find('/') != 0 && filename.find('/') == 0)
{
OMNITRACE_VERBOSE_F(
1,
"Ignoring environment variable %s=\"%s\" because the "
"filepath is relative. Using absolute path \"%s\" instead...\n",
envname.c_str(), _env_val.c_str(), filename.c_str())
}
}
}
if(_open) open();
}
dynamic_library::~dynamic_library() { close(); }
bool
dynamic_library::open()
{
if(!filename.empty())
{
handle = dlopen(filename.c_str(), flags);
if(!handle)
{
OMNITRACE_VERBOSE(2, "[dynamic_library] Error opening %s=\"%s\" :: %s.\n",
envname.c_str(), filename.c_str(), dlerror());
}
dlerror(); // Clear any existing error
}
return (handle != nullptr);
}
int
dynamic_library::close() const
{
if(handle) return dlclose(handle);
return -1;
}
bool
dynamic_library::is_open() const
{
return (handle != nullptr);
}
} // namespace omnitrace
+86
View File
@@ -0,0 +1,86 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "defines.hpp"
#include <dlfcn.h>
#include <string>
#include <unistd.h>
#include <vector>
namespace omnitrace
{
std::string
find_library_path(const std::string& _name, const std::vector<std::string>& _env_vars,
const std::vector<std::string>& _hints,
const std::vector<std::string>& _path_suffixes = { "lib", "lib64" });
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(std::string _env, std::string _fname,
int _flags = (RTLD_LAZY | RTLD_GLOBAL), bool _open = true,
bool _query_env = true, bool _store = true);
~dynamic_library();
bool open();
int close() const;
bool is_open() const;
template <typename RetT, typename... Args>
RetT invoke(std::string_view, RetT (*&_func)(Args...), Args...);
std::string envname = {};
std::string filename = {};
int flags = 0;
void* handle = nullptr;
};
template <typename RetT, typename... Args>
inline RetT
dynamic_library::invoke(std::string_view _name, RetT (*&_func)(Args...), Args... _args)
{
if(!handle) open();
if(handle)
{
*(void**) (&_func) = dlsym(handle, _name.data());
if(_func)
{
return (*_func)(_args...);
}
else
{
fprintf(stderr, "[omnitrace][pid=%i]> %s :: %s\n", getpid(), _name.data(),
dlerror());
}
}
return RetT{};
}
} // namespace omnitrace
+128
View File
@@ -0,0 +1,128 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "exception.hpp"
#include <any>
#include <cstring>
#include <exception>
#include <functional>
#include <future>
#include <memory>
#include <new>
#include <regex>
#include <stdexcept>
#include <system_error>
#include <timemory/unwind/backtrace.hpp>
#include <timemory/utility/backtrace.hpp>
#include <typeinfo>
#include <variant>
namespace omnitrace
{
namespace
{
template <typename... Args>
void
consume_args(Args&&...)
{}
template <typename... Args>
auto
get_backtrace(Args... _arg)
{
auto _bt = std::stringstream{};
if constexpr(sizeof...(Args) > 0)
{
((_bt << _arg), ...) << "\n";
}
tim::unwind::detailed_backtrace<2>(_bt, true);
return strdup(_bt.str().c_str());
consume_args(_arg...);
}
} // namespace
template <typename Tp>
exception<Tp>::exception(const std::string& _msg)
: Tp{ _msg }
, m_what{ get_backtrace(_msg) }
{}
template <typename Tp>
exception<Tp>::exception(const char* _msg)
: Tp{ _msg }
, m_what{ get_backtrace(_msg) }
{}
template <typename Tp>
exception<Tp>::~exception()
{
free(m_what);
}
template <typename Tp>
exception<Tp>::exception(const exception& _rhs)
: Tp{ _rhs }
, m_what{ strdup(_rhs.m_what) }
{}
template <typename Tp>
exception<Tp>&
exception<Tp>::operator=(const exception& _rhs)
{
if(this != &_rhs)
{
Tp::operator=(_rhs);
m_what = strdup(_rhs.m_what);
}
return *this;
}
template <typename Tp>
const char*
exception<Tp>::what() const noexcept
{
return (m_what) ? m_what : Tp::what();
}
template class exception<std::runtime_error>;
template class exception<std::logic_error>;
template class exception<std::length_error>;
template class exception<std::out_of_range>;
template class exception<std::invalid_argument>;
template class exception<std::domain_error>;
template class exception<std::range_error>;
template class exception<std::overflow_error>;
template class exception<std::underflow_error>;
// template class exception<std::future_error>;
// template class exception<std::regex_error>;
// template class exception<std::system_error>;
// template class exception<std::bad_exception>;
// template class exception<std::bad_function_call>;
// template class exception<std::bad_alloc>;
// template class exception<std::bad_array_new_length>;
// template class exception<std::bad_cast>;
// template class exception<std::bad_typeid>;
// template class exception<std::bad_weak_ptr>;
// template class exception<std::bad_any_cast>;
// template class exception<std::bad_variant_access>;
} // namespace omnitrace
+53
View File
@@ -0,0 +1,53 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <cstring>
#include <stdexcept>
#include <timemory/unwind/backtrace.hpp>
#include <timemory/utility/backtrace.hpp>
#include <type_traits>
namespace omnitrace
{
template <typename Tp>
class exception : public Tp
{
public:
explicit exception(const std::string& _msg);
explicit exception(const char* _msg);
~exception() override;
exception(exception&&) noexcept = default;
exception& operator=(exception&&) noexcept = default;
exception(const exception&);
exception& operator=(const exception&);
const char* what() const noexcept override;
private:
char* m_what = nullptr;
};
} // namespace omnitrace
+299
View File
@@ -0,0 +1,299 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#if !defined(OMNITRACE_USE_ROCM_SMI)
# define OMNITRACE_USE_ROCM_SMI 0
#endif
#if !defined(OMNITRACE_USE_HIP)
# define OMNITRACE_USE_HIP 0
#endif
#if OMNITRACE_USE_HIP > 0
# if !defined(TIMEMORY_USE_HIP)
# define TIMEMORY_USE_HIP 1
# endif
#endif
#include "gpu.hpp"
#include "debug.hpp"
#include "defines.hpp"
#include <timemory/manager.hpp>
#if OMNITRACE_USE_ROCM_SMI > 0
# include <rocm_smi/rocm_smi.h>
#endif
#if OMNITRACE_USE_HIP > 0
# include <hip/hip_runtime.h>
# include <hip/hip_runtime_api.h>
# include <timemory/components/hip/backends.hpp>
# if !defined(OMNITRACE_HIP_RUNTIME_CALL)
# define OMNITRACE_HIP_RUNTIME_CALL(err) \
{ \
if(err != ::tim::hip::success_v && (int) err != 0) \
{ \
OMNITRACE_THROW( \
"[%s:%d] Warning! HIP API call failed with code %i :: %s\n", \
__FILE__, __LINE__, (int) err, hipGetErrorString(err)); \
} \
}
# endif
#endif
namespace omnitrace
{
namespace gpu
{
namespace
{
namespace scope = ::tim::scope;
#if OMNITRACE_USE_ROCM_SMI > 0
# define OMNITRACE_ROCM_SMI_CALL(ERROR_CODE) \
::omnitrace::gpu::check_rsmi_error(ERROR_CODE, __FILE__, __LINE__)
void
check_rsmi_error(rsmi_status_t _code, const char* _file, int _line)
{
if(_code == RSMI_STATUS_SUCCESS) return;
const char* _msg = nullptr;
auto _err = rsmi_status_string(_code, &_msg);
if(_err != RSMI_STATUS_SUCCESS)
OMNITRACE_THROW("rsmi_status_string failed. No error message available. "
"Error code %i originated at %s:%i\n",
static_cast<int>(_code), _file, _line);
OMNITRACE_THROW("[%s:%i] Error code %i :: %s", _file, _line, static_cast<int>(_code),
_msg);
}
bool
rsmi_init()
{
auto _rsmi_init = []() {
try
{
OMNITRACE_ROCM_SMI_CALL(::rsmi_init(0));
} catch(std::exception& _e)
{
OMNITRACE_BASIC_VERBOSE(1, "Exception thrown initializing rocm-smi: %s\n",
_e.what());
return false;
}
return true;
}();
return _rsmi_init;
}
#endif
} // namespace
int
hip_device_count()
{
#if OMNITRACE_USE_HIP > 0
return ::tim::hip::device_count();
#else
return 0;
#endif
}
int
rsmi_device_count()
{
#if OMNITRACE_USE_ROCM_SMI > 0
if(!rsmi_init()) return 0;
static auto _num_devices = []() {
uint32_t _v = 0;
try
{
OMNITRACE_ROCM_SMI_CALL(rsmi_num_monitor_devices(&_v));
} catch(std::exception& _e)
{
OMNITRACE_BASIC_VERBOSE(
1, "Exception thrown getting the rocm-smi devices: %s\n", _e.what());
}
return _v;
}();
return _num_devices;
#else
return 0;
#endif
}
int
device_count()
{
#if OMNITRACE_USE_ROCM_SMI > 0
// store as static since calls after rsmi_shutdown will return zero
return rsmi_device_count();
#elif OMNITRACE_USE_HIP > 0
return ::tim::hip::device_count();
#else
return 0;
#endif
}
template <typename ArchiveT>
void
add_hip_device_metadata(ArchiveT& ar)
{
#if OMNITRACE_USE_HIP > 0
namespace cereal = tim::cereal;
using cereal::make_nvp;
using intvec_t = std::vector<int>;
int _device_count = 0;
int _current_device = 0;
hipError_t _device_count_err = hipGetDeviceCount(&_device_count);
if(_device_count_err != hipSuccess) return;
hipError_t _current_device_err = hipGetDevice(&_current_device);
scope::destructor _dtor{ [_current_device, _current_device_err]() {
if(_current_device_err == hipSuccess)
{
OMNITRACE_HIP_RUNTIME_CALL(hipSetDevice(_current_device));
}
} };
if(_current_device_err != hipSuccess || _device_count == 0) return;
# define OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(NAME) \
ar(make_nvp(#NAME, _device_prop.NAME));
# define OMNITRACE_SERIALIZE_HIP_DEVICE_PROP_ARRAY(NAME, ...) \
ar(make_nvp(NAME, __VA_ARGS__));
ar.setNextName("hip_device_properties");
ar.startNode();
ar.makeArray();
scope::destructor _prop_dtor{ [&ar]() { ar.finishNode(); } };
for(int dev = 0; dev < _device_count; ++dev)
{
auto _device_prop = hipDeviceProp_t{};
int _driver_version = 0;
int _runtime_version = 0;
OMNITRACE_HIP_RUNTIME_CALL(hipSetDevice(dev));
OMNITRACE_HIP_RUNTIME_CALL(hipGetDeviceProperties(&_device_prop, dev));
OMNITRACE_HIP_RUNTIME_CALL(hipDriverGetVersion(&_driver_version));
OMNITRACE_HIP_RUNTIME_CALL(hipRuntimeGetVersion(&_runtime_version));
ar.startNode();
ar(make_nvp("name", std::string{ _device_prop.name }));
ar(make_nvp("driver_version", _driver_version));
ar(make_nvp("runtime_version", _runtime_version));
ar(make_nvp("capability.major_version", _device_prop.major));
ar(make_nvp("capability.minor_version", _device_prop.minor));
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(totalGlobalMem)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(totalConstMem)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(clockRate)
# if OMNITRACE_HIP_VERSION >= 5000
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(memoryClockRate)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(memoryBusWidth)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(l2CacheSize)
# endif
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(sharedMemPerBlock)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(regsPerBlock)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(warpSize)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(multiProcessorCount)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(maxThreadsPerMultiProcessor)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(maxThreadsPerBlock)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP_ARRAY(
"maxThreadsDim",
intvec_t{ _device_prop.maxThreadsDim[0], _device_prop.maxThreadsDim[1],
_device_prop.maxThreadsDim[2] })
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP_ARRAY("maxGridSize",
intvec_t{ _device_prop.maxGridSize[0],
_device_prop.maxGridSize[1],
_device_prop.maxGridSize[2] })
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(memPitch)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(textureAlignment)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(kernelExecTimeoutEnabled)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(integrated)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(canMapHostMemory)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(ECCEnabled)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(cooperativeLaunch)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(cooperativeMultiDeviceLaunch)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(pciDomainID)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(pciBusID)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(pciDeviceID)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(computeMode)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(computeMode)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(gcnArch)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(gcnArchName)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(isMultiGpuBoard)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(clockInstructionRate)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(pageableMemoryAccess)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(pageableMemoryAccessUsesHostPageTables)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(directManagedMemAccessFromHost)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(concurrentManagedAccess)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(concurrentKernels)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(maxSharedMemoryPerMultiProcessor)
OMNITRACE_SERIALIZE_HIP_DEVICE_PROP(asicRevision)
const char* _compute_mode_descr[] = {
"Default (multiple host threads can use ::hipSetDevice() with device "
"simultaneously)",
"Exclusive (only one host thread in one process is able to use "
"::hipSetDevice() with this device)",
"Prohibited (no host thread can use ::hipSetDevice() with this device)",
"Exclusive Process (many threads in one process is able to use "
"::hipSetDevice() with this device)",
"Unknown",
nullptr
};
ar(make_nvp("computeModeDescription",
std::string{ _compute_mode_descr[_device_prop.computeMode] }));
ar.finishNode();
}
#else
(void) ar;
#endif
}
void
add_hip_device_metadata()
{
if(device_count() == 0) return;
OMNITRACE_METADATA([](auto& ar) {
try
{
add_hip_device_metadata(ar);
} catch(std::runtime_error& _e)
{
OMNITRACE_VERBOSE(2, "%s\n", _e.what());
}
});
}
} // namespace gpu
} // namespace omnitrace
+41
View File
@@ -0,0 +1,41 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
namespace omnitrace
{
namespace gpu
{
int
device_count();
int
hip_device_count();
int
rsmi_device_count();
void
add_hip_device_metadata();
} // namespace gpu
} // namespace omnitrace
+102
View File
@@ -0,0 +1,102 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "locking.hpp"
namespace omnitrace
{
namespace locking
{
void
atomic_mutex::lock()
{
while(!try_lock())
{}
}
void
atomic_mutex::unlock()
{
if((m_value.load() & 1) == 1) ++m_value;
}
bool
atomic_mutex::try_lock()
{
auto _targ = m_value.load(std::memory_order_relaxed);
if((_targ & 1) == 0)
{
return (
m_value.compare_exchange_strong(_targ, _targ + 1, std::memory_order_relaxed));
}
return false;
}
atomic_lock::atomic_lock(atomic_mutex& _v)
: m_mutex{ _v }
{
lock();
}
atomic_lock::atomic_lock(atomic_mutex& _v, std::defer_lock_t)
: m_mutex{ _v }
{}
atomic_lock::~atomic_lock() { unlock(); }
bool
atomic_lock::owns_lock() const
{
return m_owns;
}
void
atomic_lock::lock()
{
if(!owns_lock())
{
m_mutex.lock();
m_owns = true;
}
}
void
atomic_lock::unlock()
{
if(owns_lock())
{
m_mutex.unlock();
m_owns = false;
}
}
bool
atomic_lock::try_lock()
{
if(!owns_lock())
{
m_owns = m_mutex.try_lock();
}
return m_owns;
}
} // namespace locking
} // namespace omnitrace
+78
View File
@@ -0,0 +1,78 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <atomic>
#include <mutex>
namespace omnitrace
{
namespace locking
{
/// simple mutex which spins on an atomic while trying to lock.
/// Provided for internal use for when there is low contention
/// but we want to avoid using pthread mutexes since those
/// are wrapped by library
struct atomic_mutex
{
atomic_mutex() = default;
~atomic_mutex() = default;
atomic_mutex(const atomic_mutex&) = delete;
atomic_mutex(atomic_mutex&&) noexcept = delete;
atomic_mutex& operator=(const atomic_mutex&) = delete;
atomic_mutex& operator=(atomic_mutex&&) noexcept = delete;
void lock();
void unlock();
bool try_lock();
private:
std::atomic<int64_t> m_value = {};
};
struct atomic_lock
{
atomic_lock(atomic_mutex&);
atomic_lock(atomic_mutex&, std::defer_lock_t);
~atomic_lock();
atomic_lock(const atomic_lock&) = delete;
atomic_lock(atomic_lock&&) noexcept = delete;
atomic_lock& operator=(const atomic_lock&) = delete;
atomic_lock& operator=(atomic_lock&&) noexcept = delete;
bool owns_lock() const;
void lock();
void unlock();
bool try_lock();
private:
bool m_owns = false;
atomic_mutex& m_mutex;
};
} // namespace locking
} // namespace omnitrace
+74
View File
@@ -0,0 +1,74 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "mproc.hpp"
#include "common.hpp"
#include "debug.hpp"
#include <fstream>
#include <set>
#include <sstream>
#include <string>
#include <unistd.h>
namespace omnitrace
{
namespace mproc
{
std::set<int>
get_concurrent_processes(int _ppid)
{
std::set<int> _children = {};
if(_ppid > 0)
{
auto _inp = JOIN('/', "/proc", _ppid, "task", _ppid, "children");
std::ifstream _ifs{ _inp };
if(!_ifs)
{
OMNITRACE_VERBOSE_F(2, "Warning! File '%s' cannot be read\n", _inp.c_str());
return _children;
}
while(_ifs)
{
int _v = -1;
_ifs >> _v;
if(!_ifs.good() || _ifs.eof()) break;
if(_v < 0) continue;
_children.emplace(_v);
}
}
return _children;
}
int
get_process_index(int _pid, int _ppid)
{
auto _children = get_concurrent_processes(_ppid);
for(auto itr = _children.begin(); itr != _children.end(); ++itr)
{
if(*itr == _pid) return std::distance(_children.begin(), itr);
}
return -1;
}
} // namespace mproc
} // namespace omnitrace
+39
View File
@@ -0,0 +1,39 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <set>
#include <unistd.h>
namespace omnitrace
{
namespace mproc
{
// get the concurrent processes from /proc/<PPID>/task/<PPID>/children
std::set<int>
get_concurrent_processes(int _ppid = getppid());
int
get_process_index(int _pid = getpid(), int _ppid = getppid());
} // namespace mproc
} // namespace omnitrace
+101
View File
@@ -0,0 +1,101 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "perfetto.hpp"
#include "config.hpp"
namespace omnitrace
{
namespace perfetto
{
auto&
get_config()
{
static auto _v = ::perfetto::TraceConfig{};
return _v;
}
auto&
get_session()
{
static auto _v = std::unique_ptr<::perfetto::TracingSession>{};
return _v;
}
void
setup()
{
auto args = ::perfetto::TracingInitArgs{};
auto track_event_cfg = ::perfetto::protos::gen::TrackEventConfig{};
auto& cfg = get_config();
// environment settings
auto shmem_size_hint = config::get_perfetto_shmem_size_hint();
auto buffer_size = config::get_perfetto_buffer_size();
auto _policy =
config::get_perfetto_fill_policy() == "discard"
? ::perfetto::protos::gen::TraceConfig_BufferConfig_FillPolicy_DISCARD
: ::perfetto::protos::gen::TraceConfig_BufferConfig_FillPolicy_RING_BUFFER;
auto* buffer_config = cfg.add_buffers();
buffer_config->set_size_kb(buffer_size);
buffer_config->set_fill_policy(_policy);
for(const auto& itr : config::get_disabled_categories())
{
OMNITRACE_VERBOSE_F(1, "Disabling perfetto track event category: %s\n",
itr.c_str());
track_event_cfg.add_disabled_categories(itr);
}
auto* ds_cfg = cfg.add_data_sources()->mutable_config();
ds_cfg->set_name("track_event"); // this MUST be track_event
ds_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString());
args.shmem_size_hint_kb = shmem_size_hint;
if(get_backend() != "inprocess") args.backends |= ::perfetto::kSystemBackend;
if(get_backend() != "system") args.backends |= ::perfetto::kInProcessBackend;
::perfetto::Tracing::Initialize(args);
::perfetto::TrackEvent::Register();
}
void
start()
{
auto& cfg = get_config();
auto& tracing_session = get_session();
tracing_session = ::perfetto::Tracing::NewTrace();
tracing_session->Setup(cfg);
tracing_session->StartBlocking();
}
} // namespace perfetto
std::unique_ptr<::perfetto::TracingSession>&
get_perfetto_session()
{
return ::omnitrace::perfetto::get_session();
}
} // namespace omnitrace
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
+155
View File
@@ -0,0 +1,155 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "categories.hpp"
#include "common.hpp"
#if defined(TIMEMORY_USE_PERFETTO)
# include <timemory/components/perfetto/backends.hpp>
#else
# include <perfetto.h>
PERFETTO_DEFINE_CATEGORIES(OMNITRACE_PERFETTO_CATEGORIES);
#endif
#include "debug.hpp"
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
namespace omnitrace
{
std::unique_ptr<::perfetto::TracingSession>&
get_perfetto_session();
template <typename Tp>
struct perfetto_counter_track
{
using track_map_t = std::map<uint32_t, std::vector<::perfetto::CounterTrack>>;
using name_map_t = std::map<uint32_t, std::vector<std::unique_ptr<std::string>>>;
using data_t = std::pair<name_map_t, track_map_t>;
static auto init() { (void) get_data(); }
static auto exists(size_t _idx, int64_t _n = -1);
static size_t size(size_t _idx);
static auto emplace(size_t _idx, const std::string& _v, const char* _units = nullptr,
const char* _category = nullptr, int64_t _mult = 1,
bool _incr = false);
static auto& at(size_t _idx, size_t _n) { return get_data().second.at(_idx).at(_n); }
private:
static data_t& get_data()
{
static auto _v = data_t{};
return _v;
}
};
template <typename Tp>
auto
perfetto_counter_track<Tp>::exists(size_t _idx, int64_t _n)
{
bool _v = get_data().second.count(_idx) != 0;
if(_n < 0 || !_v) return _v;
return static_cast<size_t>(_n) < get_data().second.at(_idx).size();
}
template <typename Tp>
size_t
perfetto_counter_track<Tp>::size(size_t _idx)
{
bool _v = get_data().second.count(_idx) != 0;
if(!_v) return 0;
return get_data().second.at(_idx).size();
}
template <typename Tp>
auto
perfetto_counter_track<Tp>::emplace(size_t _idx, const std::string& _v,
const char* _units, const char* _category,
int64_t _mult, bool _incr)
{
auto& _name_data = get_data().first[_idx];
auto& _track_data = get_data().second[_idx];
std::vector<std::tuple<std::string, const char*, bool>> _missing = {};
if(config::get_is_continuous_integration())
{
for(const auto& itr : _name_data)
{
_missing.emplace_back(std::make_tuple(*itr, itr->c_str(), false));
}
}
auto _index = _track_data.size();
auto& _name = _name_data.emplace_back(std::make_unique<std::string>(_v));
const char* _unit_name = (_units && strlen(_units) > 0) ? _units : nullptr;
_track_data.emplace_back(::perfetto::CounterTrack{ _name->c_str() }
.set_unit_name(_unit_name)
.set_category(_category)
.set_unit_multiplier(_mult)
.set_is_incremental(_incr));
if(config::get_is_continuous_integration())
{
for(auto& itr : _missing)
{
const char* citr = std::get<1>(itr);
for(const auto& ditr : _name_data)
{
if(citr == ditr->c_str() && strcmp(citr, ditr->c_str()) == 0)
{
std::get<2>(itr) = true;
break;
}
}
if(!std::get<2>(itr))
{
std::set<void*> _prev = {};
std::set<void*> _curr = {};
for(const auto& eitr : _missing)
_prev.emplace(
static_cast<void*>(const_cast<char*>(std::get<1>(eitr))));
for(const auto& eitr : _name_data)
_curr.emplace(static_cast<void*>(const_cast<char*>(eitr->c_str())));
std::stringstream _pss{};
for(auto&& eitr : _prev)
_pss << " " << std::hex << std::setw(12) << std::left << eitr;
std::stringstream _css{};
for(auto&& eitr : _curr)
_css << " " << std::hex << std::setw(12) << std::left << eitr;
OMNITRACE_THROW("perfetto_counter_track emplace method for '%s' (%p) "
"invalidated C-string '%s' (%p).\n%8s: %s\n%8s: %s\n",
_v.c_str(), (void*) _name->c_str(),
std::get<0>(itr).c_str(),
(void*) std::get<0>(itr).c_str(), "previous",
_pss.str().c_str(), "current", _css.str().c_str());
}
}
}
return _index;
}
} // namespace omnitrace
+102
View File
@@ -0,0 +1,102 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "core/defines.hpp"
#include <array>
#include <iostream>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
namespace omnitrace
{
inline namespace config
{
bool
get_debug() OMNITRACE_HOT;
int
get_verbose() OMNITRACE_HOT;
} // namespace config
struct redirect
{
redirect(std::ostream& _os, std::string _expected)
: m_os{ _os }
, m_expected{ std::move(_expected) }
{
if(!get_debug())
{
// save stream buffer
m_strm_buffer = m_os.rdbuf();
// redirect to stringstream
_os.rdbuf(m_buffer.rdbuf());
}
}
~redirect()
{
if(!m_strm_buffer) return;
// restore stream buffer
m_os.rdbuf(m_strm_buffer);
auto _v = m_buffer.str();
_v = replace<3>(m_buffer.str(), { '\n', '\t', ' ' });
auto _expect = replace<3>(m_expected, { '\n', '\t', ' ' });
if(_v != _expect)
{
if(get_verbose() > 0)
std::cerr << "[omnitrace::redirect] Expected:\n[omnitrace::redirect] "
<< _expect
<< "\n[omnitrace::redirect] Found:\n[omnitrace::redirect] "
<< _v << "\n";
if(get_verbose() <= 0 || (&m_os != &std::cerr && &m_os != &std::cout))
m_os << m_buffer.str() << std::flush;
}
}
private:
template <size_t N>
static std::string replace(std::string _v, const std::array<char, N>& _c,
const std::string& _s = "")
{
for(const auto& itr : _c)
{
while(true)
{
auto _pos = _v.find(itr);
if(_pos == std::string::npos) break;
_v = _v.replace(_pos, 1, _s);
}
}
return _v;
}
std::ostream& m_os;
std::string m_expected = {};
std::stringstream m_buffer{};
std::streambuf* m_strm_buffer = nullptr;
};
} // namespace omnitrace
+172
View File
@@ -0,0 +1,172 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "state.hpp"
#include "config.hpp"
#include "debug.hpp"
#include "utility.hpp"
#include <string>
namespace omnitrace
{
namespace
{
auto&
get_state_value()
{
static State _v{ State::PreInit };
return _v;
}
ThreadState&
get_thread_state_value()
{
static thread_local ThreadState _v{ ThreadState::Enabled };
return _v;
}
auto&
get_thread_state_history(int64_t _idx = utility::get_thread_index())
{
static auto _v = utility::get_filled_array<OMNITRACE_MAX_THREADS>(
[]() { return utility::get_reserved_vector<ThreadState>(32); });
if(_idx >= OMNITRACE_MAX_THREADS)
{
static thread_local auto _tl_v = utility::get_reserved_vector<ThreadState>(32);
return _tl_v;
}
return _v.at(_idx);
}
} // namespace
State
get_state()
{
return get_state_value();
}
ThreadState
get_thread_state()
{
return get_thread_state_value();
}
State
set_state(State _n)
{
OMNITRACE_CONDITIONAL_PRINT_F(get_debug_init(), "Setting state :: %s -> %s\n",
std::to_string(get_state()).c_str(),
std::to_string(_n).c_str());
// state should always be increased, not decreased
OMNITRACE_CI_BASIC_THROW(
_n < get_state(), "State is being assigned to a lesser value :: %s -> %s",
std::to_string(get_state()).c_str(), std::to_string(_n).c_str());
std::swap(get_state_value(), _n);
return _n;
}
ThreadState
set_thread_state(ThreadState _n)
{
std::swap(get_thread_state_value(), _n);
return _n;
}
ThreadState
push_thread_state(ThreadState _v)
{
if(get_thread_state() >= ThreadState::Completed) return get_thread_state();
return get_thread_state_history().emplace_back(set_thread_state(_v));
}
ThreadState
pop_thread_state()
{
if(get_thread_state() >= ThreadState::Completed) return get_thread_state();
auto& _hist = get_thread_state_history();
if(!_hist.empty())
{
set_thread_state(_hist.back());
_hist.pop_back();
}
return get_thread_state();
}
} // namespace omnitrace
namespace std
{
std::string
to_string(omnitrace::State _v)
{
switch(_v)
{
case omnitrace::State::PreInit: return "PreInit";
case omnitrace::State::Init: return "Init";
case omnitrace::State::Active: return "Active";
case omnitrace::State::Disabled: return "Disabled";
case omnitrace::State::Finalized: return "Finalized";
}
return {};
}
std::string
to_string(omnitrace::ThreadState _v)
{
switch(_v)
{
case omnitrace::ThreadState::Enabled: return "Enabled";
case omnitrace::ThreadState::Internal: return "Internal";
case omnitrace::ThreadState::Completed: return "Completed";
case omnitrace::ThreadState::Disabled: return "Disabled";
}
return {};
}
std::string
to_string(omnitrace::Mode _v)
{
switch(_v)
{
case omnitrace::Mode::Trace: return "Trace";
case omnitrace::Mode::Sampling: return "Sampling";
case omnitrace::Mode::Causal: return "Causal";
case omnitrace::Mode::Coverage: return "Coverage";
}
return {};
}
std::string
to_string(omnitrace::CausalMode _v)
{
switch(_v)
{
case omnitrace::CausalMode::Line: return "Line";
case omnitrace::CausalMode::Function: return "Function";
}
return {};
}
} // namespace std
+114
View File
@@ -0,0 +1,114 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common/defines.h"
#include "defines.hpp"
#include <cstdint>
#include <string>
namespace omnitrace
{
// used for specifying the state of omnitrace
enum class State : unsigned short
{
PreInit = 0,
Init,
Active,
Finalized,
Disabled,
};
// used for specifying the state of omnitrace
enum class ThreadState : unsigned short
{
Enabled = 0,
Internal,
Completed,
Disabled,
};
enum class Mode : unsigned short
{
Trace = 0,
Sampling,
Causal,
Coverage
};
enum class CausalMode : unsigned short
{
Line = 0,
Function
};
//
// Runtime configuration data
//
State
get_state() OMNITRACE_HOT;
ThreadState
get_thread_state() OMNITRACE_HOT;
/// returns old state
State set_state(State) OMNITRACE_COLD; // does not change often
/// returns old state
ThreadState set_thread_state(ThreadState) OMNITRACE_HOT; // changes often
/// return current state (state change may be ignored)
ThreadState push_thread_state(ThreadState) OMNITRACE_HOT;
/// return current state (state change may be ignored)
ThreadState
pop_thread_state() OMNITRACE_HOT;
struct scoped_thread_state
{
OMNITRACE_INLINE scoped_thread_state(ThreadState _v) { push_thread_state(_v); }
OMNITRACE_INLINE ~scoped_thread_state() { pop_thread_state(); }
};
} // namespace omnitrace
#define OMNITRACE_SCOPED_THREAD_STATE(STATE) \
::omnitrace::scoped_thread_state OMNITRACE_VARIABLE(_scoped_thread_state_, __LINE__) \
{ \
::omnitrace::STATE \
}
namespace std
{
std::string
to_string(omnitrace::State _v);
std::string
to_string(omnitrace::ThreadState _v);
std::string
to_string(omnitrace::Mode _v);
std::string
to_string(omnitrace::CausalMode _v);
} // namespace std
+27
View File
@@ -0,0 +1,27 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "timemory.hpp"
using namespace omnitrace;
TIMEMORY_INITIALIZE_STORAGE(comp::wall_clock, comp::user_global_bundle)
+59
View File
@@ -0,0 +1,59 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "common.hpp"
#include "components/fwd.hpp"
#include "defines.hpp"
#include <timemory/api.hpp>
#include <timemory/backends/mpi.hpp>
#include <timemory/backends/process.hpp>
#include <timemory/backends/threading.hpp>
#include <timemory/components.hpp>
#include <timemory/components/gotcha/mpip.hpp>
#include <timemory/config.hpp>
#include <timemory/environment.hpp>
#include <timemory/manager.hpp>
#include <timemory/mpl.hpp>
#include <timemory/operations.hpp>
#include <timemory/runtime.hpp>
#include <timemory/settings.hpp>
#include <timemory/storage.hpp>
#include <timemory/utility/signals.hpp>
#include <timemory/variadic.hpp>
namespace omnitrace
{
namespace audit = ::tim::audit; // NOLINT
namespace comp = ::tim::component; // NOLINT
namespace dmp = ::tim::dmp; // NOLINT
namespace operation = ::tim::operation; // NOLINT
namespace quirk = ::tim::quirk; // NOLINT
namespace units = ::tim::units; // NOLINT
using settings = ::tim::settings; // NOLINT
using ::tim::get_env; // NOLINT
using ::tim::set_env; // NOLINT
} // namespace omnitrace
+242
View File
@@ -0,0 +1,242 @@
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include "concepts.hpp"
#include <timemory/mpl/concepts.hpp>
#include <timemory/utility/join.hpp>
#include <algorithm>
#include <array>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <sstream>
#include <stdexcept>
#include <vector>
namespace omnitrace
{
namespace utility
{
/// provides an alternative thread index for when using threading::get_id() is not
/// desirable
inline auto
get_thread_index()
{
static std::atomic<int64_t> _c{ 0 };
static thread_local int64_t _v = _c++;
return _v;
}
/// fills any array with the result of the functor
template <size_t N, typename FuncT>
inline auto
get_filled_array(FuncT&& _func)
{
using Tp = std::decay_t<decltype(_func())>;
std::array<Tp, N> _v{};
for(auto& itr : _v)
itr = std::move(_func());
return _v;
}
/// returns a vector with a preallocated buffer
template <typename... Tp>
inline auto
get_reserved_vector(size_t _n)
{
std::vector<Tp...> _v{};
_v.reserve(_n);
return _v;
}
template <typename Tp, size_t Offset>
struct offset_index_sequence;
template <size_t Idx, size_t Offset>
struct offset_index_value
{
static constexpr size_t value = Idx + Offset;
};
template <size_t Offset, size_t... Idx>
struct offset_index_sequence<std::index_sequence<Idx...>, Offset>
{
using type = std::integer_sequence<size_t, offset_index_value<Idx, Offset>::value...>;
};
template <size_t N, size_t OffsetN>
using make_offset_index_sequence =
offset_index_sequence<std::make_index_sequence<N>, OffsetN>;
template <size_t StartN, size_t EndN>
using make_index_sequence_range =
typename offset_index_sequence<std::make_index_sequence<(EndN - StartN)>,
StartN>::type;
template <typename Tp>
struct generate
{
using type = Tp;
template <typename... Args>
auto operator()(Args&&... _args) const
{
if constexpr(concepts::is_unique_pointer<Tp>::value)
{
using value_type = typename type::element_type;
if constexpr(use_placement_new_when_generating_unique_ptr<value_type>::value)
{
// create a thread-local buffer for placement-new
static thread_local auto _buffer = std::array<char, sizeof(value_type)>{};
if constexpr(std::is_constructible<value_type, Args...>::value)
{
return type{ new(_buffer.data())
value_type{ std::forward<Args>(_args)... } };
}
else
{
return type{ new(_buffer.data())
value_type{ invoke(std::forward<Args>(_args))... } };
}
}
else
{
if constexpr(std::is_constructible<value_type, Args...>::value)
{
return type{ new value_type{ std::forward<Args>(_args)... } };
}
else
{
return type{ new value_type{ invoke(std::forward<Args>(_args))... } };
}
}
}
else
{
if constexpr(std::is_constructible<type, Args...>::value)
{
return type{ std::forward<Args>(_args)... };
}
else
{
return type{ invoke(std::forward<Args>(_args))... };
}
}
}
private:
template <typename Up>
static auto invoke(Up&& _v, int,
std::enable_if_t<std::is_invocable<Up>::value, int> = 0)
-> decltype(std::forward<Up>(_v)())
{
return std::forward<Up>(_v)();
}
template <typename Up>
static auto&& invoke(Up&& _v, long)
{
return std::forward<Up>(_v);
}
template <typename Up>
static decltype(auto) invoke(Up&& _v)
{
return invoke(std::forward<Up>(_v), 0);
}
};
template <template <typename, typename...> class ContainerT, typename DataT,
typename... TailT, typename PredicateT = bool (*)(const DataT&)>
inline ContainerT<DataT, TailT...>&
filter_sort_unique(
ContainerT<DataT, TailT...>& _v,
PredicateT&& _predicate = [](const auto& itr) { return !itr; })
{
_v.erase(std::remove_if(_v.begin(), _v.end(), std::forward<PredicateT>(_predicate)),
_v.end());
std::sort(_v.begin(), _v.end());
auto _last = std::unique(_v.begin(), _v.end());
if(std::distance(_v.begin(), _last) > 0) _v.erase(_last, _v.end());
return _v;
}
template <typename LhsT, typename RhsT>
inline LhsT&
combine(LhsT& _lhs, RhsT&& _rhs)
{
for(auto&& itr : _rhs)
_lhs.emplace_back(itr);
return _lhs;
}
template <template <typename, typename...> class ContainerT, typename Tp,
typename... TailT>
std::string
get_regex_or(const ContainerT<Tp, TailT...>& _container, const std::string& _fallback)
{
static_assert(tim::concepts::is_string_type<Tp>::value,
"get_regex_or requires a container of string types");
if(_container.empty()) return _fallback;
namespace join = timemory::join;
return join::join(join::array_config{ "|", "(", ")" }, _container);
}
template <template <typename, typename...> class ContainerT, typename Tp,
typename... TailT, typename PredicateT>
std::string
get_regex_or(const ContainerT<Tp, TailT...>& _container, PredicateT&& _predicate,
const std::string& _fallback)
{
static_assert(tim::concepts::is_string_type<Tp>::value,
"get_regex_or requires a container of string types");
if(_container.empty()) return _fallback;
auto _dest = std::vector<std::string>{};
_dest.reserve(_container.size());
for(const auto& itr : _container)
_dest.emplace_back(_predicate(itr));
return get_regex_or(_dest, _fallback);
}
template <typename Tp>
Tp
convert(std::string_view _inp)
{
auto _iss = std::stringstream{};
auto _ret = Tp{};
_iss << _inp;
_iss >> _ret;
return _ret;
}
} // namespace utility
} // namespace omnitrace