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
165 lines
6.0 KiB
C++
165 lines
6.0 KiB
C++
// Copyright (c) Advanced Micro Devices, Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <condition_variable>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <string_view>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#include <hip/hip_runtime.h>
|
|
#include <rocprofiler-sdk-roctx/roctx.h>
|
|
|
|
// Open a named region using either roctxRangeStartA (start_stop) or
|
|
// roctxRangePushA (push_pop). Returns the range ID for start_stop; 0 for push_pop.
|
|
inline roctx_range_id_t
|
|
range_start(const char* name, bool use_push_pop)
|
|
{
|
|
if(use_push_pop)
|
|
{
|
|
roctxRangePushA(name);
|
|
return 0;
|
|
}
|
|
return roctxRangeStartA(name);
|
|
}
|
|
|
|
// Close the region opened by range_start().
|
|
inline void
|
|
range_stop(roctx_range_id_t id, bool use_push_pop)
|
|
{
|
|
if(use_push_pop)
|
|
roctxRangePop();
|
|
else
|
|
roctxRangeStop(id);
|
|
}
|
|
|
|
static std::mutex print_lock{};
|
|
|
|
#define HIP_CHECK(call) \
|
|
do \
|
|
{ \
|
|
hipError_t err = call; \
|
|
if(err != hipSuccess) \
|
|
{ \
|
|
std::lock_guard<std::mutex> _lk{ print_lock }; \
|
|
fprintf(stderr, "HIP error %s at %s:%d\n", hipGetErrorString(err), __FILE__, \
|
|
__LINE__); \
|
|
exit(1); \
|
|
} \
|
|
} while(0)
|
|
|
|
constexpr int KERNEL_ELEMENTS = 1024 * 1024;
|
|
constexpr int KERNEL_ITERS = 1000;
|
|
constexpr int BLOCK_SIZE = 256;
|
|
constexpr int GRID_SIZE = (KERNEL_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
|
|
|
// Each code block launches the kernel this many times to produce enough
|
|
// sustained CPU+GPU work for the sampling profiler to capture thread timers.
|
|
constexpr int KERNEL_LAUNCH_REPEATS = 100;
|
|
constexpr size_t DEFAULT_NUM_THREADS = 2;
|
|
|
|
#define DEFINE_KERNEL(name, offset) \
|
|
__global__ void name(float* data, int n) \
|
|
{ \
|
|
int idx = blockIdx.x * blockDim.x + threadIdx.x; \
|
|
if(idx < n) \
|
|
for(int i = 0; i < KERNEL_ITERS; ++i) \
|
|
data[idx] = __sinf(data[idx] + float(offset)); \
|
|
}
|
|
|
|
#define LAUNCH_KERNEL(name, data) \
|
|
do \
|
|
{ \
|
|
name<<<GRID_SIZE, BLOCK_SIZE>>>(data, KERNEL_ELEMENTS); \
|
|
HIP_CHECK(hipDeviceSynchronize()); \
|
|
} while(0)
|
|
|
|
#define LAUNCH_KERNEL_STREAM(name, stream, data) \
|
|
do \
|
|
{ \
|
|
for(int _rep = 0; _rep < KERNEL_LAUNCH_REPEATS; ++_rep) \
|
|
{ \
|
|
name<<<GRID_SIZE, BLOCK_SIZE, 0, stream>>>(data, KERNEL_ELEMENTS); \
|
|
HIP_CHECK(hipStreamSynchronize(stream)); \
|
|
} \
|
|
} while(0)
|
|
|
|
struct gpu_buffer
|
|
{
|
|
float* d_data = nullptr;
|
|
|
|
gpu_buffer()
|
|
{
|
|
HIP_CHECK(hipMalloc(&d_data, KERNEL_ELEMENTS * sizeof(float)));
|
|
HIP_CHECK(hipMemset(d_data, 0, KERNEL_ELEMENTS * sizeof(float)));
|
|
}
|
|
|
|
~gpu_buffer() { (void) hipFree(d_data); }
|
|
|
|
gpu_buffer(const gpu_buffer&) = delete;
|
|
gpu_buffer& operator=(const gpu_buffer&) = delete;
|
|
|
|
float* get() { return d_data; }
|
|
};
|
|
|
|
// Reusable barrier for synchronizing N threads at region boundaries.
|
|
// Threads must all arrive before any can proceed past each wait() call.
|
|
class thread_barrier
|
|
{
|
|
public:
|
|
explicit thread_barrier(size_t count)
|
|
: m_threshold(count)
|
|
, m_count(count)
|
|
, m_generation(0)
|
|
{}
|
|
|
|
void wait()
|
|
{
|
|
std::unique_lock<std::mutex> lock{ m_mutex };
|
|
auto gen = m_generation;
|
|
if(--m_count == 0)
|
|
{
|
|
++m_generation;
|
|
m_count = m_threshold;
|
|
lock.unlock();
|
|
m_cv.notify_all();
|
|
}
|
|
else
|
|
{
|
|
m_cv.wait(lock, [this, gen] { return gen != m_generation; });
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::mutex m_mutex;
|
|
std::condition_variable m_cv;
|
|
size_t m_threshold;
|
|
size_t m_count;
|
|
size_t m_generation;
|
|
};
|
|
|
|
inline void
|
|
run_on_threads(size_t nthreads, std::function<void(int, hipStream_t)> func)
|
|
{
|
|
std::vector<hipStream_t> streams(nthreads);
|
|
for(size_t i = 0; i < nthreads; ++i)
|
|
HIP_CHECK(hipStreamCreate(&streams[i]));
|
|
|
|
std::vector<std::thread> threads;
|
|
for(size_t i = 1; i < nthreads; ++i)
|
|
threads.emplace_back(func, static_cast<int>(i), streams[i]);
|
|
|
|
func(0, streams[0]);
|
|
|
|
for(auto& t : threads)
|
|
t.join();
|
|
|
|
for(size_t i = 0; i < nthreads; ++i)
|
|
HIP_CHECK(hipStreamDestroy(streams[i]));
|
|
}
|