Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

835 lines
33 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc.
// SPDX-License-Identifier: MIT
#include "profiler-hub/storage.hpp"
#include "profiler-hub/writer.hpp"
#include "profiler-hub/writer_types.hpp"
#include <profiler-hub/version.hpp>
#include <benchmark/benchmark.h>
#include "utility.hpp"
#include <cstdio>
#include <memory>
#include <string>
namespace
{
using namespace profiler_hub::writer_types;
// ============================================================================
// Benchmark Configuration
// ============================================================================
// Standard data insert counts for benchmarking
// Use ->Arg() to select: 10k (quick), 100k (standard), 1000k (stress)
constexpr size_t COUNT_10K = 10000;
constexpr size_t COUNT_100K = 100000;
constexpr size_t COUNT_1000K = 1000000;
// ============================================================================
// Test Data Generators
// ============================================================================
node_info_t
make_node_info(size_t node_id) noexcept
{
return node_info_t{ .node_id = node_id,
.hash = 0xDEADBEEF + node_id,
.machine_id = "bench-machine",
.system_name = "Linux",
.hostname = "benchmark-host",
.release = "6.0.0",
.version = "v1",
.hardware_name = "x86_64",
.domain_name = "local" };
}
process_info_t
make_process_info(size_t node_id, size_t pid) noexcept
{
return process_info_t{ .ppid = 0,
.pid = pid,
.init = 0,
.fini = 0,
.start = 0,
.end = 0,
.command = "/bin/benchmark",
.environment = "{}",
.extdata = "{}",
.node_id = node_id };
}
thread_info_t
make_thread_info(size_t node_id, size_t pid, size_t tid) noexcept
{
return thread_info_t{ .parent_process_id = pid,
.thread_id = tid,
.name = "main",
.start = 0,
.end = 0,
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
agent_info_t
make_gpu_agent(size_t node_id, size_t pid, size_t type_index = 0) noexcept
{
return agent_info_t{ .unique_id = { .agent_type = "GPU", .type_index = type_index },
.absolute_index = type_index,
.logical_index = type_index,
.uuid = 0xABCD + type_index,
.name = "gfx90a",
.model_name = "MI200",
.vendor_name = "AMD",
.product_name = "MI210",
.user_name = "",
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
agent_info_t
make_cpu_agent(size_t node_id, size_t pid, size_t type_index = 0) noexcept
{
return agent_info_t{ .unique_id = { .agent_type = "CPU", .type_index = type_index },
.absolute_index = type_index,
.logical_index = type_index,
.uuid = 0,
.name = "cpu0",
.model_name = "EPYC",
.vendor_name = "AMD",
.product_name = "EPYC7763",
.user_name = "",
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
queue_info_t
make_queue_info(size_t node_id, size_t pid, size_t queue_id) noexcept
{
return queue_info_t{ .queue_id = queue_id,
.name = "hsa_queue_0",
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
stream_info_t
make_stream_info(size_t node_id, size_t pid, size_t stream_id) noexcept
{
return stream_info_t{ .stream_id = stream_id,
.name = "hip_stream_0",
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
code_object_info_t
make_code_object(size_t id,
size_t node_id,
size_t pid,
agent_unique_id_t agent_id) noexcept
{
return code_object_info_t{ .id = id,
.uri = "file:///kernels.hsaco",
.load_base = 0x10000,
.load_size = 0x1000,
.load_delta = 0,
.storage_type = "FILE",
.extdata = "{}",
.node_id = node_id,
.process_id = pid,
.agent_id = agent_id };
}
kernel_symbol_info_t
make_kernel_symbol(size_t id, size_t node_id, size_t pid, size_t code_obj_id) noexcept
{
return kernel_symbol_info_t{ .id = id,
.name = "vectorAdd",
.display_name = "vectorAdd(float*,float*,float*,int)",
.kernel_object = 0x1234,
.kernarg_segment_size = 256,
.kernarg_segment_alignment = 8,
.group_segment_size = 65536,
.private_segment_size = 0,
.sgpr_count = 32,
.arch_vgpr_count = 64,
.accum_vgpr_count = 0,
.extdata = "{}",
.node_id = node_id,
.process_id = pid,
.code_obj_id = code_obj_id };
}
pmc_info_t
make_pmc_info(size_t node_id,
size_t pid,
const char* name,
std::optional<agent_unique_id_t> agent_id = std::nullopt) noexcept
{
return pmc_info_t{ .unique_id = { .name = name, .agent_id = agent_id },
.target_arch = "GPU",
.event_code = 0x100,
.instance_id = 0,
.symbol = name,
.description = name,
.long_description = name,
.component = "SQ",
.units = "value",
.value_type = "ABS",
.block = "SQ",
.expression = "",
.is_constant = 0,
.is_derived = 0,
.extdata = "{}",
.node_id = node_id,
.process_id = pid };
}
track_info_t
make_track_info(const char* name,
size_t node_id,
std::optional<size_t> pid = std::nullopt,
std::optional<size_t> tid = std::nullopt) noexcept
{
return track_info_t{ .name = name,
.extdata = "{}",
.node_id = node_id,
.process_id = pid,
.thread_id = tid };
}
// ============================================================================
// Benchmark Fixture
// ============================================================================
class writer_fixture : public benchmark::Fixture
{
public:
void SetUp(const benchmark::State& state) override
{
m_database_path =
"benchmark_writer_" + std::to_string(state.thread_index()) + ".db";
m_uuid = std::to_string(state.thread_index());
m_storage = std::make_unique<profiler_hub::storage_t>(m_database_path, m_uuid);
m_writer = std::make_shared<profiler_hub::writer_t>(std::move(m_storage));
setup_schema();
}
void TearDown(const benchmark::State&) override
{
m_writer.reset();
m_storage.reset();
std::remove(m_database_path.c_str());
}
[[nodiscard]] std::string get_db_size_label() const
{
const size_t size = utility::get_file_size(m_database_path);
return " DB: " + utility::format_file_size(size);
}
protected:
void setup_schema()
{
constexpr size_t node_id = 1;
constexpr size_t pid = 1000;
constexpr size_t tid = 1001;
// Register infrastructure (not measured - this is setup cost)
m_writer->register_node_info(make_node_info(node_id));
m_writer->register_process_info(make_process_info(node_id, pid));
m_writer->register_thread_info(make_thread_info(node_id, pid, tid));
m_writer->register_agent_info(make_gpu_agent(node_id, pid, 0));
m_writer->register_agent_info(make_cpu_agent(node_id, pid, 0));
m_writer->register_queue_info(make_queue_info(node_id, pid, 1));
m_writer->register_stream_info(make_stream_info(node_id, pid, 1));
const agent_unique_id_t gpu_agent{ "GPU", 0 };
m_writer->register_code_object_info(make_code_object(1, node_id, pid, gpu_agent));
m_writer->register_kernel_symbol_info(make_kernel_symbol(1, node_id, pid, 1));
// Register PMC descriptions
m_writer->register_pmc_info(make_pmc_info(node_id, pid, "SQ_WAVES", gpu_agent));
m_writer->register_pmc_info(make_pmc_info(node_id, pid, "SQ_INSTS", gpu_agent));
m_writer->register_pmc_info(make_pmc_info(node_id, pid, "TA_BUSY", gpu_agent));
// Register tracks
m_writer->register_track_info(make_track_info("gpu_kernel", node_id, pid, tid));
m_writer->register_track_info(make_track_info("gpu_memcpy", node_id, pid, tid));
m_writer->register_track_info(make_track_info("cpu_sample", node_id, pid, tid));
m_writer->register_track_info(
make_track_info("amd_smi", node_id, std::nullopt, std::nullopt));
// Store commonly used values
m_trace_env = trace_environment_t{ .node_id = node_id,
.process_id = pid,
.thread_id = tid,
.agent_id = gpu_agent,
.stream_id = 1,
.queue_id = 1,
.track_name = "gpu_kernel" };
m_gpu_agent_id = gpu_agent;
}
std::string m_database_path;
std::string m_uuid;
std::unique_ptr<profiler_hub::storage_t> m_storage;
std::shared_ptr<profiler_hub::writer_t> m_writer;
trace_environment_t m_trace_env;
agent_unique_id_t m_gpu_agent_id;
};
// ============================================================================
// Registration Benchmarks (Setup Cost)
// These benchmarks measure the cost of registering metadata
// ============================================================================
class registration_fixture : public benchmark::Fixture
{
public:
void SetUp(const benchmark::State& state) override
{
m_database_path =
"benchmark_registration_" + std::to_string(state.thread_index()) + ".db";
m_uuid = std::to_string(state.thread_index());
m_storage = std::make_unique<profiler_hub::storage_t>(m_database_path, m_uuid);
m_writer = std::make_shared<profiler_hub::writer_t>(std::move(m_storage));
}
void TearDown(const benchmark::State&) override
{
m_writer.reset();
m_storage.reset();
std::remove(m_database_path.c_str());
}
[[nodiscard]] std::string get_db_size_label() const
{
const size_t size = utility::get_file_size(m_database_path);
return " DB: " + utility::format_file_size(size);
}
protected:
std::string m_database_path;
std::string m_uuid;
std::unique_ptr<profiler_hub::storage_t> m_storage;
std::shared_ptr<profiler_hub::writer_t> m_writer;
};
// Benchmark: Register multiple threads
BENCHMARK_DEFINE_F(registration_fixture, register_threads)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
constexpr size_t node_id = 1;
constexpr size_t pid = 1000;
// Register required dependencies first
m_writer->register_node_info(make_node_info(node_id));
m_writer->register_process_info(make_process_info(node_id, pid));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
m_writer->register_thread_info(make_thread_info(node_id, pid, 2000 + i));
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
}
BENCHMARK_REGISTER_F(registration_fixture, register_threads)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K });
// Benchmark: Register multiple kernel symbols
BENCHMARK_DEFINE_F(registration_fixture, register_kernel_symbols)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
constexpr size_t node_id = 1;
constexpr size_t pid = 1000;
// Register required dependencies
m_writer->register_node_info(make_node_info(node_id));
m_writer->register_process_info(make_process_info(node_id, pid));
const agent_unique_id_t gpu_agent{ "GPU", 0 };
m_writer->register_agent_info(make_gpu_agent(node_id, pid, 0));
m_writer->register_code_object_info(make_code_object(1, node_id, pid, gpu_agent));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
m_writer->register_kernel_symbol_info(
make_kernel_symbol(i + 1, node_id, pid, 1));
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
}
BENCHMARK_REGISTER_F(registration_fixture, register_kernel_symbols)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K });
// Benchmark: Register PMC descriptions
BENCHMARK_DEFINE_F(registration_fixture, register_pmc_info)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
constexpr size_t node_id = 1;
constexpr size_t pid = 1000;
// Register required dependencies
m_writer->register_node_info(make_node_info(node_id));
m_writer->register_process_info(make_process_info(node_id, pid));
const agent_unique_id_t gpu_agent{ "GPU", 0 };
m_writer->register_agent_info(make_gpu_agent(node_id, pid, 0));
// Generate unique PMC names
std::vector<std::string> pmc_names;
pmc_names.reserve(count);
for(size_t i = 0; i < count; ++i)
{
pmc_names.push_back("PMC_COUNTER_" + std::to_string(i));
}
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
m_writer->register_pmc_info(
make_pmc_info(node_id, pid, pmc_names[i].c_str(), gpu_agent));
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
}
BENCHMARK_REGISTER_F(registration_fixture, register_pmc_info)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K });
// Benchmark: Full schema registration (realistic setup)
BENCHMARK_DEFINE_F(registration_fixture, register_full_schema)(benchmark::State& state)
{
const auto thread_count = static_cast<size_t>(state.range(0));
const auto kernel_count = static_cast<size_t>(state.range(1));
for(auto _ : state)
{
constexpr size_t node_id = 1;
constexpr size_t pid = 1000;
// Infrastructure
m_writer->register_node_info(make_node_info(node_id));
m_writer->register_process_info(make_process_info(node_id, pid));
// Threads
for(size_t i = 0; i < thread_count; ++i)
{
m_writer->register_thread_info(make_thread_info(node_id, pid, 2000 + i));
}
// GPU agent
const agent_unique_id_t gpu_agent{ "GPU", 0 };
m_writer->register_agent_info(make_gpu_agent(node_id, pid, 0));
m_writer->register_queue_info(make_queue_info(node_id, pid, 1));
m_writer->register_stream_info(make_stream_info(node_id, pid, 1));
// Code objects and kernels
m_writer->register_code_object_info(make_code_object(1, node_id, pid, gpu_agent));
for(size_t i = 0; i < kernel_count; ++i)
{
m_writer->register_kernel_symbol_info(
make_kernel_symbol(i + 1, node_id, pid, 1));
}
// Tracks
for(size_t i = 0; i < thread_count; ++i)
{
m_writer->register_track_info(
make_track_info("track", node_id, pid, 2000 + i));
}
m_writer->flush_in_memory_data_to_disk();
}
const size_t total_registrations =
1 + 1 + thread_count + 1 + 1 + 1 + 1 + kernel_count + thread_count;
state.SetItemsProcessed(state.iterations() * total_registrations);
state.counters["threads"] = static_cast<double>(thread_count);
state.counters["kernels"] = static_cast<double>(kernel_count);
}
BENCHMARK_REGISTER_F(registration_fixture, register_full_schema)
->Unit(benchmark::kSecond)
->Iterations(1)
// Small setup (12 threads, 100 kernels)
->Args({ 12, 100 })
// Medium setup (64 threads, 1000 kernels)
->Args({ 64, 1000 })
// Large setup (256 threads, 10000 kernels)
->Args({ 256, 10000 });
// ============================================================================
// Data Insertion Benchmarks (Hot Path - Primary Focus)
// ============================================================================
BENCHMARK_DEFINE_F(writer_fixture, kernel_dispatch)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
const kernel_dispatch_data_t data{ .event = std::nullopt,
.dispatch_id = i,
.start_timestamp = i * 1000,
.end_timestamp = i * 1000 + 500,
.kernel_symbol_id = 1,
.code_object_id = 1,
.private_segment_size = 0,
.group_segment_size = 65536,
.workgroup_size_x = 256,
.workgroup_size_y = 1,
.workgroup_size_z = 1,
.grid_size_x = 1024,
.grid_size_y = 1,
.grid_size_z = 1,
.name = "vectorAdd",
.extdata = "{}" };
m_writer->insert_kernel_dispatch_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, kernel_dispatch)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
BENCHMARK_DEFINE_F(writer_fixture, memory_copy)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
const memory_copy_data_t data{ .event = std::nullopt,
.start_timestamp = i * 1000,
.end_timestamp = i * 1000 + 200,
.dst_agent_id = m_gpu_agent_id,
.dst_address = 0x7FFF00000000 + i * 4096,
.src_agent_id = std::nullopt,
.src_address = 0x100000 + i * 4096,
.size = 4096,
.name = "hipMemcpy",
.region_name = std::nullopt,
.extdata = "{}" };
m_writer->insert_memory_copy_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, memory_copy)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
BENCHMARK_DEFINE_F(writer_fixture, memory_alloc)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
const memory_alloc_data_t data{ .event = std::nullopt,
.type = "ALLOC",
.level = "REAL",
.start_timestamp = i * 1000,
.end_timestamp = i * 1000 + 100,
.address = 0x7FFF00000000 + i * 4096,
.size = 4096,
.extdata = "{}" };
m_writer->insert_memory_alloc_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, memory_alloc)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
BENCHMARK_DEFINE_F(writer_fixture, region)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
const region_data_t data{ .event = std::nullopt,
.start_timestamp = i * 500,
.end_timestamp = i * 500 + 100,
.name = "user_region",
.extdata = "{}",
.args = {} };
m_writer->insert_region_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, region)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
BENCHMARK_DEFINE_F(writer_fixture, region_with_args)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
// Pre-create argument data
const std::vector<arg_data_t> args = {
{ .position = 0, .type = "int", .name = "level", .value = "0", .extdata = "{}" },
{ .position = 1,
.type = "char*",
.name = "name",
.value = "region",
.extdata = "{}" },
{ .position = 2,
.type = "size_t",
.name = "id",
.value = "12345",
.extdata = "{}" },
{ .position = 3,
.type = "void*",
.name = "ptr",
.value = "0x7fff000",
.extdata = "{}" },
{ .position = 4,
.type = "double",
.name = "value",
.value = "3.14159",
.extdata = "{}" }
};
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
// Variable number of arguments (0-5) based on iteration
const size_t num_args = i % 6;
std::vector<arg_data_t> iter_args(args.begin(), args.begin() + num_args);
// Create event data when args are present (required for correlation)
std::optional<event_data_t> event_opt = std::nullopt;
if(!iter_args.empty())
{
event_opt = event_data_t{ .stack_id = i,
.parent_stack_id = 0,
.correlation_id = i,
.call_stack = {},
.line_info_list = {},
.event_category = "HIP_API",
.extdata = "{}" };
}
const region_data_t data{ .event = std::move(event_opt),
.start_timestamp = i * 500,
.end_timestamp = i * 500 + 100,
.name = "api_call",
.extdata = "{}",
.args = std::move(iter_args) };
m_writer->insert_region_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, region_with_args)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
BENCHMARK_DEFINE_F(writer_fixture, pmc_event)(benchmark::State& state)
{
const auto count = static_cast<size_t>(state.range(0));
const pmc_info_unique_id_t pmc_id{ .name = "SQ_WAVES", .agent_id = m_gpu_agent_id };
const track_info_t track = make_track_info("gpu_kernel", 1, 1000, 1001);
for(auto _ : state)
{
for(size_t i = 0; i < count; ++i)
{
const pmc_event_data_t data{
.event = std::nullopt,
.value = static_cast<double>(i * 100),
.extdata = "{}",
.sample = { .timestamp = i * 1000, .track = track, .extdata = "{}" }
};
m_writer->insert_pmc_event_data(data, pmc_id);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * count);
state.SetLabel(get_db_size_label());
}
BENCHMARK_REGISTER_F(writer_fixture, pmc_event)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
// ============================================================================
// End-to-End Benchmark (Realistic Mixed Workload)
// ============================================================================
BENCHMARK_DEFINE_F(writer_fixture, end_to_end_mixed)(benchmark::State& state)
{
const auto total_events = static_cast<size_t>(state.range(0));
// Realistic distribution: 70% regions, 20% kernel dispatches, 10% memory ops
const size_t region_count = total_events * 70 / 100;
const size_t kernel_count = total_events * 20 / 100;
const size_t memcopy_count = total_events * 5 / 100;
const size_t memalloc_count = total_events * 5 / 100;
for(auto _ : state)
{
// Regions (most common)
for(size_t i = 0; i < region_count; ++i)
{
const region_data_t data{ .event = std::nullopt,
.start_timestamp = i * 500,
.end_timestamp = i * 500 + 100,
.name = "hip_api",
.extdata = "{}",
.args = {} };
m_writer->insert_region_data(data, m_trace_env);
}
// Kernel dispatches
for(size_t i = 0; i < kernel_count; ++i)
{
const kernel_dispatch_data_t data{ .event = std::nullopt,
.dispatch_id = i,
.start_timestamp = i * 10000,
.end_timestamp = i * 10000 + 5000,
.kernel_symbol_id = 1,
.code_object_id = 1,
.private_segment_size = 0,
.group_segment_size = 65536,
.workgroup_size_x = 256,
.workgroup_size_y = 1,
.workgroup_size_z = 1,
.grid_size_x = 1024,
.grid_size_y = 1,
.grid_size_z = 1,
.name = "vectorAdd",
.extdata = "{}" };
m_writer->insert_kernel_dispatch_data(data, m_trace_env);
}
// Memory copies
for(size_t i = 0; i < memcopy_count; ++i)
{
const memory_copy_data_t data{ .event = std::nullopt,
.start_timestamp = i * 2000,
.end_timestamp = i * 2000 + 500,
.dst_agent_id = m_gpu_agent_id,
.dst_address = 0x7FFF00000000 + i * 4096,
.src_agent_id = std::nullopt,
.src_address = 0x100000 + i * 4096,
.size = 4096,
.name = "hipMemcpy",
.region_name = std::nullopt,
.extdata = "{}" };
m_writer->insert_memory_copy_data(data, m_trace_env);
}
// Memory allocations
for(size_t i = 0; i < memalloc_count; ++i)
{
const memory_alloc_data_t data{ .event = std::nullopt,
.type = "ALLOC",
.level = "REAL",
.start_timestamp = i * 1000,
.end_timestamp = i * 1000 + 100,
.address = 0x7FFF00000000 + i * 4096,
.size = 4096,
.extdata = "{}" };
m_writer->insert_memory_alloc_data(data, m_trace_env);
}
m_writer->flush_in_memory_data_to_disk();
}
state.SetItemsProcessed(state.iterations() * total_events);
state.SetLabel(get_db_size_label());
state.counters["regions"] = static_cast<double>(region_count);
state.counters["kernels"] = static_cast<double>(kernel_count);
state.counters["memcopies"] = static_cast<double>(memcopy_count);
state.counters["memallocs"] = static_cast<double>(memalloc_count);
}
BENCHMARK_REGISTER_F(writer_fixture, end_to_end_mixed)
->Unit(benchmark::kSecond)
->Iterations(1)
->Args({ COUNT_10K })
->Args({ COUNT_100K })
->Args({ COUNT_1000K });
} // namespace