Add 'projects/rocshmem/' from commit '0496586829058af5cfd7f23acda2a6d0040da584'

git-subtree-dir: projects/rocshmem
git-subtree-mainline: 5fd976da70
git-subtree-split: 0496586829
Этот коммит содержится в:
Ameya Keshava Mallya
2026-01-21 20:25:37 +00:00
родитель 5fd976da70 0496586829
Коммит 12ab8df3bc
367 изменённых файлов: 81890 добавлений и 0 удалений
+108
Просмотреть файл
@@ -0,0 +1,108 @@
###############################################################################
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# 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.
###############################################################################
cmake_minimum_required(VERSION 3.16.3 FATAL_ERROR)
###############################################################################
# PROJECT
###############################################################################
include(${CMAKE_SOURCE_DIR}/cmake/setup_project.cmake)
project(rocshmem_functional_tests VERSION 1.0.0 LANGUAGES CXX)
###############################################################################
# SOURCES
###############################################################################
add_executable(${PROJECT_NAME} "")
target_include_directories(
${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_sources(
${PROJECT_NAME}
PRIVATE
barrier_all_tester.cpp
sync_all_tester.cpp
test_driver.cpp
tester.cpp
tester_arguments.cpp
ping_pong_tester.cpp
ping_all_tester.cpp
primitive_tester.cpp
primitive_mr_tester.cpp
default_ctx_primitive_tester.cpp
team_ctx_primitive_tester.cpp
team_ctx_infra_tester.cpp
amo_bitwise_tester.cpp
amo_extended_tester.cpp
amo_standard_tester.cpp
random_access_tester.cpp
shmem_ptr_tester.cpp
signaling_operations_tester.cpp
signaling_operations_tester.hpp
workgroup_primitives.cpp
empty_tester.cpp
wavefront_primitives.cpp
flood_tester.cpp
)
###############################################################################
# ROCSHMEM
###############################################################################
if (BUILD_TESTS_ONLY)
#TODO these find_packages should be performed as-needed in rocshmem-config.cmake
find_package(hip REQUIRED PATHS /opt/rocm)
find_package(MPI)
find_package(Threads REQUIRED)
find_package(rocshmem REQUIRED PATHS /opt/rocm)
target_include_directories(
${PROJECT_NAME}
PRIVATE
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../src>
)
endif()
find_package(PMIx)
target_compile_definitions(
${PROJECT_NAME}
PRIVATE
$<$<TARGET_EXISTS:PMIx::pmix>:HAVE_PMIX=1>
)
configure_file(../../scripts/functional_tests/driver.sh rocshmem_functional_driver.sh COPYONLY)
rocm_install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/rocshmem_functional_driver.sh COMPONENT tests DESTINATION ${CMAKE_INSTALL_DATADIR}/rocshmem)
rocm_install(TARGETS rocshmem_functional_tests COMPONENT tests)
target_link_libraries(
${PROJECT_NAME}
PRIVATE
roc::rocshmem
$<TARGET_NAME_IF_EXISTS:MPI::MPI_CXX>
$<TARGET_NAME_IF_EXISTS:PMIx::pmix>
)
+302
Просмотреть файл
@@ -0,0 +1,302 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "amo_bitwise_tester.hpp"
#include <iostream>
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/* Declare the global kernel template with a generic implementation */
template <typename T>
__global__ void AMOBitwiseTest(int loop, int skip, long long int *start_time,
long long int *end_time, T *dest, T *ret_val,
AddrMode addr_mode, TestType type,
ShmemContextType ctx_type) {
return;
}
template <class T>
__device__ inline T* compute_target_ptr(T* base_ptr, AddrMode addr_mode,
int wg_idx, int itr, int n_wgs) {
// PerBlock: element = wg_idx, with n_wgs elements per loop
// PerGrid : single element shared by the whole grid per loop
if (addr_mode == AddrMode::PerBlock) {
size_t offset = wg_idx + itr * n_wgs;
return base_ptr + offset;
} else { // PerGrid
return base_ptr + itr;
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T>
AMOBitwiseTester<T>::AMOBitwiseTester(TesterArguments args) : Tester(args) {
n_out = (args.addr_mode == AddrMode::PerBlock) ? args.num_wgs : 1;
n_in = args.num_wgs * args.wg_size;
n_loops = args.loop + args.skip;
// One return per *thread* per loop
CHECK_HIP(hipMalloc((void **)&ret_val, args.max_msg_size * n_in * n_loops));
dest = (T *)rocshmem_malloc(args.max_msg_size * n_out * n_loops);
if (dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "dest: " << (void*)dest << std::endl;
}
}
template <typename T>
AMOBitwiseTester<T>::~AMOBitwiseTester() {
CHECK_HIP(hipFree(ret_val));
rocshmem_free(dest);
}
template <typename T>
void AMOBitwiseTester<T>::resetBuffers(size_t size) {
memset(ret_val, 0, args.max_msg_size * n_in * n_loops);
memset(dest, 0, args.max_msg_size * n_out * n_loops);
}
template <typename T>
void AMOBitwiseTester<T>::launchKernel(dim3 gridsize, dim3 blocksize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(AMOBitwiseTest, gridsize, blocksize, shared_bytes, stream,
args.loop, args.skip, start_time, end_time, dest,
ret_val, args.addr_mode, _type, _shmem_context);
num_msgs = n_loops * gridsize.x * blocksize.x;
num_timed_msgs = args.loop * gridsize.x * blocksize.x;
}
template <typename G>
void fail_eq(const G& got, const G& exp) {
std::cerr << "data validation error\n"
<< "got " << got << ", expected " << exp << std::endl;
std::exit(-1);
}
// Map (loop, elem_idx) -> dest[] index for current address mode.
template <typename T>
int AMOBitwiseTester<T>::destIndex(int l, int elem_idx) const {
return (args.addr_mode == AddrMode::PerBlock)
? l * static_cast<int>(args.num_wgs) + elem_idx
: l; // PerGrid has a single element per loop
}
// Number of output elements to check per loop for current address mode.
template <typename T>
int AMOBitwiseTester<T>::numElems() const {
return (args.addr_mode == AddrMode::PerBlock)
? static_cast<int>(args.num_wgs)
: 1; // PerGrid
}
// Return pointer to the start of the ret_val “chunk” for (loop, elem_idx)
// plus the chunk length for this address mode.
template <typename T>
std::pair<T*, int> AMOBitwiseTester<T>::retChunk(int l, int elem_idx) const {
if (args.addr_mode == AddrMode::PerBlock) {
// One chunk per element (workgroup): wg_size returns
T* p = ret_val + l * n_in + elem_idx * args.wg_size;
int sz = static_cast<int>(args.wg_size);
return {p, sz};
}
// PerGrid: one big chunk per loop (all threads)
T* p = ret_val + l * n_in;
int sz = static_cast<int>(n_in);
return {p, sz};
}
template <typename T>
void AMOBitwiseTester<T>::verifyDestValues() {
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
auto check_equal_all = [&](T expected) {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
const int idx = destIndex(l, elem);
if (dest[idx] != expected) fail_eq(dest[idx], expected);
}
}
};
// Use all-ones mask for type T
const T MASK = static_cast<T>(~T{0});
switch (_type) {
case AMO_AndTestType:
case AMO_FetchAndTestType: {
// Start at 0; 0 & MASK == 0 regardless of writer count.
check_equal_all(static_cast<T>(0));
break;
}
case AMO_OrTestType:
case AMO_FetchOrTestType: {
// final value is MASK.
check_equal_all(MASK);
break;
}
case AMO_XorTestType:
case AMO_FetchXorTestType: {
// PerBlock: K = wg_size; PerGrid: K = num_wgs * wg_size
const int K = (args.addr_mode == AddrMode::PerBlock)
? static_cast<int>(args.wg_size)
: static_cast<int>(args.num_wgs * args.wg_size);
const T expected = (K & 1) ? MASK : static_cast<T>(0);
check_equal_all(expected);
break;
}
default:
break;
}
}
template <typename T>
void AMOBitwiseTester<T>::verifyReturnValues() {
// Only “fetch-*” types produce return values to validate.
if (_type == AMO_AndTestType || _type == AMO_OrTestType ||
_type == AMO_XorTestType) return;
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
const T MASK = static_cast<T>(~T{0});
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
auto [p, cnt] = retChunk(l, elem);
// Count distribution of observed old values in this chunk
int zeros = 0, masks = 0;
for (int i = 0; i < cnt; ++i) {
zeros += (p[i] == static_cast<T>(0));
masks += (p[i] == MASK);
}
if (zeros + masks != cnt) {
fail_eq(zeros + masks, cnt); // unexpected values present
}
switch (_type) {
case AMO_FetchAndTestType:
// Old value is 0 (dest stays 0)
if (!(zeros == cnt && masks == 0)) fail_eq(zeros, cnt);
break;
case AMO_FetchOrTestType:
// Exactly one 0 (the first OR), rest MASK
if (!(zeros == 1 && masks == cnt - 1)) fail_eq(zeros, 1);
break;
case AMO_FetchXorTestType: {
// returns multiset = { ceil(K/2) zeros, floor(K/2) MASKs }
const int exp_zeros = (cnt + 1) / 2; // ceil(cnt/2)
const int exp_masks = cnt / 2; // floor(cnt/2)
if (!(zeros == exp_zeros && masks == exp_masks)) {
fail_eq(zeros, exp_zeros);
}
// cross-check
if ((cnt & 1) && zeros != masks + 1) fail_eq(zeros, masks + 1);
if (!(cnt & 1) && zeros != masks) fail_eq(zeros, masks);
break;
}
default:
break;
}
}
}
}
template <typename T>
void AMOBitwiseTester<T>::verifyResults(size_t size) {
// PE 0 checks returns; target PE checks dest.
if (args.myid) {
verifyDestValues();
} else {
verifyReturnValues();
}
}
#define AMO_BITWISE_DEF_GEN(T, TNAME) \
template <> \
__global__ void AMOBitwiseTest<T>( \
int loop, int skip, long long int *start_time, \
long long int *end_time, T *dest, T *ret_val, \
AddrMode addr_mode, TestType type, ShmemContextType ctx_type) { \
__shared__ rocshmem_ctx_t ctx; \
int wg_id = get_flat_grid_id(); \
int global_id = get_flat_id(); \
int n_threads = get_flat_grid_size(); \
int n_wgs = get_grid_num_blocks(); \
rocshmem_wg_ctx_create(ctx_type, &ctx); \
for (int i = 0; i < loop + skip; i++) { \
T *ptr = compute_target_ptr<T>(dest, addr_mode, wg_id, i, n_wgs); \
T ret = 0; \
if (i == skip) { \
start_time[wg_id] = wall_clock64(); \
} \
switch (type) { \
case AMO_FetchAndTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch_and(ctx, ptr, \
(T)~(T)0, 1); \
break; \
case AMO_AndTestType: \
rocshmem_ctx_##TNAME##_atomic_and(ctx, ptr, (T)~(T)0, 1); \
break; \
case AMO_FetchOrTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch_or(ctx, ptr, \
(T)~(T)0, 1); \
break; \
case AMO_OrTestType: \
rocshmem_ctx_##TNAME##_atomic_or(ctx, ptr, (T)~(T)0, 1); \
break; \
case AMO_FetchXorTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch_xor(ctx, ptr, \
(T)~(T)0, 1); \
break; \
case AMO_XorTestType: \
rocshmem_ctx_##TNAME##_atomic_xor(ctx, ptr, (T)~(T)0, 1); \
break; \
default: \
break; \
} \
ret_val[global_id + i * n_threads] = ret; \
} \
rocshmem_ctx_quiet(ctx); \
end_time[wg_id] = wall_clock64(); \
__syncthreads(); \
rocshmem_wg_ctx_destroy(&ctx); \
} \
template class AMOBitwiseTester<T>;
AMO_BITWISE_DEF_GEN(unsigned int, uint)
AMO_BITWISE_DEF_GEN(unsigned long, ulong)
AMO_BITWISE_DEF_GEN(unsigned long long, ulonglong)
AMO_BITWISE_DEF_GEN(int32_t, int32)
AMO_BITWISE_DEF_GEN(int64_t, int64)
+62
Просмотреть файл
@@ -0,0 +1,62 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _AMO_BITWISE_TESTER_HPP_
#define _AMO_BITWISE_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T>
class AMOBitwiseTester : public Tester {
public:
explicit AMOBitwiseTester(TesterArguments args);
virtual ~AMOBitwiseTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
void verifyDestValues();
void verifyReturnValues();
int destIndex(int l, int elem_idx) const;
int numElems() const;
std::pair<T*, int> retChunk(int l, int elem_idx) const;
T* dest{nullptr}; // symmetric target buffer [loop][elem]
T* ret_val{nullptr}; // device returns [loop][thread]
size_t n_in{0}; // num_wgs * wg_size
size_t n_out{0}; // elements per loop: PerBlock->num_wgs, PerGrid->1
size_t n_loops{0}; // loop + skip
};
#endif
+268
Просмотреть файл
@@ -0,0 +1,268 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "amo_extended_tester.hpp"
#include <iostream>
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/* Declare the global kernel template with a generic implementation */
template <typename T>
__global__ void AMOExtendedTest(int loop, int skip, long long int *start_time,
long long int *end_time, T *dest, T *ret_val,
AddrMode addr_mode, TestType type,
ShmemContextType ctx_type) {
return;
}
template <class T>
__device__ inline T* compute_target_ptr(T* base_ptr, AddrMode addr_mode,
int wg_idx, int itr, int n_wgs) {
// PerBlock: element = wg_idx, with n_wgs elements per loop
// PerGrid : single element shared by the whole grid per loop
if (addr_mode == AddrMode::PerBlock) {
size_t offset = wg_idx + itr * n_wgs;
return base_ptr + offset;
} else { // PerGrid
return base_ptr + itr;
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T>
AMOExtendedTester<T>::AMOExtendedTester(TesterArguments args) : Tester(args) {
n_out = (args.addr_mode == AddrMode::PerBlock) ? args.num_wgs : 1;
n_in = args.num_wgs * args.wg_size;
n_loops = args.loop + args.skip;
// One return per *thread* per loop
CHECK_HIP(hipMalloc((void **)&ret_val, args.max_msg_size * n_in * n_loops));
dest = (T *)rocshmem_malloc(args.max_msg_size * n_out * n_loops);
if (dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "dest: " << (void*)dest << std::endl;
}
}
template <typename T>
AMOExtendedTester<T>::~AMOExtendedTester() {
CHECK_HIP(hipFree(ret_val));
rocshmem_free(dest);
}
template <typename T>
void AMOExtendedTester<T>::resetBuffers(size_t size) {
memset(ret_val, 0, args.max_msg_size * n_in * n_loops);
memset(dest, 0, args.max_msg_size * n_out * n_loops);
}
template <typename T>
void AMOExtendedTester<T>::launchKernel(dim3 gridsize, dim3 blocksize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(AMOExtendedTest, gridsize, blocksize, shared_bytes, stream,
args.loop, args.skip, start_time, end_time, dest,
ret_val, args.addr_mode, _type, _shmem_context);
num_msgs = n_loops * gridsize.x * blocksize.x;
num_timed_msgs = args.loop * gridsize.x * blocksize.x;
}
template <typename G>
void fail_eq(const G& got, const G& exp) {
std::cerr << "data validation error\n"
<< "got " << got << ", expected " << exp << std::endl;
std::exit(-1);
}
// Map (loop, elem_idx) -> dest[] index for current address mode.
template <typename T>
int AMOExtendedTester<T>::destIndex(int l, int elem_idx) const {
return (args.addr_mode == AddrMode::PerBlock)
? l * static_cast<int>(args.num_wgs) + elem_idx
: l; // PerGrid has a single element per loop
}
// Number of output elements to check per loop for current address mode.
template <typename T>
int AMOExtendedTester<T>::numElems() const {
return (args.addr_mode == AddrMode::PerBlock)
? static_cast<int>(args.num_wgs)
: 1; // PerGrid
}
// Return pointer to the start of the ret_val “chunk” for (loop, elem_idx)
// plus the chunk length for this address mode.
template <typename T>
std::pair<T*, int> AMOExtendedTester<T>::retChunk(int l, int elem_idx) const {
if (args.addr_mode == AddrMode::PerBlock) {
// One chunk per element (workgroup): wg_size returns
T* p = ret_val + l * n_in + elem_idx * args.wg_size;
int sz = static_cast<int>(args.wg_size);
return {p, sz};
}
// PerGrid: one big chunk per loop (all threads)
T* p = ret_val + l * n_in;
int sz = static_cast<int>(n_in);
return {p, sz};
}
template <typename T>
void AMOExtendedTester<T>::verifyDestValues() {
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
auto check_equal_all = [&](T expected) {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
const int idx = destIndex(l, elem);
if (dest[idx] != expected) fail_eq(dest[idx], expected);
}
}
};
auto check_nonzero_all = [&]() {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
const int idx = destIndex(l, elem);
if (dest[idx] == T{0}) fail_eq(dest[idx], T{1});
}
}
};
switch (_type) {
case AMO_FetchTestType:
// fetch does not modify dest -> stays 0
check_equal_all(T{0});
break;
case AMO_SetTestType:
// set writes a constant (17)
check_equal_all(static_cast<T>(17));
break;
case AMO_SwapTestType:
// swap writes non-zero values -> final must be non-zero
check_nonzero_all();
break;
default:
break;
}
}
template <typename T>
void AMOExtendedTester<T>::verifyReturnValues() {
// Only fetch/swap produce return values to validate
if (_type == AMO_SetTestType) return;
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
auto [p, cnt] = retChunk(l, elem);
int zeros = 0;
for (int i = 0; i < cnt; ++i) {
zeros += (p[i] == T{0});
}
if (_type == AMO_FetchTestType) {
// fetch returns the current value (initially 0), dest unchanged
if (zeros != cnt) fail_eq(zeros, cnt);
} else { // AMO_SwapTestType
// For a single element per (loop,elem), exactly one atomic_swap
// observes old==0 (the first arriving swap). The rest see non-zero.
if (zeros != 1) fail_eq(zeros, 1);
}
}
}
}
template <typename T>
void AMOExtendedTester<T>::verifyResults(size_t /*size*/) {
// PE 0 checks returns; target PE checks dest.
if (args.myid) {
verifyDestValues();
} else {
verifyReturnValues();
}
}
#define AMO_EXTENDED_DEF_GEN(T, TNAME) \
template <> \
__global__ void AMOExtendedTest<T>( \
int loop, int skip, long long int *start_time, \
long long int *end_time, T *dest, T *ret_val, \
AddrMode addr_mode, TestType type, ShmemContextType ctx_type) { \
__shared__ rocshmem_ctx_t ctx; \
int wg_id = get_flat_grid_id(); \
int global_id = get_flat_id(); \
int t_id = get_flat_block_id(); \
int n_threads = get_flat_grid_size(); \
int n_wgs = get_grid_num_blocks(); \
rocshmem_wg_ctx_create(ctx_type, &ctx); \
for (int i = 0; i < loop + skip; i++) { \
T *ptr = compute_target_ptr<T>(dest, addr_mode, wg_id, i, n_wgs); \
T ret = 0; \
if (i == skip) { \
start_time[wg_id] = wall_clock64(); \
} \
switch (type) { \
case AMO_FetchTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch(ctx, ptr, 1); \
break; \
case AMO_SetTestType: \
rocshmem_ctx_##TNAME##_atomic_set(ctx, ptr, (T)17, 1); \
break; \
case AMO_SwapTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_swap(ctx, ptr, (T)(t_id + 1),1);\
break; \
default: \
break; \
} \
ret_val[global_id + i * n_threads] = ret; \
} \
rocshmem_ctx_quiet(ctx); \
end_time[wg_id] = wall_clock64(); \
__syncthreads(); \
rocshmem_wg_ctx_destroy(&ctx); \
} \
template class AMOExtendedTester<T>;
AMO_EXTENDED_DEF_GEN(float, float)
AMO_EXTENDED_DEF_GEN(double, double)
AMO_EXTENDED_DEF_GEN(int, int)
AMO_EXTENDED_DEF_GEN(long, long)
AMO_EXTENDED_DEF_GEN(long long, longlong)
AMO_EXTENDED_DEF_GEN(unsigned int, uint)
AMO_EXTENDED_DEF_GEN(unsigned long, ulong)
AMO_EXTENDED_DEF_GEN(unsigned long long, ulonglong)
+62
Просмотреть файл
@@ -0,0 +1,62 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _AMO_EXTENDED_TESTER_HPP_
#define _AMO_EXTENDED_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T>
class AMOExtendedTester : public Tester {
public:
explicit AMOExtendedTester(TesterArguments args);
virtual ~AMOExtendedTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
void verifyDestValues();
void verifyReturnValues();
int destIndex(int l, int elem_idx) const;
int numElems() const;
std::pair<T*, int> retChunk(int l, int elem_idx) const;
T* dest{nullptr}; // symmetric target buffer [loop][elem]
T* ret_val{nullptr}; // device returns [loop][thread]
size_t n_in{0}; // num_wgs * wg_size
size_t n_out{0}; // elements per loop: PerBlock->num_wgs, PerGrid->1
size_t n_loops{0}; // loop + skip
};
#endif
+304
Просмотреть файл
@@ -0,0 +1,304 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "amo_standard_tester.hpp"
#include "tester.hpp"
#include <iostream>
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/* Declare the global kernel template with a generic implementation */
template <typename T>
__global__ void AMOStandardTest(int loop, int skip, long long int *start_time,
long long int *end_time, T *dest,
T *ret_val, AddrMode addr_mode,
TestType type, ShmemContextType ctx_type) {
return;
}
template <class T>
__device__ inline T* compute_target_ptr(T* base_ptr, AddrMode addr_mode,
int wg_idx, int itr, int n_wgs) {
// PerBlock: element = wg_idx, with n_wgs elements per loop
// PerGrid : single element shared by the whole grid per loop
if (addr_mode == AddrMode::PerBlock) {
size_t offset = wg_idx + itr * n_wgs;
return base_ptr + offset;
} else { // PerGrid
return base_ptr + itr;
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T>
AMOStandardTester<T>::AMOStandardTester(TesterArguments args) : Tester(args) {
n_out = (args.addr_mode == AddrMode::PerBlock) ? args.num_wgs : 1;
n_in = args.num_wgs * args.wg_size;
n_loops = args.loop + args.skip;
// One return per *thread* per loop
CHECK_HIP(hipMalloc((void **)&ret_val, args.max_msg_size * n_in * n_loops));
dest = (T *)rocshmem_malloc(args.max_msg_size * n_out * n_loops);
if (dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "dest: " << dest << std::endl;
}
}
template <typename T>
AMOStandardTester<T>::~AMOStandardTester() {
CHECK_HIP(hipFree(ret_val));
rocshmem_free(dest);
}
template <typename T>
void AMOStandardTester<T>::resetBuffers(size_t size) {
memset(ret_val, 0, args.max_msg_size * n_in * n_loops);
memset(dest, 0, args.max_msg_size * n_out * n_loops);
}
template <typename T>
void AMOStandardTester<T>::launchKernel(dim3 gridsize, dim3 blocksize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(AMOStandardTest, gridsize, blocksize, shared_bytes, stream,
args.loop, args.skip, start_time, end_time, dest, ret_val,
args.addr_mode, _type, _shmem_context);
num_msgs = n_loops * gridsize.x * blocksize.x;
num_timed_msgs = args.loop * gridsize.x * blocksize.x;
}
template <typename G>
void fail_eq(const G& got, const G& exp) {
std::cerr << "data validation error\n"
<< "got " << got << ", expected " << exp << std::endl;
std::exit(-1);
}
template <typename G>
void fail_nonzero(const G& got) {
std::cerr << "data validation error\n"
<< "got " << got << ", expected non-zero" << std::endl;
std::exit(-1);
}
// Map (loop, elem_idx) -> dest[] index for current address mode.
template <typename T>
int AMOStandardTester<T>::destIndex(int l, int elem_idx) const {
return (args.addr_mode == AddrMode::PerBlock)
? l * args.num_wgs + elem_idx
: l; // PerGrid has a single element per loop
}
// Number of output elements to check per loop for current address mode.
template <typename T>
int AMOStandardTester<T>::numElems() const {
return (args.addr_mode == AddrMode::PerBlock)
? static_cast<int>(args.num_wgs)
: 1; // PerGrid
}
// Return pointer to the start of the ret_val “chunk” for (loop, elem_idx)
// plus the chunk length for this address mode.
template <typename T>
std::pair<T*, int> AMOStandardTester<T>::retChunk(int l, int elem_idx) const {
if (args.addr_mode == AddrMode::PerBlock) {
// One chunk per element (workgroup): wg_size returns
T* p = ret_val + l * n_in + elem_idx * args.wg_size;
int sz = static_cast<int>(args.wg_size);
return {p, sz};
}
// PerGrid: one big chunk per loop
T* p = ret_val + l * n_in;
int sz = static_cast<int>(n_in);
return {p, sz};
}
template <typename T>
void AMOStandardTester<T>::verifyDestValues() {
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
auto check_equal_all = [&](T expected) {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
const int idx = destIndex(l, elem);
if (dest[idx] != expected) fail_eq(dest[idx], expected);
}
}
};
auto check_nonzero_all = [&]() {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
const int idx = destIndex(l, elem);
if (dest[idx] == T{0}) fail_nonzero(dest[idx]);
}
}
};
switch (_type) {
case AMO_AddTestType:
case AMO_FAddTestType: {
const T expected = (args.addr_mode == AddrMode::PerBlock)
? static_cast<T>(args.wg_size * 2)
: static_cast<T>(args.wg_size * args.num_wgs * 2);
check_equal_all(expected);
break;
}
case AMO_IncTestType:
case AMO_FIncTestType: {
const T expected = (args.addr_mode == AddrMode::PerBlock)
? static_cast<T>(args.wg_size)
: static_cast<T>(args.wg_size * args.num_wgs);
check_equal_all(expected);
break;
}
case AMO_FCswapTestType:
check_nonzero_all();
break;
default:
break;
}
}
template <typename T>
void AMOStandardTester<T>::verifyReturnValues() {
// Only “fetch-*” types produce return values to validate.
if (_type == AMO_AddTestType || _type == AMO_IncTestType) return;
const int loops = static_cast<int>(n_loops);
const int n_elems = numElems();
auto check_sorted_sequence = [&](auto value_of_i) {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
auto [p, cnt] = retChunk(l, elem);
std::sort(p, p + cnt);
for (int i = 0; i < cnt; ++i) {
const T expected = static_cast<T>(value_of_i(i));
if (p[i] != expected) fail_eq(p[i], expected);
}
}
}
};
auto check_single_success_zero = [&]() {
for (int l = 0; l < loops; ++l) {
for (int elem = 0; elem < n_elems; ++elem) {
auto [p, cnt] = retChunk(l, elem);
unsigned success = 0;
for (int i = 0; i < cnt; ++i) if (!p[i]) ++success;
if (success != 1u) fail_eq(success, 1u);
}
}
};
switch (_type) {
case AMO_FAddTestType:
check_sorted_sequence([](int i) { return i * 2; });
break;
case AMO_FIncTestType:
check_sorted_sequence([](int i) { return i; });
break;
case AMO_FCswapTestType:
check_single_success_zero();
break;
default:
break;
}
}
template <typename T>
void AMOStandardTester<T>::verifyResults(size_t size) {
// PE 0 checks returns; target PE checks dest.
if (args.myid) {
verifyDestValues();
} else {
verifyReturnValues();
}
}
#define AMO_STANDARD_DEF_GEN(T, TNAME) \
template <> \
__global__ void AMOStandardTest<T>( \
int loop, int skip, long long int *start_time, \
long long int *end_time, T *dest, T *ret_val, \
AddrMode addr_mode, TestType type, ShmemContextType ctx_type) { \
__shared__ rocshmem_ctx_t ctx; \
int wg_id = get_flat_grid_id(); \
int global_id = get_flat_id(); \
int t_id = get_flat_block_id(); \
int n_threads = get_flat_grid_size(); \
int n_wgs = get_grid_num_blocks(); \
rocshmem_wg_ctx_create(ctx_type, &ctx); \
for (int i = 0; i < loop + skip; i++) { \
T *ptr = compute_target_ptr<T>(dest, addr_mode, wg_id, i, n_wgs); \
T ret = 0; \
if (i == skip) { \
start_time[wg_id] = wall_clock64(); \
} \
switch (type) { \
case AMO_FAddTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch_add(ctx, (T *)ptr, 2, 1); \
break; \
case AMO_FIncTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_fetch_inc(ctx, (T *)ptr, 1); \
break; \
case AMO_FCswapTestType: \
ret = rocshmem_ctx_##TNAME##_atomic_compare_swap(ctx, (T *)ptr, 0, \
(T)(t_id + 1), 1); \
break; \
case AMO_AddTestType: \
rocshmem_ctx_##TNAME##_atomic_add(ctx, (T *)ptr, 2, 1); \
break; \
case AMO_IncTestType: \
rocshmem_ctx_##TNAME##_atomic_inc(ctx, (T *)ptr, 1); \
break; \
default: \
break; \
} \
ret_val[global_id + i * n_threads] = ret; \
} \
rocshmem_ctx_quiet(ctx); \
end_time[wg_id] = wall_clock64(); \
__syncthreads(); \
rocshmem_wg_ctx_destroy(&ctx); \
} \
template class AMOStandardTester<T>;
AMO_STANDARD_DEF_GEN(int, int)
AMO_STANDARD_DEF_GEN(long, long)
AMO_STANDARD_DEF_GEN(long long, longlong)
AMO_STANDARD_DEF_GEN(unsigned int, uint)
AMO_STANDARD_DEF_GEN(unsigned long, ulong)
AMO_STANDARD_DEF_GEN(unsigned long long, ulonglong)
+62
Просмотреть файл
@@ -0,0 +1,62 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _AMO_STANDARD_TESTER_HPP_
#define _AMO_STANDARD_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T>
class AMOStandardTester : public Tester {
public:
explicit AMOStandardTester(TesterArguments args);
virtual ~AMOStandardTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
void verifyDestValues();
void verifyReturnValues();
int destIndex(int l, int elem_idx) const;
int numElems() const;
std::pair<T*, int> retChunk(int l, int elem_idx) const;
T* dest{nullptr}; // symmetric target buffer [loop][elem]
T* ret_val{nullptr}; // device returns [loop][thread]
size_t n_in{0}; // num_wgs * wg_size
size_t n_out{0}; // elements per loop: PerBlock->num_wgs, PerGrid->1
size_t n_loops{0}; // loop + skip
};
#endif
+151
Просмотреть файл
@@ -0,0 +1,151 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "barrier_all_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
BarrierAllOnStreamTester::BarrierAllOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_my_pe();
n_pes = rocshmem_n_pes();
char *value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_NUM_STREAMS"))) {
num_streams = atoi(value);
} else {
// Default to 1 stream
num_streams = 1;
}
// Check if we should test with nullptr (default stream)
use_default_stream = false;
if ((value = getenv("ROCSHMEM_TEST_USE_DEFAULT_STREAM"))) {
use_default_stream = (atoi(value) != 0);
if (use_default_stream) {
num_streams = 1; // Only test with one nullptr stream
}
}
streams.resize(num_streams);
start_events_timed.resize(num_streams);
stop_events_timed.resize(num_streams);
for (int i = 0; i < num_streams; i++) {
if (use_default_stream) {
streams[i] = nullptr; // Use default stream (0)
} else {
CHECK_HIP(hipStreamCreate(&streams[i]));
}
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
BarrierAllOnStreamTester::~BarrierAllOnStreamTester() {
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
// Don't destroy default stream (nullptr)
if (!use_default_stream) {
CHECK_HIP(hipStreamDestroy(streams[i]));
}
}
}
void BarrierAllOnStreamTester::preLaunchKernel() {
// No specific setup needed for barrier
}
void BarrierAllOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each stream from HIP events
for (int stream_id = 0; stream_id < num_streams && stream_id < num_timers;
stream_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms,
start_events_timed[stream_id],
stop_events_timed[stream_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles =
static_cast<long long int>(elapsed_time_ms *
static_cast<float>(wall_clk_rate));
start_time[stream_id] = 0;
end_time[stream_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_streams
for (int i = num_streams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
}
void BarrierAllOnStreamTester::resetBuffers(size_t size) {}
void BarrierAllOnStreamTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
rocshmem_barrier_all_on_stream(streams[stream_id]);
}
}
for (int i = 0; i < loop; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// Record start event for this stream on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[stream_id],
streams[stream_id]));
}
rocshmem_barrier_all_on_stream(streams[stream_id]);
// Record stop event for this stream on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[stream_id],
streams[stream_id]));
}
}
}
num_msgs = (loop + args.skip) * num_streams;
num_timed_msgs = loop * num_streams;
}
void BarrierAllOnStreamTester::verifyResults(size_t size) {}
+67
Просмотреть файл
@@ -0,0 +1,67 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _BARRIER_ALL_ON_STREAM_TESTER_HPP_
#define _BARRIER_ALL_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class BarrierAllOnStreamTester : public Tester {
public:
explicit BarrierAllOnStreamTester(TesterArguments args);
virtual ~BarrierAllOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
int my_pe;
int n_pes;
int num_streams = 1;
bool use_default_stream = false;
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "barrier_all_on_stream_tester.cpp"
#endif
+108
Просмотреть файл
@@ -0,0 +1,108 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "barrier_all_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void BarrierAllTest(int loop, int skip, long long int *start_time,
long long int *end_time, TestType type,
int wf_size) {
__shared__ rocshmem_ctx_t ctx;
int t_id = get_flat_block_id();
int wg_id = get_flat_grid_id();
int wf_id = t_id / wf_size;
for (int i = 0; i < loop + skip; i++) {
if (hipThreadIdx_x == 0 && i == skip) {
start_time[wg_id] = wall_clock64();
}
if (is_block_zero_in_grid()) {
switch (type) {
case BarrierAllTestType:
if(t_id == 0) {
/**
* The function `rocshmem_barrier_all` should be called from only
* one thread within the grid to avoid undefined behavior.
*/
rocshmem_barrier_all();
}
break;
case WAVEBarrierAllTestType:
if(wf_id == 0) {
/**
* The function `rocshmem_barrier_all_wave` should be called from only
* one wavefront within the grid to avoid undefined behavior.
*/
rocshmem_barrier_all_wave();
}
break;
case WGBarrierAllTestType:
/**
* The function `rocshmem_barrier_all_wg` should be called from only
* one workgroup within the grid to avoid undefined behavior.
*/
rocshmem_barrier_all_wg();
break;
default:
break;
}
}
__syncthreads();
}
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
BarrierAllTester::BarrierAllTester(TesterArguments args) : Tester(args) {}
BarrierAllTester::~BarrierAllTester() {}
void BarrierAllTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(BarrierAllTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, _type, wf_size);
num_msgs = (loop + args.skip);
num_timed_msgs = loop;
}
void BarrierAllTester::resetBuffers(size_t size) {}
void BarrierAllTester::verifyResults(size_t size) {}
+52
Просмотреть файл
@@ -0,0 +1,52 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _BARRIER_ALL_TESTER_HPP_
#define _BARRIER_ALL_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void BarrierAllTest(TestType type);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class BarrierAllTester : public Tester {
public:
explicit BarrierAllTester(TesterArguments args);
virtual ~BarrierAllTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
};
#endif
+194
Просмотреть файл
@@ -0,0 +1,194 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "default_ctx_primitive_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void DefaultCTXPrimitiveTest(int loop, int skip,
long long int *start_time,
long long int *end_time, char *source,
char *dest, size_t size, TestType type,
ShmemContextType ctx_type, int wf_size) {
int wg_id = get_flat_grid_id();
int t_id = get_flat_block_id();
int wf_id = t_id / wf_size;
/**
* Shared array to capture the start time for each wavefront
* Max threads per block = 1024, wavefront size = 64 or 32 depending
* on the GPUs. Using 32 since its safer for the dimensioning of the array,
* the last 16 elements will not be used on GPUs with a wf size of 64.
* Maximum array size required = 1024/32 = 32
*/
__shared__ long long int wf_start_time[32];
/**
* Calculate start index for each thread within the grid
*/
size_t offset = size * get_flat_id();
source += offset;
dest += offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
// Ensures all RMA calls from the skip loops are completed
if(is_thread_zero_in_block()) {
rocshmem_quiet();
}
__syncthreads();
// Capture the start time of each wavefront to identify the earliest one
wf_start_time[wf_id] = wall_clock64();
}
switch (type) {
case DefaultCTXGetTestType:
rocshmem_getmem(dest, source, size, 1);
break;
case DefaultCTXGetNBITestType:
rocshmem_getmem_nbi(dest, source, size, 1);
break;
case DefaultCTXPutTestType:
rocshmem_putmem(dest, source, size, 1);
break;
case DefaultCTXPutNBITestType:
rocshmem_putmem_nbi(dest, source, size, 1);
break;
case DefaultCTXPTestType:
for (int s = 0; s < size; s++) {
char val = source[s];
rocshmem_char_p(&dest[s], val, 1);
}
break;
case DefaultCTXGTestType:
for (int s = 0; s < size; s++) {
char ret = rocshmem_char_g(&source[s], 1);
dest[s] = ret;
}
break;
default:
break;
}
}
__syncthreads();
if(is_thread_zero_in_block()) {
rocshmem_quiet();
}
/**
* End time of the last wavefront is recorded by overwriting
* the value previously set by earlier wavefronts.
*/
end_time[wg_id] = wall_clock64();
// Find the earliest start time
int num_wfs = (get_flat_block_size() - 1 ) / wf_size + 1;
for (int i = num_wfs / 2; i > 0; i >>= 1 ) {
if(t_id < i) {
wf_start_time[t_id] = min(wf_start_time[t_id], wf_start_time[t_id + i]);
}
}
__syncthreads();
if (t_id == 0) {
start_time[wg_id] = wf_start_time[0];
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
DefaultCTXPrimitiveTester::DefaultCTXPrimitiveTester(TesterArguments args)
: Tester(args) {
size_t buff_size = args.max_msg_size * args.wg_size * args.num_wgs;
source = (char *)rocshmem_malloc(buff_size);
dest = (char *)rocshmem_malloc(buff_size);
if (source == nullptr || dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source << ", dest: " << dest << std::endl;
if (source) {
rocshmem_free(source);
}
if (dest) {
rocshmem_free(dest);
}
rocshmem_global_exit(1);
}
for(size_t i = 0; i < buff_size; i++) {
source[i] = static_cast<char>('a' + i % 26);
}
}
DefaultCTXPrimitiveTester::~DefaultCTXPrimitiveTester() {
rocshmem_free(source);
rocshmem_free(dest);
}
void DefaultCTXPrimitiveTester::resetBuffers(size_t size) {
size_t buff_size = size * args.wg_size * args.num_wgs;
memset(dest, '1', buff_size);
}
void DefaultCTXPrimitiveTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(DefaultCTXPrimitiveTest, gridSize, blockSize,
shared_bytes, stream, loop, args.skip, start_time,
end_time, source, dest, size, _type, _shmem_context,
wf_size);
num_msgs = (loop + args.skip) * gridSize.x * blockSize.x;
num_timed_msgs = loop * gridSize.x * blockSize.x;
}
void DefaultCTXPrimitiveTester::verifyResults(size_t size) {
int check_id =
(_type == DefaultCTXGetTestType ||
_type == DefaultCTXGetNBITestType || _type == DefaultCTXGTestType)
? 0
: 1;
if (args.myid == check_id) {
size_t buff_size = size * args.wg_size * args.num_wgs;
for (size_t i = 0; i < buff_size; i++) {
if (dest[i] != source[i]) {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected "
<< source[i] << std::endl;
exit(-1);
}
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _DEFAULT_CTX_PRIMITIVE_TESTER_HPP_
#define _DEFAULT_CTX_PRIMITIVE_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class DefaultCTXPrimitiveTester : public Tester {
public:
explicit DefaultCTXPrimitiveTester(TesterArguments args);
virtual ~DefaultCTXPrimitiveTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *source = nullptr;
char *dest = nullptr;
};
#endif
+61
Просмотреть файл
@@ -0,0 +1,61 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "empty_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void EmptyTest(int loop, int skip, long long int *start_time,
long long int *end_time, int size, TestType type,
ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
rocshmem_wg_ctx_create(ctx_type, &ctx);
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
EmptyTester::EmptyTester(TesterArguments args) : Tester(args) {}
EmptyTester::~EmptyTester() {}
void EmptyTester::resetBuffers(size_t size) {}
void EmptyTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(EmptyTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, size, _type,
_shmem_context);
}
void EmptyTester::verifyResults(size_t size) {}
+47
Просмотреть файл
@@ -0,0 +1,47 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef ROCSHMEM_CLIENTS_FUNCTIONAL_TESTS_EMPTY_TESTER_HPP
#define ROCSHMEM_CLIENTS_FUNCTIONAL_TESTS_EMPTY_TESTER_HPP
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class EmptyTester : public Tester {
public:
explicit EmptyTester(TesterArguments args);
virtual ~EmptyTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
};
#endif // ROCSHMEM_CLIENTS_FUNCTIONAL_TESTS_EMPTY_TESTER_HPP
+217
Просмотреть файл
@@ -0,0 +1,217 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "flood_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void FloodTest(int loop, int skip, long long int *start_time,
long long int *end_time, uint64_t *r_buf, uint64_t *s_buf,
TestType type, ShmemContextType ctx_type, int wf_size) {
__shared__ rocshmem_ctx_t ctx;
/**
* Shared array to capture the start time for each wavefront
* Max threads per block = 1024, wavefront size = 64 or 32 depending
* on the GPUs. Using 32 since its safer for the dimensioning of the array,
* the last 16 elements will not be used on GPUs with a wf size of 64.
* Maximum array size required = 1024/32 = 32
*/
__shared__ long long int wf_start_time[32];
rocshmem_wg_ctx_create(ctx_type, &ctx);
int num_pe {rocshmem_ctx_n_pes(ctx)};
int num_wg {get_grid_num_blocks()};
int num_th {get_flat_block_size()};
int my_pe {rocshmem_ctx_my_pe(ctx)};
int wg_id {get_flat_grid_id()};
int t_id {get_flat_block_id()};
int wf_id {t_id / wf_size};
auto t_offset {wg_id * num_th + t_id};
auto tgt_offset {my_pe * num_wg * num_th + t_offset};
auto dst_offset {0};
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
// Capture the start time of each wavefront to identify the earliest one
wf_start_time[wf_id] = wall_clock64();
}
for (int j{0}; j < num_pe; j++) {
// shuffle ordering so that threads in the wave put to a
// different pe 'simultaneously'
auto pe = (t_id + j) % num_pe;
switch (type) {
case FloodPutTestType:
rocshmem_ctx_putmem(ctx, &r_buf[tgt_offset], &s_buf[t_offset], sizeof(uint64_t), pe);
break;
case FloodPutNBITestType:
rocshmem_ctx_putmem_nbi(ctx, &r_buf[tgt_offset], &s_buf[t_offset], sizeof(uint64_t), pe);
break;
case FloodPTestType:
rocshmem_ctx_ulong_p(ctx, &r_buf[tgt_offset], s_buf[t_offset], pe);
break;
case FloodGetTestType:
dst_offset = pe * num_wg * num_th + t_offset;
rocshmem_ctx_getmem(ctx, &r_buf[dst_offset], &s_buf[t_offset], sizeof(uint64_t), pe);
break;
case FloodGetNBITestType:
dst_offset = pe * num_wg * num_th + t_offset;
rocshmem_ctx_getmem_nbi(ctx, &r_buf[dst_offset], &s_buf[t_offset], sizeof(uint64_t), pe);
break;
case FloodGTestType:
dst_offset = pe * num_wg * num_th + t_offset;
r_buf[dst_offset] = rocshmem_ctx_ulong_g(ctx, &s_buf[t_offset], pe);
break;
default:
break;
}
__syncthreads();
if (is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
}
}
__syncthreads();
if (is_thread_zero_in_wave()) {
end_time[wg_id] = wall_clock64();
}
// Find the earliest start time
int num_wfs = (get_flat_block_size() - 1 ) / wf_size + 1;
for (int i = num_wfs / 2; i > 0; i >>= 1 ) {
if(t_id < i) {
wf_start_time[t_id] = min(wf_start_time[t_id], wf_start_time[t_id + i]);
}
}
__syncthreads();
if (t_id == 0) {
start_time[wg_id] = wf_start_time[0];
}
rocshmem_wg_ctx_destroy(&ctx);
}
static __global__ void verify_results_kernel(uint64_t *dest, size_t buf_size,
bool *verification_error) {
int num_pe {rocshmem_n_pes()};
int num_wg {get_grid_num_blocks()};
int num_th {get_flat_block_size()};
int my_pe {rocshmem_my_pe()};
int wg_id {get_flat_grid_id()};
int t_id {get_flat_block_id()};
auto t_offset {wg_id * num_th + t_id};
for (int pe{0}; pe < num_pe; pe++) {
auto dst_offset {pe * num_wg * num_th + t_offset};
auto value = dest[dst_offset];
auto v_th = value & 0x0fff;
auto v_wg = (value>>12) & 0xffff'ffff;
auto v_pe = (value>>44);
if (v_th != t_id || v_wg != wg_id || v_pe != pe) {
*verification_error = true;
}
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
FloodTester::FloodTester(TesterArguments args) : Tester(args) {
int num_pes {rocshmem_n_pes()};
int my_pe {rocshmem_my_pe()};
s_buf = (uint64_t*)rocshmem_malloc(sizeof(uint64_t) * args.num_wgs * args.wg_size);
for(int wg = 0; wg < args.num_wgs; wg++) for(int th = 0; th < args.wg_size; th++) {
s_buf[wg * args.wg_size + th] = (((uint64_t)my_pe)<<44) + (wg<<12) + th; // set value for verification
}
r_buf = (uint64_t*)rocshmem_malloc(sizeof(uint64_t) * args.num_wgs * args.wg_size * num_pes);
}
FloodTester::~FloodTester() {
rocshmem_free(s_buf);
rocshmem_free(r_buf);
}
void FloodTester::resetBuffers(size_t size) {
int num_pes {rocshmem_n_pes()};
memset(r_buf, 0, sizeof(uint64_t) * args.num_wgs * args.wg_size * num_pes);
}
void FloodTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
int num_pes {rocshmem_n_pes()};
hipLaunchKernelGGL(FloodTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, r_buf, s_buf,
_type, _shmem_context, wf_size);
num_msgs = (loop + args.skip) * gridSize.x * blockSize.x * num_pes;
num_timed_msgs = loop * gridSize.x * blockSize.x * num_pes;
}
void FloodTester::verifyResults(size_t size) {
int num_pes {rocshmem_n_pes()};
int my_pe {rocshmem_my_pe()};
if (num_pes > 1<<20 || args.num_wgs > 1<<31 || args.wg_size > 1<<12) {
// can't check
return;
}
assert(size == sizeof(uint64_t));
hipLaunchKernelGGL(verify_results_kernel, args.num_wgs, args.wg_size, 0, stream,
r_buf, sizeof(uint64_t), verification_error);
CHECK_HIP(hipStreamSynchronize(stream));
if (*verification_error) {
for(auto pe = 0; pe < num_pes; pe++)
for(auto wg = 0; wg < args.num_wgs; wg++)
for(auto th = 0; th < args.wg_size; th++) {
auto t_offset {wg * args.wg_size + th};
auto dst_offset {pe * args.num_wgs * args.wg_size + t_offset};
auto value = r_buf[dst_offset];
auto v_th = value & 0x0fff;
auto v_wg = (value>>12) & 0xffff'ffff;
auto v_pe = (value>>44);
if (v_th != th || v_wg != wg || v_pe != pe) {
std::cerr << "Data validation error at idx " << dst_offset << std::endl;
std::cerr << " Got " << v_pe << ":" << v_wg << ":" << v_th
<< ", Expected " << pe << ":" << wg << ":" << th << std::endl;
*verification_error = false;
}
}
}
}
+56
Просмотреть файл
@@ -0,0 +1,56 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _FLOOD_TESTER_HPP_
#define _FLOOD_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void FloodTest(int loop, int skip, long long int *start_time,
long long int *end_time, uint64_t *r_buf);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class FloodTester : public Tester {
public:
explicit FloodTester(TesterArguments args);
virtual ~FloodTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
uint64_t *r_buf;
uint64_t *s_buf;
};
#endif
+205
Просмотреть файл
@@ -0,0 +1,205 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "getmem_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
GetmemOnStreamTester::GetmemOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_my_pe();
n_pes = rocshmem_n_pes();
char *value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_NUM_STREAMS"))) {
num_streams = atoi(value);
} else {
// Default to 1 stream
num_streams = 1;
}
// Set target PE to get from (default: next PE in ring)
pe_target = (my_pe + 1) % n_pes;
if ((value = getenv("ROCSHMEM_TEST_GETMEM_TARGET"))) {
pe_target = atoi(value);
if (pe_target < 0 || pe_target >= n_pes) {
std::cerr << "Invalid ROCSHMEM_TEST_GETMEM_TARGET value. Using next PE."
<< std::endl;
pe_target = (my_pe + 1) % n_pes;
}
}
int num_bytes_stream = args.max_msg_size;
int total_bytes = num_bytes_stream * num_streams;
buf_size = total_bytes;
source_buf = static_cast<char *>(rocshmem_malloc(buf_size));
dest_buf = static_cast<char *>(rocshmem_malloc(buf_size));
if (source_buf == nullptr || dest_buf == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source_buf << ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
streams.resize(num_streams);
start_events_timed.resize(num_streams);
stop_events_timed.resize(num_streams);
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamCreate(&streams[i]));
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
GetmemOnStreamTester::~GetmemOnStreamTester() {
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
CHECK_HIP(hipStreamDestroy(streams[i]));
}
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
}
void GetmemOnStreamTester::preLaunchKernel() {
bw_factor = 1; // Point-to-point operation
}
void GetmemOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each stream from HIP events
for (int stream_id = 0; stream_id < num_streams && stream_id < num_timers;
stream_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms,
start_events_timed[stream_id],
stop_events_timed[stream_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles =
static_cast<long long int>(elapsed_time_ms *
static_cast<float>(wall_clk_rate));
start_time[stream_id] = 0;
end_time[stream_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_streams
for (int i = num_streams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
}
void GetmemOnStreamTester::resetBuffers(size_t size) {
// Initialize source buffer on all PEs
// Each stream has its own portion
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Each PE fills its source buffer with a unique value
int value = (my_pe + 1) * 100 + stream_id;
std::memset(source_buf + idx, value, size);
}
// Clear destination buffer
std::memset(dest_buf, 0, buf_size);
}
void GetmemOnStreamTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
char *stream_dest = dest_buf + stream_id * size;
char *stream_source = source_buf + stream_id * size;
rocshmem_getmem_on_stream(stream_dest, stream_source, size, pe_target,
streams[stream_id]);
}
}
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
for (int i = 0; i < loop; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// Record start event for this stream on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[stream_id],
streams[stream_id]));
}
char *stream_dest = dest_buf + stream_id * size;
char *stream_source = source_buf + stream_id * size;
rocshmem_getmem_on_stream(stream_dest, stream_source, size, pe_target,
streams[stream_id]);
// Record stop event for this stream on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[stream_id],
streams[stream_id]));
}
}
}
num_msgs = (loop + args.skip) * num_streams;
num_timed_msgs = loop * num_streams;
}
void GetmemOnStreamTester::verifyResults(size_t size) {
// Verify correctness: after getmem, local dest buffer should have
// the data from target PE's source buffer
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Expected value is from pe_target
int expected_value = (pe_target + 1) * 100 + stream_id;
for (size_t k = 0; k < size; k++) {
if (static_cast<unsigned char>(dest_buf[idx + k]) !=
static_cast<unsigned char>(expected_value)) {
std::cerr << "PE " << my_pe << ": Verification failed for stream "
<< stream_id << " at byte " << k << std::endl;
std::cerr << "Expected value: " << expected_value
<< ", Got: " << static_cast<int>(dest_buf[idx + k])
<< std::endl;
rocshmem_global_exit(1);
}
}
}
}
+70
Просмотреть файл
@@ -0,0 +1,70 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _GETMEM_ON_STREAM_TESTER_HPP_
#define _GETMEM_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class GetmemOnStreamTester : public Tester {
public:
explicit GetmemOnStreamTester(TesterArguments args);
virtual ~GetmemOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
char *source_buf;
char *dest_buf;
int my_pe;
int n_pes;
size_t buf_size;
int num_streams = 1;
int pe_target; // Target PE to get from
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "getmem_on_stream_tester.cpp"
#endif
+95
Просмотреть файл
@@ -0,0 +1,95 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "ping_all_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PingAllTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *r_buf,
ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
int pe = rocshmem_ctx_my_pe(ctx);
int num_pe = rocshmem_ctx_n_pes(ctx);
int status[1024];
for (int j{0}; j < num_pe; j++) {
status[j] = 0;
}
if (is_thread_zero_in_block()) {
auto blk_pe_off {wg_id * num_pe};
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
start_time[wg_id] = wall_clock64();
}
for (int j{0}; j < num_pe; j++) {
rocshmem_ctx_int_p(ctx, &r_buf[blk_pe_off + pe], 1, j);
}
rocshmem_int_wait_until_all(&r_buf[blk_pe_off], num_pe, status, ROCSHMEM_CMP_EQ, 1);
}
end_time[wg_id] = wall_clock64();
rocshmem_ctx_quiet(ctx);
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PingAllTester::PingAllTester(TesterArguments args) : Tester(args) {
int num_pes {rocshmem_n_pes()};
r_buf = (int *)rocshmem_malloc(sizeof(int) * args.num_wgs * num_pes);
}
PingAllTester::~PingAllTester() { rocshmem_free(r_buf); }
void PingAllTester::resetBuffers(size_t size) {
int num_pes {rocshmem_n_pes()};
memset(r_buf, 0, sizeof(int) * args.num_wgs * num_pes);
}
void PingAllTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(PingAllTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, r_buf,
_shmem_context);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop;
}
void PingAllTester::verifyResults(size_t size) {}
+55
Просмотреть файл
@@ -0,0 +1,55 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PING_ALL_TESTER_HPP_
#define _PING_ALL_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PingAllTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *r_buf);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PingAllTester : public Tester {
public:
explicit PingAllTester(TesterArguments args);
virtual ~PingAllTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
int *r_buf;
};
#endif
+94
Просмотреть файл
@@ -0,0 +1,94 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "ping_pong_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PingPongTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *r_buf,
ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
int pe = rocshmem_ctx_my_pe(ctx);
if (is_thread_zero_in_block()) {
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
start_time[wg_id] = wall_clock64();
}
if (pe == 0) {
rocshmem_ctx_int_p(ctx, &r_buf[hipBlockIdx_x], i + 1, 1);
rocshmem_int_wait_until(&r_buf[hipBlockIdx_x], ROCSHMEM_CMP_EQ,
i + 1);
} else {
rocshmem_int_wait_until(&r_buf[hipBlockIdx_x], ROCSHMEM_CMP_EQ,
i + 1);
rocshmem_ctx_int_p(ctx, &r_buf[hipBlockIdx_x], i + 1, 0);
}
}
end_time[wg_id] = wall_clock64();
rocshmem_ctx_quiet(ctx);
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PingPongTester::PingPongTester(TesterArguments args) : Tester(args) {
r_buf = (int *)rocshmem_malloc(sizeof(int) * args.num_wgs);
}
PingPongTester::~PingPongTester() { rocshmem_free(r_buf); }
void PingPongTester::resetBuffers(size_t size) {
memset(r_buf, 0, sizeof(int) * args.num_wgs);
}
void PingPongTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(PingPongTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, r_buf,
_shmem_context);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop;
}
void PingPongTester::verifyResults(size_t size) {}
+55
Просмотреть файл
@@ -0,0 +1,55 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PING_PONG_TESTER_HPP_
#define _PING_PONG_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PingPongTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *r_buf);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PingPongTester : public Tester {
public:
explicit PingPongTester(TesterArguments args);
virtual ~PingPongTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
int *r_buf;
};
#endif
+114
Просмотреть файл
@@ -0,0 +1,114 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "primitive_mr_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PrimitiveMRTest(int loop, long long int *start_time,
long long int *end_time, char *s_buf,
char *r_buf, size_t size,
ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
if (hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
for (int win_i = 0; win_i < 64 * loop; win_i++) {
for (int i = 0; i < 64; i++) {
rocshmem_ctx_putmem_nbi(ctx, r_buf, s_buf, size, 1);
}
rocshmem_ctx_quiet(ctx);
}
end_time[wg_id] = wall_clock64();
}
__syncthreads();
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PrimitiveMRTester::PrimitiveMRTester(TesterArguments args) : Tester(args) {
s_buf = (char *)rocshmem_malloc(args.max_msg_size * args.wg_size);
r_buf = (char *)rocshmem_malloc(args.max_msg_size * args.wg_size);
}
PrimitiveMRTester::~PrimitiveMRTester() {
rocshmem_free(s_buf);
rocshmem_free(r_buf);
}
void PrimitiveMRTester::resetBuffers(size_t size) {
memset(s_buf, '0', args.max_msg_size * args.wg_size);
memset(r_buf, '1', args.max_msg_size * args.wg_size);
}
void PrimitiveMRTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
/* Warmup */
hipLaunchKernelGGL(PrimitiveMRTest, gridSize, blockSize, shared_bytes, stream,
loop, start_time, end_time, s_buf, r_buf, size,
_shmem_context);
/* Benchmark */
hipLaunchKernelGGL(PrimitiveMRTest, gridSize, blockSize, shared_bytes, stream,
loop, start_time, end_time, s_buf, r_buf, size,
_shmem_context);
CHECK_HIP(hipDeviceSynchronize());
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * 64;
}
void PrimitiveMRTester::verifyResults(size_t size) {
int check_id =
(_type == GetTestType || _type == GetNBITestType || _type == GTestType)
? 0
: 1;
if (args.myid == check_id) {
for (uint64_t i = 0; i < size; i++) {
if (r_buf[i] != '0') {
fprintf(stderr, "Data validation error at idx %lu\n", i);
fprintf(stderr, "Got %c, Expected %c\n", r_buf[i], '0');
exit(-1);
}
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PRIMITIVE_MR_TESTER_HPP_
#define _PRIMITIVE_MR_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PrimitiveMRTester : public Tester {
public:
explicit PrimitiveMRTester(TesterArguments args);
virtual ~PrimitiveMRTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *s_buf = nullptr;
char *r_buf = nullptr;
};
#endif
+201
Просмотреть файл
@@ -0,0 +1,201 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "primitive_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PrimitiveTest(int loop, int skip, long long int *start_time,
long long int *end_time, char *source,
char *dest, size_t size, TestType type,
ShmemContextType ctx_type, int wf_size) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
int t_id = get_flat_block_id();
int wf_id = t_id / wf_size;
rocshmem_wg_ctx_create(ctx_type, &ctx);
/**
* Shared array to capture the start time for each wavefront
* Max threads per block = 1024, wavefront size = 64 or 32 depending
* on the GPUs. Using 32 since its safer for the dimensioning of the array,
* the last 16 elements will not be used on GPUs with a wf size of 64.
* Maximum array size required = 1024/32 = 32
*/
__shared__ long long int wf_start_time[32];
/**
* Calculate start index for each thread within the grid
*/
size_t offset = size * get_flat_id();
source += offset;
dest += offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
// Ensures all RMA calls from the skip loops are completed
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
__syncthreads();
// Capture the start time of each wavefront to identify the earliest one
wf_start_time[wf_id] = wall_clock64();
}
switch (type) {
case GetTestType:
rocshmem_ctx_getmem(ctx, dest, source, size, 1);
break;
case GetNBITestType:
rocshmem_ctx_getmem_nbi(ctx, dest, source, size, 1);
break;
case PutTestType:
rocshmem_ctx_putmem(ctx, dest, source, size, 1);
break;
case PutNBITestType:
rocshmem_ctx_putmem_nbi(ctx, dest, source, size, 1);
break;
case PTestType:
{
/* Assigment required to verify we can send non-symetric memory */
char val = *source;
rocshmem_ctx_char_p(ctx, dest, val, 1);
}
break;
case GTestType:
*dest = rocshmem_ctx_char_g(ctx, source, 1);
break;
default:
break;
}
}
__syncthreads();
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
/**
* End time of the last wavefront is recorded by overwriting
* the value previously set by earlier wavefronts.
*/
end_time[wg_id] = wall_clock64();
// Find the earliest start time
int num_wfs = (get_flat_block_size() - 1 ) / wf_size + 1;
for (int i = num_wfs / 2; i > 0; i >>= 1 ) {
if(t_id < i) {
wf_start_time[t_id] = min(wf_start_time[t_id], wf_start_time[t_id + i]);
}
}
__syncthreads();
if (t_id == 0) {
start_time[wg_id] = wf_start_time[0];
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PrimitiveTester::PrimitiveTester(TesterArguments args) : Tester(args) {
size_t buff_size = args.max_msg_size * args.wg_size * args.num_wgs;
source = (char *)rocshmem_malloc(buff_size);
dest = (char *)rocshmem_malloc(buff_size);
if (source == nullptr || dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source << ", dest: " << dest << std::endl;
if (source) {
rocshmem_free(source);
}
if (dest) {
rocshmem_free(dest);
}
rocshmem_global_exit(1);
}
for(size_t i = 0; i < buff_size; i++) {
source[i] = static_cast<char>('a' + i % 26);
}
}
PrimitiveTester::~PrimitiveTester() {
rocshmem_free(source);
rocshmem_free(dest);
}
void PrimitiveTester::resetBuffers(size_t size) {
size_t buff_size = size * args.wg_size * args.num_wgs;
memset(dest, '1', buff_size);
}
void PrimitiveTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(PrimitiveTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, source, dest,
size, _type, _shmem_context, wf_size);
num_msgs = (loop + args.skip) * gridSize.x * blockSize.x;
num_timed_msgs = loop * gridSize.x * blockSize.x;
}
void PrimitiveTester::verifyResults(size_t size) {
int check_id =
(_type == GetTestType || _type == GetNBITestType || _type == GTestType)
? 0
: 1;
if (args.myid == check_id) {
size_t buff_size = size * args.wg_size * args.num_wgs;
size_t verify_wg_size = std::min((size_t) 1024, buff_size);
size_t verify_num_wgs = buff_size / verify_wg_size;
hipLaunchKernelGGL(verify_results_kernel_char, verify_num_wgs, verify_wg_size, 0, stream,
source, dest, buff_size, verification_error);
CHECK_HIP(hipStreamSynchronize(stream));
if (*verification_error) {
for (uint64_t i = 0; i < buff_size; i++) {
if (dest[i] != source[i]) {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected "
<< source[i] << std::endl;
exit(-1);
}
}
*verification_error = false;
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PRIMITIVE_TESTER_HPP_
#define _PRIMITIVE_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PrimitiveTester : public Tester {
public:
explicit PrimitiveTester(TesterArguments args);
virtual ~PrimitiveTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *source = nullptr;
char *dest = nullptr;
};
#endif
+225
Просмотреть файл
@@ -0,0 +1,225 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "putmem_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PutmemOnStreamTester::PutmemOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_my_pe();
n_pes = rocshmem_n_pes();
char *value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_NUM_STREAMS"))) {
num_streams = atoi(value);
} else {
// Default to 1 stream
num_streams = 1;
}
// Check if we should test with nullptr (default stream)
use_default_stream = false;
if ((value = getenv("ROCSHMEM_TEST_USE_DEFAULT_STREAM"))) {
use_default_stream = (atoi(value) != 0);
if (use_default_stream) {
num_streams = 1; // Only test with one nullptr stream
}
}
// Set target PE to put to (default: next PE in ring)
pe_target = (my_pe + 1) % n_pes;
if ((value = getenv("ROCSHMEM_TEST_PUTMEM_TARGET"))) {
pe_target = atoi(value);
if (pe_target < 0 || pe_target >= n_pes) {
std::cerr << "Invalid ROCSHMEM_TEST_PUTMEM_TARGET value. Using next PE."
<< std::endl;
pe_target = (my_pe + 1) % n_pes;
}
}
int num_bytes_stream = args.max_msg_size;
int total_bytes = num_bytes_stream * num_streams;
buf_size = total_bytes;
source_buf = static_cast<char *>(rocshmem_malloc(buf_size));
dest_buf = static_cast<char *>(rocshmem_malloc(buf_size));
if (source_buf == nullptr || dest_buf == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source_buf << ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
streams.resize(num_streams);
start_events_timed.resize(num_streams);
stop_events_timed.resize(num_streams);
for (int i = 0; i < num_streams; i++) {
if (use_default_stream) {
streams[i] = nullptr; // Use default stream (0)
} else {
CHECK_HIP(hipStreamCreate(&streams[i]));
}
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
PutmemOnStreamTester::~PutmemOnStreamTester() {
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
// Don't destroy default stream (nullptr)
if (!use_default_stream) {
CHECK_HIP(hipStreamDestroy(streams[i]));
}
}
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
}
void PutmemOnStreamTester::preLaunchKernel() {
bw_factor = 1; // Point-to-point operation
}
void PutmemOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each stream from HIP events
for (int stream_id = 0; stream_id < num_streams && stream_id < num_timers;
stream_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms,
start_events_timed[stream_id],
stop_events_timed[stream_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles =
static_cast<long long int>(elapsed_time_ms *
static_cast<float>(wall_clk_rate));
start_time[stream_id] = 0;
end_time[stream_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_streams
for (int i = num_streams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
}
void PutmemOnStreamTester::resetBuffers(size_t size) {
// Initialize source buffer on all PEs
// Each stream has its own portion
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Each PE fills its source buffer with a unique value
int value = (my_pe + 1) * 100 + stream_id;
std::memset(source_buf + idx, value, size);
}
// Clear destination buffer (will receive data from other PEs)
std::memset(dest_buf, 0, buf_size);
}
void PutmemOnStreamTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
char *stream_source = source_buf + stream_id * size;
char *stream_dest = dest_buf + stream_id * size;
rocshmem_putmem_on_stream(stream_dest, stream_source, size, pe_target,
streams[stream_id]);
}
}
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
for (int i = 0; i < loop; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// Record start event for this stream on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[stream_id],
streams[stream_id]));
}
char *stream_source = source_buf + stream_id * size;
char *stream_dest = dest_buf + stream_id * size;
rocshmem_putmem_on_stream(stream_dest, stream_source, size, pe_target,
streams[stream_id]);
// Record stop event for this stream on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[stream_id],
streams[stream_id]));
}
}
}
num_msgs = (loop + args.skip) * num_streams;
num_timed_msgs = loop * num_streams;
}
void PutmemOnStreamTester::verifyResults(size_t size) {
// Verify correctness: after putmem, my dest buffer should have
// the data that was put from the PE that targets me
// We need to find which PE writes to me: pe_source where (pe_source + 1) % n_pes == my_pe
int pe_source = (my_pe - 1 + n_pes) % n_pes;
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Expected value is from pe_source
int expected_value = (pe_source + 1) * 100 + stream_id;
for (size_t k = 0; k < size; k++) {
if (static_cast<unsigned char>(dest_buf[idx + k]) !=
static_cast<unsigned char>(expected_value)) {
std::cerr << "PE " << my_pe << ": Verification failed for stream "
<< stream_id << " at byte " << k << std::endl;
std::cerr << "Expected value from PE " << pe_source << ": "
<< expected_value
<< ", Got: " << static_cast<int>(dest_buf[idx + k])
<< std::endl;
rocshmem_global_exit(1);
}
}
}
}
+71
Просмотреть файл
@@ -0,0 +1,71 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PUTMEM_ON_STREAM_TESTER_HPP_
#define _PUTMEM_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PutmemOnStreamTester : public Tester {
public:
explicit PutmemOnStreamTester(TesterArguments args);
virtual ~PutmemOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
char *source_buf;
char *dest_buf;
int my_pe;
int n_pes;
size_t buf_size;
int num_streams = 1;
bool use_default_stream = false;
int pe_target; // Target PE to put to
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "putmem_on_stream_tester.cpp"
#endif
+236
Просмотреть файл
@@ -0,0 +1,236 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "putmem_signal_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
PutmemSignalOnStreamTester::PutmemSignalOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_my_pe();
n_pes = rocshmem_n_pes();
char *value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_NUM_STREAMS"))) {
num_streams = atoi(value);
} else {
// Default to 1 stream
num_streams = 1;
}
// Set target PE to put to (default: next PE in ring)
pe_target = (my_pe + 1) % n_pes;
if ((value = getenv("ROCSHMEM_TEST_PUTMEM_TARGET"))) {
pe_target = atoi(value);
if (pe_target < 0 || pe_target >= n_pes) {
std::cerr << "Invalid ROCSHMEM_TEST_PUTMEM_TARGET value. Using next PE."
<< std::endl;
pe_target = (my_pe + 1) % n_pes;
}
}
int num_bytes_stream = args.max_msg_size;
int total_bytes = num_bytes_stream * num_streams;
buf_size = total_bytes;
source_buf = static_cast<char *>(rocshmem_malloc(buf_size));
dest_buf = static_cast<char *>(rocshmem_malloc(buf_size));
sig_addr = static_cast<uint64_t *>(rocshmem_malloc(num_streams * sizeof(uint64_t)));
if (source_buf == nullptr || dest_buf == nullptr || sig_addr == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source_buf << ", dest: " << dest_buf
<< ", sig_addr: " << sig_addr << std::endl;
rocshmem_global_exit(1);
}
streams.resize(num_streams);
start_events_timed.resize(num_streams);
stop_events_timed.resize(num_streams);
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamCreate(&streams[i]));
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
PutmemSignalOnStreamTester::~PutmemSignalOnStreamTester() {
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
CHECK_HIP(hipStreamDestroy(streams[i]));
}
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
rocshmem_free(sig_addr);
}
void PutmemSignalOnStreamTester::preLaunchKernel() {
bw_factor = 1; // Point-to-point operation
}
void PutmemSignalOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each stream from HIP events
for (int stream_id = 0; stream_id < num_streams && stream_id < num_timers;
stream_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms,
start_events_timed[stream_id],
stop_events_timed[stream_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles =
static_cast<long long int>(elapsed_time_ms *
static_cast<float>(wall_clk_rate));
start_time[stream_id] = 0;
end_time[stream_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_streams
for (int i = num_streams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
}
void PutmemSignalOnStreamTester::resetBuffers(size_t size) {
// Initialize source buffer on all PEs
// Each stream has its own portion
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Each PE fills its source buffer with a unique value
int value = (my_pe + 1) * 100 + stream_id;
std::memset(source_buf + idx, value, size);
}
// Clear destination buffer (will receive data from other PEs)
std::memset(dest_buf, 0, buf_size);
// Clear signal addresses
std::memset(sig_addr, 0, num_streams * sizeof(uint64_t));
}
void PutmemSignalOnStreamTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
uint64_t signal_value = 1;
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
char *stream_source = source_buf + stream_id * size;
char *stream_dest = dest_buf + stream_id * size;
rocshmem_putmem_signal_on_stream(stream_dest, stream_source, size,
&sig_addr[stream_id], signal_value,
sig_op, pe_target, streams[stream_id]);
}
}
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Reset signal addresses after warmup and synchronize across PEs
std::memset(sig_addr, 0, num_streams * sizeof(uint64_t));
rocshmem_barrier_all();
for (int i = 0; i < loop; i++) {
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// Record start event for this stream on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[stream_id],
streams[stream_id]));
}
char *stream_source = source_buf + stream_id * size;
char *stream_dest = dest_buf + stream_id * size;
rocshmem_putmem_signal_on_stream(stream_dest, stream_source, size,
&sig_addr[stream_id], signal_value,
sig_op, pe_target, streams[stream_id]);
// Record stop event for this stream on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[stream_id],
streams[stream_id]));
}
}
}
num_msgs = (loop + args.skip) * num_streams;
num_timed_msgs = loop * num_streams;
}
void PutmemSignalOnStreamTester::verifyResults(size_t size) {
// Synchronize to ensure all operations completed
rocshmem_barrier_all();
// Verify correctness: after putmem_signal, my dest buffer should have
// the data that was put from the PE that targets me
// We need to find which PE writes to me: pe_source where (pe_source + 1) % n_pes == my_pe
int pe_source = (my_pe - 1 + n_pes) % n_pes;
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
int idx = stream_id * size;
// Expected value is from pe_source
int expected_value = (pe_source + 1) * 100 + stream_id;
// Verify data
for (size_t k = 0; k < size; k++) {
if (static_cast<unsigned char>(dest_buf[idx + k]) !=
static_cast<unsigned char>(expected_value)) {
std::cerr << "PE " << my_pe << ": Data verification failed for stream "
<< stream_id << " at byte " << k << std::endl;
std::cerr << "Expected value from PE " << pe_source << ": "
<< expected_value
<< ", Got: " << static_cast<int>(dest_buf[idx + k])
<< std::endl;
rocshmem_global_exit(1);
}
}
// Verify signal
uint64_t expected_signal = 1;
if (sig_addr[stream_id] != expected_signal) {
std::cerr << "PE " << my_pe << ": Signal verification failed for stream "
<< stream_id << std::endl;
std::cerr << "Expected signal: " << expected_signal
<< ", Got: " << sig_addr[stream_id] << std::endl;
rocshmem_global_exit(1);
}
}
}
+72
Просмотреть файл
@@ -0,0 +1,72 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _PUTMEM_SIGNAL_ON_STREAM_TESTER_HPP_
#define _PUTMEM_SIGNAL_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class PutmemSignalOnStreamTester : public Tester {
public:
explicit PutmemSignalOnStreamTester(TesterArguments args);
virtual ~PutmemSignalOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
char *source_buf;
char *dest_buf;
uint64_t *sig_addr;
int my_pe;
int n_pes;
size_t buf_size;
int num_streams = 1;
int pe_target; // Target PE to put to
int sig_op = ROCSHMEM_SIGNAL_SET; // Signal operation
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "putmem_signal_on_stream_tester.cpp"
#endif
+235
Просмотреть файл
@@ -0,0 +1,235 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "random_access_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <cassert>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__device__ bool thread_passing(int num_bins, uint32_t *bin_threads,
uint32_t *off_bins, uint32_t *PE_bins,
size_t *offset, int *PE, int coal_coef,
size_t size) {
bool pass = false;
int wave_id = ((hipThreadIdx_x + hipBlockIdx_x * hipBlockDim_x) /
64); // get_global_wave_id();
int off = wave_id * num_bins;
for (int i = 0; i < num_bins; i++) {
if (((hipThreadIdx_x % 64) >= bin_threads[i + off]) &&
((hipThreadIdx_x % 64) < bin_threads[i + off] + coal_coef)) {
pass = true;
*offset = off_bins[i + off] +
(((hipThreadIdx_x % 64) - bin_threads[i + off]) * size);
*PE = PE_bins[i + off];
}
}
return pass;
}
__global__ void RandomAccessTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *s_buf,
int *r_buf, size_t size, OpType type,
int coal_coef, int num_bins, int num_waves,
uint32_t *threads_bins, uint32_t *off_bins,
uint32_t *PE_bins, ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
int pe = rocshmem_ctx_my_pe(ctx);
size_t offset;
int PE;
if (thread_passing(num_bins, threads_bins, off_bins, PE_bins, &offset, &PE,
coal_coef, (size / sizeof(int))) == true) {
s_buf = s_buf + offset;
r_buf = r_buf + offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
start_time[wg_id] = wall_clock64();
}
switch (type) {
case GetType:
rocshmem_ctx_getmem(ctx, r_buf, s_buf, size, PE);
break;
case PutType:
rocshmem_ctx_putmem(ctx, (char *)r_buf, (char *)s_buf, size, PE);
break;
default:
break;
}
}
rocshmem_ctx_quiet(ctx);
// atomicAdd((unsigned long long *)&timer[hipBlockIdx_x],
// rocshmem_timer() - start);
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST HELPER FUNCTIONS
****************************************************************************/
__host__ void init_bins(int num_bins, int num_waves, uint32_t *off_bins,
uint32_t *threads_bins, uint32_t *PE_bins, int size,
int coal_coef, int num_pes, int max_size) {
srand(time(NULL));
for (int j = 0; j < num_waves; j++) {
for (int i = 0; i < num_bins; i++) {
int current_bin = j * num_bins + i;
assert((64 % num_bins) == 0);
int quad_size = 64 / num_bins;
int allowed_index_range = quad_size - coal_coef - 1;
assert(allowed_index_range >= 0);
int rand_val = 0;
if (allowed_index_range) rand_val = rand() % allowed_index_range;
threads_bins[current_bin] = rand_val + i * quad_size;
quad_size = max_size / (num_bins + num_waves);
rand_val = rand() % (quad_size - (size * coal_coef - 1));
off_bins[current_bin] = rand_val + current_bin * quad_size;
PE_bins[current_bin] = rand() % num_pes;
}
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
RandomAccessTester::RandomAccessTester(TesterArguments args) : Tester(args) {
int max_size = args.max_msg_size;
int wg_size = args.wg_size;
_num_waves = (args.wg_size / 64) * args.num_wgs;
_num_bins = args.thread_access / args.coal_coef;
if ((args.wg_size / 64) > 1 || (64 % _num_bins) != 0) {
printf("Argument are incorrect\n");
assert((args.wg_size / 64) <= 1);
assert((64 % _num_bins) == 0);
abort();
}
s_buf = (int *)rocshmem_malloc(max_size * wg_size * space);
r_buf = (int *)rocshmem_malloc(max_size * wg_size * space);
h_buf = (int *)malloc(max_size * wg_size * space);
h_dev_buf = (int *)malloc(max_size * wg_size * space);
CHECK_HIP(hipMalloc((void **)&_threads_bins, sizeof(uint32_t) * _num_waves * _num_bins));
CHECK_HIP(hipMalloc((void **)&_off_bins, sizeof(uint32_t) * _num_waves * _num_bins));
CHECK_HIP(hipMalloc((void **)&_PE_bins, sizeof(uint32_t) * _num_waves * _num_bins));
memset(_threads_bins, 0, sizeof(uint32_t) * _num_waves * _num_bins);
memset(_off_bins, 0, sizeof(uint32_t) * _num_waves * _num_bins);
memset(_PE_bins, 0, sizeof(uint32_t) * _num_waves * _num_bins);
}
RandomAccessTester::~RandomAccessTester() {
rocshmem_free(s_buf);
rocshmem_free(r_buf);
free(h_buf);
free(h_dev_buf);
CHECK_HIP(hipFree(_threads_bins));
CHECK_HIP(hipFree(_off_bins));
CHECK_HIP(hipFree(_PE_bins));
}
void RandomAccessTester::resetBuffers(size_t size) {
for (size_t i = 0; i < args.max_msg_size / sizeof(int) * args.wg_size * space;
i++) {
s_buf[i] = 1;
r_buf[i] = 0;
h_buf[i] = 0;
}
}
void RandomAccessTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
int _thread_access = args.thread_access;
int _coal_coef = args.coal_coef;
assert(_coal_coef >= 1);
assert(gridSize.x == 1 && gridSize.y == 1 && gridSize.z == 1);
init_bins(_num_bins, _num_waves, _off_bins, _threads_bins, _PE_bins,
size / sizeof(int), _coal_coef, args.numprocs,
(space * size * args.wg_size) / sizeof(int));
if (args.myid == 0) {
hipLaunchKernelGGL(RandomAccessTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time, s_buf,
r_buf, size, (OpType)args.op_type, _coal_coef,
_num_bins, _num_waves, _threads_bins, _off_bins,
_PE_bins, _shmem_context);
}
num_msgs = (loop + args.skip) * _num_waves * _thread_access;
num_timed_msgs = loop * _num_waves * _thread_access;
}
void RandomAccessTester::verifyResults(size_t size) {
uint64_t offset;
for (int k = 0; k < _num_waves; k++) {
for (int i = 0; i < _num_bins; i++) {
int index = i + _num_bins * k;
if (args.op_type == PutType) {
if (_PE_bins[index] == static_cast<uint32_t>(args.myid)) {
offset = _off_bins[index];
for (uint64_t j = 0; j < ((size / sizeof(int)) * args.coal_coef); j++) {
h_buf[offset + j] = 1;
}
}
} else {
if (args.myid == 0) {
offset = _off_bins[index];
for (uint64_t j = 0; j < ((size / sizeof(int)) * args.coal_coef); j++) {
h_buf[offset + j] = 1;
}
}
}
}
}
CHECK_HIP(hipMemcpy(h_dev_buf, r_buf, space * args.wg_size * size,
hipMemcpyDeviceToHost));
CHECK_HIP(hipDeviceSynchronize());
for (uint64_t i = 0; i < (space * args.wg_size * size / sizeof(int)); i++) {
if (h_dev_buf[i] != h_buf[i]) {
printf("PE %d Got Data Validation: expecting %d got %d at %lu\n",
args.myid, h_buf[i], h_dev_buf[i], i);
exit(-1);
}
}
}
+68
Просмотреть файл
@@ -0,0 +1,68 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _RANDOM_ACCESS_TESTER_HPP_
#define _RANDOM_ACCESS_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void RandomAccessTest(int loop, int skip, long long int *start_time,
long long int *end_time, int *s_buf,
int *r_buf, int size, OpType type,
int coal_coef, int num_bins, int num_waves,
uint32_t *threads_bins, uint32_t *off_bins,
uint32_t *PE_bins);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class RandomAccessTester : public Tester {
public:
explicit RandomAccessTester(TesterArguments args);
virtual ~RandomAccessTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
int *r_buf;
int *s_buf;
int *h_buf;
int *h_dev_buf;
uint32_t *_threads_bins;
uint32_t *_off_bins;
uint32_t *_PE_bins;
int _num_waves;
int _num_bins;
static constexpr int space = 16 * 2;
};
#endif
+176
Просмотреть файл
@@ -0,0 +1,176 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "shmem_ptr_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void ShmemPtrTest(int loop, int skip, long long int *start_time,
long long int *end_time, char *dest, int wf_size,
ShmemContextType ctx_type, int *available) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
int t_id = get_flat_block_id();
int wf_id = t_id / wf_size;
rocshmem_wg_ctx_create(ctx_type, &ctx);
/**
* Shared array to capture the start time for each wavefront
* Max threads per block = 1024, wavefront size = 64 or 32 depending
* on the GPUs. Using 32 since its safer for the dimensioning of the array,
* the last 16 elements will not be used on GPUs with a wf size of 64.
* Maximum array size required = 1024/32 = 32
*/
__shared__ long long int wf_start_time[32];
/**
* Calculate start index for each thread within the grid
*/
dest += get_flat_id();
char *local_addr = dest;
void *remote_addr = rocshmem_ptr((void *)local_addr, 1);
if (remote_addr != NULL) {
*available = 1;
}
if(*available) {
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
// Ensures all RMA calls from the skip loops are completed
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
__syncthreads();
// Capture the start time of each wavefront to identify the earliest one
wf_start_time[wf_id] = wall_clock64();
}
((char *)remote_addr)[0] = '1';
}
}
__syncthreads();
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
/**
* End time of the last wavefront is recorded by overwriting
* the value previously set by earlier wavefronts.
*/
end_time[wg_id] = wall_clock64();
// Find the earliest start time
int num_wfs = (get_flat_block_size() - 1 ) / wf_size + 1;
for (int i = num_wfs / 2; i > 0; i >>= 1 ) {
if(t_id < i) {
wf_start_time[t_id] = min(wf_start_time[t_id], wf_start_time[t_id + i]);
}
}
// For data validation in remote PE
if( get_flat_id() == 0 ) {
int *store_avail = (int*)(dest + get_flat_grid_size());
*store_avail = *available;
rocshmem_ctx_int_put(ctx, store_avail, store_avail, 1, 1);
}
__syncthreads();
if (t_id == 0) {
start_time[wg_id] = wf_start_time[0];
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
ShmemPtrTester::ShmemPtrTester(TesterArguments args) : Tester(args) {
size_t buff_size = args.wg_size * args.num_wgs + sizeof(int);
CHECK_HIP(hipMalloc((void **)&_available, sizeof(int)));
dest = (char *)rocshmem_malloc(buff_size);
if (dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "dest: " << dest << std::endl;
rocshmem_global_exit(1);
}
}
ShmemPtrTester::~ShmemPtrTester() {
CHECK_HIP(hipFree(_available));
rocshmem_free(dest);
}
void ShmemPtrTester::resetBuffers(size_t size) {
size_t buff_size = args.wg_size * args.num_wgs + sizeof(int);
memset(dest, '0', buff_size);
memset(_available, 0, sizeof(int));
}
void ShmemPtrTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(ShmemPtrTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
dest, wf_size, _type, _available);
num_msgs = (loop + args.skip) * gridSize.x * blockSize.x;
num_timed_msgs = loop * gridSize.x * blockSize.x;
}
void ShmemPtrTester::verifyResults(size_t size) {
if (args.myid == 0) {
if (*_available == 0) {
_print_results = false;
std::cout << "rocshmem ptr not available\n" << std::endl;
}
}
else {
size_t buff_size = args.wg_size * args.num_wgs;
int *available = (int*)(dest + buff_size);
if(*available == 1) {
for (size_t i = 0; i < buff_size; i++) {
if (dest[i] != '1') {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected 1 " << std::endl;
exit(-1);
}
}
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _SHMEM_PTR_TESTER_HPP_
#define _SHMEM_PTR_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class ShmemPtrTester : public Tester {
public:
explicit ShmemPtrTester(TesterArguments args);
virtual ~ShmemPtrTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *dest = nullptr;
int *_available = nullptr;
};
#endif
+204
Просмотреть файл
@@ -0,0 +1,204 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
SignalWaitUntilOnStreamTester::SignalWaitUntilOnStreamTester(
TesterArguments args)
: Tester(args) {
my_pe = rocshmem_my_pe();
n_pes = rocshmem_n_pes();
char *value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_NUM_STREAMS"))) {
num_streams = atoi(value);
} else {
// Default to 1 stream
num_streams = 1;
}
// Set target PE (next PE in ring)
pe_target = (my_pe + 1) % n_pes;
// Allocate signal addresses on symmetric heap
sig_addr =
static_cast<uint64_t *>(rocshmem_malloc(num_streams * sizeof(uint64_t)));
source_buf =
static_cast<uint64_t *>(rocshmem_malloc(num_streams * sizeof(uint64_t)));
if (sig_addr == nullptr || source_buf == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "sig_addr: " << sig_addr << ", source_buf: " << source_buf
<< std::endl;
rocshmem_global_exit(1);
}
streams.resize(num_streams);
start_events_timed.resize(num_streams);
stop_events_timed.resize(num_streams);
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamCreate(&streams[i]));
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
SignalWaitUntilOnStreamTester::~SignalWaitUntilOnStreamTester() {
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
CHECK_HIP(hipStreamDestroy(streams[i]));
}
rocshmem_free(sig_addr);
rocshmem_free(source_buf);
}
void SignalWaitUntilOnStreamTester::preLaunchKernel() {
bw_factor = 1; // Point-to-point operation
}
void SignalWaitUntilOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_streams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each stream from HIP events
for (int stream_id = 0; stream_id < num_streams && stream_id < num_timers;
stream_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms,
start_events_timed[stream_id],
stop_events_timed[stream_id]));
// Convert milliseconds to GPU cycles
long long int elapsed_cycles =
static_cast<long long int>(elapsed_time_ms *
static_cast<float>(wall_clk_rate));
start_time[stream_id] = 0;
end_time[stream_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_streams
for (int i = num_streams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
}
void SignalWaitUntilOnStreamTester::resetBuffers(size_t size) {
// Clear signal addresses
std::memset(sig_addr, 0, num_streams * sizeof(uint64_t));
}
void SignalWaitUntilOnStreamTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
// Execute warmup + timed iterations
for (int i = 0; i < args.skip + loop; i++) {
// Increment signal value for each iteration
uint64_t signal_value = i + 1;
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// Record start event after warmup on first timed iteration for all streams
if (i == args.skip) {
CHECK_HIP(hipEventRecord(start_events_timed[stream_id],
streams[stream_id]));
}
// PE 0 starts the ring by signaling PE 1
if (my_pe == 0) {
rocshmem_putmem_signal_on_stream(&sig_addr[stream_id],
&source_buf[stream_id],
sizeof(uint64_t), &sig_addr[stream_id],
signal_value, sig_op, pe_target,
streams[stream_id]);
} else {
// All other PEs wait for signal from previous PE
rocshmem_signal_wait_until_on_stream(&sig_addr[stream_id],
ROCSHMEM_CMP_GE, signal_value,
streams[stream_id]);
// Forward the signal to next PE (unless we're the last PE)
if (my_pe != n_pes - 1) {
rocshmem_putmem_signal_on_stream(&sig_addr[stream_id],
&source_buf[stream_id],
sizeof(uint64_t), &sig_addr[stream_id],
signal_value, sig_op, pe_target,
streams[stream_id]);
}
}
// Record stop event on last timed iteration for all streams
if (i == args.skip + loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[stream_id],
streams[stream_id]));
}
}
// Wait for all streams to complete
for (int j = 0; j < num_streams; j++) {
CHECK_HIP(hipStreamSynchronize(streams[j]));
}
// Barrier to ensure all RMA operations completed across all PEs
rocshmem_barrier_all();
}
num_msgs = (loop + args.skip) * num_streams;
num_timed_msgs = loop * num_streams;
}
void SignalWaitUntilOnStreamTester::verifyResults(size_t size) {
// Synchronize to ensure all operations completed
rocshmem_barrier_all();
// Verify signal values
// All PEs except PE 0 should have received the final signal value
uint64_t expected_signal = args.skip + args.loop;
for (int stream_id = 0; stream_id < num_streams; stream_id++) {
// PE 0 doesn't receive signals (it initiates), so skip verification
if (my_pe == 0) {
continue;
}
// Verify signal
if (sig_addr[stream_id] != expected_signal) {
std::cerr << "PE " << my_pe << ": Signal verification failed for stream "
<< stream_id << std::endl;
std::cerr << "Expected signal: " << expected_signal
<< ", Got: " << sig_addr[stream_id] << std::endl;
rocshmem_global_exit(1);
}
}
}
+69
Просмотреть файл
@@ -0,0 +1,69 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _SIGNAL_WAIT_UNTIL_ON_STREAM_TESTER_HPP_
#define _SIGNAL_WAIT_UNTIL_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class SignalWaitUntilOnStreamTester : public Tester {
public:
explicit SignalWaitUntilOnStreamTester(TesterArguments args);
virtual ~SignalWaitUntilOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
uint64_t *sig_addr;
uint64_t *source_buf; // Source buffer in symmetric heap
int my_pe;
int n_pes;
int num_streams = 1;
int pe_target; // Target PE to signal next
int sig_op = ROCSHMEM_SIGNAL_SET; // Signal operation
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "signal_wait_until_on_stream_tester.cpp"
#endif
+239
Просмотреть файл
@@ -0,0 +1,239 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "signaling_operations_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void PutmemSignalTest(int loop, int skip, long long int *start_time,
long long int *end_time, char *s_buf,
char *r_buf, size_t size, uint64_t *sig_addr,
TestType type, ShmemContextType ctx_type,
int sig_op) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
uint64_t signal = 1;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
start_time[wg_id] = wall_clock64();
}
switch (type) {
case PutSignalTestType:
rocshmem_ctx_putmem_signal(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
case WGPutSignalTestType:
rocshmem_ctx_putmem_signal_wg(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
case WAVEPutSignalTestType:
rocshmem_ctx_putmem_signal_wave(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
case PutSignalNBITestType:
rocshmem_ctx_putmem_signal_nbi(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
case WGPutSignalNBITestType:
rocshmem_ctx_putmem_signal_nbi_wg(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
case WAVEPutSignalNBITestType:
rocshmem_ctx_putmem_signal_nbi_wave(ctx, r_buf, s_buf, size, sig_addr,
signal, sig_op, 1);
break;
default:
break;
}
}
rocshmem_ctx_quiet(ctx);
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
__global__ void SignalFetchTest(int loop, int skip, long long int *start_time,
long long int *end_time, uint64_t *sig_addr,
uint64_t *fetched_value, TestType type) {
int wg_id = get_flat_grid_id();
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
start_time[wg_id] = wall_clock64();
}
switch (type) {
case SignalFetchTestType:
*fetched_value = rocshmem_signal_fetch(sig_addr);
break;
case WGSignalFetchTestType:
*fetched_value = rocshmem_signal_fetch_wg(sig_addr);
break;
case WAVESignalFetchTestType:
*fetched_value = rocshmem_signal_fetch_wave(sig_addr);
break;
default:
break;
}
}
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
SignalingOperationsTester::SignalingOperationsTester(TesterArguments args)
: Tester(args) {
s_buf = (char *)rocshmem_malloc(args.max_msg_size * args.wg_size);
r_buf = (char *)rocshmem_malloc(args.max_msg_size * args.wg_size);
sig_addr = (uint64_t *)rocshmem_malloc(sizeof(uint64_t));
CHECK_HIP(hipMallocManaged(&fetched_value, sizeof(uint64_t), hipMemAttachHost));
}
SignalingOperationsTester::SignalingOperationsTester(TesterArguments args,
int signal_op)
: SignalingOperationsTester(args) {
sig_op = signal_op;
}
SignalingOperationsTester::~SignalingOperationsTester() {
rocshmem_free(s_buf);
rocshmem_free(r_buf);
rocshmem_free(sig_addr);
CHECK_HIP(hipFree(fetched_value));
}
void SignalingOperationsTester::resetBuffers(size_t size) {
memset(s_buf, '0', args.max_msg_size * args.wg_size);
memset(r_buf, '1', args.max_msg_size * args.wg_size);
*fetched_value = -1;
*sig_addr = args.myid + 123;
}
void SignalingOperationsTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
if ((_type == SignalFetchTestType) ||
(_type == WAVESignalFetchTestType) ||
(_type == WGSignalFetchTestType)) {
hipLaunchKernelGGL(SignalFetchTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, sig_addr, fetched_value, _type);
} else {
hipLaunchKernelGGL(PutmemSignalTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, s_buf, r_buf, size, sig_addr,
_type, _shmem_context, sig_op);
}
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop;
}
void SignalingOperationsTester::verifyResults(size_t size) {
if (_type == SignalFetchTestType ||
_type == WAVESignalFetchTestType ||
_type == WGSignalFetchTestType) {
if (0 == args.myid) {
uint64_t value = *fetched_value;
uint64_t expected_value = (args.myid + 123);
if (value != expected_value) {
fprintf(stderr, "Fetched Value %lu, Expected %lu\n", value, expected_value);
exit(-1);
}
return;
}
} else {
if (1 == args.myid) {
// Validate Data
for (uint64_t i = 0; i < size; i++) {
if (r_buf[i] != '0') {
fprintf(stderr, "Data validation error at idx %lu\n", i);
fprintf(stderr, "Got %c, Expected %c\n", r_buf[i], '0');
exit(-1);
}
}
// Validate Signal
if (ROCSHMEM_SIGNAL_SET == sig_op) {
uint64_t expected_value = 1;
uint64_t value = *sig_addr;
if (value != expected_value) {
fprintf(stderr, "ROCSHMEM_SIGNAL_SET Value %lu, Expected %lu\n", value, expected_value);
exit(-1);
}
} else if (ROCSHMEM_SIGNAL_ADD == sig_op) {
uint64_t value = *sig_addr;
uint64_t expected_value = (args.myid + 123); // Initial Value
switch (_type) {
case PutSignalTestType:
case PutSignalNBITestType:
expected_value += ((args.skip + args.loop) * args.wg_size * args.num_wgs);
break;
case WGPutSignalTestType:
case WGPutSignalNBITestType:
expected_value += ((args.skip + args.loop) * args.num_wgs);
break;
case WAVEPutSignalTestType:
case WAVEPutSignalNBITestType:
expected_value += ((args.skip + args.loop) * args.num_wgs * num_warps);
break;
default:
fprintf(stderr, "Invalid Test\n");
exit(-1);
}
if (value != expected_value) {
fprintf(stderr, "ROCSHMEM_SIGNAL_ADD Value %lu, Expected %lu\n", value, expected_value);
exit(-1);
}
}
}
}
}
+54
Просмотреть файл
@@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _SIGNALING_OPERATIONS_
#define _SIGNALING_OPERATIONS_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class SignalingOperationsTester : public Tester {
public:
explicit SignalingOperationsTester(TesterArguments args);
explicit SignalingOperationsTester(TesterArguments args, int signal_op);
virtual ~SignalingOperationsTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
int sig_op;
char *s_buf = nullptr;
char *r_buf = nullptr;
uint64_t *sig_addr;
uint64_t *fetched_value;
};
#endif
+108
Просмотреть файл
@@ -0,0 +1,108 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "sync_all_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void SyncAllTest(int loop, int skip, long long int *start_time,
long long int *end_time, TestType type,
int wf_size) {
__shared__ rocshmem_ctx_t ctx;
int t_id = get_flat_block_id();
int wg_id = get_flat_grid_id();
int wf_id = t_id / wf_size;
for (int i = 0; i < loop + skip; i++) {
if (hipThreadIdx_x == 0 && i == skip) {
start_time[wg_id] = wall_clock64();
}
if (is_block_zero_in_grid()) {
switch (type) {
case SyncAllTestType:
if(t_id == 0) {
/**
* The function `rocshmem_sync_all` should be called from only
* one thread within the grid to avoid undefined behavior.
*/
rocshmem_sync_all();
}
break;
case WAVESyncAllTestType:
if(wf_id == 0) {
/**
* The function `rocshmem_sync_all_wave` should be called from only
* one thread within the grid to avoid undefined behavior.
*/
rocshmem_sync_all_wave();
}
break;
case WGSyncAllTestType:
/**
* The function `rocshmem_sync_all_wg` should be called from only
* one thread within the grid to avoid undefined behavior.
*/
rocshmem_sync_all_wg();
break;
default:
break;
}
__syncthreads();
}
}
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
SyncAllTester::SyncAllTester(TesterArguments args) : Tester(args) {}
SyncAllTester::~SyncAllTester() {}
void SyncAllTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(SyncAllTest, gridSize, blockSize, shared_bytes, stream,
loop, args.skip, start_time, end_time, _type, wf_size);
num_msgs = (loop + args.skip);
num_timed_msgs = loop;
}
void SyncAllTester::resetBuffers(size_t size) {}
void SyncAllTester::verifyResults(size_t size) {}
+52
Просмотреть файл
@@ -0,0 +1,52 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _SYNC_ALL_TESTER_HPP_
#define _SYNC_ALL_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void SyncAllTest(TestType type);
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class SyncAllTester : public Tester {
public:
explicit SyncAllTester(TesterArguments args);
virtual ~SyncAllTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
};
#endif
+222
Просмотреть файл
@@ -0,0 +1,222 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
/* Declare the template with a generic implementation */
template <typename T>
__device__ void wg_team_alltoall(rocshmem_ctx_t ctx, rocshmem_team_t team,
T *dest, const T *source, int nelem) {
return;
}
/* Define templates to call rocSHMEM */
#define TEAM_ALLTOALL_DEF_GEN(T, TNAME) \
template <> \
__device__ void wg_team_alltoall<T>(rocshmem_ctx_t ctx, rocshmem_team_t team,\
T * dest, const T *source, int nelem) { \
rocshmem_ctx_##TNAME##_alltoall_wg(ctx, team, dest, source, nelem); \
}
TEAM_ALLTOALL_DEF_GEN(float, float)
TEAM_ALLTOALL_DEF_GEN(double, double)
TEAM_ALLTOALL_DEF_GEN(char, char)
// TEAM_ALLTOALL_DEF_GEN(long double, longdouble)
TEAM_ALLTOALL_DEF_GEN(signed char, schar)
TEAM_ALLTOALL_DEF_GEN(short, short)
TEAM_ALLTOALL_DEF_GEN(int, int)
TEAM_ALLTOALL_DEF_GEN(long, long)
TEAM_ALLTOALL_DEF_GEN(long long, longlong)
TEAM_ALLTOALL_DEF_GEN(unsigned char, uchar)
TEAM_ALLTOALL_DEF_GEN(unsigned short, ushort)
TEAM_ALLTOALL_DEF_GEN(unsigned int, uint)
TEAM_ALLTOALL_DEF_GEN(unsigned long, ulong)
TEAM_ALLTOALL_DEF_GEN(unsigned long long, ulonglong)
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
template <typename T1>
__global__ void TeamAlltoallTest(int loop, int skip, long long int *start_time,
long long int *end_time, T1 *source_buf,
T1 *dest_buf, int num_elems,
ShmemContextType ctx_type,
rocshmem_team_t *teams) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_team_create_ctx(teams[wg_id], ctx_type, &ctx);
int n_pes = rocshmem_ctx_n_pes(ctx);
source_buf += wg_id * n_pes * num_elems;
dest_buf += wg_id * n_pes * num_elems;
__syncthreads();
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
wg_team_alltoall<T1>(ctx, teams[wg_id],
dest_buf, // T* dest
source_buf, // const T* source
num_elems); // int nelement
}
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T1>
TeamAlltoallTester<T1>::TeamAlltoallTester(TesterArguments args)
: Tester(args){
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
// Number of elements per work group
int num_elems_wg = (args.max_msg_size / sizeof(T1)) * n_pes;
// Total number of elements in the GPU kernel
int total_elems = num_elems_wg * args.num_wgs;
int buff_size = total_elems * sizeof(T1);
source_buf = (T1 *)rocshmem_malloc(buff_size);
dest_buf = (T1 *)rocshmem_malloc(buff_size);
if (source_buf == nullptr || dest_buf == nullptr) {
std::cout << "Error allocating memory from symmetric heap" << std::endl;
std::cout << "source: " << source_buf
<< ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
char* value{nullptr};
if ((value = getenv("ROCSHMEM_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
}
CHECK_HIP(hipMalloc(&team_alltoall_world_dup,
sizeof(rocshmem_team_t) * num_teams));
}
template <typename T1>
TeamAlltoallTester<T1>::~TeamAlltoallTester() {
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
CHECK_HIP(hipFree(team_alltoall_world_dup));
}
template <typename T1>
void TeamAlltoallTester<T1>::preLaunchKernel() {
bw_factor = n_pes;
for (int team_i = 0; team_i < num_teams; team_i++) {
team_alltoall_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_alltoall_world_dup[team_i]);
if (team_alltoall_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
std::cout << "Team " << team_i << " is invalid!" << std::endl;
abort();
}
}
}
template <typename T1>
void TeamAlltoallTester<T1>::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
int num_elems = size / sizeof(T1);
hipLaunchKernelGGL(TeamAlltoallTest<T1>, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
source_buf, dest_buf, num_elems, _shmem_context,
team_alltoall_world_dup);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
template <typename T1>
void TeamAlltoallTester<T1>::postLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_alltoall_world_dup[team_i]);
}
}
template <typename T1>
void TeamAlltoallTester<T1>::resetBuffers(size_t size) {
int num_elems = size / sizeof(T1);
int buff_size = num_elems * sizeof(T1) * args.num_wgs * n_pes;
int idx = 0;
for(int wg_id = 0; wg_id < args.num_wgs; wg_id++) {
for(int pe = 0; pe < n_pes; pe++) {
for(int i = 0; i < num_elems; i++) {
idx = (wg_id * n_pes + pe) * num_elems + i;
if constexpr (std::is_same<T1, char>::value ||
std::is_same<T1, signed char>::value ||
std::is_same<T1, unsigned char>::value) {
source_buf[idx] = static_cast<T1>('a' + my_pe + pe + wg_id);
}
else if constexpr (std::is_floating_point<T1>::value) {
source_buf[idx] = static_cast<T1>(3.14 + my_pe + pe + wg_id);
}
else if constexpr (std::is_integral<T1>::value) {
source_buf[idx] = static_cast<T1>(my_pe + pe + wg_id);
}
}
}
}
memset(dest_buf, -1, buff_size);
}
template <typename T1>
void TeamAlltoallTester<T1>::verifyResults(size_t size) {
int num_elems = size / sizeof(T1);
int idx = 0;
for(int wg_id = 0; wg_id < args.num_wgs; wg_id++) {
for(int pe = 0; pe < n_pes; pe++) {
for(int i = 0; i < num_elems; i++) {
idx = (wg_id * n_pes + pe) * num_elems + i;
if (dest_buf[idx] != source_buf[idx]) {
std::cerr << "Data validation error at idx " << idx << std::endl;
std::cerr << "PE " << my_pe << " Got " << dest_buf[idx]
<< ", Expected " << source_buf[idx] << std::endl;
exit(-1);
}
}
}
}
}
+73
Просмотреть файл
@@ -0,0 +1,73 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_ALLTOALL_TESTER_HPP_
#define _TEAM_ALLTOALL_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
using namespace rocshmem;
/************* *****************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T1>
class TeamAlltoallTester : public Tester {
public:
explicit TeamAlltoallTester(TesterArguments args);
virtual ~TeamAlltoallTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
T1 *source_buf = nullptr;
T1 *dest_buf = nullptr;
private:
int my_pe = 0;
int n_pes = 0;
/**
* This constant should equal ROCSHMEM_MAX_NUM_TEAMS - 1.
* The default value for the maximum number of teams is 40.
*/
int num_teams = 39;
rocshmem_team_t *team_alltoall_world_dup;
};
#include "team_alltoall_tester.cpp"
#endif
+219
Просмотреть файл
@@ -0,0 +1,219 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "team_alltoallmem_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamAlltoallmemOnStreamTester::TeamAlltoallmemOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
char* value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
} else {
// Default to number of work groups
num_teams = args.num_wgs;
}
int num_bytes_wg = args.max_msg_size * n_pes;
int total_bytes = num_bytes_wg * num_teams;
buf_size = total_bytes;
source_buf = static_cast<char *>(rocshmem_malloc(buf_size));
dest_buf = static_cast<char *>(rocshmem_malloc(buf_size));
if (source_buf == nullptr || dest_buf == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source_buf << ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
team_world_dup.resize(num_teams);
streams.resize(num_teams);
start_events_timed.resize(num_teams);
stop_events_timed.resize(num_teams);
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamCreate(&streams[i]));
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
TeamAlltoallmemOnStreamTester::~TeamAlltoallmemOnStreamTester() {
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
CHECK_HIP(hipStreamDestroy(streams[i]));
}
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
}
void TeamAlltoallmemOnStreamTester::preLaunchKernel() {
bw_factor = n_pes;
for (int team_i = 0; team_i < num_teams; team_i++) {
team_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_world_dup[team_i]);
if (team_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
std::cerr << "Team " << team_i << " is invalid!" << std::endl;
abort();
}
}
}
void TeamAlltoallmemOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each work group from HIP events
for (int wg_id = 0; wg_id < num_teams && wg_id < num_timers; wg_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms, start_events_timed[wg_id],
stop_events_timed[wg_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles = static_cast<long long int>(
elapsed_time_ms * static_cast<float>(wall_clk_rate));
start_time[wg_id] = 0;
end_time[wg_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_teams
for (int i = num_teams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_world_dup[team_i]);
}
}
void TeamAlltoallmemOnStreamTester::resetBuffers(size_t size) {
// Initialize source buffer: each PE fills its portion with its PE number
// For alltoall, PE i sends block j to PE j
// Support multiple work groups (teams)
int idx = 0;
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
for (int pe = 0; pe < n_pes; pe++) {
// Each block in source buffer is filled with (my_pe * n_pes + pe)
// This makes it easy to verify correctness
int value = my_pe * n_pes + pe;
idx = (wg_id * n_pes + pe) * size;
std::memset(source_buf + idx, value, size);
}
}
// Clear destination buffer
std::memset(dest_buf, 0, buf_size);
}
void TeamAlltoallmemOnStreamTester::launchKernel(dim3 gridSize,
dim3 blockSize,
int loop,
size_t size) {
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
char *wg_source = source_buf + wg_id * n_pes * size;
char *wg_dest = dest_buf + wg_id * n_pes * size;
rocshmem_alltoallmem_on_stream(team_world_dup[wg_id], wg_dest,
wg_source, size, streams[wg_id]);
}
}
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
for (int i = 0; i < loop; i++) {
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
// Record start event for this work group on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[wg_id], streams[wg_id]));
}
char *wg_source = source_buf + wg_id * n_pes * size;
char *wg_dest = dest_buf + wg_id * n_pes * size;
rocshmem_alltoallmem_on_stream(team_world_dup[wg_id], wg_dest,
wg_source, size, streams[wg_id]);
// Record stop event for this work group on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[wg_id], streams[wg_id]));
}
}
}
num_msgs = (loop + args.skip) * num_teams;
num_timed_msgs = loop * num_teams;
}
void TeamAlltoallmemOnStreamTester::verifyResults(size_t size) {
// Verify correctness: after alltoall, PE i should receive from PE j
// the block that PE j sent to PE i
// PE j sends block i (containing value j * n_pes + i) to PE i
// Support multiple work groups (teams)
int idx = 0;
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
for (int j = 0; j < n_pes; j++) {
int expected_value = j * n_pes + my_pe;
idx = (wg_id * n_pes + j) * size;
for (size_t k = 0; k < size; k++) {
if (static_cast<unsigned char>(dest_buf[idx + k]) !=
static_cast<unsigned char>(expected_value)) {
std::cerr << "PE " << my_pe << ": Verification failed for WG "
<< wg_id << ", block from PE " << j << " at byte " << k
<< std::endl;
std::cerr << "Expected value: " << expected_value
<< ", Got: " << static_cast<int>(dest_buf[idx + k])
<< std::endl;
rocshmem_global_exit(1);
}
}
}
}
}
+70
Просмотреть файл
@@ -0,0 +1,70 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_ALLTOALLMEM_ON_STREAM_TESTER_HPP_
#define _TEAM_ALLTOALLMEM_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamAlltoallmemOnStreamTester : public Tester {
public:
explicit TeamAlltoallmemOnStreamTester(TesterArguments args);
virtual ~TeamAlltoallmemOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
char *source_buf;
char *dest_buf;
int my_pe;
int n_pes;
size_t buf_size;
int num_teams = 1;
std::vector<rocshmem_team_t> team_world_dup;
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "team_alltoallmem_on_stream_tester.cpp"
#endif
+127
Просмотреть файл
@@ -0,0 +1,127 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
rocshmem_team_t team_barrier_world_dup;
/******************************************************************************
* Device TEST KERNEL
*****************************************************************************/
__global__ void TeamBarrierTest(int loop, int skip, long long int *start_time,
long long int *end_time,
ShmemContextType ctx_type, TestType type,
int wf_size, rocshmem_team_t *teams) {
__shared__ rocshmem_ctx_t ctx;
int t_id = get_flat_block_id();
int wg_id = get_flat_grid_id();
int wf_id = t_id / wf_size;
rocshmem_wg_team_create_ctx(teams[wg_id], ctx_type, &ctx);
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
switch (type) {
case TeamBarrierTestType:
if(t_id == 0) {
rocshmem_ctx_barrier(ctx, teams[wg_id]);
}
break;
case TeamWAVEBarrierTestType:
if(wf_id == 0) {
rocshmem_ctx_barrier_wave(ctx, teams[wg_id]);
}
break;
case TeamWGBarrierTestType:
rocshmem_ctx_barrier_wg(ctx, teams[wg_id]);
break;
default:
break;
}
__syncthreads();
}
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamBarrierTester::TeamBarrierTester(TesterArguments args)
: Tester(args){
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
char* value{nullptr};
if ((value = getenv("ROCSHMEM_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
}
CHECK_HIP(hipMalloc(&team_barrier_world_dup,
sizeof(rocshmem_team_t) * num_teams));
}
TeamBarrierTester::~TeamBarrierTester() {
CHECK_HIP(hipFree(team_barrier_world_dup));
}
void TeamBarrierTester::preLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
team_barrier_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_barrier_world_dup[team_i]);
if (team_barrier_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
printf("Team %d is invalid!\n", team_i);
abort();
}
}
}
void TeamBarrierTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(TeamBarrierTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
_shmem_context, _type, wf_size,
team_barrier_world_dup);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
void TeamBarrierTester::postLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_barrier_world_dup[team_i]);
}
}
void TeamBarrierTester::resetBuffers(size_t size) {}
void TeamBarrierTester::verifyResults(size_t size) {}
+68
Просмотреть файл
@@ -0,0 +1,68 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_BARRIER_TESTER_HPP_
#define _TEAM_BARRIER_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
using namespace rocshmem;
/************* *****************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamBarrierTester : public Tester {
public:
explicit TeamBarrierTester(TesterArguments args);
virtual ~TeamBarrierTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
int my_pe = 0;
int n_pes = 0;
/**
* This constant should equal ROCSHMEM_MAX_NUM_TEAMS - 1.
* The default value for the maximum number of teams is 40.
*/
int num_teams = 39;
rocshmem_team_t *team_barrier_world_dup;
};
#include "team_barrier_tester.cpp"
#endif
+243
Просмотреть файл
@@ -0,0 +1,243 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
/* Declare the template with a generic implementation */
template <typename T>
__device__ void wg_team_broadcast(rocshmem_ctx_t ctx, rocshmem_team_t team,
T *dest, const T *source, int nelem,
int pe_root) {
return;
}
/* Define templates to call ROCSHMEM */
#define TEAM_BROADCAST_DEF_GEN(T, TNAME) \
template <> \
__device__ void wg_team_broadcast<T>( \
rocshmem_ctx_t ctx, rocshmem_team_t team, T * dest, const T *source, \
int nelem, int pe_root) { \
rocshmem_ctx_##TNAME##_broadcast_wg(ctx, team, dest, source, nelem, \
pe_root); \
}
TEAM_BROADCAST_DEF_GEN(float, float)
TEAM_BROADCAST_DEF_GEN(double, double)
TEAM_BROADCAST_DEF_GEN(char, char)
// TEAM_BROADCAST_DEF_GEN(long double, longdouble)
TEAM_BROADCAST_DEF_GEN(signed char, schar)
TEAM_BROADCAST_DEF_GEN(short, short)
TEAM_BROADCAST_DEF_GEN(int, int)
TEAM_BROADCAST_DEF_GEN(long, long)
TEAM_BROADCAST_DEF_GEN(long long, longlong)
TEAM_BROADCAST_DEF_GEN(unsigned char, uchar)
TEAM_BROADCAST_DEF_GEN(unsigned short, ushort)
TEAM_BROADCAST_DEF_GEN(unsigned int, uint)
TEAM_BROADCAST_DEF_GEN(unsigned long, ulong)
TEAM_BROADCAST_DEF_GEN(unsigned long long, ulonglong)
rocshmem_team_t team_bcast_world_dup;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
template <typename T1>
__global__ void TeamBroadcastTest(int loop, int skip, long long int *start_time,
long long int *end_time, T1 *source_buf,
T1 *dest_buf, int size,
ShmemContextType ctx_type,
rocshmem_team_t *teams) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_team_create_ctx(teams[wg_id], ctx_type, &ctx);
int n_pes = rocshmem_ctx_n_pes(ctx);
source_buf += wg_id * size;
dest_buf += wg_id * size;
__syncthreads();
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
wg_team_broadcast<T1>(ctx, teams[wg_id],
dest_buf, // T* dest
source_buf, // const T* source
size, // int nelement
0); // int PE_root
}
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T1>
TeamBroadcastTester<T1>::TeamBroadcastTester(TesterArguments args)
: Tester(args){
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
// Total number of elements in src buffer
int total_elems = (args.max_msg_size / sizeof(T1)) * args.num_wgs ;
int buff_size = total_elems * sizeof(T1);
source_buf = (T1 *)rocshmem_malloc(buff_size);
dest_buf = (T1 *)rocshmem_malloc(buff_size);
if (source_buf == nullptr || dest_buf == nullptr) {
std::cout << "Error allocating memory from symmetric heap" << std::endl;
std::cout << "source: " << source_buf << ", dest: " << dest_buf << std::endl;
rocshmem_global_exit(1);
}
char* value{nullptr};
if ((value = getenv("ROCSHMEM_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
}
CHECK_HIP(hipMalloc(&team_bcast_world_dup,
sizeof(rocshmem_team_t) * num_teams));
}
template <typename T1>
TeamBroadcastTester<T1>::~TeamBroadcastTester() {
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
CHECK_HIP(hipFree(team_bcast_world_dup));
}
template <typename T1>
void TeamBroadcastTester<T1>::preLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
team_bcast_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_bcast_world_dup[team_i]);
if (team_bcast_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
printf("Team %d is invalid!\n", team_i);
abort();
}
}
}
template <typename T1>
void TeamBroadcastTester<T1>::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
int num_elems = size / sizeof(T1);
hipLaunchKernelGGL(TeamBroadcastTest<T1>, gridSize, blockSize,
shared_bytes, stream, loop, args.skip,
start_time, end_time, source_buf, dest_buf,
num_elems, _shmem_context, team_bcast_world_dup);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
template <typename T1>
void TeamBroadcastTester<T1>::postLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_bcast_world_dup[team_i]);
}
}
template <typename T1>
void TeamBroadcastTester<T1>::resetBuffers(size_t size) {
int num_elems = size / sizeof(T1);
int buff_size = num_elems * sizeof(T1) * args.num_wgs;
int idx = 0;
for (int wg_id = 0; wg_id < args.num_wgs; wg_id++) {
for (int i = 0; i < num_elems; i++) {
idx = wg_id * num_elems + i;
if constexpr (std::is_same<T1, char>::value ||
std::is_same<T1, signed char>::value ||
std::is_same<T1, unsigned char>::value) {
source_buf[idx] = static_cast<T1>('a' + n_pes + wg_id);
dest_buf[idx] = static_cast<T1>('a' + wg_id);
}
else if constexpr (std::is_floating_point<T1>::value) {
source_buf[idx] = static_cast<T1>(3.14 + n_pes + wg_id);
dest_buf[idx] = static_cast<T1>(3.14 + wg_id);
}
else if constexpr (std::is_integral<T1>::value) {
source_buf[idx] = static_cast<T1>(n_pes + wg_id);
dest_buf[idx] = static_cast<T1>(wg_id);
}
}
}
}
template <typename T1>
void TeamBroadcastTester<T1>::verifyResults(size_t size) {
int num_elems = size / sizeof(T1);
int idx = 0;
T1 expected;
/**
* The verification routine here requires that the
* PE_root value is 0 which denotes that the
* sending processing element is rank 0.
*
* The difference in expected values arises from
* the specification for broadcast where the
* PE_root processing element does not copy the
* contents from its own source to dest during
* the broadcast.
*/
for (int wg_id = 0; wg_id < args.num_wgs; wg_id++) {
for (int i = 0; i < num_elems; i++) {
idx = wg_id * num_elems + i;
if constexpr (std::is_same<T1, char>::value ||
std::is_same<T1, signed char>::value ||
std::is_same<T1, unsigned char>::value) {
expected = static_cast<T1>('a' + wg_id + (my_pe ? n_pes : 0));
}
else if constexpr (std::is_floating_point<T1>::value) {
expected = static_cast<T1>(3.14 + wg_id + (my_pe ? n_pes : 0));
}
else if constexpr (std::is_integral<T1>::value) {
expected = static_cast<T1>(wg_id + (my_pe ? n_pes : 0));
}
if (dest_buf[idx] != expected) {
std::cerr << "Data validation error at idx " << idx << std::endl;
std::cerr << "PE " << my_pe << " Got " << dest_buf[idx]
<< ", Expected " << expected << std::endl;
exit(-1);
}
}
}
}
+72
Просмотреть файл
@@ -0,0 +1,72 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_BROADCAST_TESTER_HPP_
#define _TEAM_BROADCAST_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
using namespace rocshmem;
/************* *****************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T1>
class TeamBroadcastTester : public Tester {
public:
explicit TeamBroadcastTester(TesterArguments args);
virtual ~TeamBroadcastTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
T1 *source_buf;
T1 *dest_buf;
private:
int my_pe = 0;
int n_pes = 0;
/**
* This constant should equal ROCSHMEM_MAX_NUM_TEAMS - 1.
* The default value for the maximum number of teams is 40.
*/
int num_teams = 39;
rocshmem_team_t *team_bcast_world_dup;
};
#include "team_broadcast_tester.cpp"
#endif
+240
Просмотреть файл
@@ -0,0 +1,240 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "team_broadcastmem_on_stream_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <hip/hip_runtime.h>
#include <cstring>
#include <cassert>
#include <vector>
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamBroadcastmemOnStreamTester::TeamBroadcastmemOnStreamTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
char* value{nullptr};
if ((value = getenv("ROCSHMEM_TEST_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
} else {
// Default to number of work groups
num_teams = args.num_wgs;
}
// Set root PE to 0 by default, can be modified via environment variable
if ((value = getenv("ROCSHMEM_TEST_BROADCAST_ROOT"))) {
pe_root = atoi(value);
if (pe_root < 0 || pe_root >= n_pes) {
std::cerr << "Invalid ROCSHMEM_TEST_BROADCAST_ROOT value. Using PE 0."
<< std::endl;
pe_root = 0;
}
}
int num_bytes_wg = args.max_msg_size;
int total_bytes = num_bytes_wg * num_teams;
buf_size = total_bytes;
source_buf = static_cast<char *>(rocshmem_malloc(buf_size));
dest_buf = static_cast<char *>(rocshmem_malloc(buf_size));
if (source_buf == nullptr || dest_buf == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source_buf << ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
team_world_dup.resize(num_teams);
streams.resize(num_teams);
start_events_timed.resize(num_teams);
stop_events_timed.resize(num_teams);
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamCreate(&streams[i]));
CHECK_HIP(hipEventCreate(&start_events_timed[i]));
CHECK_HIP(hipEventCreate(&stop_events_timed[i]));
}
}
TeamBroadcastmemOnStreamTester::~TeamBroadcastmemOnStreamTester() {
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipEventDestroy(stop_events_timed[i]));
CHECK_HIP(hipEventDestroy(start_events_timed[i]));
CHECK_HIP(hipStreamDestroy(streams[i]));
}
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
}
void TeamBroadcastmemOnStreamTester::preLaunchKernel() {
bw_factor = 1; // Broadcast is one-to-all
for (int team_i = 0; team_i < num_teams; team_i++) {
team_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_world_dup[team_i]);
if (team_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
std::cerr << "Team " << team_i << " is invalid!" << std::endl;
abort();
}
}
}
void TeamBroadcastmemOnStreamTester::postLaunchKernel() {
// Synchronize all streams to ensure events are recorded
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
// Get elapsed time for each work group from HIP events
for (int wg_id = 0; wg_id < num_teams && wg_id < num_timers; wg_id++) {
float elapsed_time_ms = 0.0f;
CHECK_HIP(hipEventElapsedTime(&elapsed_time_ms, start_events_timed[wg_id],
stop_events_timed[wg_id]));
// Convert milliseconds to GPU cycles
// wall_clk_rate is in kHz, so: cycles = ms * wall_clk_rate
long long int elapsed_cycles = static_cast<long long int>(
elapsed_time_ms * static_cast<float>(wall_clk_rate));
start_time[wg_id] = 0;
end_time[wg_id] = elapsed_cycles;
}
// Fill remaining timers with zero if num_timers > num_teams
for (int i = num_teams; i < num_timers; i++) {
start_time[i] = 0;
end_time[i] = 0;
}
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_world_dup[team_i]);
}
}
void TeamBroadcastmemOnStreamTester::resetBuffers(size_t size) {
// Initialize source buffer on all PEs
// Each work group has its own portion
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
int idx = wg_id * size;
if (my_pe == pe_root) {
// Root PE fills its source buffer with broadcast value
int value = (pe_root + 1) * 100 + wg_id;
std::memset(source_buf + idx, value, size);
} else {
// Non-root PEs source buffer (not used in broadcast)
std::memset(source_buf + idx, 0xFF, size);
}
}
// Initialize destination buffer on all PEs
// Root PE keeps its initial dest value (broadcast doesn't copy to root's
// dest) Non-root PEs set to 0 (will receive broadcast data)
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
int idx = wg_id * size;
if (my_pe == pe_root) {
// Root PE's dest buffer stays with a different value
int root_dest_value = 0xAA;
std::memset(dest_buf + idx, root_dest_value, size);
} else {
std::memset(dest_buf + idx, 0, size);
}
}
}
void TeamBroadcastmemOnStreamTester::launchKernel(dim3 gridSize,
dim3 blockSize,
int loop,
size_t size) {
// Execute warmup iterations (skip)
for (int i = 0; i < args.skip; i++) {
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
char *wg_source = source_buf + wg_id * size;
char *wg_dest = dest_buf + wg_id * size;
rocshmem_broadcastmem_on_stream(team_world_dup[wg_id], wg_dest,
wg_source, size, pe_root, streams[wg_id]);
}
}
for (int i = 0; i < num_teams; i++) {
CHECK_HIP(hipStreamSynchronize(streams[i]));
}
for (int i = 0; i < loop; i++) {
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
// Record start event for this work group on first iteration
if (i == 0) {
CHECK_HIP(hipEventRecord(start_events_timed[wg_id], streams[wg_id]));
}
char *wg_source = source_buf + wg_id * size;
char *wg_dest = dest_buf + wg_id * size;
rocshmem_broadcastmem_on_stream(team_world_dup[wg_id], wg_dest,
wg_source, size, pe_root, streams[wg_id]);
// Record stop event for this work group on last iteration
if (i == loop - 1) {
CHECK_HIP(hipEventRecord(stop_events_timed[wg_id], streams[wg_id]));
}
}
}
num_msgs = (loop + args.skip) * num_teams;
num_timed_msgs = loop * num_teams;
}
void TeamBroadcastmemOnStreamTester::verifyResults(size_t size) {
// Verify correctness: after broadcast, non-root PEs receive the broadcast
// data Root PE's dest buffer is NOT modified (per OpenSHMEM/rocSHMEM spec)
for (int wg_id = 0; wg_id < num_teams; wg_id++) {
int idx = wg_id * size;
int expected_value;
if (my_pe == pe_root) {
// Root PE's dest buffer should remain unchanged (0xAA)
expected_value = 0xAA;
} else {
// Non-root PEs should have received the broadcast value
expected_value = (pe_root + 1) * 100 + wg_id;
}
for (size_t k = 0; k < size; k++) {
if (static_cast<unsigned char>(dest_buf[idx + k]) !=
static_cast<unsigned char>(expected_value)) {
std::cerr << "PE " << my_pe << ": Verification failed for WG "
<< wg_id << " at byte " << k << std::endl;
std::cerr << "Expected value: " << expected_value
<< ", Got: " << static_cast<int>(dest_buf[idx + k])
<< std::endl;
rocshmem_global_exit(1);
}
}
}
}
+71
Просмотреть файл
@@ -0,0 +1,71 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_BROADCASTMEM_ON_STREAM_TESTER_HPP_
#define _TEAM_BROADCASTMEM_ON_STREAM_TESTER_HPP_
#include "tester.hpp"
#include <vector>
#include <hip/hip_runtime.h>
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamBroadcastmemOnStreamTester : public Tester {
public:
explicit TeamBroadcastmemOnStreamTester(TesterArguments args);
virtual ~TeamBroadcastmemOnStreamTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
char *source_buf;
char *dest_buf;
int my_pe;
int n_pes;
size_t buf_size;
int num_teams = 1;
int pe_root = 0; // Root PE for broadcast
std::vector<rocshmem_team_t> team_world_dup;
std::vector<hipStream_t> streams;
std::vector<hipEvent_t> start_events_timed;
std::vector<hipEvent_t> stop_events_timed;
};
#include "team_broadcastmem_on_stream_tester.cpp"
#endif
+273
Просмотреть файл
@@ -0,0 +1,273 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "team_ctx_infra_tester.hpp"
#include <rocshmem/rocshmem.hpp>
#include <cstdlib>
#include <cassert>
using namespace rocshmem;
/* this constant should equal ROCSHMEM_MAX_NUM_TEAMS-1 */
#define NUM_TEAMS 39
rocshmem_team_t team_world_dup[NUM_TEAMS];
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void TeamCtxInfraSimpleTest(ShmemContextType ctx_type,
rocshmem_team_t team,
int expected_pe, int expected_n_pes) {
__shared__ rocshmem_ctx_t ctx;
rocshmem_wg_team_create_ctx(team, ctx_type, &ctx);
int num_pes = rocshmem_ctx_n_pes(ctx);
int my_pe = rocshmem_ctx_my_pe(ctx);
if (my_pe != expected_pe) {
printf("PE doesn't match. Expected %d got %d\n", expected_pe, my_pe);
abort();
}
if (num_pes != expected_n_pes) {
printf("Team size doesn't match. Expected %d got %d\n", expected_n_pes, num_pes);
abort();
}
__syncthreads();
rocshmem_ctx_quiet(ctx);
rocshmem_wg_ctx_destroy(&ctx);
}
__global__ void TeamCtxInfraTest(ShmemContextType ctx_type,
rocshmem_team_t *team) {
__shared__ rocshmem_ctx_t ctx1, ctx2, ctx3;
__shared__ rocshmem_ctx_t ctx[NUM_TEAMS];
/**
* Test 1: Assert team infos of different ctxs
* from the same team are the same.
*/
rocshmem_wg_team_create_ctx(team[0], ctx_type, &ctx1);
if (nullptr == ctx1.ctx_opaque) {
printf("Create ctx1 on team[0] returned an invalid context!\n");
abort();
}
rocshmem_wg_team_create_ctx(team[0], ctx_type, &ctx2);
if (nullptr == ctx2.ctx_opaque) {
printf("Create ctx2 on team[0] returned an invalid context!\n");
abort();
}
rocshmem_wg_ctx_destroy(&ctx1);
rocshmem_wg_team_create_ctx(team[0], ctx_type, &ctx3);
if (nullptr == ctx3.ctx_opaque) {
printf("Create ctx3 on team[0] returned an invalid context!\n");
abort();
}
__syncthreads();
if (ctx3.team_opaque != ctx2.team_opaque) {
printf("Incorrect for teams of ctx2 and ctx3 to be different!\n");
abort();
}
rocshmem_wg_ctx_destroy(&ctx2);
rocshmem_wg_ctx_destroy(&ctx3);
__syncthreads();
/**
* Test 2: Assert team infos of different ctxs
* from different teams are different.
*/
for (int team_i = 0; team_i < NUM_TEAMS; team_i++) {
rocshmem_wg_team_create_ctx(team[team_i], ctx_type, &ctx[team_i]);
if (nullptr == ctx[team_i].ctx_opaque) {
printf("Create ctx on team[%d] returned an invalid context!\n", team_i);
abort();
}
}
if (ctx[0].team_opaque == ctx[NUM_TEAMS - 1].team_opaque) {
printf("Incorrect for teams of ctx[0] and ctx[NUM_TEAMS-1] to be equal to each other\n");
abort();
}
__syncthreads();
for (int team_i = 0; team_i < NUM_TEAMS; team_i++) {
rocshmem_wg_ctx_destroy(&ctx[team_i]);
}
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamCtxInfraTester::TeamCtxInfraTester(TesterArguments args) : Tester(args) {
_splitType = args.team_type;
}
TeamCtxInfraTester::~TeamCtxInfraTester() {}
void TeamCtxInfraTester::resetBuffers(size_t size) {}
void TeamCtxInfraTester::preLaunchKernel() {
int n_pes = rocshmem_team_n_pes(_parentTeam);
int my_pe = rocshmem_team_my_pe(_parentTeam);
if (_splitType == ROCSHMEM_TEST_TEAM_DUP) {
// validate we can run the test
if (auto maximum_num_contexts_str = getenv("ROCSHMEM_MAX_NUM_CONTEXTS")) {
int max_ctx = atoi(maximum_num_contexts_str);
if (max_ctx <= NUM_TEAMS) {
printf("ROCSHMEM_MAX_NUM_CONTEXTS=%d is smaller than NUM_TEAMS %d, invalid test setup!\n", max_ctx, NUM_TEAMS);
assert(max_ctx > NUM_TEAMS);
abort();
}
}
for (int team_i = 0; team_i < NUM_TEAMS; team_i++) {
team_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(_parentTeam, 0, 1, n_pes, nullptr, 0,
&team_world_dup[team_i]);
if (team_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
printf("Created team %d is invalid!\n", team_i);
abort();
}
}
/* Assert the failure of a new team creation. */
rocshmem_team_t new_team = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(_parentTeam, 0, 1, n_pes, nullptr, 0,
&new_team);
if (new_team != ROCSHMEM_TEAM_INVALID) {
printf("Created new team should have been invalid!\n");
abort();
}
}
else if (_splitType == ROCSHMEM_TEST_TEAM_SINGLE) {
rocshmem_team_split_strided(_parentTeam, my_pe, 1, 1, nullptr, 0,
&team_world_dup[0]);
_expected_pe = rocshmem_team_my_pe(team_world_dup[0]);
_expected_n_pes = rocshmem_team_n_pes(team_world_dup[0]);
if (_expected_n_pes != 1) {
printf("ROCSHMEM_TEST_TEAM_SINGLE: n_pes %d expected: 1\n", _expected_n_pes);
abort();
}
if (_expected_pe != 0) {
printf("ROCSHMEM_TEST_TEAM_SINGLE: my_pe %d expected: 0\n", _expected_pe);
abort();
}
} else if (_splitType == ROCSHMEM_TEST_TEAM_BLOCK) {
int mid_pe = n_pes / 2; // integer division
int start_pe = my_pe < mid_pe ? 0 : mid_pe;
int end_pe = my_pe < mid_pe ? (mid_pe - 1) : (n_pes - 1);
int num_pes = end_pe - start_pe + 1;
int new_pe = my_pe < mid_pe ? my_pe : (my_pe - start_pe);
rocshmem_team_split_strided(_parentTeam, start_pe, 1, num_pes, nullptr, 0,
&team_world_dup[0]);
_expected_pe = rocshmem_team_my_pe(team_world_dup[0]);
_expected_n_pes = rocshmem_team_n_pes(team_world_dup[0]);
if (_expected_n_pes != num_pes) {
printf("ROCSHMEM_TEST_TEAM_BLOCK: n_pes %d expected: %d\n", _expected_n_pes, num_pes);
abort();
}
if (_expected_pe != new_pe) {
printf("ROCSHMEM_TEST_TEAM_BLOCK: my_pe %d expected: %d\n", _expected_pe, new_pe);
abort();
}
} else if (_splitType == ROCSHMEM_TEST_TEAM_ODDEVEN) {
int start_pe = (my_pe % 2) == 0 ? 0 : 1;
int num_pes = n_pes / 2;
if (((n_pes % 2) != 0) && ((my_pe % 2) == 0))
num_pes++;
int new_pe = (my_pe / 2);
rocshmem_team_split_strided(_parentTeam, start_pe, 2, num_pes, nullptr, 0,
&team_world_dup[0]);
_expected_pe = rocshmem_team_my_pe(team_world_dup[0]);
_expected_n_pes = rocshmem_team_n_pes(team_world_dup[0]);
if (_expected_n_pes != num_pes) {
printf("ROCSHMEM_TEST_TEAM_ODDEVEN: n_pes %d expected: %d\n", _expected_n_pes, num_pes);
abort();
}
if (_expected_pe != new_pe) {
printf("ROCSHMEM_TEST_TEAM_ODDEVEN: my_pe %d expected: %d\n", _expected_pe, new_pe);
abort();
}
}
}
void TeamCtxInfraTester::launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) {
size_t shared_bytes = 0;
/* Copy array of teams to device */
rocshmem_team_t *teams_on_device;
if (_splitType == ROCSHMEM_TEST_TEAM_DUP) {
CHECK_HIP(hipMalloc(&teams_on_device, sizeof(rocshmem_team_t) * NUM_TEAMS));
CHECK_HIP(hipMemcpy(teams_on_device, team_world_dup,
sizeof(rocshmem_team_t) * NUM_TEAMS, hipMemcpyHostToDevice));
hipLaunchKernelGGL(TeamCtxInfraTest, gridSize, blockSize, shared_bytes,
stream, _shmem_context, teams_on_device);
} else if (_splitType == ROCSHMEM_TEST_TEAM_SINGLE ||
_splitType == ROCSHMEM_TEST_TEAM_BLOCK ||
_splitType == ROCSHMEM_TEST_TEAM_ODDEVEN ) {
CHECK_HIP(hipMalloc(&teams_on_device, sizeof(rocshmem_team_t)));
CHECK_HIP(hipMemcpy(teams_on_device, team_world_dup,
sizeof(rocshmem_team_t), hipMemcpyHostToDevice));
hipLaunchKernelGGL(TeamCtxInfraSimpleTest, gridSize, blockSize, shared_bytes,
stream, _shmem_context, teams_on_device[0], _expected_pe, _expected_n_pes);
}
CHECK_HIP(hipFree(teams_on_device));
}
void TeamCtxInfraTester::postLaunchKernel() {
int num_teams = _splitType == ROCSHMEM_TEST_TEAM_DUP ? NUM_TEAMS : 1;
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_world_dup[team_i]);
}
}
void TeamCtxInfraTester::verifyResults(size_t size) {}
+59
Просмотреть файл
@@ -0,0 +1,59 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_CTX_INFRA_TESTER_HPP_
#define _TEAM_CTX_INFRA_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamCtxInfraTester : public Tester {
public:
explicit TeamCtxInfraTester(TesterArguments args);
virtual ~TeamCtxInfraTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
char *s_buf = nullptr;
char *r_buf = nullptr;
TeamSplitType _splitType;
rocshmem::rocshmem_team_t _parentTeam = rocshmem::ROCSHMEM_TEAM_WORLD;
int _expected_pe;
int _expected_n_pes;
};
#endif
+196
Просмотреть файл
@@ -0,0 +1,196 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "team_ctx_primitive_tester.hpp"
#include <rocshmem/rocshmem.hpp>
using namespace rocshmem;
rocshmem_team_t team_primitive_world_dup;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void TeamCtxPrimitiveTest(int loop, int skip, long long int *start_time,
long long int *end_time, char *source,
char *dest, size_t size, TestType type,
ShmemContextType ctx_type, int wf_size,
rocshmem_team_t team) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
int t_id = get_flat_block_id();
int wf_id = t_id / wf_size;
rocshmem_wg_team_create_ctx(team, ctx_type, &ctx);
/**
* Shared array to capture the start time for each wavefront
* Max threads per block = 1024, wavefront size = 64 or 32 depending
* on the GPUs. Using 32 since its safer for the dimensioning of the array,
* the last 16 elements will not be used on GPUs with a wf size of 64.
* Maximum array size required = 1024/32 = 32
*/
__shared__ long long int wf_start_time[32];
/**
* Calculate start index for each thread within the grid
*/
size_t offset = size * get_flat_id();
source += offset;
dest += offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
__syncthreads();
// Ensures all RMA calls from the skip loops are completed
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
__syncthreads();
// Capture the start time of each wavefront to identify the earliest one
wf_start_time[wf_id] = wall_clock64();
}
switch (type) {
case TeamCtxGetTestType:
rocshmem_ctx_getmem(ctx, dest, source, size, 1);
break;
case TeamCtxGetNBITestType:
rocshmem_ctx_getmem_nbi(ctx, dest, source, size, 1);
break;
case TeamCtxPutTestType:
rocshmem_ctx_putmem(ctx, dest, source, size, 1);
break;
case TeamCtxPutNBITestType:
rocshmem_ctx_putmem_nbi(ctx, dest, source, size, 1);
break;
default:
break;
}
}
__syncthreads();
if(is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
/**
* End time of the last wavefront is recorded by overwriting
* the value previously set by earlier wavefronts.
*/
end_time[wg_id] = wall_clock64();
// Find the earliest start time
int num_wfs = (get_flat_block_size() - 1 ) / wf_size + 1;
for (int i = num_wfs / 2; i > 0; i >>= 1 ) {
if(t_id < i) {
wf_start_time[t_id] = min(wf_start_time[t_id], wf_start_time[t_id + i]);
}
}
__syncthreads();
if (t_id == 0) {
start_time[wg_id] = wf_start_time[0];
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamCtxPrimitiveTester::TeamCtxPrimitiveTester(TesterArguments args)
: Tester(args) {
size_t buff_size = args.max_msg_size * args.wg_size * args.num_wgs;
source = (char *)rocshmem_malloc(buff_size);
dest = (char *)rocshmem_malloc(buff_size);
if (source == nullptr || dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source << ", dest: " << dest << std::endl;
if (source) {
rocshmem_free(source);
}
if (dest) {
rocshmem_free(dest);
}
rocshmem_global_exit(1);
}
for(size_t i = 0; i < buff_size; i++) {
source[i] = static_cast<char>('a' + i % 26);
}
}
TeamCtxPrimitiveTester::~TeamCtxPrimitiveTester() {
rocshmem_free(source);
rocshmem_free(dest);
}
void TeamCtxPrimitiveTester::resetBuffers(size_t size) {
size_t buff_size = size * args.wg_size * args.num_wgs;
memset(dest, '1', buff_size);
}
void TeamCtxPrimitiveTester::preLaunchKernel() {
int n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
team_primitive_world_dup = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_primitive_world_dup);
}
void TeamCtxPrimitiveTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(TeamCtxPrimitiveTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time, source,
dest, size, _type, _shmem_context, wf_size,
team_primitive_world_dup);
num_msgs = (loop + args.skip) * gridSize.x * blockSize.x;
num_timed_msgs = loop * gridSize.x * blockSize.x;
}
void TeamCtxPrimitiveTester::postLaunchKernel() {
rocshmem_team_destroy(team_primitive_world_dup);
}
void TeamCtxPrimitiveTester::verifyResults(size_t size) {
int check_id =
(_type == TeamCtxGetTestType || _type == TeamCtxGetNBITestType) ? 0 : 1;
if (args.myid == check_id) {
size_t buff_size = size * args.wg_size * args.num_wgs;
for (uint64_t i = 0; i < buff_size; i++) {
if (dest[i] != source[i]) {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected "
<< source[i] << std::endl;
exit(-1);
}
}
}
}
+54
Просмотреть файл
@@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_CTX_PRIMITIVE_TESTER_HPP_
#define _TEAM_CTX_PRIMITIVE_TESTER_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamCtxPrimitiveTester : public Tester {
public:
explicit TeamCtxPrimitiveTester(TesterArguments args);
virtual ~TeamCtxPrimitiveTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
char *source = nullptr;
char *dest = nullptr;
};
#endif
+232
Просмотреть файл
@@ -0,0 +1,232 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
/* Declare the template with a generic implementation */
template <typename T>
__device__ void wg_team_fcollect(rocshmem_ctx_t ctx, rocshmem_team_t team,
T *dest, const T *source, int nelems) {
return;
}
/* Define templates to call rocSHMEM */
#define TEAM_FCOLLECT_DEF_GEN(T, TNAME) \
template <> \
__device__ void wg_team_fcollect<T>(rocshmem_ctx_t ctx, rocshmem_team_t team,\
T * dest, const T *source, int nelem) { \
rocshmem_ctx_##TNAME##_fcollect_wg(ctx, team, dest, source, nelem); \
}
TEAM_FCOLLECT_DEF_GEN(float, float)
TEAM_FCOLLECT_DEF_GEN(double, double)
TEAM_FCOLLECT_DEF_GEN(char, char)
// TEAM_FCOLLECT_DEF_GEN(long double, longdouble)
TEAM_FCOLLECT_DEF_GEN(signed char, schar)
TEAM_FCOLLECT_DEF_GEN(short, short)
TEAM_FCOLLECT_DEF_GEN(int, int)
TEAM_FCOLLECT_DEF_GEN(long, long)
TEAM_FCOLLECT_DEF_GEN(long long, longlong)
TEAM_FCOLLECT_DEF_GEN(unsigned char, uchar)
TEAM_FCOLLECT_DEF_GEN(unsigned short, ushort)
TEAM_FCOLLECT_DEF_GEN(unsigned int, uint)
TEAM_FCOLLECT_DEF_GEN(unsigned long, ulong)
TEAM_FCOLLECT_DEF_GEN(unsigned long long, ulonglong)
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
template <typename T1>
__global__ void TeamFcollectTest(int loop, int skip, long long int *start_time,
long long int *end_time, T1 *source_buf,
T1 *dest_buf, int num_elems,
ShmemContextType ctx_type,
rocshmem_team_t *teams) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_team_create_ctx(teams[wg_id], ctx_type, &ctx);
int n_pes = rocshmem_ctx_n_pes(ctx);
source_buf += wg_id * num_elems;
dest_buf += wg_id * num_elems * n_pes;
__syncthreads();
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
wg_team_fcollect<T1>(ctx, teams[wg_id],
dest_buf, // T* dest
source_buf, // const T* source
num_elems); // int nelement
}
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T1>
TeamFcollectTester<T1>::TeamFcollectTester(TesterArguments args)
: Tester(args) {
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
// Total number of elements in src buffer
int total_elems = (args.max_msg_size / sizeof(T1)) * args.num_wgs ;
int buff_size = total_elems * sizeof(T1);
source_buf = (T1 *)rocshmem_malloc(buff_size);
dest_buf = (T1 *)rocshmem_malloc(buff_size * n_pes);
if (source_buf == nullptr || dest_buf == nullptr) {
std::cout << "Error allocating memory from symmetric heap" << std::endl;
std::cout << "source: " << source_buf
<< ", dest: " << dest_buf
<< std::endl;
rocshmem_global_exit(1);
}
if constexpr (std::is_same<T1, char>::value ||
std::is_same<T1, signed char>::value ||
std::is_same<T1, unsigned char>::value) {
for (int i = 0; i < total_elems; ++i) {
source_buf[i] = static_cast<T1>('a' + my_pe);
}
}
else if constexpr (std::is_floating_point<T1>::value) {
for (int i = 0; i < total_elems; ++i) {
source_buf[i] = static_cast<T1>(3.14 + my_pe);
}
}
else if constexpr (std::is_integral<T1>::value) {
for (int i = 0; i < total_elems; i++) {
source_buf[i] = static_cast<T1>(my_pe);
}
}
char* value{nullptr};
if ((value = getenv("ROCSHMEM_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
}
CHECK_HIP(hipMalloc(&team_fcollect_world_dup,
sizeof(rocshmem_team_t) * num_teams));
}
template <typename T1>
TeamFcollectTester<T1>::~TeamFcollectTester() {
rocshmem_free(source_buf);
rocshmem_free(dest_buf);
CHECK_HIP(hipFree(team_fcollect_world_dup));
}
template <typename T1>
void TeamFcollectTester<T1>::preLaunchKernel() {
bw_factor = n_pes;
for (int team_i = 0; team_i < num_teams; team_i++) {
team_fcollect_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_fcollect_world_dup[team_i]);
if (team_fcollect_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
std::cout << "Team " << team_i << " is invalid!" << std::endl;
abort();
}
}
}
template <typename T1>
void TeamFcollectTester<T1>::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
int num_elems = size / sizeof(T1);
int my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
int n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
hipLaunchKernelGGL(TeamFcollectTest<T1>, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
source_buf, dest_buf, num_elems, _shmem_context,
team_fcollect_world_dup);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
template <typename T1>
void TeamFcollectTester<T1>::postLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_fcollect_world_dup[team_i]);
}
}
template <typename T1>
void TeamFcollectTester<T1>::resetBuffers(size_t size) {
int num_elems = (size / sizeof(T1));
int buff_size = num_elems * sizeof(T1) * args.num_wgs * n_pes;
memset(dest_buf, -1, buff_size);
}
template <typename T1>
void TeamFcollectTester<T1>::verifyResults(size_t size) {
int num_elems = size / sizeof(T1);
int idx = 0;
T1 expected;
for(int wg_id = 0; wg_id < args.num_wgs; wg_id++) {
for(int pe = 0; pe < n_pes; pe++) {
for(int i = 0; i < num_elems; i++) {
idx = (wg_id * n_pes + pe) * num_elems + i;
if constexpr (std::is_same<T1, char>::value ||
std::is_same<T1, signed char>::value ||
std::is_same<T1, unsigned char>::value) {
expected = static_cast<T1>('a' + pe);
}
else if constexpr (std::is_floating_point<T1>::value) {
expected = static_cast<T1>(3.14 + pe);
}
else if constexpr (std::is_integral<T1>::value) {
expected = pe;
}
if (dest_buf[idx] != expected) {
std::cerr << "Data validation error at idx " << idx << std::endl;
std::cerr << "PE " << my_pe << " Got " << dest_buf[idx]
<< ", Expected " << expected << std::endl;
exit(-1);
}
}
}
}
}
+72
Просмотреть файл
@@ -0,0 +1,72 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_FCOLLECT_TESTER_HPP_
#define _TEAM_FCOLLECT_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
using namespace rocshmem;
/************* *****************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T1>
class TeamFcollectTester : public Tester {
public:
explicit TeamFcollectTester(TesterArguments args);
virtual ~TeamFcollectTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
T1 *source_buf;
T1 *dest_buf;
private:
int my_pe = 0;
int n_pes = 0;
/**
* This constant should equal ROCSHMEM_MAX_NUM_TEAMS - 1.
* The default value for the maximum number of teams is 40.
*/
int num_teams = 39;
rocshmem_team_t *team_fcollect_world_dup;
};
#include "team_fcollect_tester.cpp"
#endif
+172
Просмотреть файл
@@ -0,0 +1,172 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
using namespace rocshmem;
/* Declare the template with a generic implementation */
template <typename T, ROCSHMEM_OP Op>
__device__ int wg_team_reduce(rocshmem_ctx_t ctx, rocshmem_team_t, T *dest,
const T *source, int nreduce) {
return ROCSHMEM_SUCCESS;
}
/* Define templates to call rocSHMEM */
#define TEAM_REDUCTION_DEF_GEN(T, TNAME, Op_API, Op) \
template <> \
__device__ int wg_team_reduce<T, Op>(rocshmem_ctx_t ctx, \
rocshmem_team_t team, T * dest, \
const T *source, int nreduce) { \
return rocshmem_ctx_##TNAME##_##Op_API##_reduce_wg(ctx, team, dest, \
source, nreduce); \
}
#define TEAM_ARITH_REDUCTION_DEF_GEN(T, TNAME) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, sum, ROCSHMEM_SUM) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, min, ROCSHMEM_MIN) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, max, ROCSHMEM_MAX) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, prod, ROCSHMEM_PROD)
#define TEAM_BITWISE_REDUCTION_DEF_GEN(T, TNAME) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, or, ROCSHMEM_OR) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, and, ROCSHMEM_AND) \
TEAM_REDUCTION_DEF_GEN(T, TNAME, xor, ROCSHMEM_XOR)
#define TEAM_INT_REDUCTION_DEF_GEN(T, TNAME) \
TEAM_ARITH_REDUCTION_DEF_GEN(T, TNAME) \
TEAM_BITWISE_REDUCTION_DEF_GEN(T, TNAME)
#define TEAM_FLOAT_REDUCTION_DEF_GEN(T, TNAME) \
TEAM_ARITH_REDUCTION_DEF_GEN(T, TNAME)
TEAM_INT_REDUCTION_DEF_GEN(int, int)
TEAM_INT_REDUCTION_DEF_GEN(short, short)
TEAM_INT_REDUCTION_DEF_GEN(long, long)
TEAM_INT_REDUCTION_DEF_GEN(long long, longlong)
TEAM_FLOAT_REDUCTION_DEF_GEN(float, float)
TEAM_FLOAT_REDUCTION_DEF_GEN(double, double)
// long double reduction fails. hipcc/device may not support long double.
// so disable it for now.
// FLOAT_REDUCTION_DEF_GEN(long double, longdouble)
rocshmem_team_t team_reduce_world_dup;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
template <typename T1, ROCSHMEM_OP T2>
__global__ void TeamReductionTest(int loop, int skip, long long int *start_time,
long long int *end_time, T1 *s_buf, T1 *r_buf,
size_t size, TestType type,
ShmemContextType ctx_type,
rocshmem_team_t team) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_team_create_ctx(team, ctx_type, &ctx);
int n_pes = rocshmem_ctx_n_pes(ctx);
__syncthreads();
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
wg_team_reduce<T1, T2>(ctx, team, r_buf, s_buf, size);
}
__syncthreads();
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
template <typename T1, ROCSHMEM_OP T2>
TeamReductionTester<T1, T2>::TeamReductionTester(
TesterArguments args, std::function<void(T1 &, T1 &)> f1,
std::function<std::pair<bool, std::string>(const T1 &, const T1 &)> f2)
: Tester(args), init_buf{f1}, verify_buf{f2} {
s_buf = (T1 *)rocshmem_malloc(args.max_msg_size * sizeof(T1));
r_buf = (T1 *)rocshmem_malloc(args.max_msg_size * sizeof(T1));
}
template <typename T1, ROCSHMEM_OP T2>
TeamReductionTester<T1, T2>::~TeamReductionTester() {
rocshmem_free(s_buf);
rocshmem_free(r_buf);
}
template <typename T1, ROCSHMEM_OP T2>
void TeamReductionTester<T1, T2>::preLaunchKernel() {
int n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
team_reduce_world_dup = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_reduce_world_dup);
}
template <typename T1, ROCSHMEM_OP T2>
void TeamReductionTester<T1, T2>::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(HIP_KERNEL_NAME(TeamReductionTest<T1, T2>), gridSize,
blockSize, shared_bytes, stream, loop, args.skip,
start_time, end_time, s_buf, r_buf, size, _type,
_shmem_context, team_reduce_world_dup);
num_msgs = loop + args.skip;
num_timed_msgs = loop;
}
template <typename T1, ROCSHMEM_OP T2>
void TeamReductionTester<T1, T2>::postLaunchKernel() {
rocshmem_team_destroy(team_reduce_world_dup);
}
template <typename T1, ROCSHMEM_OP T2>
void TeamReductionTester<T1, T2>::resetBuffers(size_t size) {
for (uint64_t i = 0; i < args.max_msg_size; i++) {
init_buf(s_buf[i], r_buf[i]);
}
}
template <typename T1, ROCSHMEM_OP T2>
void TeamReductionTester<T1, T2>::verifyResults(size_t size) {
int n_pes = rocshmem_n_pes();
for (uint64_t i = 0; i < size; i++) {
auto r = verify_buf(r_buf[i], (T1)n_pes);
if (r.first == false) {
fprintf(stderr, "Data validation error at idx %lu\n", i);
fprintf(stderr, "%s.\n", r.second.c_str());
exit(-1);
}
}
}
+69
Просмотреть файл
@@ -0,0 +1,69 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_REDUCTION_TESTER_HPP_
#define _TEAM_REDUCTION_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
template <typename T1, ROCSHMEM_OP T2>
class TeamReductionTester : public Tester {
public:
explicit TeamReductionTester(
TesterArguments args, std::function<void(T1 &, T1 &)> f1,
std::function<std::pair<bool, std::string>(const T1 &, const T1 &)> f2);
virtual ~TeamReductionTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
T1 *s_buf;
T1 *r_buf;
T1 *pWrk;
long *pSync;
private:
std::function<void(T1 &, T1 &)> init_buf;
std::function<std::pair<bool, std::string>(const T1 &, const T1 &)>
verify_buf;
};
#include "team_reduction_tester.cpp"
#endif
+124
Просмотреть файл
@@ -0,0 +1,124 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void TeamSyncTest(int loop, int skip, long long int *start_time,
long long int *end_time,
ShmemContextType ctx_type, TestType type,
int wf_size, rocshmem_team_t *teams) {
__shared__ rocshmem_ctx_t ctx;
int t_id = get_flat_block_id();
int wg_id = get_flat_grid_id();
int wf_id = t_id / wf_size;
rocshmem_wg_team_create_ctx(teams[wg_id], ctx_type, &ctx);
for (int i = 0; i < loop + skip; i++) {
if (i == skip && hipThreadIdx_x == 0) {
start_time[wg_id] = wall_clock64();
}
switch (type) {
case TeamSyncTestType:
if(t_id == 0) {
rocshmem_ctx_sync(ctx, teams[wg_id]);
}
break;
case TeamWAVESyncTestType:
if(wf_id == 0) {
rocshmem_ctx_sync_wave(ctx, teams[wg_id]);
}
break;
case TeamWGSyncTestType:
rocshmem_ctx_sync_wg(ctx, teams[wg_id]);
break;
default:
break;
}
__syncthreads();
}
if (hipThreadIdx_x == 0) {
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
TeamSyncTester::TeamSyncTester(TesterArguments args) : Tester(args) {
my_pe = rocshmem_team_my_pe(ROCSHMEM_TEAM_WORLD);
n_pes = rocshmem_team_n_pes(ROCSHMEM_TEAM_WORLD);
char* value{nullptr};
if ((value = getenv("ROCSHMEM_MAX_NUM_TEAMS"))) {
num_teams = atoi(value);
}
CHECK_HIP(hipMalloc(&team_sync_world_dup,
sizeof(rocshmem_team_t) * num_teams));
}
TeamSyncTester::~TeamSyncTester() {
CHECK_HIP(hipFree(team_sync_world_dup));
}
void TeamSyncTester::preLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
team_sync_world_dup[team_i] = ROCSHMEM_TEAM_INVALID;
rocshmem_team_split_strided(ROCSHMEM_TEAM_WORLD, 0, 1, n_pes, nullptr, 0,
&team_sync_world_dup[team_i]);
if (team_sync_world_dup[team_i] == ROCSHMEM_TEAM_INVALID) {
printf("Team %d is invalid!\n", team_i);
abort();
}
}
}
void TeamSyncTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(TeamSyncTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
_shmem_context, _type, wf_size,
team_sync_world_dup);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
void TeamSyncTester::postLaunchKernel() {
for (int team_i = 0; team_i < num_teams; team_i++) {
rocshmem_team_destroy(team_sync_world_dup[team_i]);
}
}
void TeamSyncTester::resetBuffers(size_t size) {}
void TeamSyncTester::verifyResults(size_t size) {}
+68
Просмотреть файл
@@ -0,0 +1,68 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TEAM_SYNC_TESTER_HPP_
#define _TEAM_SYNC_TESTER_HPP_
#include <functional>
#include <utility>
#include "tester.hpp"
using namespace rocshmem;
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class TeamSyncTester : public Tester {
public:
explicit TeamSyncTester(TesterArguments args);
virtual ~TeamSyncTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void preLaunchKernel() override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void postLaunchKernel() override;
virtual void verifyResults(size_t size) override;
private:
int my_pe = 0;
int n_pes = 0;
/**
* This constant should equal ROCSHMEM_MAX_NUM_TEAMS - 1.
* The default value for the maximum number of teams is 40.
*/
int num_teams = 39;
rocshmem_team_t *team_sync_world_dup;
};
#include "team_sync_tester.cpp"
#endif
+231
Просмотреть файл
@@ -0,0 +1,231 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 <rocshmem/rocshmem.hpp>
#include <vector>
#include "tester.hpp"
#include "tester_arguments.hpp"
#if defined(HAVE_PMIX)
#include <pmix.h>
static pmix_proc_t pmix_myproc;
static pmix_proc_t pmix_proc;
static void init_pmix(int *rank, int *nranks)
{
pmix_status_t rc;
pmix_value_t *val;
if (PMIX_SUCCESS != (rc = PMIx_Init(&pmix_myproc, NULL, 0))) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Init failed: " << rc << std::endl;
abort();
}
#ifdef VERBOSE
printf("Client ns %s rank %d: Running\n", pmix_myproc.nspace, pmix_myproc.rank);
#endif
PMIX_PROC_CONSTRUCT(&pmix_proc);
PMIX_LOAD_PROCID(&pmix_proc, pmix_myproc.nspace, PMIX_RANK_WILDCARD);
/* get our job size */
if (PMIX_SUCCESS != (rc = PMIx_Get(&pmix_proc, PMIX_JOB_SIZE, NULL, 0, &val))) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Get universe size failed: "
<< rc << std::endl;
abort();
}
*nranks = val->data.uint32;
*rank = pmix_myproc.rank;
PMIX_VALUE_RELEASE(val);
return;
}
static void pmix_bcast(void *buf, size_t nbytes, char *key, int root)
{
pmix_status_t rc;
pmix_value_t value;
pmix_value_t *val;
pmix_info_t *info;
bool flag;
if (pmix_myproc.rank == root) {
value.type = PMIX_BYTE_OBJECT;
value.data.bo.bytes = (char *) (buf);
value.data.bo.size = nbytes;
rc = PMIx_Put(PMIX_GLOBAL, key, &value);
if (PMIX_SUCCESS != rc) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Put failed: " << rc << std::endl;
abort();
}
/* push the data to our PMIx server */
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Commit failed: " << rc << std::endl;
abort();
}
}
/* call fence to synchronize with our peers - instruct
* the fence operation to collect and return all "put"
* data from our peers */
PMIX_INFO_CREATE(info, 1);
flag = true;
PMIX_INFO_LOAD(info, PMIX_COLLECT_DATA, &flag, PMIX_BOOL);
if (PMIX_SUCCESS != (rc = PMIx_Fence(&pmix_proc, 1, info, 1))) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Fence failed: " << rc << std::endl;
abort();
}
PMIX_INFO_FREE(info, 1);
pmix_proc.rank = 0;
if (PMIX_SUCCESS != (rc = PMIx_Get(&pmix_proc, key, NULL, 0, &val))) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Get failed: " << rc << std::endl;
abort();
}
if (PMIX_BYTE_OBJECT != val->type) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Get returned wrong type: " << val->type << std::endl;
PMIX_VALUE_RELEASE(val);
abort();
}
if (pmix_myproc.rank != root) {
if (NULL == val->data.bo.bytes) {
std::cerr << "Rank " << pmix_myproc.rank << " PMIx_Get %d returned NULL pointer\n";
PMIX_VALUE_RELEASE(val);
abort();
}
memcpy (buf, val->data.bo.bytes, val->data.bo.size);
}
PMIX_VALUE_RELEASE(val);
return;
}
#endif
using namespace rocshmem;
int main(int argc, char *argv[]) {
/**
* Setup the tester arguments.
*/
TesterArguments args(argc, argv);
/***
* Select a GPU
*/
char* ompi_local_rank = getenv("OMPI_COMM_WORLD_LOCAL_RANK");
if (nullptr == ompi_local_rank) {
printf("Could not determine local rank, use Open MPI `mpiexec`\n");
abort();
}
CHECK_HIP(hipSetDevice(atoi(ompi_local_rank)));
/**
* Must initialize rocshmem to access arguments needed by the tester.
*/
#ifdef HAVE_PMIX
int test_uuid = 0;
char *rocshmem_test_uuid = getenv("ROCSHMEM_TEST_UUID");
if (rocshmem_test_uuid != nullptr) {
test_uuid = atoi(rocshmem_test_uuid);
}
if (test_uuid) {
int ret;
int rank, nranks;
rocshmem_uniqueid_t uid;
rocshmem_init_attr_t attr;
init_pmix(&rank, &nranks);
if (rank == 0) {
ret = rocshmem_get_uniqueid (&uid);
if (ret != ROCSHMEM_SUCCESS) {
std::cout << rank << ": Error in rocshmem_get_uniqueid. Aborting.\n";
abort();
}
}
char key[] = "rocshmem-uuid";
pmix_bcast(&uid, sizeof(rocshmem_uniqueid_t), key, 0);
// Close PMIx before potentially doing MPI_Init inside rocshmem_init
PMIx_Finalize(NULL, 0);
ret = rocshmem_set_attr_uniqueid_args(rank, nranks, &uid, &attr);
if (ret != ROCSHMEM_SUCCESS) {
std::cout << rank << ": Error in rocshmem_set_attr_uniqueid_args. Aborting.\n";
abort();
}
ret = rocshmem_init_attr(ROCSHMEM_INIT_WITH_UNIQUEID, &attr);
if (ret != ROCSHMEM_SUCCESS) {
std::cout << rank << ": Error in rocshmem_init_attr. Aborting.\n";
abort();
}
#ifdef VERBOSE
std::cout << rank << ": rocshmem_init_attr SUCCESS\n";
#endif
} else {
rocshmem_init();
}
#else
rocshmem_init();
#endif
/**
* Now grab the arguments from rocshmem.
*/
args.get_arguments();
/**
* Using the arguments we just constructed, call the tester factory
* method to get the tester (specified by the arguments).
*/
std::vector<Tester *> tests = Tester::create(args);
/**
* Run the tests
*/
for (auto test : tests) {
test->execute();
/**
* The tester factory method news the tester to create it so we clean
* up the memory here.
*/
delete test;
}
/**
* The rocshmem library needs to be cleaned up with this call. It pairs
* with the init function above.
*/
rocshmem_finalize();
return 0;
}
+771
Просмотреть файл
@@ -0,0 +1,771 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "tester.hpp"
#include <hip/hip_runtime.h>
#include <functional>
#include <iostream>
#include <rocshmem/rocshmem.hpp>
#include <vector>
#include "amo_bitwise_tester.hpp"
#include "amo_extended_tester.hpp"
#include "amo_standard_tester.hpp"
#include "default_ctx_primitive_tester.hpp"
#include "barrier_all_tester.hpp"
#include "barrier_all_on_stream_tester.hpp"
#include "empty_tester.hpp"
#include "getmem_on_stream_tester.hpp"
#include "putmem_on_stream_tester.hpp"
#include "putmem_signal_on_stream_tester.hpp"
#include "signal_wait_until_on_stream_tester.hpp"
#include "ping_all_tester.hpp"
#include "ping_pong_tester.hpp"
#include "primitive_mr_tester.hpp"
#include "primitive_tester.hpp"
#include "random_access_tester.hpp"
#include "shmem_ptr_tester.hpp"
#include "signaling_operations_tester.hpp"
#include "sync_all_tester.hpp"
#include "team_sync_tester.hpp"
#include "team_alltoall_tester.hpp"
#include "team_alltoallmem_on_stream_tester.hpp"
#include "team_broadcastmem_on_stream_tester.hpp"
#include "team_barrier_tester.hpp"
#include "team_broadcast_tester.hpp"
#include "team_ctx_infra_tester.hpp"
#include "team_ctx_primitive_tester.hpp"
#include "team_fcollect_tester.hpp"
#include "team_reduction_tester.hpp"
#include "wavefront_primitives.hpp"
#include "workgroup_primitives.hpp"
#include "flood_tester.hpp"
#include "backend_bc.hpp"
extern Backend* backend;
Tester::Tester(TesterArguments args) : args(args) {
_type = (TestType)args.algorithm;
_shmem_context = args.shmem_context;
CHECK_HIP(hipGetDevice(&device_id));
CHECK_HIP(hipGetDeviceProperties(&deviceProps, device_id));
wf_size = deviceProps.warpSize;
num_warps = (args.wg_size - 1) / wf_size + 1;
CHECK_HIP(hipStreamCreate(&stream));
CHECK_HIP(hipEventCreate(&start_event));
CHECK_HIP(hipEventCreate(&stop_event));
CHECK_HIP(hipDeviceGetAttribute(&wall_clk_rate,
hipDeviceAttributeWallClockRate, device_id));
num_timers = args.num_wgs;
switch (_type) {
case WAVEGetTestType:
case WAVEGetNBITestType:
case WAVEPutTestType:
case WAVEPutNBITestType:
num_timers = args.num_wgs * num_warps;
break;
default:
break;
}
CHECK_HIP(hipMalloc((void**)&timer, sizeof(long long int) * num_timers));
CHECK_HIP(hipMalloc((void**)&start_time, sizeof(long long int) * num_timers));
CHECK_HIP(hipMalloc((void**)&end_time, sizeof(long long int) * num_timers));
CHECK_HIP(hipHostMalloc((void**)&verification_error, sizeof(bool)));
*verification_error = false;
}
Tester::~Tester() {
CHECK_HIP(hipFree(end_time));
CHECK_HIP(hipFree(start_time));
CHECK_HIP(hipFree(timer));
CHECK_HIP(hipEventDestroy(stop_event));
CHECK_HIP(hipEventDestroy(start_event));
CHECK_HIP(hipStreamDestroy(stream));
CHECK_HIP(hipFree(verification_error));
}
std::vector<Tester*> Tester::create(TesterArguments args) {
int rank = args.myid;
std::vector<Tester*> testers;
if (rank == 0) std::cout << "### Creating Test: ";
BackendType backend_type = get_backend_type();
TestType type = (TestType)args.algorithm;
switch (type) {
case InitTestType:
if (rank == 0) std::cout << "Init ###" << std::endl;
testers.push_back(new EmptyTester(args));
return testers;
case GetTestType:
if (rank == 0) std::cout << "Blocking Gets ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case GetNBITestType:
if (rank == 0) std::cout << "Non-Blocking Gets ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case PutTestType:
if (rank == 0) std::cout << "Blocking Puts ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case PutNBITestType:
if (rank == 0) std::cout << "Non-Blocking Puts ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case DefaultCTXGetTestType:
if (rank == 0)
std::cout << "Default context Blocking Gets ###" << std::endl;
testers.push_back(new DefaultCTXPrimitiveTester(args));
return testers;
case DefaultCTXGetNBITestType:
if (rank == 0)
std::cout << "Default context Non-Blocking Gets ###" << std::endl;
testers.push_back(new DefaultCTXPrimitiveTester(args));
return testers;
case DefaultCTXPutTestType:
if (rank == 0)
std::cout << "Default context Blocking Puts ###" << std::endl;
testers.push_back(new DefaultCTXPrimitiveTester(args));
return testers;
case DefaultCTXPutNBITestType:
if (rank == 0)
std::cout << "Default context Non-Blocking Puts ###" << std::endl;
testers.push_back(new DefaultCTXPrimitiveTester(args));
return testers;
case TeamCtxInfraTestType:
if (rank == 0) std::cout << "Team Ctx Infra test ###" << std::endl;
testers.push_back(new TeamCtxInfraTester(args));
return testers;
case TeamCtxInfraTestSingleType:
if (rank == 0) std::cout << "Team Ctx Infra Single test ###" << std::endl;
args.team_type = ROCSHMEM_TEST_TEAM_SINGLE;
testers.push_back(new TeamCtxInfraTester(args));
return testers;
case TeamCtxInfraTestBlockType:
if (rank == 0) std::cout << "Team Ctx Infra Block test ###" << std::endl;
args.team_type = ROCSHMEM_TEST_TEAM_BLOCK;
testers.push_back(new TeamCtxInfraTester(args));
return testers;
case TeamCtxInfraTestOddEvenType:
if (rank == 0) std::cout << "Team Ctx Infra Odd-Even test ###" << std::endl;
args.team_type = ROCSHMEM_TEST_TEAM_ODDEVEN;
testers.push_back(new TeamCtxInfraTester(args));
return testers;
case TeamCtxGetTestType:
if (rank == 0) std::cout << "Blocking Team Ctx Gets ###" << std::endl;
testers.push_back(new TeamCtxPrimitiveTester(args));
return testers;
case TeamCtxGetNBITestType:
if (rank == 0) std::cout << "Non-Blocking Team Ctx Gets ###" << std::endl;
testers.push_back(new TeamCtxPrimitiveTester(args));
return testers;
case TeamCtxPutTestType:
if (rank == 0) std::cout << "Blocking Team Ctx Puts ###" << std::endl;
testers.push_back(new TeamCtxPrimitiveTester(args));
return testers;
case TeamCtxPutNBITestType:
if (rank == 0) std::cout << "Non-Blocking Team Ctx Puts ###" << std::endl;
testers.push_back(new TeamCtxPrimitiveTester(args));
return testers;
case PTestType:
if (rank == 0) std::cout << "P Test ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case GTestType:
if (rank == 0) std::cout << "G Test ###" << std::endl;
testers.push_back(new PrimitiveTester(args));
return testers;
case TeamReductionTestType:
if (rank == 0)
std::cout << "All-to-All Team-based Reduction ###" << std::endl;
testers.push_back(new TeamReductionTester<float, ROCSHMEM_SUM>(
args,
[](float& f1, float& f2) {
f1 = 1;
f2 = 1;
},
[](float v, float n_pes) {
return (v == n_pes)
? std::make_pair(true, "")
: std::make_pair(false, "Got " + std::to_string(v) +
", Expect " +
std::to_string(n_pes));
}));
return testers;
case TeamBroadcastTestType:
if (rank == 0) {
std::cout << "Team Broadcast Test ###" << std::endl;
}
testers.push_back(new TeamBroadcastTester<int64_t>(args));
testers.push_back(new TeamBroadcastTester<int>(args));
testers.push_back(new TeamBroadcastTester<long long>(args));
testers.push_back(new TeamBroadcastTester<float>(args));
testers.push_back(new TeamBroadcastTester<double>(args));
testers.push_back(new TeamBroadcastTester<char>(args));
testers.push_back(new TeamBroadcastTester<unsigned char>(args));
return testers;
case TeamAllToAllTestType:
if (rank == 0) {
std::cout << "Alltoall Test ###" << std::endl;
}
testers.push_back(new TeamAlltoallTester<float>(args));
return testers;
case TeamAlltoallmemOnStreamTestType:
if (rank == 0)
std::cout << "Alltoallmem_On_Stream ###" << std::endl;
testers.push_back(new TeamAlltoallmemOnStreamTester(args));
return testers;
case BarrierAllOnStreamTestType:
if (rank == 0)
std::cout << "Barrier_All_On_Stream ###" << std::endl;
testers.push_back(new BarrierAllOnStreamTester(args));
return testers;
case TeamBroadcastmemOnStreamTestType:
if (rank == 0)
std::cout << "Broadcastmem_On_Stream ###" << std::endl;
testers.push_back(new TeamBroadcastmemOnStreamTester(args));
return testers;
case GetmemOnStreamTestType:
if (rank == 0)
std::cout << "Getmem_On_Stream ###" << std::endl;
testers.push_back(new GetmemOnStreamTester(args));
return testers;
case PutmemOnStreamTestType:
if (rank == 0)
std::cout << "Putmem_On_Stream ###" << std::endl;
testers.push_back(new PutmemOnStreamTester(args));
return testers;
case PutmemSignalOnStreamTestType:
if (rank == 0)
std::cout << "Putmem_Signal_On_Stream ###" << std::endl;
testers.push_back(new PutmemSignalOnStreamTester(args));
return testers;
case SignalWaitUntilOnStreamTestType:
if (rank == 0)
std::cout << "Signal_Wait_Until_On_Stream ###" << std::endl;
testers.push_back(new SignalWaitUntilOnStreamTester(args));
return testers;
case TeamFCollectTestType:
if (rank == 0) {
std::cout << "Fcollect Test ###" << std::endl;
}
testers.push_back(new TeamFcollectTester<int64_t>(args));
testers.push_back(new TeamFcollectTester<int>(args));
testers.push_back(new TeamFcollectTester<long long>(args));
testers.push_back(new TeamFcollectTester<float>(args));
testers.push_back(new TeamFcollectTester<double>(args));
testers.push_back(new TeamFcollectTester<char>(args));
testers.push_back(new TeamFcollectTester<unsigned char>(args));
return testers;
case AMO_FAddTestType:
if (rank == 0) std::cout << "AMO Fetch_Add ###" << std::endl;
testers.push_back(new AMOStandardTester<long long>(args));
testers.push_back(new AMOStandardTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOStandardTester<int>(args));
return testers;
case AMO_FIncTestType:
if (rank == 0) std::cout << "AMO Fetch_Inc ###" << std::endl;
testers.push_back(new AMOStandardTester<long long>(args));
testers.push_back(new AMOStandardTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOStandardTester<int>(args));
return testers;
case AMO_FetchTestType:
if (rank == 0) std::cout << "AMO Fetch ###" << std::endl;
testers.push_back(new AMOExtendedTester<long long>(args));
testers.push_back(new AMOExtendedTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOExtendedTester<int>(args));
return testers;
case AMO_FCswapTestType:
if (rank == 0) std::cout << "AMO Fetch_CSWAP ###" << std::endl;
testers.push_back(new AMOStandardTester<long long>(args));
testers.push_back(new AMOStandardTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOStandardTester<int>(args));
return testers;
case AMO_AddTestType:
if (rank == 0) std::cout << "AMO Add ###" << std::endl;
testers.push_back(new AMOStandardTester<long long>(args));
testers.push_back(new AMOStandardTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOStandardTester<int>(args));
return testers;
case AMO_SetTestType:
if (rank == 0) std::cout << "AMO Set ###" << std::endl;
testers.push_back(new AMOExtendedTester<long long>(args));
testers.push_back(new AMOExtendedTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOExtendedTester<int>(args));
return testers;
case AMO_SwapTestType:
if (rank == 0) std::cout << "AMO Swap ###" << std::endl;
testers.push_back(new AMOExtendedTester<long long>(args));
testers.push_back(new AMOExtendedTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOExtendedTester<int>(args));
return testers;
case AMO_FetchAndTestType:
if (rank == 0) std::cout << "AMO Fetch And ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_AndTestType:
if (rank == 0) std::cout << "AMO And ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_FetchOrTestType:
if (rank == 0) std::cout << "AMO Fetch Or ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_OrTestType:
if (rank == 0) std::cout << "AMO Or ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_FetchXorTestType:
if (rank == 0) std::cout << "AMO Fetch Xor ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_XorTestType:
if (rank == 0) std::cout << "AMO Xor ###" << std::endl;
testers.push_back(new AMOBitwiseTester<unsigned long long>(args));
testers.push_back(new AMOBitwiseTester<unsigned long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOBitwiseTester<unsigned int>(args));
return testers;
case AMO_IncTestType:
if (rank == 0) std::cout << "AMO Inc ###" << std::endl;
testers.push_back(new AMOStandardTester<long long>(args));
testers.push_back(new AMOStandardTester<long>(args));
if (BackendType::GDA_BACKEND != backend_type) // not implemented for GDA
testers.push_back(new AMOStandardTester<int>(args));
return testers;
case PingPongTestType:
if (rank == 0) std::cout << "PingPong ###" << std::endl;
testers.push_back(new PingPongTester(args));
return testers;
case PingAllTestType:
if (rank == 0) std::cout << "PingAll ###" << std::endl;
testers.push_back(new PingAllTester(args));
return testers;
case BarrierAllTestType:
if (rank == 0) std::cout << "Barrier_All ###" << std::endl;
testers.push_back(new BarrierAllTester(args));
return testers;
case WAVEBarrierAllTestType:
if (rank == 0) std::cout << "WAVE Barrier_All ###" << std::endl;
testers.push_back(new BarrierAllTester(args));
return testers;
case WGBarrierAllTestType:
if (rank == 0) std::cout << "WG Barrier_All ###" << std::endl;
testers.push_back(new BarrierAllTester(args));
return testers;
case TeamBarrierTestType:
if (rank == 0) std::cout << "Team Barrier Test ###" << std::endl;
testers.push_back(new TeamBarrierTester(args));
return testers;
case TeamWAVEBarrierTestType:
if (rank == 0) std::cout << "Team WAVE Barrier Test ###" << std::endl;
testers.push_back(new TeamBarrierTester(args));
return testers;
case TeamWGBarrierTestType:
if (rank == 0) std::cout << "Team WG Barrier Test ###" << std::endl;
testers.push_back(new TeamBarrierTester(args));
return testers;
case SyncAllTestType:
if (rank == 0) std::cout << "SyncAll ###" << std::endl;
testers.push_back(new SyncAllTester(args));
return testers;
case WAVESyncAllTestType:
if (rank == 0) std::cout << "WAVE SyncAll ###" << std::endl;
testers.push_back(new SyncAllTester(args));
return testers;
case WGSyncAllTestType:
if (rank == 0) std::cout << "WG SyncAll ###" << std::endl;
testers.push_back(new SyncAllTester(args));
return testers;
case TeamSyncTestType:
if (rank == 0) std::cout << "Team Sync ###" << std::endl;
testers.push_back(new TeamSyncTester(args));
return testers;
case TeamWAVESyncTestType:
if (rank == 0) std::cout << "Team WAVE Sync ###" << std::endl;
testers.push_back(new TeamSyncTester(args));
return testers;
case TeamWGSyncTestType:
if (rank == 0) std::cout << "Team WG Sync ###" << std::endl;
testers.push_back(new TeamSyncTester(args));
return testers;
case RandomAccessTestType:
if (rank == 0) std::cout << "Random_Access ###" << std::endl;
testers.push_back(new RandomAccessTester(args));
return testers;
case ShmemPtrTestType:
if (rank == 0) std::cout << "Shmem_Ptr ###" << std::endl;
testers.push_back(new ShmemPtrTester(args));
return testers;
case WGGetTestType:
if (rank == 0)
std::cout << "Blocking WG level Gets ###" << std::endl;
testers.push_back(new WorkGroupPrimitiveTester(args));
return testers;
case WGGetNBITestType:
if (rank == 0)
std::cout << "Non-Blocking WG level Gets ###" << std::endl;
testers.push_back(new WorkGroupPrimitiveTester(args));
return testers;
case WGPutTestType:
if (rank == 0)
std::cout << "Blocking WG level Puts ###" << std::endl;
testers.push_back(new WorkGroupPrimitiveTester(args));
return testers;
case WGPutNBITestType:
if (rank == 0)
std::cout << "Non-Blocking WG level Puts ###" << std::endl;
testers.push_back(new WorkGroupPrimitiveTester(args));
return testers;
case PutNBIMRTestType:
if (rank == 0)
std::cout << "Non-Blocking Put message rate ###" << std::endl;
testers.push_back(new PrimitiveMRTester(args));
return testers;
case WAVEGetTestType:
if (rank == 0)
std::cout << "Blocking WAVE level Gets ###" << std::endl;
testers.push_back(new WaveFrontPrimitiveTester(args));
return testers;
case WAVEGetNBITestType:
if (rank == 0)
std::cout << "Non-Blocking WAVE level Gets ###" << std::endl;
testers.push_back(new WaveFrontPrimitiveTester(args));
return testers;
case WAVEPutTestType:
if (rank == 0)
std::cout << "Blocking WAVE level Puts ###" << std::endl;
testers.push_back(new WaveFrontPrimitiveTester(args));
return testers;
case WAVEPutNBITestType:
if (rank == 0)
std::cout << "Non-Blocking WAVE level Puts ###" << std::endl;
testers.push_back(new WaveFrontPrimitiveTester(args));
return testers;
case PutSignalTestType:
if (rank == 0) std::cout << "Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case WGPutSignalTestType:
if (rank == 0) std::cout << "WG Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case WAVEPutSignalTestType:
if (rank == 0) std::cout << "Wave Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case PutSignalNBITestType:
if (rank == 0) std::cout << "Non-Blocking Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case WGPutSignalNBITestType:
if (rank == 0) std::cout << "Non-Blocking WG Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case WAVEPutSignalNBITestType:
if (rank == 0) std::cout << "Non-Blocking Wave Putmem Signal ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_SET));
testers.push_back(new SignalingOperationsTester(args, ROCSHMEM_SIGNAL_ADD));
return testers;
case SignalFetchTestType:
if (rank == 0) std::cout << "Signal Fetch ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args));
return testers;
case WGSignalFetchTestType:
if (rank == 0) std::cout << "WG Signal Fetch ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args));
return testers;
case WAVESignalFetchTestType:
if (rank == 0) std::cout << "Wave Signal Fetch ###" << std::endl;
testers.push_back(new SignalingOperationsTester(args));
return testers;
case FloodPutTestType:
if (rank == 0) std::cout << "Flood Put (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
case FloodPutNBITestType:
if (rank == 0) std::cout << "Flood Non-Blocking Put (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
case FloodPTestType:
if (rank == 0) std::cout << "Flood P (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
case FloodGetTestType:
if (rank == 0) std::cout << "Flood Get (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
case FloodGetNBITestType:
if (rank == 0) std::cout << "Flood Non-Blocking Get (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
case FloodGTestType:
if (rank == 0) std::cout << "Flood G (multidirectional) ###" << std::endl;
testers.push_back(new FloodTester(args));
return testers;
default:
if (rank == 0) std::cout << "Empty Test ###" << std::endl;
return testers;
}
return testers;
}
void Tester::execute() {
if (_type == InitTestType) return;
int num_loops = args.loop;
/**
* Some tests loop through data sizes in powers of 2 and report the
* results for those ranges.
*/
for (size_t size = args.min_msg_size; size <= args.max_msg_size;
size <<= 1) {
resetBuffers(size);
/**
* Restricts the number of iterations of really large messages.
*/
if (size > args.large_message_size) num_loops = args.loop_large;
barrier();
preLaunchKernel();
/**
* This conditional launches the HIP kernel.
*
* Some tests may only launch a single kernel. These kernels will
* be kicked off by the initiator (denoted by the args.myid check).
*
* Other tests will initiate of both sides and launch from both
* rocshmem pes.
*/
if (peLaunchesKernel()) {
memset(timer, 0, sizeof(uint64_t) * args.num_wgs);
const dim3 blockSize(args.wg_size, 1, 1);
const dim3 gridSize(args.num_wgs, 1, 1);
CHECK_HIP(hipEventRecord(start_event, stream));
launchKernel(gridSize, blockSize, num_loops, size);
CHECK_HIP(hipEventRecord(stop_event, stream));
hipError_t err = hipStreamSynchronize(stream);
if (err != hipSuccess) {
printf("error = %d \n", err);
}
}
barrier();
postLaunchKernel();
// data validation
verifyResults(size);
barrier();
if (_type != TeamCtxInfraTestType &&
_type != TeamCtxInfraTestSingleType &&
_type != TeamCtxInfraTestBlockType &&
_type != TeamCtxInfraTestOddEvenType ) {
print(size);
}
}
}
bool Tester::peLaunchesKernel() {
/**
* The PE assigned 0 is always active in these tests.
*/
bool is_launcher = (args.myid == 0);
/**
* Some test types are active on both sides.
*/
switch (_type) {
case TeamReductionTestType:
case TeamBroadcastTestType:
case TeamCtxInfraTestType:
case TeamCtxInfraTestSingleType:
case TeamCtxInfraTestBlockType:
case TeamCtxInfraTestOddEvenType:
case TeamAllToAllTestType:
case TeamFCollectTestType:
case PingPongTestType:
case BarrierAllTestType:
case WAVEBarrierAllTestType:
case WGBarrierAllTestType:
case TeamSyncTestType:
case TeamWAVESyncTestType:
case TeamWGSyncTestType:
case SyncAllTestType:
case WAVESyncAllTestType:
case WGSyncAllTestType:
case RandomAccessTestType:
case PingAllTestType:
case TeamBarrierTestType:
case TeamWAVEBarrierTestType:
case TeamWGBarrierTestType:
case TeamAlltoallmemOnStreamTestType:
case BarrierAllOnStreamTestType:
case TeamBroadcastmemOnStreamTestType:
case GetmemOnStreamTestType:
case PutmemOnStreamTestType:
case PutmemSignalOnStreamTestType:
case SignalWaitUntilOnStreamTestType:
case FloodPutTestType:
case FloodPutNBITestType:
case FloodPTestType:
case FloodGetTestType:
case FloodGetNBITestType:
case FloodGTestType:
is_launcher = true;
break;
default:
break;
}
return is_launcher;
}
void Tester::print(uint64_t size) {
if (args.myid != 0 || !_print_results) {
return;
}
/**
* Calculate total amount of data transfered
*/
uint64_t total_size = size * num_timed_msgs;
double timer_avg = timerAvgInMicroseconds();
double time_us = gpuCyclesToMicroseconds(max_end_time - min_start_time);
double time_s = time_us / 1e6;
double latency_avg = time_us / num_timed_msgs;
double avg_msg_rate = num_timed_msgs / time_s;
double bandwidth_avg_gbs =
static_cast<double>(total_size * bw_factor) / time_s / pow(2, 30);
float total_kern_time_ms;
CHECK_HIP(hipEventElapsedTime(&total_kern_time_ms, start_event, stop_event));
float total_kern_time_s = total_kern_time_ms / 1000;
int field_width = 20;
int float_precision = 2;
if (_print_header) {
printf("%-*s%-*s%*s%*s%*s",
15, "# Size (B)",
15, "# of timed Msgs",
field_width, "Latency (us)",
field_width, "Bandwidth (GB/s)",
field_width + 1, "Msg Rate (Msg/s)\n");
_print_header = 0;
}
printf("%-*lu%-*d%*.*f%*.*f%*.*f\n",
15, size,
15, num_timed_msgs,
field_width, float_precision, latency_avg,
field_width, float_precision, bandwidth_avg_gbs,
field_width, float_precision, avg_msg_rate);
fflush(stdout);
}
void flush_hdp() {
int hip_dev_id{};
unsigned int* hdp_flush_ptr_{nullptr};
CHECK_HIP(hipGetDevice(&hip_dev_id));
CHECK_HIP(hipDeviceGetAttribute(reinterpret_cast<int*>(&hdp_flush_ptr_),
hipDeviceAttributeHdpMemFlushCntl, hip_dev_id));
__atomic_store_n(hdp_flush_ptr_, 0x1, __ATOMIC_SEQ_CST);
}
void Tester::barrier() {
rocshmem_barrier_all();
flush_hdp();
}
double Tester::gpuCyclesToMicroseconds(long long int cycles) {
return static_cast<double>(cycles) /
(static_cast<double>(wall_clk_rate) * 1e-3);
}
double Tester::timerAvgInMicroseconds() {
double sum = 0;
min_start_time = LLONG_MAX;
max_end_time = 0;
for (uint32_t i = 0; i < num_timers; i++) {
timer[i] = end_time[i] - start_time[i];
sum += gpuCyclesToMicroseconds(timer[i]);
min_start_time = (start_time[i] < min_start_time)
? start_time[i]
: min_start_time;
max_end_time = (end_time[i] > max_end_time)
? end_time[i]
: max_end_time;
}
return sum / num_timers;
}
+214
Просмотреть файл
@@ -0,0 +1,214 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TESTER_HPP_
#define _TESTER_HPP_
#include <rocshmem/rocshmem.hpp>
#include <vector>
#include <climits>
#include "tester_arguments.hpp"
#include "../src/util.hpp"
#include "verify_results_kernels.hpp"
/******************************************************************************
* TESTER CLASS TYPES
*****************************************************************************/
enum TestType {
GetTestType = 0,
GetNBITestType = 1,
PutTestType = 2,
PutNBITestType = 3,
AMO_FAddTestType = 4,
AMO_FIncTestType = 5,
AMO_FetchTestType = 6,
AMO_FCswapTestType = 7,
AMO_AddTestType = 8,
AMO_IncTestType = 9,
AMO_CswapTestType = 10,
InitTestType = 11,
PingPongTestType = 12,
RandomAccessTestType = 13,
BarrierAllTestType = 14,
SyncAllTestType = 15,
TeamSyncTestType = 16,
CollectTestType = 17,
TeamFCollectTestType = 18,
TeamAllToAllTestType = 19,
AllToAllsTestType = 20,
ShmemPtrTestType = 21,
PTestType = 22,
GTestType = 23,
WGGetTestType = 24,
WGGetNBITestType = 25,
WGPutTestType = 26,
WGPutNBITestType = 27,
WAVEGetTestType = 28,
WAVEGetNBITestType = 29,
WAVEPutTestType = 30,
WAVEPutNBITestType = 31,
TeamBroadcastTestType = 32,
TeamReductionTestType = 33,
TeamCtxGetTestType = 34,
TeamCtxGetNBITestType = 35,
TeamCtxPutTestType = 36,
TeamCtxPutNBITestType = 37,
TeamCtxInfraTestType = 38,
PutNBIMRTestType = 39,
AMO_SetTestType = 40,
AMO_SwapTestType = 41,
AMO_FetchAndTestType = 42,
AMO_FetchOrTestType = 43,
AMO_FetchXorTestType = 44,
AMO_AndTestType = 45,
AMO_OrTestType = 46,
AMO_XorTestType = 47,
PingAllTestType = 48,
PutSignalTestType = 49,
WGPutSignalTestType = 50,
WAVEPutSignalTestType = 51,
PutSignalNBITestType = 52,
WGPutSignalNBITestType = 53,
WAVEPutSignalNBITestType = 54,
SignalFetchTestType = 55,
WGSignalFetchTestType = 56,
WAVESignalFetchTestType = 57,
TeamWGBarrierTestType = 58,
DefaultCTXGetTestType = 59,
DefaultCTXGetNBITestType = 60,
DefaultCTXPutTestType = 61,
DefaultCTXPutNBITestType = 62,
DefaultCTXPTestType = 63,
DefaultCTXGTestType = 64,
WAVEBarrierAllTestType = 65,
WGBarrierAllTestType = 66,
WAVESyncAllTestType = 67,
WGSyncAllTestType = 68,
TeamBarrierTestType = 69,
TeamWAVEBarrierTestType = 70,
TeamWAVESyncTestType = 71,
TeamWGSyncTestType = 72,
TeamCtxInfraTestSingleType = 73,
TeamCtxInfraTestBlockType = 74,
TeamCtxInfraTestOddEvenType = 75,
TeamAlltoallmemOnStreamTestType = 76,
BarrierAllOnStreamTestType = 77,
TeamBroadcastmemOnStreamTestType = 78,
GetmemOnStreamTestType = 79,
PutmemOnStreamTestType = 80,
PutmemSignalOnStreamTestType = 81,
SignalWaitUntilOnStreamTestType = 82,
FloodPutTestType = 83,
FloodPutNBITestType = 84,
FloodPTestType = 85,
FloodGetTestType = 86,
FloodGetNBITestType = 87,
FloodGTestType = 88,
};
enum OpType { PutType = 0, GetType = 1 };
typedef int ShmemContextType;
/******************************************************************************
* TESTER INTERFACE
*****************************************************************************/
class Tester {
public:
explicit Tester(TesterArguments args);
virtual ~Tester();
void execute();
static std::vector<Tester *> create(TesterArguments args);
protected:
virtual void resetBuffers(uint64_t size) = 0;
virtual void preLaunchKernel() {}
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
uint64_t size) = 0;
virtual void postLaunchKernel() {}
virtual void verifyResults(uint64_t size) = 0;
int num_msgs = 0;
int num_timed_msgs = 0;
int num_warps = 0;
int bw_factor = 1;
int device_id = 0;
int wall_clk_rate = 0; //in kilohertz
int wf_size = 0;
TesterArguments args;
TestType _type;
ShmemContextType _shmem_context = 8; // SHMEM_CTX_WP_PRIVATE
hipStream_t stream;
hipDeviceProp_t deviceProps;
long long int *timer = nullptr;
long long int *start_time = nullptr;
long long int *end_time = nullptr;
long long int min_start_time = 0;
long long int max_end_time = 0;
uint32_t num_timers = 0;
bool *verification_error;
protected:
bool _print_results = true;
private:
bool _print_header = true;
void print(uint64_t size);
void barrier();
double gpuCyclesToMicroseconds(long long int cycles);
double timerAvgInMicroseconds();
bool peLaunchesKernel();
hipEvent_t start_event;
hipEvent_t stop_event;
};
//TODO remove altogether? THere is a small difference in print format
#undef CHECK_HIP
#define CHECK_HIP(instr) do { \
hipError_t error = (instr); \
if (error != hipSuccess) { \
fprintf(stderr, "error: " #instr ": %s (%d) at %s:%d\n", \
hipGetErrorString(error), error, __FILE__, __LINE__); \
abort(); \
} \
} while(0)
#endif /* _TESTER_HPP */
+240
Просмотреть файл
@@ -0,0 +1,240 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "tester_arguments.hpp"
#include <cstdlib>
#include <iostream>
#include <rocshmem/rocshmem.hpp>
#include "tester.hpp"
using namespace rocshmem;
TesterArguments::TesterArguments(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg == "-t") {
i++;
num_threads = atoi(argv[i]);
} else if (arg == "-w") {
i++;
num_wgs = atoi(argv[i]);
} else if (arg == "-s") {
i++;
max_msg_size = atoll(argv[i]);
} else if (arg == "-a") {
i++;
algorithm = atoi(argv[i]);
} else if (arg == "-z") {
i++;
wg_size = atoi(argv[i]);
} else if (arg == "-c") {
i++;
coal_coef = atoi(argv[i]);
} else if (arg == "-o") {
i++;
op_type = atoi(argv[i]);
} else if (arg == "-ta") {
i++;
thread_access = atoi(argv[i]);
} else if (arg == "-x") {
i++;
shmem_context = atoi(argv[i]);
} else if (arg == "-m") {
int atomics_addr_mode = atoi(argv[i]);
if(atomics_addr_mode >= static_cast<int>(AddrMode::PerGrid) &&
atomics_addr_mode <= static_cast<int>(AddrMode::PerBlock)) {
addr_mode = static_cast<AddrMode>(atomics_addr_mode);
}
i++;
} else if (arg == "-n") {
i++;
loop = atoi(argv[i]);
loop_large = loop;
} else if (arg == "-nloop") {
i++;
loop = atoi(argv[i]);
} else if (arg == "-nlarge") {
i++;
loop_large = atoi(argv[i]);
} else if (arg == "-nskip") {
i++;
skip = atoi(argv[i]);
} else {
show_usage(argv[0]);
exit(-1);
}
}
TestType type = (TestType)algorithm;
switch (type) {
case AMO_FAddTestType:
case AMO_AddTestType:
case AMO_SetTestType:
case AMO_SwapTestType:
case AMO_FetchAndTestType:
case AMO_AndTestType:
case AMO_FetchOrTestType:
case AMO_OrTestType:
case AMO_FetchXorTestType:
case AMO_XorTestType:
case AMO_FCswapTestType:
case AMO_CswapTestType:
case AMO_FIncTestType:
case AMO_IncTestType:
case AMO_FetchTestType:
case BarrierAllTestType:
case WAVEBarrierAllTestType:
case WGBarrierAllTestType:
case TeamBarrierTestType:
case TeamWAVEBarrierTestType:
case TeamWGBarrierTestType:
case BarrierAllOnStreamTestType:
case SyncAllTestType:
case WAVESyncAllTestType:
case WGSyncAllTestType:
case TeamSyncTestType:
case SignalWaitUntilOnStreamTestType:
min_msg_size = 8;
max_msg_size = 8;
break;
case PingPongTestType:
case ShmemPtrTestType:
min_msg_size = 4;
max_msg_size = 4;
break;
case RandomAccessTestType:
case TeamAlltoallmemOnStreamTestType:
case TeamBroadcastmemOnStreamTestType:
min_msg_size = 4;
break;
case TeamFCollectTestType:
case TeamAllToAllTestType:
case TeamBroadcastTestType:
min_msg_size = 8;
break;
case TeamCtxInfraTestType:
case TeamCtxInfraTestSingleType:
case TeamCtxInfraTestBlockType:
case TeamCtxInfraTestOddEvenType:
max_msg_size = min_msg_size;
break;
case PutNBIMRTestType:
min_msg_size = max_msg_size;
break;
case PTestType:
case GTestType:
min_msg_size = 1;
max_msg_size = 1;
break;
case FloodPutTestType:
case FloodPutNBITestType:
case FloodPTestType:
case FloodGetTestType:
case FloodGetNBITestType:
case FloodGTestType:
min_msg_size = max_msg_size = 8;
break;
default:
break;
}
}
void TesterArguments::show_usage(std::string executable_name) {
std::cout << "Usage: " << executable_name << std::endl;
std::cout << "\t-t <number of rocshmem service threads>\n";
std::cout << "\t-w <number of workgroups>\n";
std::cout << "\t-s <maximum message size (in bytes)>\n";
std::cout << "\t-a <algorithm number to test>\n";
std::cout << "\t-z <WorkGroup Size>\n";
std::cout << "\t-c <Coalescing Coefficient>\n";
std::cout << "\t-o <Operation type for the random_access test>\n";
std::cout << "\t-ta <Number of Thread Accessing the communication>\n";
std::cout << "\t-x <shmem context>\n";
std::cout << "\t-m Atomics Address mode\n";
std::cout << "\t-n Set both loop and loop_large count\n";
std::cout << "\t-nloop Set loop count\n";
std::cout << "\t-nlarge Set loop_large count\n";
std::cout << "\t-nskip Set skip/warmup count\n";
}
void TesterArguments::get_arguments() {
numprocs = rocshmem_n_pes();
myid = rocshmem_my_pe();
TestType type = (TestType)algorithm;
// Check if test requires exactly 2 PEs
// Tests that support arbitrary number of PEs are excluded
bool requires_two_pes = true;
switch (type) {
// Collective/barrier tests - support any number of PEs
case BarrierAllTestType:
case WAVEBarrierAllTestType:
case WGBarrierAllTestType:
case SyncAllTestType:
case WAVESyncAllTestType:
case WGSyncAllTestType:
case TeamSyncTestType:
case TeamWAVESyncTestType:
case TeamWGSyncTestType:
case TeamAllToAllTestType:
case TeamFCollectTestType:
case TeamReductionTestType:
case TeamBroadcastTestType:
case PingAllTestType:
case TeamBarrierTestType:
case TeamWAVEBarrierTestType:
case TeamWGBarrierTestType:
case TeamCtxInfraTestBlockType:
case TeamCtxInfraTestOddEvenType:
// On-stream tests - support any number of PEs
case TeamAlltoallmemOnStreamTestType:
case BarrierAllOnStreamTestType:
case TeamBroadcastmemOnStreamTestType:
case GetmemOnStreamTestType:
case PutmemOnStreamTestType:
case PutmemSignalOnStreamTestType:
case SignalWaitUntilOnStreamTestType:
case FloodPutTestType:
case FloodPutNBITestType:
case FloodPTestType:
case FloodGetTestType:
case FloodGetNBITestType:
case FloodGTestType:
requires_two_pes = false;
break;
default:
break;
}
if (requires_two_pes && numprocs != 2) {
if (myid == 0) {
std::cerr << "This test requires exactly two processes, we have "
<< numprocs << "\n";
}
exit(-1);
}
}
+99
Просмотреть файл
@@ -0,0 +1,99 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _TESTER_ARGUMENTS_HPP_
#define _TESTER_ARGUMENTS_HPP_
#include <climits>
#include <cstdint>
#include <rocshmem/rocshmem.hpp>
#include <string>
#include <iostream>
enum TeamSplitType {
ROCSHMEM_TEST_TEAM_DUP = 0, // Dup parent team
ROCSHMEM_TEST_TEAM_SINGLE, // each PE will be its own team
ROCSHMEM_TEST_TEAM_BLOCK, // split parent into two halfs
ROCSHMEM_TEST_TEAM_ODDEVEN, // odd-even splitting
};
/*-----------------------------------------
* Atomics Addressing modes (contention model)
*-----------------------------------------*/
enum class AddrMode : int {
PerGrid, // all WGs -> same address
PerBlock, // each WG -> its own address (default)
};
class TesterArguments {
public:
TesterArguments(int argc, char *argv[]);
/**
* Initialize rocshmem members
* Valid after rocshmem_init function called.
*/
void get_arguments();
private:
/**
* Output method which displays available command line options
*/
static void show_usage(std::string executable_name);
public:
/**
* Arguments obtained from command line
*/
unsigned num_wgs = 1;
unsigned num_threads = 1;
unsigned algorithm = 0;
size_t min_msg_size = 1;
size_t max_msg_size = 1 << 20;
unsigned wg_size = 64;
unsigned thread_access = 64;
unsigned coal_coef = 64;
unsigned op_type = 0;
unsigned shmem_context = rocshmem::ROCSHMEM_CTX_WG_PRIVATE;
AddrMode addr_mode = AddrMode::PerBlock;
/**
* Arguments obtained from rocshmem
*/
int numprocs = INT_MAX;
int myid = INT_MAX;
/**
* Defaults tester values
*/
int loop = 10;
int skip = 10;
int loop_large = 10;
size_t large_message_size = 32768;
TeamSplitType team_type = ROCSHMEM_TEST_TEAM_DUP;
};
#endif
+46
Просмотреть файл
@@ -0,0 +1,46 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _VERIFY_RESULTS_KERNELS_HPP_
#define _VERIFY_RESULTS_KERNELS_HPP_
namespace rocshmem {
static __global__ void verify_results_kernel_char(char *source, char *dest, size_t buf_size,
bool *verification_error) {
int idx = get_flat_id();
if (idx >= buf_size) {
return;
}
if (dest[idx] != source[idx]) {
*verification_error = true;
}
}
}
#endif /* _VERIFY_RESULTS_KERNELS_HPP_ */
+165
Просмотреть файл
@@ -0,0 +1,165 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "wavefront_primitives.hpp"
#include <rocshmem/rocshmem.hpp>
#include <numeric>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void WaveFrontPrimitiveTest(int loop, int skip,
long long int *start_time,
long long int *end_time, char *source,
char *dest, size_t size, TestType type,
ShmemContextType ctx_type,
int wf_size) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
// Calculate start index for each wavefront
int wf_id = get_flat_block_id() / wf_size;
int wg_offset = wg_id * ((get_flat_block_size() - 1 ) / wf_size + 1);
int idx = wf_id + wg_offset;
size_t offset = size * idx;
source += offset;
dest += offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
// Ensures all RMA calls from the skip loops are completed
rocshmem_ctx_quiet(ctx);
__syncthreads();
if (is_thread_zero_in_wave()) {
start_time[idx] = wall_clock64();
}
}
switch (type) {
case WAVEGetTestType:
rocshmem_ctx_getmem_wave(ctx, dest, source, size, 1);
break;
case WAVEGetNBITestType:
rocshmem_ctx_getmem_nbi_wave(ctx, dest, source, size, 1);
break;
case WAVEPutTestType:
rocshmem_ctx_putmem_wave(ctx, dest, source, size, 1);
break;
case WAVEPutNBITestType:
rocshmem_ctx_putmem_nbi_wave(ctx, dest, source, size, 1);
break;
default:
break;
}
}
rocshmem_ctx_quiet(ctx);
if (is_thread_zero_in_wave()) {
end_time[idx] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
WaveFrontPrimitiveTester::WaveFrontPrimitiveTester(TesterArguments args)
: Tester(args) {
size_t buff_size = args.max_msg_size * args.num_wgs * num_warps;
source = (char *)rocshmem_malloc(buff_size);
dest = (char *)rocshmem_malloc(buff_size);
if (source == nullptr || dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source << ", dest: " << dest << std::endl;
if (source) {
rocshmem_free(source);
}
if (dest) {
rocshmem_free(dest);
}
rocshmem_global_exit(1);
}
for(size_t i = 0; i < buff_size; i++) {
source[i] = static_cast<char>('a' + i % 26);
}
}
WaveFrontPrimitiveTester::~WaveFrontPrimitiveTester() {
rocshmem_free(source);
rocshmem_free(dest);
}
void WaveFrontPrimitiveTester::resetBuffers(size_t size) {
size_t buff_size = size * args.num_wgs * num_warps;
memset(dest, '1', buff_size);
}
void WaveFrontPrimitiveTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(WaveFrontPrimitiveTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
source, dest, size, _type, _shmem_context,
wf_size);
num_msgs = (loop + args.skip) * gridSize.x * num_warps;
num_timed_msgs = loop * gridSize.x * num_warps;
}
void WaveFrontPrimitiveTester::verifyResults(size_t size) {
int check_id = (_type == WAVEGetTestType || _type == WAVEGetNBITestType)
? 0
: 1;
if (args.myid == check_id) {
size_t buff_size = size * args.num_wgs * num_warps;
size_t verify_wg_size = std::min((size_t) 1024, buff_size);
size_t verify_num_wgs = buff_size / verify_wg_size;
hipLaunchKernelGGL(verify_results_kernel_char, verify_num_wgs, verify_wg_size, 0, stream,
source, dest, buff_size, verification_error);
CHECK_HIP(hipStreamSynchronize(stream));
if (*verification_error) {
for (size_t i = 0; i < buff_size; i++) {
if (dest[i] != source[i]) {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected "
<< source[i] << std::endl;
exit(-1);
}
}
*verification_error = false;
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _WAVE_LEVEL_PRIMITIVE_TEST_HPP_
#define _WAVE_LEVEL_PRIMITIVE_TEST_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class WaveFrontPrimitiveTester : public Tester {
public:
explicit WaveFrontPrimitiveTester(TesterArguments args);
virtual ~WaveFrontPrimitiveTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *source = nullptr;
char *dest = nullptr;
};
#endif
+160
Просмотреть файл
@@ -0,0 +1,160 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "workgroup_primitives.hpp"
#include <rocshmem/rocshmem.hpp>
#include <numeric>
using namespace rocshmem;
/******************************************************************************
* DEVICE TEST KERNEL
*****************************************************************************/
__global__ void WorkGroupPrimitiveTest(int loop, int skip,
long long int *start_time,
long long int *end_time, char *source,
char *dest, size_t size, TestType type,
ShmemContextType ctx_type) {
__shared__ rocshmem_ctx_t ctx;
int wg_id = get_flat_grid_id();
rocshmem_wg_ctx_create(ctx_type, &ctx);
// Calculate start index for each work group
size_t offset = size * wg_id;
source += offset;
dest += offset;
for (int i = 0; i < loop + skip; i++) {
if (i == skip) {
// Ensures all RMA calls from the skip loops are completed
if (is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
}
__syncthreads();
start_time[wg_id] = wall_clock64();
}
switch (type) {
case WGGetTestType:
rocshmem_ctx_getmem_wg(ctx, dest, source, size, 1);
break;
case WGGetNBITestType:
rocshmem_ctx_getmem_nbi_wg(ctx, dest, source, size, 1);
break;
case WGPutTestType:
rocshmem_ctx_putmem_wg(ctx, dest, source, size, 1);
break;
case WGPutNBITestType:
rocshmem_ctx_putmem_nbi_wg(ctx, dest, source, size, 1);
break;
default:
break;
}
}
if (is_thread_zero_in_block()) {
rocshmem_ctx_quiet(ctx);
end_time[wg_id] = wall_clock64();
}
rocshmem_wg_ctx_destroy(&ctx);
}
/******************************************************************************
* HOST TESTER CLASS METHODS
*****************************************************************************/
WorkGroupPrimitiveTester::WorkGroupPrimitiveTester(TesterArguments args)
: Tester(args) {
size_t buff_size = args.max_msg_size * args.num_wgs;
source = (char *)rocshmem_malloc(buff_size);
dest = (char *)rocshmem_malloc(buff_size);
if (source == nullptr || dest == nullptr) {
std::cerr << "Error allocating memory from symmetric heap" << std::endl;
std::cerr << "source: " << source << ", dest: " << dest << std::endl;
if (source) {
rocshmem_free(source);
}
if (dest) {
rocshmem_free(dest);
}
rocshmem_global_exit(1);
}
for(size_t i = 0; i < buff_size; i++) {
source[i] = static_cast<char>('a' + i % 26);
}
}
WorkGroupPrimitiveTester::~WorkGroupPrimitiveTester() {
rocshmem_free(source);
rocshmem_free(dest);
}
void WorkGroupPrimitiveTester::resetBuffers(size_t size) {
size_t buff_size = size * args.num_wgs;
memset(dest, '1', buff_size);
}
void WorkGroupPrimitiveTester::launchKernel(dim3 gridSize, dim3 blockSize,
int loop, size_t size) {
size_t shared_bytes = 0;
hipLaunchKernelGGL(WorkGroupPrimitiveTest, gridSize, blockSize, shared_bytes,
stream, loop, args.skip, start_time, end_time,
source, dest, size, _type, _shmem_context);
num_msgs = (loop + args.skip) * gridSize.x;
num_timed_msgs = loop * gridSize.x;
}
void WorkGroupPrimitiveTester::verifyResults(size_t size) {
int check_id = (_type == WGGetTestType || _type == WGGetNBITestType)
? 0
: 1;
if (args.myid == check_id) {
size_t buff_size = size * args.num_wgs;
size_t verify_wg_size = std::min((size_t) 1024, buff_size);
size_t verify_num_wgs = buff_size / verify_wg_size;
hipLaunchKernelGGL(verify_results_kernel_char, verify_num_wgs, verify_wg_size, 0, stream,
source, dest, buff_size, verification_error);
CHECK_HIP(hipStreamSynchronize(stream));
if (*verification_error) {
for (size_t i = 0; i < buff_size; i++) {
if (dest[i] != source[i]) {
std::cerr << "Data validation error at idx " << i << std::endl;
std::cerr << " Got " << dest[i] << ", Expected "
<< source[i] << std::endl;
exit(-1);
}
}
*verification_error = false;
}
}
}
+50
Просмотреть файл
@@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*****************************************************************************/
#ifndef _EXTENDED_PRIMITIVES_HPP_
#define _EXTENDED_PRIMITIVES_HPP_
#include "tester.hpp"
/******************************************************************************
* HOST TESTER CLASS
*****************************************************************************/
class WorkGroupPrimitiveTester : public Tester {
public:
explicit WorkGroupPrimitiveTester(TesterArguments args);
virtual ~WorkGroupPrimitiveTester();
protected:
virtual void resetBuffers(size_t size) override;
virtual void launchKernel(dim3 gridSize, dim3 blockSize, int loop,
size_t size) override;
virtual void verifyResults(size_t size) override;
char *source = nullptr;
char *dest = nullptr;
};
#endif