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

324 lines
14 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 <benchmark/benchmark.h>
#include "utility.hpp"
#include <chrono>
#include <cstdio>
#include <memory>
#include <string>
#include <thread>
#include <vector>
namespace
{
using namespace profiler_hub::writer_types;
// ============================================================================
// Benchmark Configuration
// ============================================================================
// Configurable event counts for parallel scaling tests
constexpr size_t COUNT_10K = 10000;
constexpr size_t COUNT_100K = 100000;
constexpr size_t COUNT_1000K = 1000000;
// ============================================================================
// Per-Thread Context
// Each thread gets its own isolated database to avoid contention
// ============================================================================
struct thread_context
{
std::string database_path;
std::unique_ptr<profiler_hub::storage_t> storage;
std::shared_ptr<profiler_hub::writer_t> writer;
size_t context_id = 0;
trace_environment_t trace_env;
agent_unique_id_t gpu_agent_id;
void setup(size_t thread_id)
{
context_id = thread_id;
database_path = "benchmark_writer_parallel_" + std::to_string(thread_id) + ".db";
const std::string uuid = std::to_string(thread_id);
storage = std::make_unique<profiler_hub::storage_t>(database_path, uuid);
writer = std::make_shared<profiler_hub::writer_t>(std::move(storage));
constexpr size_t node_id = 1;
const size_t pid = 1000 + thread_id;
const size_t tid = 2000 + thread_id;
// Register infrastructure
writer->register_node_info(node_info_t{ .node_id = node_id,
.hash = 0xDEADBEEF + thread_id,
.machine_id = "bench-machine",
.system_name = "Linux",
.hostname = "benchmark-host",
.release = "6.0.0",
.version = "v1",
.hardware_name = "x86_64",
.domain_name = "local" });
writer->register_process_info(process_info_t{ .ppid = 0,
.pid = pid,
.init = 0,
.fini = 0,
.start = 0,
.end = 0,
.command = "/bin/benchmark",
.environment = "{}",
.extdata = "{}",
.node_id = node_id });
writer->register_thread_info(thread_info_t{ .parent_process_id = pid,
.thread_id = tid,
.name = "worker",
.start = 0,
.end = 0,
.extdata = "{}",
.node_id = node_id,
.process_id = pid });
gpu_agent_id = agent_unique_id_t{ .agent_type = "GPU", .type_index = 0 };
writer->register_agent_info(agent_info_t{ .unique_id = gpu_agent_id,
.absolute_index = 0,
.logical_index = 0,
.uuid = 0xABCD,
.name = "gfx90a",
.model_name = "MI200",
.vendor_name = "AMD",
.product_name = "MI210",
.user_name = "",
.extdata = "{}",
.node_id = node_id,
.process_id = pid });
writer->register_queue_info(queue_info_t{ .queue_id = 1,
.name = "hsa_queue_0",
.extdata = "{}",
.node_id = node_id,
.process_id = pid });
writer->register_stream_info(stream_info_t{ .stream_id = 1,
.name = "hip_stream_0",
.extdata = "{}",
.node_id = node_id,
.process_id = pid });
writer->register_code_object_info(
code_object_info_t{ .id = 1,
.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 = gpu_agent_id });
writer->register_kernel_symbol_info(
kernel_symbol_info_t{ .id = 1,
.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 = 1 });
writer->register_track_info(track_info_t{ .name = "gpu_kernel",
.extdata = "{}",
.node_id = node_id,
.process_id = pid,
.thread_id = tid });
// Store trace environment for data insertion
trace_env = trace_environment_t{ .node_id = node_id,
.process_id = pid,
.thread_id = tid,
.agent_id = gpu_agent_id,
.stream_id = 1,
.queue_id = 1,
.track_name = "gpu_kernel" };
}
void teardown()
{
writer.reset();
storage.reset();
std::remove(database_path.c_str());
}
[[nodiscard]] size_t get_db_size() const
{
return utility::get_file_size(database_path);
}
};
// ============================================================================
// Realistic Workload Generator
// Simulates typical profiling workload with regions and kernel dispatches
// ============================================================================
void
run_realistic_workload(thread_context& ctx, size_t total_events)
{
// Distribution: 99.67% regions, 0.33% kernel dispatches
const size_t region_count = total_events * 9967 / 10000;
const size_t kernel_count = total_events * 33 / 10000;
// Insert regions (majority of workload) - no args for simplicity
for(size_t i = 0; i < region_count; ++i)
{
const region_data_t data{ .event = std::nullopt,
.start_timestamp = i * 1000,
.end_timestamp = i * 1000 + 500,
.name = "user_region",
.extdata = "{}",
.args = {} };
ctx.writer->insert_region_data(data, ctx.trace_env);
}
// Insert 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 = "{}" };
ctx.writer->insert_kernel_dispatch_data(data, ctx.trace_env);
}
ctx.writer->flush_in_memory_data_to_disk();
}
// ============================================================================
// Parallel Writer Benchmark Fixture
// ============================================================================
class parallel_writer_fixture : public benchmark::Fixture
{
public:
void SetUp(const benchmark::State&) override {}
void TearDown(const benchmark::State&) override {}
};
// ============================================================================
// Scaling Benchmark
// Measures parallel scalability with isolated databases per thread
// All times should be similar regardless of thread count (no contention)
// ============================================================================
BENCHMARK_DEFINE_F(parallel_writer_fixture, scaling_test)(benchmark::State& state)
{
const auto num_threads = static_cast<size_t>(state.range(0));
const auto total_events = static_cast<size_t>(state.range(1));
for(auto _ : state)
{
std::vector<thread_context> contexts(num_threads);
std::vector<std::thread> threads;
// Setup phase (not measured - done sequentially)
for(size_t i = 0; i < num_threads; ++i)
{
contexts[i].setup(i);
}
// Measure parallel workload execution
auto start_time = std::chrono::high_resolution_clock::now();
for(size_t i = 0; i < num_threads; ++i)
{
threads.emplace_back([&contexts, i, total_events]() {
run_realistic_workload(contexts[i], total_events);
});
}
for(auto& t : threads)
{
t.join();
}
auto end_time = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time)
.count();
// Collect metrics
size_t total_db_size = 0;
for(size_t i = 0; i < num_threads; ++i)
{
total_db_size += contexts[i].get_db_size();
}
// Cleanup
for(size_t i = 0; i < num_threads; ++i)
{
contexts[i].teardown();
}
state.SetIterationTime(static_cast<double>(duration) / 1000.0);
state.counters["total_db_size_mb"] =
static_cast<double>(total_db_size) / (1024.0 * 1024.0);
state.counters["total_events"] = static_cast<double>(total_events);
state.counters["events_per_sec"] =
static_cast<double>(total_events) / (static_cast<double>(duration) / 1000.0);
}
state.SetItemsProcessed(state.iterations() * total_events);
}
BENCHMARK_REGISTER_F(parallel_writer_fixture, scaling_test)
->Unit(benchmark::kSecond)
->UseManualTime()
->Iterations(1)
// in_memory: 10k events - quick validation
->Args({ 1, COUNT_10K })
->Args({ 2, COUNT_10K })
->Args({ 4, COUNT_10K })
->Args({ 8, COUNT_10K })
// in_memory: 100k events - standard benchmark
->Args({ 1, COUNT_100K })
->Args({ 2, COUNT_100K })
->Args({ 4, COUNT_100K })
->Args({ 8, COUNT_100K })
// in_memory: 1000k events - stress test
->Args({ 1, COUNT_1000K })
->Args({ 2, COUNT_1000K })
->Args({ 4, COUNT_1000K })
->Args({ 8, COUNT_1000K });
} // namespace