SWDEV-451170 - Merge PR#3432 to amd-staging
Change-Id: I210bced4e626fc2ac464b80172132481b882cf63
Αυτή η υποβολή περιλαμβάνεται σε:
υποβλήθηκε από
Julia Jiang
γονέας
c0d0504d2d
υποβολή
fee13d6a3f
@@ -0,0 +1,23 @@
|
||||
# Terms used in HIP Documentation
|
||||
|
||||
- host, host cpu : Executes the HIP runtime API and is capable of initiating kernel launches to one or more devices.
|
||||
- default device : Each host thread maintains a "default device".
|
||||
Most HIP runtime APIs (including memory allocation, copy commands, kernel launches) do not use accept an explicit device
|
||||
argument but instead implicitly use the default device.
|
||||
The default device can be set with hipSetDevice.
|
||||
|
||||
- "active host thread" - the thread which is running the HIP APIs.
|
||||
|
||||
- HIP-Clang - Heterogeneous AMDGPU Compiler, with its capability to compile HIP programs on AMD platform (https://github.com/RadeonOpenCompute/llvm-project).
|
||||
|
||||
- clr - a repository for AMD Common Language Runtime, contains source codes for AMD's compute languages runtimes: HIP and OpenCL�.
|
||||
clr (https://github.com/ROCm/clr) contains the following three parts,
|
||||
hipamd: contains implementation of HIP language on AMD platform.
|
||||
rocclr: contains common runtime used in HIP and OpenCL�, which provides virtual device interfaces that compute runtimes interact with different backends such as ROCr on Linux or PAL on Windows.
|
||||
opencl: contains implementation of OpenCL� on AMD platform.
|
||||
|
||||
- hipify tools - tools to convert CUDA code to portable C++ code (https://github.com/ROCm/HIPIFY).
|
||||
|
||||
- hipconfig - tool to report various configuration properties of the target platform.
|
||||
|
||||
- nvcc = nvcc compiler, do not capitalize.
|
||||
Το diff αρχείου καταστέλλεται επειδή είναι πολύ μεγάλο
Φόρτωση Διαφορών
@@ -0,0 +1,38 @@
|
||||
# Table Comparing Syntax for Different Compute APIs
|
||||
|
||||
|Term|CUDA|HIP|OpenCL|
|
||||
|---|---|---|---|
|
||||
|Device|`int deviceId`|`int deviceId`|`cl_device`|
|
||||
|Queue|`cudaStream_t`|`hipStream_t`|`cl_command_queue`|
|
||||
|Event|`cudaEvent_t`|`hipEvent_t`|`cl_event`|
|
||||
|Memory|`void *`|`void *`|`cl_mem`|
|
||||
|||||
|
||||
| |grid|grid|NDRange|
|
||||
| |block|block|work-group|
|
||||
| |thread|thread|work-item|
|
||||
| |warp|warp|sub-group|
|
||||
|||||
|
||||
|Thread-<br>index | threadIdx.x | threadIdx.x | get_local_id(0) |
|
||||
|Block-<br>index | blockIdx.x | blockIdx.x | get_group_id(0) |
|
||||
|Block-<br>dim | blockDim.x | blockDim.x | get_local_size(0) |
|
||||
|Grid-dim | gridDim.x | gridDim.x | get_num_groups(0) |
|
||||
|||||
|
||||
|Device Kernel|`__global__`|`__global__`|`__kernel`|
|
||||
|Device Function|`__device__`|`__device__`|Implied in device compilation|
|
||||
|Host Function|`__host_` (default)|`__host_` (default)|Implied in host compilation|
|
||||
|Host + Device Function|`__host__` `__device__`|`__host__` `__device__`| No equivalent|
|
||||
|Kernel Launch|`<<< >>>`|`hipLaunchKernel`/`hipLaunchKernelGGL`/`<<< >>>`|`clEnqueueNDRangeKernel`|
|
||||
||||||
|
||||
|Global Memory|`__global__`|`__global__`|`__global`|
|
||||
|Group Memory|`__shared__`|`__shared__`|`__local`|
|
||||
|Constant|`__constant__`|`__constant__`|`__constant`|
|
||||
||||||
|
||||
||`__syncthreads`|`__syncthreads`|`barrier(CLK_LOCAL_MEMFENCE)`|
|
||||
|Atomic Builtins|`atomicAdd`|`atomicAdd`|`atomic_add`|
|
||||
|Precise Math|`cos(f)`|`cos(f)`|`cos(f)`|
|
||||
|Fast Math|`__cos(f)`|`__cos(f)`|`native_cos(f)`|
|
||||
|Vector|`float4`|`float4`|`float4`|
|
||||
|
||||
### Notes
|
||||
The indexing functions (starting with `thread-index`) show the terminology for a 1D grid. Some APIs use reverse order of xyz / 012 indexing for 3D grids.
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
# Frequently asked questions
|
||||
|
||||
## What APIs and features does HIP support?
|
||||
HIP provides the following:
|
||||
- Devices (hipSetDevice(), hipGetDeviceProperties(), etc.)
|
||||
- Memory management (hipMalloc(), hipMemcpy(), hipFree(), etc.)
|
||||
- Streams (hipStreamCreate(),hipStreamSynchronize(), hipStreamWaitEvent(), etc.)
|
||||
- Events (hipEventRecord(), hipEventElapsedTime(), etc.)
|
||||
- Kernel launching (hipLaunchKernel/hipLaunchKernelGGL is the preferred way of launching kernels. hipLaunchKernelGGL is a standard C/C++ macro that can serve as an alternative way to launch kernels, replacing the CUDA triple-chevron (<<< >>>) syntax).
|
||||
- HIP Module API to control when adn how code is loaded.
|
||||
- CUDA-style kernel coordinate functions (threadIdx, blockIdx, blockDim, gridDim)
|
||||
- Cross-lane instructions including shfl, ballot, any, all
|
||||
- Most device-side math built-ins
|
||||
- Error reporting (hipGetLastError(), hipGetErrorString())
|
||||
|
||||
The HIP API documentation describes each API and its limitations, if any, compared with the equivalent CUDA API.
|
||||
|
||||
## What is not supported?
|
||||
|
||||
### Runtime/Driver API features
|
||||
At a high-level, the following features are not supported:
|
||||
- Textures (partial support available)
|
||||
- Dynamic parallelism (CUDA 5.0)
|
||||
- Graphics interoperability with OpenGL or Direct3D
|
||||
- CUDA IPC Functions (Under Development)
|
||||
- CUDA array, mipmappedArray and pitched memory
|
||||
- Queue priority controls
|
||||
|
||||
See the [API Support Table](https://github.com/ROCm/HIPIFY/blob/amd-staging/docs/tables/CUDA_Runtime_API_functions_supported_by_HIP.md) for more detailed information.
|
||||
|
||||
### Kernel language features
|
||||
- C++-style device-side dynamic memory allocations (free, new, delete) (CUDA 4.0)
|
||||
- Virtual functions, indirect functions and try/catch (CUDA 4.0)
|
||||
- `__prof_trigger`
|
||||
- PTX assembly (CUDA 4.0). HIP-Clang supports inline GCN assembly.
|
||||
- Several kernel features are under development. See the {doc}`/reference/kernel_language` for more information.
|
||||
|
||||
|
||||
## Is HIP a drop-in replacement for CUDA?
|
||||
No. HIP provides porting tools which do most of the work to convert CUDA code into portable C++ code that uses the HIP APIs.
|
||||
Most developers will port their code from CUDA to HIP and then maintain the HIP version.
|
||||
HIP code provides the same performance as native CUDA code, plus the benefits of running on AMD platforms.
|
||||
|
||||
## What specific version of CUDA does HIP support?
|
||||
HIP APIs and features do not map to a specific CUDA version. HIP provides a strong subset of the functionality provided in CUDA, and the hipify tools can scan code to identify any unsupported CUDA functions - this is useful for identifying the specific features required by a given application.
|
||||
|
||||
However, we can provide a rough summary of the features included in each CUDA SDK and the support level in HIP. Each bullet below lists the major new language features in each CUDA release and then indicate which are supported/not supported in HIP:
|
||||
|
||||
- CUDA 4.0 and earlier :
|
||||
- HIP supports CUDA 4.0 except for the limitations described above.
|
||||
- CUDA 5.0 :
|
||||
- Dynamic Parallelism (not supported)
|
||||
- cuIpc functions (under development).
|
||||
- CUDA 6.0 :
|
||||
- Managed memory (under development)
|
||||
- CUDA 6.5 :
|
||||
- __shfl intriniscs (supported)
|
||||
- CUDA 7.0 :
|
||||
- Per-thread default streams (supported)
|
||||
- C++11 (Hip-Clang supports all of C++11, all of C++14 and some C++17 features)
|
||||
- CUDA 7.5 :
|
||||
- float16 (supported)
|
||||
- CUDA 8.0 :
|
||||
- Page Migration including cudaMemAdvise, cudaMemPrefetch, other cudaMem* APIs(not supported)
|
||||
- CUDA 9.0 :
|
||||
- Cooperative Launch, Surface Object Management, Version Management
|
||||
|
||||
## What libraries does HIP support?
|
||||
HIP includes growing support for the four key math libraries using hipBlas, hipFFt, hipRAND and hipSPARSE, as well as MIOpen for machine intelligence applications.
|
||||
These offer pointer-based memory interfaces (as opposed to opaque buffers) and can be easily interfaced with other HIP applications.
|
||||
The hip interfaces support both ROCm and CUDA paths, with familiar library interfaces.
|
||||
|
||||
- [hipBlas](https://github.com/ROCmSoftwarePlatform/hipBLAS), which utilizes [rocBlas](https://github.com/ROCmSoftwarePlatform/rocBLAS).
|
||||
- [hipFFt](https://github.com/ROCmSoftwarePlatform/hipfft)
|
||||
- [hipsSPARSE](https://github.com/ROCmSoftwarePlatform/hipsparse)
|
||||
- [hipRAND](https://github.com/ROCmSoftwarePlatform/hipRAND)
|
||||
- [MIOpen](https://github.com/ROCmSoftwarePlatform/MIOpen)
|
||||
|
||||
Additionally, some of the cublas routines are automatically converted to hipblas equivalents by the HIPIFY tools. These APIs use cublas or hcblas depending on the platform and replace the need to use conditional compilation.
|
||||
|
||||
## How does HIP compare with OpenCL?
|
||||
Both AMD and Nvidia support OpenCL 1.2 on their devices so that developers can write portable code.
|
||||
HIP offers several benefits over OpenCL:
|
||||
- Developers can code in C++ as well as mix host and device C++ code in their source files. HIP C++ code can use templates, lambdas, classes and so on.
|
||||
- The HIP API is less verbose than OpenCL and is familiar to CUDA developers.
|
||||
- Because both CUDA and HIP are C++ languages, porting from CUDA to HIP is significantly easier than porting from CUDA to OpenCL.
|
||||
- HIP uses the best available development tools on each platform: on Nvidia GPUs, HIP code compiles using NVCC and can employ the nSight profiler and debugger (unlike OpenCL on Nvidia GPUs).
|
||||
- HIP provides pointers and host-side pointer arithmetic.
|
||||
- HIP provides device-level control over memory allocation and placement.
|
||||
- HIP offers an offline compilation model.
|
||||
|
||||
## How does porting CUDA to HIP compare to porting CUDA to OpenCL?
|
||||
Both HIP and CUDA are dialects of C++, and thus porting between them is relatively straightforward.
|
||||
Both dialects support templates, classes, lambdas, and other C++ constructs.
|
||||
As one example, the hipify-perl tool was originally a Perl script that used simple text conversions from CUDA to HIP.
|
||||
HIP and CUDA provide similar math library calls as well. In summary, the HIP philosophy was to make the HIP language close enough to CUDA that the porting effort is relatively simple.
|
||||
This reduces the potential for error, and also makes it easy to automate the translation. HIP's goal is to quickly get the ported program running on both platforms with little manual intervention, so that the programmer can focus on performance optimizations.
|
||||
|
||||
There have been several tools that have attempted to convert CUDA into OpenCL, such as CU2CL. OpenCL is a C99-based kernel language (rather than C++) and also does not support single-source compilation.
|
||||
As a result, the OpenCL syntax is different from CUDA, and the porting tools have to perform some heroic transformations to bridge this gap.
|
||||
The tools also struggle with more complex CUDA applications, in particular, those that use templates, classes, or other C++ features inside the kernel.
|
||||
|
||||
## What hardware does HIP support?
|
||||
- For AMD platforms, see the [ROCm documentation](https://github.com/RadeonOpenCompute/ROCm#supported-gpus) for the list of supported platforms.
|
||||
- For Nvidia platforms, HIP requires Unified Memory and should run on any device supporting CUDA SDK 6.0 or newer. We have tested the Nvidia Titan and Tesla K40.
|
||||
|
||||
## Do HIPIFY tools automatically convert all source code?
|
||||
Typically, HIPIFY tools can automatically convert almost all run-time code.
|
||||
Most device code needs no additional conversion since HIP and CUDA have similar names for math and built-in functions.
|
||||
The hipify-clang tool will automatically modify the kernel signature as needed (automating a step that used to be done manually).
|
||||
Additional porting may be required to deal with architecture feature queries or with CUDA capabilities that HIP doesn't support.
|
||||
In general, developers should always expect to perform some platform-specific tuning and optimization.
|
||||
|
||||
## What is NVCC?
|
||||
NVCC is Nvidia's compiler driver for compiling "CUDA C++" code into PTX or device code for Nvidia GPUs. It's a closed-source binary compiler that is provided by the CUDA SDK.
|
||||
|
||||
## What is HIP-Clang?
|
||||
HIP-Clang is a Clang/LLVM based compiler to compile HIP programs which can run on AMD platform.
|
||||
|
||||
## Why use HIP rather than supporting CUDA directly?
|
||||
While HIP is a strong subset of the CUDA, it is a subset. The HIP layer allows that subset to be clearly defined and documented.
|
||||
Developers who code to the HIP API can be assured their code will remain portable across Nvidia and AMD platforms.
|
||||
In addition, HIP defines portable mechanisms to query architectural features and supports a larger 64-bit wavesize which expands the return type for cross-lane functions like ballot and shuffle from 32-bit ints to 64-bit ints.
|
||||
|
||||
## Can I develop HIP code on an Nvidia CUDA platform?
|
||||
Yes. HIP's CUDA path only exposes the APIs and functionality that work on both NVCC and AMDGPU back-ends.
|
||||
"Extra" APIs, parameters, and features which exist in CUDA but not in HIP-Clang will typically result in compile-time or run-time errors.
|
||||
Developers need to use the HIP API for most accelerator code and bracket any CUDA-specific code with preprocessor conditionals.
|
||||
Developers concerned about portability should, of course, run on both platforms, and should expect to tune for performance.
|
||||
In some cases, CUDA has a richer set of modes for some APIs, and some C++ capabilities such as virtual functions - see the HIP @API documentation for more details.
|
||||
|
||||
## Can I develop HIP code on an AMD HIP-Clang platform?
|
||||
Yes. HIP's HIP-Clang path only exposes the APIs and functions that work on AMD runtime back ends. "Extra" APIs, parameters and features that appear in HIP-Clang but not CUDA will typically cause compile- or run-time errors. Developers must use the HIP API for most accelerator code and bracket any HIP-Clang specific code with preprocessor conditionals. Those concerned about portability should, of course, test their code on both platforms and should tune it for performance. Typically, HIP-Clang supports a more modern set of C++11/C++14/C++17 features, so HIP developers who want portability should be careful when using advanced C++ features on the HIP-Clang path.
|
||||
|
||||
## How to use HIP-Clang to build HIP programs?
|
||||
The environment variable can be used to set compiler path:
|
||||
- HIP_CLANG_PATH: path to hip-clang. When set, this variable let hipcc to use hip-clang for compilation/linking.
|
||||
|
||||
There is an alternative environment variable to set compiler path:
|
||||
- HIP_ROCCLR_HOME: path to root directory of the HIP-ROCclr runtime. When set, this variable let hipcc use hip-clang from the ROCclr distribution.
|
||||
NOTE: If HIP_ROCCLR_HOME is set, there is no need to set HIP_CLANG_PATH since hipcc will deduce them from HIP_ROCCLR_HOME.
|
||||
|
||||
## What is AMD clr?
|
||||
AMD clr (Common Language Runtime) is a repository for the AMD platform, which contains source codes for AMD's compute languages runtimes as follows,
|
||||
|
||||
- hipamd - contains implementation of HIP language for AMD GPU.
|
||||
- rocclr - contains virtual device interfaces that compute runtimes interact with backends, such as ROCr on Linux and PAL on Windows.
|
||||
- opencl - contains implementation of OpenCL™ on the AMD platform.
|
||||
|
||||
## What is hipother?
|
||||
A new repository 'hipother' is added in the ROCm 6.1 release, which is branched out from HIP.
|
||||
hipother supports the HIP back-end implementation on some non-AMD platforms, like NVIDIA.
|
||||
|
||||
## Can I get HIP open source repository for Windows?
|
||||
No, there is no HIP repository open publicly on Windows.
|
||||
|
||||
## Can a HIP binary run on both AMD and Nvidia platforms?
|
||||
HIP is a source-portable language that can be compiled to run on either AMD or NVIDIA platform. HIP tools don't create a "fat binary" that can run on either platform, however.
|
||||
|
||||
## On HIP-Clang, can I link HIP code with host code compiled with another compiler such as gcc, icc, or clang ?
|
||||
Yes. HIP generates the object code which conforms to the GCC ABI, and also links with libstdc++. This means you can compile host code with the compiler of your choice and link the generated object code
|
||||
with GPU code compiled with HIP. Larger projects often contain a mixture of accelerator code (initially written in CUDA with nvcc) and host code (compiled with gcc, icc, or clang). These projects
|
||||
can convert the accelerator code to HIP, compile that code with hipcc, and link with object code from their preferred compiler.
|
||||
|
||||
## Can HIP API support C style application? What is the differentce between C and C++ ?
|
||||
HIP is C++ runtime API that supports C style applications as well.
|
||||
|
||||
Some C style applications (and interfaces to other languages (Fortran, Python)) would call certain HIP APIs but not use kernel programming.
|
||||
They can be compiled with a C compiler and run correctly, however, small details must be considered in the code. For example, initializtion, as shown in the simple application below, uses HIP structs dim3 with the file name "test.hip.cpp"
|
||||
```
|
||||
#include "hip/hip_runtime_api.h"
|
||||
#include "stdio.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
dim3 grid1;
|
||||
printf("dim3 grid1; x=%d, y=%d, z=%d\n",grid1.x,grid1.y,grid1.z);
|
||||
dim3 grid2 = {1,1,1};
|
||||
printf("dim3 grid2 = {1,1,1}; x=%d, y=%d, z=%d\n",grid2.x,grid2.y,grid2.z);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
When using a C++ compiler,
|
||||
```
|
||||
$ gcc -x c++ $(hipconfig --cpp_config) test3.hip.cpp -o test
|
||||
$ ./test
|
||||
dim3 grid1; x=1, y=1, z=1
|
||||
dim3 grid2 = {1,1,1}; x=1, y=1, z=1
|
||||
```
|
||||
In which "dim3 grid1;" will yield a dim3 grid with all dimentional members x,y,z initalized to 1, as the default constructor behaves that way.
|
||||
Further, if write,
|
||||
```
|
||||
dim3 grid(2); // yields {2,1,1}
|
||||
dim3 grid(2,3); yields {2,3,1}
|
||||
```
|
||||
|
||||
In comparison, when using the C compiler,
|
||||
```
|
||||
$ gcc -x c $(hipconfig --cpp_config) test.hip.cpp -o test
|
||||
$ ./test
|
||||
dim3 grid1; x=646881376, y=21975, z=1517277280
|
||||
dim3 grid2 = {1,1,1}; x=1, y=1, z=1
|
||||
```
|
||||
In which "dim3 grid;" does not imply any initialization, no constructor is called, and dimentional values x,y,z of grid are undefined.
|
||||
NOTE: To get the C++ default behavior, C programmers must additionally specify the right-hand side as shown below,
|
||||
```
|
||||
dim3 grid = {1,1,1}; // initialized as in C++
|
||||
```
|
||||
|
||||
|
||||
## Can I install both CUDA SDK and HIP-Clang on the same machine?
|
||||
Yes. You can use HIP_PLATFORM to choose which path hipcc targets. This configuration can be useful when using HIP to develop an application which is portable to both AMD and NVIDIA.
|
||||
|
||||
|
||||
## HIP detected my platform (HIP-Clang vs nvcc) incorrectly - what should I do?
|
||||
HIP will set the platform to AMD and use HIP-Clang as compiler if it sees that the AMD graphics driver is installed and has detected an AMD GPU.
|
||||
Sometimes this isn't what you want - you can force HIP to recognize the platform by setting the following,
|
||||
```
|
||||
export HIP_PLATFORM=amd
|
||||
```
|
||||
HIP then set and use correct AMD compiler and runtime,
|
||||
HIP_COMPILER=clang
|
||||
HIP_RUNTIME=rocclr
|
||||
|
||||
To choose NVIDIA platform, you can set,
|
||||
```
|
||||
export HIP_PLATFORM=nvidia
|
||||
```
|
||||
In this case, HIP will set and use the following,
|
||||
HIP_COMPILER=cuda
|
||||
HIP_RUNTIME=nvcc
|
||||
|
||||
One symptom of this problem is the message "error: 'unknown error'(11) at square.hipref.cpp:56". This can occur if you have a CUDA installation on an AMD platform, and HIP incorrectly detects the platform as nvcc. HIP may be able to compile the application using the nvcc tool-chain but will generate this error at runtime since the platform does not have a CUDA device.
|
||||
|
||||
## On CUDA, can I mix CUDA code with HIP code?
|
||||
Yes. Most HIP data structures (hipStream_t, hipEvent_t) are typedefs to CUDA equivalents and can be intermixed. Both CUDA and HIP use integer device ids.
|
||||
One notable exception is that hipError_t is a new type, and cannot be used where a cudaError_t is expected. In these cases, refactor the code to remove the expectation. Alternatively, hip_runtime_api.h defines functions which convert between the error code spaces:
|
||||
|
||||
hipErrorToCudaError
|
||||
hipCUDAErrorTohipError
|
||||
hipCUResultTohipError
|
||||
|
||||
If platform portability is important, use #ifdef __HIP_PLATFORM_NVIDIA__ to guard the CUDA-specific code.
|
||||
|
||||
## How do I trace HIP application flow?
|
||||
See {doc}`/developer_guide/logging` for more information.
|
||||
|
||||
## What is maximum limit of kernel launching parameter?
|
||||
Product of block.x, block.y, and block.z should be less than 1024.
|
||||
Please note, HIP does not support kernel launch with total work items defined in dimension with size gridDim x blockDim >= 2^32, so gridDim.x * blockDim.x, gridDim.y * blockDim.y and gridDim.z * blockDim.z are always less than 2^32.
|
||||
|
||||
## Are __shfl_*_sync functions supported on HIP platform?
|
||||
__shfl_*_sync is not supported on HIP but for nvcc path CUDA 9.0 and above all shuffle calls get redirected to it's sync version.
|
||||
|
||||
## How to create a guard for code that is specific to the host or the GPU?
|
||||
The compiler defines the `__HIP_DEVICE_COMPILE__` macro only when compiling the code for the GPU. It could be used to guard code that is specific to the host or the GPU.
|
||||
|
||||
## Why _OpenMP is undefined when compiling with -fopenmp?
|
||||
When compiling an OpenMP source file with `hipcc -fopenmp`, the compiler may generate error if there is a reference to the `_OPENMP` macro. This is due to a limitation in hipcc that treats any source file type (e.g., `.cpp`) as an HIP translation unit leading to some conflicts with the OpenMP language switch. If the OpenMP source file doesn't contain any HIP language construct, you could workaround this issue by adding the `-x c++` switch to force the compiler to treat the file as regular C++. Another approach would be to guard the OpenMP code with `#ifdef _OPENMP` so that the code block is disabled when compiling for the GPU. The `__HIP_DEVICE_COMPILE__` macro defined by the HIP compiler when compiling GPU code could also be used for guarding code paths specific to the host or the GPU.
|
||||
|
||||
## Does the HIP-Clang compiler support extern shared declarations?
|
||||
|
||||
Previously, it was essential to declare dynamic shared memory using the HIP_DYNAMIC_SHARED macro for accuracy, as using static shared memory in the same kernel could result in overlapping memory ranges and data-races.
|
||||
|
||||
Now, the HIP-Clang compiler provides support for extern shared declarations, and the HIP_DYNAMIC_SHARED option is no longer required. You may use the standard extern definition:
|
||||
extern __shared__ type var[];
|
||||
|
||||
## I have multiple HIP enabled devices and I am getting an error code hipErrorSharedObjectInitFailed with the message "Error: shared object initialization failed"?
|
||||
|
||||
This error message is seen due to the fact that you do not have valid code object for all of your devices.
|
||||
|
||||
If you have compiled the application yourself, make sure you have given the correct device name(s) and its features via: `--offload-arch`. If you are not mentioning the `--offload-arch`, make sure that `hipcc` is using the correct offload arch by verifying the hipcc output generated by setting the environment variable `HIPCC_VERBOSE=1`.
|
||||
|
||||
If you have a precompiled application/library (like rocblas, tensorflow etc) which gives you such error, there are one of two possibilities.
|
||||
|
||||
- The application/library does not ship code object bundles for *all* of your device(s): in this case you need to recompile the application/library yourself with correct `--offload-arch`.
|
||||
- The application/library does not ship code object bundles for *some* of your device(s), for example you have a system with an APU + GPU and the library does not ship code objects for your APU. For this you can set the environment variable `HIP_VISIBLE_DEVICES` or `CUDA_VISIBLE_DEVICES` on NVdia platform, to only enable GPUs for which code object is available. This will limit the GPUs visible to your application and allow it to run.
|
||||
|
||||
Note: In previous releases, the error code is hipErrorNoBinaryForGpu with message "Unable to find code object for all current devices".
|
||||
The error code handling behavior is changed. HIP runtime shows the error code hipErrorSharedObjectInitFailed with message "Error: shared object initialization failed" on unsupported GPU.
|
||||
|
||||
## How to use per-thread default stream in HIP?
|
||||
|
||||
The per-thread default stream is an implicit stream local to both the thread and the current device. It does not do any implicit synchronization with other streams (like explicitly created streams), or default per-thread stream on other threads.
|
||||
|
||||
The per-thread default stream is a blocking stream and will synchronize with the default null stream if both are used in a program.
|
||||
|
||||
In ROCm, a compilation option should be added in order to compile the translation unit with per-thread default stream enabled.
|
||||
"-fgpu-default-stream=per-thread".
|
||||
Once source is compiled with per-thread default stream enabled, all APIs will be executed on per thread default stream, hence there will not be any implicit synchronization with other streams.
|
||||
|
||||
Besides, per-thread default stream be enabled per translation unit, users can compile some files with feature enabled and some with feature disabled. Feature enabled translation unit will have default stream as per thread and there will not be any implicit synchronization done but other modules will have legacy default stream which will do implicit synchronization.
|
||||
|
||||
## How to use complex muliplication and division operations?
|
||||
|
||||
In HIP, hipFloatComplex and hipDoubleComplex are defined as complex data types,
|
||||
typedef float2 hipFloatComplex;
|
||||
typedef double2 hipDoubleComplex;
|
||||
|
||||
Any application uses complex multiplication and division operations, need to replace '*' and '/' operators with the following,
|
||||
- hipCmulf() and hipCdivf() for hipFloatComplex
|
||||
- hipCmul() and hipCdiv() for hipDoubleComplex
|
||||
|
||||
Note: These complex operations are equivalent to corresponding types/functions on the NVIDIA platform.
|
||||
|
||||
## Can I develop applications with HIP APIs on Windows the same on Linux?
|
||||
|
||||
Yes, HIP APIs are available to use on both Linux and Windows.
|
||||
Due to different working mechanisms on operating systems like Windows vs Linux, HIP APIs call corresponding lower level backend runtime libraries and kernel drivers for the OS, in order to control the executions on GPU hardware accordingly. There might be a few differences on the related backend software and driver support, which might affect usage of HIP APIs. See OS support details in HIP API document.
|
||||
|
||||
## Does HIP support LUID?
|
||||
|
||||
Starting ROCm 6.0, HIP runtime supports Locally Unique Identifier (LUID).
|
||||
This feature enables the local physical device(s) to interoperate with other devices. For example, DX12.
|
||||
|
||||
HIP runtime sets device LUID properties so the driver can query LUID to identify each device for interoperability.
|
||||
|
||||
Note: HIP supports LUID only on Windows OS.
|
||||
|
||||
## How can I know the version of HIP?
|
||||
|
||||
HIP version definition has been updated since ROCm 4.2 release as the following:
|
||||
|
||||
HIP_VERSION=HIP_VERSION_MAJOR * 10000000 + HIP_VERSION_MINOR * 100000 + HIP_VERSION_PATCH)
|
||||
|
||||
HIP version can be queried from HIP API call,
|
||||
hipRuntimeGetVersion(&runtimeVersion);
|
||||
|
||||
The version returned will always be greater than the versions in previous ROCm releases.
|
||||
|
||||
Note: The version definition of HIP runtime is different from CUDA. On AMD platform, the function returns HIP runtime version, while on NVIDIA platform, it returns CUDA runtime version. And there is no mapping/correlation between HIP version and CUDA version.
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
# Porting CUDA Driver API
|
||||
|
||||
## Introduction to the CUDA Driver and Runtime APIs
|
||||
CUDA provides a separate CUDA Driver and Runtime APIs. The two APIs have significant overlap in functionality:
|
||||
- Both APIs support events, streams, memory management, memory copy, and error handling.
|
||||
- Both APIs deliver similar performance.
|
||||
- Driver APIs calls begin with the prefix `cu` while Runtime APIs begin with the prefix `cuda`. For example, the Driver API API contains `cuEventCreate` while the Runtime API contains `cudaEventCreate`, with similar functionality.
|
||||
- The Driver API defines a different but largely overlapping error code space than the Runtime API, and uses a different coding convention. For example, Driver API defines `CUDA_ERROR_INVALID_VALUE` while the Runtime API defines `cudaErrorInvalidValue`
|
||||
|
||||
|
||||
The Driver API offers two additional pieces of functionality not provided by the Runtime API: cuModule and cuCtx APIs.
|
||||
|
||||
### cuModule API
|
||||
The Module section of the Driver API provides additional control over how and when accelerator code objects are loaded.
|
||||
For example, the driver API allows code objects to be loaded from files or memory pointers.
|
||||
Symbols for kernels or global data can be extracted from the loaded code objects.
|
||||
In contrast, the Runtime API automatically loads and (if necessary) compiles all of the kernels from an executable binary when run.
|
||||
In this mode, NVCC must be used to compile kernel code so the automatic loading can function correctly.
|
||||
|
||||
Both Driver and Runtime APIs define a function for launching kernels (called `cuLaunchKernel` or `cudaLaunchKernel`.
|
||||
The kernel arguments and the execution configuration (grid dimensions, group dimensions, dynamic shared memory, and stream) are passed as arguments to the launch function.
|
||||
The Runtime additionally provides the `<<< >>>` syntax for launching kernels, which resembles a special function call and is easier to use than explicit launch API (in particular with respect to handling of kernel arguments).
|
||||
However, this syntax is not standard C++ and is available only when NVCC is used to compile the host code.
|
||||
|
||||
The Module features are useful in an environment which generates the code objects directly, such as a new accelerator language front-end.
|
||||
Here, NVCC is not used. Instead, the environment may have a different kernel language or different compilation flow.
|
||||
Other environments have many kernels and do not want them to be all loaded automatically.
|
||||
The Module functions can be used to load the generated code objects and launch kernels.
|
||||
As we will see below, HIP defines a Module API which provides similar explicit control over code object management.
|
||||
|
||||
### cuCtx API
|
||||
The Driver API defines "Context" and "Devices" as separate entities.
|
||||
Contexts contain a single device, and a device can theoretically have multiple contexts.
|
||||
Each context contains a set of streams and events specific to the context.
|
||||
Historically contexts also defined a unique address space for the GPU, though this may no longer be the case in Unified Memory platforms (since the CPU and all the devices in the same process share a single unified address space).
|
||||
The Context APIs also provide a mechanism to switch between devices, which allowed a single CPU thread to send commands to different GPUs.
|
||||
HIP as well as a recent versions of CUDA Runtime provide other mechanisms to accomplish this feat - for example using streams or `cudaSetDevice`.
|
||||
|
||||
The CUDA Runtime API unifies the Context API with the Device API. This simplifies the APIs and has little loss of functionality since each Context can contain a single device, and the benefits of multiple contexts has been replaced with other interfaces.
|
||||
HIP provides a context API to facilitate easy porting from existing Driver codes.
|
||||
In HIP, the Ctx functions largely provide an alternate syntax for changing the active device.
|
||||
|
||||
Most new applications will prefer to use `hipSetDevice` or the stream APIs , therefore HIP has marked hipCtx APIs as **deprecated**. Support for these APIs may not be available in future releases. For more details on deprecated APIs please refer [HIP deprecated APIs](https://github.com/ROCm/HIP/blob/develop/docs/reference/deprecated_api_list.md).
|
||||
|
||||
## HIP Module and Ctx APIs
|
||||
|
||||
Rather than present two separate APIs, HIP extends the HIP API with new APIs for Modules and Ctx control.
|
||||
|
||||
### hipModule API
|
||||
|
||||
Like the CUDA Driver API, the Module API provides additional control over how code is loaded, including options to load code from files or from in-memory pointers.
|
||||
NVCC and HIP-Clang target different architectures and use different code object formats: NVCC is `cubin` or `ptx` files, while the HIP-Clang path is the `hsaco` format.
|
||||
The external compilers which generate these code objects are responsible for generating and loading the correct code object for each platform.
|
||||
Notably, there is not a fat binary format that can contain code for both NVCC and HIP-Clang platforms. The following table summarizes the formats used on each platform:
|
||||
|
||||
| Format | APIs | NVCC | HIP-CLANG |
|
||||
| --- | --- | --- | --- |
|
||||
| Code Object | hipModuleLoad, hipModuleLoadData | .cubin or PTX text | .hsaco |
|
||||
| Fat Binary | hipModuleLoadFatBin | .fatbin | .hip_fatbin |
|
||||
|
||||
`hipcc` uses HIP-Clang or NVCC to compile host codes. Both of these may embed code objects into the final executable, and these code objects will be automatically loaded when the application starts.
|
||||
The hipModule API can be used to load additional code objects, and in this way provides an extended capability to the automatically loaded code objects.
|
||||
HIP-Clang allows both of these capabilities to be used together, if desired. Of course it is possible to create a program with no kernels and thus no automatic loading.
|
||||
|
||||
|
||||
### hipCtx API
|
||||
HIP provides a `Ctx` API as a thin layer over the existing Device functions. This Ctx API can be used to set the current context, or to query properties of the device associated with the context.
|
||||
The current context is implicitly used by other APIs such as `hipStreamCreate`.
|
||||
|
||||
### hipify translation of CUDA Driver API
|
||||
The HIPIFY tools convert CUDA Driver APIs for streams, events, modules, devices, memory management, context, profiler to the equivalent HIP driver calls. For example, `cuEventCreate` will be translated to `hipEventCreate`.
|
||||
HIPIFY tools also convert error codes from the Driver namespace and coding convention to the equivalent HIP error code. Thus, HIP unifies the APIs for these common functions.
|
||||
|
||||
The memory copy API requires additional explanation. The CUDA driver includes the memory direction in the name of the API (ie `cuMemcpyH2D`) while the CUDA driver API provides a single memory copy API with a parameter that specifies the direction and additionally supports a "default" direction where the runtime determines the direction automatically.
|
||||
HIP provides APIs with both styles: for example, `hipMemcpyH2D` as well as `hipMemcpy`.
|
||||
The first flavor may be faster in some cases since they avoid host overhead to detect the different memory directions.
|
||||
|
||||
HIP defines a single error space, and uses camel-case for all errors (i.e. `hipErrorInvalidValue`).
|
||||
|
||||
#### Address Spaces
|
||||
HIP-Clang defines a process-wide address space where the CPU and all devices allocate addresses from a single unified pool.
|
||||
Thus addresses may be shared between contexts, and unlike the original CUDA definition a new context does not create a new address space for the device.
|
||||
|
||||
#### Using hipModuleLaunchKernel
|
||||
`hipModuleLaunchKernel` is `cuLaunchKernel` in HIP world. It takes the same arguments as `cuLaunchKernel`.
|
||||
|
||||
#### Additional Information
|
||||
- HIP-Clang creates a primary context when the HIP API is called. So in a pure driver API code, HIP-Clang will create a primary context while HIP/NVCC will have empty context stack.
|
||||
HIP-Clang will push primary context to context stack when it is empty. This can have subtle differences on applications which mix the runtime and driver APIs.
|
||||
|
||||
### hip-clang Implementation Notes
|
||||
#### .hip_fatbin
|
||||
hip-clang links device code from different translation units together. For each device target, a code object is generated. Code objects for different device targets are bundled by clang-offload-bundler as one fatbinary, which is embeded as a global symbol `__hip_fatbin` in the .hip_fatbin section of the ELF file of the executable or shared object.
|
||||
|
||||
#### Initialization and Termination Functions
|
||||
hip-clang generates initializatiion and termination functions for each translation unit for host code compilation. The initialization functions call `__hipRegisterFatBinary` to register the fatbinary embeded in the ELF file. They also call `__hipRegisterFunction` and `__hipRegisterVar` to register kernel functions and device side global variables. The termination functions call `__hipUnregisterFatBinary`.
|
||||
hip-clang emits a global variable `__hip_gpubin_handle` of void** type with linkonce linkage and inital value 0 for each host translation unit. Each initialization function checks `__hip_gpubin_handle` and register the fatbinary only if `__hip_gpubin_handle` is 0 and saves the return value of `__hip_gpubin_handle` to `__hip_gpubin_handle`. This is to guarantee that the fatbinary is only registered once. Similar check is done in the termination functions.
|
||||
|
||||
#### Kernel Launching
|
||||
hip-clang supports kernel launching by CUDA `<<<>>>` syntax, hipLaunchKernelGGL. The latter one is macro which expand to CUDA `<<<>>>` syntax.
|
||||
|
||||
When the executable or shared library is loaded by the dynamic linker, the initilization functions are called. In the initialization functions, when `__hipRegisterFatBinary` is called, the code objects containing all kernels are loaded; when `__hipRegisterFunction` is called, the stub functions are associated with the corresponding kernels in code objects.
|
||||
|
||||
hip-clang implements two sets of kernel launching APIs.
|
||||
|
||||
By default, in the host code, for the `<<<>>>` statement, hip-clang first emits call of hipConfigureCall to set up the threads and grids, then emits call of the stub function with the given arguments. In the stub function, hipSetupArgument is called for each kernel argument, then hipLaunchByPtr is called with a function pointer to the stub function. In hipLaunchByPtr, the real kernel associated with the stub function is launched.
|
||||
|
||||
### NVCC Implementation Notes
|
||||
|
||||
#### Interoperation between HIP and CUDA Driver
|
||||
CUDA applications may want to mix CUDA driver code with HIP code (see example below). This table shows the type equivalence to enable this interaction.
|
||||
|
||||
|**HIP Type** |**CU Driver Type**|**CUDA Runtime Type**|
|
||||
| ---- | ---- | ---- |
|
||||
| hipModule_t | CUmodule | |
|
||||
| hipFunction_t | CUfunction | |
|
||||
| hipCtx_t | CUcontext | |
|
||||
| hipDevice_t | CUdevice | |
|
||||
| hipStream_t | CUstream | cudaStream_t |
|
||||
| hipEvent_t | CUevent | cudaEvent_t |
|
||||
| hipArray | CUarray | cudaArray |
|
||||
|
||||
#### Compilation Options
|
||||
The `hipModule_t` interface does not support `cuModuleLoadDataEx` function, which is used to control PTX compilation options.
|
||||
HIP-Clang does not use PTX and does not support these compilation options.
|
||||
In fact, HIP-Clang code objects always contain fully compiled ISA and do not require additional compilation as a part of the load step.
|
||||
The corresponding HIP function `hipModuleLoadDataEx` behaves as `hipModuleLoadData` on HIP-Clang path (compilation options are not used) and as `cuModuleLoadDataEx` on NVCC path.
|
||||
For example (CUDA):
|
||||
```
|
||||
CUmodule module;
|
||||
void *imagePtr = ...; // Somehow populate data pointer with code object
|
||||
|
||||
const int numOptions = 1;
|
||||
CUJit_option options[numOptions];
|
||||
void * optionValues[numOptions];
|
||||
|
||||
options[0] = CU_JIT_MAX_REGISTERS;
|
||||
unsigned maxRegs = 15;
|
||||
optionValues[0] = (void*)(&maxRegs);
|
||||
|
||||
cuModuleLoadDataEx(module, imagePtr, numOptions, options, optionValues);
|
||||
|
||||
CUfunction k;
|
||||
cuModuleGetFunction(&k, module, "myKernel");
|
||||
```
|
||||
HIP:
|
||||
```
|
||||
hipModule_t module;
|
||||
void *imagePtr = ...; // Somehow populate data pointer with code object
|
||||
|
||||
const int numOptions = 1;
|
||||
hipJitOption options[numOptions];
|
||||
void * optionValues[numOptions];
|
||||
|
||||
options[0] = hipJitOptionMaxRegisters;
|
||||
unsigned maxRegs = 15;
|
||||
optionValues[0] = (void*)(&maxRegs);
|
||||
|
||||
// hipModuleLoadData(module, imagePtr) will be called on HIP-Clang path, JIT options will not be used, and
|
||||
// cupModuleLoadDataEx(module, imagePtr, numOptions, options, optionValues) will be called on NVCC path
|
||||
hipModuleLoadDataEx(module, imagePtr, numOptions, options, optionValues);
|
||||
|
||||
hipFunction_t k;
|
||||
hipModuleGetFunction(&k, module, "myKernel");
|
||||
```
|
||||
|
||||
The below sample shows how to use `hipModuleGetFunction`.
|
||||
|
||||
```
|
||||
#include<hip_runtime.h>
|
||||
#include<hip_runtime_api.h>
|
||||
#include<iostream>
|
||||
#include<fstream>
|
||||
#include<vector>
|
||||
|
||||
#define LEN 64
|
||||
#define SIZE LEN<<2
|
||||
|
||||
#ifdef __HIP_PLATFORM_AMD__
|
||||
#define fileName "vcpy_isa.co"
|
||||
#endif
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVIDIA__
|
||||
#define fileName "vcpy_isa.ptx"
|
||||
#endif
|
||||
|
||||
#define kernel_name "hello_world"
|
||||
|
||||
int main(){
|
||||
float *A, *B;
|
||||
hipDeviceptr_t Ad, Bd;
|
||||
A = new float[LEN];
|
||||
B = new float[LEN];
|
||||
|
||||
for(uint32_t i=0;i<LEN;i++){
|
||||
A[i] = i*1.0f;
|
||||
B[i] = 0.0f;
|
||||
std::cout<<A[i] << " "<<B[i]<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVIDIA__
|
||||
hipInit(0);
|
||||
hipDevice_t device;
|
||||
hipCtx_t context;
|
||||
hipDeviceGet(&device, 0);
|
||||
hipCtxCreate(&context, 0, device);
|
||||
#endif
|
||||
|
||||
hipMalloc((void**)&Ad, SIZE);
|
||||
hipMalloc((void**)&Bd, SIZE);
|
||||
|
||||
hipMemcpyHtoD(Ad, A, SIZE);
|
||||
hipMemcpyHtoD(Bd, B, SIZE);
|
||||
hipModule_t Module;
|
||||
hipFunction_t Function;
|
||||
hipModuleLoad(&Module, fileName);
|
||||
hipModuleGetFunction(&Function, Module, kernel_name);
|
||||
|
||||
std::vector<void*>argBuffer(2);
|
||||
memcpy(&argBuffer[0], &Ad, sizeof(void*));
|
||||
memcpy(&argBuffer[1], &Bd, sizeof(void*));
|
||||
|
||||
size_t size = argBuffer.size()*sizeof(void*);
|
||||
|
||||
void *config[] = {
|
||||
HIP_LAUNCH_PARAM_BUFFER_POINTER, &argBuffer[0],
|
||||
HIP_LAUNCH_PARAM_BUFFER_SIZE, &size,
|
||||
HIP_LAUNCH_PARAM_END
|
||||
};
|
||||
|
||||
hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, 0, NULL, (void**)&config);
|
||||
|
||||
hipMemcpyDtoH(B, Bd, SIZE);
|
||||
for(uint32_t i=0;i<LEN;i++){
|
||||
std::cout<<A[i]<<" - "<<B[i]<<std::endl;
|
||||
}
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVIDIA__
|
||||
hipCtxDetach(context);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## HIP Module and Texture Driver API
|
||||
|
||||
HIP supports texture driver APIs however texture reference should be declared in host scope. Following code explains the use of texture reference for __HIP_PLATFORM_AMD__ platform.
|
||||
|
||||
```
|
||||
// Code to generate code object
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
extern texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
__global__ void tex2dKernel(hipLaunchParm lp, float* outputData,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x = blockIdx.x*blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y*blockDim.y + threadIdx.y;
|
||||
outputData[y*width + x] = tex2D(tex, x, y);
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
// Host code:
|
||||
|
||||
texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
void myFunc ()
|
||||
{
|
||||
// ...
|
||||
|
||||
textureReference* texref;
|
||||
hipModuleGetTexRef(&texref, Module1, "tex");
|
||||
hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap);
|
||||
hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap);
|
||||
hipTexRefSetFilterMode(texref, hipFilterModePoint);
|
||||
hipTexRefSetFlags(texref, 0);
|
||||
hipTexRefSetFormat(texref, HIP_AD_FORMAT_FLOAT, 1);
|
||||
hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT);
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,553 @@
|
||||
# HIP Porting Guide
|
||||
In addition to providing a portable C++ programming environment for GPUs, HIP is designed to ease
|
||||
the porting of existing CUDA code into the HIP environment. This section describes the available tools
|
||||
and provides practical suggestions on how to port CUDA code and work through common issues.
|
||||
|
||||
## Porting a New CUDA Project
|
||||
|
||||
### General Tips
|
||||
- Starting the port on a CUDA machine is often the easiest approach, since you can incrementally port pieces of the code to HIP while leaving the rest in CUDA. (Recall that on CUDA machines HIP is just a thin layer over CUDA, so the two code types can interoperate on nvcc platforms.) Also, the HIP port can be compared with the original CUDA code for function and performance.
|
||||
- Once the CUDA code is ported to HIP and is running on the CUDA machine, compile the HIP code using the HIP compiler on an AMD machine.
|
||||
- HIP ports can replace CUDA versions: HIP can deliver the same performance as a native CUDA implementation, with the benefit of portability to both Nvidia and AMD architectures as well as a path to future C++ standard support. You can handle platform-specific features through conditional compilation or by adding them to the open-source HIP infrastructure.
|
||||
- Use **[hipconvertinplace-perl.sh](https://github.com/ROCm/HIPIFY/blob/amd-staging/bin/hipconvertinplace-perl.sh)** to hipify all code files in the CUDA source directory.
|
||||
|
||||
### Scanning existing CUDA code to scope the porting effort
|
||||
The **[hipexamine-perl.sh](https://github.com/ROCm/HIPIFY/blob/amd-staging/bin/hipexamine-perl.sh)** tool will scan a source directory to determine which files contain CUDA code and how much of that code can be automatically hipified.
|
||||
```
|
||||
> cd examples/rodinia_3.0/cuda/kmeans
|
||||
> $HIP_DIR/bin/hipexamine-perl.sh.
|
||||
info: hipify ./kmeans.h =====>
|
||||
info: hipify ./unistd.h =====>
|
||||
info: hipify ./kmeans.c =====>
|
||||
info: hipify ./kmeans_cuda_kernel.cu =====>
|
||||
info: converted 40 CUDA->HIP refs( dev:0 mem:0 kern:0 builtin:37 math:0 stream:0 event:0 err:0 def:0 tex:3 other:0 ) warn:0 LOC:185
|
||||
info: hipify ./getopt.h =====>
|
||||
info: hipify ./kmeans_cuda.cu =====>
|
||||
info: converted 49 CUDA->HIP refs( dev:3 mem:32 kern:2 builtin:0 math:0 stream:0 event:0 err:0 def:0 tex:12 other:0 ) warn:0 LOC:311
|
||||
info: hipify ./rmse.c =====>
|
||||
info: hipify ./cluster.c =====>
|
||||
info: hipify ./getopt.c =====>
|
||||
info: hipify ./kmeans_clustering.c =====>
|
||||
info: TOTAL-converted 89 CUDA->HIP refs( dev:3 mem:32 kern:2 builtin:37 math:0 stream:0 event:0 err:0 def:0 tex:15 other:0 ) warn:0 LOC:3607
|
||||
kernels (1 total) : kmeansPoint(1)
|
||||
```
|
||||
|
||||
hipexamine-perl scans each code file (cpp, c, h, hpp, etc.) found in the specified directory:
|
||||
|
||||
* Files with no CUDA code (ie kmeans.h) print one line summary just listing the source file name.
|
||||
* Files with CUDA code print a summary of what was found - for example the kmeans_cuda_kernel.cu file:
|
||||
```
|
||||
info: hipify ./kmeans_cuda_kernel.cu =====>
|
||||
info: converted 40 CUDA->HIP refs( dev:0 mem:0 kern:0 builtin:37 math:0 stream:0 event:0
|
||||
```
|
||||
* Interesting information in kmeans_cuda_kernel.cu :
|
||||
* How many CUDA calls were converted to HIP (40)
|
||||
* Breakdown of the CUDA functionality used (dev:0 mem:0 etc). This file uses many CUDA builtins (37) and texture functions (3).
|
||||
* Warning for code that looks like CUDA API but was not converted (0 in this file).
|
||||
* Count Lines-of-Code (LOC) - 185 for this file.
|
||||
|
||||
* hipexamine-perl also presents a summary at the end of the process for the statistics collected across all files. This has similar format to the per-file reporting, and also includes a list of all kernels which have been called. An example from above:
|
||||
|
||||
```shell
|
||||
info: TOTAL-converted 89 CUDA->HIP refs( dev:3 mem:32 kern:2 builtin:37 math:0 stream:0 event:0 err:0 def:0 tex:15 other:0 ) warn:0 LOC:3607
|
||||
kernels (1 total) : kmeansPoint(1)
|
||||
```
|
||||
|
||||
### Converting a project "in-place"
|
||||
|
||||
```shell
|
||||
> hipify-perl --inplace
|
||||
```
|
||||
|
||||
For each input file FILE, this script will:
|
||||
- If "FILE.prehip file does not exist, copy the original code to a new file with extension ".prehip". Then hipify the code file.
|
||||
- If "FILE.prehip" file exists, hipify FILE.prehip and save to FILE.
|
||||
|
||||
This is useful for testing improvements to the hipify toolset.
|
||||
|
||||
|
||||
The [hipconvertinplace-perl.sh](https://github.com/ROCm/HIPIFY/blob/amd-staging/bin/hipconvertinplace-perl.sh) script will perform inplace conversion for all code files in the specified directory.
|
||||
This can be quite handy when dealing with an existing CUDA code base since the script preserves the existing directory structure
|
||||
and filenames - and includes work. After converting in-place, you can review the code to add additional parameters to
|
||||
directory names.
|
||||
|
||||
|
||||
```shell
|
||||
> hipconvertinplace-perl.sh MY_SRC_DIR
|
||||
```
|
||||
|
||||
### Library Equivalents
|
||||
|
||||
Most CUDA libraries have a corresponding ROCm library with similar functionality and APIs. However, ROCm also provides HIP marshalling libraries that greatly simplify the porting process because they more precisely reflect their CUDA counterparts and can be used with either the AMD or NVIDIA platforms (see "Identifying HIP Target Platform" below). There are a few notable exceptions:
|
||||
- MIOpen does not have a marshalling library interface to ease porting from cuDNN.
|
||||
- RCCL is a drop-in replacement for NCCL and implements the NCCL APIs.
|
||||
- hipBLASLt does not have a ROCm library but can still target the NVIDIA platform, as needed.
|
||||
- EIGEN's HIP support is part of the library.
|
||||
|
||||
| CUDA Library | HIP Library | ROCm Library | Comment |
|
||||
|------------- | ----------- | ------------ | ------- |
|
||||
| cuBLAS | hipBLAS | rocBLAS | Basic Linear Algebra Subroutines
|
||||
| cuBLASLt | hipBLASLt | N/A | Basic Linear Algebra Subroutines, lightweight and new flexible API
|
||||
| cuFFT | hipFFT | rocFFT | Fast Fourier Transfer Library
|
||||
| cuSPARSE | hipSPARSE | rocSPARSE | Sparse BLAS + SPMV
|
||||
| cuSolver | hipSOLVER | rocSOLVER | Lapack library
|
||||
| AMG-X | N/A | rocALUTION | Sparse iterative solvers and preconditioners with Geometric and Algebraic MultiGrid
|
||||
| Thrust | N/A | rocThrust | C++ parallel algorithms library
|
||||
| CUB | hipCUB | rocPRIM | Low Level Optimized Parallel Primitives
|
||||
| cuDNN | N/A | MIOpen | Deep learning Solver Library
|
||||
| cuRAND | hipRAND | rocRAND | Random Number Generator Library
|
||||
| EIGEN | EIGEN | N/A | C++ template library for linear algebra: matrices, vectors, numerical solvers,
|
||||
| NCCL | N/A | RCCL | Communications Primitives Library based on the MPI equivalents
|
||||
|
||||
|
||||
|
||||
## Distinguishing Compiler Modes
|
||||
|
||||
|
||||
### Identifying HIP Target Platform
|
||||
All HIP projects target either AMD or NVIDIA platform. The platform affects which headers are included and which libraries are used for linking.
|
||||
|
||||
- `HIP_PLATFORM_AMD` is defined if the HIP platform targets AMD.
|
||||
Note, `HIP_PLATFORM_HCC` was previously defined if the HIP platform targeted AMD, it is deprecated.
|
||||
|
||||
- `HIP_PLATFORM_NVDIA` is defined if the HIP platform targets NVIDIA.
|
||||
Note, `HIP_PLATFORM_NVCC` was previously defined if the HIP platform targeted NVIDIA, it is deprecated.
|
||||
|
||||
### Identifying the Compiler: hip-clang or nvcc
|
||||
Often, it's useful to know whether the underlying compiler is HIP-Clang or nvcc. This knowledge can guard platform-specific code or aid in platform-specific performance tuning.
|
||||
|
||||
```
|
||||
#ifdef __HIP_PLATFORM_AMD__
|
||||
// Compiled with HIP-Clang
|
||||
#endif
|
||||
```
|
||||
|
||||
```
|
||||
#ifdef __HIP_PLATFORM_NVIDIA__
|
||||
// Compiled with nvcc
|
||||
// Could be compiling with CUDA language extensions enabled (for example, a ".cu file)
|
||||
// Could be in pass-through mode to an underlying host compile OR (for example, a .cpp file)
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
#ifdef __CUDACC__
|
||||
// Compiled with nvcc (CUDA language extensions enabled)
|
||||
```
|
||||
|
||||
Compiler directly generates the host code (using the Clang x86 target) and passes the code to another host compiler. Thus, they have no equivalent of the \__CUDA_ACC define.
|
||||
|
||||
|
||||
### Identifying Current Compilation Pass: Host or Device
|
||||
|
||||
nvcc makes two passes over the code: one for host code and one for device code.
|
||||
HIP-Clang will have multiple passes over the code: one for the host code, and one for each architecture on the device code.
|
||||
`__HIP_DEVICE_COMPILE__` is set to a nonzero value when the compiler (HIP-Clang or nvcc) is compiling code for a device inside a `__global__` kernel or for a device function. `__HIP_DEVICE_COMPILE__` can replace #ifdef checks on the `__CUDA_ARCH__` define.
|
||||
|
||||
```
|
||||
// #ifdef __CUDA_ARCH__
|
||||
#if __HIP_DEVICE_COMPILE__
|
||||
```
|
||||
|
||||
Unlike `__CUDA_ARCH__`, the `__HIP_DEVICE_COMPILE__` value is 1 or undefined, and it doesn't represent the feature capability of the target device.
|
||||
|
||||
### Compiler Defines: Summary
|
||||
|Define | HIP-Clang | nvcc | Other (GCC, ICC, Clang, etc.)
|
||||
|--- | --- | --- |---|
|
||||
|HIP-related defines:|
|
||||
|`__HIP_PLATFORM_AMD__`| Defined | Undefined | Defined if targeting AMD platform; undefined otherwise |
|
||||
|`__HIP_PLATFORM_NVIDIA__`| Undefined | Defined | Defined if targeting NVIDIA platform; undefined otherwise |
|
||||
|`__HIP_DEVICE_COMPILE__` | 1 if compiling for device; undefined if compiling for host |1 if compiling for device; undefined if compiling for host | Undefined
|
||||
|`__HIPCC__` | Defined | Defined | Undefined
|
||||
|`__HIP_ARCH_*` |0 or 1 depending on feature support (see below) | 0 or 1 depending on feature support (see below) | 0
|
||||
|nvcc-related defines:|
|
||||
|`__CUDACC__` | Defined if source code is compiled by nvcc; undefined otherwise | Undefined
|
||||
|`__NVCC__` | Undefined | Defined | Undefined
|
||||
|`__CUDA_ARCH__` | Undefined | Unsigned representing compute capability (e.g., "130") if in device code; 0 if in host code | Undefined
|
||||
|hip-clang-related defines:|
|
||||
|`__HIP__` | Defined | Undefined | Undefined
|
||||
|HIP-Clang common defines:|
|
||||
|`__clang__` | Defined | Defined | Undefined | Defined if using Clang; otherwise undefined
|
||||
|
||||
## Identifying Architecture Features
|
||||
|
||||
### HIP_ARCH Defines
|
||||
|
||||
Some CUDA code tests `__CUDA_ARCH__` for a specific value to determine whether the machine supports a certain architectural feature. For instance,
|
||||
|
||||
```
|
||||
#if (__CUDA_ARCH__ >= 130)
|
||||
// doubles are supported
|
||||
```
|
||||
This type of code requires special attention, since AMD and CUDA devices have different architectural capabilities. Moreover, you can't determine the presence of a feature using a simple comparison against an architecture's version number. HIP provides a set of defines and device properties to query whether a specific architectural feature is supported.
|
||||
|
||||
The `__HIP_ARCH_*` defines can replace comparisons of `__CUDA_ARCH__` values:
|
||||
```
|
||||
//#if (__CUDA_ARCH__ >= 130) // non-portable
|
||||
if __HIP_ARCH_HAS_DOUBLES__ { // portable HIP feature query
|
||||
// doubles are supported
|
||||
}
|
||||
```
|
||||
|
||||
For host code, the `__HIP_ARCH__*` defines are set to 0. You should only use the __HIP_ARCH__ fields in device code.
|
||||
|
||||
### Device-Architecture Properties
|
||||
|
||||
Host code should query the architecture feature flags in the device properties that hipGetDeviceProperties returns, rather than testing the "major" and "minor" fields directly:
|
||||
|
||||
```
|
||||
hipGetDeviceProperties(&deviceProp, device);
|
||||
//if ((deviceProp.major == 1 && deviceProp.minor < 2)) // non-portable
|
||||
if (deviceProp.arch.hasSharedInt32Atomics) { // portable HIP feature query
|
||||
// has shared int32 atomic operations ...
|
||||
}
|
||||
```
|
||||
|
||||
### Table of Architecture Properties
|
||||
The table below shows the full set of architectural properties that HIP supports.
|
||||
|
||||
|Define (use only in device code) | Device Property (run-time query) | Comment |
|
||||
|------- | --------- | ----- |
|
||||
|32-bit atomics:||
|
||||
|`__HIP_ARCH_HAS_GLOBAL_INT32_ATOMICS__` | hasGlobalInt32Atomics |32-bit integer atomics for global memory
|
||||
|`__HIP_ARCH_HAS_GLOBAL_FLOAT_ATOMIC_EXCH__` | hasGlobalFloatAtomicExch |32-bit float atomic exchange for global memory
|
||||
|`__HIP_ARCH_HAS_SHARED_INT32_ATOMICS__` | hasSharedInt32Atomics |32-bit integer atomics for shared memory
|
||||
|`__HIP_ARCH_HAS_SHARED_FLOAT_ATOMIC_EXCH__` | hasSharedFloatAtomicExch |32-bit float atomic exchange for shared memory
|
||||
|`__HIP_ARCH_HAS_FLOAT_ATOMIC_ADD__` | hasFloatAtomicAdd |32-bit float atomic add in global and shared memory
|
||||
|64-bit atomics: | |
|
||||
|`__HIP_ARCH_HAS_GLOBAL_INT64_ATOMICS__` | hasGlobalInt64Atomics |64-bit integer atomics for global memory
|
||||
|`__HIP_ARCH_HAS_SHARED_INT64_ATOMICS__` | hasSharedInt64Atomics |64-bit integer atomics for shared memory
|
||||
|Doubles: | |
|
||||
|`__HIP_ARCH_HAS_DOUBLES__` | hasDoubles |Double-precision floating point
|
||||
|Warp cross-lane operations: | |
|
||||
|`__HIP_ARCH_HAS_WARP_VOTE__` | hasWarpVote |Warp vote instructions (any, all)
|
||||
|`__HIP_ARCH_HAS_WARP_BALLOT__` | hasWarpBallot |Warp ballot instructions
|
||||
|`__HIP_ARCH_HAS_WARP_SHUFFLE__` | hasWarpShuffle |Warp shuffle operations (shfl\_\*)
|
||||
|`__HIP_ARCH_HAS_WARP_FUNNEL_SHIFT__` | hasFunnelShift |Funnel shift two input words into one
|
||||
|Sync: | |
|
||||
|`__HIP_ARCH_HAS_THREAD_FENCE_SYSTEM__` | hasThreadFenceSystem |threadfence\_system
|
||||
|`__HIP_ARCH_HAS_SYNC_THREAD_EXT__` | hasSyncThreadsExt |syncthreads\_count, syncthreads\_and, syncthreads\_or
|
||||
|Miscellaneous: | |
|
||||
|`__HIP_ARCH_HAS_SURFACE_FUNCS__` | hasSurfaceFuncs |
|
||||
|`__HIP_ARCH_HAS_3DGRID__` | has3dGrid | Grids and groups are 3D
|
||||
|`__HIP_ARCH_HAS_DYNAMIC_PARALLEL__` | hasDynamicParallelism |
|
||||
|
||||
|
||||
## Finding HIP
|
||||
|
||||
Makefiles can use the following syntax to conditionally provide a default HIP_PATH if one does not exist:
|
||||
|
||||
```
|
||||
HIP_PATH ?= $(shell hipconfig --path)
|
||||
```
|
||||
|
||||
## Identifying HIP Runtime
|
||||
|
||||
HIP can depend on rocclr, or cuda as runtime
|
||||
|
||||
- AMD platform
|
||||
On AMD platform, HIP uses Radeon Open Compute Common Language Runtime, called ROCclr.
|
||||
ROCclr is a virtual device interface that HIP runtimes interact with different backends which allows runtimes to work on Linux , as well as Windows without much efforts.
|
||||
|
||||
- NVIDIA platform
|
||||
On Nvidia platform, HIP is just a thin layer on top of CUDA.
|
||||
On non-AMD platform, HIP runtime determines if cuda is available and can be used. If available, HIP_PLATFORM is set to nvidia and underneath CUDA path is used.
|
||||
|
||||
|
||||
## hipLaunchKernelGGL
|
||||
|
||||
hipLaunchKernelGGL is a macro that can serve as an alternative way to launch kernel, which accepts parameters of launch configurations (grid dims, group dims, stream, dynamic shared size) followed by a variable number of kernel arguments.
|
||||
It can replace <<< >>>, if the user so desires.
|
||||
|
||||
## Compiler Options
|
||||
|
||||
hipcc is a portable compiler driver that will call nvcc or HIP-Clang (depending on the target system) and attach all required include and library options. It passes options through to the target compiler. Tools that call hipcc must ensure the compiler options are appropriate for the target compiler.
|
||||
The `hipconfig` script may helpful in identifying the target platform, compiler and runtime. It can also help set options appropriately.
|
||||
|
||||
### Compiler options supported on AMD platforms
|
||||
|
||||
Here are the main compiler options supported on AMD platforms by HIP-Clang.
|
||||
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| --amdgpu-target=<gpu_arch> | [DEPRECATED] This option is being replaced by `--offload-arch=<target>`. Generate code for the given GPU target. Supported targets are gfx701, gfx801, gfx802, gfx803, gfx900, gfx906, gfx908, gfx1010, gfx1011, gfx1012, gfx1030, gfx1031. This option could appear multiple times on the same command line to generate a fat binary for multiple targets. |
|
||||
| --fgpu-rdc | Generate relocatable device code, which allows kernels or device functions calling device functions in different translation units. |
|
||||
| -ggdb | Equivalent to `-g` plus tuning for GDB. This is recommended when using ROCm's GDB to debug GPU code. |
|
||||
| --gpu-max-threads-per-block=<num> | Generate code to support up to the specified number of threads per block. |
|
||||
| -O<n> | Specify the optimization level. |
|
||||
| -offload-arch=<target> | Specify the AMD GPU [target ID](https://clang.llvm.org/docs/ClangOffloadBundler.html#target-id). |
|
||||
| -save-temps | Save the compiler generated intermediate files. |
|
||||
| -v | Show the compilation steps. |
|
||||
|
||||
## Linking Issues
|
||||
|
||||
### Linking With hipcc
|
||||
|
||||
hipcc adds the necessary libraries for HIP as well as for the accelerator compiler (nvcc or AMD compiler). We recommend linking with hipcc since it automatically links the binary to the necessary HIP runtime libraries. It also has knowledge on how to link and to manage the GPU objects.
|
||||
|
||||
### -lm Option
|
||||
|
||||
hipcc adds -lm by default to the link command.
|
||||
|
||||
|
||||
## Linking Code With Other Compilers
|
||||
|
||||
CUDA code often uses nvcc for accelerator code (defining and launching kernels, typically defined in .cu or .cuh files).
|
||||
It also uses a standard compiler (g++) for the rest of the application. nvcc is a preprocessor that employs a standard host compiler (gcc) to generate the host code.
|
||||
Code compiled using this tool can employ only the intersection of language features supported by both nvcc and the host compiler.
|
||||
In some cases, you must take care to ensure the data types and alignment of the host compiler are identical to those of the device compiler. Only some host compilers are supported---for example, recent nvcc versions lack Clang host-compiler capability.
|
||||
|
||||
HIP-Clang generates both device and host code using the same Clang-based compiler. The code uses the same API as gcc, which allows code generated by different gcc-compatible compilers to be linked together. For example, code compiled using HIP-Clang can link with code compiled using "standard" compilers (such as gcc, ICC and Clang). Take care to ensure all compilers use the same standard C++ header and library formats.
|
||||
|
||||
|
||||
### libc++ and libstdc++
|
||||
|
||||
hipcc links to libstdc++ by default. This provides better compatibility between g++ and HIP.
|
||||
|
||||
If you pass "--stdlib=libc++" to hipcc, hipcc will use the libc++ library. Generally, libc++ provides a broader set of C++ features while libstdc++ is the standard for more compilers (notably including g++).
|
||||
|
||||
When cross-linking C++ code, any C++ functions that use types from the C++ standard library (including std::string, std::vector and other containers) must use the same standard-library implementation. They include the following:
|
||||
|
||||
- Functions or kernels defined in HIP-Clang that are called from a standard compiler
|
||||
- Functions defined in a standard compiler that are called from HIP-Clanng.
|
||||
|
||||
Applications with these interfaces should use the default libstdc++ linking.
|
||||
|
||||
Applications which are compiled entirely with hipcc, and which benefit from advanced C++ features not supported in libstdc++, and which do not require portability to nvcc, may choose to use libc++.
|
||||
|
||||
|
||||
### HIP Headers (hip_runtime.h, hip_runtime_api.h)
|
||||
|
||||
The hip_runtime.h and hip_runtime_api.h files define the types, functions and enumerations needed to compile a HIP program:
|
||||
|
||||
- hip_runtime_api.h: defines all the HIP runtime APIs (e.g., hipMalloc) and the types required to call them. A source file that is only calling HIP APIs but neither defines nor launches any kernels can include hip_runtime_api.h. hip_runtime_api.h uses no custom hc language features and can be compiled using a standard C++ compiler.
|
||||
- hip_runtime.h: included in hip_runtime_api.h. It additionally provides the types and defines required to create and launch kernels. hip_runtime.h can be compiled using a standard C++ compiler but will expose a subset of the available functions.
|
||||
|
||||
CUDA has slightly different contents for these two files. In some cases you may need to convert hipified code to include the richer hip_runtime.h instead of hip_runtime_api.h.
|
||||
|
||||
### Using a Standard C++ Compiler
|
||||
You can compile hip\_runtime\_api.h using a standard C or C++ compiler (e.g., gcc or ICC). The HIP include paths and defines (`__HIP_PLATFORM_AMD__` or `__HIP_PLATFORM_NVIDIA__`) must pass to the standard compiler; hipconfig then returns the necessary options:
|
||||
```
|
||||
> hipconfig --cxx_config
|
||||
-D__HIP_PLATFORM_AMD__ -I/home/user1/hip/include
|
||||
```
|
||||
|
||||
You can capture the hipconfig output and passed it to the standard compiler; below is a sample makefile syntax:
|
||||
|
||||
```
|
||||
CPPFLAGS += $(shell $(HIP_PATH)/bin/hipconfig --cpp_config)
|
||||
```
|
||||
|
||||
nvcc includes some headers by default. However, HIP does not include default headers, and instead all required files must be explicitly included.
|
||||
Specifically, files that call HIP run-time APIs or define HIP kernels must explicitly include the appropriate HIP headers.
|
||||
If the compilation process reports that it cannot find necessary APIs (for example, "error: identifier hipSetDevice is undefined"),
|
||||
ensure that the file includes hip_runtime.h (or hip_runtime_api.h, if appropriate).
|
||||
The hipify-perl script automatically converts "cuda_runtime.h" to "hip_runtime.h," and it converts "cuda_runtime_api.h" to "hip_runtime_api.h", but it may miss nested headers or macros.
|
||||
|
||||
#### cuda.h
|
||||
|
||||
The HIP-Clang path provides an empty cuda.h file. Some existing CUDA programs include this file but don't require any of the functions.
|
||||
|
||||
### Choosing HIP File Extensions
|
||||
|
||||
Many existing CUDA projects use the ".cu" and ".cuh" file extensions to indicate code that should be run through the nvcc compiler.
|
||||
For quick HIP ports, leaving these file extensions unchanged is often easier, as it minimizes the work required to change file names in the directory and #include statements in the files.
|
||||
|
||||
For new projects or ports which can be re-factored, we recommend the use of the extension ".hip.cpp" for source files, and
|
||||
".hip.h" or ".hip.hpp" for header files.
|
||||
This indicates that the code is standard C++ code, but also provides a unique indication for make tools to
|
||||
run hipcc when appropriate.
|
||||
|
||||
## Workarounds
|
||||
|
||||
### warpSize
|
||||
Code should not assume a warp size of 32 or 64. See [Warp Cross-Lane Functions](https://rocm.docs.amd.com/projects/HIP/en/latest/reference/kernel_language.html#warp-cross-lane-functions) for information on how to write portable wave-aware code.
|
||||
|
||||
### Kernel launch with group size > 256
|
||||
Kernel code should use ``` __attribute__((amdgpu_flat_work_group_size(<min>,<max>)))```.
|
||||
|
||||
For example:
|
||||
```
|
||||
__global__ void dot(double *a,double *b,const int n) __attribute__((amdgpu_flat_work_group_size(1, 512)))
|
||||
```
|
||||
|
||||
## memcpyToSymbol
|
||||
|
||||
HIP support for hipMemcpyToSymbol is complete. This feature allows a kernel
|
||||
to define a device-side data symbol which can be accessed on the host side. The symbol
|
||||
can be in __constant or device space.
|
||||
|
||||
Note that the symbol name needs to be encased in the HIP_SYMBOL macro, as shown in the code example below. This also applies to hipMemcpyFromSymbol, hipGetSymbolAddress, and hipGetSymbolSize.
|
||||
|
||||
For example:
|
||||
|
||||
Device Code:
|
||||
```
|
||||
#include<hip/hip_runtime.h>
|
||||
#include<hip/hip_runtime_api.h>
|
||||
#include<iostream>
|
||||
|
||||
#define HIP_ASSERT(status) \
|
||||
assert(status == hipSuccess)
|
||||
|
||||
#define LEN 512
|
||||
#define SIZE 2048
|
||||
|
||||
__constant__ int Value[LEN];
|
||||
|
||||
__global__ void Get(hipLaunchParm lp, int *Ad)
|
||||
{
|
||||
int tid = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
Ad[tid] = Value[tid];
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int *A, *B, *Ad;
|
||||
A = new int[LEN];
|
||||
B = new int[LEN];
|
||||
for(unsigned i=0;i<LEN;i++)
|
||||
{
|
||||
A[i] = -1*i;
|
||||
B[i] = 0;
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipMalloc((void**)&Ad, SIZE));
|
||||
|
||||
HIP_ASSERT(hipMemcpyToSymbol(HIP_SYMBOL(Value), A, SIZE, 0, hipMemcpyHostToDevice));
|
||||
hipLaunchKernelGGL(Get, dim3(1,1,1), dim3(LEN,1,1), 0, 0, Ad);
|
||||
HIP_ASSERT(hipMemcpy(B, Ad, SIZE, hipMemcpyDeviceToHost));
|
||||
|
||||
for(unsigned i=0;i<LEN;i++)
|
||||
{
|
||||
assert(A[i] == B[i]);
|
||||
}
|
||||
std::cout<<"Passed"<<std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
## CU_POINTER_ATTRIBUTE_MEMORY_TYPE
|
||||
|
||||
To get pointer's memory type in HIP/HIP-Clang, developers should use hipPointerGetAttributes API. First parameter of the API is hipPointerAttribute_t which has 'type' as member variable. 'type' indicates input pointer is allocated on device or host.
|
||||
|
||||
For example:
|
||||
```
|
||||
double * ptr;
|
||||
hipMalloc(reinterpret_cast<void**>(&ptr), sizeof(double));
|
||||
hipPointerAttribute_t attr;
|
||||
hipPointerGetAttributes(&attr, ptr); /*attr.type will have value as hipMemoryTypeDevice*/
|
||||
|
||||
double* ptrHost;
|
||||
hipHostMalloc(&ptrHost, sizeof(double));
|
||||
hipPointerAttribute_t attr;
|
||||
hipPointerGetAttributes(&attr, ptrHost); /*attr.type will have value as hipMemoryTypeHost*/
|
||||
```
|
||||
Please note, hipMemoryType enum values are different from cudaMemoryType enum values.
|
||||
|
||||
For example, on AMD platform, hipMemoryType is defined in hip_runtime_api.h,
|
||||
```
|
||||
typedef enum hipMemoryType {
|
||||
hipMemoryTypeHost = 0, ///< Memory is physically located on host
|
||||
hipMemoryTypeDevice = 1, ///< Memory is physically located on device. (see deviceId for specific device)
|
||||
hipMemoryTypeArray = 2, ///< Array memory, physically located on device. (see deviceId for specific device)
|
||||
hipMemoryTypeUnified = 3, ///< Not used currently
|
||||
hipMemoryTypeManaged = 4 ///< Managed memory, automaticallly managed by the unified memory system
|
||||
} hipMemoryType;
|
||||
```
|
||||
Looking into CUDA toolkit, it defines cudaMemoryType as following,
|
||||
```
|
||||
enum cudaMemoryType
|
||||
{
|
||||
cudaMemoryTypeUnregistered = 0, // Unregistered memory.
|
||||
cudaMemoryTypeHost = 1, // Host memory.
|
||||
cudaMemoryTypeDevice = 2, // Device memory.
|
||||
cudaMemoryTypeManaged = 3, // Managed memory
|
||||
}
|
||||
```
|
||||
In this case, memory type translation for hipPointerGetAttributes needs to be handled properly on nvidia platform to get the correct memory type in CUDA, which is done in the file nvidia_hip_runtime_api.h.
|
||||
|
||||
So in any HIP applications which use HIP APIs involving memory types, developers should use #ifdef in order to assign the correct enum values depending on Nvidia or AMD platform.
|
||||
|
||||
As an example, please see the code from the [link](https://github.com/ROCm/hip-tests/tree/develop/catch/unit/memory/hipMemcpyParam2D.cc).
|
||||
|
||||
With the #ifdef condition, HIP APIs work as expected on both AMD and NVIDIA platforms.
|
||||
|
||||
Note, cudaMemoryTypeUnregstered is currently not supported in hipMemoryType enum, due to HIP functionality backward compatibility.
|
||||
|
||||
## threadfence_system
|
||||
Threadfence_system makes all device memory writes, all writes to mapped host memory, and all writes to peer memory visible to CPU and other GPU devices.
|
||||
Some implementations can provide this behavior by flushing the GPU L2 cache.
|
||||
HIP/HIP-Clang does not provide this functionality. As a workaround, users can set the environment variable `HSA_DISABLE_CACHE=1` to disable the GPU L2 cache. This will affect all accesses and for all kernels and so may have a performance impact.
|
||||
|
||||
### Textures and Cache Control
|
||||
|
||||
Compute programs sometimes use textures either to access dedicated texture caches or to use the texture-sampling hardware for interpolation and clamping. The former approach uses simple point samplers with linear interpolation, essentially only reading a single point. The latter approach uses the sampler hardware to interpolate and combine multiple samples. AMD hardware, as well as recent competing hardware, has a unified texture/L1 cache, so it no longer has a dedicated texture cache. But the nvcc path often caches global loads in the L2 cache, and some programs may benefit from explicit control of the L1 cache contents. We recommend the __ldg instruction for this purpose.
|
||||
|
||||
AMD compilers currently load all data into both the L1 and L2 caches, so __ldg is treated as a no-op.
|
||||
|
||||
We recommend the following for functional portability:
|
||||
|
||||
- For programs that use textures only to benefit from improved caching, use the __ldg instruction
|
||||
- Programs that use texture object and reference APIs, work well on HIP
|
||||
|
||||
|
||||
## More Tips
|
||||
|
||||
### HIP Logging
|
||||
|
||||
On an AMD platform, set the AMD_LOG_LEVEL environment variable to log HIP application execution information.
|
||||
|
||||
The value of the setting controls different logging level,
|
||||
|
||||
```
|
||||
enum LogLevel {
|
||||
LOG_NONE = 0,
|
||||
LOG_ERROR = 1,
|
||||
LOG_WARNING = 2,
|
||||
LOG_INFO = 3,
|
||||
LOG_DEBUG = 4
|
||||
};
|
||||
```
|
||||
|
||||
Logging mask is used to print types of functionalities during the execution of HIP application.
|
||||
It can be set as one of the following values,
|
||||
|
||||
```
|
||||
enum LogMask {
|
||||
LOG_API = 1, //!< (0x1) API call
|
||||
LOG_CMD = 2, //!< (0x2) Kernel and Copy Commands and Barriers
|
||||
LOG_WAIT = 4, //!< (0x4) Synchronization and waiting for commands to finish
|
||||
LOG_AQL = 8, //!< (0x8) Decode and display AQL packets
|
||||
LOG_QUEUE = 16, //!< (0x10) Queue commands and queue contents
|
||||
LOG_SIG = 32, //!< (0x20) Signal creation, allocation, pool
|
||||
LOG_LOCK = 64, //!< (0x40) Locks and thread-safety code.
|
||||
LOG_KERN = 128, //!< (0x80) Kernel creations and arguments, etc.
|
||||
LOG_COPY = 256, //!< (0x100) Copy debug
|
||||
LOG_COPY2 = 512, //!< (0x200) Detailed copy debug
|
||||
LOG_RESOURCE = 1024, //!< (0x400) Resource allocation, performance-impacting events.
|
||||
LOG_INIT = 2048, //!< (0x800) Initialization and shutdown
|
||||
LOG_MISC = 4096, //!< (0x1000) Misc debug, not yet classified
|
||||
LOG_AQL2 = 8192, //!< (0x2000) Show raw bytes of AQL packet
|
||||
LOG_CODE = 16384, //!< (0x4000) Show code creation debug
|
||||
LOG_CMD2 = 32768, //!< (0x8000) More detailed command info, including barrier commands
|
||||
LOG_LOCATION = 65536, //!< (0x10000) Log message location
|
||||
LOG_MEM = 131072, //!< (0x20000) Memory allocation
|
||||
LOG_MEM_POOL = 262144, //!< (0x40000) Memory pool allocation, including memory in graphs
|
||||
LOG_ALWAYS = -1 //!< (0xFFFFFFFF) Log always even mask flag is zero
|
||||
};
|
||||
```
|
||||
|
||||
### Debugging hipcc
|
||||
To see the detailed commands that hipcc issues, set the environment variable HIPCC_VERBOSE to 1. Doing so will print to stderr the HIP-clang (or nvcc) commands that hipcc generates.
|
||||
|
||||
```
|
||||
export HIPCC_VERBOSE=1
|
||||
make
|
||||
...
|
||||
hipcc-cmd: /opt/rocm/bin/hipcc --offload-arch=native -x hip backprop_cuda.cu
|
||||
```
|
||||
|
||||
### Editor Highlighting
|
||||
See the utils/vim or utils/gedit directories to add handy highlighting to hip files.
|
||||
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
# HIP RTC Programming Guide
|
||||
|
||||
## HIP RTC lib
|
||||
HIP allows you to compile kernels at runtime with its ```hiprtc*``` APIs.
|
||||
Kernels can be stored as a text string and can be passed on to HIPRTC APIs alongside options to guide the compilation.
|
||||
|
||||
NOTE:
|
||||
|
||||
- This library can be used on systems without HIP install nor AMD GPU driver installed at all (offline compilation). Therefore it does not depend on any HIP runtime library.
|
||||
- But it does depend on COMGr. You may try to statically link COMGr into HIPRTC to avoid any ambiguity.
|
||||
- Developers can decide to bundle this library with their application.
|
||||
|
||||
## Compile APIs
|
||||
|
||||
#### Example
|
||||
To use HIPRTC functionality, HIPRTC header needs to be included first.
|
||||
```#include <hip/hiprtc.h>```
|
||||
|
||||
|
||||
Kernels can be stored in a string:
|
||||
```cpp
|
||||
static constexpr auto kernel {
|
||||
R"(
|
||||
extern "C"
|
||||
__global__ void gpu_kernel(...) {
|
||||
// Kernel Functionality
|
||||
}
|
||||
)"};
|
||||
```
|
||||
|
||||
Now to compile this kernel, it needs to be associated with hiprtcProgram type, which is done via declaring ```hiprtcProgram prog;``` and associating the string of kernel with this program:
|
||||
|
||||
```cpp
|
||||
hiprtcCreateProgram(&prog, // HIPRTC program
|
||||
kernel, // kernel string
|
||||
"gpu_kernel.cu", // Name of the file
|
||||
num_headers, // Number of headers
|
||||
&header_sources[0], // Header sources
|
||||
&header_names[0]); // Name of header files
|
||||
```
|
||||
|
||||
hiprtcCreateProgram API also allows you to add headers which can be included in your rtc program.
|
||||
For online compilation, the compiler pre-defines HIP device API functions, HIP specific types and macros for device compilation, but does not include standard C/C++ headers by default. Users can only include header files provided to hiprtcCreateProgram.
|
||||
|
||||
After associating the kernel string with hiprtcProgram, you can now compile this program using:
|
||||
```cpp
|
||||
hiprtcCompileProgram(prog, // hiprtcProgram
|
||||
0, // Number of options
|
||||
options); // Clang Options [Supported Clang Options](clang_options.md)
|
||||
```
|
||||
|
||||
hiprtcCompileProgram returns a status value which can be converted to string via ```hiprtcGetErrorString```. If compilation is successful, hiprtcCompileProgram will return ```HIPRTC_SUCCESS```.
|
||||
|
||||
If the compilation fails, you can look up the logs via:
|
||||
|
||||
```cpp
|
||||
size_t logSize;
|
||||
hiprtcGetProgramLogSize(prog, &logSize);
|
||||
|
||||
if (logSize) {
|
||||
string log(logSize, '\0');
|
||||
hiprtcGetProgramLog(prog, &log[0]);
|
||||
// Corrective action with logs
|
||||
}
|
||||
```
|
||||
|
||||
If the compilation is successful, you can load the compiled binary in a local variable.
|
||||
```cpp
|
||||
size_t codeSize;
|
||||
hiprtcGetCodeSize(prog, &codeSize);
|
||||
|
||||
vector<char> kernel_binary(codeSize);
|
||||
hiprtcGetCode(prog, kernel_binary.data());
|
||||
```
|
||||
|
||||
After loading the binary, hiprtcProgram can be destroyed.
|
||||
```hiprtcDestroyProgram(&prog);```
|
||||
|
||||
The binary present in ```kernel_binary``` can now be loaded via ```hipModuleLoadData``` API.
|
||||
```cpp
|
||||
hipModule_t module;
|
||||
hipFunction_t kernel;
|
||||
|
||||
hipModuleLoadData(&module, kernel_binary.data());
|
||||
hipModuleGetFunction(&kernel, module, "gpu_kernel");
|
||||
```
|
||||
|
||||
And now this kernel can be launched via hipModule APIs.
|
||||
|
||||
Please have a look at saxpy.cpp and hiprtcGetLoweredName.cpp files for a detailed example.
|
||||
|
||||
#### HIPRTC specific options
|
||||
HIPRTC provides a few HIPRTC specific flags
|
||||
- ```--gpu-architecture``` : This flag can guide the code object generation for a specific gpu arch. Example: ```--gpu-architecture=gfx906:sramecc+:xnack-```, its equivalent to ```--offload-arch```.
|
||||
- This option is compulsory if compilation is done on a system without AMD GPUs supported by HIP runtime.
|
||||
- Otherwise, HIPRTC will load the hip runtime and gather the current device and its architecture info and use it as option.
|
||||
- ```-fgpu-rdc``` : This flag when provided during the hiprtcCompileProgram generates the bitcode (HIPRTC doesn't convert this bitcode into ISA and binary). This bitcode can later be fetched using hiprtcGetBitcode and hiprtcGetBitcodeSize APIs.
|
||||
|
||||
#### Bitcode
|
||||
In the usual scenario, the kernel associated with hiprtcProgram is compiled into the binary which can be loaded and run. However, if -fpu-rdc option is provided in the compile options, HIPRTC calls comgr and generates only the LLVM bitcode. It doesn't convert this bitcode to ISA and generate the final binary.
|
||||
```cpp
|
||||
std::string sarg = std::string("-fgpu-rdc");
|
||||
const char* options[] = {
|
||||
sarg.c_str() };
|
||||
hiprtcCompileProgram(prog, // hiprtcProgram
|
||||
1, // Number of options
|
||||
options);
|
||||
```
|
||||
|
||||
If the compilation is successful, one can load the bitcode in a local variable using the bitcode APIs provided by HIPRTC.
|
||||
```cpp
|
||||
size_t bitCodeSize;
|
||||
hiprtcGetBitcodeSize(prog, &bitCodeSize);
|
||||
|
||||
vector<char> kernel_bitcode(bitCodeSize);
|
||||
hiprtcGetBitcode(prog, kernel_bitcode.data());
|
||||
```
|
||||
|
||||
#### CU Mode vs WGP mode
|
||||
|
||||
AMD GPUs consist of array of workgroup processors, which are built with 2 compute units(CUs) each capeable of executing SIMD32. Local data share(LDS) is shared by all the CUs inside a workgroup processor.
|
||||
|
||||
gfx10+ support execution of wavefront in CU mode and WGP mode. Please refer to section 2.3 of [RDNA3 ISA reference](https://www.amd.com/content/dam/amd/en/documents/radeon-tech-docs/instruction-set-architectures/rdna3-shader-instruction-set-architecture-feb-2023_0.pdf).
|
||||
|
||||
gfx9 and below only supports CU mode.
|
||||
|
||||
In WGP mode, 4 warps of a block can simultaneously be executed on the workgroup processor, where as in CU mode only 2 warps of a block can simultaneously execute on a CU. In theory, WGP mode might help with occupancy and increase the performance of certain HIP programs (if not bound to inter warp communication), but might incur performance penalty on other HIP programs which rely on atomics and inter warp communication. This also has effect of how the LDS is split between warps, please refer to [RDNA3 ISA reference](https://www.amd.com/content/dam/amd/en/documents/radeon-tech-docs/instruction-set-architectures/rdna3-shader-instruction-set-architecture-feb-2023_0.pdf) for more information.
|
||||
|
||||
HIPRTC assumes **WGP mode by default** for gfx10+. This can be overridden by passing `-mcumode` to HIPRTC compile options in `hiprtcCompileProgram`.
|
||||
|
||||
## Linker APIs
|
||||
|
||||
#### Introduction
|
||||
The bitcode generated using the HIPRTC Bitcode APIs can be loaded using hipModule APIs and also can be linked with other generated bitcodes with appropriate linker flags using the HIPRTC linker APIs. This also provides more flexibility and optimizations to the applications who want to generate the binary dynamically according to their needs. The input bitcodes can be generated only for a specific architecture or it can be a bundled bitcode which is generated for multiple architectures.
|
||||
|
||||
#### Example
|
||||
Firstly, HIPRTC link instance or a pending linker invocation must be created using hiprtcLinkCreate, with the appropriate linker options provided.
|
||||
```cpp
|
||||
hiprtcLinkCreate( num_options, // number of options
|
||||
options, // Array of options
|
||||
option_vals, // Array of option values cast to void*
|
||||
&rtc_link_state ); // HIPRTC link state created upon success
|
||||
```
|
||||
|
||||
Following which, the bitcode data can be added to this link instance via hiprtcLinkAddData (if the data is present as a string) or hiprtcLinkAddFile (if the data is present as a file) with the appropriate input type according to the data or the bitcode used.
|
||||
```cpp
|
||||
hiprtcLinkAddData(rtc_link_state, // HIPRTC link state
|
||||
input_type, // type of the input data or bitcode
|
||||
bit_code_ptr, // input data which is null terminated
|
||||
bit_code_size, // size of the input data
|
||||
"a", // optional name for this input
|
||||
0, // size of the options
|
||||
0, // Array of options applied to this input
|
||||
0); // Array of option values cast to void*
|
||||
```
|
||||
```cpp
|
||||
hiprtcLinkAddFile(rtc_link_state, // HIPRTC link state
|
||||
input_type, // type of the input data or bitcode
|
||||
bc_file_path.c_str(), // path to the input file where bitcode is present
|
||||
0, // size of the options
|
||||
0, // Array of options applied to this input
|
||||
0); // Array of option values cast to void*
|
||||
```
|
||||
|
||||
Once the bitcodes for multiple archs are added to the link instance, the linking of the device code must be completed using hiprtcLinkComplete which generates the final binary.
|
||||
```cpp
|
||||
hiprtcLinkComplete(rtc_link_state, // HIPRTC link state
|
||||
&binary, // upon success, points to the output binary
|
||||
&binarySize); // size of the binary is stored (optional)
|
||||
```
|
||||
|
||||
If the hiprtcLinkComplete returns successfully, the generated binary can be loaded and run using the hipModule* APIs.
|
||||
```cpp
|
||||
hipModuleLoadData(&module, binary);
|
||||
```
|
||||
|
||||
#### Note
|
||||
- The compiled binary must be loaded before HIPRTC link instance is destroyed using the hiprtcLinkDestroy API.
|
||||
```cpp
|
||||
hiprtcLinkDestroy(rtc_link_state);
|
||||
```
|
||||
- The correct sequence of calls is : hiprtcLinkCreate, hiprtcLinkAddData or hiprtcLinkAddFile, hiprtcLinkComplete, hiprtcModuleLoadData, hiprtcLinkDestroy.
|
||||
|
||||
#### Input Types
|
||||
HIPRTC provides hiprtcJITInputType enumeration type which defines the input types accepted by the Linker APIs. Here are the enum values of hiprtcJITInputType. However only the input types HIPRTC_JIT_INPUT_LLVM_BITCODE, HIPRTC_JIT_INPUT_LLVM_BUNDLED_BITCODE and HIPRTC_JIT_INPUT_LLVM_ARCHIVES_OF_BUNDLED_BITCODE are supported currently.
|
||||
|
||||
HIPRTC_JIT_INPUT_LLVM_BITCODE can be used to load both LLVM bitcode or LLVM IR assembly code. However, HIPRTC_JIT_INPUT_LLVM_BUNDLED_BITCODE and HIPRTC_JIT_INPUT_LLVM_ARCHIVES_OF_BUNDLED_BITCODE are only for bundled bitcode and archive of bundled bitcode.
|
||||
|
||||
```cpp
|
||||
HIPRTC_JIT_INPUT_CUBIN = 0,
|
||||
HIPRTC_JIT_INPUT_PTX,
|
||||
HIPRTC_JIT_INPUT_FATBINARY,
|
||||
HIPRTC_JIT_INPUT_OBJECT,
|
||||
HIPRTC_JIT_INPUT_LIBRARY,
|
||||
HIPRTC_JIT_INPUT_NVVM,
|
||||
HIPRTC_JIT_NUM_LEGACY_INPUT_TYPES,
|
||||
HIPRTC_JIT_INPUT_LLVM_BITCODE = 100,
|
||||
HIPRTC_JIT_INPUT_LLVM_BUNDLED_BITCODE = 101,
|
||||
HIPRTC_JIT_INPUT_LLVM_ARCHIVES_OF_BUNDLED_BITCODE = 102,
|
||||
HIPRTC_JIT_NUM_INPUT_TYPES = (HIPRTC_JIT_NUM_LEGACY_INPUT_TYPES + 3)
|
||||
```
|
||||
|
||||
#### Backward Compatibility of LLVM Bitcode/IR
|
||||
|
||||
For HIP applications utilizing HIPRTC to compile LLVM bitcode/IR, compatibility is assured only when the ROCm or HIP SDK version used for generating the LLVM bitcode/IR matches the version used during the runtime compilation. When an application requires the ingestion of bitcode/IR not derived from the currently installed AMD compiler, it must run with HIPRTC and COMgr dynamic libraries that are compatible with the version of the bitcode/IR.
|
||||
|
||||
COMgr, a shared library, incorporates the LLVM/Clang compiler that HIPRTC relies on. To identify the bitcode/IR version that COMgr is compatible with, one can execute "clang -v" using the clang binary from the same ROCm or HIP SDK package. For instance, if compiling bitcode/IR version 14, the HIPRTC and COMgr libraries released by AMD around mid 2022 would be the best choice, assuming the LLVM/Clang version included in the package is also version 14.
|
||||
|
||||
To ensure smooth operation and compatibility, an application may choose to ship the specific versions of HIPRTC and COMgr dynamic libraries, or it may opt to clearly specify the version requirements and dependencies. This approach guarantees that the application can correctly compile the specified version of bitcode/IR.
|
||||
|
||||
#### Link Options
|
||||
- `HIPRTC_JIT_IR_TO_ISA_OPT_EXT` - AMD Only. Options to be passed on to link step of compiler by `hiprtcLinkCreate`.
|
||||
- `HIPRTC_JIT_IR_TO_ISA_OPT_COUNT_EXT` - AMD Only. Count of options passed on to link step of compiler.
|
||||
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
const char* isaopts[] = {"-mllvm", "-inline-threshold=1", "-mllvm", "-inlinehint-threshold=1"};
|
||||
std::vector<hiprtcJIT_option> jit_options = {HIPRTC_JIT_IR_TO_ISA_OPT_EXT,
|
||||
HIPRTC_JIT_IR_TO_ISA_OPT_COUNT_EXT};
|
||||
size_t isaoptssize = 4;
|
||||
const void* lopts[] = {(void*)isaopts, (void*)(isaoptssize)};
|
||||
hiprtcLinkState linkstate;
|
||||
hiprtcLinkCreate(2, jit_options.data(), (void**)lopts, &linkstate);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
HIPRTC defines the hiprtcResult enumeration type and a function hiprtcGetErrorString for API call error handling. hiprtcResult enum defines the API result codes. HIPRTC APIs return hiprtcResult to indicate the call result. hiprtcGetErrorString function returns a string describing the given hiprtcResult code, e.g., HIPRTC_SUCCESS to "HIPRTC_SUCCESS". For unrecognized enumeration values, it returns "Invalid HIPRTC error code".
|
||||
|
||||
hiprtcResult enum supported values and the hiprtcGetErrorString usage are mentioned below.
|
||||
```cpp
|
||||
HIPRTC_SUCCESS = 0,
|
||||
HIPRTC_ERROR_OUT_OF_MEMORY = 1,
|
||||
HIPRTC_ERROR_PROGRAM_CREATION_FAILURE = 2,
|
||||
HIPRTC_ERROR_INVALID_INPUT = 3,
|
||||
HIPRTC_ERROR_INVALID_PROGRAM = 4,
|
||||
HIPRTC_ERROR_INVALID_OPTION = 5,
|
||||
HIPRTC_ERROR_COMPILATION = 6,
|
||||
HIPRTC_ERROR_LINKING = 7,
|
||||
HIPRTC_ERROR_BUILTIN_OPERATION_FAILURE = 8,
|
||||
HIPRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION = 9,
|
||||
HIPRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION = 10,
|
||||
HIPRTC_ERROR_NAME_EXPRESSION_NOT_VALID = 11,
|
||||
HIPRTC_ERROR_INTERNAL_ERROR = 12
|
||||
```
|
||||
```cpp
|
||||
hiprtcResult result;
|
||||
result = hiprtcCompileProgram(prog, 1, opts);
|
||||
if (result != HIPRTC_SUCCESS) {
|
||||
std::cout << "hiprtcCompileProgram fails with error " << hiprtcGetErrorString(result);
|
||||
}
|
||||
```
|
||||
|
||||
## HIPRTC General APIs
|
||||
HIPRTC provides the following API for querying the version.
|
||||
|
||||
hiprtcVersion(int* major, int* minor) - This sets the output parameters major and minor with the HIP Runtime compilation major version and minor version number respectively.
|
||||
|
||||
Currently, it returns hardcoded value. This should be implemented to return HIP runtime major and minor version in the future releases.
|
||||
|
||||
## Lowered Names (Mangled Names)
|
||||
HIPRTC mangles the ```__global__``` function names and names of ```__device__``` and ```__constant__``` variables. If the generated binary is being loaded using the HIP Runtime API, the kernel function or ```__device__/__constant__``` variable must be looked up by name, but this is very hard when the name has been mangled. To overcome this, HIPRTC provides API functions that map ```__global__``` function or ```__device__/__constant__``` variable names in the source to the mangled names present in the generated binary.
|
||||
|
||||
The two APIs hiprtcAddNameExpression and hiprtcGetLoweredName provide this functionality. First, a 'name expression' string denoting the address for the ```__global__``` function or ```__device__/__constant__``` variable is provided to hiprtcAddNameExpression. Then, the program is compiled with hiprtcCompileProgram. During compilation, HIPRTC will parse the name expression string as a C++ constant expression at the end of the user program. Finally, the function hiprtcGetLoweredName is called with the original name expression and it returns a pointer to the lowered name. The lowered name can be used to refer to the kernel or variable in the HIP Runtime API.
|
||||
|
||||
#### Note
|
||||
- The identical name expression string must be provided on a subsequent call to hiprtcGetLoweredName to extract the lowered name.
|
||||
- The correct sequence of calls is : hiprtcAddNameExpression, hiprtcCompileProgram, hiprtcGetLoweredName, hiprtcDestroyProgram.
|
||||
- The lowered names must be fetched using hiprtcGetLoweredName only after the HIPRTC program has been compiled, and before it has been destroyed.
|
||||
|
||||
#### Example
|
||||
kernel containing various definitions ```__global__``` functions/function templates and ```__device__/__constant__``` variables can be stored in a string.
|
||||
|
||||
```cpp
|
||||
static constexpr const char gpu_program[]{
|
||||
R"(
|
||||
__device__ int V1; // set from host code
|
||||
static __global__ void f1(int *result) { *result = V1 + 10; }
|
||||
namespace N1 {
|
||||
namespace N2 {
|
||||
__constant__ int V2; // set from host code
|
||||
__global__ void f2(int *result) { *result = V2 + 20; }
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
__global__ void f3(int *result) { *result = sizeof(T); }
|
||||
)"};
|
||||
```
|
||||
hiprtcAddNameExpression is called with various name expressions referring to the address of ```__global__``` functions and ```__device__/__constant__``` variables.
|
||||
|
||||
```cpp
|
||||
kernel_name_vec.push_back("&f1");
|
||||
kernel_name_vec.push_back("N1::N2::f2");
|
||||
kernel_name_vec.push_back("f3<int>");
|
||||
for (auto&& x : kernel_name_vec) hiprtcAddNameExpression(prog, x.c_str());
|
||||
variable_name_vec.push_back("&V1");
|
||||
variable_name_vec.push_back("&N1::N2::V2");
|
||||
for (auto&& x : variable_name_vec) hiprtcAddNameExpression(prog, x.c_str());
|
||||
```
|
||||
|
||||
After which, the program is compiled using hiprtcCompileProgram and the generated binary is loaded using hipModuleLoadData. And the mangled names can be fetched using hirtcGetLoweredName.
|
||||
```cpp
|
||||
for (decltype(variable_name_vec.size()) i = 0; i != variable_name_vec.size(); ++i) {
|
||||
const char* name;
|
||||
hiprtcGetLoweredName(prog, variable_name_vec[i].c_str(), &name);
|
||||
}
|
||||
```
|
||||
```cpp
|
||||
for (decltype(kernel_name_vec.size()) i = 0; i != kernel_name_vec.size(); ++i) {
|
||||
const char* name;
|
||||
hiprtcGetLoweredName(prog, kernel_name_vec[i].c_str(), &name);
|
||||
}
|
||||
```
|
||||
|
||||
The mangled name of the variables are used to look up the variable in the module and update its value.
|
||||
```
|
||||
hipDeviceptr_t variable_addr;
|
||||
size_t bytes{};
|
||||
hipModuleGetGlobal(&variable_addr, &bytes, module, name);
|
||||
hipMemcpyHtoD(variable_addr, &initial_value, sizeof(initial_value));
|
||||
```
|
||||
|
||||
Finally, the mangled name of the kernel is used to launch it using the hipModule APIs.
|
||||
|
||||
```cpp
|
||||
hipFunction_t kernel;
|
||||
hipModuleGetFunction(&kernel, module, name);
|
||||
hipModuleLaunchKernel(kernel, 1, 1, 1, 1, 1, 1, 0, nullptr, nullptr, config);
|
||||
```
|
||||
|
||||
Please have a look at hiprtcGetLoweredName.cpp for the detailed example.
|
||||
|
||||
## Versioning
|
||||
HIPRTC follows the below versioning.
|
||||
- Linux
|
||||
- HIPRTC follows the same versioning as HIP runtime library.
|
||||
- The soname field for the shared library is set to MAJOR version. eg: For HIP 5.3 the soname is set to 5 (hiprtc.so.5).
|
||||
- Windows
|
||||
- HIPRTC dll is named as hiprtcXXYY.dll where XX is MAJOR version and YY is MINOR version. eg: For HIP 5.3 the name is hiprtc0503.dll.
|
||||
|
||||
## HIP header support
|
||||
- Added HIPRTC support for all the hip common header files such as library_types.h, hip_math_constants.h, hip_complex.h, math_functions.h, surface_types.h etc. from 6.1. HIPRTC users need not include any HIP macros or constants explicitly in their header files. All of these should get included via HIPRTC builtins when the app links to HIPRTC library.
|
||||
|
||||
## Deprecation notice
|
||||
- Currently HIPRTC APIs are separated from HIP APIs and HIPRTC is available as a separate library libhiprtc.so/libhiprtc.dll. But on Linux, HIPRTC symbols are also present in libhipamd64.so in order to support the existing applications. Gradually, these symbols will be removed from HIP library and applications using HIPRTC will be required to explictly link to HIPRTC library. However, on Windows hiprtc.dll must be used as the hipamd64.dll doesn't contain the HIPRTC symbols.
|
||||
- Datatypes such as uint32_t, uint64_t, int32_t, int64_t defined in std namespace in HIPRTC are deprecated earlier and are being removed from ROCm release 6.1 since these can conflict with the standard C++ datatypes. These datatypes are now prefixed with __hip__, e.g. __hip_uint32_t. Apps previously using std::uint32_t or similar types can use __hip_ prefixed types to avoid conflicts with standard std namespace or apps can have their own definitions for these types. Also, type_traits templates previously defined in std namespace are moved to __hip_internal namespace as implementation details.
|
||||
@@ -0,0 +1,194 @@
|
||||
# HIP Programming Manual
|
||||
|
||||
## Host Memory
|
||||
|
||||
### Introduction
|
||||
hipHostMalloc allocates pinned host memory which is mapped into the address space of all GPUs in the system, the memory can be accessed directly by the GPU device, and can be read or written with much higher bandwidth than pageable memory obtained with functions such as malloc().
|
||||
There are two use cases for this host memory:
|
||||
- Faster HostToDevice and DeviceToHost Data Transfers:
|
||||
The runtime tracks the hipHostMalloc allocations and can avoid some of the setup required for regular unpinned memory. For exact measurements on a specific system, experiment with --unpinned and --pinned switches for the hipBusBandwidth tool.
|
||||
- Zero-Copy GPU Access:
|
||||
GPU can directly access the host memory over the CPU/GPU interconnect, without need to copy the data. This avoids the need for the copy, but during the kernel access each memory access must traverse the interconnect, which can be tens of times slower than accessing the GPU's local device memory. Zero-copy memory can be a good choice when the memory accesses are infrequent (perhaps only once). Zero-copy memory is typically "Coherent" and thus not cached by the GPU but this can be overridden if desired.
|
||||
|
||||
### Memory allocation flags
|
||||
There are flags parameter which can specify options how to allocate the memory, for example,
|
||||
hipHostMallocPortable, the memory is considered allocated by all contexts, not just the one on which the allocation is made.
|
||||
hipHostMallocMapped, will map the allocation into the address space for the current device, and the device pointer can be obtained with the API hipHostGetDevicePointer().
|
||||
hipHostMallocNumaUser is the flag to allow host memory allocation to follow Numa policy by user. Please note this flag is currently only applicable on Linux, under development on Windows.
|
||||
|
||||
All allocation flags are independent, and can be used in any combination without restriction, for instance, hipHostMalloc can be called with both hipHostMallocPortable and hipHostMallocMapped flags set. Both usage models described above use the same allocation flags, and the difference is in how the surrounding code uses the host memory.
|
||||
|
||||
### Numa-aware host memory allocation
|
||||
Numa policy determines how memory is allocated.
|
||||
Target of Numa policy is to select a CPU that is closest to each GPU.
|
||||
Numa distance is the measurement of how far between GPU and CPU devices.
|
||||
|
||||
By default, each GPU selects a Numa CPU node that has the least Numa distance between them, that is, host memory will be automatically allocated closest on the memory pool of Numa node of the current GPU device. Using hipSetDevice API to a different GPU will still be able to access the host allocation, but can have longer Numa distance.
|
||||
Note, Numa policy is so far implemented on Linux, and under development on Windows.
|
||||
|
||||
|
||||
### Coherency Controls
|
||||
ROCm defines two coherency options for host memory:
|
||||
- Coherent memory : Supports fine-grain synchronization while the kernel is running. For example, a kernel can perform atomic operations that are visible to the host CPU or to other (peer) GPUs. Synchronization instructions include threadfence_system and C++11-style atomic operations.
|
||||
In order to achieve this fine-grained coherence, many AMD GPUs use a limited cache policy, such as leaving these allocations uncached by the GPU, or making them read-only.
|
||||
|
||||
- Non-coherent memory : Can be cached by GPU, but cannot support synchronization while the kernel is running. Non-coherent memory can be optionally synchronized only at command (end-of-kernel or copy command) boundaries. This memory is appropriate for high-performance access when fine-grain synchronization is not required.
|
||||
|
||||
HIP provides the developer with controls to select which type of memory is used via allocation flags passed to hipHostMalloc and the HIP_HOST_COHERENT environment variable. By default, the environment variable HIP_HOST_COHERENT is set to 0 in HIP.
|
||||
The control logic in the current version of HIP is as follows:
|
||||
- No flags are passed in: the host memory allocation is coherent, the HIP_HOST_COHERENT environment variable is ignored.
|
||||
- hipHostMallocCoherent=1: The host memory allocation will be coherent, the HIP_HOST_COHERENT environment variable is ignored.
|
||||
- hipHostMallocMapped=1: The host memory allocation will be coherent, the HIP_HOST_COHERENT environment variable is ignored.
|
||||
- hipHostMallocNonCoherent=1, hipHostMallocCoherent=0, and hipHostMallocMapped=0: The host memory will be non-coherent, the HIP_HOST_COHERENT environment variable is ignored.
|
||||
- hipHostMallocCoherent=0, hipHostMallocNonCoherent=0, hipHostMallocMapped=0, but one of the other HostMalloc flags is set:
|
||||
- If HIP_HOST_COHERENT is defined as 1, the host memory allocation is coherent.
|
||||
- If HIP_HOST_COHERENT is not defined, or defined as 0, the host memory allocation is non-coherent.
|
||||
- hipHostMallocCoherent=1, hipHostMallocNonCoherent=1: Illegal.
|
||||
|
||||
### Visibility of Zero-Copy Host Memory
|
||||
Coherent host memory is automatically visible at synchronization points.
|
||||
Non-coherent
|
||||
|
||||
| HIP API | Synchronization Effect | Fence | Coherent Host Memory Visibiity | Non-Coherent Host Memory Visibility|
|
||||
| --- | --- | --- | --- | --- |
|
||||
| hipStreamSynchronize | host waits for all commands in the specified stream to complete | system-scope release | yes | yes |
|
||||
| hipDeviceSynchronize | host waits for all commands in all streams on the specified device to complete | system-scope release | yes | yes |
|
||||
| hipEventSynchronize | host waits for the specified event to complete | device-scope release | yes | depends - see below|
|
||||
| hipStreamWaitEvent | stream waits for the specified event to complete | none | yes | no |
|
||||
|
||||
|
||||
### hipEventSynchronize
|
||||
Developers can control the release scope for hipEvents:
|
||||
- By default, the GPU performs a device-scope acquire and release operation with each recorded event. This will make host and device memory visible to other commands executing on the same device.
|
||||
|
||||
A stronger system-level fence can be specified when the event is created with hipEventCreateWithFlags:
|
||||
- hipEventReleaseToSystem : Perform a system-scope release operation when the event is recorded. This will make both Coherent and Non-Coherent host memory visible to other agents in the system, but may involve heavyweight operations such as cache flushing. Coherent memory will typically use lighter-weight in-kernel synchronization mechanisms such as an atomic operation and thus does not need to use hipEventReleaseToSystem.
|
||||
- hipEventDisableTiming: Events created with this flag would not record profiling data and provide best performance if used for synchronization.
|
||||
|
||||
### Summary and Recommendations:
|
||||
|
||||
- Coherent host memory is the default and is the easiest to use since the memory is visible to the CPU at typical synchronization points. This memory allows in-kernel synchronization commands such as threadfence_system to work transparently.
|
||||
- HIP/ROCm also supports the ability to cache host memory in the GPU using the "Non-Coherent" host memory allocations. This can provide performance benefit, but care must be taken to use the correct synchronization.
|
||||
|
||||
### Managed memory allocation
|
||||
Managed memory, including the `__managed__` keyword, is supported in HIP combined host/device compilation, on Linux, not on Windows (under development).
|
||||
|
||||
Managed memory, via unified memory allocation, allows data be shared and accessible to both the CPU and GPU using a single pointer.
|
||||
The allocation will be managed by AMD GPU driver using the linux HMM (Heterogeneous Memory Management) mechanism, the user can call managed memory API hipMallocManaged to allocate a large chuch of HMM memory, execute kernels on device and fetch data between the host and device as needed.
|
||||
|
||||
In HIP application, It is recommend to do the capability check before calling the managed memory APIs. For example:
|
||||
|
||||
```
|
||||
int managed_memory = 0;
|
||||
HIPCHECK(hipDeviceGetAttribute(&managed_memory,
|
||||
hipDeviceAttributeManagedMemory,p_gpuDevice));
|
||||
|
||||
if (!managed_memory ) {
|
||||
printf ("info: managed memory access not supported on the device %d\n Skipped\n", p_gpuDevice);
|
||||
}
|
||||
else {
|
||||
HIPCHECK(hipSetDevice(p_gpuDevice));
|
||||
HIPCHECK(hipMallocManaged(&Hmm, N * sizeof(T)));
|
||||
. . .
|
||||
}
|
||||
```
|
||||
Please note, the managed memory capability check may not be necessary, but if HMM is not supported, then managed malloc will fall back to using system memory and other managed memory API calls will have undefined behavior.
|
||||
|
||||
Note, managed memory management is implemented on Linux, not supported on Windows yet.
|
||||
|
||||
### HIP Stream Memory Operations
|
||||
|
||||
HIP supports Stream Memory Operations to enable direct synchronization between Network Nodes and GPU. Following new APIs are added,
|
||||
hipStreamWaitValue32
|
||||
hipStreamWaitValue64
|
||||
hipStreamWriteValue32
|
||||
hipStreamWriteValue64
|
||||
|
||||
Note, CPU access to the semaphore's memory requires volatile keyword to disable CPU compiler's optimizations on memory access.
|
||||
For more details, please check the documentation HIP-API.pdf.
|
||||
|
||||
Please note, HIP stream does not gurantee concurrency on AMD hardware for the case of multiple (at least 6) long running streams executing concurrently, using hipStreamSynchronize(nullptr) for synchronization.
|
||||
|
||||
## Direct Dispatch
|
||||
HIP runtime has Direct Dispatch enabled by default in ROCM 4.4 on Linux.
|
||||
With this feature we move away from our conventional producer-consumer model where the runtime creates a worker thread(consumer) for each HIP Stream, and the host thread(producer) enqueues commands to a command queue(per stream).
|
||||
|
||||
For Direct Dispatch, HIP runtime would directly enqueue a packet to the AQL queue (user mode queue on GPU) on the Dispatch API call from the application. That has shown to reduce the latency to launch the first wave on the idle GPU and total time of tiny dispatches synchronized with the host.
|
||||
|
||||
In addition, eliminating the threads in runtime has reduced the variance in the dispatch numbers as the thread scheduling delays and atomics/locks synchronization latencies are reduced.
|
||||
|
||||
This feature can be disabled via setting the following environment variable,
|
||||
AMD_DIRECT_DISPATCH=0
|
||||
|
||||
Note, Direct Dispatch is implemented on Linux. It is currently not supported on Windows.
|
||||
|
||||
## HIP Runtime Compilation
|
||||
HIP now supports runtime compilation (HIPRTC), the usage of which will provide the possibility of optimizations and performance improvement compared with other APIs via regular offline static compilation.
|
||||
|
||||
HIPRTC APIs accept HIP source files in character string format as input parameters and create handles of programs by compiling the HIP source files without spawning separate processes.
|
||||
|
||||
For more details on HIPRTC APIs, refer to [HIP Runtime API Reference](https://rocm.docs.amd.com/projects/HIP/en/latest/doxygen/html/index.html).
|
||||
|
||||
For Linux developers, the link [here](https://github.com/ROCm/hip-tests/blob/develop/samples/2_Cookbook/23_cmake_hiprtc/saxpy.cpp) shows an example how to program HIP application using runtime compilation mechanism, and detail HIPRTC programming guide is also available in Github (https://github.com/ROCm/HIP/blob/develop/docs/user_guide/hip_rtc.md).
|
||||
|
||||
## HIP Graph
|
||||
HIP graph is supported. For more details, refer to the HIP API Guide.
|
||||
|
||||
## Device-Side Malloc
|
||||
|
||||
HIP-Clang now supports device-side malloc and free.
|
||||
This implementation does not require the use of `hipDeviceSetLimit(hipLimitMallocHeapSize,value)` nor respects any setting. The heap is fully dynamic and can grow until the available free memory on the device is consumed.
|
||||
|
||||
## Use of Per-thread default stream
|
||||
|
||||
The per-thread default stream is supported in HIP. It is an implicit stream local to both the thread and the current device. This means that the command issued to the per-thread default stream by the thread does not implicitly synchronize with other streams (like explicitly created streams), or default per-thread stream on other threads.
|
||||
The per-thread default stream is a blocking stream and will synchronize with the default null stream if both are used in a program.
|
||||
The per-thread default stream can be enabled via adding a compilation option,
|
||||
"-fgpu-default-stream=per-thread".
|
||||
|
||||
And users can explicitly use "hipStreamPerThread" as per-thread default stream handle as input in API commands. There are test codes as examples in the [link](https://github.com/ROCm/hip-tests/tree/develop/catch/unit/streamperthread).
|
||||
|
||||
## Use of Long Double Type
|
||||
|
||||
In HIP-Clang, long double type is 80-bit extended precision format for x86_64, which is not supported by AMDGPU. HIP-Clang treats long double type as IEEE double type for AMDGPU. Using long double type in HIP source code will not cause issue as long as data of long double type is not transferred between host and device. However, long double type should not be used as kernel argument type.
|
||||
|
||||
## Use of _Float16 Type
|
||||
|
||||
If a host function is to be used between clang (or hipcc) and gcc for x86_64, i.e. its definition is compiled by one compiler but the caller is compiled by a different compiler, _Float16 or aggregates containing _Float16 should not be used as function argument or return type. This is due to lack of stable ABI for _Float16 on x86_64. Passing _Float16 or aggregates containing _Float16 between clang and gcc could cause undefined behavior.
|
||||
|
||||
## FMA and contractions
|
||||
|
||||
By default HIP-Clang assumes -ffp-contract=fast-honor-pragmas.
|
||||
Users can use '#pragma clang fp contract(on|off|fast)' to control fp contraction of a block of code.
|
||||
For x86_64, FMA is off by default since the generic x86_64 target does not
|
||||
support FMA by default. To turn on FMA on x86_64, either use -mfma or -march=native
|
||||
on CPU's supporting FMA.
|
||||
|
||||
When contractions are enabled and the CPU has not enabled FMA instructions, the
|
||||
GPU can produce different numerical results than the CPU for expressions that
|
||||
can be contracted. Tolerance should be used for floating point comparsions.
|
||||
|
||||
## Math functions with special rounding modes
|
||||
|
||||
Note: Currently, HIP only supports basic math functions with rounding mode rn (round to nearest). HIP does not support basic math functions with rounding modes ru (round up), rd (round down), and rz (round towards zero).
|
||||
|
||||
## Creating Static Libraries
|
||||
|
||||
HIP-Clang supports generating two types of static libraries. The first type of static library does not export device functions, and only exports and launches host functions within the same library. The advantage of this type is the ability to link with a non-hipcc compiler such as gcc. The second type exports device functions to be linked by other code objects. However this requires using hipcc as the linker.
|
||||
|
||||
In addition, the first type of library contains host objects with device code embedded as fat binaries. It is generated using the flag --emit-static-lib. The second type of library contains relocatable device objects and is generated using ar.
|
||||
|
||||
Here is an example to create and use static libraries:
|
||||
- Type 1 using --emit-static-lib:
|
||||
```
|
||||
hipcc hipOptLibrary.cpp --emit-static-lib -fPIC -o libHipOptLibrary.a
|
||||
gcc test.cpp -L. -lhipOptLibrary -L/path/to/hip/lib -lamdhip64 -o test.out
|
||||
```
|
||||
- Type 2 using system ar:
|
||||
```
|
||||
hipcc hipDevice.cpp -c -fgpu-rdc -o hipDevice.o
|
||||
ar rcsD libHipDevice.a hipDevice.o
|
||||
hipcc libHipDevice.a test.cpp -fgpu-rdc -o test.out
|
||||
```
|
||||
|
||||
For more information, please see [HIP samples](https://github.com/ROCm/hip-tests/tree/develop/samples/2_Cookbook/15_static_library/host_functions) and [samples](https://github.com/ROCm/hip-tests/tree/rocm-5.5.x/samples/2_Cookbook/15_static_library/device_functions).
|
||||
Αναφορά σε νέο ζήτημα
Block a user