Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ The CUDA build is not enabled by default. If you are interested in building the

export NV_CUDA=Y

To build AMD-GPU-enabled code, you will also need the HIP compiler.

The HIP build is not enabled by default. If you are interested in building the GPU-accelerated libraries, set::

export AMD_HIP=Y

There is also support for OpenMP Offload and OpenACC builds, by setting either ``AMD_CXX`` or ``NV_CXX``, but it is still experimental.

Provided files and their usage
Expand Down
39 changes: 33 additions & 6 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ ifneq ($(SKBB_ENABLE_ACC_NV),)
# CUDA version
SKBB_ENABLE_ACC_NV_BINS := 1
NV_CXX := nvcc
NV_CXXFLAGS := -DCUDA
NV_CXXFLAGS := -DSKBB_CUDA
NV_CXXFLAGS += -O3 --use_fast_math -std=c++17 -I. $(OPT) -Xcompiler -fPIC
NV_CXXFLAGS += -arch=all-major
else
Expand All @@ -75,14 +75,24 @@ ifneq ($(SKBB_ENABLE_ACC_NV),)
endif
endif

ifneq ($(AMD_CXX),)
ifneq ($(SKBB_ENABLE_ACC_AMD),)
ifneq ($(SKBB_ENABLE_ACC_AMD),)
ifneq ($(AMD_HIP),)
# HIP version
SKBB_ENABLE_ACC_AMD_BINS := 1
AMD_CXX := hipcc
AMD_CXXFLAGS := -DSKBB_HIP
AMD_CXXFLAGS += -O3 -ffast-math -std=c++17 -I. $(OPT) -fPIC
AMD_CXXFLAGS += --offload-arch=gfx1100,gfx1101,gfx1102,gfx1103,gfx1030,gfx1031,gfx90a,gfx942
AMD_SO_LDDFLAGS += -shared -fgpu-rdc --hip-link
else
ifneq ($(AMD_CXX),)
SKBB_ENABLE_ACC_AMD_BINS := 1
AMD_CXXFLAGS += -fopenmp -fopenmp-offload-mandatory -DOMPGPU=1
AMD_CXXFLAGS += -O3 -ffast-math -std=c++17 -I. $(OPT) -fPIC
AMD_LDFLAGS += -shared -fopenmp
AMD_CXXFLAGS += --offload-arch=gfx1100,gfx1101,gfx1102,gfx1103,gfx1030,gfx1031,gfx90a,gfx942
AMD_LDFLAGS += --offload-arch=gfx1100,gfx1101,gfx1102,gfx1103,gfx1030,gfx1031,gfx90a,gfx942
endif
endif
endif

Expand Down Expand Up @@ -246,22 +256,32 @@ endif
ifdef SKBB_ENABLE_ACC_AMD
SKBB_OBJS += permanova_acc_amd.o


permanova_dyn_acc_amd.h: distance/permanova_dyn_impl.hpp
./tools/generate_permanova_dyn.py acc_amd api_h > $@
permanova_dyn_acc_amd.cpp: distance/permanova_dyn_impl.hpp permanova_dyn_acc_amd.h
./tools/generate_permanova_dyn.py acc_amd api > $@
permanova_acc_amd.cpp: distance/permanova_dyn_impl.hpp permanova_dyn_acc_amd.h
./tools/generate_permanova_dyn.py acc_amd indirect > $@

permanova_acc_amd.o: permanova_acc_amd.cpp permanova_dyn_acc_amd.h distance/permanova_dyn.hpp util/skbb_dl.cpp
$(CXX) $(CXXFLAGS) -DSKBB_ACC_NM=skbb_acc_amd -c $< -o $@

ifneq ($(AMD_HIP),)
# HIP version
permanova_dyn_acc_amd.hip: distance/permanova_dyn_impl.hpp permanova_dyn_acc_amd.h
./tools/generate_permanova_dyn.py acc_amd api > $@
permanova_dyn_acc_amd.o: permanova_dyn_acc_amd.hip distance/permanova_dyn.hpp distance/permanova_dyn_impl.hpp
$(AMD_CXX) $(AMD_CXXFLAGS) -DSKBB_ACC_NM=skbb_acc_amd -c $< -o $@

