[rocpd] Convert to perfetto does not display scratch_memory correctly - SWDEV-542550 (#168)
Add scratch memory to pftrace generated with rocpd ---- Co-authored-by: Marko Crnobrnja <Marko.Crnobrnja@amd.com> Co-authored-by: Aleksei Tumakaev <atumakae@amd.com> Co-authored-by: Jonathan R. Madsen <jrmadsen@users.noreply.github.com>
Cette révision appartient à :
révisé par
GitHub
Parent
93cfcb1a4e
révision
1e9d8abbf6
@@ -41,6 +41,7 @@
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/output/sql/common.hpp"
|
||||
#include "lib/output/sql/deferred_transaction.hpp"
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
@@ -1212,6 +1213,9 @@ write_rocpd(
|
||||
|
||||
auto insert_memory_alloc_data =
|
||||
[&conn, &tool_metadata, &string_entries, node_id, this_pid](const auto& _gen) {
|
||||
auto address_to_agent_and_size =
|
||||
std::unordered_map<rocprofiler_address_t, rocprofiler::agent::index_and_size>{};
|
||||
|
||||
for(auto pitr : _gen)
|
||||
{
|
||||
auto _deferred = sql::deferred_transaction{conn};
|
||||
@@ -1231,17 +1235,55 @@ write_rocpd(
|
||||
ROCP_FATAL_IF(_level != "REAL" && _level != "VIRTUAL" && _level != "SCRATCH")
|
||||
<< "erroneous db level: " << _level;
|
||||
|
||||
auto _node_id = std::optional<uint64_t>{};
|
||||
if(_type == "ALLOC")
|
||||
{
|
||||
_node_id = tool_metadata.get_agent(itr.agent_id)->node_id;
|
||||
}
|
||||
|
||||
auto _stream_id = get_stream_id(extract_stream_field(itr));
|
||||
auto _queue_id = get_queue_id(extract_queue_field(itr));
|
||||
auto _address = extract_address_field(itr);
|
||||
auto _allocation_size = extract_allocation_size_field(itr);
|
||||
|
||||
// memory allocation counter track
|
||||
struct free_memory_information
|
||||
{
|
||||
rocprofiler_timestamp_t start_timestamp = 0;
|
||||
rocprofiler_timestamp_t end_timestamp = 0;
|
||||
rocprofiler_address_t address = {.handle = 0};
|
||||
};
|
||||
|
||||
auto _node_id = std::optional<uint64_t>{};
|
||||
if(_type == "ALLOC")
|
||||
{
|
||||
_node_id = tool_metadata.get_agent(itr.agent_id)->node_id;
|
||||
address_to_agent_and_size.emplace(
|
||||
rocprofiler_address_t{.handle = _address.handle},
|
||||
rocprofiler::agent::index_and_size{_node_id.value(), _allocation_size});
|
||||
}
|
||||
else if(_type == "FREE")
|
||||
{
|
||||
if(address_to_agent_and_size.count(_address) == 0)
|
||||
{
|
||||
if(_address.handle == 0)
|
||||
{
|
||||
// Freeing null pointers is expected behavior and is occurs in HSA
|
||||
// functions like hipStreamDestroy
|
||||
ROCP_INFO << "null pointer freed due to HSA operation";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Following should not occur
|
||||
ROCP_INFO << "Unpaired free operation occurred";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [agent_abs_index, size] = address_to_agent_and_size[_address];
|
||||
_node_id = agent_abs_index;
|
||||
_allocation_size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCP_CI_LOG(WARNING) << "unhandled memory allocation type " << _type;
|
||||
}
|
||||
|
||||
auto evt_id = create_event(
|
||||
conn,
|
||||
{
|
||||
|
||||
@@ -460,6 +460,9 @@ PYBIND11_MODULE(libpyrocpd, pyrocpd)
|
||||
auto memory_copies = rocpd::sql_generator<rocpd::types::memory_copies>{
|
||||
conn, select_guid_nid_pid("memory_copies")};
|
||||
|
||||
auto scratch_memory = rocpd::sql_generator<rocpd::types::scratch_memory>{
|
||||
conn, select_guid_nid_pid("scratch_memory")};
|
||||
|
||||
auto counters = rocpd::sql_generator<rocpd::types::counter>{
|
||||
conn, select_guid_nid_pid("counters_collection")};
|
||||
|
||||
@@ -495,6 +498,7 @@ PYBIND11_MODULE(libpyrocpd, pyrocpd)
|
||||
samples,
|
||||
kernels,
|
||||
memory_copies,
|
||||
scratch_memory,
|
||||
memory_allocations,
|
||||
counters);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "lib/output/sql/common.hpp"
|
||||
#include "lib/output/stream_info.hpp"
|
||||
#include "lib/rocprofiler-sdk-tool/config.hpp"
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
@@ -174,6 +175,7 @@ write_perfetto(
|
||||
const tool::generator<types::sample>& sample_gen,
|
||||
const tool::generator<types::kernel_dispatch>& kernel_dispatch_gen,
|
||||
const tool::generator<types::memory_copies>& memory_copy_gen,
|
||||
const tool::generator<types::scratch_memory>& scratch_memory_gen,
|
||||
const tool::generator<types::memory_allocation>& memory_allocation_gen,
|
||||
const tool::generator<types::counter>& counter_collection_gen)
|
||||
{
|
||||
@@ -687,19 +689,15 @@ write_perfetto(
|
||||
rocprofiler_timestamp_t start_timestamp = 0;
|
||||
rocprofiler_timestamp_t end_timestamp = 0;
|
||||
rocprofiler_address_t address = {.handle = 0};
|
||||
rocprofiler_queue_id_t queue = {.handle = 0};
|
||||
};
|
||||
|
||||
struct memory_information
|
||||
{
|
||||
uint64_t alloc_size = {0};
|
||||
rocprofiler_address_t address = {.handle = 0};
|
||||
bool is_alloc_op = {false};
|
||||
};
|
||||
|
||||
struct agent_and_size
|
||||
{
|
||||
uint64_t agent_abs_index = {};
|
||||
uint64_t size = {0};
|
||||
uint64_t alloc_size = {0};
|
||||
rocprofiler_address_t address = {.handle = 0};
|
||||
rocprofiler_queue_id_t queue = {.handle = 0};
|
||||
bool is_alloc_op = {false};
|
||||
};
|
||||
|
||||
auto mem_alloc_endpoints =
|
||||
@@ -707,7 +705,9 @@ write_perfetto(
|
||||
auto mem_alloc_extremes = std::pair<uint64_t, uint64_t>{
|
||||
std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::min()};
|
||||
auto address_to_agent_and_size =
|
||||
std::unordered_map<rocprofiler_address_t, agent_and_size>{};
|
||||
std::unordered_map<rocprofiler_address_t, rocprofiler::agent::index_and_size>{};
|
||||
auto queue_to_agent_and_size =
|
||||
std::unordered_map<rocprofiler_queue_id_t, rocprofiler::agent::index_and_size>{};
|
||||
auto free_mem_info = std::vector<free_memory_information>{};
|
||||
|
||||
// Load memory allocation endpoints
|
||||
@@ -719,24 +719,47 @@ write_perfetto(
|
||||
{
|
||||
LOG_IF(FATAL, itr.agent_name.empty())
|
||||
<< "Missing agent id for memory allocation trace";
|
||||
mem_alloc_endpoints[itr.agent_abs_index].emplace(
|
||||
itr.start,
|
||||
memory_information{
|
||||
itr.size, rocprofiler_address_t{.handle = itr.address}, true});
|
||||
mem_alloc_endpoints[itr.agent_abs_index].emplace(
|
||||
itr.end,
|
||||
memory_information{
|
||||
itr.size, rocprofiler_address_t{.handle = itr.address}, true});
|
||||
address_to_agent_and_size.emplace(
|
||||
rocprofiler_address_t{.handle = itr.address},
|
||||
agent_and_size{itr.agent_abs_index, itr.size});
|
||||
|
||||
if(itr.level == "REAL")
|
||||
{
|
||||
mem_alloc_endpoints[itr.agent_abs_index].emplace(
|
||||
itr.start,
|
||||
memory_information{itr.size,
|
||||
rocprofiler_address_t{.handle = itr.address},
|
||||
rocprofiler_queue_id_t{.handle = itr.queue_id},
|
||||
true});
|
||||
mem_alloc_endpoints[itr.agent_abs_index].emplace(
|
||||
itr.end,
|
||||
memory_information{itr.size,
|
||||
rocprofiler_address_t{.handle = itr.address},
|
||||
rocprofiler_queue_id_t{.handle = itr.queue_id},
|
||||
true});
|
||||
|
||||
address_to_agent_and_size.emplace(
|
||||
rocprofiler_address_t{.handle = itr.address},
|
||||
rocprofiler::agent::index_and_size{itr.agent_abs_index, itr.size});
|
||||
}
|
||||
// Scratch memory operations are indexed by queue id as agent
|
||||
// id is not available
|
||||
else if(itr.level == "SCRATCH")
|
||||
{
|
||||
queue_to_agent_and_size.emplace(
|
||||
rocprofiler_queue_id_t{.handle = itr.queue_id},
|
||||
rocprofiler::agent::index_and_size{itr.agent_abs_index, itr.size});
|
||||
}
|
||||
}
|
||||
else if(itr.type == "FREE")
|
||||
{
|
||||
// Store free memory operations in seperate vector to pair with agent
|
||||
// and allocation size in following loop
|
||||
free_mem_info.push_back(free_memory_information{
|
||||
itr.start, itr.end, rocprofiler_address_t{.handle = itr.address}});
|
||||
if(itr.level == "REAL")
|
||||
{
|
||||
free_mem_info.push_back(free_memory_information{
|
||||
itr.start,
|
||||
itr.end,
|
||||
rocprofiler_address_t{.handle = itr.address},
|
||||
rocprofiler_queue_id_t{.handle = itr.queue_id}});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -765,9 +788,9 @@ write_perfetto(
|
||||
}
|
||||
auto [agent_abs_index, size] = address_to_agent_and_size[itr.address];
|
||||
mem_alloc_endpoints[agent_abs_index].emplace(
|
||||
itr.start_timestamp, memory_information{size, itr.address, false});
|
||||
itr.start_timestamp, memory_information{size, itr.address, itr.queue, false});
|
||||
mem_alloc_endpoints[agent_abs_index].emplace(
|
||||
itr.end_timestamp, memory_information{size, itr.address, false});
|
||||
itr.end_timestamp, memory_information{size, itr.address, itr.queue, false});
|
||||
}
|
||||
// Create running sum of allocated memory
|
||||
for(auto& [_, endpoint_map] : mem_alloc_endpoints)
|
||||
@@ -817,10 +840,10 @@ write_perfetto(
|
||||
{
|
||||
mem_alloc_endpoints[abs_index].emplace(
|
||||
mem_alloc_extremes.first - extremes_endpoint_buffer,
|
||||
memory_information{0, {0}, false});
|
||||
memory_information{0, {0}, {0}, false});
|
||||
mem_alloc_endpoints[abs_index].emplace(
|
||||
mem_alloc_extremes.second + extremes_endpoint_buffer,
|
||||
memory_information{0, {0}, false});
|
||||
memory_information{0, {0}, {0}, false});
|
||||
|
||||
auto _track_name = std::stringstream{};
|
||||
|
||||
@@ -853,9 +876,93 @@ write_perfetto(
|
||||
mem_alloc_tracks.at(alloc_itr.first),
|
||||
itr.first,
|
||||
itr.second.alloc_size / bytes_multiplier);
|
||||
tracing_session->FlushBlocking();
|
||||
}
|
||||
}
|
||||
|
||||
// scratch memory counter track
|
||||
auto scratch_mem_endpoints =
|
||||
std::unordered_map<uint64_t, std::map<rocprofiler_timestamp_t, uint64_t>>{};
|
||||
|
||||
// Load scratch memory usage endpoints
|
||||
for(const auto& ditr : scratch_memory_gen)
|
||||
for(const auto& itr : scratch_memory_gen.get(ditr))
|
||||
{
|
||||
auto agent_abs_index = itr.agent_abs_index;
|
||||
if(itr.operation == "FREE")
|
||||
{
|
||||
auto [agent_index, size] =
|
||||
queue_to_agent_and_size[rocprofiler_queue_id_t{.handle = itr.queue_id}];
|
||||
agent_abs_index = agent_index;
|
||||
}
|
||||
|
||||
// Track start and end timestamps for this scratch memory record
|
||||
scratch_mem_endpoints[agent_abs_index].emplace(itr.start, 0);
|
||||
scratch_mem_endpoints[agent_abs_index].emplace(itr.end, 0);
|
||||
}
|
||||
|
||||
// Load values at each endpoint
|
||||
for(const auto& ditr : scratch_memory_gen)
|
||||
for(const auto& itr : scratch_memory_gen.get(ditr))
|
||||
{
|
||||
if(itr.operation == "ALLOC")
|
||||
{
|
||||
auto agent_abs_index = itr.agent_abs_index;
|
||||
|
||||
// For each timestamp in the range of this record including intervening
|
||||
// deallocations write in allocation size
|
||||
auto begin = scratch_mem_endpoints.at(agent_abs_index).lower_bound(itr.start);
|
||||
auto end = scratch_mem_endpoints.at(agent_abs_index).upper_bound(itr.end);
|
||||
|
||||
for(auto mitr = begin; mitr != end; ++mitr)
|
||||
{
|
||||
mitr->second = itr.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create counter tracks for visualization
|
||||
auto scratch_mem_tracks = std::unordered_map<uint64_t, ::perfetto::CounterTrack>{};
|
||||
auto scratch_mem_names = std::vector<std::string>{};
|
||||
scratch_mem_names.reserve(scratch_mem_endpoints.size());
|
||||
|
||||
for(auto& [abs_index, ts_map] : scratch_mem_endpoints)
|
||||
{
|
||||
// Add buffer timestamps for better visualization
|
||||
if(!ts_map.empty())
|
||||
{
|
||||
auto _track_name = std::stringstream{};
|
||||
const auto _agent = agent_data.at(abs_index).first;
|
||||
auto agent_index_info = agent_data.at(abs_index).second;
|
||||
|
||||
_track_name << "SCRATCH MEMORY on " << agent_index_info.label << " ["
|
||||
<< agent_index_info.index << "] (" << agent_index_info.type << ")";
|
||||
|
||||
constexpr auto _unit = ::perfetto::CounterTrack::Unit::UNIT_SIZE_BYTES;
|
||||
auto& _name = scratch_mem_names.emplace_back(_track_name.str());
|
||||
scratch_mem_tracks.emplace(abs_index,
|
||||
::perfetto::CounterTrack{_name.c_str(), this_pid_track}
|
||||
.set_unit(_unit)
|
||||
.set_unit_multiplier(bytes_multiplier)
|
||||
.set_is_incremental(false));
|
||||
}
|
||||
}
|
||||
|
||||
// Write counter values to perfetto trace
|
||||
for(const auto& mitr : scratch_mem_endpoints)
|
||||
{
|
||||
if(scratch_mem_tracks.count(mitr.first) > 0)
|
||||
{
|
||||
for(const auto& itr : mitr.second)
|
||||
{
|
||||
TRACE_COUNTER(sdk::perfetto_category<sdk::category::scratch_memory>::name,
|
||||
scratch_mem_tracks.at(mitr.first),
|
||||
itr.first,
|
||||
itr.second / bytes_multiplier);
|
||||
tracing_session->FlushBlocking();
|
||||
}
|
||||
}
|
||||
}
|
||||
tracing_session->FlushBlocking();
|
||||
}
|
||||
|
||||
// Create counter tracks per agent
|
||||
|
||||
@@ -63,6 +63,7 @@ write_perfetto(
|
||||
const tool::generator<types::sample>& sample_gen,
|
||||
const tool::generator<types::kernel_dispatch>& kernel_dispatch_gen,
|
||||
const tool::generator<types::memory_copies>& memory_copy_gen,
|
||||
const tool::generator<types::scratch_memory>& scratch_memory_gen,
|
||||
const tool::generator<types::memory_allocation>& memory_allocation_gen,
|
||||
const tool::generator<types::counter>& counter_collection_gen);
|
||||
} // namespace output
|
||||
|
||||
@@ -76,6 +76,12 @@ struct uuid_view_t
|
||||
}
|
||||
};
|
||||
|
||||
struct index_and_size
|
||||
{
|
||||
uint64_t agent_abs_index = {};
|
||||
uint64_t size = {0};
|
||||
};
|
||||
|
||||
std::vector<const rocprofiler_agent_t*>
|
||||
get_agents();
|
||||
|
||||
|
||||
+81
-20
@@ -343,6 +343,55 @@ class PerfettoReader:
|
||||
[self.dataframe, counter_collection_df], ignore_index=True
|
||||
)
|
||||
|
||||
scratch_df = self.query_tp(
|
||||
"""WITH Pairs AS(
|
||||
SELECT
|
||||
counter.id as slice_id,
|
||||
track_id,
|
||||
ts,
|
||||
(LEAD(counter.ts) OVER window) - counter.ts AS dur,
|
||||
counter_track.name as track_name,
|
||||
ROW_NUMBER() OVER window AS rn
|
||||
FROM counter JOIN counter_track ON counter.track_id = counter_track.id
|
||||
WHERE counter_track.name LIKE '%SCRATCH MEMORY%'
|
||||
WINDOW window AS (PARTITION BY counter.value, track_id ORDER BY counter.ts)
|
||||
)
|
||||
SELECT
|
||||
slice_id,
|
||||
track_id,
|
||||
'scratch_memory' as category,
|
||||
0 as depth,
|
||||
0 as stack_id,
|
||||
0 as parent_stack_id,
|
||||
ts,
|
||||
dur,
|
||||
Pairs.track_name as name
|
||||
FROM Pairs WHERE (rn % 2 == 1) ORDER BY slice_id"""
|
||||
)
|
||||
|
||||
# Transform scratch memory data to match the main dataframe schema
|
||||
if not scratch_df.empty:
|
||||
# Register counter track IDs in self.track_ids before adding to dataframe
|
||||
for row in scratch_df.itertuples():
|
||||
if (
|
||||
row.tp_index < len(self.track_ids)
|
||||
and row.track_id not in self.track_ids[row.tp_index]
|
||||
):
|
||||
# Add the counter track to track_ids with reasonable default values
|
||||
self.track_ids[row.tp_index][row.track_id] = {
|
||||
"tp_index": row.tp_index,
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
"rank": 0,
|
||||
"thread": 0,
|
||||
"prio": 2,
|
||||
"process_name": "scratch_process",
|
||||
"thread_name": f"scratch_track_{row.category}",
|
||||
}
|
||||
|
||||
# Concatenate with main dataframe
|
||||
self.dataframe = pd.concat([self.dataframe, scratch_df], ignore_index=True)
|
||||
|
||||
self.df_categories = sorted(list(self.dataframe["category"].unique()))
|
||||
|
||||
# check for update to include/exclude category
|
||||
@@ -420,26 +469,38 @@ class PerfettoReader:
|
||||
_thread_name = (
|
||||
thread.thread_name if thread.track_name is None else thread.track_name
|
||||
)
|
||||
for process in self.process.itertuples():
|
||||
if process.tp_index != thread.tp_index:
|
||||
continue
|
||||
_process_name = (
|
||||
process.process_name
|
||||
if process.track_name is None
|
||||
else process.track_name
|
||||
)
|
||||
if process.track_id == thread.track_parent_id:
|
||||
self.track_ids[thread.tp_index][thread.track_id] = {
|
||||
"tp_index": thread.tp_index,
|
||||
"pid": process.pid,
|
||||
"tid": thread.tid,
|
||||
"rank": -1,
|
||||
"thread": -1,
|
||||
"prio": 0 if thread.is_main_thread else 1,
|
||||
"process_name": _process_name,
|
||||
"thread_name": _thread_name,
|
||||
}
|
||||
break
|
||||
if thread.track_parent_id == 0:
|
||||
self.track_ids[thread.tp_index][thread.track_id] = {
|
||||
"tp_index": thread.tp_index,
|
||||
"pid": 0,
|
||||
"tid": thread.tid,
|
||||
"rank": -1,
|
||||
"thread": -1,
|
||||
"prio": 0 if thread.is_main_thread else 1,
|
||||
"process_name": "",
|
||||
"thread_name": _thread_name,
|
||||
}
|
||||
else:
|
||||
for process in self.process.itertuples():
|
||||
if process.tp_index != thread.tp_index:
|
||||
continue
|
||||
_process_name = (
|
||||
process.process_name
|
||||
if process.track_name is None
|
||||
else process.track_name
|
||||
)
|
||||
if process.track_id == thread.track_parent_id:
|
||||
self.track_ids[thread.tp_index][thread.track_id] = {
|
||||
"tp_index": thread.tp_index,
|
||||
"pid": process.pid,
|
||||
"tid": thread.tid,
|
||||
"rank": -1,
|
||||
"thread": -1,
|
||||
"prio": 0 if thread.is_main_thread else 1,
|
||||
"process_name": _process_name,
|
||||
"thread_name": _thread_name,
|
||||
}
|
||||
break
|
||||
|
||||
# some track ids do not have an associated system thread id so handle them here.
|
||||
# for example, omnitrace post-processes sampling data collected on a thread
|
||||
|
||||
@@ -49,3 +49,4 @@ add_subdirectory(python-bindings)
|
||||
add_subdirectory(rocpd)
|
||||
add_subdirectory(rocpd-kernel-rename)
|
||||
add_subdirectory(attachment)
|
||||
add_subdirectory(rocpd-scratch)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#
|
||||
# rocprofv3 rocpd tests
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
project(
|
||||
rocprofiler-sdk-tests-rocprofv3-rocpd-scratch
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
|
||||
set(rocprofv3-rocpd-scratch-env
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}"
|
||||
"PYTHONPATH=${rocprofiler-sdk_LIB_DIR}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages"
|
||||
"OMPI_ALLOW_RUN_AS_ROOT=1"
|
||||
"OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1")
|
||||
|
||||
rocprofiler_configure_pytest_files(CONFIG pytest.ini COPY conftest.py validate.py)
|
||||
|
||||
find_package(Python3 REQUIRED)
|
||||
|
||||
#########################################################################################
|
||||
#
|
||||
# generate rocpd database and json for comparison
|
||||
#
|
||||
#########################################################################################
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocpd-scratch-execute
|
||||
COMMAND
|
||||
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --scratch-memory-trace -d
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocpd-input-data -o out --output-format rocpd json
|
||||
--runtime-trace --kernel-rename -- $<TARGET_FILE:scratch-memory>)
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocpd-scratch-execute
|
||||
PROPERTIES TIMEOUT
|
||||
120
|
||||
LABELS
|
||||
"integration-tests;rocpd"
|
||||
ENVIRONMENT
|
||||
"${rocprofv3-rocpd-scratch-env}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
FIXTURES_SETUP
|
||||
rocprofv3-test-rocpd-scratch)
|
||||
|
||||
#########################################################################################
|
||||
#
|
||||
# perfetto generate
|
||||
#
|
||||
#########################################################################################
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocpd-scratch-perfetto-generation
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} -m rocpd convert -f pftrace --kernel-rename -d
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocpd-output-data -i
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocpd-input-data/out_results.db)
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocpd-scratch-perfetto-generation
|
||||
PROPERTIES TIMEOUT
|
||||
120
|
||||
LABELS
|
||||
"integration-tests;rocpd"
|
||||
ENVIRONMENT
|
||||
"${rocprofv3-rocpd-scratch-env}"
|
||||
DEPENDS
|
||||
"rocprofv3-test-rocpd-scratch-execute"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
FIXTURES_SETUP
|
||||
rocprofv3-test-rocpd-scratch-generation
|
||||
FIXTURES_REQUIRED
|
||||
rocprofv3-test-rocpd-scratch)
|
||||
|
||||
#########################################################################################
|
||||
#
|
||||
# Validation
|
||||
#
|
||||
#########################################################################################
|
||||
|
||||
set(VALIDATION_DEPENDS rocprofv3-test-rocpd-scratch-perfetto-generation)
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocpd-scratch-validation
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/validate.py --json-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocpd-input-data/out_results.json --pftrace-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocpd-output-data/out_results.pftrace)
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocpd-scratch-validation
|
||||
PROPERTIES TIMEOUT
|
||||
120
|
||||
LABELS
|
||||
"integration-tests;rocpd"
|
||||
ENVIRONMENT
|
||||
"${rocprofv3-rocpd-scratch-env}"
|
||||
DEPENDS
|
||||
rocprofv3-test-rocpd-scratch-perfetto-generation
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
FIXTURES_REQUIRED
|
||||
rocprofv3-test-rocpd-scratch-generation)
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2024-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.
|
||||
|
||||
import pandas as pd
|
||||
import pytest
|
||||
import json
|
||||
import os
|
||||
import io
|
||||
|
||||
from rocprofiler_sdk.pytest_utils.dotdict import dotdict
|
||||
from rocprofiler_sdk.pytest_utils import collapse_dict_list
|
||||
from rocprofiler_sdk.pytest_utils.perfetto_reader import PerfettoReader
|
||||
from rocprofiler_sdk.pytest_utils.otf2_reader import OTF2Reader
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--json-input",
|
||||
action="store",
|
||||
help="Path to JSON file.",
|
||||
)
|
||||
parser.addoption(
|
||||
"--pftrace-input",
|
||||
action="store",
|
||||
help="Path to Perfetto trace file.",
|
||||
)
|
||||
|
||||
pd.set_option("display.width", 2000)
|
||||
# increase debug display of pandas dataframes
|
||||
for itr in ["rows", "columns", "colwidth"]:
|
||||
pd.set_option(f"display.max_{itr}", None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def json_data(request):
|
||||
filename = request.config.getoption("--json-input")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(collapse_dict_list(json.load(inp)))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pftrace_data(request):
|
||||
filename = request.config.getoption("--pftrace-input")
|
||||
return PerfettoReader(filename).read()[0]
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
[pytest]
|
||||
addopts = --durations=20 -rA -s -vv
|
||||
testpaths = validate.py
|
||||
pythonpath = @ROCPROFILER_SDK_TESTS_BINARY_DIR@/pytest-packages
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2024-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.
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
|
||||
def test_perfetto_data(pftrace_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
rocprofv3.test_perfetto_data(
|
||||
pftrace_data,
|
||||
json_data,
|
||||
("scratch_memory",),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = pytest.main(["-x", __file__] + sys.argv[1:])
|
||||
sys.exit(exit_code)
|
||||
Référencer dans un nouveau ticket
Bloquer un utilisateur