[rocprofiler-systems] Add trace_cache unit tests (#2086)
Improve test coverage and reliability of the trace_cache module by adding comprehensive unit tests for all major components.
This commit is contained in:
zatwierdzone przez
GitHub
rodzic
09a9f9e31d
commit
fddef714a0
@@ -48,3 +48,7 @@ target_include_directories(
|
||||
rocprofiler-systems-core-library
|
||||
PUBLIC ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
if(ROCPROFSYS_BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -21,14 +21,10 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "buffer_storage.hpp"
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/TaskGroup.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "debug.hpp"
|
||||
#include "library/runtime.hpp"
|
||||
#include <chrono>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
@@ -71,8 +67,6 @@ flush_worker_t::start(const pid_t& current_pid)
|
||||
m_worker_synchronization->origin_pid = current_pid;
|
||||
m_worker_synchronization->is_running = true;
|
||||
|
||||
ROCPROFSYS_SCOPED_SAMPLING_ON_CHILD_THREADS(false);
|
||||
|
||||
m_flushing_thread = std::make_unique<std::thread>([&]() {
|
||||
std::mutex _shutdown_condition_mutex;
|
||||
while(m_worker_synchronization->is_running)
|
||||
@@ -99,7 +93,6 @@ flush_worker_t::stop(const pid_t& current_pid)
|
||||
|
||||
if(flushing_thread_exist && worker_is_running)
|
||||
{
|
||||
ROCPROFSYS_DEBUG("Buffer storage shutting down..\n");
|
||||
m_worker_synchronization->is_running = false;
|
||||
m_worker_synchronization->is_running_condition.notify_all();
|
||||
|
||||
@@ -107,8 +100,6 @@ flush_worker_t::stop(const pid_t& current_pid)
|
||||
current_pid == m_worker_synchronization->origin_pid;
|
||||
if(!thread_is_created_in_this_process)
|
||||
{
|
||||
ROCPROFSYS_DEBUG(
|
||||
"Buffer storage is not created in same process as shutting down..\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,16 +25,19 @@
|
||||
#include "core/trace_cache/cacheable.hpp"
|
||||
|
||||
#include "common/defines.h"
|
||||
#include "core/debug.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
#include <unistd.h>
|
||||
@@ -134,7 +137,6 @@ public:
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Worker is null - unable to shutdown buffered storage.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!is_running())
|
||||
@@ -213,11 +215,9 @@ private:
|
||||
}
|
||||
if(ofs.fail())
|
||||
{
|
||||
ROCPROFSYS_WARNING(1, "Error flushing buffered storage to file for pid: %d",
|
||||
m_worker_synchronization->origin_pid);
|
||||
ROCPROFSYS_CI_THROW(true,
|
||||
"Error flushing buffered storage to file for pid: %d",
|
||||
m_worker_synchronization->origin_pid);
|
||||
throw std::runtime_error(
|
||||
std::string("Error flushing buffered storage to file for pid: ") +
|
||||
std::to_string(m_worker_synchronization->origin_pid) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofsys
|
||||
@@ -444,7 +445,14 @@ process_buffered_storage(
|
||||
storage_parser_t _parser(_storage_filename);
|
||||
|
||||
_processor_coordinator->prepare_for_processing();
|
||||
_parser.load(_processor_coordinator);
|
||||
try
|
||||
{
|
||||
_parser.load(_processor_coordinator);
|
||||
|
||||
} catch(const std::runtime_error& exp)
|
||||
{
|
||||
ROCPROFSYS_WARNING(1, "Error parsing buffered storage: %s\n", exp.what());
|
||||
}
|
||||
_processor_coordinator->finalize_processing();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
#include "core/trace_cache/metadata_registry.hpp"
|
||||
#include "core/trace_cache/sample_type.hpp"
|
||||
#include "core/trace_cache/storage_parser.hpp"
|
||||
|
||||
#include "library/runtime.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace rocprofsys
|
||||
{
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#pragma once
|
||||
#include "core/trace_cache/cache_type_traits.hpp"
|
||||
#include "library/runtime.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "core/trace_cache/cacheable.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
@@ -407,7 +408,7 @@ inline void
|
||||
serialize(uint8_t* buffer, const in_time_sample& item)
|
||||
{
|
||||
utility::store_value(
|
||||
buffer, std::string_view(item.track_name),
|
||||
buffer, item.category_enum_id, std::string_view(item.track_name),
|
||||
static_cast<uint64_t>(item.timestamp_ns), std::string_view(item.event_metadata),
|
||||
static_cast<uint64_t>(item.stack_id), static_cast<uint64_t>(item.parent_stack_id),
|
||||
static_cast<uint64_t>(item.correlation_id), std::string_view(item.call_stack),
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/defines.h"
|
||||
#include "core/debug.hpp"
|
||||
|
||||
#include "core/trace_cache/cacheable.hpp"
|
||||
#include "core/trace_cache/type_registry.hpp"
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -67,9 +67,6 @@ public:
|
||||
throw std::runtime_error("TypeProcessing is nullptr");
|
||||
}
|
||||
|
||||
ROCPROFSYS_DEBUG("Consuming buffered storage with filename: %s\n",
|
||||
m_filename.c_str());
|
||||
|
||||
std::ifstream ifs(m_filename, std::ios::binary);
|
||||
if(!ifs.good())
|
||||
{
|
||||
@@ -94,10 +91,9 @@ public:
|
||||
{
|
||||
if(!ifs.good())
|
||||
{
|
||||
ROCPROFSYS_WARNING(0,
|
||||
"Stream not in good state, stopping parse. File: %s\n",
|
||||
m_filename.c_str());
|
||||
break;
|
||||
throw std::runtime_error(
|
||||
std::string("Stream not in good state, stopping parse. File: ") +
|
||||
m_filename + "\n");
|
||||
}
|
||||
|
||||
ifs.read(reinterpret_cast<char*>(&header), sizeof(header));
|
||||
@@ -118,11 +114,10 @@ public:
|
||||
|
||||
if(ifs.fail())
|
||||
{
|
||||
ROCPROFSYS_WARNING(1,
|
||||
"Bad read while consuming buffered storage. Filename: "
|
||||
"%s Bytes read: %d\n",
|
||||
m_filename.c_str(), static_cast<int>(ifs.tellg()));
|
||||
continue;
|
||||
throw std::runtime_error(
|
||||
std::string("Bad read while consuming buffered storage. Filename: ") +
|
||||
m_filename + " Bytes read: " +
|
||||
std::to_string(static_cast<int>(ifs.tellg())) + "\n");
|
||||
}
|
||||
|
||||
if(header.type == TypeIdentifierEnum::fragmented_space)
|
||||
@@ -144,7 +139,6 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCPROFSYS_DEBUG("Unsupported type detected. Skipping current sample.\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# 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.
|
||||
|
||||
set(trace_cache_tests_sources
|
||||
test_type_registry.cpp
|
||||
test_cacheable.cpp
|
||||
test_buffer_storage.cpp
|
||||
test_storage_parser.cpp
|
||||
test_flush_worker.cpp
|
||||
test_cache_integration.cpp
|
||||
test_sample_type.cpp
|
||||
)
|
||||
|
||||
add_library(trace-cache-tests OBJECT ${trace_cache_tests_sources})
|
||||
|
||||
target_link_libraries(
|
||||
trace-cache-tests
|
||||
PRIVATE rocprofiler-systems-googletest-library rocprofiler-systems-core-library
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
trace-cache-tests
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}/source/lib ${CMAKE_BINARY_DIR}/source/lib/
|
||||
)
|
||||
@@ -0,0 +1,167 @@
|
||||
// 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 "core/trace_cache/cacheable.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
enum class test_type_identifier_t : uint32_t
|
||||
{
|
||||
sample_type_1 = 1,
|
||||
sample_type_2 = 2,
|
||||
sample_type_3 = 3,
|
||||
fragmented_space = 0xFFFF
|
||||
};
|
||||
struct test_sample_1 : public rocprofsys::trace_cache::cacheable_t
|
||||
{
|
||||
static constexpr test_type_identifier_t type_identifier =
|
||||
test_type_identifier_t::sample_type_1;
|
||||
|
||||
test_sample_1() = default;
|
||||
test_sample_1(int v, std::string_view s)
|
||||
: value(v)
|
||||
, text(s)
|
||||
{}
|
||||
|
||||
int value = 0;
|
||||
std::string_view text;
|
||||
|
||||
bool operator==(const test_sample_1& other) const
|
||||
{
|
||||
return value == other.value && text == other.text;
|
||||
}
|
||||
};
|
||||
|
||||
struct test_sample_2 : public rocprofsys::trace_cache::cacheable_t
|
||||
{
|
||||
static constexpr test_type_identifier_t type_identifier =
|
||||
test_type_identifier_t::sample_type_2;
|
||||
|
||||
test_sample_2() = default;
|
||||
test_sample_2(double d, uint32_t id)
|
||||
: data(d)
|
||||
, sample_id(id)
|
||||
{}
|
||||
|
||||
double data = 0.0;
|
||||
uint32_t sample_id = 0;
|
||||
|
||||
bool operator==(const test_sample_2& other) const
|
||||
{
|
||||
if(sample_id != other.sample_id) return false;
|
||||
|
||||
if(std::isnan(data) && std::isnan(other.data)) return true;
|
||||
|
||||
if(std::isinf(data) && std::isinf(other.data))
|
||||
return std::signbit(data) == std::signbit(other.data);
|
||||
|
||||
return std::abs(data - other.data) < 1e-9;
|
||||
}
|
||||
};
|
||||
|
||||
struct test_sample_3 : public rocprofsys::trace_cache::cacheable_t
|
||||
{
|
||||
static constexpr test_type_identifier_t type_identifier =
|
||||
test_type_identifier_t::sample_type_3;
|
||||
|
||||
test_sample_3() = default;
|
||||
test_sample_3(std::vector<uint8_t> p)
|
||||
: payload(std::move(p))
|
||||
{}
|
||||
|
||||
std::vector<uint8_t> payload;
|
||||
|
||||
bool operator==(const test_sample_3& other) const { return payload == other.payload; }
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void
|
||||
rocprofsys::trace_cache::serialize(uint8_t* buffer, const test_sample_1& item)
|
||||
{
|
||||
rocprofsys::trace_cache::utility::store_value(buffer, item.value, item.text);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline test_sample_1
|
||||
rocprofsys::trace_cache::deserialize(uint8_t*& buffer)
|
||||
{
|
||||
test_sample_1 result;
|
||||
rocprofsys::trace_cache::utility::parse_value(buffer, result.value, result.text);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t
|
||||
rocprofsys::trace_cache::get_size(const test_sample_1& item)
|
||||
{
|
||||
return rocprofsys::trace_cache::utility::get_size(item.value, item.text);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void
|
||||
rocprofsys::trace_cache::serialize(uint8_t* buffer, const test_sample_2& item)
|
||||
{
|
||||
rocprofsys::trace_cache::utility::store_value(buffer, item.data, item.sample_id);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline test_sample_2
|
||||
rocprofsys::trace_cache::deserialize(uint8_t*& buffer)
|
||||
{
|
||||
test_sample_2 result;
|
||||
rocprofsys::trace_cache::utility::parse_value(buffer, result.data, result.sample_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t
|
||||
rocprofsys::trace_cache::get_size(const test_sample_2& item)
|
||||
{
|
||||
return rocprofsys::trace_cache::utility::get_size(item.data, item.sample_id);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void
|
||||
rocprofsys::trace_cache::serialize(uint8_t* buffer, const test_sample_3& item)
|
||||
{
|
||||
rocprofsys::trace_cache::utility::store_value(buffer, item.payload);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline test_sample_3
|
||||
rocprofsys::trace_cache::deserialize(uint8_t*& buffer)
|
||||
{
|
||||
test_sample_3 result;
|
||||
rocprofsys::trace_cache::utility::parse_value(buffer, result.payload);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t
|
||||
rocprofsys::trace_cache::get_size(const test_sample_3& item)
|
||||
{
|
||||
return rocprofsys::trace_cache::utility::get_size(item.payload);
|
||||
}
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
// 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 "core/trace_cache/buffer_storage.hpp"
|
||||
#include "mocked_types.hpp"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
verify_buffer_contains(const T& sample, const uint8_t* buffer, size_t& buffer_pos)
|
||||
{
|
||||
auto type_id = *reinterpret_cast<const test_type_identifier_t*>(buffer + buffer_pos);
|
||||
EXPECT_EQ(type_id, T::type_identifier);
|
||||
buffer_pos += sizeof(test_type_identifier_t);
|
||||
|
||||
auto size = *reinterpret_cast<const size_t*>(buffer + buffer_pos);
|
||||
EXPECT_EQ(size, rocprofsys::trace_cache::get_size(sample));
|
||||
buffer_pos += sizeof(size_t);
|
||||
|
||||
uint8_t* deserialize_ptr = const_cast<uint8_t*>(buffer + buffer_pos);
|
||||
auto deserialized = rocprofsys::trace_cache::deserialize<T>(deserialize_ptr);
|
||||
EXPECT_EQ(deserialized, sample);
|
||||
buffer_pos += size;
|
||||
}
|
||||
|
||||
struct mock_worker_t
|
||||
{
|
||||
explicit mock_worker_t(rocprofsys::trace_cache::worker_function_t worker_function,
|
||||
rocprofsys::trace_cache::worker_synchronization_ptr_t sync,
|
||||
std::string filepath)
|
||||
|
||||
: m_worker_function(std::move(worker_function))
|
||||
, m_sync(std::move(sync))
|
||||
, m_filepath(std::move(filepath))
|
||||
{}
|
||||
|
||||
MOCK_METHOD(void, start, (const pid_t&) );
|
||||
MOCK_METHOD(void, stop, (const pid_t&) );
|
||||
|
||||
void execute_flush(bool force = false)
|
||||
{
|
||||
m_worker_function(m_output_string_stream, force);
|
||||
}
|
||||
|
||||
std::ostringstream m_output_string_stream;
|
||||
|
||||
rocprofsys::trace_cache::worker_function_t m_worker_function;
|
||||
rocprofsys::trace_cache::worker_synchronization_ptr_t m_sync;
|
||||
std::string m_filepath;
|
||||
};
|
||||
|
||||
std::shared_ptr<mock_worker_t> g_mock_worker;
|
||||
|
||||
struct mock_worker_factory_t
|
||||
{
|
||||
using worker_t = mock_worker_t;
|
||||
|
||||
mock_worker_factory_t() = delete;
|
||||
mock_worker_factory_t(mock_worker_factory_t&) = delete;
|
||||
mock_worker_factory_t& operator=(mock_worker_factory_t&) = delete;
|
||||
mock_worker_factory_t(mock_worker_factory_t&&) = delete;
|
||||
mock_worker_factory_t& operator=(mock_worker_factory_t&&) = delete;
|
||||
|
||||
static std::shared_ptr<worker_t> get_worker(
|
||||
rocprofsys::trace_cache::worker_function_t worker_function,
|
||||
const rocprofsys::trace_cache::worker_synchronization_ptr_t&
|
||||
worker_synchronization_ptr,
|
||||
std::string filepath)
|
||||
{
|
||||
g_mock_worker = std::make_shared<worker_t>(
|
||||
worker_function, worker_synchronization_ptr, std::move(filepath));
|
||||
return g_mock_worker;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class buffer_storage_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
test_file_path = "test_cache_" + std::to_string(test_counter++) + ".bin";
|
||||
std::remove(test_file_path.c_str()); // Be sure that file is created by test case
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
std::remove(test_file_path.c_str());
|
||||
g_mock_worker.reset();
|
||||
}
|
||||
|
||||
std::string test_file_path;
|
||||
static std::atomic<int> test_counter;
|
||||
|
||||
void SetUpStartStopOnCall()
|
||||
{
|
||||
ON_CALL(*g_mock_worker, start).WillByDefault([] {
|
||||
g_mock_worker->m_sync->is_running = true;
|
||||
});
|
||||
|
||||
ON_CALL(*g_mock_worker, stop).WillByDefault([] {
|
||||
g_mock_worker->m_sync->is_running = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
std::atomic<int> buffer_storage_test::test_counter{ 0 };
|
||||
|
||||
TEST_F(buffer_storage_test, multiple_start)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1).WillOnce([] {
|
||||
g_mock_worker->m_sync->is_running = true;
|
||||
});
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
EXPECT_NO_THROW(storage.start());
|
||||
EXPECT_NO_THROW(storage.start());
|
||||
EXPECT_EQ(test_file_path, g_mock_worker->m_filepath);
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, start_stop)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1).WillOnce([] {
|
||||
g_mock_worker->m_sync->is_running = true;
|
||||
});
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1).WillOnce([] {
|
||||
g_mock_worker->m_sync->is_running = false;
|
||||
});
|
||||
|
||||
storage.start();
|
||||
storage.shutdown();
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, try_store_event_sample_throw)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(0);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(0);
|
||||
|
||||
test_sample_1 sample{ 10, "test string" };
|
||||
EXPECT_THROW(storage.store(sample), std::runtime_error);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, store_after_shutdown)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
storage.start();
|
||||
test_sample_1 before_shutdown(1, "before");
|
||||
EXPECT_NO_THROW(storage.store(before_shutdown));
|
||||
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
|
||||
test_sample_1 after_shutdown(2, "after");
|
||||
EXPECT_THROW(storage.store(after_shutdown), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, store_event_samples)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
EXPECT_NO_THROW(storage.start());
|
||||
test_sample_1 sample{ 10, "test string" };
|
||||
EXPECT_NO_THROW(storage.store(sample));
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, immediately_flush)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
EXPECT_NO_THROW(storage.start());
|
||||
EXPECT_NO_THROW(g_mock_worker->execute_flush(true));
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, flush_below_threshold)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
EXPECT_NO_THROW(storage.start());
|
||||
|
||||
test_sample_1 sample{ 10, "test string" };
|
||||
EXPECT_NO_THROW(storage.store(sample));
|
||||
|
||||
EXPECT_NO_THROW(g_mock_worker->execute_flush());
|
||||
EXPECT_EQ(g_mock_worker->m_output_string_stream.str().size(), 0);
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, MixedSampleTypes)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
storage.start();
|
||||
test_sample_1 sample1(42, "event_data");
|
||||
test_sample_2 sample2(3.14159, 1001);
|
||||
test_sample_3 sample3({ 0xAA, 0xBB, 0xCC, 0xDD });
|
||||
|
||||
// Empty samples
|
||||
test_sample_3 sample4;
|
||||
test_sample_1 sample5;
|
||||
|
||||
EXPECT_NO_THROW(storage.store(sample1));
|
||||
EXPECT_NO_THROW(storage.store(sample2));
|
||||
EXPECT_NO_THROW(storage.store(sample3));
|
||||
EXPECT_NO_THROW(storage.store(sample1));
|
||||
EXPECT_NO_THROW(storage.store(sample4));
|
||||
EXPECT_NO_THROW(storage.store(sample5));
|
||||
|
||||
g_mock_worker->execute_flush(true);
|
||||
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
|
||||
std::string buffer_data = g_mock_worker->m_output_string_stream.str();
|
||||
ASSERT_FALSE(buffer_data.empty());
|
||||
|
||||
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buffer_data.data());
|
||||
size_t buffer_pos = 0;
|
||||
|
||||
verify_buffer_contains(sample1, buffer, buffer_pos);
|
||||
verify_buffer_contains(sample2, buffer, buffer_pos);
|
||||
verify_buffer_contains(sample3, buffer, buffer_pos);
|
||||
verify_buffer_contains(sample1, buffer, buffer_pos);
|
||||
verify_buffer_contains(sample4, buffer, buffer_pos);
|
||||
verify_buffer_contains(sample5, buffer, buffer_pos);
|
||||
|
||||
EXPECT_EQ(buffer_pos, buffer_data.size());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, large_payload_handling)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
storage.start();
|
||||
std::vector<uint8_t> large_payload(5000, 0xFF);
|
||||
test_sample_3 large_sample(large_payload);
|
||||
|
||||
EXPECT_NO_THROW(storage.store(large_sample));
|
||||
|
||||
for(int i = 0; i < 10; ++i)
|
||||
{
|
||||
std::vector<uint8_t> payload(1000 + i * 100, static_cast<uint8_t>(i));
|
||||
test_sample_3 sample(payload);
|
||||
EXPECT_NO_THROW(storage.store(sample));
|
||||
}
|
||||
|
||||
for(int i = 0; i < 5; ++i)
|
||||
{
|
||||
std::string large_string(1000 + i * 200, 'A' + (i % 26));
|
||||
test_sample_1 large_text_sample(i * 1000, large_string);
|
||||
EXPECT_NO_THROW(storage.store(large_text_sample));
|
||||
}
|
||||
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, concurrent_mixed_type_store)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
storage.start();
|
||||
|
||||
const int num_threads = 4;
|
||||
const int items_per_thread = 10;
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for(int t = 0; t < num_threads; ++t)
|
||||
{
|
||||
threads.emplace_back([&, t]() {
|
||||
for(int i = 0; i < items_per_thread; ++i)
|
||||
{
|
||||
switch(t % 3)
|
||||
{
|
||||
case 0:
|
||||
EXPECT_NO_THROW(
|
||||
storage.store(test_sample_1(t * 100 + i, "data")));
|
||||
break;
|
||||
case 1:
|
||||
EXPECT_NO_THROW(storage.store(test_sample_2(t * 2.5 + i, t + i)));
|
||||
break;
|
||||
case 2:
|
||||
EXPECT_NO_THROW(
|
||||
storage.store(test_sample_3(std::vector<uint8_t>(10, t))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& thread : threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
|
||||
g_mock_worker->execute_flush(true);
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
|
||||
std::string buffer_data = g_mock_worker->m_output_string_stream.str();
|
||||
EXPECT_FALSE(buffer_data.empty());
|
||||
|
||||
size_t actual_samples = 0;
|
||||
size_t buffer_pos = 0;
|
||||
|
||||
while(buffer_pos < buffer_data.size())
|
||||
{
|
||||
auto type_id = *reinterpret_cast<const test_type_identifier_t*>(
|
||||
buffer_data.data() + buffer_pos);
|
||||
buffer_pos += sizeof(test_type_identifier_t);
|
||||
|
||||
auto size = *reinterpret_cast<const size_t*>(buffer_data.data() + buffer_pos);
|
||||
buffer_pos += sizeof(size_t) + size;
|
||||
|
||||
if(type_id != test_type_identifier_t::fragmented_space)
|
||||
{
|
||||
actual_samples++;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(actual_samples, num_threads * items_per_thread);
|
||||
}
|
||||
|
||||
TEST_F(buffer_storage_test, repeated_fragmentation)
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<mock_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
SetUpStartStopOnCall();
|
||||
EXPECT_CALL(*g_mock_worker, start).Times(1);
|
||||
EXPECT_CALL(*g_mock_worker, stop).Times(1);
|
||||
|
||||
storage.start();
|
||||
|
||||
const size_t fragment_trigger_size = rocprofsys::trace_cache::buffer_size / 5;
|
||||
std::vector<uint8_t> fragment_payload(fragment_trigger_size, 0xDD);
|
||||
const int cycle_count = 3;
|
||||
const int iter_count = 2;
|
||||
|
||||
for(int cycle = 0; cycle < cycle_count; ++cycle)
|
||||
{
|
||||
for(int i = 0; i < iter_count; ++i)
|
||||
{
|
||||
test_sample_3 sample(fragment_payload);
|
||||
EXPECT_NO_THROW(storage.store(sample));
|
||||
}
|
||||
|
||||
test_sample_1 small_sample(cycle, "cycle_" + std::to_string(cycle));
|
||||
EXPECT_NO_THROW(storage.store(small_sample));
|
||||
|
||||
g_mock_worker->execute_flush(true);
|
||||
}
|
||||
|
||||
EXPECT_NO_THROW(storage.shutdown());
|
||||
|
||||
std::string buffer_data = g_mock_worker->m_output_string_stream.str();
|
||||
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buffer_data.data());
|
||||
size_t buffer_pos = 0;
|
||||
size_t fragmented_space_count = 0;
|
||||
size_t sample1_count = 0;
|
||||
size_t sample3_count = 0;
|
||||
|
||||
while(buffer_pos < buffer_data.size())
|
||||
{
|
||||
auto type_id =
|
||||
*reinterpret_cast<const test_type_identifier_t*>(buffer + buffer_pos);
|
||||
buffer_pos += sizeof(test_type_identifier_t);
|
||||
|
||||
auto size = *reinterpret_cast<const size_t*>(buffer + buffer_pos);
|
||||
buffer_pos += sizeof(size_t) + size;
|
||||
|
||||
switch(type_id)
|
||||
{
|
||||
case test_type_identifier_t::sample_type_1: sample1_count++; break;
|
||||
case test_type_identifier_t::sample_type_3: sample3_count++; break;
|
||||
case test_type_identifier_t::fragmented_space:
|
||||
fragmented_space_count++;
|
||||
break;
|
||||
case test_type_identifier_t::sample_type_2:
|
||||
FAIL() << "Unexpected sample type";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(sample1_count, cycle_count);
|
||||
EXPECT_EQ(sample3_count, cycle_count * iter_count);
|
||||
EXPECT_GT(fragmented_space_count, 0);
|
||||
}
|
||||
+556
@@ -0,0 +1,556 @@
|
||||
// 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 "mocked_types.hpp"
|
||||
|
||||
#include "core/trace_cache/buffer_storage.hpp"
|
||||
#include "core/trace_cache/storage_parser.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct sample_1_hash
|
||||
{
|
||||
size_t operator()(const test_sample_1& s) const
|
||||
{
|
||||
size_t h = std::hash<int>{}(s.value);
|
||||
|
||||
for(size_t i = 0; i < s.text.size(); ++i)
|
||||
{
|
||||
h ^= std::hash<char>{}(s.text[i]) + 0x9e3779b9 + (h << 6) + (h >> 2) + i;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct sample_2_hash
|
||||
{
|
||||
size_t operator()(const test_sample_2& s) const
|
||||
{
|
||||
size_t h1 = std::hash<double>{}(s.data);
|
||||
size_t h2 = std::hash<uint32_t>{}(s.sample_id);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct sample_3_hash
|
||||
{
|
||||
size_t operator()(const test_sample_3& s) const
|
||||
{
|
||||
size_t h = 0;
|
||||
for(auto byte : s.payload)
|
||||
{
|
||||
h ^= std::hash<uint8_t>{}(byte) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class integration_sample_processor_t
|
||||
{
|
||||
public:
|
||||
integration_sample_processor_t() = default;
|
||||
|
||||
void set_expected_samples_1(const std::vector<test_sample_1>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_1.clear();
|
||||
for(const auto& s : samples)
|
||||
{
|
||||
m_expected_samples_1[s]++;
|
||||
}
|
||||
}
|
||||
|
||||
void set_expected_samples_2(const std::vector<test_sample_2>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_2.clear();
|
||||
for(const auto& s : samples)
|
||||
{
|
||||
m_expected_samples_2[s]++;
|
||||
}
|
||||
}
|
||||
|
||||
void set_expected_samples_3(const std::vector<test_sample_3>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_3.clear();
|
||||
for(const auto& s : samples)
|
||||
{
|
||||
m_expected_samples_3[s]++;
|
||||
}
|
||||
}
|
||||
|
||||
void execute_sample_processing(test_type_identifier_t type_identifier,
|
||||
const rocprofsys::trace_cache::cacheable_t& value)
|
||||
{
|
||||
switch(type_identifier)
|
||||
{
|
||||
case test_type_identifier_t::sample_type_1:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_1&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_sample_1_count++;
|
||||
check_sample_1(sample);
|
||||
break;
|
||||
}
|
||||
case test_type_identifier_t::sample_type_2:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_2&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_sample_2_count++;
|
||||
check_sample_2(sample);
|
||||
break;
|
||||
}
|
||||
case test_type_identifier_t::sample_type_3:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_3&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_sample_3_count++;
|
||||
check_sample_3(sample);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
int get_sample_1_count() const { return m_sample_1_count.load(); }
|
||||
int get_sample_2_count() const { return m_sample_2_count.load(); }
|
||||
int get_sample_3_count() const { return m_sample_3_count.load(); }
|
||||
bool all_expected_samples_found() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
return m_expected_samples_1.empty() && m_expected_samples_2.empty() &&
|
||||
m_expected_samples_3.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
void check_sample_1(const test_sample_1& sample)
|
||||
{
|
||||
auto it = m_expected_samples_1.find(sample);
|
||||
EXPECT_NE(it, m_expected_samples_1.end());
|
||||
if(it != m_expected_samples_1.end())
|
||||
{
|
||||
it->second--;
|
||||
if(it->second == 0)
|
||||
{
|
||||
m_expected_samples_1.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_sample_2(const test_sample_2& sample)
|
||||
{
|
||||
auto it = m_expected_samples_2.find(sample);
|
||||
EXPECT_NE(it, m_expected_samples_2.end());
|
||||
if(it != m_expected_samples_2.end())
|
||||
{
|
||||
it->second--;
|
||||
if(it->second == 0)
|
||||
{
|
||||
m_expected_samples_2.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_sample_3(const test_sample_3& sample)
|
||||
{
|
||||
auto it = m_expected_samples_3.find(sample);
|
||||
EXPECT_NE(it, m_expected_samples_3.end());
|
||||
if(it != m_expected_samples_3.end())
|
||||
{
|
||||
it->second--;
|
||||
if(it->second == 0)
|
||||
{
|
||||
m_expected_samples_3.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<int> m_sample_1_count{ 0 };
|
||||
std::atomic<int> m_sample_2_count{ 0 };
|
||||
std::atomic<int> m_sample_3_count{ 0 };
|
||||
std::unordered_map<test_sample_1, int, sample_1_hash> m_expected_samples_1;
|
||||
std::unordered_map<test_sample_2, int, sample_2_hash> m_expected_samples_2;
|
||||
std::unordered_map<test_sample_3, int, sample_3_hash> m_expected_samples_3;
|
||||
mutable std::mutex m_data_mutex;
|
||||
};
|
||||
|
||||
class trace_cache_module_integration_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
test_file_path =
|
||||
"integration_test_cache_" + std::to_string(test_counter++) + ".bin";
|
||||
std::remove(test_file_path.c_str());
|
||||
}
|
||||
|
||||
void TearDown() override { std::remove(test_file_path.c_str()); }
|
||||
|
||||
std::string test_file_path;
|
||||
static std::atomic<int> test_counter;
|
||||
};
|
||||
|
||||
std::atomic<int> trace_cache_module_integration_test::test_counter{ 0 };
|
||||
|
||||
TEST_F(trace_cache_module_integration_test, buffer_fragmentation_handling)
|
||||
{
|
||||
std::vector<std::string> large_texts;
|
||||
large_texts.reserve(100);
|
||||
std::vector<test_sample_1> large_samples;
|
||||
large_samples.reserve(100);
|
||||
std::vector<test_sample_3> small_samples;
|
||||
small_samples.reserve(100);
|
||||
|
||||
for(int i = 0; i < 100; ++i)
|
||||
{
|
||||
large_texts.push_back(std::string(1000, 'A' + (i % 26)));
|
||||
large_samples.push_back({ i, large_texts[i] });
|
||||
|
||||
std::vector<uint8_t> small_payload(10, static_cast<uint8_t>(i));
|
||||
small_samples.emplace_back(small_payload);
|
||||
}
|
||||
|
||||
std::vector<test_sample_1> expected_1;
|
||||
std::vector<test_sample_3> expected_3;
|
||||
expected_1.reserve(100);
|
||||
expected_3.reserve(50);
|
||||
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<
|
||||
rocprofsys::trace_cache::flush_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
storage.start();
|
||||
|
||||
for(size_t i = 0; i < large_samples.size(); ++i)
|
||||
{
|
||||
storage.store(large_samples[i]);
|
||||
expected_1.push_back(large_samples[i]);
|
||||
if(i % 2 == 0 && i < small_samples.size())
|
||||
{
|
||||
storage.store(small_samples[i]);
|
||||
expected_3.push_back(small_samples[i]);
|
||||
}
|
||||
}
|
||||
|
||||
storage.shutdown();
|
||||
}
|
||||
|
||||
auto processor = std::make_shared<integration_sample_processor_t>();
|
||||
processor->set_expected_samples_1(expected_1);
|
||||
processor->set_expected_samples_3(expected_3);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
parser.load(processor);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 100);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 50);
|
||||
EXPECT_EQ(processor->get_sample_1_count() + processor->get_sample_3_count(), 150);
|
||||
}
|
||||
|
||||
TEST_F(trace_cache_module_integration_test, content_validation_edge_cases)
|
||||
{
|
||||
std::vector<std::string> strings;
|
||||
strings.reserve(4);
|
||||
strings.emplace_back("max_value");
|
||||
strings.emplace_back("min_value");
|
||||
strings.emplace_back("");
|
||||
strings.emplace_back("Special\n\t\r\0chars");
|
||||
|
||||
test_sample_1 max_int(std::numeric_limits<int>::max(), strings[0]);
|
||||
test_sample_1 min_int(std::numeric_limits<int>::min(), strings[1]);
|
||||
test_sample_1 zero_int(0, strings[2]);
|
||||
test_sample_1 special_chars(123, strings[3]);
|
||||
|
||||
test_sample_2 max_double(std::numeric_limits<double>::max(),
|
||||
std::numeric_limits<uint32_t>::max());
|
||||
test_sample_2 min_double(std::numeric_limits<double>::lowest(), 0);
|
||||
test_sample_2 infinity(std::numeric_limits<double>::infinity(), 42);
|
||||
test_sample_2 neg_infinity(-std::numeric_limits<double>::infinity(), 43);
|
||||
|
||||
std::vector<uint8_t> max_vector(10000, 0xFF);
|
||||
test_sample_3 large_payload(max_vector);
|
||||
test_sample_3 empty_payload;
|
||||
std::vector<uint8_t> single_zero = { 0x00 };
|
||||
test_sample_3 zero_payload(single_zero);
|
||||
|
||||
std::vector<test_sample_1> expected_1;
|
||||
std::vector<test_sample_2> expected_2;
|
||||
std::vector<test_sample_3> expected_3;
|
||||
expected_1.reserve(4);
|
||||
expected_2.reserve(4);
|
||||
expected_3.reserve(3);
|
||||
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<
|
||||
rocprofsys::trace_cache::flush_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
storage.start();
|
||||
|
||||
storage.store(max_int);
|
||||
expected_1.push_back(max_int);
|
||||
storage.store(min_int);
|
||||
expected_1.push_back(min_int);
|
||||
storage.store(zero_int);
|
||||
expected_1.push_back(zero_int);
|
||||
storage.store(special_chars);
|
||||
expected_1.push_back(special_chars);
|
||||
|
||||
storage.store(max_double);
|
||||
expected_2.push_back(max_double);
|
||||
storage.store(min_double);
|
||||
expected_2.push_back(min_double);
|
||||
storage.store(infinity);
|
||||
expected_2.push_back(infinity);
|
||||
storage.store(neg_infinity);
|
||||
expected_2.push_back(neg_infinity);
|
||||
|
||||
storage.store(large_payload);
|
||||
expected_3.push_back(large_payload);
|
||||
storage.store(empty_payload);
|
||||
expected_3.push_back(empty_payload);
|
||||
storage.store(zero_payload);
|
||||
expected_3.push_back(zero_payload);
|
||||
|
||||
storage.shutdown();
|
||||
}
|
||||
|
||||
auto processor = std::make_shared<integration_sample_processor_t>();
|
||||
processor->set_expected_samples_1(expected_1);
|
||||
processor->set_expected_samples_2(expected_2);
|
||||
processor->set_expected_samples_3(expected_3);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
parser.load(processor);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 4);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 4);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 3);
|
||||
}
|
||||
|
||||
TEST_F(trace_cache_module_integration_test, stress_test_multiple_fragmentations)
|
||||
{
|
||||
const int iterations = 10;
|
||||
const int samples_per_iteration = 10000;
|
||||
|
||||
std::mt19937 rng(42);
|
||||
std::uniform_int_distribution<int> value_dist(1, 1000);
|
||||
std::uniform_int_distribution<size_t> size_dist(1, 500);
|
||||
|
||||
std::vector<std::string> texts;
|
||||
texts.reserve(iterations * samples_per_iteration);
|
||||
std::vector<test_sample_1> expected_1;
|
||||
expected_1.reserve(iterations * samples_per_iteration);
|
||||
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<
|
||||
rocprofsys::trace_cache::flush_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
storage.start();
|
||||
|
||||
for(int iter = 0; iter < iterations; ++iter)
|
||||
{
|
||||
for(int i = 0; i < samples_per_iteration; ++i)
|
||||
{
|
||||
int value = value_dist(rng);
|
||||
size_t text_size = size_dist(rng);
|
||||
texts.push_back(std::string(text_size, 'X'));
|
||||
|
||||
test_sample_1 sample(value, texts.back());
|
||||
expected_1.push_back(sample);
|
||||
storage.store(sample);
|
||||
}
|
||||
}
|
||||
|
||||
storage.shutdown();
|
||||
}
|
||||
|
||||
auto processor = std::make_shared<integration_sample_processor_t>();
|
||||
processor->set_expected_samples_1(expected_1);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
parser.load(processor);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), iterations * samples_per_iteration);
|
||||
}
|
||||
|
||||
TEST_F(trace_cache_module_integration_test, performance_write_test)
|
||||
{
|
||||
const int sample_count = 50000;
|
||||
const size_t payload_size = 1024 * 2;
|
||||
|
||||
std::vector<std::string> payloads;
|
||||
payloads.reserve(sample_count);
|
||||
std::vector<test_sample_1> samples;
|
||||
samples.reserve(sample_count);
|
||||
for(int i = 0; i < sample_count; ++i)
|
||||
{
|
||||
payloads.push_back(std::string(payload_size, static_cast<char>(i % 255)));
|
||||
samples.push_back({ i, payloads[i] });
|
||||
}
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<
|
||||
rocprofsys::trace_cache::flush_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
storage.start();
|
||||
|
||||
for(const auto& sample : samples)
|
||||
{
|
||||
storage.store(sample);
|
||||
}
|
||||
|
||||
storage.shutdown();
|
||||
}
|
||||
|
||||
using unit = std::chrono::microseconds;
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto duration_in_microseconds =
|
||||
std::chrono::duration_cast<unit>(end_time - start_time);
|
||||
auto period = static_cast<double>(unit::period().den);
|
||||
|
||||
double avg_write_time =
|
||||
static_cast<double>(duration_in_microseconds.count()) / sample_count;
|
||||
double throughput =
|
||||
(sample_count * payload_size) / (duration_in_microseconds.count() / period);
|
||||
|
||||
EXPECT_LT(avg_write_time, 50.0);
|
||||
EXPECT_GT(throughput, 10 * 1024.0);
|
||||
|
||||
auto processor = std::make_shared<integration_sample_processor_t>();
|
||||
processor->set_expected_samples_1(samples);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
parser.load(processor);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), sample_count);
|
||||
}
|
||||
|
||||
TEST_F(trace_cache_module_integration_test, concurrent_write_read_validation)
|
||||
{
|
||||
const int thread_count = 4;
|
||||
const int samples_per_thread = 250;
|
||||
const int total_samples = thread_count * samples_per_thread;
|
||||
std::vector<std::thread> writers;
|
||||
std::vector<int> thread_counters(thread_count, 0);
|
||||
|
||||
std::vector<std::vector<std::string>> thread_strings(thread_count);
|
||||
for(int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
thread_strings[t].reserve(samples_per_thread);
|
||||
for(int i = 0; i < samples_per_thread; ++i)
|
||||
{
|
||||
thread_strings[t].push_back("thread_" + std::to_string(t) + "_sample_" +
|
||||
std::to_string(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<test_sample_1> expected_1;
|
||||
expected_1.reserve(total_samples);
|
||||
|
||||
for(int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
for(int i = 0; i < samples_per_thread; ++i)
|
||||
{
|
||||
expected_1.emplace_back(t, thread_strings[t][i]);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
rocprofsys::trace_cache::buffer_storage<
|
||||
rocprofsys::trace_cache::flush_worker_factory_t, test_type_identifier_t>
|
||||
storage(test_file_path);
|
||||
storage.start();
|
||||
|
||||
for(int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
writers.emplace_back([&, thread_id = t]() {
|
||||
for(int i = 0; i < samples_per_thread; ++i)
|
||||
{
|
||||
test_sample_1 sample(thread_id, thread_strings[thread_id][i]);
|
||||
|
||||
storage.store(sample);
|
||||
thread_counters[thread_id]++;
|
||||
|
||||
if(i % 10 == 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& writer : writers)
|
||||
{
|
||||
writer.join();
|
||||
}
|
||||
|
||||
storage.shutdown();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
int total_written = 0;
|
||||
for(int counter : thread_counters)
|
||||
{
|
||||
EXPECT_EQ(counter, samples_per_thread);
|
||||
total_written += counter;
|
||||
}
|
||||
EXPECT_EQ(total_written, total_samples);
|
||||
|
||||
auto processor = std::make_shared<integration_sample_processor_t>();
|
||||
processor->set_expected_samples_1(expected_1);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
parser.load(processor);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), total_samples);
|
||||
EXPECT_TRUE(processor->all_expected_samples_found());
|
||||
}
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
// 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 "core/trace_cache/cacheable.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
class cacheable_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
buffer.fill(0);
|
||||
position = 0;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 1024> buffer;
|
||||
size_t position;
|
||||
};
|
||||
|
||||
TEST_F(cacheable_test, store_value_int)
|
||||
{
|
||||
int value = 42;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(int));
|
||||
int stored_value = *reinterpret_cast<int*>(buffer.data());
|
||||
EXPECT_EQ(stored_value, 42);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_double)
|
||||
{
|
||||
double value = 3.14159;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(double));
|
||||
double stored_value = *reinterpret_cast<double*>(buffer.data());
|
||||
EXPECT_DOUBLE_EQ(stored_value, 3.14159);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_unsigned_long)
|
||||
{
|
||||
unsigned long value = 123456789UL;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(unsigned long));
|
||||
unsigned long stored_value = *reinterpret_cast<unsigned long*>(buffer.data());
|
||||
EXPECT_EQ(stored_value, 123456789UL);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_unsigned_char)
|
||||
{
|
||||
unsigned char value = 255;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(unsigned char));
|
||||
unsigned char stored_value = *reinterpret_cast<unsigned char*>(buffer.data());
|
||||
EXPECT_EQ(stored_value, 255);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_string_literal)
|
||||
{
|
||||
auto value = "Hello World"sv;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
size_t expected_size = value.size() + sizeof(size_t);
|
||||
EXPECT_EQ(position, expected_size);
|
||||
|
||||
std::string stored_value(
|
||||
reinterpret_cast<const char*>(buffer.data() + sizeof(size_t)));
|
||||
EXPECT_EQ(stored_value, "Hello World");
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_empty_string)
|
||||
{
|
||||
auto value = ""sv;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(size_t));
|
||||
EXPECT_EQ(buffer[0], '\0');
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_byte_array)
|
||||
{
|
||||
std::vector<uint8_t> value = { 1, 2, 3, 4, 5 };
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
size_t expected_size = value.size() + sizeof(size_t);
|
||||
EXPECT_EQ(position, expected_size);
|
||||
|
||||
size_t stored_size = *reinterpret_cast<size_t*>(buffer.data());
|
||||
EXPECT_EQ(stored_size, 5);
|
||||
|
||||
uint8_t* data_start = buffer.data() + sizeof(size_t);
|
||||
for(size_t i = 0; i < value.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(data_start[i], value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_value_empty_byte_array)
|
||||
{
|
||||
std::vector<uint8_t> value;
|
||||
rocprofsys::trace_cache::utility::store_value(value, buffer.data(), position);
|
||||
|
||||
EXPECT_EQ(position, sizeof(size_t));
|
||||
size_t stored_size = *reinterpret_cast<size_t*>(buffer.data());
|
||||
EXPECT_EQ(stored_size, 0);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, store_multiple_values)
|
||||
{
|
||||
int int_val = 100;
|
||||
double double_val = 2.718;
|
||||
auto str_val = "test"sv;
|
||||
|
||||
rocprofsys::trace_cache::utility::store_value(int_val, buffer.data(), position);
|
||||
rocprofsys::trace_cache::utility::store_value(double_val, buffer.data(), position);
|
||||
rocprofsys::trace_cache::utility::store_value(str_val, buffer.data(), position);
|
||||
|
||||
size_t expected_total =
|
||||
sizeof(int) + sizeof(double) + str_val.size() + sizeof(size_t);
|
||||
EXPECT_EQ(position, expected_total);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_int)
|
||||
{
|
||||
int original_value = 987;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
int parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value, 987);
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(int));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_double)
|
||||
{
|
||||
double original_value = 1.618033988;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
double parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_DOUBLE_EQ(parsed_value, 1.618033988);
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(double));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_unsigned_long)
|
||||
{
|
||||
unsigned long original_value = 0xDEADBEEF;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
unsigned long parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value, 0xDEADBEEF);
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(unsigned long));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_string)
|
||||
{
|
||||
auto original_value = "Parse this string"sv;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
std::string_view parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value, "Parse this string");
|
||||
EXPECT_EQ(data_pos, buffer.data() + original_value.size() + sizeof(size_t));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_empty_string)
|
||||
{
|
||||
auto original_value = ""sv;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
std::string_view parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value, "");
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(size_t));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_byte_array)
|
||||
{
|
||||
std::vector<uint8_t> original_value = { 10, 20, 30, 40, 50 };
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
std::vector<uint8_t> parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value.size(), 5);
|
||||
EXPECT_EQ(parsed_value, original_value);
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(size_t) + original_value.size());
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, parse_value_empty_byte_array)
|
||||
{
|
||||
std::vector<uint8_t> original_value;
|
||||
rocprofsys::trace_cache::utility::store_value(original_value, buffer.data(),
|
||||
position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
std::vector<uint8_t> parsed_value;
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_value);
|
||||
|
||||
EXPECT_EQ(parsed_value.size(), 0);
|
||||
EXPECT_TRUE(parsed_value.empty());
|
||||
EXPECT_EQ(data_pos, buffer.data() + sizeof(size_t));
|
||||
}
|
||||
TEST_F(cacheable_test, parse_multiple_values)
|
||||
{
|
||||
int int_val = 42;
|
||||
double double_val = 3.14;
|
||||
auto str_val = "multi"sv;
|
||||
unsigned char uchar_val = 128;
|
||||
|
||||
rocprofsys::trace_cache::utility::store_value(int_val, buffer.data(), position);
|
||||
rocprofsys::trace_cache::utility::store_value(double_val, buffer.data(), position);
|
||||
rocprofsys::trace_cache::utility::store_value(str_val, buffer.data(), position);
|
||||
rocprofsys::trace_cache::utility::store_value(uchar_val, buffer.data(), position);
|
||||
|
||||
uint8_t* data_pos = buffer.data();
|
||||
|
||||
int parsed_int;
|
||||
double parsed_double;
|
||||
std::string_view parsed_string;
|
||||
unsigned char parsed_uchar;
|
||||
|
||||
rocprofsys::trace_cache::utility::parse_value(data_pos, parsed_int, parsed_double,
|
||||
parsed_string, parsed_uchar);
|
||||
|
||||
EXPECT_EQ(parsed_int, 42);
|
||||
EXPECT_DOUBLE_EQ(parsed_double, 3.14);
|
||||
EXPECT_EQ(parsed_string, "multi");
|
||||
EXPECT_EQ(parsed_uchar, 128);
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, get_size_helper_int)
|
||||
{
|
||||
int value = 42;
|
||||
size_t size = rocprofsys::trace_cache::utility::get_size(value);
|
||||
EXPECT_EQ(size, sizeof(int));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, get_size_helper_double)
|
||||
{
|
||||
double value = 3.14;
|
||||
size_t size = rocprofsys::trace_cache::utility::get_size(value);
|
||||
EXPECT_EQ(size, sizeof(double));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, get_size_helper_string_literal)
|
||||
{
|
||||
auto value = "test string"sv;
|
||||
size_t size = rocprofsys::trace_cache::utility::get_size(value);
|
||||
EXPECT_EQ(size, value.size() + sizeof(size_t));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, get_size_helper_byte_array)
|
||||
{
|
||||
std::vector<uint8_t> value = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
size_t size = rocprofsys::trace_cache::utility::get_size(value);
|
||||
EXPECT_EQ(size, value.size() + sizeof(size_t));
|
||||
}
|
||||
|
||||
TEST_F(cacheable_test, get_buffered_storage_filename)
|
||||
{
|
||||
int ppid = 1234;
|
||||
int pid = 5678;
|
||||
|
||||
std::string filename =
|
||||
rocprofsys::trace_cache::utility::get_buffered_storage_filename(ppid, pid);
|
||||
std::string expected = "/tmp/buffered_storage_1234_5678.bin";
|
||||
|
||||
EXPECT_EQ(filename, expected);
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
// 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 "core/trace_cache/buffer_storage.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
|
||||
class flush_worker_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
test_file_path =
|
||||
"flush_test_" + std::to_string(test_counter.fetch_add(1)) + ".bin";
|
||||
std::remove(test_file_path.c_str());
|
||||
worker_sync =
|
||||
std::make_shared<rocprofsys::trace_cache::worker_synchronization_t>();
|
||||
}
|
||||
|
||||
void TearDown() override { std::remove(test_file_path.c_str()); }
|
||||
|
||||
rocprofsys::trace_cache::worker_synchronization_ptr_t worker_sync;
|
||||
std::string test_file_path;
|
||||
static std::atomic<int> test_counter;
|
||||
};
|
||||
|
||||
std::atomic<int> flush_worker_test::test_counter{ 0 };
|
||||
|
||||
TEST_F(flush_worker_test, start_worker_in_correct_state)
|
||||
{
|
||||
bool worker_called = false;
|
||||
auto worker_function = [&](rocprofsys::trace_cache::ofs_t&, bool) {
|
||||
worker_called = true;
|
||||
};
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
test_file_path);
|
||||
pid_t current_pid = getpid();
|
||||
|
||||
worker.start(current_pid);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
EXPECT_TRUE(worker_sync->is_running);
|
||||
EXPECT_EQ(worker_sync->origin_pid, current_pid);
|
||||
|
||||
worker.stop(current_pid);
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, stop_worker_complete)
|
||||
{
|
||||
std::atomic<bool> worker_called{ false };
|
||||
auto worker_function = [&](rocprofsys::trace_cache::ofs_t&, bool) {
|
||||
worker_called = true;
|
||||
};
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
test_file_path);
|
||||
pid_t current_pid = getpid();
|
||||
|
||||
worker.start(current_pid);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
worker.stop(current_pid);
|
||||
|
||||
EXPECT_TRUE(worker_sync->exit_finished);
|
||||
EXPECT_FALSE(worker_sync->is_running);
|
||||
EXPECT_TRUE(worker_called);
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, worker_function_called_on_stop)
|
||||
{
|
||||
std::atomic<int> call_count{ 0 };
|
||||
std::atomic<bool> force_flag{ false };
|
||||
auto worker_function = [&](rocprofsys::trace_cache::ofs_t&, bool force) {
|
||||
call_count++;
|
||||
force_flag = force;
|
||||
};
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
test_file_path);
|
||||
pid_t current_pid = getpid();
|
||||
|
||||
worker.start(current_pid);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
worker.stop(current_pid);
|
||||
|
||||
EXPECT_GE(call_count.load(), 1);
|
||||
EXPECT_TRUE(force_flag);
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, multiple_stop_calls_are_safe)
|
||||
{
|
||||
auto worker_function = [](rocprofsys::trace_cache::ofs_t&, bool) {};
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
test_file_path);
|
||||
pid_t current_pid = getpid();
|
||||
|
||||
worker.start(current_pid);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
worker.stop(current_pid);
|
||||
worker.stop(current_pid);
|
||||
worker.stop(current_pid);
|
||||
|
||||
EXPECT_TRUE(worker_sync->exit_finished);
|
||||
EXPECT_FALSE(worker_sync->is_running);
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, worker_factory_creates_valid_object)
|
||||
{
|
||||
auto worker_function = [](rocprofsys::trace_cache::ofs_t&, bool) {};
|
||||
|
||||
auto worker = rocprofsys::trace_cache::flush_worker_factory_t::get_worker(
|
||||
worker_function, worker_sync, test_file_path);
|
||||
|
||||
EXPECT_NE(worker, nullptr);
|
||||
EXPECT_EQ(typeid(*worker), typeid(rocprofsys::trace_cache::flush_worker_t));
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, worker_handles_invalid_path)
|
||||
{
|
||||
auto worker_function = [](rocprofsys::trace_cache::ofs_t&, bool) {};
|
||||
std::string invalid_path = "/invalid/path/file.bin";
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
invalid_path);
|
||||
pid_t current_pid = getpid();
|
||||
|
||||
EXPECT_THROW(worker.start(current_pid), std::runtime_error);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
worker.stop(current_pid);
|
||||
|
||||
EXPECT_FALSE(worker_sync->exit_finished);
|
||||
EXPECT_FALSE(worker_sync->is_running);
|
||||
}
|
||||
|
||||
TEST_F(flush_worker_test, different_pid_start_stop)
|
||||
{
|
||||
std::atomic<bool> worker_called{ false };
|
||||
auto worker_function = [&](rocprofsys::trace_cache::ofs_t&, bool) {
|
||||
worker_called = true;
|
||||
};
|
||||
|
||||
rocprofsys::trace_cache::flush_worker_t worker(worker_function, worker_sync,
|
||||
test_file_path);
|
||||
pid_t parent_pid = getpid();
|
||||
|
||||
worker.start(parent_pid);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
EXPECT_TRUE(worker_sync->is_running);
|
||||
EXPECT_EQ(worker_sync->origin_pid, parent_pid);
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if(child_pid == 0)
|
||||
{
|
||||
pid_t current_child_pid = getpid();
|
||||
worker.stop(current_child_pid);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
bool still_running = worker_sync->is_running;
|
||||
bool exit_finished = worker_sync->exit_finished;
|
||||
|
||||
exit(still_running ? 1 : (exit_finished ? 2 : 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
int status;
|
||||
waitpid(child_pid, &status, 0);
|
||||
int child_exit_code = WEXITSTATUS(status);
|
||||
|
||||
EXPECT_EQ(child_exit_code, 0);
|
||||
EXPECT_FALSE(worker_sync->exit_finished);
|
||||
EXPECT_TRUE(worker_sync->is_running);
|
||||
|
||||
worker.stop(parent_pid);
|
||||
EXPECT_TRUE(worker_sync->exit_finished);
|
||||
EXPECT_FALSE(worker_sync->is_running);
|
||||
EXPECT_TRUE(worker_called);
|
||||
}
|
||||
}
|
||||
+568
@@ -0,0 +1,568 @@
|
||||
// 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 "core/trace_cache/sample_type.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace rocprofsys::trace_cache;
|
||||
|
||||
class sample_type_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override { buffer.fill(0); }
|
||||
|
||||
std::array<uint8_t, 4096> buffer;
|
||||
};
|
||||
|
||||
TEST_F(sample_type_test, kernel_dispatch_sample_serialize_deserialize)
|
||||
{
|
||||
kernel_dispatch_sample original(1000, 2000, 42, 100, 200, 300, 400, 500, 600, 1024,
|
||||
2048, 64, 32, 16, 256, 128, 64, 0xABCD);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<kernel_dispatch_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.start_timestamp, original.start_timestamp);
|
||||
EXPECT_EQ(deserialized.end_timestamp, original.end_timestamp);
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.agent_id_handle, original.agent_id_handle);
|
||||
EXPECT_EQ(deserialized.kernel_id, original.kernel_id);
|
||||
EXPECT_EQ(deserialized.dispatch_id, original.dispatch_id);
|
||||
EXPECT_EQ(deserialized.queue_id_handle, original.queue_id_handle);
|
||||
EXPECT_EQ(deserialized.correlation_id_internal, original.correlation_id_internal);
|
||||
EXPECT_EQ(deserialized.correlation_id_ancestor, original.correlation_id_ancestor);
|
||||
EXPECT_EQ(deserialized.private_segment_size, original.private_segment_size);
|
||||
EXPECT_EQ(deserialized.group_segment_size, original.group_segment_size);
|
||||
EXPECT_EQ(deserialized.workgroup_size_x, original.workgroup_size_x);
|
||||
EXPECT_EQ(deserialized.workgroup_size_y, original.workgroup_size_y);
|
||||
EXPECT_EQ(deserialized.workgroup_size_z, original.workgroup_size_z);
|
||||
EXPECT_EQ(deserialized.grid_size_x, original.grid_size_x);
|
||||
EXPECT_EQ(deserialized.grid_size_y, original.grid_size_y);
|
||||
EXPECT_EQ(deserialized.grid_size_z, original.grid_size_z);
|
||||
EXPECT_EQ(deserialized.stream_handle, original.stream_handle);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, kernel_dispatch_sample_get_size)
|
||||
{
|
||||
kernel_dispatch_sample sample(1000, 2000, 42, 100, 200, 300, 400, 500, 600, 1024,
|
||||
2048, 64, 32, 16, 256, 128, 64, 0xABCD);
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) * 9 + sizeof(uint32_t) * 8 + sizeof(uint64_t);
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, kernel_dispatch_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(kernel_dispatch_sample::type_identifier,
|
||||
type_identifier_t::kernel_dispatch);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_copy_sample_serialize_deserialize)
|
||||
{
|
||||
memory_copy_sample original(5000, 6000, 123, 200, 201, 1, 2, 4096, 700, 800, 0x1000,
|
||||
0x2000, 0xDEAD);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<memory_copy_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.start_timestamp, original.start_timestamp);
|
||||
EXPECT_EQ(deserialized.end_timestamp, original.end_timestamp);
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.dst_agent_id_handle, original.dst_agent_id_handle);
|
||||
EXPECT_EQ(deserialized.src_agent_id_handle, original.src_agent_id_handle);
|
||||
EXPECT_EQ(deserialized.kind, original.kind);
|
||||
EXPECT_EQ(deserialized.operation, original.operation);
|
||||
EXPECT_EQ(deserialized.bytes, original.bytes);
|
||||
EXPECT_EQ(deserialized.correlation_id_internal, original.correlation_id_internal);
|
||||
EXPECT_EQ(deserialized.correlation_id_ancestor, original.correlation_id_ancestor);
|
||||
EXPECT_EQ(deserialized.dst_address_value, original.dst_address_value);
|
||||
EXPECT_EQ(deserialized.src_address_value, original.src_address_value);
|
||||
EXPECT_EQ(deserialized.stream_handle, original.stream_handle);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_copy_sample_get_size)
|
||||
{
|
||||
memory_copy_sample sample(5000, 6000, 123, 200, 201, 1, 2, 4096, 700, 800, 0x1000,
|
||||
0x2000, 0xDEAD);
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) * 11 + sizeof(int32_t) * 2;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_copy_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(memory_copy_sample::type_identifier, type_identifier_t::memory_copy);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_allocate_sample_serialize_deserialize)
|
||||
{
|
||||
memory_allocate_sample original(7000, 8000, 456, 300, 3, 4, 8192, 900, 1000, 0x3000,
|
||||
0xBEEF);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<memory_allocate_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.start_timestamp, original.start_timestamp);
|
||||
EXPECT_EQ(deserialized.end_timestamp, original.end_timestamp);
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.agent_id_handle, original.agent_id_handle);
|
||||
EXPECT_EQ(deserialized.kind, original.kind);
|
||||
EXPECT_EQ(deserialized.operation, original.operation);
|
||||
EXPECT_EQ(deserialized.allocation_size, original.allocation_size);
|
||||
EXPECT_EQ(deserialized.correlation_id_internal, original.correlation_id_internal);
|
||||
EXPECT_EQ(deserialized.correlation_id_ancestor, original.correlation_id_ancestor);
|
||||
EXPECT_EQ(deserialized.address_value, original.address_value);
|
||||
EXPECT_EQ(deserialized.stream_handle, original.stream_handle);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_allocate_sample_get_size)
|
||||
{
|
||||
memory_allocate_sample sample(7000, 8000, 456, 300, 3, 4, 8192, 900, 1000, 0x3000,
|
||||
0xBEEF);
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) * 9 + sizeof(int32_t) * 2;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_allocate_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(memory_allocate_sample::type_identifier, type_identifier_t::memory_alloc);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, region_sample_serialize_deserialize)
|
||||
{
|
||||
region_sample original(789, "test_function", 1100, 1200, 10000, 20000,
|
||||
"frame1\nframe2", "arg1=1, arg2=hello", "hip");
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<region_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.name, original.name);
|
||||
EXPECT_EQ(deserialized.correlation_id_internal, original.correlation_id_internal);
|
||||
EXPECT_EQ(deserialized.correlation_id_ancestor, original.correlation_id_ancestor);
|
||||
EXPECT_EQ(deserialized.start_timestamp, original.start_timestamp);
|
||||
EXPECT_EQ(deserialized.end_timestamp, original.end_timestamp);
|
||||
EXPECT_EQ(deserialized.call_stack, original.call_stack);
|
||||
EXPECT_EQ(deserialized.args_str, original.args_str);
|
||||
EXPECT_EQ(deserialized.category, original.category);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, region_sample_get_size)
|
||||
{
|
||||
region_sample sample(789, "test_function", 1100, 1200, 10000, 20000, "frame1\nframe2",
|
||||
"arg1=1, arg2=hello", "hip");
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) * 5 + sizeof(size_t) * 4 + 13 + 13 + 18 + 3;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, region_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(region_sample::type_identifier, type_identifier_t::region);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, region_sample_empty_strings)
|
||||
{
|
||||
region_sample original(123, "", 0, 0, 0, 0, "", "", "");
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<region_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.name, "");
|
||||
EXPECT_EQ(deserialized.call_stack, "");
|
||||
EXPECT_EQ(deserialized.args_str, "");
|
||||
EXPECT_EQ(deserialized.category, "");
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, in_time_sample_serialize_deserialize)
|
||||
{
|
||||
in_time_sample original(42, "GPU:0", 50000, "kernel_launch", 100, 99, 1500,
|
||||
"main\nfoo\nbar", "file.cpp:42");
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<in_time_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.category_enum_id, original.category_enum_id);
|
||||
EXPECT_EQ(deserialized.track_name, original.track_name);
|
||||
EXPECT_EQ(deserialized.timestamp_ns, original.timestamp_ns);
|
||||
EXPECT_EQ(deserialized.event_metadata, original.event_metadata);
|
||||
EXPECT_EQ(deserialized.stack_id, original.stack_id);
|
||||
EXPECT_EQ(deserialized.parent_stack_id, original.parent_stack_id);
|
||||
EXPECT_EQ(deserialized.correlation_id, original.correlation_id);
|
||||
EXPECT_EQ(deserialized.call_stack, original.call_stack);
|
||||
EXPECT_EQ(deserialized.line_info, original.line_info);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, in_time_sample_get_size)
|
||||
{
|
||||
in_time_sample sample(42, "GPU:0", 50000, "kernel_launch", 100, 99, 1500,
|
||||
"main\nfoo\nbar", "file.cpp:42");
|
||||
|
||||
size_t expected_size = sizeof(size_t) + sizeof(size_t) + 5 + sizeof(uint64_t) +
|
||||
sizeof(size_t) + 13 + sizeof(uint64_t) * 3 + sizeof(size_t) +
|
||||
12 + sizeof(size_t) + 11;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, in_time_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(in_time_sample::type_identifier, type_identifier_t::in_time_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, pmc_event_with_sample_serialize_deserialize)
|
||||
{
|
||||
pmc_event_with_sample original(42, "CPU:0", 60000, "counter_sample", 200, 199, 1600,
|
||||
"entry\nexit", "counter.cpp:100", 5, 1,
|
||||
"PERF_COUNT_HW_CPU_CYCLES", 12345.67);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<pmc_event_with_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.category_enum_id, original.category_enum_id);
|
||||
EXPECT_EQ(deserialized.track_name, original.track_name);
|
||||
EXPECT_EQ(deserialized.timestamp_ns, original.timestamp_ns);
|
||||
EXPECT_EQ(deserialized.event_metadata, original.event_metadata);
|
||||
EXPECT_EQ(deserialized.stack_id, original.stack_id);
|
||||
EXPECT_EQ(deserialized.parent_stack_id, original.parent_stack_id);
|
||||
EXPECT_EQ(deserialized.correlation_id, original.correlation_id);
|
||||
EXPECT_EQ(deserialized.call_stack, original.call_stack);
|
||||
EXPECT_EQ(deserialized.line_info, original.line_info);
|
||||
EXPECT_EQ(deserialized.device_id, original.device_id);
|
||||
EXPECT_EQ(deserialized.device_type, original.device_type);
|
||||
EXPECT_EQ(deserialized.pmc_info_name, original.pmc_info_name);
|
||||
EXPECT_DOUBLE_EQ(deserialized.value, original.value);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, pmc_event_with_sample_get_size)
|
||||
{
|
||||
pmc_event_with_sample sample(42, "CPU:0", 60000, "counter_sample", 200, 199, 1600,
|
||||
"entry\nexit", "counter.cpp:100", 5, 1,
|
||||
"PERF_COUNT_HW_CPU_CYCLES", 12345.67);
|
||||
|
||||
size_t expected_size = sizeof(size_t) * 6 + 5 + 14 + 10 + 15 + 24 +
|
||||
sizeof(uint64_t) * 4 + sizeof(uint32_t) + sizeof(uint8_t) +
|
||||
sizeof(double);
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, pmc_event_with_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(pmc_event_with_sample::type_identifier,
|
||||
type_identifier_t::pmc_event_with_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_serialize_deserialize)
|
||||
{
|
||||
std::vector<uint8_t> gpu_activity_data = { 10, 20, 30, 40, 50 };
|
||||
amd_smi_sample original(0xFF, 2, 70000, 80, 60, 40, 250, 75, 1024 * 1024 * 512,
|
||||
gpu_activity_data);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<amd_smi_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.settings, original.settings);
|
||||
EXPECT_EQ(deserialized.device_id, original.device_id);
|
||||
EXPECT_EQ(deserialized.timestamp, original.timestamp);
|
||||
EXPECT_EQ(deserialized.gfx_activity, original.gfx_activity);
|
||||
EXPECT_EQ(deserialized.umc_activity, original.umc_activity);
|
||||
EXPECT_EQ(deserialized.mm_activity, original.mm_activity);
|
||||
EXPECT_EQ(deserialized.power, original.power);
|
||||
EXPECT_EQ(deserialized.temperature, original.temperature);
|
||||
EXPECT_EQ(deserialized.mem_usage, original.mem_usage);
|
||||
EXPECT_EQ(deserialized.gpu_activity.size(), original.gpu_activity.size());
|
||||
EXPECT_EQ(deserialized.gpu_activity, original.gpu_activity);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_get_size)
|
||||
{
|
||||
std::vector<uint8_t> gpu_activity_data = { 10, 20, 30, 40, 50 };
|
||||
amd_smi_sample sample(0xFF, 2, 70000, 80, 60, 40, 250, 75, 1024 * 1024 * 512,
|
||||
gpu_activity_data);
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint64_t) +
|
||||
sizeof(uint32_t) * 4 + sizeof(int64_t) + sizeof(uint64_t) +
|
||||
sizeof(size_t) + 5;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(amd_smi_sample::type_identifier, type_identifier_t::amd_smi_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_empty_gpu_activity)
|
||||
{
|
||||
std::vector<uint8_t> empty_activity;
|
||||
amd_smi_sample original(0, 0, 0, 0, 0, 0, 0, 0, 0, empty_activity);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<amd_smi_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_TRUE(deserialized.gpu_activity.empty());
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, cpu_freq_sample_serialize_deserialize)
|
||||
{
|
||||
std::vector<uint8_t> freqs_data = { 100, 150, 200, 180, 190, 195, 185, 170 };
|
||||
cpu_freq_sample original(80000, 1024, 2048, 4096, 500, 100, 1000000, 500000,
|
||||
freqs_data);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<cpu_freq_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.timestamp, original.timestamp);
|
||||
EXPECT_EQ(deserialized.page_rss, original.page_rss);
|
||||
EXPECT_EQ(deserialized.virt_mem_usage, original.virt_mem_usage);
|
||||
EXPECT_EQ(deserialized.peak_rss, original.peak_rss);
|
||||
EXPECT_EQ(deserialized.context_switch_count, original.context_switch_count);
|
||||
EXPECT_EQ(deserialized.page_faults, original.page_faults);
|
||||
EXPECT_EQ(deserialized.user_mode_time, original.user_mode_time);
|
||||
EXPECT_EQ(deserialized.kernel_mode_time, original.kernel_mode_time);
|
||||
EXPECT_EQ(deserialized.freqs.size(), original.freqs.size());
|
||||
EXPECT_EQ(deserialized.freqs, original.freqs);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, cpu_freq_sample_get_size)
|
||||
{
|
||||
std::vector<uint8_t> freqs_data = { 100, 150, 200, 180, 190, 195, 185, 170 };
|
||||
cpu_freq_sample sample(80000, 1024, 2048, 4096, 500, 100, 1000000, 500000,
|
||||
freqs_data);
|
||||
|
||||
size_t expected_size = sizeof(uint64_t) + sizeof(int64_t) * 7 + sizeof(size_t) + 8;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, cpu_freq_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(cpu_freq_sample::type_identifier, type_identifier_t::cpu_freq_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, cpu_freq_sample_empty_freqs)
|
||||
{
|
||||
std::vector<uint8_t> empty_freqs;
|
||||
cpu_freq_sample original(0, 0, 0, 0, 0, 0, 0, 0, empty_freqs);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<cpu_freq_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_TRUE(deserialized.freqs.empty());
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, backtrace_region_sample_serialize_deserialize)
|
||||
{
|
||||
backtrace_region_sample original(1, 999, "Thread:999", "my_function", 90000, 95000,
|
||||
"rocm", "main\nworker\nfunc", "worker.cpp:256",
|
||||
"{\"extra\":\"data\"}");
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<backtrace_region_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.type, original.type);
|
||||
EXPECT_EQ(deserialized.thread_id, original.thread_id);
|
||||
EXPECT_EQ(deserialized.track_name, original.track_name);
|
||||
EXPECT_EQ(deserialized.name, original.name);
|
||||
EXPECT_EQ(deserialized.start_timestamp, original.start_timestamp);
|
||||
EXPECT_EQ(deserialized.end_timestamp, original.end_timestamp);
|
||||
EXPECT_EQ(deserialized.category, original.category);
|
||||
EXPECT_EQ(deserialized.call_stack, original.call_stack);
|
||||
EXPECT_EQ(deserialized.line_info, original.line_info);
|
||||
EXPECT_EQ(deserialized.extdata, original.extdata);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, backtrace_region_sample_get_size)
|
||||
{
|
||||
backtrace_region_sample sample(1, 999, "Thread:999", "my_function", 90000, 95000,
|
||||
"rocm", "main\nworker\nfunc", "worker.cpp:256",
|
||||
"{\"extra\":\"data\"}");
|
||||
|
||||
size_t expected_size = sizeof(uint32_t) + sizeof(uint64_t) * 3 + sizeof(size_t) * 6 +
|
||||
10 + 11 + 4 + 16 + 14 + 16;
|
||||
|
||||
EXPECT_EQ(get_size(sample), expected_size);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, backtrace_region_sample_type_identifier)
|
||||
{
|
||||
EXPECT_EQ(backtrace_region_sample::type_identifier,
|
||||
type_identifier_t::backtrace_region_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, backtrace_region_sample_empty_strings)
|
||||
{
|
||||
backtrace_region_sample original(0, 0, "", "", 0, 0, "", "", "", "");
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<backtrace_region_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.track_name, "");
|
||||
EXPECT_EQ(deserialized.name, "");
|
||||
EXPECT_EQ(deserialized.category, "");
|
||||
EXPECT_EQ(deserialized.call_stack, "");
|
||||
EXPECT_EQ(deserialized.line_info, "");
|
||||
EXPECT_EQ(deserialized.extdata, "");
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, type_identifier_enum_values)
|
||||
{
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::in_time_sample), 0x0000);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::pmc_event_with_sample), 0x0001);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::region), 0x0002);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::kernel_dispatch), 0x0003);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::memory_copy), 0x0004);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::memory_alloc), 0x0005);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::amd_smi_sample), 0x0006);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::cpu_freq_sample), 0x0007);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::backtrace_region_sample), 0x0008);
|
||||
EXPECT_EQ(static_cast<uint32_t>(type_identifier_t::fragmented_space), 0xFFFF);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, kernel_dispatch_sample_default_constructor)
|
||||
{
|
||||
kernel_dispatch_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::kernel_dispatch);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_copy_sample_default_constructor)
|
||||
{
|
||||
memory_copy_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::memory_copy);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, memory_allocate_sample_default_constructor)
|
||||
{
|
||||
memory_allocate_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::memory_alloc);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, region_sample_default_constructor)
|
||||
{
|
||||
region_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::region);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, in_time_sample_default_constructor)
|
||||
{
|
||||
in_time_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::in_time_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, pmc_event_with_sample_default_constructor)
|
||||
{
|
||||
pmc_event_with_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::pmc_event_with_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_default_constructor)
|
||||
{
|
||||
amd_smi_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::amd_smi_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, cpu_freq_sample_default_constructor)
|
||||
{
|
||||
cpu_freq_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::cpu_freq_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, backtrace_region_sample_default_constructor)
|
||||
{
|
||||
backtrace_region_sample sample;
|
||||
EXPECT_EQ(sample.type_identifier, type_identifier_t::backtrace_region_sample);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, kernel_dispatch_sample_large_values)
|
||||
{
|
||||
kernel_dispatch_sample original(
|
||||
UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX,
|
||||
UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX,
|
||||
UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, SIZE_MAX);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<kernel_dispatch_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.start_timestamp, UINT64_MAX);
|
||||
EXPECT_EQ(deserialized.end_timestamp, UINT64_MAX);
|
||||
EXPECT_EQ(deserialized.thread_id, UINT64_MAX);
|
||||
EXPECT_EQ(deserialized.private_segment_size, UINT32_MAX);
|
||||
EXPECT_EQ(deserialized.grid_size_z, UINT32_MAX);
|
||||
}
|
||||
|
||||
TEST_F(sample_type_test, amd_smi_sample_large_gpu_activity)
|
||||
{
|
||||
std::vector<uint8_t> large_activity(256);
|
||||
for(size_t i = 0; i < large_activity.size(); ++i)
|
||||
{
|
||||
large_activity[i] = static_cast<uint8_t>(i);
|
||||
}
|
||||
|
||||
amd_smi_sample original(0xFF, 0, 0, 0, 0, 0, 0, 0, 0, large_activity);
|
||||
|
||||
serialize(buffer.data(), original);
|
||||
|
||||
uint8_t* buffer_ptr = buffer.data();
|
||||
auto deserialized = deserialize<amd_smi_sample>(buffer_ptr);
|
||||
|
||||
EXPECT_EQ(deserialized.gpu_activity.size(), 256);
|
||||
EXPECT_EQ(deserialized.gpu_activity, large_activity);
|
||||
}
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
// 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 "core/trace_cache/storage_parser.hpp"
|
||||
#include "mocked_types.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
class sample_processor_t
|
||||
{
|
||||
public:
|
||||
sample_processor_t() = default;
|
||||
|
||||
void set_expected_samples_1(const std::vector<test_sample_1>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_1 = samples;
|
||||
}
|
||||
|
||||
void set_expected_samples_2(const std::vector<test_sample_2>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_2 = samples;
|
||||
}
|
||||
|
||||
void set_expected_samples_3(const std::vector<test_sample_3>& samples)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
m_expected_samples_3 = samples;
|
||||
}
|
||||
|
||||
void execute_sample_processing(test_type_identifier_t type_identifier,
|
||||
const rocprofsys::trace_cache::cacheable_t& value)
|
||||
{
|
||||
switch(type_identifier)
|
||||
{
|
||||
case test_type_identifier_t::sample_type_1:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_1&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
size_t idx = m_sample_1_count++;
|
||||
check_sample_1(idx, sample);
|
||||
break;
|
||||
}
|
||||
case test_type_identifier_t::sample_type_2:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_2&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
size_t idx = m_sample_2_count++;
|
||||
check_sample_2(idx, sample);
|
||||
break;
|
||||
}
|
||||
case test_type_identifier_t::sample_type_3:
|
||||
{
|
||||
const auto& sample = static_cast<const test_sample_3&>(value);
|
||||
std::lock_guard<std::mutex> lock(m_data_mutex);
|
||||
size_t idx = m_sample_3_count++;
|
||||
check_sample_3(idx, sample);
|
||||
break;
|
||||
}
|
||||
default: m_unknown_count++; break;
|
||||
}
|
||||
}
|
||||
|
||||
int get_sample_1_count() const { return m_sample_1_count.load(); }
|
||||
int get_sample_2_count() const { return m_sample_2_count.load(); }
|
||||
int get_sample_3_count() const { return m_sample_3_count.load(); }
|
||||
int get_unknown_count() const { return m_unknown_count.load(); }
|
||||
|
||||
private:
|
||||
void check_sample_1(size_t index, const test_sample_1& sample)
|
||||
{
|
||||
if(index < m_expected_samples_1.size())
|
||||
{
|
||||
EXPECT_EQ(m_expected_samples_1[index], sample);
|
||||
}
|
||||
}
|
||||
|
||||
void check_sample_2(size_t index, const test_sample_2& sample)
|
||||
{
|
||||
if(index < m_expected_samples_2.size())
|
||||
{
|
||||
EXPECT_EQ(m_expected_samples_2[index], sample);
|
||||
}
|
||||
}
|
||||
|
||||
void check_sample_3(size_t index, const test_sample_3& sample)
|
||||
{
|
||||
if(index < m_expected_samples_3.size())
|
||||
{
|
||||
EXPECT_EQ(m_expected_samples_3[index], sample);
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<int> m_sample_1_count{ 0 };
|
||||
std::atomic<int> m_sample_2_count{ 0 };
|
||||
std::atomic<int> m_sample_3_count{ 0 };
|
||||
std::atomic<int> m_unknown_count{ 0 };
|
||||
std::vector<test_sample_1> m_expected_samples_1;
|
||||
std::vector<test_sample_2> m_expected_samples_2;
|
||||
std::vector<test_sample_3> m_expected_samples_3;
|
||||
std::mutex m_data_mutex;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) sample_header
|
||||
{
|
||||
test_type_identifier_t type;
|
||||
size_t sample_size;
|
||||
};
|
||||
|
||||
class storage_parser_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
test_file_path = "test_storage_parser_" + std::to_string(test_counter++) + ".bin";
|
||||
cleanup_test_file();
|
||||
}
|
||||
|
||||
void TearDown() override { cleanup_test_file(); }
|
||||
|
||||
void cleanup_test_file() { std::remove(test_file_path.c_str()); }
|
||||
|
||||
template <typename T>
|
||||
void write_vector(std::ofstream& ofs, const std::vector<T>& vec,
|
||||
test_type_identifier_t identifier)
|
||||
{
|
||||
for(const auto& sample : vec)
|
||||
{
|
||||
sample_header header;
|
||||
header.type = identifier;
|
||||
header.sample_size = rocprofsys::trace_cache::get_size(sample);
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.reserve(header.sample_size);
|
||||
buffer.assign(header.sample_size, 0xFF);
|
||||
|
||||
rocprofsys::trace_cache::serialize(buffer.data(), sample);
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(buffer.data()), header.sample_size);
|
||||
}
|
||||
}
|
||||
|
||||
void create_test_file_with_samples(const std::vector<test_sample_1>& samples_1,
|
||||
const std::vector<test_sample_2>& samples_2,
|
||||
const std::vector<test_sample_3>& samples_3)
|
||||
{
|
||||
std::ofstream ofs(test_file_path, std::ios::binary);
|
||||
ASSERT_TRUE(ofs.is_open());
|
||||
|
||||
write_vector(ofs, samples_1, test_type_identifier_t::sample_type_1);
|
||||
write_vector(ofs, samples_2, test_type_identifier_t::sample_type_2);
|
||||
write_vector(ofs, samples_3, test_type_identifier_t::sample_type_3);
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
std::string test_file_path;
|
||||
static std::atomic<int> test_counter;
|
||||
};
|
||||
|
||||
std::atomic<int> storage_parser_test::test_counter{ 0 };
|
||||
|
||||
TEST_F(storage_parser_test, load_empty_file)
|
||||
{
|
||||
std::ofstream ofs(test_file_path, std::ios::binary);
|
||||
ofs.close();
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 0);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 0);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 0);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_single_sample_type_1)
|
||||
{
|
||||
std::vector<test_sample_1> samples_1 = { test_sample_1(42, "test_string"),
|
||||
test_sample_1(100, "another_test") };
|
||||
|
||||
create_test_file_with_samples(samples_1, {}, {});
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1(samples_1);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 2);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 0);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 0);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_multiple_sample_types)
|
||||
{
|
||||
std::vector<test_sample_1> samples_1 = { test_sample_1(123, "mixed_test") };
|
||||
std::vector<test_sample_2> samples_2 = { test_sample_2(3.14159, 555),
|
||||
test_sample_2(2.71828, 777) };
|
||||
std::vector<test_sample_3> samples_3 = { test_sample_3({ 0x01, 0x02, 0x03 }) };
|
||||
|
||||
create_test_file_with_samples(samples_1, samples_2, samples_3);
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1(samples_1);
|
||||
processor->set_expected_samples_2(samples_2);
|
||||
processor->set_expected_samples_3(samples_3);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 1);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 2);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 1);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_unsupported_sample_type)
|
||||
{
|
||||
std::vector<test_sample_1> samples_1 = { test_sample_1(123, "mixed_test") };
|
||||
std::vector<test_sample_2> samples_2 = { test_sample_2(3.14159, 555),
|
||||
test_sample_2(2.71828, 777) };
|
||||
std::vector<test_sample_3> samples_3 = { test_sample_3({ 0x01, 0x02, 0x03 }) };
|
||||
|
||||
create_test_file_with_samples(samples_1, samples_2, samples_3);
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1(samples_1);
|
||||
processor->set_expected_samples_2(samples_2);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 1);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 2);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 0);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_file_with_zero_sized_samples)
|
||||
{
|
||||
test_sample_1 valid_sample(42, "valid");
|
||||
{
|
||||
std::ofstream ofs(test_file_path, std::ios::binary);
|
||||
|
||||
sample_header zero_header;
|
||||
zero_header.type = test_type_identifier_t::sample_type_1;
|
||||
zero_header.sample_size = 0;
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(&zero_header), sizeof(zero_header));
|
||||
ofs.write(reinterpret_cast<const char*>(&zero_header), sizeof(zero_header));
|
||||
|
||||
sample_header valid_header;
|
||||
valid_header.type = test_type_identifier_t::sample_type_1;
|
||||
valid_header.sample_size = rocprofsys::trace_cache::get_size(valid_sample);
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(&valid_header), sizeof(valid_header));
|
||||
|
||||
std::vector<uint8_t> buffer(valid_header.sample_size);
|
||||
rocprofsys::trace_cache::serialize(buffer.data(), valid_sample);
|
||||
ofs.write(reinterpret_cast<const char*>(buffer.data()), valid_header.sample_size);
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1({ valid_sample });
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 1);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_nonexisting_file)
|
||||
{
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser("non_existent_file.bin");
|
||||
|
||||
EXPECT_THROW(parser.load(processor), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_large_sample_data)
|
||||
{
|
||||
std::vector<uint8_t> large_payload(10000);
|
||||
std::iota(large_payload.begin(), large_payload.end(), 0);
|
||||
|
||||
std::vector<test_sample_3> samples_3 = { test_sample_3(large_payload) };
|
||||
|
||||
create_test_file_with_samples({}, {}, samples_3);
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_3(samples_3);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 1);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, load_many_small_samples)
|
||||
{
|
||||
constexpr auto num_of_elements = 15;
|
||||
|
||||
std::vector<std::string> strings;
|
||||
strings.reserve(num_of_elements);
|
||||
std::vector<test_sample_1> many_samples;
|
||||
many_samples.reserve(num_of_elements);
|
||||
|
||||
for(int i = 0; i < num_of_elements; ++i)
|
||||
{
|
||||
auto x = "sample_" + std::to_string(i);
|
||||
strings.push_back(x);
|
||||
many_samples.push_back({ 0, strings[i] });
|
||||
}
|
||||
|
||||
create_test_file_with_samples(many_samples, {}, {});
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1(many_samples);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), num_of_elements);
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, write_less_than_expected)
|
||||
{
|
||||
std::ofstream ofs(test_file_path, std::ios::binary);
|
||||
|
||||
sample_header header;
|
||||
header.type = test_type_identifier_t::sample_type_1;
|
||||
header.sample_size = 100;
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
std::vector<uint8_t> partial_data(50, 0xAA);
|
||||
ofs.write(reinterpret_cast<const char*>(partial_data.data()), partial_data.size());
|
||||
|
||||
ofs.close();
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_THROW(parser.load(processor), std::runtime_error);
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 0);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 0);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 0);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
|
||||
TEST_F(storage_parser_test, read_fragmented_space)
|
||||
{
|
||||
std::vector<test_sample_1> samples_1 = { test_sample_1(123,
|
||||
"fragmented-space test") };
|
||||
std::vector<test_sample_2> samples_2 = { test_sample_2(3.14159, 555),
|
||||
test_sample_2(2.71828, 777) };
|
||||
std::vector<test_sample_3> samples_3 = { test_sample_3({ 0x01, 0x02, 0x03 }) };
|
||||
{
|
||||
std::ofstream ofs(test_file_path, std::ios::binary);
|
||||
|
||||
write_vector(ofs, samples_1, test_type_identifier_t::sample_type_1);
|
||||
|
||||
sample_header header;
|
||||
header.sample_size = 100;
|
||||
header.type = test_type_identifier_t::fragmented_space;
|
||||
std::vector<uint8_t> fragmented_space;
|
||||
fragmented_space.reserve(header.sample_size);
|
||||
fragmented_space.assign(header.sample_size, 0);
|
||||
|
||||
ofs.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
ofs.write(reinterpret_cast<const char*>(fragmented_space.data()),
|
||||
header.sample_size);
|
||||
|
||||
write_vector(ofs, samples_2, test_type_identifier_t::sample_type_2);
|
||||
write_vector(ofs, samples_3, test_type_identifier_t::sample_type_3);
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
auto processor = std::make_shared<sample_processor_t>();
|
||||
processor->set_expected_samples_1(samples_1);
|
||||
processor->set_expected_samples_2(samples_2);
|
||||
processor->set_expected_samples_3(samples_3);
|
||||
|
||||
rocprofsys::trace_cache::storage_parser<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2, test_sample_3>
|
||||
parser(test_file_path);
|
||||
|
||||
EXPECT_NO_THROW(parser.load(processor));
|
||||
|
||||
EXPECT_EQ(processor->get_sample_1_count(), 1);
|
||||
EXPECT_EQ(processor->get_sample_2_count(), 2);
|
||||
EXPECT_EQ(processor->get_sample_3_count(), 1);
|
||||
|
||||
EXPECT_EQ(std::remove(test_file_path.c_str()), 0);
|
||||
}
|
||||
+126
@@ -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.
|
||||
|
||||
#include "core/trace_cache/type_registry.hpp"
|
||||
#include "mocked_types.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class type_registry_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
rocprofsys::trace_cache::type_registry<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2>
|
||||
type_registry;
|
||||
};
|
||||
|
||||
TEST_F(type_registry_test, test_get_type_sample_1)
|
||||
{
|
||||
test_sample_1 test_value{ 42, "hello" };
|
||||
size_t buffer_size = rocprofsys::trace_cache::get_size(test_value);
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
rocprofsys::trace_cache::serialize(buffer.data(), test_value);
|
||||
|
||||
auto* buffer_data = buffer.data();
|
||||
auto result =
|
||||
type_registry.get_type(test_type_identifier_t::sample_type_1, buffer_data);
|
||||
|
||||
ASSERT_TRUE(result.has_value());
|
||||
ASSERT_TRUE(std::holds_alternative<test_sample_1>(result.value()));
|
||||
|
||||
auto sample_1 = std::get<test_sample_1>(result.value());
|
||||
EXPECT_EQ(sample_1.value, 42);
|
||||
EXPECT_EQ(sample_1.text, "hello");
|
||||
}
|
||||
|
||||
TEST_F(type_registry_test, test_get_type_sample_2)
|
||||
{
|
||||
test_sample_2 test_value{ 3.14, 123 };
|
||||
size_t buffer_size = rocprofsys::trace_cache::get_size(test_value);
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
rocprofsys::trace_cache::serialize(buffer.data(), test_value);
|
||||
|
||||
auto* buffer_data = buffer.data();
|
||||
auto result =
|
||||
type_registry.get_type(test_type_identifier_t::sample_type_2, buffer_data);
|
||||
|
||||
ASSERT_TRUE(result.has_value());
|
||||
ASSERT_TRUE(std::holds_alternative<test_sample_2>(result.value()));
|
||||
|
||||
auto sample_2 = std::get<test_sample_2>(result.value());
|
||||
EXPECT_DOUBLE_EQ(sample_2.data, 3.14);
|
||||
EXPECT_EQ(sample_2.sample_id, 123);
|
||||
}
|
||||
|
||||
TEST_F(type_registry_test, test_get_type_unknown_id)
|
||||
{
|
||||
uint8_t dummy_data = 0;
|
||||
uint8_t* data = &dummy_data;
|
||||
|
||||
auto result = type_registry.get_type(test_type_identifier_t::fragmented_space, data);
|
||||
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(type_registry_test, test_variant_type_definition)
|
||||
{
|
||||
using expected_variant = std::variant<test_sample_1, test_sample_2>;
|
||||
using actual_variant =
|
||||
rocprofsys::trace_cache::type_registry<test_type_identifier_t, test_sample_1,
|
||||
test_sample_2>::variant_t;
|
||||
|
||||
EXPECT_TRUE((std::is_same_v<expected_variant, actual_variant>) );
|
||||
}
|
||||
|
||||
TEST_F(type_registry_test, test_multiple_calls_same_type)
|
||||
{
|
||||
test_sample_1 test_value1{ 100, "first" };
|
||||
test_sample_1 test_value2{ 200, "second" };
|
||||
|
||||
size_t buffer_size1 = rocprofsys::trace_cache::get_size(test_value1);
|
||||
size_t buffer_size2 = rocprofsys::trace_cache::get_size(test_value2);
|
||||
|
||||
std::vector<uint8_t> buffer1(buffer_size1);
|
||||
std::vector<uint8_t> buffer2(buffer_size2);
|
||||
|
||||
rocprofsys::trace_cache::serialize(buffer1.data(), test_value1);
|
||||
rocprofsys::trace_cache::serialize(buffer2.data(), test_value2);
|
||||
|
||||
auto* buffer1_data = buffer1.data();
|
||||
auto* buffer2_data = buffer2.data();
|
||||
|
||||
auto result1 =
|
||||
type_registry.get_type(test_type_identifier_t::sample_type_1, buffer1_data);
|
||||
auto result2 =
|
||||
type_registry.get_type(test_type_identifier_t::sample_type_1, buffer2_data);
|
||||
|
||||
ASSERT_TRUE(result1.has_value());
|
||||
ASSERT_TRUE(result2.has_value());
|
||||
|
||||
auto sample_1_1 = std::get<test_sample_1>(result1.value());
|
||||
auto sample_1_2 = std::get<test_sample_1>(result2.value());
|
||||
|
||||
EXPECT_EQ(sample_1_1.value, 100);
|
||||
EXPECT_EQ(sample_1_1.text, "first");
|
||||
EXPECT_EQ(sample_1_2.value, 200);
|
||||
EXPECT_EQ(sample_1_2.text, "second");
|
||||
}
|
||||
@@ -578,7 +578,11 @@ rocprofsys_init_tooling_hidden(void)
|
||||
ROCPROFSYS_DEBUG_F("State: %s -> State::Active\n",
|
||||
std::to_string(get_state()).c_str());
|
||||
|
||||
trace_cache::get_buffer_storage().start(getpid());
|
||||
{
|
||||
ROCPROFSYS_SCOPED_SAMPLING_ON_CHILD_THREADS(false);
|
||||
trace_cache::get_buffer_storage().start(getpid());
|
||||
}
|
||||
|
||||
set_state(State::Active); // set to active as very last operation
|
||||
} };
|
||||
|
||||
|
||||
@@ -20,12 +20,9 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
add_executable(rocprof-sys-unit-tests dummy.cpp)
|
||||
add_executable(rocprof-sys-unit-tests dummy.cpp $<TARGET_OBJECTS:trace-cache-tests>)
|
||||
|
||||
target_link_libraries(
|
||||
rocprof-sys-unit-tests
|
||||
PRIVATE rocprofiler-systems-googletest-library
|
||||
PRIVATE rocprofiler-systems-googletest-library rocprofiler-systems-core-library
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(rocprof-sys-unit-tests)
|
||||
|
||||
Reference in New Issue
Block a user