else
# OpenMP Target version
permanova_dyn_acc_amd.cpp: distance/permanova_dyn_impl.hpp permanova_dyn_acc_amd.h
./tools/generate_permanova_dyn.py acc_amd api > $@
permanova_dyn_acc_amd.o: permanova_dyn_acc_amd.cpp distance/permanova_dyn.hpp distance/permanova_dyn_impl.hpp
$(AMD_CXX) $(AMD_CXXFLAGS) -DSKBB_ACC_NM=skbb_acc_amd -c $< -o $@

endif

endif




Expand Down Expand Up @@ -317,8 +337,15 @@ ifdef SKBB_ENABLE_ACC_AMD_BINS

SKBB_SHLIBS += libskbb_acc_amd.so

ifneq ($(AMD_HIP),)
#HIP version
libskbb_acc_amd.so: skbb_accapi_dyn_acc_amd.o permanova_dyn_acc_amd.o
$(AMD_CXX) $(AMD_SO_LDDFLAGS) -o $@ skbb_accapi_dyn_acc_amd.o permanova_dyn_acc_amd.o
else
#OpenMP Target version
libskbb_acc_amd.so: skbb_accapi_dyn_acc_amd.o permanova_dyn_acc_amd.o
$(AMD_CXX) $(AMD_LDFLAGS) $(SO_LDDFLAGS) -o $@ skbb_accapi_dyn_acc_amd.o permanova_dyn_acc_amd.o
endif

endif

Expand Down
57 changes: 40 additions & 17 deletions src/distance/permanova_dyn_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,60 @@
#include <cstdlib>
#include <algorithm>

#if defined(CUDA)
#if defined(SKBB_CUDA)

#include <cuda.h>
#include <cuda_runtime.h>
#include <stdexcept>

#elif !(defined(_OPENACC) || defined(OMPGPU))
#elif defined(SKBB_HIP)

#include <omp.h>
#include <hip/hip_runtime.h>
#include <hip/hip_runtime_api.h>
#include <stdexcept>

#elif defined(_OPENACC)

#include <openacc.h>

#elif !(defined(_OPENACC) || defined(OMPGPU))

#include <omp.h>

#define SKBB_CPU Y

#endif

