ROCpd support [Part 1] (#279)

- Add rocpd support for
 - cpu_frequency
 - amd_smi
 - sampling
This commit is contained in:
Aleksandar Djordjevic
2025-07-28 17:33:52 +02:00
committed by GitHub
parent 4b4a846b58
commit 26ae543012
49 changed files with 6770 additions and 365 deletions
+26 -2
View File
@@ -6,31 +6,38 @@ configure_file(
)
set(core_sources
${CMAKE_CURRENT_LIST_DIR}/agent_manager.cpp
${CMAKE_CURRENT_LIST_DIR}/amd_smi.cpp
${CMAKE_CURRENT_LIST_DIR}/argparse.cpp
${CMAKE_CURRENT_LIST_DIR}/categories.cpp
${CMAKE_CURRENT_LIST_DIR}/config.cpp
${CMAKE_CURRENT_LIST_DIR}/constraint.cpp
${CMAKE_CURRENT_LIST_DIR}/cpu.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}/mproc.cpp
${CMAKE_CURRENT_LIST_DIR}/node_info.cpp
${CMAKE_CURRENT_LIST_DIR}/perf.cpp
${CMAKE_CURRENT_LIST_DIR}/perfetto.cpp
${CMAKE_CURRENT_LIST_DIR}/rocprofiler-sdk.cpp
${CMAKE_CURRENT_LIST_DIR}/amd_smi.cpp
${CMAKE_CURRENT_LIST_DIR}/state.cpp
${CMAKE_CURRENT_LIST_DIR}/timemory.cpp
${CMAKE_CURRENT_LIST_DIR}/utility.cpp
)
set(core_headers
${CMAKE_CURRENT_LIST_DIR}/agent.hpp
${CMAKE_CURRENT_LIST_DIR}/agent_manager.hpp
${CMAKE_CURRENT_LIST_DIR}/amd_smi.hpp
${CMAKE_CURRENT_LIST_DIR}/argparse.hpp
${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}/cpu.hpp
${CMAKE_CURRENT_LIST_DIR}/debug.hpp
${CMAKE_CURRENT_LIST_DIR}/dynamic_library.hpp
${CMAKE_CURRENT_LIST_DIR}/exception.hpp
@@ -38,11 +45,11 @@ set(core_headers
${CMAKE_CURRENT_LIST_DIR}/locking.hpp
${CMAKE_CURRENT_LIST_DIR}/mpi.hpp
${CMAKE_CURRENT_LIST_DIR}/mproc.hpp
${CMAKE_CURRENT_LIST_DIR}/node_info.hpp
${CMAKE_CURRENT_LIST_DIR}/perf.hpp
${CMAKE_CURRENT_LIST_DIR}/perfetto.hpp
${CMAKE_CURRENT_LIST_DIR}/redirect.hpp
${CMAKE_CURRENT_LIST_DIR}/rocprofiler-sdk.hpp
${CMAKE_CURRENT_LIST_DIR}/amd_smi.hpp
${CMAKE_CURRENT_LIST_DIR}/state.hpp
${CMAKE_CURRENT_LIST_DIR}/timemory.hpp
${CMAKE_CURRENT_LIST_DIR}/utility.hpp
@@ -61,6 +68,7 @@ target_sources(
add_subdirectory(binary)
add_subdirectory(components)
add_subdirectory(containers)
add_subdirectory(rocpd)
target_include_directories(
rocprofiler-systems-core-library
@@ -95,6 +103,22 @@ target_link_libraries(
$<BUILD_INTERFACE:$<IF:$<BOOL:${ROCPROFSYS_BUILD_LTO}>,rocprofiler-systems::rocprofiler-systems-lto,>>
)
file(GLOB ROCPD_SCHEMA_FILES "${CMAKE_CURRENT_LIST_DIR}/rocpd/data_storage/schema/*.sql")
foreach(_SRC ${ROCPD_SCHEMA_FILES})
cmake_path(GET _SRC FILENAME _BASE)
configure_file(
${_SRC}
${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/${_BASE}
COPYONLY
)
install(
FILES ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/${_BASE}
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}
COMPONENT core
)
endforeach()
set_target_properties(
rocprofiler-systems-core-library
PROPERTIES OUTPUT_NAME ${BINARY_NAME_PREFIX}-core
+62
View File
@@ -0,0 +1,62 @@
// MIT License
//
// Copyright (c) 2025 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 <cstddef>
#include <cstdint>
#include <string>
#if ROCPROFSYS_USE_ROCM > 0
# include <amd_smi/amdsmi.h>
# include <rocprofiler-sdk/agent.h>
#endif
namespace rocprofsys
{
enum class agent_type : uint8_t
{
CPU, ///< Agent type is a CPU
GPU ///< Agent type is a GPU
};
struct agent
{
agent_type type;
uint64_t id;
uint32_t node_id;
int32_t logical_node_id;
int32_t logical_node_type_id;
std::string name;
std::string model_name;
std::string vendor_name;
std::string product_name;
size_t device_id{ 0 };
size_t base_id{ 0 };
#if ROCPROFSYS_USE_ROCM > 0
amdsmi_processor_handle smi_handle = nullptr;
#endif
};
} // namespace rocprofsys
+137
View File
@@ -0,0 +1,137 @@
// MIT License
//
// Copyright (c) 2025 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 "agent_manager.hpp"
#include "debug.hpp"
#include <algorithm>
#include <iterator>
namespace rocprofsys
{
agent_manager&
agent_manager::get_instance()
{
static agent_manager instance;
return instance;
}
void
agent_manager::insert_agent(agent& _agent)
{
ROCPROFSYS_VERBOSE(
3, "Inserting agent with device handle: %lu, and agent id: %ld, device type: %s",
_agent.device_id,
(_agent.type == agent_type::GPU ? _gpu_agents_cnt : _cpu_agents_cnt),
(_agent.type == agent_type::GPU ? "GPU" : "CPU"));
_agent.device_id =
(_agent.type == agent_type::GPU ? _gpu_agents_cnt++ : _cpu_agents_cnt++);
_agents.emplace_back(std::make_shared<agent>(_agent));
}
const agent&
agent_manager::get_agent_by_id(size_t device_id, agent_type type) const
{
ROCPROFSYS_VERBOSE(3, "Getting agent for device id: %ld, type %s\n", device_id,
(type == agent_type::GPU) ? "GPU" : "CPU");
auto _agent =
std::find_if(_agents.begin(), _agents.end(), [&](const auto& agent_ptr) {
return agent_ptr->type == type && agent_ptr->device_id == device_id;
});
if(_agent == _agents.end())
{
std::ostringstream oss;
oss << "Agent not found for device id: " << device_id
<< ", type: " << (type == agent_type::GPU ? "GPU" : "CPU");
throw std::out_of_range(oss.str());
}
return **_agent;
}
const agent&
agent_manager::get_agent_by_handle(uint64_t device_handle, agent_type type) const
{
ROCPROFSYS_VERBOSE(3, "Getting agent for device handle: %ld, type %s\n",
device_handle, (type == agent_type::GPU ? "GPU" : "CPU"));
auto _agent =
std::find_if(_agents.begin(), _agents.end(), [&](const auto& agent_ptr) {
return agent_ptr->type == type && agent_ptr->id == device_handle;
});
if(_agent == _agents.end())
{
std::ostringstream oss;
oss << "Agent not found for device handle: " << device_handle
<< ", type: " << (type == agent_type::GPU ? "GPU" : "CPU");
throw std::out_of_range(oss.str());
}
return **_agent;
}
const agent&
agent_manager::get_agent_by_handle(size_t device_handle) const
{
ROCPROFSYS_VERBOSE(3, "Getting agent for device handle: %ld\n", device_handle);
auto _agent =
std::find_if(_agents.begin(), _agents.end(), [&](const auto& agent_ptr) {
return agent_ptr->id == device_handle;
});
if(_agent == _agents.end())
{
std::ostringstream oss;
oss << "Agent not found for device handle: " << device_handle;
throw std::out_of_range(oss.str());
}
return **_agent;
}
std::vector<std::shared_ptr<agent>>
agent_manager::get_agents_by_type(agent_type type) const
{
ROCPROFSYS_VERBOSE(3, "Getting agent for device type: %s\n",
type == agent_type::GPU ? "GPU" : "CPU");
std::vector<std::shared_ptr<agent>> agents;
std::copy_if(std::begin(_agents), std::end(_agents), std::back_inserter(agents),
[&type](const auto& agent_ptr) { return agent_ptr->type == type; });
return agents;
}
std::vector<std::shared_ptr<agent>>
agent_manager::get_agents() const
{
return _agents;
}
size_t
agent_manager::get_gpu_agents_count() const
{
return _gpu_agents_cnt;
}
size_t
agent_manager::get_cpu_agents_count() const
{
return _cpu_agents_cnt;
}
} // namespace rocprofsys
+62
View File
@@ -0,0 +1,62 @@
// MIT License
//
// Copyright (c) 2025 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 <cstddef>
#include <memory>
#include <vector>
#include "agent.hpp"
namespace rocprofsys
{
struct agent_manager
{
static agent_manager& get_instance();
agent_manager(const agent_manager&) = delete;
agent_manager& operator=(const agent_manager&) = delete;
agent_manager(agent_manager&&) = delete;
agent_manager& operator=(agent_manager&&) = delete;
~agent_manager() = default;
void insert_agent(agent& agent);
const agent& get_agent_by_id(size_t device_id, agent_type type) const;
const agent& get_agent_by_handle(size_t device_id, agent_type type) const;
const agent& get_agent_by_handle(size_t device_handle) const;
std::vector<std::shared_ptr<agent>> get_agents_by_type(agent_type type) const;
std::vector<std::shared_ptr<agent>> get_agents() const;
size_t get_gpu_agents_count() const;
size_t get_cpu_agents_count() const;
private:
std::vector<std::shared_ptr<agent>> _agents;
size_t _gpu_agents_cnt{ 0 };
size_t _cpu_agents_cnt{ 0 };
agent_manager() = default;
};
} // namespace rocprofsys
+353
View File
@@ -0,0 +1,353 @@
// MIT License
//
// Copyright (c) 2022-2025 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 <algorithm>
#include <array>
#include <bitset>
#include <chrono>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <limits>
#include <mutex>
#include <sstream>
#include <string>
#include <type_traits>
#include <unistd.h>
#include <unordered_map>
#include <vector>
#include "core/benchmark/category.hpp"
#include "core/debug.hpp"
namespace rocprofsys
{
namespace benchmark
{
namespace
{
template <bool enabled, typename category_enum, category_enum... enabled_categories>
struct benchmark_impl
{
template <category_enum... categories>
struct scope
{
scope(const scope&) = delete;
scope& operator=(const scope&) = delete;
~scope() = default;
protected:
scope() = default;
scope(scope&&) = default;
scope& operator=(scope&&) = default;
};
template <category_enum... categories>
static void start()
{}
template <category_enum... categories>
static void end()
{}
template <category_enum... categories>
[[nodiscard]] static scope<categories...> scoped_trace()
{
return scope<categories...>{};
}
static void init_from_env(const char* = nullptr) {}
static void show_results() {}
};
using tid_t = __pid_t;
struct indexed_category
{
size_t category;
tid_t thread_id;
friend bool operator==(const indexed_category& lhs, const indexed_category& rhs)
{
return lhs.category == rhs.category && lhs.thread_id == rhs.thread_id;
}
};
struct indexed_category_hash
{
size_t operator()(const indexed_category& p) const noexcept
{
std::size_t hash1 = std::hash<size_t>{}(p.category);
std::size_t hash2 = std::hash<size_t>{}(p.thread_id);
return hash1 ^ (hash2 << 1);
}
};
template <typename category_enum, category_enum... enabled_categories>
struct benchmark_impl<true, category_enum, enabled_categories...>
{
static_assert(std::is_enum_v<category_enum>, "category_enum must be an enum");
public:
using clock = std::chrono::high_resolution_clock;
using time_point = clock::time_point;
static constexpr size_t _max_categories = static_cast<size_t>(category_enum::count);
template <category_enum... categories>
struct scope
{
friend benchmark_impl;
public:
scope(const scope&) = delete;
scope& operator=(const scope&) = delete;
~scope() { end<categories...>(); }
protected:
scope() { start<categories...>(); }
scope(scope&&) = default;
scope& operator=(scope&&) = default;
};
template <category_enum... categories>
static void start()
{
static const thread_local auto _thread_id = gettid();
const auto now = clock::now();
std::lock_guard lock(m_mutex);
(..., (is_category_defined<categories>([&] {
if(m_enabled.test(to_index(categories)))
m_started[{ to_index(categories), _thread_id }] = now;
})));
}
template <category_enum... categories>
static void end()
{
static const thread_local auto _thread_id = getpid();
const auto _end_time = clock::now();
std::lock_guard lock(m_mutex);
(..., (is_category_defined<categories>([&] {
if(m_enabled.test(to_index(categories)))
end_category(_end_time, categories, _thread_id);
})));
}
template <category_enum... categories>
[[nodiscard]] static scope<categories...> scoped_trace()
{
return scope<categories...>{};
}
static void init_from_env(const char* envVar = "ROCPROFSYS_BENCHMARK_CATEGORIES")
{
std::lock_guard lock(m_mutex);
const auto* env = std::getenv(envVar);
if(env == nullptr || std::string(env).empty())
{
ROCPROFSYS_WARNING(1, "No BENCHMARK categories specified in environment "
"variable ROCPROFSYS_BENCHMARK_CATEGORIES.\n");
return;
}
std::string _str(env);
std::istringstream ss(_str);
std::string token;
while(std::getline(ss, token, ','))
{
token.erase(0, token.find_first_not_of(" \t"));
token.erase(token.find_last_not_of(" \t") + 1);
for(category_enum cat : compiledCategories)
{
if(to_string(cat) == token)
{
m_enabled.set(to_index(cat));
}
}
}
}
static void show_results()
{
std::lock_guard lock(m_mutex);
std::vector<std::pair<category_enum, result_data>> sorted;
for(category_enum cat : compiledCategories)
{
const auto& data = m_results[to_index(cat)];
if(data.count > 0)
{
sorted.emplace_back(cat, data);
}
}
std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b) {
return a.second.total_time > b.second.total_time;
});
constexpr uint32_t _category = 30;
constexpr uint32_t _calls = 8;
constexpr uint32_t _total = 12;
constexpr uint32_t _avg = 10;
constexpr uint32_t _min = 10;
constexpr uint32_t _max = 10;
std::cout << "\033[32m"
<< std::string(_category + _calls + _total + _avg + _min + _max, '=')
<< "\n";
std::cout << "Benchmark Results (Sorted by Total Time):\n";
std::cout << std::string(_category + _calls + _total + _avg + _min + _max, '-')
<< "\n";
std::cout << std::left << std::setw(_category) << "Category" << std::right
<< std::setw(_calls) << "Calls" << std::setw(_total) << "Total(ms)"
<< std::setw(_avg) << "Avg(us)" << std::setw(_min) << "Min(us)"
<< std::setw(_max) << "Max(us)" << "\n";
std::cout << std::string(_category + _calls + _total + _avg + _min + _max, '-')
<< "\n";
for(const auto& [cat, data] : sorted)
{
double totalMs = static_cast<double>(data.total_time) / 1000.0;
double avgUs = static_cast<double>(data.total_time) / data.count;
std::cout << std::left << std::setw(_category) << to_string(cat) << std::right
<< std::setw(_calls) << data.count << std::setw(_total)
<< std::fixed << std::setprecision(3) << totalMs << std::setw(_avg)
<< std::fixed << std::setprecision(1) << avgUs << std::setw(_min)
<< data.min_time << std::setw(_max) << data.max_time << "\n";
}
std::cout << std::string(_category + _calls + _total + _avg + _min + _max, '=')
<< "\033[0m" << "\n\n";
}
private:
struct result_data
{
uint64_t total_time = 0;
size_t count = 0;
uint64_t min_time = std::numeric_limits<uint64_t>::max();
uint64_t max_time = std::numeric_limits<uint64_t>::min();
void update(uint64_t duration)
{
total_time += duration;
count += 1;
if(duration < min_time) min_time = duration;
if(duration > max_time) max_time = duration;
}
};
static constexpr size_t to_index(category_enum cat)
{
return static_cast<size_t>(cat);
}
static void end_category(const time_point& end_time, category_enum cat,
const tid_t thread_id)
{
const size_t _idx = to_index(cat);
auto _it = m_started.find({ _idx, thread_id });
if(_it == m_started.end())
{
ROCPROFSYS_WARNING(1, "Benchmark error: missing start time for category!\n");
return;
}
auto duration =
std::chrono::duration_cast<std::chrono::microseconds>(end_time - _it->second)
.count();
m_started.erase(_it);
m_results[_idx].update(duration);
}
template <category_enum Cat, typename Func>
static constexpr void is_category_defined(Func&& f)
{
if constexpr(((Cat == enabled_categories) || ...))
{
f();
}
}
static constexpr std::array<category_enum, sizeof...(enabled_categories)>
compiledCategories = { enabled_categories... };
static inline std::unordered_map<indexed_category, time_point, indexed_category_hash>
m_started;
static inline std::array<result_data, _max_categories> m_results{};
static inline std::bitset<_max_categories> m_enabled;
static inline std::mutex m_mutex;
};
#ifdef ROCPROFSYS_ENABLE_BENCHMARK
using _benchmark_impl = benchmark::benchmark_impl<
static_cast<bool>(ROCPROFSYS_ENABLE_BENCHMARK), benchmark::category,
benchmark::category::kernel_dispatch, benchmark::category::memory_copy,
benchmark::category::memory_allocate, benchmark::category::db_entry_kernel_dispatch,
benchmark::category::db_entry_memory_copy,
benchmark::category::db_entry_memory_allocate,
benchmark::category::perfetto_kernel_dispatch,
benchmark::category::sdk_tool_buffered_tracing>;
#else
using _benchmark_impl = benchmark::benchmark_impl<false, benchmark::category>;
#endif
} // namespace
template <category... categories>
void
start()
{
_benchmark_impl::template start<categories...>();
}
template <category... categories>
void
end()
{
_benchmark_impl::template end<categories...>();
}
template <category... categories>
[[nodiscard]] auto
scoped_trace()
{
return _benchmark_impl::template scoped_trace<categories...>();
}
inline void
init_from_env(const char* envVar = "BENCHMARK_CATEGORIES")
{
_benchmark_impl::init_from_env(envVar);
}
inline void
show_results()
{
_benchmark_impl::show_results();
}
} // namespace benchmark
} // namespace rocprofsys
+68
View File
@@ -0,0 +1,68 @@
// Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include <string_view>
namespace rocprofsys
{
namespace benchmark
{
enum class category
{
kernel_dispatch,
db_entry_kernel_dispatch,
memory_copy,
db_entry_memory_copy,
memory_allocate,
db_entry_memory_allocate,
perfetto_kernel_dispatch,
sdk_tool_buffered_tracing,
count
};
constexpr std::string_view
to_string(category cat)
{
switch(cat)
{
case category::kernel_dispatch: return "kernel_dispatch";
case category::db_entry_kernel_dispatch: return "db_entry_kernel_dispatch";
case category::memory_copy: return "memory_copy";
case category::memory_allocate: return "memory_allocate";
case category::db_entry_memory_copy: return "db_entry_memory_copy";
case category::db_entry_memory_allocate: return "db_entry_memory_allocate";
case category::perfetto_kernel_dispatch: return "perfetto_kernel_dispatch";
case category::sdk_tool_buffered_tracing: return "sdk_tool_buffered_tracing";
default: return "unknown";
}
}
} // namespace benchmark
} // namespace rocprofsys
+44
View File
@@ -312,6 +312,9 @@ configure_settings(bool _init)
"Enable causal profiling analysis", false, "backend",
"causal", "analysis");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_ROCPD", "Enable rocpd backend", false,
"backend", "rocpd");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_ROCM",
"Enable ROCm API and kernel tracing", true, "backend",
"rocm");
@@ -1246,10 +1249,17 @@ configure_signal_handler(const std::shared_ptr<settings>& _config)
static auto _dyninst_trampoline_signal =
getenv("DYNINST_SIGNAL_TRAMPOLINE_SIGILL") ? SIGILL : SIGTRAP;
static auto root_pid =
get_env<pid_t>("ROCPROFSYS_ROOT_PROCESS", process::get_id(), false);
if(_config->get_enable_signal_handler())
{
tim::signals::disable_signal_detection();
signal_settings::enable(sys_signal::Interrupt);
auto is_child_process = root_pid != getpid();
if(is_child_process)
{
signal_settings::enable(sys_signal::Terminate);
}
signal_settings::set_exit_action(rocprofsys_exit_action);
signal_settings::check_environment();
auto default_signals = signal_settings::get_default();
@@ -2347,6 +2357,40 @@ get_tmpdir()
return static_cast<tim::tsettings<std::string>&>(*_v->second).get();
}
std::string
get_database_absolute_path(std::string_view database_name)
{
const auto* _existing_path = std::getenv("ROCPROFSYS_DATABASE_DIR");
auto _dir = _existing_path ? std::string{ _existing_path } : std::string{};
auto _ext = std::string{ "db" };
auto _cfg = settings::compose_filename_config{ settings::use_output_suffix(),
settings::default_process_suffix(),
false, _dir };
const auto get_path = [](const std::string& path) {
size_t last_slash = path.find_last_of("/\\");
return (last_slash != std::string::npos) ? path.substr(0, last_slash + 1)
: std::string{};
};
auto _val = settings::compose_output_filename(std::string(database_name), _ext, _cfg);
_dir = get_path(_val);
setenv("ROCPROFSYS_DATABASE_DIR", _dir.c_str(), 1);
if(!_val.empty() && _val.at(0) != '/')
return settings::format(JOIN('/', "%env{PWD}%", _val), get_config()->get_tag());
return _val;
}
bool&
get_use_rocpd()
{
static auto _v = get_config()->at("ROCPROFSYS_USE_ROCPD");
return static_cast<tim::tsettings<bool>&>(*_v).get();
}
tmp_file::tmp_file(std::string _v)
: filename{ std::move(_v) }
{}
+6
View File
@@ -358,6 +358,12 @@ get_use_tmp_files();
std::string
get_tmpdir();
std::string
get_database_absolute_path(std::string_view database_name);
bool&
get_use_rocpd() ROCPROFSYS_HOT;
struct tmp_file
{
tmp_file(std::string);
+168
View File
@@ -0,0 +1,168 @@
#include "cpu.hpp"
#include "agent_manager.hpp"
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <functional>
#include <unordered_map>
namespace rocprofsys
{
namespace cpu
{
std::vector<cpu_info>
process_cpu_info_data()
{
std::vector<cpu_info> cpu_data;
std::ifstream cpuinfo_file("/proc/cpuinfo");
if(!cpuinfo_file.is_open())
{
return cpu_data;
}
std::string line;
cpu_info current_cpu;
bool has_processor_entry = false;
auto parse_long = [](const std::string& value) -> long {
try
{
return std::stol(value);
} catch(const std::exception&)
{
return -1;
}
};
auto trim_whitespace = [](const std::string& str) -> std::string {
size_t start = str.find_first_not_of(" \t");
if(start == std::string::npos) return "";
size_t end = str.find_last_not_of(" \t");
return str.substr(start, end - start + 1);
};
static const std::unordered_map<std::string,
std::function<void(cpu_info&, const std::string&)>>
field_parsers = {
{ "processor",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.processor = parse_long(val);
} },
{ "cpu family",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.family = parse_long(val);
} },
{ "model",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.model = parse_long(val);
} },
{ "physical id",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.physical_id = parse_long(val);
} },
{ "core id",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.core_id = parse_long(val);
} },
{ "apicid",
[&parse_long](cpu_info& cpu, const std::string& val) {
cpu.apicid = parse_long(val);
} },
{ "vendor_id",
[](cpu_info& cpu, const std::string& val) { cpu.vendor_id = val; } },
{ "model name",
[](cpu_info& cpu, const std::string& val) { cpu.model_name = val; } }
};
while(std::getline(cpuinfo_file, line))
{
if(line.empty())
{
if(has_processor_entry)
{
cpu_data.push_back(current_cpu);
return cpu_data; // Return immediately after first core
}
continue;
}
size_t colon_pos = line.find(':');
if(colon_pos == std::string::npos)
{
continue;
}
std::string key = trim_whitespace(line.substr(0, colon_pos));
std::string value = trim_whitespace(line.substr(colon_pos + 1));
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
auto it = field_parsers.find(key);
if(it != field_parsers.end())
{
it->second(current_cpu, value);
if(key == "processor")
{
has_processor_entry = true;
}
}
}
if(has_processor_entry)
{
cpu_data.push_back(current_cpu);
}
return cpu_data;
}
std::vector<cpu_info>
get_cpu_info()
{
static auto _v = process_cpu_info_data();
return _v;
}
size_t
device_count()
{
auto cpu_data = get_cpu_info();
return cpu_data.size();
}
void
query_cpu_agents()
{
int32_t id_count = 0;
uint32_t node_count = 0;
uint32_t cpu_count = 0;
if(device_count() == 0)
{
return;
}
auto& _agent_manager = agent_manager::get_instance();
auto cpu_data = get_cpu_info();
for(auto& cpu : cpu_data)
{
auto node_id = node_count++;
auto logical_id = id_count++;
auto id = cpu_count++;
auto cur_agent = agent{ agent_type::CPU,
id,
node_id,
logical_id,
static_cast<int32_t>(id),
cpu.model_name,
cpu.model_name,
cpu.vendor_id,
"" };
_agent_manager.insert_agent(cur_agent);
}
}
} // namespace cpu
} // namespace rocprofsys
+57
View File
@@ -0,0 +1,57 @@
// MIT License
//
// Copyright (c) 2022-2025 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <string>
#include <vector>
namespace rocprofsys
{
namespace cpu
{
struct cpu_info
{
long processor = -1;
long family = -1;
long model = -1;
long physical_id = -1;
long core_id = -1;
long apicid = -1;
std::string vendor_id = {};
std::string model_name = {};
};
std::vector<cpu_info>
process_cpu_info_data();
std::vector<cpu_info>
get_cpu_info();
size_t
device_count();
void
query_cpu_agents();
} // namespace cpu
} // namespace rocprofsys
+50 -21
View File
@@ -20,6 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "agent.hpp"
#define ROCPROFILER_SDK_CEREAL_NAMESPACE_BEGIN \
namespace tim \
{ \
@@ -41,6 +42,10 @@
#include <timemory/manager.hpp>
#include <string>
#include "core/agent_manager.hpp"
#if ROCPROFSYS_USE_ROCM > 0
# include <amd_smi/amdsmi.h>
# include <rocprofiler-sdk/agent.h>
@@ -108,18 +113,31 @@ amdsmi_init()
}
#endif // ROCPROFSYS_USE_ROCM > 0
int32_t
query_rocm_gpu_agents()
size_t
query_rocm_agents()
{
int32_t _dev_cnt = 0;
size_t _dev_cnt = 0;
#if ROCPROFSYS_USE_ROCM > 0
auto iterator = [](rocprofiler_agent_version_t /*version*/, const void** agents,
size_t num_agents, void* user_data) -> rocprofiler_status_t {
auto* _cnt = static_cast<int32_t*>(user_data);
auto iterator = []([[maybe_unused]] rocprofiler_agent_version_t version,
const void** agents, size_t num_agents,
[[maybe_unused]] void* user_data) -> rocprofiler_status_t {
auto& _agent_manager = agent_manager::get_instance();
for(size_t i = 0; i < num_agents; ++i)
{
const auto* _agent = static_cast<const rocprofiler_agent_v0_t*>(agents[i]);
if(_agent && _agent->type == ROCPROFILER_AGENT_TYPE_GPU) *_cnt += 1;
const auto* _agent = static_cast<const rocprofiler_agent_v0_t*>(agents[i]);
auto cur_agent = agent{
(_agent->type == ROCPROFILER_AGENT_TYPE_GPU ? agent_type::GPU
: agent_type::CPU),
_agent->device_id,
_agent->node_id,
_agent->logical_node_id,
_agent->logical_node_type_id,
std::string(_agent->name),
std::string(_agent->vendor_name),
std::string(_agent->product_name),
std::string(_agent->model_name),
};
_agent_manager.insert_agent(cur_agent);
}
return ROCPROFILER_STATUS_SUCCESS;
};
@@ -127,15 +145,14 @@ query_rocm_gpu_agents()
try
{
rocprofiler_query_available_agents(ROCPROFILER_AGENT_INFO_VERSION_0, iterator,
sizeof(rocprofiler_agent_v0_t), &_dev_cnt);
sizeof(rocprofiler_agent_v0_t), nullptr);
} catch(std::exception& _e)
{
ROCPROFSYS_BASIC_VERBOSE(
1, "Exception thrown getting the rocm agents: %s. _dev_cnt=%d\n", _e.what(),
1, "Exception thrown getting the rocm agents: %s. _dev_cnt=%ld\n", _e.what(),
_dev_cnt);
}
// rocprofiler_query_available_agents(ROCPROFILER_AGENT_INFO_VERSION_0, iterator,
// sizeof(rocprofiler_agent_v0_t), &_dev_cnt);
_dev_cnt = agent_manager::get_instance().get_gpu_agents_count();
#endif
return _dev_cnt;
}
@@ -145,7 +162,7 @@ int
device_count()
{
#if ROCPROFSYS_USE_ROCM > 0
static int _num_devices = query_rocm_gpu_agents();
static int _num_devices = query_rocm_agents();
return _num_devices;
#else
return 0;
@@ -174,20 +191,31 @@ add_device_metadata(ArchiveT& ar)
#if ROCPROFSYS_USE_ROCM > 0
using agent_vec_t = std::vector<rocprofiler_agent_v0_t>;
auto _agents_vec = agent_vec_t{};
auto iterator = [](rocprofiler_agent_version_t /*version*/, const void** agents,
size_t num_agents, void* user_data) -> rocprofiler_status_t {
auto* _agents_vec_v = static_cast<agent_vec_t*>(user_data);
_agents_vec_v->reserve(num_agents);
auto iterator_cb = []([[maybe_unused]] rocprofiler_agent_version_t version,
const void** agents, size_t num_agents,
[[maybe_unused]] void* user_data) -> rocprofiler_status_t {
auto* agents_vec = static_cast<agent_vec_t*>(user_data);
for(size_t i = 0; i < num_agents; ++i)
{
const auto* _agent = static_cast<const rocprofiler_agent_v0_t*>(agents[i]);
if(_agent) _agents_vec_v->emplace_back(*_agent);
if(_agent->type == ROCPROFILER_AGENT_TYPE_GPU)
{
agents_vec->push_back(*_agent);
}
}
return ROCPROFILER_STATUS_SUCCESS;
};
rocprofiler_query_available_agents(ROCPROFILER_AGENT_INFO_VERSION_0, iterator,
sizeof(rocprofiler_agent_v0_t), &_agents_vec);
auto _agents_vec = agent_vec_t{};
try
{
rocprofiler_query_available_agents(ROCPROFILER_AGENT_INFO_VERSION_0, iterator_cb,
sizeof(rocprofiler_agent_v0_t), &_agents_vec);
} catch(std::exception& _e)
{
ROCPROFSYS_BASIC_VERBOSE(1, "Exception thrown getting the rocm agents: %s.\n",
_e.what());
}
ar(make_nvp("rocm_agents", _agents_vec));
#else
@@ -228,6 +256,7 @@ get_processor_handles()
{
uint32_t socket_count;
uint32_t processor_count;
processors::processors_list.clear();
// Passing nullptr will return us the number of sockets available for read in this
// system
+72
View File
@@ -0,0 +1,72 @@
// MIT License
//
// Copyright (c) 2025 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 "node_info.hpp"
#include "debug.hpp"
#include <fstream>
#include <iostream>
#include <limits>
#include <sys/utsname.h>
namespace rocprofsys
{
node_info::node_info()
{
auto ifs = std::ifstream{ "/etc/machine-id" };
if(!ifs.is_open())
{
ROCPROFSYS_WARNING(0, "Error: Unable to open /etc/machine-id!");
return;
}
if(!(ifs >> machine_id) || machine_id.empty())
{
ROCPROFSYS_WARNING(0, "Error: Unable to read machine ID from /etc/machine-id!");
}
hash = std::hash<std::string>{}(machine_id) % std::numeric_limits<int64_t>::max();
id = hash % std::numeric_limits<size_t>::max();
struct utsname _sys_info;
if(uname(&_sys_info))
{
ROCPROFSYS_WARNING(0, "Error: Unable to get system information!");
return;
}
system_name = _sys_info.sysname;
node_name = _sys_info.nodename;
release = _sys_info.release;
version = _sys_info.version;
machine = _sys_info.machine;
domain_name = _sys_info.domainname;
}
node_info&
node_info::get_instance()
{
static node_info instance;
return instance;
}
} // namespace rocprofsys
+58
View File
@@ -0,0 +1,58 @@
// MIT License
//
// Copyright (c) 2025 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 <cstdint>
#include <string>
namespace rocprofsys
{
struct node_info
{
private:
node_info();
public:
~node_info() = default;
node_info(const node_info&) = default;
node_info(node_info&&) noexcept = default;
node_info& operator=(const node_info&) = default;
node_info& operator=(node_info&&) noexcept = default;
static node_info& get_instance();
uint64_t id = 0;
uint64_t hash = 0;
std::string machine_id = {};
std::string system_name = {};
std::string node_name = {};
std::string release = {};
std::string version = {};
std::string machine = {};
std::string domain_name = {};
};
const node_info&
get_node_info();
} // namespace rocprofsys
+13
View File
@@ -0,0 +1,13 @@
set(rocpd_sources
${CMAKE_CURRENT_LIST_DIR}/data_processor.cpp
${CMAKE_CURRENT_LIST_DIR}/json.cpp
)
set(rocpd_headers
${CMAKE_CURRENT_LIST_DIR}/data_processor.hpp
${CMAKE_CURRENT_LIST_DIR}/json.hpp
)
target_sources(rocprofiler-systems-core-library PRIVATE ${rocpd_sources} ${rocpd_headers})
add_subdirectory(data_storage)
+674
View File
@@ -0,0 +1,674 @@
// MIT License
//
// Copyright (c) 2025 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 "data_processor.hpp"
#include "core/rocpd/data_storage/database.hpp"
#include "core/rocpd/data_storage/table_insert_query.hpp"
#include "debug.hpp"
namespace rocprofsys
{
namespace rocpd
{
data_processor::data_processor()
{
data_storage::database::get_instance().initialize_schema();
_upid = data_storage::database::get_instance().get_upid();
// Initialize event statement
initialize_event_stmt();
initialize_pmc_event_stmt();
initialize_sample_stmt();
initialize_region_stmt();
initialize_kernel_dispatch_stmt();
initialize_memory_copy_stmt();
initialize_code_object_stmt();
initialize_kernel_symbol_stmt();
initialize_metadata();
initialize_args_stmt();
initialize_memory_alloc_stmt();
}
data_processor&
data_processor::get_instance()
{
static data_processor _instance;
return _instance;
}
void
data_processor::initialize_metadata()
{
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_metadata_" + _upid)
.set_columns("tag", "value")
.set_values("upid", _upid)
.get_query_string());
}
size_t
data_processor::insert_string(const char* str)
{
std::lock_guard<std::mutex> lock(_data_mutex);
auto it = _string_map.find(str);
if(it != _string_map.end()) return _string_map.at(str);
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_string_" + _upid)
.set_columns("guid", "string")
.set_values(_upid, str)
.get_query_string());
const auto string_id = data_storage::database::get_instance().get_last_insert_id();
_string_map.emplace(str, string_id);
return string_id;
}
void
data_processor::insert_node_info(size_t node_id, size_t hash, const char* machine_id,
const char* system_name, const char* hostname,
const char* release, const char* version,
const char* hardware_name, const char* domain_name)
{
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_node_" + _upid)
.set_columns("id", "guid", "hash", "machine_id", "system_name", "hostname",
"release", "version", "hardware_name", "domain_name")
.set_values(node_id, _upid, hash, machine_id, system_name, hostname, release,
version, hardware_name, domain_name)
.get_query_string());
}
void
data_processor::insert_process_info(size_t nid, size_t ppid, size_t pid, size_t init,
size_t fini, size_t start, size_t end,
const char* command, const char* environment,
const char* extdata)
{
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_process_" + _upid)
.set_columns("id", "guid", "nid", "ppid", "pid", "init", "fini", "start",
"end", "command", "environment", "extdata")
.set_values(pid, _upid, nid, ppid, pid, init, fini, start, end, command,
environment, extdata)
.get_query_string());
}
size_t
data_processor::insert_agent(size_t node_id, size_t pid, const char* agent_type,
size_t absolute_index, size_t logical_index,
size_t type_index, uint64_t uuid, const char* name,
const char* model_name, const char* vendor_name,
const char* product_name, const char* user_name,
const char* extdata)
{
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_agent_" + _upid)
.set_columns("guid", "nid", "pid", "type", "absolute_index", "logical_index",
"type_index", "uuid", "name", "model_name", "vendor_name",
"product_name", "user_name", "extdata")
.set_values(_upid, node_id, pid, agent_type, absolute_index, logical_index,
type_index, uuid, name, model_name, vendor_name, product_name,
user_name, extdata)
.get_query_string());
return data_storage::database::get_instance().get_last_insert_id();
}
void
data_processor::insert_track(const char* track_name, size_t node_id, size_t process_id,
std::optional<size_t> thread_id, const char* extdata)
{
if(_tracks.find(track_name) != _tracks.end())
{
ROCPROFSYS_WARNING(2, "Fail to add track %s, already exist!\n", track_name);
return;
}
auto name_id = insert_string(track_name);
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_track_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "name_id", "extdata")
.set_values(_upid, node_id, process_id, thread_id, name_id, extdata)
.get_query_string());
auto track_id = data_storage::database::get_instance().get_last_insert_id();
_tracks[track_name] = track_name_map{ track_id, name_id };
}
void
data_processor::insert_pmc_description(
size_t node_id, size_t process_id, size_t agent_id, const char* target_arch,
size_t event_code, size_t instance_id, const char* name, const char* symbol,
const char* description, const char* long_description, const char* component,
const char* units, const char* value_type, const char* block, const char* expression,
uint32_t is_constant, uint32_t is_derived, const char* extdata)
{
auto it = _pmc_descriptor_map.find({ agent_id, name });
if(it != _pmc_descriptor_map.end())
{
ROCPROFSYS_WARNING(0,
"Insert PMC description failed! Error: PMC descriptor "
"(name:%s) (ID:%lu) already exist!\n",
name, agent_id);
return;
}
data_storage::queries::table_insert_query query_builder;
auto query =
query_builder.set_table_name("rocpd_info_pmc_" + _upid)
.set_columns("guid", "nid", "pid", "agent_id", "target_arch", "event_code",
"instance_id", "name", "symbol", "description",
"long_description", "component", "units", "value_type", "block",
"expression", "is_constant", "is_derived", "extdata")
.set_values(_upid, node_id, process_id, agent_id, target_arch, event_code,
instance_id, name, symbol, description, long_description,
component, units, value_type, block, expression, is_constant,
is_derived, extdata)
.get_query_string();
data_storage::database::get_instance().execute_query(query);
auto pmc_id = data_storage::database::get_instance().get_last_insert_id();
_pmc_descriptor_map.emplace(
std::pair<pmc_identifier, size_t>{ { agent_id, name }, pmc_id });
}
void
data_processor::insert_pmc_event(size_t event_id, size_t agent_id, const char* pmc_name,
double value, const char* extdata)
{
ROCPROFSYS_VERBOSE(2,
"Insert PMC event: id %ld, agent id: %ld, pmc name: %s, value: "
"%lf, extdata: %s\n",
event_id, agent_id, pmc_name, value, extdata);
auto it = _pmc_descriptor_map.find({ agent_id, pmc_name });
if(it == _pmc_descriptor_map.end())
{
ROCPROFSYS_WARNING(0,
"Insert PMC event failed! Error: non-existing PMC description "
"agent id: %ld, pmc name: %s !\n",
agent_id, pmc_name);
return;
}
const auto pmc_description_id = it->second;
_insert_pmc_event_statement(_upid.c_str(), event_id, pmc_description_id, value,
extdata);
}
void
data_processor::insert_sample(const char* track, uint64_t timestamp, size_t event_id,
const char* extdata)
{
ROCPROFSYS_VERBOSE(
3, "Insert sample: track: %s, timestamp: %lu, event id: %ld, extdata: %s\n",
track, timestamp, event_id, extdata);
auto it = _tracks.find(track);
if(it == _tracks.end())
{
ROCPROFSYS_WARNING(0, "Insert sample failed! Error: Unexisting track %s!\n",
track);
return;
}
auto track_info = it->second;
_insert_sample_statement(_upid.c_str(), track_info.track_id, timestamp, event_id,
extdata);
}
size_t
data_processor::insert_event(size_t category_id, size_t stack_id, size_t parent_stack_id,
size_t correlation_id, const char* call_stack,
const char* line_info, const char* extdata)
{
std::lock_guard<std::mutex> lock(_data_mutex);
auto it = _category_map.find(category_id);
if(it == _category_map.end())
{
std::ostringstream oss;
oss << "Insert event failed! Error: Unknown category id: " << category_id
<< " for UPID: " << _upid;
throw std::runtime_error(oss.str());
}
ROCPROFSYS_VERBOSE(3, "Insert event category id: %ld, string id: %ld\n", category_id,
it->second);
_insert_event_statement(_upid.c_str(), it->second, stack_id, parent_stack_id,
correlation_id, call_stack, line_info, extdata);
return data_storage::database::get_instance().get_last_insert_id();
}
void
data_processor::initialize_event_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_event_" + _upid)
.set_columns("guid", "category_id", "stack_id", "parent_stack_id",
"correlation_id", "call_stack", "line_info", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_event_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, size_t, size_t,
const char*, const char*, const char*>(query);
}
void
data_processor::initialize_pmc_event_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_pmc_event_" + _upid)
.set_columns("guid", "event_id", "pmc_id", "value", "extdata")
.set_values('?', '?', '?', '?', '?')
.get_query_string();
_insert_pmc_event_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, double, const char*>(
query);
}
void
data_processor::initialize_sample_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_sample_" + _upid)
.set_columns("guid", "track_id", "timestamp", "event_id", "extdata")
.set_values('?', '?', '?', '?', '?')
.get_query_string();
_insert_sample_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, uint64_t, size_t,
const char*>(query);
}
void
data_processor::initialize_region_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_region_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "start", "end", "name_id",
"event_id", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_region_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, size_t, uint64_t,
uint64_t, size_t, size_t, const char*>(query);
}
void
data_processor::initialize_kernel_dispatch_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_kernel_dispatch_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "agent_id", "kernel_id",
"dispatch_id", "queue_id", "stream_id", "start", "end",
"private_segment_size", "group_segment_size",
"workgroup_size_x", "workgroup_size_y",
"workgroup_size_z", "grid_size_x", "grid_size_y",
"grid_size_z", "region_name_id", "event_id", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_kernel_dispatch_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, size_t, size_t,
size_t, size_t, size_t, size_t, uint64_t, uint64_t,
size_t, size_t, size_t, size_t, size_t, size_t,
size_t, size_t, size_t, size_t, const char*>(
query);
}
void
data_processor::initialize_memory_copy_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_memory_copy_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "start", "end", "name_id",
"dst_agent_id", "dst_address", "src_agent_id",
"src_address", "size", "queue_id", "stream_id",
"region_name_id", "event_id", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_memory_copy_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, size_t, uint64_t,
uint64_t, size_t, size_t, size_t, size_t, size_t,
size_t, size_t, size_t, size_t, size_t,
const char*>(query);
}
void
data_processor::initialize_kernel_symbol_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query =
query_builder.set_table_name("rocpd_info_kernel_symbol_" + _upid)
.set_columns("id", "guid", "nid", "pid", "code_object_id", "kernel_name",
"display_name", "kernel_object", "kernarg_segment_size",
"kernarg_segment_alignment", "group_segment_size",
"private_segment_size", "sgpr_count", "arch_vgpr_count",
"accum_vgpr_count", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?')
.get_query_string();
_insert_kernel_symbol_statement =
data_storage::database::get_instance()
.create_statement_executor<size_t, const char*, size_t, size_t, uint64_t,
const char*, const char*, uint64_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,
uint32_t, const char*>(query);
}
void
data_processor::initialize_code_object_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query =
query_builder.set_table_name("rocpd_info_code_object_" + _upid)
.set_columns("id", "guid", "nid", "pid", "agent_id", "uri", "load_base",
"load_size", "load_delta", "storage_type", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_code_object_statement =
data_storage::database::get_instance()
.create_statement_executor<size_t, const char*, size_t, size_t, size_t,
const char*, uint64_t, uint64_t, uint64_t,
const char*, const char*>(query);
}
void
data_processor::initialize_args_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_arg_" + _upid)
.set_columns("guid", "event_id", "position", "type", "name", "value",
"extdata")
.set_values('?', '?', '?', '?', '?', '?', '?')
.get_query_string();
_insert_args_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, const char*,
const char*, const char*, const char*>(query);
}
void
data_processor::initialize_memory_alloc_stmt()
{
data_storage::queries::table_insert_query query_builder;
auto query = query_builder.set_table_name("rocpd_memory_allocate_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "agent_id", "type",
"level", "start", "end", "address", "size", "queue_id",
"stream_id", "event_id", "extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?')
.get_query_string();
_insert_memory_alloc_statement =
data_storage::database::get_instance()
.create_statement_executor<
const char*, size_t, size_t, size_t, size_t, const char*, const char*,
uint64_t, uint64_t, size_t, size_t, size_t, size_t, size_t, const char*>(
query);
// Statement without agent_id
query = query_builder.set_table_name("rocpd_memory_allocate_" + _upid)
.set_columns("guid", "nid", "pid", "tid", "type", "level", "start", "end",
"address", "size", "queue_id", "stream_id", "event_id",
"extdata")
.set_values('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?')
.get_query_string();
_insert_memory_alloc_no_agent_statement =
data_storage::database::get_instance()
.create_statement_executor<const char*, size_t, size_t, size_t, const char*,
const char*, uint64_t, uint64_t, size_t, size_t,
size_t, size_t, size_t, const char*>(query);
}
void
data_processor::insert_args(size_t event_id, size_t position, const char* type,
const char* name, const char* value, const char* extdata)
{
std::lock_guard<std::mutex> lock(_data_mutex);
_insert_args_statement(_upid.c_str(), event_id, position, type, name, value, extdata);
}
void
data_processor::insert_stream_info(size_t stream_id, size_t node_id, size_t process_id,
const char* name, const char* extdata)
{
if(_stream_ids.count(stream_id) > 0)
{
// ROCPROFSYS_WARNING(
// 1, "Insert stream info failed! Error: Stream ID %ld already exists!\n",
// stream_id);
return;
}
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_stream_" + _upid)
.set_columns("id", "guid", "nid", "pid", "name", "extdata")
.set_values(stream_id, _upid, node_id, process_id, name, extdata)
.get_query_string());
_stream_ids.insert(stream_id);
}
void
data_processor::insert_queue_info(size_t queue_id, size_t node_id, size_t process_id,
const char* name, const char* extdata)
{
if(_queue_ids.count(queue_id) > 0)
{
// ROCPROFSYS_WARNING(
// 1, "Insert queue info failed! Error: Queue ID %ld already exists!\n",
// queue_id);
return;
}
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_queue_" + _upid)
.set_columns("id", "guid", "nid", "pid", "name", "extdata")
.set_values(queue_id, _upid, node_id, process_id, name, extdata)
.get_query_string());
_queue_ids.insert(queue_id);
}
void
data_processor::insert_code_object(size_t id, size_t node_id, size_t process_id,
size_t agent_id, const char* uri, uint64_t ld_base,
uint64_t ld_size, uint64_t ld_delta,
const char* storage_type, const char* extdata)
{
if(_code_object_ids.count(id) > 0)
{
// ROCPROFSYS_WARNING(
// 1,
// "Insert code object info failed! Error: Code object ID %ld already
// exists!\n", id);
return;
}
ROCPROFSYS_VERBOSE(2, "Insert code object with ID: %ld\n", id);
std::lock_guard<std::mutex> lock(_data_mutex);
_insert_code_object_statement(id, _upid.c_str(), node_id, process_id, agent_id, uri,
ld_base, ld_size, ld_delta, storage_type, extdata);
_code_object_ids.insert(id);
}
void
data_processor::insert_kernel_symbol(
size_t id, size_t node_id, size_t process_id, uint64_t code_obj_id, const char* name,
const char* display_name, uint32_t kernel_obj, uint32_t kernarg_segmnt_size,
uint32_t kernarg_segment_alignment, uint32_t group_segment_size,
uint32_t private_segment_size, uint32_t sgrp_count, uint32_t arch_vgrp_count,
uint32_t accum_vgrp_count, const char* extdata)
{
if(_kernel_sym_ids.count(id) > 0)
{
// ROCPROFSYS_WARNING(
// 1,
// "Insert kernel symbol failed! Error: Kernel symbol ID %ld already
// exists!\n", id);
return;
}
ROCPROFSYS_VERBOSE(2, "Insert kernel symbol: %s with ID: %ld\n", name, id);
std::lock_guard<std::mutex> lock(_data_mutex);
_insert_kernel_symbol_statement(
id, _upid.c_str(), node_id, process_id, code_obj_id, name, display_name,
kernel_obj, kernarg_segmnt_size, kernarg_segment_alignment, group_segment_size,
private_segment_size, sgrp_count, arch_vgrp_count, accum_vgrp_count, extdata);
_kernel_sym_ids.insert(id);
}
void
data_processor::insert_category(size_t category_id, const char* name)
{
auto it = _category_map.find(category_id);
if(it != _category_map.end())
{
// ROCPROFSYS_WARNING(
// 1, "Insert category failed! Error: Category %s already exist!\n", name);
return;
}
auto name_id = insert_string(name);
std::lock_guard<std::mutex> lock(_data_mutex);
ROCPROFSYS_VERBOSE(2, "Insert category: name: %s, id: %ld, name id: %ld\n", name,
category_id, name_id);
_category_map.emplace(category_id, name_id);
}
void
data_processor::insert_region(size_t node_id, size_t process_id, size_t thread_id,
uint64_t start, uint64_t end, size_t name_id,
size_t event_id, const char* extdata)
{
std::lock_guard<std::mutex> lock(_data_mutex);
ROCPROFSYS_VERBOSE(2, "Insert region for event id: %ld\n", event_id);
_insert_region_statement(_upid.c_str(), node_id, process_id, thread_id, start, end,
name_id, event_id, extdata);
}
void
data_processor::insert_kernel_dispatch(
size_t node_id, size_t process_id, size_t thread_id, size_t agent_id,
size_t kernel_id, size_t dispatch_id, size_t queue_id, size_t stream_id,
uint64_t start, uint64_t end, size_t private_segment_size, size_t group_segment_size,
size_t workgroup_size_x, size_t workgroup_size_y, size_t workgroup_size_z,
size_t grid_size_x, size_t grid_size_y, size_t grid_size_z, size_t region_name_id,
size_t event_id, const char* extdata)
{
std::lock_guard<std::mutex> lock(_data_mutex);
ROCPROFSYS_VERBOSE(2, "Insert kernel dispatch for event id: %ld\n", event_id);
_insert_kernel_dispatch_statement(
_upid.c_str(), node_id, process_id, thread_id, agent_id, kernel_id, dispatch_id,
queue_id, stream_id, start, end, private_segment_size, group_segment_size,
workgroup_size_x, workgroup_size_y, workgroup_size_z, grid_size_x, grid_size_y,
grid_size_z, region_name_id, event_id, extdata);
}
void
data_processor::insert_memory_copy(size_t node_id, size_t process_id, size_t thread_id,
uint64_t start, uint64_t end, size_t name_id,
size_t dst_agent_id, size_t dst_addr,
size_t src_agent_id, size_t src_addr, size_t size,
size_t queue_id, size_t stream_id,
size_t region_name_id, size_t event_id,
const char* extdata)
{
std::lock_guard<std::mutex> lock(_data_mutex);
_insert_memory_copy_statement(_upid.c_str(), node_id, process_id, thread_id, start,
end, name_id, dst_agent_id, dst_addr, src_agent_id,
src_addr, size, queue_id, stream_id, region_name_id,
event_id, extdata);
}
void
data_processor::insert_memory_alloc(size_t node_id, size_t process_id, size_t thread_id,
std::optional<size_t> agent_id, const char* type,
const char* level, uint64_t start, uint64_t end,
size_t address, size_t size, size_t queue_id,
size_t stream_id, size_t event_id,
const char* extdata)
{
if(agent_id.has_value())
{
_insert_memory_alloc_statement(_upid.c_str(), node_id, process_id, thread_id,
agent_id.value(), type, level, start, end, address,
size, queue_id, stream_id, event_id, extdata);
}
else
{
_insert_memory_alloc_no_agent_statement(
_upid.c_str(), node_id, process_id, thread_id, type, level, start, end,
address, size, queue_id, stream_id, event_id, extdata);
}
}
size_t
data_processor::insert_thread_info(size_t node_id, size_t parent_process_id,
size_t process_id, size_t thread_id, const char* name,
uint64_t start, uint64_t end, const char* extdata)
{
auto it = _thread_id_map.find(thread_id);
if(it != _thread_id_map.end())
{
return _thread_id_map.at(thread_id);
}
data_storage::queries::table_insert_query query;
data_storage::database::get_instance().execute_query(
query.set_table_name("rocpd_info_thread_" + _upid)
.set_columns("guid", "nid", "ppid", "pid", "tid", "name", "start", "end",
"extdata")
.set_values(_upid.c_str(), node_id, parent_process_id, process_id, thread_id,
name, start, end, extdata)
.get_query_string());
auto thread_idx = data_storage::database::get_instance().get_last_insert_id();
_thread_id_map.emplace(thread_id, thread_idx);
return thread_idx;
}
void
data_processor::flush()
{
// Flush all pending data to the database
data_storage::database::get_instance().flush();
}
} // namespace rocpd
} // namespace rocprofsys
+252
View File
@@ -0,0 +1,252 @@
// MIT License
//
// Copyright (c) 2025 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 <cstdint>
#include <functional>
#include <mutex>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
namespace rocprofsys
{
namespace rocpd
{
struct data_processor
{
using insert_event_stmt =
std::function<void(const char*, size_t, size_t, size_t, size_t, const char*,
const char*, const char*)>;
using insert_pmc_event_stms =
std::function<void(const char*, size_t, size_t, double, const char*)>;
using insert_sample_stmt =
std::function<void(const char*, size_t, uint64_t, size_t, const char*)>;
using insert_region_stmt =
std::function<void(const char*, size_t, size_t, size_t, uint64_t, uint64_t,
size_t, size_t, const char*)>;
using insert_kernel_dispatch_stmt = std::function<void(
const char*, size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
uint64_t, uint64_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t,
size_t, size_t, size_t, const char*)>;
using insert_memory_copy_stmt = std::function<void(
const char*, size_t, size_t, size_t, uint64_t, uint64_t, size_t, size_t, size_t,
size_t, size_t, size_t, size_t, size_t, size_t, size_t, const char*)>;
using insert_memory_alloc_stmt = std::function<void(
const char*, size_t, size_t, size_t, size_t, const char*, const char*, uint64_t,
uint64_t, size_t, size_t, size_t, size_t, size_t, const char*)>;
using insert_memory_alloc_no_agent_stmt = std::function<void(
const char*, size_t, size_t, size_t, const char*, const char*, uint64_t, uint64_t,
size_t, size_t, size_t, size_t, size_t, const char*)>;
using insert_kernel_symbol_stmt =
std::function<void(size_t, const char*, size_t, size_t, uint64_t, const char*,
const char*, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, const char*)>;
using insert_code_object_stmt =
std::function<void(size_t, const char*, size_t, size_t, size_t, const char*,
uint64_t, uint64_t, uint64_t, const char*, const char*)>;
using insert_args_stmt = std::function<void(const char*, size_t, size_t, const char*,
const char*, const char*, const char*)>;
private:
struct track_name_map
{
size_t track_id;
size_t name_id;
};
struct pmc_identifier
{
size_t agent_id;
std::string name;
};
struct pmc_identifier_hash
{
std::size_t operator()(const pmc_identifier& pmc) const noexcept
{
std::size_t h1 = std::hash<size_t>{}(pmc.agent_id);
std::size_t h2 = std::hash<std::string>{}(pmc.name);
return h1 ^ (h2 << 1);
}
};
struct pmc_identifier_equal
{
bool operator()(const pmc_identifier& lhs,
const pmc_identifier& rhs) const noexcept
{
return lhs.agent_id == rhs.agent_id && lhs.name == rhs.name;
}
};
public:
static data_processor& get_instance();
size_t insert_string(const char* str);
void insert_node_info(size_t node_id, size_t hash, const char* machine_id,
const char* system_name, const char* hostname,
const char* release, const char* version,
const char* hardware_name, const char* domain_name);
void insert_process_info(size_t node_id, size_t ppid, size_t pid, size_t init,
size_t fini, size_t start, size_t end, const char* command,
const char* environment = "{}", const char* extdata = "{}");
size_t insert_agent(size_t node_id, size_t pid, const char* agent_type,
size_t absolute_index, size_t logical_index, size_t type_index,
uint64_t uuid, const char* name, const char* model_name,
const char* vendor_name, const char* product_name,
const char* user_name, const char* extdata = "{}");
void insert_track(const char* track_name, size_t node_id, size_t process_id,
std::optional<size_t> thread_id, const char* extdata = "{}");
size_t insert_event(size_t category_id, size_t stack_id, size_t parent_stack_id,
size_t correlation_id, const char* call_stack = "{}",
const char* line_info = "{}", const char* extdata = "{}");
void insert_pmc_event(size_t event_id, size_t agent_id, const char* pmc_descriptor,
double value, const char* extdata = "{}");
void insert_pmc_description(size_t node_id, size_t process_id, size_t agent_id,
const char* target_arch, size_t event_code,
size_t instance_id, const char* name, const char* symbol,
const char* description, const char* long_description,
const char* component, const char* units,
const char* value_type, const char* block,
const char* expression, uint32_t is_constant,
uint32_t is_derived, const char* extdata = "{}");
void insert_sample(const char* track, uint64_t timestamp, size_t event_id,
const char* extdata = "{}");
void insert_category(size_t category_id, const char* name);
void insert_region(size_t node_id, size_t process_id, size_t thread_id,
uint64_t start, uint64_t end, size_t name_id, size_t event_id,
const char* extdata = "{}");
size_t insert_thread_info(size_t node_id, size_t parent_process_id, size_t process_id,
size_t thread_id, const char* name, uint64_t start = 0,
uint64_t end = 0, const char* extdata = "{}");
void insert_stream_info(size_t stream_id, size_t node_id, size_t process_id,
const char* name, const char* extdata = "{}");
void insert_queue_info(size_t queue_id, size_t node_id, size_t process_id,
const char* name, const char* extdata = "{}");
void insert_kernel_dispatch(size_t node_id, size_t process_id, size_t thread_id,
size_t agent_id, size_t kernel_id, size_t dispatch_id,
size_t queue_id, size_t stream_id, uint64_t start,
uint64_t end, size_t private_segment_size,
size_t group_segment_size, size_t workgroup_size_x,
size_t workgroup_size_y, size_t workgroup_size_z,
size_t grid_size_x, size_t grid_size_y,
size_t grid_size_z, size_t region_name_id,
size_t event_id, const char* extdata = "{}");
void insert_memory_copy(size_t node_id, size_t process_id, size_t thread_id,
uint64_t start, uint64_t end, size_t name_id,
size_t dst_agent_id, size_t dst_addr, size_t src_agent_id,
size_t src_addr, size_t size, size_t queue_id,
size_t stream_id, size_t region_name_id, size_t event_id,
const char* extdata = "{}");
void insert_kernel_symbol(size_t id, size_t node_id, size_t process_id,
uint64_t code_obj_id, const char* name,
const char* display_name, uint32_t kernel_obj,
uint32_t kernarg_segmnt_size,
uint32_t kernarg_segment_alignment,
uint32_t group_segment_size, uint32_t private_segment_size,
uint32_t sgrp_count, uint32_t arch_vgrp_count,
uint32_t accum_vgrp_count, const char* extdata = "{}");
void insert_code_object(size_t id, size_t node_id, size_t process_id, size_t agent_id,
const char* uri, uint64_t ld_base, uint64_t ld_size,
uint64_t ld_delta, const char* storage_type,
const char* extdata = "{}");
void insert_args(size_t event_id, size_t position, const char* type, const char* name,
const char* value, const char* extdata = "{}");
void insert_memory_alloc(size_t node_id, size_t process_id, size_t thread_id,
std::optional<size_t> agent_id, const char* type,
const char* level, uint64_t start, uint64_t end,
size_t address, size_t size, size_t queue_id,
size_t stream_id, size_t event_id,
const char* extdata = "{}");
void flush();
private:
data_processor();
data_processor(data_processor&) = delete;
data_processor& operator=(const data_processor&) = delete;
void initialize_pmc_event_stmt();
void initialize_event_stmt();
void initialize_sample_stmt();
void initialize_region_stmt();
void initialize_kernel_dispatch_stmt();
void initialize_memory_copy_stmt();
void initialize_kernel_symbol_stmt();
void initialize_code_object_stmt();
void initialize_metadata();
void initialize_args_stmt();
void initialize_memory_alloc_stmt();
private:
std::unordered_map<std::string, track_name_map> _tracks;
std::unordered_map<pmc_identifier, size_t, pmc_identifier_hash, pmc_identifier_equal>
_pmc_descriptor_map;
std::unordered_map<size_t, size_t> _thread_id_map;
std::unordered_map<size_t, size_t> _category_map;
std::unordered_map<std::string, size_t> _string_map;
std::set<uint64_t> _code_object_ids;
std::set<uint64_t> _kernel_sym_ids;
std::set<uint64_t> _stream_ids;
std::set<uint64_t> _queue_ids;
insert_event_stmt _insert_event_statement;
insert_pmc_event_stms _insert_pmc_event_statement;
insert_sample_stmt _insert_sample_statement;
insert_region_stmt _insert_region_statement;
insert_kernel_dispatch_stmt _insert_kernel_dispatch_statement;
insert_memory_copy_stmt _insert_memory_copy_statement;
insert_kernel_symbol_stmt _insert_kernel_symbol_statement;
insert_code_object_stmt _insert_code_object_statement;
insert_args_stmt _insert_args_statement;
insert_memory_alloc_stmt _insert_memory_alloc_statement;
insert_memory_alloc_no_agent_stmt _insert_memory_alloc_no_agent_statement;
std::string _upid{};
std::mutex _data_mutex;
};
} // namespace rocpd
} // namespace rocprofsys
@@ -0,0 +1,14 @@
set(data_storage_sources ${CMAKE_CURRENT_LIST_DIR}/database.cpp)
set(data_storage_headers
${CMAKE_CURRENT_LIST_DIR}/database.hpp
${CMAKE_CURRENT_LIST_DIR}/insert_query_builders.hpp
${CMAKE_CURRENT_LIST_DIR}/table_insert_query.hpp
)
target_sources(rocprofiler-systems-core-library PRIVATE ${data_storage_sources})
target_link_libraries(
rocprofiler-systems-core-library
PRIVATE $<BUILD_INTERFACE:rocprofiler-systems::rocprofiler-systems-sqlite3>
)
@@ -0,0 +1,170 @@
// MIT License
//
// Copyright (c) 2025 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 "database.hpp"
#include "common/md5sum.hpp"
#include "debug.hpp"
#include "node_info.hpp"
#include <config.hpp>
#include <fstream>
#include <regex>
#include <timemory/environment/types.hpp>
#include <timemory/utility/filepath.hpp>
#include <unistd.h>
namespace
{
void
create_directory_for_database_file(const std::string& db_file)
{
auto _db_dirname = tim::filepath::dirname(db_file);
if(!tim::filepath::direxists(_db_dirname))
{
tim::filepath::makedir(_db_dirname);
}
}
} // namespace
namespace rocprofsys
{
namespace rocpd
{
namespace data_storage
{
database&
database::get_instance()
{
static database _instance;
return _instance;
}
database::database()
{
auto db_name = std::string_view{ "rocpd.db" };
auto abs_db_path = rocprofsys::get_database_absolute_path(db_name);
create_directory_for_database_file(abs_db_path);
ROCPROFSYS_VERBOSE(0, "Database: %s\r\n", abs_db_path.c_str());
validate_sqlite3_result(sqlite3_open(":memory:", &_sqlite3_db_temp), "",
"database open failed!");
validate_sqlite3_result(sqlite3_open(abs_db_path.c_str(), &_sqlite3_db), "",
"database open failed!");
}
database::~database()
{
sqlite3_close(_sqlite3_db_temp);
sqlite3_close(_sqlite3_db);
}
void
database::initialize_schema()
{
auto get_file_path = [](const std::string_view filename) {
auto _rocprofsys_root = tim::get_env<std::string>(
"rocprofiler_systems_ROOT", tim::get_env<std::string>("ROCPROFSYS_ROOT", ""));
if(!_rocprofsys_root.empty() &&
tim::filepath::direxists(std::string(_rocprofsys_root)))
{
auto new_file_path = std::string(_rocprofsys_root)
.append("/share/rocprofiler-systems/")
.append(filename);
if(tim::filepath::exists(new_file_path))
{
return new_file_path;
}
}
return std::string(
"rocprofiler-systems/source/lib/core/rocpd/data_storage/schema/")
.append(filename);
};
std::vector<std::string_view> schema_files = { "rocpd_tables.sql", "rocpd_views.sql",
"data_views.sql", "marker_views.sql",
"summary_views.sql" };
// Process each schema file
for(const auto& schema_file : schema_files)
{
auto file_path = get_file_path(schema_file);
std::ifstream file(file_path);
if(!file.is_open())
{
throw std::runtime_error(
std::string("Failed to open schema file ").append(file_path));
}
std::stringstream ss_query;
ss_query << file.rdbuf();
std::string query = ss_query.str();
std::regex upid_pattern("\\{\\{uuid\\}\\}");
std::regex view_upid_pattern("\\{\\{view_upid\\}\\}");
query = std::regex_replace(query, upid_pattern, "_" + get_upid());
query = std::regex_replace(query, view_upid_pattern, "");
validate_sqlite3_result(
sqlite3_exec(_sqlite3_db_temp, query.c_str(), 0, 0, 0), query.c_str(),
std::string("Invalid schema file, init database failed!").append(file_path));
file.close();
}
}
void
database::execute_query(const std::string& query)
{
validate_sqlite3_result(sqlite3_exec(_sqlite3_db_temp, query.c_str(), 0, 0, 0),
"Failed to execute query - ", query);
}
std::string
database::get_upid()
{
static std::string _upid = []() {
auto n_info = node_info::get_instance();
auto guid = common::md5sum{ n_info.id, getpid(), getppid() };
return guid.hexdigest();
}();
return _upid;
}
size_t
database::get_last_insert_id() const
{
return sqlite3_last_insert_rowid(_sqlite3_db_temp);
}
void
database::flush()
{
auto* backup = sqlite3_backup_init(_sqlite3_db, "main", _sqlite3_db_temp, "main");
if(backup)
{
sqlite3_backup_step(backup, -1); // Copy all pages
sqlite3_backup_finish(backup);
}
}
} // namespace data_storage
} // namespace rocpd
} // namespace rocprofsys
@@ -0,0 +1,204 @@
// MIT License
//
// Copyright (c) 2025 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/traits.hpp"
#include <memory>
#include <mutex>
#include <sqlite3.h>
#include <sstream>
#include <stdexcept>
namespace rocprofsys
{
namespace rocpd
{
namespace data_storage
{
static std::mutex _mutex;
class database
{
public:
static database& get_instance();
database(database&) = delete;
database& operator=(database&) = delete;
void flush();
~database();
private:
database();
template <typename... Args>
inline void validate_sqlite3_result(int sqlite3_error_code, const char* query,
Args&&... args)
{
std::stringstream ss;
ss << "\n===========================================================\n";
ss << "Database Error\n";
((ss << args << " "), ...);
ss << "\nQuery: " << query << "\n";
switch(sqlite3_error_code)
{
case SQLITE_OK:
case SQLITE_DONE: return;
case SQLITE_CONSTRAINT:
{
sqlite3_stmt* stmt;
ss << "Constraint violation(s): " << "\n";
sqlite3_exec(_sqlite3_db_temp, "PRAGMA foreign_keys = OFF;", nullptr,
nullptr, nullptr);
sqlite3_exec(_sqlite3_db_temp, query, nullptr, nullptr, nullptr);
sqlite3_exec(_sqlite3_db_temp, "PRAGMA foreign_keys = ON;", nullptr,
nullptr, nullptr);
sqlite3_prepare_v2(_sqlite3_db_temp, "PRAGMA foreign_key_check", -1,
&stmt, nullptr);
int rc = 0;
while((rc = sqlite3_step(stmt)) == SQLITE_ROW)
{
const char* table = (const char*) sqlite3_column_text(stmt, 0);
int rowid = sqlite3_column_int(stmt, 1);
const char* parent = (const char*) sqlite3_column_text(stmt, 2);
int fkid = sqlite3_column_int(stmt, 3);
ss << " - " << "FK Violation - Table: " << (table ? table : "NULL")
<< ", RowID: " << rowid
<< ", Parent: " << (parent ? parent : "NULL") << ", FKID: " << fkid
<< "\n";
}
sqlite3_finalize(stmt);
}
break;
default:
{
}
break;
}
ss << " [Sqlite3 error: " << sqlite3_errstr(sqlite3_error_code);
ss << " (Extended error message: " << sqlite3_errmsg(_sqlite3_db_temp) << ")]";
throw std::runtime_error(ss.str());
}
template <typename T, std::enable_if_t<!(common::traits::is_string_literal<T>() ||
std::is_floating_point_v<std::decay_t<T>> ||
std::is_same_v<std::decay_t<T>, int64_t> ||
std::is_same_v<std::decay_t<T>, uint64_t> ||
std::is_same_v<std::decay_t<T>, int32_t> ||
std::is_same_v<std::decay_t<T>, uint32_t>),
int> = 0>
inline void bind_value([[maybe_unused]] sqlite3_stmt* stmt,
[[maybe_unused]] int position, [[maybe_unused]] T& _value,
[[maybe_unused]] const std::string& query)
{
throw std::runtime_error("Unsupported type for binding!");
}
template <typename T,
std::enable_if_t<common::traits::is_string_literal<T>(), int> = 0>
inline void bind_value(sqlite3_stmt* stmt, int position, T&& _value,
const std::string& query)
{
validate_sqlite3_result(
sqlite3_bind_text(stmt, position, _value, -1, SQLITE_STATIC), query.c_str(),
"Failed to bind text! Position: ", position, ", Value: ", _value);
}
template <typename T,
std::enable_if_t<std::is_floating_point_v<std::decay_t<T>>, int> = 0>
inline void bind_value(sqlite3_stmt* stmt, int position, T&& _value,
const std::string& query)
{
validate_sqlite3_result(
sqlite3_bind_double(stmt, position, _value), query.c_str(),
"Failed to bind double! Position: ", position, ", Value: ", _value);
}
template <typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, int64_t> ||
std::is_same_v<std::decay_t<T>, uint64_t>,
int> = 0>
inline void bind_value(sqlite3_stmt* stmt, int position, T&& _value,
const std::string& query)
{
validate_sqlite3_result(sqlite3_bind_int64(stmt, position, _value), query.c_str(),
"Failed to bind int64_t/uint64_t! Position: ", position,
", Value: ", _value);
}
template <typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, int32_t> ||
std::is_same_v<std::decay_t<T>, uint32_t>,
int> = 0>
inline void bind_value(sqlite3_stmt* stmt, int position, T&& _value,
const std::string& query)
{
validate_sqlite3_result(sqlite3_bind_int(stmt, position, _value), query.c_str(),
"Failed to bind int32_t/uint32_t! Position: ", position,
", Value: ", _value);
}
public:
void initialize_schema();
void execute_query(const std::string& query);
size_t get_last_insert_id() const;
/**
* This function prepares an SQLite statement based on the provided SQL query and
* returns a lambda that can execute the prepared statement, binding the provided
* values to the respective placeholders in the query.
*/
template <typename... Values>
auto create_statement_executor(const std::string& query)
{
sqlite3_stmt* p_stmt;
validate_sqlite3_result(
sqlite3_prepare_v2(_sqlite3_db_temp, query.c_str(), -1, &p_stmt, nullptr),
query.c_str(), "Failed to create statement!");
std::shared_ptr<sqlite3_stmt> stmt{ p_stmt, sqlite3_finalize };
return [stmt, query, this](Values... value) {
std::lock_guard lock{ _mutex };
int position = 1;
((bind_value(stmt.get(), position++, value, query)), ...);
validate_sqlite3_result(sqlite3_step(stmt.get()), query.c_str(),
"Failed to execute step!\n", "Values: ", value...);
sqlite3_reset(stmt.get());
};
}
static std::string get_upid();
private:
sqlite3* _sqlite3_db{ nullptr };
sqlite3* _sqlite3_db_temp{ nullptr };
};
} // namespace data_storage
} // namespace rocpd
} // namespace rocprofsys
@@ -0,0 +1,126 @@
// MIT License
//
// Copyright (c) 2025 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/traits.hpp"
#include <sstream>
#include <string>
#include <type_traits>
namespace rocprofsys
{
namespace rocpd
{
namespace data_storage
{
namespace queries
{
namespace query_builders
{
struct query_value_builder
{
query_value_builder(std::stringstream& ss)
: _ss{ ss }
{}
template <typename... Values>
query_value_builder& set_values(Values&&... values)
{
auto i = sizeof...(values);
_ss << "( ";
((process_value(values) << (i-- > 1 ? ", " : " ")), ...);
_ss << ")";
return *this;
}
std::string get_query_string() { return _ss.str(); }
private:
template <typename T>
std::enable_if_t<common::traits::is_string_literal<T>(), std::stringstream&>
process_value(T& value)
{
_ss << "\"" << value << "\"";
return _ss;
}
template <typename T>
std::enable_if_t<common::traits::is_optional_v<std::decay_t<T>>, std::stringstream&>
process_value(T& value)
{
if(value.has_value())
{
_ss << value.value();
}
else
{
_ss << "NULL";
}
return _ss;
}
template <typename T>
std::enable_if_t<!common::traits::is_string_literal<T>() &&
!common::traits::is_optional_v<std::decay_t<T>>,
std::stringstream&>
process_value(T& value)
{
_ss << value;
return _ss;
}
private:
std::stringstream& _ss;
};
struct query_columns_builder
{
query_columns_builder(std::stringstream& ss)
: _ss{ ss }
, _query_value_builder{ _ss }
{}
template <typename... Columns,
typename =
std::enable_if_t<(common::traits::is_string_literal<Columns>() && ...)>>
query_value_builder& set_columns(Columns&... columns)
{
auto i = sizeof...(columns);
_ss << "( ";
((_ss << columns << (i-- > 1 ? ", " : " ")), ...) << ") VALUES ";
return _query_value_builder;
}
private:
std::stringstream& _ss;
query_value_builder _query_value_builder;
};
} // namespace query_builders
} // namespace queries
} // namespace data_storage
} // namespace rocpd
} // namespace rocprofsys
@@ -0,0 +1,722 @@
--
-- Useful views
--
-- Code objects
CREATE VIEW IF NOT EXISTS
`code_objects` AS
SELECT
CO.id,
CO.guid,
CO.nid,
P.pid,
A.absolute_index AS agent_abs_index,
CO.uri,
CO.load_base,
CO.load_size,
CO.load_delta,
CO.storage_type AS storage_type_str,
JSON_EXTRACT(CO.extdata, '$.size') AS code_object_size,
JSON_EXTRACT(CO.extdata, '$.storage_type') AS storage_type,
JSON_EXTRACT(CO.extdata, '$.memory_base') AS memory_base,
JSON_EXTRACT(CO.extdata, '$.memory_size') AS memory_size
FROM
`rocpd_info_code_object` CO
INNER JOIN `rocpd_info_agent` A ON CO.agent_id = A.id
AND CO.guid = A.guid
INNER JOIN `rocpd_info_process` P ON CO.pid = P.id
AND CO.guid = P.guid;
CREATE VIEW IF NOT EXISTS
`kernel_symbols` AS
SELECT
KS.id,
KS.guid,
KS.nid,
P.pid,
KS.code_object_id,
KS.kernel_name,
KS.display_name,
KS.kernel_object,
KS.kernarg_segment_size,
KS.kernarg_segment_alignment,
KS.group_segment_size,
KS.private_segment_size,
KS.sgpr_count,
KS.arch_vgpr_count,
KS.accum_vgpr_count,
JSON_EXTRACT(KS.extdata, '$.size') AS kernel_symbol_size,
JSON_EXTRACT(KS.extdata, '$.kernel_id') AS kernel_id,
JSON_EXTRACT(KS.extdata, '$.kernel_code_entry_byte_offset') AS kernel_code_entry_byte_offset,
JSON_EXTRACT(KS.extdata, '$.formatted_kernel_name') AS formatted_kernel_name,
JSON_EXTRACT(KS.extdata, '$.demangled_kernel_name') AS demangled_kernel_name,
JSON_EXTRACT(KS.extdata, '$.truncated_kernel_name') AS truncated_kernel_name,
JSON_EXTRACT(KS.extdata, '$.kernel_address.handle') AS kernel_address
FROM
`rocpd_info_kernel_symbol` KS
INNER JOIN `rocpd_info_process` P ON KS.pid = P.id
AND KS.guid = P.guid;
-- Processes
CREATE VIEW IF NOT EXISTS
`processes` AS
SELECT
N.id AS nid,
N.machine_id,
N.system_name,
N.hostname,
N.release AS system_release,
N.version AS system_version,
P.guid,
P.ppid,
P.pid,
P.init,
P.start,
P.end,
P.fini,
P.command
FROM
`rocpd_info_process` P
INNER JOIN `rocpd_info_node` N ON N.id = P.nid
AND N.guid = P.guid;
-- Threads
CREATE VIEW IF NOT EXISTS
`threads` AS
SELECT
N.id AS nid,
N.machine_id,
N.system_name,
N.hostname,
N.release AS system_release,
N.version AS system_version,
P.guid,
P.ppid,
P.pid,
T.tid,
T.start,
T.end,
T.name
FROM
`rocpd_info_thread` T
INNER JOIN `rocpd_info_process` P ON P.id = T.pid
AND N.guid = T.guid
INNER JOIN `rocpd_info_node` N ON N.id = T.nid
AND N.guid = T.guid;
-- CPU regions
CREATE VIEW IF NOT EXISTS
`regions` AS
SELECT
R.id,
R.guid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
S.string AS name,
R.nid,
P.pid,
T.tid,
R.start,
R.end,
(R.end - R.start) AS duration,
R.event_id,
E.stack_id,
E.parent_stack_id,
E.correlation_id AS corr_id,
E.extdata,
E.call_stack,
E.line_info
FROM
`rocpd_region` R
INNER JOIN `rocpd_event` E ON E.id = R.event_id
AND E.guid = R.guid
INNER JOIN `rocpd_string` S ON S.id = R.name_id
AND S.guid = R.guid
INNER JOIN `rocpd_info_process` P ON P.id = R.pid
AND P.guid = R.guid
INNER JOIN `rocpd_info_thread` T ON T.id = R.tid
AND T.guid = R.guid;
CREATE VIEW IF NOT EXISTS
`region_args` AS
SELECT
R.id,
R.guid,
R.nid,
P.pid,
A.type,
A.name,
A.value
FROM
`rocpd_region` R
INNER JOIN `rocpd_event` E ON E.id = R.event_id
AND E.guid = R.guid
INNER JOIN `rocpd_arg` A ON A.event_id = E.id
AND A.guid = R.guid
INNER JOIN `rocpd_info_process` P ON P.id = R.pid
AND P.guid = R.guid;
--
-- Samples
CREATE VIEW IF NOT EXISTS
`samples` AS
SELECT
R.id,
R.guid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = T.name_id
AND RS.guid = T.guid
) AS name,
T.nid,
P.pid,
TH.tid,
R.timestamp,
R.event_id,
E.stack_id AS stack_id,
E.parent_stack_id AS parent_stack_id,
E.correlation_id AS corr_id,
E.extdata AS extdata,
E.call_stack AS call_stack,
E.line_info AS line_info
FROM
`rocpd_sample` R
INNER JOIN `rocpd_track` T ON T.id = R.track_id
AND T.guid = R.guid
INNER JOIN `rocpd_event` E ON E.id = R.event_id
AND E.guid = R.guid
INNER JOIN `rocpd_info_process` P ON P.id = T.pid
AND P.guid = T.guid
INNER JOIN `rocpd_info_thread` TH ON TH.id = T.tid
AND TH.guid = T.guid;
--
-- Provides samples view with the same columns as regions view
CREATE VIEW IF NOT EXISTS
`sample_regions` AS
SELECT
R.id,
R.guid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = T.name_id
AND RS.guid = T.guid
) AS name,
T.nid,
P.pid,
TH.tid,
R.timestamp AS start,
R.timestamp AS END,
(R.timestamp - R.timestamp) AS duration,
R.event_id,
E.stack_id AS stack_id,
E.parent_stack_id AS parent_stack_id,
E.correlation_id AS corr_id,
E.extdata AS extdata,
E.call_stack AS call_stack,
E.line_info AS line_info
FROM
`rocpd_sample` R
INNER JOIN `rocpd_track` T ON T.id = R.track_id
AND T.guid = R.guid
INNER JOIN `rocpd_event` E ON E.id = R.event_id
AND E.guid = R.guid
INNER JOIN `rocpd_info_process` P ON P.id = T.pid
AND P.guid = T.guid
INNER JOIN `rocpd_info_thread` TH ON TH.id = T.tid
AND TH.guid = T.guid;
--
-- Provides a unified view of the regions and samples
CREATE VIEW IF NOT EXISTS
`regions_and_samples` AS
SELECT
*
FROM
`regions`
UNION ALL
SELECT
*
FROM
`sample_regions`;
--
-- Kernel information
CREATE VIEW
`kernels` AS
SELECT
K.id,
K.guid,
T.tid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
R.string AS region,
S.display_name AS name,
K.nid,
P.pid,
A.absolute_index AS agent_abs_index,
A.logical_index AS agent_log_index,
A.type_index AS agent_type_index,
A.type AS agent_type,
S.code_object_id AS code_object_id,
K.kernel_id,
K.dispatch_id,
K.stream_id,
K.queue_id,
Q.name AS queue,
ST.name AS stream,
K.start,
K.end,
(K.end - K.start) AS duration,
K.grid_size_x AS grid_x,
K.grid_size_y AS grid_y,
K.grid_size_z AS grid_z,
K.workgroup_size_x AS workgroup_x,
K.workgroup_size_y AS workgroup_y,
K.workgroup_size_z AS workgroup_z,
K.group_segment_size AS lds_size,
K.private_segment_size AS scratch_size,
S.group_segment_size AS static_lds_size,
S.private_segment_size AS static_scratch_size,
E.stack_id,
E.parent_stack_id,
E.correlation_id AS corr_id
FROM
`rocpd_kernel_dispatch` K
INNER JOIN `rocpd_info_agent` A ON A.id = K.agent_id
AND A.guid = K.guid
INNER JOIN `rocpd_event` E ON E.id = K.event_id
AND E.guid = K.guid
INNER JOIN `rocpd_string` R ON R.id = K.region_name_id
AND R.guid = K.guid
INNER JOIN `rocpd_info_kernel_symbol` S ON S.id = K.kernel_id
AND S.guid = K.guid
LEFT JOIN `rocpd_info_stream` ST ON ST.id = K.stream_id
AND ST.guid = K.guid
LEFT JOIN `rocpd_info_queue` Q ON Q.id = K.queue_id
AND Q.guid = K.guid
INNER JOIN `rocpd_info_process` P ON P.id = Q.pid
AND P.guid = Q.guid
INNER JOIN `rocpd_info_thread` T ON T.id = K.tid
AND T.guid = K.guid;
--
-- Performance Monitoring Counters (PMC)
CREATE VIEW IF NOT EXISTS
`pmc_info` AS
SELECT
PMC_I.id,
PMC_I.guid,
PMC_I.nid,
P.pid,
A.absolute_index AS agent_abs_index,
PMC_I.is_constant,
PMC_I.is_derived,
PMC_I.name,
PMC_I.description,
PMC_I.block,
PMC_I.expression
FROM
`rocpd_info_pmc` PMC_I
INNER JOIN `rocpd_info_agent` A ON PMC_I.agent_id = A.id
AND PMC_I.guid = A.guid
INNER JOIN `rocpd_info_process` P ON P.id = PMC_I.pid
AND PMC_I.guid = P.guid;
CREATE VIEW IF NOT EXISTS
`pmc_events` AS
SELECT
PMC_E.id,
PMC_E.guid,
PMC_E.pmc_id,
E.id AS event_id,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
(
SELECT
display_name
FROM
`rocpd_info_kernel_symbol` KS
WHERE
KS.id = K.kernel_id
AND KS.guid = K.guid
) AS name,
K.nid,
P.pid,
K.dispatch_id,
K.start,
K.end,
(K.end - K.start) AS duration,
PMC_I.name AS counter_name,
PMC_E.value AS counter_value
FROM
`rocpd_pmc_event` PMC_E
INNER JOIN `rocpd_info_pmc` PMC_I ON PMC_I.id = PMC_E.pmc_id
AND PMC_I.guid = PMC_E.guid
INNER JOIN `rocpd_event` E ON E.id = PMC_E.event_id
AND E.guid = PMC_E.guid
INNER JOIN `rocpd_kernel_dispatch` K ON K.event_id = PMC_E.event_id
AND K.guid = PMC_E.guid
INNER JOIN `rocpd_info_process` P ON P.id = K.pid
AND P.guid = K.guid;
-- events with arguments ---
CREATE VIEW IF NOT EXISTS
`events_args` AS
SELECT
E.id AS event_id,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
E.stack_id,
E.parent_stack_id,
E.correlation_id,
A.position AS arg_position,
A.type AS arg_type,
A.name AS arg_name,
A.value AS arg_value,
E.call_stack,
E.line_info,
A.extdata
FROM
`rocpd_event` E
INNER JOIN `rocpd_arg` A ON A.event_id = E.id
AND A.guid = E.guid;
-- list of astream arguments enriched by the corresponding stream descriptions
CREATE VIEW IF NOT EXISTS
`stream_args` AS
SELECT
A.id AS argument_id,
A.event_id AS event_id,
A.position AS arg_position,
A.type AS arg_type,
A.value AS arg_value,
JSON_EXTRACT(A.extdata, '$.stream_id') AS stream_id,
S.nid,
P.pid,
S.name AS stream_name,
S.extdata AS extdata
FROM
`rocpd_arg` A
INNER JOIN `rocpd_info_stream` S ON JSON_EXTRACT(A.extdata, '$.stream_id') = S.id
AND A.guid = S.guid
INNER JOIN `rocpd_info_process` P ON P.id = S.pid
AND P.guid = S.guid
WHERE
A.name = 'stream';
--
--
CREATE VIEW IF NOT EXISTS
`memory_copies` AS
SELECT
M.id,
M.guid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
M.nid,
P.pid,
T.tid,
M.start,
M.end,
(M.end - M.start) AS duration,
S.string AS name,
R.string AS region_name,
M.stream_id,
M.queue_id,
ST.name AS stream_name,
Q.name AS queue_name,
M.size,
dst_agent.name AS dst_device,
dst_agent.absolute_index AS dst_agent_abs_index,
dst_agent.logical_index AS dst_agent_log_index,
dst_agent.type_index AS dst_agent_type_index,
dst_agent.type AS dst_agent_type,
M.dst_address,
src_agent.name AS src_device,
src_agent.absolute_index AS src_agent_abs_index,
src_agent.logical_index AS src_agent_log_index,
src_agent.type_index AS src_agent_type_index,
src_agent.type AS src_agent_type,
M.src_address,
E.stack_id,
E.parent_stack_id,
E.correlation_id AS corr_id
FROM
`rocpd_memory_copy` M
INNER JOIN `rocpd_string` S ON S.id = M.name_id
AND S.guid = M.guid
LEFT JOIN `rocpd_string` R ON R.id = M.region_name_id
AND R.guid = M.guid
INNER JOIN `rocpd_info_agent` dst_agent ON dst_agent.id = M.dst_agent_id
AND dst_agent.guid = M.guid
INNER JOIN `rocpd_info_agent` src_agent ON src_agent.id = M.src_agent_id
AND src_agent.guid = M.guid
LEFT JOIN `rocpd_info_queue` Q ON Q.id = M.queue_id
AND Q.guid = M.guid
LEFT JOIN `rocpd_info_stream` ST ON ST.id = M.stream_id
AND ST.guid = M.guid
INNER JOIN `rocpd_event` E ON E.id = M.event_id
AND E.guid = M.guid
INNER JOIN `rocpd_info_process` P ON P.id = M.pid
AND P.guid = M.guid
INNER JOIN `rocpd_info_thread` T ON T.id = M.tid
AND T.guid = M.guid;
--
--
CREATE VIEW IF NOT EXISTS
`memory_allocations` AS
SELECT
M.id,
M.guid,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
M.nid,
P.pid,
T.tid,
M.start,
M.end,
(M.end - M.start) AS duration,
M.type,
M.level,
A.name AS agent_name,
A.absolute_index AS agent_abs_index,
A.logical_index AS agent_log_index,
A.type_index AS agent_type_index,
A.type AS agent_type,
M.address,
M.size,
M.queue_id,
Q.name AS queue_name,
M.stream_id,
ST.name AS stream_name,
E.stack_id,
E.parent_stack_id,
E.correlation_id AS corr_id
FROM
`rocpd_memory_allocate` M
LEFT JOIN `rocpd_info_agent` A ON M.agent_id = A.id
AND M.guid = A.guid
LEFT JOIN `rocpd_info_queue` Q ON Q.id = M.queue_id
AND Q.guid = M.guid
LEFT JOIN `rocpd_info_stream` ST ON ST.id = M.stream_id
AND ST.guid = M.guid
INNER JOIN `rocpd_event` E ON E.id = M.event_id
AND E.guid = M.guid
INNER JOIN `rocpd_info_process` P ON P.id = M.pid
AND P.guid = M.guid
INNER JOIN `rocpd_info_thread` T ON T.id = M.tid
AND P.guid = M.guid;
--
--
CREATE VIEW IF NOT EXISTS
`scratch_memory` AS
SELECT
M.id,
M.guid,
M.nid,
P.pid,
M.type AS operation,
A.name AS agent_name,
A.absolute_index AS agent_abs_index,
A.logical_index AS agent_log_index,
A.type_index AS agent_type_index,
A.type AS agent_type,
M.queue_id,
T.tid,
JSON_EXTRACT(M.extdata, '$.flags') AS alloc_flags,
M.start,
M.end,
M.size,
M.address,
E.correlation_id,
E.stack_id,
E.parent_stack_id,
E.correlation_id AS corr_id,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
E.extdata AS event_extdata
FROM
`rocpd_memory_allocate` M
LEFT JOIN `rocpd_info_agent` A ON M.agent_id = A.id
AND M.guid = A.guid
LEFT JOIN `rocpd_info_queue` Q ON Q.id = M.queue_id
AND Q.guid = M.guid
INNER JOIN `rocpd_event` E ON E.id = M.event_id
AND E.guid = M.guid
INNER JOIN `rocpd_info_process` P ON P.id = M.pid
AND P.guid = M.guid
INNER JOIN `rocpd_info_thread` T ON T.id = M.tid
AND T.guid = M.guid
WHERE
M.level = 'SCRATCH'
ORDER BY
M.start ASC;
--
--
CREATE VIEW IF NOT EXISTS
`counters_collection` AS
SELECT
MIN(PMC_E.id) AS id,
PMC_E.guid,
K.dispatch_id,
K.kernel_id,
E.id AS event_id,
E.correlation_id,
E.stack_id,
E.parent_stack_id,
P.pid,
T.tid,
K.agent_id,
A.absolute_index AS agent_abs_index,
A.logical_index AS agent_log_index,
A.type_index AS agent_type_index,
A.type AS agent_type,
K.queue_id,
k.grid_size_x AS grid_size_x,
k.grid_size_y AS grid_size_y,
k.grid_size_z AS grid_size_z,
(K.grid_size_x * K.grid_size_y * K.grid_size_z) AS grid_size,
S.display_name AS kernel_name,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = K.region_name_id
AND RS.guid = K.guid
) AS kernel_region,
K.workgroup_size_x AS workgroup_size_x,
K.workgroup_size_y AS workgroup_size_y,
K.workgroup_size_z AS workgroup_size_z,
(K.workgroup_size_x * K.workgroup_size_y * K.workgroup_size_z) AS workgroup_size,
K.group_segment_size AS lds_block_size,
K.private_segment_size AS scratch_size,
S.arch_vgpr_count AS vgpr_count,
S.accum_vgpr_count,
S.sgpr_count,
PMC_I.name AS counter_name,
PMC_I.symbol AS counter_symbol,
PMC_I.component,
PMC_I.description,
PMC_I.block,
PMC_I.expression,
PMC_I.value_type,
PMC_I.id AS counter_id,
SUM(PMC_E.value) AS value,
K.start,
K.end,
PMC_I.is_constant,
PMC_I.is_derived,
(K.end - K.start) AS duration,
(
SELECT
string
FROM
`rocpd_string` RS
WHERE
RS.id = E.category_id
AND RS.guid = E.guid
) AS category,
K.nid,
E.extdata,
S.code_object_id
FROM
`rocpd_pmc_event` PMC_E
INNER JOIN `rocpd_info_pmc` PMC_I ON PMC_I.id = PMC_E.pmc_id
AND PMC_I.guid = PMC_E.guid
INNER JOIN `rocpd_event` E ON E.id = PMC_E.event_id
AND E.guid = PMC_E.guid
INNER JOIN `rocpd_kernel_dispatch` K ON K.event_id = PMC_E.event_id
AND K.guid = PMC_E.guid
INNER JOIN `rocpd_info_agent` A ON A.id = K.agent_id
AND A.guid = K.guid
INNER JOIN `rocpd_info_kernel_symbol` S ON S.id = K.kernel_id
AND S.guid = K.guid
INNER JOIN `rocpd_info_process` P ON P.id = K.pid
AND P.guid = K.guid
INNER JOIN `rocpd_info_thread` T ON T.id = K.tid
AND T.guid = K.guid
GROUP BY
PMC_E.guid,
K.dispatch_id,
PMC_I.name,
K.agent_id;
@@ -0,0 +1,3 @@
--
-- Views related to markers
--
@@ -0,0 +1,45 @@
--
-- Indexes for the various fields
--
-- string field
-- CREATE INDEX `rocpd_string{{uuid}}_string_idx` ON `rocpd_string{{uuid}}` ("string");
-- guid field
-- CREATE INDEX `rocpd_string{{uuid}}_guid_idx` ON `rocpd_string{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_node{{uuid}}_guid_idx` ON `rocpd_info_node{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_process{{uuid}}_guid_idx` ON `rocpd_info_process{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_thread{{uuid}}_guid_idx` ON `rocpd_info_thread{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_agent{{uuid}}_guid_idx` ON `rocpd_info_agent{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_queue{{uuid}}_guid_idx` ON `rocpd_info_queue{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_stream{{uuid}}_guid_idx` ON `rocpd_info_stream{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_pmc{{uuid}}_guid_idx` ON `rocpd_info_pmc{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_code_object{{uuid}}_guid_idx` ON `rocpd_info_code_object{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_info_kernel_symbol{{uuid}}_guid_idx` ON `rocpd_info_kernel_symbol{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_track{{uuid}}_guid_idx` ON `rocpd_track{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_event{{uuid}}_guid_idx` ON `rocpd_event{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_arg{{uuid}}_guid_idx` ON `rocpd_arg{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_pmc_event{{uuid}}_guid_idx` ON `rocpd_pmc_event{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_region{{uuid}}_guid_idx` ON `rocpd_region{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_sample{{uuid}}_guid_idx` ON `rocpd_sample{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_kernel_dispatch{{uuid}}_guid_idx` ON `rocpd_kernel_dispatch{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_memory_copy{{uuid}}_guid_idx` ON `rocpd_memory_copy{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_memory_allocate{{uuid}}_guid_idx` ON `rocpd_memory_allocate{{uuid}}` ("id", "guid");
-- CREATE INDEX `rocpd_event{{uuid}}_category_idx` ON `rocpd_event{{uuid}}` ("id", "guid", "category_id");
-- CREATE INDEX `rocpd_region{{uuid}}_event_idx` ON `rocpd_region{{uuid}}` ("id", "guid", "event_id");
-- CREATE INDEX `rocpd_region{{uuid}}_name_idx` ON `rocpd_region{{uuid}}` ("id", "guid", "name_id");
-- CREATE INDEX `rocpd_sample{{uuid}}_event_idx` ON `rocpd_sample{{uuid}}` ("id", "guid", "event_id");
-- CREATE INDEX `rocpd_sample{{uuid}}_track_idx` ON `rocpd_sample{{uuid}}` ("id", "guid", "track_id");
-- CREATE INDEX `rocpd_track{{uuid}}_name_idx` ON `rocpd_track{{uuid}}` ("id", "guid", "name_id");
-- CREATE INDEX `rocpd_memory_copy{{uuid}}_guid_nid_pid_idx` ON `rocpd_memory_copy{{uuid}}` ("guid", "nid", "pid");
-- CREATE INDEX `rocpd_kernel_dispatch{{uuid}}_guid_nid_pid_idx` ON `rocpd_kernel_dispatch{{uuid}}` ("guid", "nid", "pid");
-- CREATE INDEX `rocpd_region{{uuid}}_guid_idx` ON `rocpd_region{{uuid}}` ("guid", "nid", "pid");
-- CREATE INDEX `rocpd_sample{{uuid}}_guid_nid_pid_idx` ON `rocpd_sample{{uuid}}` ("guid", "nid", "pid");
-- CREATE INDEX `rocpd_region{{uuid}}_guid_idx` ON `rocpd_region{{uuid}}` ("guid");
-- CREATE INDEX `rocpd_region{{uuid}}_nid_idx` ON `rocpd_region{{uuid}}` ("nid");
-- CREATE INDEX `rocpd_region{{uuid}}_pid_idx` ON `rocpd_region{{uuid}}` ("pid");
-- CREATE INDEX `rocpd_region{{uuid}}_start_idx` ON `rocpd_region{{uuid}}` ("start");
-- CREATE INDEX `rocpd_region{{uuid}}_end_idx` ON `rocpd_region{{uuid}}` ("end");
@@ -0,0 +1,373 @@
-- Enable foreign key support for cascading
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS
"rocpd_metadata{{uuid}}" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"tag" TEXT NOT NULL,
"value" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS
`rocpd_string{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"string" TEXT NOT NULL UNIQUE ON CONFLICT ABORT
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_node{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"hash" BIGINT NOT NULL UNIQUE,
"machine_id" TEXT NOT NULL UNIQUE,
"system_name" TEXT,
"hostname" TEXT,
"release" TEXT,
"version" TEXT,
"hardware_name" TEXT,
"domain_name" TEXT
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_process{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"ppid" INTEGER,
"pid" INTEGER NOT NULL,
"init" BIGINT,
"fini" BIGINT,
"start" BIGINT,
"end" BIGINT,
"command" TEXT,
"environment" JSONB DEFAULT "{}" NOT NULL,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_thread{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"ppid" INTEGER,
"pid" INTEGER NOT NULL,
"tid" INTEGER NOT NULL,
"name" TEXT,
"start" BIGINT,
"end" BIGINT,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_agent{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"type" TEXT CHECK ("type" IN ('CPU', 'GPU')),
"absolute_index" INTEGER,
"logical_index" INTEGER,
"type_index" INTEGER,
"uuid" INTEGER,
"name" TEXT,
"model_name" TEXT,
"vendor_name" TEXT,
"product_name" TEXT,
"user_name" TEXT,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_queue{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"name" TEXT,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_stream{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"name" TEXT,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE
);
-- 2993533, 2269219937, 2993533
-- 2993533, 2269219937, 2993533
-- Performance monitoring counters (PMC) descriptions
CREATE TABLE IF NOT EXISTS
`rocpd_info_pmc{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"agent_id" INTEGER,
"target_arch" TEXT CHECK ("target_arch" IN ('CPU', 'GPU')),
"event_code" INT,
"instance_id" INTEGER,
"name" TEXT NOT NULL,
"symbol" TEXT NOT NULL,
"description" TEXT,
"long_description" TEXT DEFAULT "",
"component" TEXT,
"units" TEXT DEFAULT "",
"value_type" TEXT CHECK ("value_type" IN ('ABS', 'ACCUM', 'RELATIVE')),
"block" TEXT,
"expression" TEXT,
"is_constant" INTEGER,
"is_derived" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_code_object{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"agent_id" INTEGER,
"uri" TEXT,
"load_base" BIGINT,
"load_size" BIGINT,
"load_delta" BIGINT,
"storage_type" TEXT CHECK ("storage_type" IN ('FILE', 'MEMORY')),
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_info_kernel_symbol{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"code_object_id" INTEGER NOT NULL,
"kernel_name" TEXT,
"display_name" TEXT,
"kernel_object" INTEGER,
"kernarg_segment_size" INTEGER,
"kernarg_segment_alignment" INTEGER,
"group_segment_size" INTEGER,
"private_segment_size" INTEGER,
"sgpr_count" INTEGER,
"arch_vgpr_count" INTEGER,
"accum_vgpr_count" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (code_object_id) REFERENCES `rocpd_info_code_object{{uuid}}` (id) ON UPDATE CASCADE
);
-- Stores repetitive info for samples
CREATE TABLE IF NOT EXISTS
`rocpd_track{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER,
"tid" INTEGER,
"name_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES `rocpd_info_thread{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (name_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE
);
-- Storage for a region, instant, and counter
CREATE TABLE IF NOT EXISTS
`rocpd_event{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"category_id" INTEGER,
"stack_id" INTEGER,
"parent_stack_id" INTEGER,
"correlation_id" INTEGER,
"call_stack" JSONB DEFAULT "{}" NOT NULL,
"line_info" JSONB DEFAULT "{}" NOT NULL,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (category_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE
);
-- stores arguments for events
CREATE TABLE IF NOT EXISTS
`rocpd_arg{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"event_id" INTEGER NOT NULL,
"position" INTEGER NOT NULL,
"type" TEXT NOT NULL,
"name" TEXT NOT NULL,
"value" TEXT, -- TODO: discuss make it value_id and integer, refer to string table --
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
-- Region with a start/stop on the same thread (CPU)
CREATE TABLE IF NOT EXISTS
`rocpd_pmc_event{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"event_id" INTEGER,
"pmc_id" INTEGER NOT NULL,
"value" REAL DEFAULT 0.0,
"extdata" JSONB DEFAULT "{}",
FOREIGN KEY (pmc_id) REFERENCES `rocpd_info_pmc{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
-- Region with a start/stop on the same thread (CPU)
CREATE TABLE IF NOT EXISTS
`rocpd_region{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"tid" INTEGER NOT NULL,
"start" BIGINT NOT NULL,
"end" BIGINT NOT NULL,
"name_id" INTEGER NOT NULL,
"event_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES `rocpd_info_thread{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (name_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
-- Instantaneous sample
CREATE TABLE IF NOT EXISTS
`rocpd_sample{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"track_id" INTEGER NOT NULL,
"timestamp" BIGINT NOT NULL,
"event_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (track_id) REFERENCES `rocpd_track{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_kernel_dispatch{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"tid" INTEGER,
"agent_id" INTEGER NOT NULL,
"kernel_id" INTEGER NOT NULL,
"dispatch_id" INTEGER NOT NULL,
"queue_id" INTEGER NOT NULL,
"stream_id" INTEGER NOT NULL,
"start" BIGINT NOT NULL,
"end" BIGINT NOT NULL,
"private_segment_size" INTEGER,
"group_segment_size" INTEGER,
"workgroup_size_x" INTEGER NOT NULL,
"workgroup_size_y" INTEGER NOT NULL,
"workgroup_size_z" INTEGER NOT NULL,
"grid_size_x" INTEGER NOT NULL,
"grid_size_y" INTEGER NOT NULL,
"grid_size_z" INTEGER NOT NULL,
"region_name_id" INTEGER,
"event_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES `rocpd_info_thread{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (kernel_id) REFERENCES `rocpd_info_kernel_symbol{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (queue_id) REFERENCES `rocpd_info_queue{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (stream_id) REFERENCES `rocpd_info_stream{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (region_name_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS
`rocpd_memory_copy{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"tid" INTEGER,
"start" BIGINT NOT NULL,
"end" BIGINT NOT NULL,
"name_id" INTEGER NOT NULL,
"dst_agent_id" INTEGER,
"dst_address" INTEGER,
"src_agent_id" INTEGER,
"src_address" INTEGER,
"size" INTEGER NOT NULL,
"queue_id" INTEGER,
"stream_id" INTEGER,
"region_name_id" INTEGER,
"event_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES `rocpd_info_thread{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (name_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (dst_agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (src_agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (stream_id) REFERENCES `rocpd_info_stream{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (queue_id) REFERENCES `rocpd_info_queue{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (region_name_id) REFERENCES `rocpd_string{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
-- Memory allocations (real memory, virtual memory, and scratch memory)
CREATE TABLE IF NOT EXISTS
`rocpd_memory_allocate{{uuid}}` (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"guid" TEXT DEFAULT "{{guid}}" NOT NULL,
"nid" INTEGER NOT NULL,
"pid" INTEGER NOT NULL,
"tid" INTEGER,
"agent_id" INTEGER,
"type" TEXT CHECK ("type" IN ('ALLOC', 'FREE', 'REALLOC', 'RECLAIM')),
"level" TEXT CHECK ("level" IN ('REAL', 'VIRTUAL', 'SCRATCH')),
"start" BIGINT NOT NULL,
"end" BIGINT NOT NULL,
"address" INTEGER,
"size" INTEGER NOT NULL,
"queue_id" INTEGER,
"stream_id" INTEGER,
"event_id" INTEGER,
"extdata" JSONB DEFAULT "{}" NOT NULL,
FOREIGN KEY (nid) REFERENCES `rocpd_info_node{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (pid) REFERENCES `rocpd_info_process{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (tid) REFERENCES `rocpd_info_thread{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (agent_id) REFERENCES `rocpd_info_agent{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (stream_id) REFERENCES `rocpd_info_stream{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (queue_id) REFERENCES `rocpd_info_queue{{uuid}}` (id) ON UPDATE CASCADE,
FOREIGN KEY (event_id) REFERENCES `rocpd_event{{uuid}}` (id) ON UPDATE CASCADE
);
INSERT INTO
`rocpd_metadata{{uuid}}` ("tag", "value")
VALUES
("schema_version", "3"),
("uuid", "{{uuid}}"),
("guid", "{{guid}}");
@@ -0,0 +1,139 @@
CREATE VIEW IF NOT EXISTS
`rocpd_metadata` AS
SELECT
*
FROM
`rocpd_metadata{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_string` AS
SELECT
*
FROM
`rocpd_string{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_node` AS
SELECT
*
FROM
`rocpd_info_node{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_process` AS
SELECT
*
FROM
`rocpd_info_process{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_thread` AS
SELECT
*
FROM
`rocpd_info_thread{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_agent` AS
SELECT
*
FROM
`rocpd_info_agent{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_queue` AS
SELECT
*
FROM
`rocpd_info_queue{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_stream` AS
SELECT
*
FROM
`rocpd_info_stream{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_pmc` AS
SELECT
*
FROM
`rocpd_info_pmc{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_code_object` AS
SELECT
*
FROM
`rocpd_info_code_object{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_info_kernel_symbol` AS
SELECT
*
FROM
`rocpd_info_kernel_symbol{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_track` AS
SELECT
*
FROM
`rocpd_track{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_event` AS
SELECT
*
FROM
`rocpd_event{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_arg` AS
SELECT
*
FROM
`rocpd_arg{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_pmc_event` AS
SELECT
*
FROM
`rocpd_pmc_event{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_region` AS
SELECT
*
FROM
`rocpd_region{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_sample` AS
SELECT
*
FROM
`rocpd_sample{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_kernel_dispatch` AS
SELECT
*
FROM
`rocpd_kernel_dispatch{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_memory_copy` AS
SELECT
*
FROM
`rocpd_memory_copy{{uuid}}`;
CREATE VIEW IF NOT EXISTS
`rocpd_memory_allocate` AS
SELECT
*
FROM
`rocpd_memory_allocate{{uuid}}`;
@@ -0,0 +1,376 @@
--
-- Useful summary views
--
--
-- Sorted list of kernels which consume the most overall time
CREATE VIEW IF NOT EXISTS
`top_kernels` AS
SELECT
S.display_name AS name,
COUNT(K.kernel_id) AS total_calls,
SUM(K.end - K.start) / 1000.0 AS total_duration,
(SUM(K.end - K.start) / COUNT(K.kernel_id)) / 1000.0 AS average,
SUM(K.end - K.start) * 100.0 / (
SELECT
SUM(A.end - A.start)
FROM
`rocpd_kernel_dispatch` A
) AS percentage
FROM
`rocpd_kernel_dispatch` K
INNER JOIN `rocpd_info_kernel_symbol` S ON S.id = K.kernel_id
AND S.guid = K.guid
GROUP BY
name
ORDER BY
total_duration DESC;
--
-- GPU utilization metrics including kernels and memory copy operations
CREATE VIEW IF NOT EXISTS
`busy` AS
SELECT
A.agent_id,
AG.type,
GpuTime,
WallTime,
GpuTime * 1.0 / WallTime AS Busy
FROM
(
SELECT
agent_id,
guid,
SUM(END - start) AS GpuTime
FROM
(
SELECT
agent_id,
guid,
END,
start
FROM
`rocpd_kernel_dispatch`
UNION ALL
SELECT
dst_agent_id AS agent_id,
guid,
END,
start
FROM
`rocpd_memory_copy`
)
GROUP BY
agent_id,
guid
) A
INNER JOIN (
SELECT
MAX(END) - MIN(start) AS WallTime
FROM
(
SELECT
END,
start
FROM
`rocpd_kernel_dispatch`
UNION ALL
SELECT
END,
start
FROM
`rocpd_memory_copy`
)
) W ON 1 = 1
INNER JOIN `rocpd_info_agent` AG ON AG.id = A.agent_id
AND AG.guid = A.guid;
--
-- Overall performance summary including kernels and memory copy operations
CREATE VIEW
`top` AS
SELECT
name,
COUNT(*) AS total_calls,
SUM(duration) / 1000.0 AS total_duration,
(SUM(duration) / COUNT(*)) / 1000.0 AS average,
SUM(duration) * 100.0 / total_time AS percentage
FROM
(
-- Kernel operations
SELECT
ks.display_name AS name,
(kd.end - kd.start) AS duration
FROM
`rocpd_kernel_dispatch` kd
INNER JOIN `rocpd_info_kernel_symbol` ks ON kd.kernel_id = ks.id
AND kd.guid = ks.guid
UNION ALL
-- Memory operations
SELECT
rs.string AS name,
(END - start) AS duration
FROM
`rocpd_memory_copy` mc
INNER JOIN `rocpd_string` rs ON rs.id = mc.name_id
AND rs.guid = mc.guid
UNION ALL
-- Regions
SELECT
rs.string AS name,
(END - start) AS duration
FROM
`rocpd_region` rr
INNER JOIN `rocpd_string` rs ON rs.id = rr.name_id
AND rs.guid = rr.guid
) operations
CROSS JOIN (
SELECT
SUM(END - start) AS total_time
FROM
(
SELECT
END,
start
FROM
`rocpd_kernel_dispatch`
UNION ALL
SELECT
END,
start
FROM
`rocpd_memory_copy`
UNION ALL
SELECT
END,
start
FROM
`rocpd_region`
)
) TOTAL
GROUP BY
name
ORDER BY
total_duration DESC;
-- Kernel summary by name
CREATE VIEW
`kernel_summary` AS
WITH
avg_data AS (
SELECT
name,
AVG(duration) AS avg_duration
FROM
`kernels`
GROUP BY
name
),
aggregated_data AS (
SELECT
K.name,
COUNT(*) AS calls,
SUM(K.duration) AS total_duration,
SUM(CAST(K.duration AS REAL) * CAST(K.duration AS REAL)) AS sqr_duration,
A.avg_duration AS average_duration,
MIN(K.duration) AS min_duration,
MAX(K.duration) AS max_duration,
SUM(CAST((K.duration - A.avg_duration) AS REAL) * CAST((K.duration - A.avg_duration) AS REAL)) / (COUNT(*) - 1) AS variance_duration,
SQRT(
SUM(CAST((K.duration - A.avg_duration) AS REAL) * CAST((K.duration - A.avg_duration) AS REAL)) / (COUNT(*) - 1)
) AS std_dev_duration
FROM
`kernels` K
JOIN avg_data A ON K.name = A.name
GROUP BY
K.name
),
total_duration AS (
SELECT
SUM(total_duration) AS grand_total_duration
FROM
aggregated_data
)
SELECT
AD.name AS name,
AD.calls,
AD.total_duration AS "DURATION (nsec)",
AD.sqr_duration AS "SQR (nsec)",
AD.average_duration AS "AVERAGE (nsec)",
(CAST(AD.total_duration AS REAL) / TD.grand_total_duration) * 100 AS "PERCENT (INC)",
AD.min_duration AS "MIN (nsec)",
AD.max_duration AS "MAX (nsec)",
AD.variance_duration AS "VARIANCE",
AD.std_dev_duration AS "STD_DEV"
FROM
aggregated_data AD
CROSS JOIN total_duration TD;
--
-- Kernel summary by region name
CREATE VIEW
`kernel_summary_region` AS
WITH
avg_data AS (
SELECT
region,
AVG(duration) AS avg_duration
FROM
`kernels`
GROUP BY
region
),
aggregated_data AS (
SELECT
K.region AS name,
COUNT(*) AS calls,
SUM(K.duration) AS total_duration,
SUM(CAST(K.duration AS REAL) * CAST(K.duration AS REAL)) AS sqr_duration,
A.avg_duration AS average_duration,
MIN(K.duration) AS min_duration,
MAX(K.duration) AS max_duration,
SUM(CAST((K.duration - A.avg_duration) AS REAL) * CAST((K.duration - A.avg_duration) AS REAL)) / (COUNT(*) - 1) AS variance_duration,
SQRT(
SUM(CAST((K.duration - A.avg_duration) AS REAL) * CAST((K.duration - A.avg_duration) AS REAL)) / (COUNT(*) - 1)
) AS std_dev_duration
FROM
`kernels` K
JOIN avg_data A ON K.region = A.region
GROUP BY
K.region
),
total_duration AS (
SELECT
SUM(total_duration) AS grand_total_duration
FROM
aggregated_data
)
SELECT
AD.name AS name,
AD.calls,
AD.total_duration AS "DURATION (nsec)",
AD.sqr_duration AS "SQR (nsec)",
AD.average_duration AS "AVERAGE (nsec)",
(CAST(AD.total_duration AS REAL) / TD.grand_total_duration) * 100 AS "PERCENT (INC)",
AD.min_duration AS "MIN (nsec)",
AD.max_duration AS "MAX (nsec)",
AD.variance_duration AS "VARIANCE",
AD.std_dev_duration AS "STD_DEV"
FROM
aggregated_data AD
CROSS JOIN total_duration TD;
--
-- Memory copy summary
CREATE VIEW
`memory_copy_summary` AS
WITH
avg_data AS (
SELECT
name,
AVG(duration) AS avg_duration
FROM
`memory_copies`
GROUP BY
name
),
aggregated_data AS (
SELECT
MC.name,
COUNT(*) AS calls,
SUM(MC.duration) AS total_duration,
SUM(CAST(MC.duration AS REAL) * CAST(MC.duration AS REAL)) AS sqr_duration,
A.avg_duration AS average_duration,
MIN(MC.duration) AS min_duration,
MAX(MC.duration) AS max_duration,
SUM(
CAST((MC.duration - A.avg_duration) AS REAL) * CAST((MC.duration - A.avg_duration) AS REAL)
) / (COUNT(*) - 1) AS variance_duration,
SQRT(
SUM(
CAST((MC.duration - A.avg_duration) AS REAL) * CAST((MC.duration - A.avg_duration) AS REAL)
) / (COUNT(*) - 1)
) AS std_dev_duration
FROM
`memory_copies` MC
JOIN avg_data A ON MC.name = A.name
GROUP BY
MC.name
),
total_duration AS (
SELECT
SUM(total_duration) AS grand_total_duration
FROM
aggregated_data
)
SELECT
AD.name AS name,
AD.calls,
AD.total_duration AS "DURATION (nsec)",
AD.sqr_duration AS "SQR (nsec)",
AD.average_duration AS "AVERAGE (nsec)",
(CAST(AD.total_duration AS REAL) / TD.grand_total_duration) * 100 AS "PERCENT (INC)",
AD.min_duration AS "MIN (nsec)",
AD.max_duration AS "MAX (nsec)",
AD.variance_duration AS "VARIANCE",
AD.std_dev_duration AS "STD_DEV"
FROM
aggregated_data AD
CROSS JOIN total_duration TD;
--
-- Memory allocation summary
CREATE VIEW
`memory_allocation_summary` AS
WITH
avg_data AS (
SELECT
type AS name,
AVG(duration) AS avg_duration
FROM
`memory_allocations`
GROUP BY
type
),
aggregated_data AS (
SELECT
MA.type AS name,
COUNT(*) AS calls,
SUM(MA.duration) AS total_duration,
SUM(CAST(MA.duration AS REAL) * CAST(MA.duration AS REAL)) AS sqr_duration,
A.avg_duration AS average_duration,
MIN(MA.duration) AS min_duration,
MAX(MA.duration) AS max_duration,
SUM(
CAST((MA.duration - A.avg_duration) AS REAL) * CAST((MA.duration - A.avg_duration) AS REAL)
) / (COUNT(*) - 1) AS variance_duration,
SQRT(
SUM(
CAST((MA.duration - A.avg_duration) AS REAL) * CAST((MA.duration - A.avg_duration) AS REAL)
) / (COUNT(*) - 1)
) AS std_dev_duration
FROM
`memory_allocations` MA
JOIN avg_data A ON MA.type = A.name
GROUP BY
MA.type
),
total_duration AS (
SELECT
SUM(total_duration) AS grand_total_duration
FROM
aggregated_data
)
SELECT
'MEMORY_ALLOCATION_' || AD.name AS name,
AD.calls,
AD.total_duration AS "DURATION (nsec)",
AD.sqr_duration AS "SQR (nsec)",
AD.average_duration AS "AVERAGE (nsec)",
(CAST(AD.total_duration AS REAL) / TD.grand_total_duration) * 100 AS "PERCENT (INC)",
AD.min_duration AS "MIN (nsec)",
AD.max_duration AS "MAX (nsec)",
AD.variance_duration AS "VARIANCE",
AD.std_dev_duration AS "STD_DEV"
FROM
aggregated_data AD
CROSS JOIN total_duration TD;
@@ -0,0 +1,57 @@
// MIT License
//
// Copyright (c) 2025 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 "insert_query_builders.hpp"
namespace rocprofsys
{
namespace rocpd
{
namespace data_storage
{
namespace queries
{
struct table_insert_query
{
table_insert_query()
: _query_columns_builder{ _ss }
{}
query_builders::query_columns_builder& set_table_name(const std::string& tableName)
{
_ss.str("");
_ss << "INSERT INTO " << tableName << " ";
return _query_columns_builder;
}
private:
std::stringstream _ss;
query_builders::query_columns_builder _query_columns_builder;
};
} // namespace queries
} // namespace data_storage
} // namespace rocpd
} // namespace rocprofsys
+99
View File
@@ -0,0 +1,99 @@
// MIT License
//
// Copyright (c) 2025 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 "json.hpp"
#include <sstream>
namespace rocpd
{
std::shared_ptr<json>
json::create()
{
return std::shared_ptr<json>(new json());
}
void
json::set(const std::string& key, const json_value& value)
{
data[key] = std::make_shared<json_value>(value);
}
std::string
json::to_string() const
{
std::ostringstream oss;
oss << "{";
bool first = true;
for(const auto& [key, value] : data)
{
if(!first) oss << ", ";
first = false;
oss << "\"" << key << "\": " << stringify(value);
}
oss << "}";
return oss.str();
}
std::string
json::stringify(const std::shared_ptr<json_value>& value)
{
std::ostringstream oss;
std::visit(
[&oss](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, std::string>)
oss << "\"" << arg << "\"";
else if constexpr(std::is_same_v<T, bool>)
oss << (arg ? "true" : "false");
else if constexpr(std::is_same_v<T, std::nullptr_t>)
oss << "null";
else if constexpr(std::is_same_v<T, std::vector<json>>)
{
oss << "[";
bool first = true;
for(const auto& item : arg)
{
if(!first) oss << ", ";
first = false;
oss << item.to_string();
}
oss << "]";
}
else if constexpr(std::is_same_v<T, std::shared_ptr<json>>)
{
oss << arg->to_string();
}
else
{
// handle int + double
oss << arg;
}
},
*value);
return oss.str();
}
} // namespace rocpd
+57
View File
@@ -0,0 +1,57 @@
// MIT License
//
// Copyright (c) 2025 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 <memory>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace rocpd
{
class json
{
public:
static std::shared_ptr<json> create();
using json_value =
std::variant<std::string, int, double, long long, bool, std::vector<json>,
std::nullptr_t, std::shared_ptr<json>>;
void set(const std::string& key, const json_value& value);
std::string to_string() const;
private:
json() = default;
private:
static std::string stringify(const std::shared_ptr<json_value>& value);
private:
std::unordered_map<std::string, std::shared_ptr<json_value>> data;
};
} // namespace rocpd