Fichiers
rocm-systems/rocrtst/samples/rocm_async/rocm_async.cpp
T
Ramesh Errabolu c2caa5ae2c Benchmark copy of data from one pool to another pool either in
one or both directions. Users can enumerate the pools reported
  by system to specify which pools serve as source / destination

Change-Id: I8e6d0adb3743b3328dd3ce9152762ca840ea613b
2017-10-04 20:53:25 -04:00

479 lignes
16 KiB
C++
Fichiers exécutables

#include "common.hpp"
#include "rocm_async.hpp"
#include <stdlib.h>
#include <assert.h>
#include <algorithm>
#include <unistd.h>
#include <cctype>
#include <sstream>
// The values are in megabytes at allocation time
const uint32_t RocmAsync::SIZE_LIST[] = { 64, 128, 256, 512 };
//const uint32_t RocmAsync::SIZE_LIST[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 };
uint32_t RocmAsync::GetIterationNum() {
return num_iteration_ * 1.2 + 1;
}
void RocmAsync::AcquireAccess(hsa_agent_t agent, void* ptr) {
err_ = hsa_amd_agents_allow_access(1, &agent, NULL, ptr);
ErrorCheck(err_);
}
void RocmAsync::AllocateHostBuffers(bool bidir, uint32_t size,
void*& src_fwd, void*& dst_fwd,
void* buf_src_fwd, void* buf_dst_fwd,
hsa_agent_t src_agent_fwd, hsa_agent_t dst_agent_fwd,
void*& src_rev, void*& dst_rev,
void* buf_src_rev, void* buf_dst_rev,
hsa_agent_t src_agent_rev, hsa_agent_t dst_agent_rev,
hsa_signal_t& signal_fwd, hsa_signal_t& signal_rev) {
// Allocate host buffers and setup accessibility for copy operation
err_ = hsa_amd_memory_pool_allocate(sys_pool_, size, 0, (void**)&src_fwd);
ErrorCheck(err_);
AcquireAccess(src_agent_fwd, src_fwd);
AcquireAccess(cpu_agent_, buf_src_fwd);
err_ = hsa_amd_memory_pool_allocate(sys_pool_, size, 0, (void**)&dst_fwd);
ErrorCheck(err_);
AcquireAccess(dst_agent_fwd, dst_fwd);
AcquireAccess(cpu_agent_, buf_dst_fwd);
// Initialize host buffers to a determinate value
memset(src_fwd, 0x23, size);
memset(dst_fwd, 0x00, size);
// Create a signal to wait on copy operation
// @TODO: replace it with a signal pool call
err_ = hsa_signal_create(1, 0, NULL, &signal_fwd);
ErrorCheck(err_);
if (bidir == false) {
return;
}
err_ = hsa_amd_memory_pool_allocate(sys_pool_, size, 0, (void**)&src_rev);
ErrorCheck(err_);
AcquireAccess(src_agent_rev, src_rev);
AcquireAccess(cpu_agent_, buf_src_rev);
err_ = hsa_amd_memory_pool_allocate(sys_pool_, size, 0, (void**)&dst_rev);
ErrorCheck(err_);
AcquireAccess(dst_agent_rev, dst_rev);
AcquireAccess(cpu_agent_, buf_dst_rev);
// Initialize host buffers to a determinate value
memset(src_rev, 0x23, size);
memset(dst_rev, 0x00, size);
err_ = hsa_signal_create(1, 0, NULL, &signal_rev);
ErrorCheck(err_);
}
void RocmAsync::AllocateCopyBuffers(bool bidir, uint32_t size,
void*& src_fwd, hsa_amd_memory_pool_t src_pool_fwd,
void*& dst_fwd, hsa_amd_memory_pool_t dst_pool_fwd,
hsa_agent_t src_agent_fwd, hsa_agent_t dst_agent_fwd,
void*& src_rev, hsa_amd_memory_pool_t src_pool_rev,
void*& dst_rev, hsa_amd_memory_pool_t dst_pool_rev,
hsa_agent_t src_agent_rev, hsa_agent_t dst_agent_rev,
hsa_signal_t& signal_fwd, hsa_signal_t& signal_rev) {
// Allocate buffers in src and dst pools for forward copy
err_ = hsa_amd_memory_pool_allocate(src_pool_fwd, size, 0, &src_fwd);
ErrorCheck(err_);
err_ = hsa_amd_memory_pool_allocate(dst_pool_fwd, size, 0, &dst_fwd);
ErrorCheck(err_);
// Allocate buffers in src and dst pools for reverse copy
if (bidir) {
err_ = hsa_amd_memory_pool_allocate(src_pool_rev, size, 0, &src_rev);
ErrorCheck(err_);
err_ = hsa_amd_memory_pool_allocate(dst_pool_rev, size, 0, &dst_rev);
ErrorCheck(err_);
}
// Acquire access to src and dst buffers for forward copy
AcquireAccess(src_agent_fwd, dst_fwd);
AcquireAccess(dst_agent_fwd, src_fwd);
// Acquire access to src and dst buffers for reverse copy
if (bidir) {
AcquireAccess(src_agent_rev, dst_rev);
AcquireAccess(dst_agent_rev, src_rev);
}
// Create a signal to wait on copy operation
// @TODO: replace it with a signal pool call
err_ = hsa_signal_create(1, 0, NULL, &signal_fwd);
ErrorCheck(err_);
if (bidir) {
err_ = hsa_signal_create(1, 0, NULL, &signal_rev);
ErrorCheck(err_);
}
}
void RocmAsync::ReleaseBuffers(bool bidir,
void* src_fwd, void* src_rev,
void* dst_fwd, void* dst_rev,
hsa_signal_t signal_fwd,
hsa_signal_t signal_rev) {
// Free the src and dst buffers used in forward copy
// including the signal used to wait
err_ = hsa_amd_memory_pool_free(src_fwd);
ErrorCheck(err_);
err_ = hsa_amd_memory_pool_free(dst_fwd);
ErrorCheck(err_);
err_ = hsa_signal_destroy(signal_fwd);
ErrorCheck(err_);
// Free the src and dst buffers used in reverse copy
// including the signal used to wait
if (bidir) {
err_ = hsa_amd_memory_pool_free(src_rev);
ErrorCheck(err_);
err_ = hsa_amd_memory_pool_free(dst_rev);
ErrorCheck(err_);
err_ = hsa_signal_destroy(signal_rev);
ErrorCheck(err_);
}
}
double RocmAsync::GetGpuCopyTime(bool bidir,
hsa_signal_t signal_fwd,
hsa_signal_t signal_rev) {
// Obtain time taken for forward copy
hsa_amd_profiling_async_copy_time_t async_time_fwd = {0};
err_= hsa_amd_profiling_get_async_copy_time(signal_fwd, &async_time_fwd);
ErrorCheck(err_);
if (bidir == false) {
return(async_time_fwd.end - async_time_fwd.start);
}
hsa_amd_profiling_async_copy_time_t async_time_rev = {0};
err_= hsa_amd_profiling_get_async_copy_time(signal_rev, &async_time_rev);
ErrorCheck(err_);
double start = min(async_time_fwd.start, async_time_rev.start);
double end = max(async_time_fwd.end, async_time_rev.end);
return(end - start);
}
void RocmAsync::copy_buffer(void* dst, hsa_agent_t dst_agent,
void* src, hsa_agent_t src_agent,
size_t size, hsa_signal_t signal) {
// Copy from src into dst buffer
err_ = hsa_amd_memory_async_copy(dst, dst_agent,
src, src_agent,
size, 0, NULL, signal);
ErrorCheck(err_);
// Wait for the forward copy operation to complete
while (hsa_signal_wait_acquire(signal, HSA_SIGNAL_CONDITION_LT, 1,
uint64_t(-1), HSA_WAIT_STATE_ACTIVE));
}
void RocmAsync::RunCopyBenchmark(async_trans_t& trans) {
// Bind if this transaction is bidirectional
bool bidir = trans.copy.bidir_;
// Initialize size of buffer to equal the largest element of allocation
uint32_t size_len = size_list_.size();
uint32_t max_size = size_list_.back() * 1024 * 1024;
// Bind to resources such as pool and agents that are involved
// in both forward and reverse copy operations
void* buf_src_fwd;
void* buf_dst_fwd;
void* buf_src_rev;
void* buf_dst_rev;
void* host_src_fwd;
void* host_dst_fwd;
void* host_src_rev;
void* host_dst_rev;
hsa_signal_t signal_fwd;
hsa_signal_t signal_rev;
hsa_signal_t host_signal_fwd;
hsa_signal_t host_signal_rev;
hsa_amd_memory_pool_t src_pool_fwd = trans.copy.src_pool_;
hsa_amd_memory_pool_t dst_pool_fwd = trans.copy.dst_pool_;
hsa_amd_memory_pool_t src_pool_rev = dst_pool_fwd;
hsa_amd_memory_pool_t dst_pool_rev = src_pool_fwd;
hsa_agent_t src_agent_fwd = pool_list_[trans.copy.src_idx_].owner_agent_;
hsa_agent_t dst_agent_fwd = pool_list_[trans.copy.dst_idx_].owner_agent_;
hsa_agent_t src_agent_rev = dst_agent_fwd;
hsa_agent_t dst_agent_rev = src_agent_fwd;
// Allocate buffers and signal objects
AllocateCopyBuffers(bidir, max_size,
buf_src_fwd, src_pool_fwd,
buf_dst_fwd, dst_pool_fwd,
src_agent_fwd, dst_agent_fwd,
buf_src_rev, src_pool_rev,
buf_dst_rev, dst_pool_rev,
src_agent_rev, dst_agent_rev,
signal_fwd, signal_rev);
if (verify_) {
AllocateHostBuffers(bidir, max_size,
host_src_fwd, host_dst_fwd,
buf_src_fwd, buf_dst_fwd,
src_agent_fwd, dst_agent_fwd,
host_src_rev, host_dst_rev,
buf_src_rev, buf_dst_rev,
src_agent_rev, dst_agent_rev,
host_signal_fwd, host_signal_rev);
// Initialize source buffer with values from verification buffer
copy_buffer(buf_src_fwd, src_agent_fwd,
host_src_fwd, cpu_agent_,
max_size, host_signal_fwd);
ErrorCheck(err_);
if (bidir) {
copy_buffer(buf_src_rev, src_agent_rev,
host_src_rev, cpu_agent_,
max_size, host_signal_rev);
ErrorCheck(err_);
}
}
// Bind the number of iterations
uint32_t iterations = GetIterationNum();
// Iterate through the differnt buffer sizes to
// compute the bandwidth as determined by copy
for (uint32_t idx = 0; idx < size_len; idx++) {
// This should not be happening
uint32_t curr_size = size_list_[idx] * 1024 * 1024;
if (curr_size > max_size) {
break;
}
std::vector<double> cpu_time;
std::vector<double> gpu_time;
for (uint32_t it = 0; it < iterations; it++) {
#if DEBUG
printf(".");
fflush(stdout);
#endif
hsa_signal_store_relaxed(signal_fwd, 1);
if (bidir) {
hsa_signal_store_relaxed(signal_rev, 1);
}
if (verify_) {
AcquireAccess(src_agent_fwd, buf_dst_fwd);
AcquireAccess(dst_agent_fwd, buf_src_fwd);
if (bidir) {
AcquireAccess(src_agent_rev, buf_dst_rev);
AcquireAccess(dst_agent_rev, buf_src_rev);
}
}
// Create a timer object and reset signals
PerfTimer timer;
uint32_t index = timer.CreateTimer();
// Start the timer and launch forward copy operation
timer.StartTimer(index);
err_ = hsa_amd_memory_async_copy(buf_dst_fwd, dst_agent_fwd,
buf_src_fwd, src_agent_fwd,
curr_size, 0, NULL, signal_fwd);
ErrorCheck(err_);
// Launch reverse copy operation if it is bidirectional
if (bidir) {
err_ = hsa_amd_memory_async_copy(buf_dst_rev, dst_agent_rev,
buf_src_rev, src_agent_rev,
curr_size, 0, NULL, signal_rev);
ErrorCheck(err_);
}
// Wait for the forward copy operation to complete
while (hsa_signal_wait_acquire(signal_fwd, HSA_SIGNAL_CONDITION_LT, 1,
uint64_t(-1), HSA_WAIT_STATE_ACTIVE));
// Wait for the reverse copy operation to complete
if (bidir) {
while (hsa_signal_wait_acquire(signal_rev, HSA_SIGNAL_CONDITION_LT, 1,
uint64_t(-1), HSA_WAIT_STATE_ACTIVE));
}
// Stop the timer object
timer.StopTimer(index);
// Push the time taken for copy into a vector of copy times
cpu_time.push_back(timer.ReadTimer(index));
// Collect time from the signal(s)
if (trans.copy.uses_gpu_) {
double temp = GetGpuCopyTime(bidir, signal_fwd, signal_rev);
gpu_time.push_back(temp);
}
if (verify_) {
// Re-Establish access to destination buffer and host buffer
AcquireAccess(cpu_agent_, buf_dst_fwd);
AcquireAccess(dst_agent_fwd, host_dst_fwd);
// Init dst buffer with values from outbuffer of copy operation
hsa_signal_store_relaxed(host_signal_fwd, 1);
copy_buffer(host_dst_fwd, cpu_agent_,
buf_dst_fwd, dst_agent_fwd,
curr_size, host_signal_fwd);
ErrorCheck(err_);
// Compare output equals input
err_ = (hsa_status_t)memcmp(host_src_fwd, host_dst_fwd, curr_size);
ErrorCheck(err_);
if (bidir) {
// Re-Establish access to destination buffer and host buffer
AcquireAccess(cpu_agent_, buf_dst_rev);
AcquireAccess(dst_agent_rev, host_dst_rev);
hsa_signal_store_relaxed(host_signal_rev, 1);
copy_buffer(host_dst_rev, cpu_agent_,
buf_dst_rev, dst_agent_rev,
curr_size, host_signal_rev);
ErrorCheck(err_);
// Compare output equals input
err_ = (hsa_status_t)memcmp(host_src_rev, host_dst_rev, curr_size);
ErrorCheck(err_);
}
}
}
#if DEBUG
std::cout << std::endl;
#endif
// Get Cpu min copy time
trans.cpu_min_time_.push_back(GetMinTime(cpu_time));
// Get Cpu mean copy time and store to the array
trans.cpu_avg_time_.push_back(GetMeanTime(cpu_time));
if (trans.copy.uses_gpu_) {
// Get Gpu min copy time
trans.gpu_min_time_.push_back(GetMinTime(gpu_time));
// Get Gpu mean copy time and store to the array
trans.gpu_avg_time_.push_back(GetMeanTime(gpu_time));
}
// Clear the stack of cpu times
cpu_time.clear();
gpu_time.clear();
}
// Free up buffers and signal objects used in copy operation
ReleaseBuffers(bidir, buf_src_fwd, buf_src_rev,
buf_dst_fwd, buf_dst_rev, signal_fwd, signal_rev);
if (verify_) {
ReleaseBuffers(bidir, host_src_fwd, host_src_rev,
host_dst_fwd, host_dst_rev, host_signal_fwd, host_signal_rev);
}
}
void RocmAsync::RunIOBenchmark(async_trans_t& trans) {
std::cout << "Unsupported Request - Read / Write" << std::endl;
exit(1);
}
void RocmAsync::Run() {
// Enable profiling of Async Copy Activity
err_ = hsa_amd_profiling_async_copy_enable(true);
ErrorCheck(err_);
// Iterate through the list of transactions and execute them
uint32_t trans_size = trans_list_.size();
for (uint32_t idx = 0; idx < trans_size; idx++) {
async_trans_t& trans = trans_list_[idx];
if ((trans.req_type_ == REQ_COPY_BIDIR) ||
(trans.req_type_ == REQ_COPY_UNIDIR)) {
RunCopyBenchmark(trans);
}
if ((trans.req_type_ == REQ_READ) ||
(trans.req_type_ == REQ_WRITE)) {
RunIOBenchmark(trans);
}
}
// Disable profiling of Async Copy Activity
err_ = hsa_amd_profiling_async_copy_enable(false);
ErrorCheck(err_);
}
void RocmAsync::Close() {
hsa_status_t status = hsa_shut_down();
ErrorCheck(status);
return;
}
// Sets up the bandwidth test object to enable running
// the various test scenarios requested by user. The
// things this proceedure takes care of are:
//
// Parse user arguments
// Discover RocR Device Topology
// Determine validity of requested test scenarios
// Build the list of transactions to execute
// Miscellaneous
//
void RocmAsync::SetUp() {
// Parse user arguments
ParseArguments();
// Validate input parameters
bool status = ValidateArguments();
if (status == false) {
PrintHelpScreen();
exit(1);
}
// Build list of transactions (copy, read, write) to execute
status = BuildTransList();
if (status == false) {
PrintHelpScreen();
exit(1);
}
// Print Debug Info - List of Agents, Pool, Transactions
char* print_debug = getenv("PRINT_DEBUG");
if (print_debug) {
//PrintAgentsList();
//PrintPoolsList();
PrintTransList();
//PrintTopology();
}
}
RocmAsync::RocmAsync(int argc, char** argv) : BaseTest() {
usr_argc_ = argc;
usr_argv_ = argv;
verify_ = false;
pool_index_ = 0;
agent_index_ = 0;
req_read_ = REQ_INVALID;
req_write_ = REQ_INVALID;
req_copy_bidir_ = REQ_INVALID;
req_copy_unidir_ = REQ_INVALID;
}
RocmAsync::~RocmAsync() { }