static inline int pmn_get_max_parallelism_T() {
#if defined(CUDA)
#if defined(SKBB_CPU)
// No good reason to do more than max threads
// (but use 2x to reduce thread spawning overhead)
// but we do use 16x blocking, so account for that, too
return 2*omp_get_max_threads()*16;

#elif defined(SKBB_CUDA)
int deviceID;
cudaDeviceProp props;

cudaGetDevice(&deviceID);
if (cudaGetDevice(&deviceID)!=cudaSuccess) return 4000; // should never get in here, but just in case
cudaGetDeviceProperties(&props, deviceID);

// GPUs typically need at least 64 blocks per SM to be fully loaded
// We want a few multiples of that to deal with unbalanced load
// Most permanovas are multiple of 100, so double that makes a good constant
return 200*props.multiProcessorCount;

#elif !(defined(_OPENACC) || defined(OMPGPU))
// No good reason to do more than max threads
// (but use 2x to reduce thread spawning overhead)
// but we do use 16x blocking, so account for that, too
return 2*omp_get_max_threads()*16;
#elif defined(SKBB_HIP)
int deviceID = 0;
hipDeviceProp_t props;

if (hipGetDevice(&deviceID)!=hipSuccess) return 4000; // should never get in here, but just in case
if (hipGetDeviceProperties(&props, deviceID)!=hipSuccess) throw std::runtime_error("hipGetDeviceProperties failed");

// GPUs typically need at least 64 blocks per SM to be fully loaded
// We want a few multiples of that to deal with unbalanced load
// Most permanovas are multiple of 100, so double that makes a good constant
return 200*props.multiProcessorCount;

#else
// 1k is enough for consumer-grade GPUs
Expand Down Expand Up @@ -122,7 +143,7 @@ static inline void pmn_f_stat_sW_block(
// inv_group_sizes is an array of size maxel(groupings)
// Results in group_sWs, and array of size n_grouping_dims

#if !(defined(_OPENACC) || defined(OMPGPU) || defined(CUDA))
#if defined(SKBB_CPU)

template<class TFloat>
static inline void pmn_f_stat_sW_cpu(
Expand Down Expand Up @@ -187,7 +208,7 @@ static inline void pmn_f_stat_sW_cpu(
}
}

#elif defined(CUDA)
#elif (defined(SKBB_CUDA) || defined(SKBB_HIP))

template<class TFloat>
__global__ void pmn_f_stat_sW_cuda_one(
Expand Down Expand Up @@ -273,15 +294,19 @@ __global__ void pmn_f_stat_sW_cuda_one(
}

template<class TFloat>
static inline void pmn_f_stat_sW_cuda(
static inline void pmn_f_stat_sW_gpu(
const uint32_t n_dims,
const TFloat * mat,
const uint32_t n_grouping_dims,
const uint32_t *groupings,
const TFloat *inv_group_sizes,
TFloat *group_sWs) {
pmn_f_stat_sW_cuda_one<TFloat><<<n_grouping_dims,128>>>(n_dims,mat,n_grouping_dims,groupings,inv_group_sizes,group_sWs);
cudaDeviceSynchronize();
#if defined(SKBB_CUDA)
if (cudaDeviceSynchronize()!=cudaSuccess) throw std::runtime_error("cudaDeviceSynchronize failed");
#else
if (hipDeviceSynchronize()!=hipSuccess) throw std::runtime_error("hipDeviceSynchronize failed");
#endif
}
#else

Expand Down Expand Up @@ -332,10 +357,8 @@ static inline void pmn_f_stat_sW_T(
const uint32_t *groupings,
const TFloat *inv_group_sizes,
TFloat *group_sWs) {
#if !(defined(_OPENACC) || defined(OMPGPU) || defined(CUDA))
#if defined(SKBB_CPU)
pmn_f_stat_sW_cpu(n_dims, mat, n_grouping_dims, groupings, inv_group_sizes, group_sWs);
#elif defined(CUDA)
pmn_f_stat_sW_cuda(n_dims, mat, n_grouping_dims, groupings, inv_group_sizes, group_sWs);
#else
pmn_f_stat_sW_gpu(n_dims, mat, n_grouping_dims, groupings, inv_group_sizes, group_sWs);
#endif
Expand Down
56 changes: 41 additions & 15 deletions src/util/skbb_accapi_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@
#include "util/skbb_accapi.hpp"
#include <cstdlib>

#if defined(CUDA)
#if defined(SKBB_CUDA)

#include <cuda_runtime_api.h>
#include <stdexcept>

#elif defined(SKBB_HIP)

#include <hip/hip_runtime.h>
#include <hip/hip_runtime_api.h>
#include <stdexcept>

#elif defined(OMPGPU)

Expand All @@ -38,11 +45,16 @@
#endif

static inline bool acc_found_gpu_T() {
#if defined(CUDA)
#if defined(SKBB_CUDA)
int deviceCount;
cudaError_t error = cudaGetDeviceCount(&deviceCount);
if (error != cudaSuccess) return false;
return deviceCount != 0;
#elif defined(SKBB_HIP)
int deviceCount;
hipError_t error = hipGetDeviceCount(&deviceCount);
if (error != hipSuccess) return false;
return deviceCount != 0;
#elif defined(OMPGPU)
return omp_get_num_devices() > 0;
#elif defined(_OPENACC)
Expand All @@ -54,16 +66,18 @@ static inline bool acc_found_gpu_T() {

// is the implementation async, and need the alt structures?
static inline bool acc_need_alt_T() {
#if defined(_OPENACC) || defined(OMPGPU) || defined(CUDA)
#if defined(_OPENACC) || defined(OMPGPU) || defined(SKBB_CUDA) || defined(SKBB_HIP)
return true;
#else
return false;
#endif
}

static inline void acc_wait_T() {
#if defined(CUDA)
cudaDeviceSynchronize();
#if defined(SKBB_CUDA)
if (cudaDeviceSynchronize()!=cudaSuccess) throw std::runtime_error("cudaDeviceSynchronize failed");
#elif defined(SKBB_HIP)
if (hipDeviceSynchronize()!=hipSuccess) throw std::runtime_error("hipDeviceSynchronize failed");
#elif defined(OMPGPU)
// TODO: Change if we ever implement async in OMPGPU
#elif defined(_OPENACC)
Expand All @@ -76,8 +90,10 @@ static inline void acc_create_buf_T(
TNum* buf_host,
TNum** buf_device,
uint64_t size) {
#if defined(CUDA)
cudaMalloc((void**)buf_device, sizeof(TNum) * size);
#if defined(SKBB_CUDA)
if (cudaMalloc((void**)buf_device, sizeof(TNum) * size)!=cudaSuccess) throw std::runtime_error("cudaMalloc failed");
#elif defined(SKBB_HIP)
if (hipMalloc((void**)buf_device, sizeof(TNum) * size)!=hipSuccess) throw std::runtime_error("hipMalloc failed");
#elif defined(OMPGPU)
#pragma omp target enter data map(alloc:buf_host[0:size])
*buf_device = buf_host;
Expand All @@ -94,9 +110,12 @@ static inline void acc_copyin_buf_T(
TNum* buf_host,
TNum** buf_device,
uint64_t size) {
#if defined(CUDA)
cudaMalloc((void**)buf_device, sizeof(TNum) * size);
cudaMemcpy(*buf_device, buf_host, sizeof(TNum) * size, cudaMemcpyHostToDevice);
#if defined(SKBB_CUDA)
if (cudaMalloc((void**)buf_device, sizeof(TNum) * size)!=cudaSuccess) throw std::runtime_error("cudaMalloc failed");
if (cudaMemcpy(*buf_device, buf_host, sizeof(TNum) * size, cudaMemcpyHostToDevice)!=cudaSuccess) throw std::runtime_error("cudaMemcpy failed");
#elif defined(SKBB_HIP)
if (hipMalloc((void**)buf_device, sizeof(TNum) * size)!=hipSuccess) throw std::runtime_error("hipMalloc failed");
if (hipMemcpy(*buf_device, buf_host, sizeof(TNum) * size, hipMemcpyHostToDevice)!=hipSuccess) throw std::runtime_error("hipMemcpy failed");
#elif defined(OMPGPU)
#pragma omp target enter data map(to:buf_host[0:size])
*buf_device = buf_host;
Expand All @@ -113,8 +132,10 @@ static inline void acc_update_device_T(
TNum *buf_host,
TNum *buf_device,
uint64_t start, uint64_t end) {
#if defined(CUDA)
cudaMemcpy(buf_device+start, buf_host+start, sizeof(TNum) * (end-start), cudaMemcpyHostToDevice);
#if defined(SKBB_CUDA)
if (cudaMemcpy(buf_device+start, buf_host+start, sizeof(TNum) * (end-start), cudaMemcpyHostToDevice)!=cudaSuccess) throw std::runtime_error("cudaMemcpy failed");
#elif defined(SKBB_HIP)
if (hipMemcpy(buf_device+start, buf_host+start, sizeof(TNum) * (end-start), hipMemcpyHostToDevice)!=hipSuccess) throw std::runtime_error("hipMemcpy failed");
#elif defined(OMPGPU)
// assert buf_host==buf_device
#pragma omp target update to(buf_host[start:end])
Expand All @@ -129,9 +150,12 @@ static inline void acc_copyout_buf_T(
TNum *buf_host,
TNum *buf_device,
uint64_t size) {
#if defined(CUDA)
cudaMemcpy(buf_host, buf_device, sizeof(TNum) * size, cudaMemcpyDeviceToHost);
#if defined(SKBB_CUDA)
if (cudaMemcpy(buf_host, buf_device, sizeof(TNum) * size, cudaMemcpyDeviceToHost)!=cudaSuccess) throw std::runtime_error("cudaMemcpy failed");
cudaFree(buf_device);
#elif defined(SKBB_HIP)
if (hipMemcpy(buf_host, buf_device, sizeof(TNum) * size, hipMemcpyDeviceToHost)!=hipSuccess) throw std::runtime_error("hipMemcpy failed");
if (hipFree(buf_device)!=hipSuccess) {} // ignore any errors, not critical
#elif defined(OMPGPU)
// assert buf_host==buf_device
#pragma omp target exit data map(from:buf_device[0:size])
Expand All @@ -145,8 +169,10 @@ template<class TNum>
static inline void acc_destroy_buf_T(
TNum *buf_device,
uint64_t size) {
#if defined(CUDA)
#if defined(SKBB_CUDA)
cudaFree(buf_device);
#elif defined(SKBB_HIP)
if (hipFree(buf_device)!=hipSuccess) {} // ignore any errors, not critical
#elif defined(OMPGPU)
#pragma omp target exit data map(delete:buf_device[0:size])
#elif defined(_OPENACC)
Expand Down
Loading