Doxysphinx docs (#3192)
* Reorganize documenation based on rocm-docs-core
* Move build, install and contributing guides to docs
* Bump readthedocs config to Ubuntu 20.04
* Add more direct links to the API modules
* Pin rocm-docs-core version, add dependabot
- Use the pip package to have rocm-docs-core pinned
- Add dependabot config to update pinned packages (including rocm-docs-core)
* fixup! Add more direct links to the API modules
---------
[ROCm/hip commit: ae5f8714f4]
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# 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](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 5.5 :
|
||||
- CUPTI (not directly supported, [AMD GPUPerfAPI](http://developer.amd.com/tools-and-sdks/graphics-development/gpuperfapi/) can be used as an alternative in some cases)
|
||||
- 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 ROCclr?
|
||||
ROCclr (Radeon Open Compute Common Language Runtime) is a virtual device interface that compute runtimes interact with backends such as ROCr on Linux, as well as PAL on Windows.
|
||||
|
||||
## What is HIPAMD?
|
||||
HIPAMD is a repository branched out from HIP, mainly the implementation for AMD GPU.
|
||||
|
||||
## 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 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 message hipErrorNoBinaryForGpu Unable to find code object for all current devices?
|
||||
|
||||
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` to only enable GPUs for which code object is available. This will limit the GPUs visible to your application and allow it to run.
|
||||
|
||||
## 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 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,322 @@
|
||||
# HIP RTC Programming Guide
|
||||
|
||||
## HIP RTC lib
|
||||
HIP allows you to compile kernels at runtime with its ```hiprtc*``` APIs.
|
||||
Kernels can be store 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. We 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());
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
#### 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
|
||||
- Currently, the HIPRTC dll doesn't have any version attached. It is just named as hiprtc.dll.
|
||||
- In the upcoming releases, HIPRTC dll will be named as hiprtc_XXYY.dll where XX is MAJOR version and YY is MINOR version. eg: For HIP 5.3 the name is hiprtc_0503.dll.
|
||||
|
||||
## 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 and will be removed in the upcoming releases since these can conflict with the standard C++ datatypes. These datatypes are now prefixed with __hip__, e.g. __hip_uint32_t. type_traits templates previously defined in std namespace are moved to __hip_internal namespace as implementation details. Apps previously using std::uint32_t or similar types should use __hip_ prefixed types to avoid conflicts with standard std namespace.
|
||||
@@ -0,0 +1,191 @@
|
||||
# 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.
|
||||
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.
|
||||
|
||||
See the hipHostMalloc API for more information.
|
||||
|
||||
### 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.
|
||||
|
||||
### Managed memory allocation
|
||||
Managed memory, including the `__managed__` keyword, is supported in HIP combined host/device compilation.
|
||||
|
||||
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.
|
||||
For more details on managed memory APIs, please refer to the documentation HIP-API.pdf, and the application at (https://github.com/ROCm-Developer-Tools/HIP/blob/rocm-4.5.x/tests/src/runtimeApi/memory/hipMallocManaged.cpp) is a sample usage.
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.
|
||||
|
||||
## Direct Dispatch
|
||||
HIP runtime has Direct Dispatch enabled by default in ROCM 4.4. 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
|
||||
|
||||
## 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-API.pdf in GitHub (https://github.com/RadeonOpenCompute/ROCm).
|
||||
|
||||
The link here(https://github.com/ROCm-Developer-Tools/HIP/blob/main/tests/src/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-Developer-Tools/HIP/blob/main/docs/markdown/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.
|
||||
|
||||
The test codes in the link (https://github.com/ROCm-Developer-Tools/HIP/blob/develop/tests/src/deviceLib/hipDeviceMalloc.cpp) show how to implement application using malloc and free functions in device kernels.
|
||||
|
||||
## 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-Developer-Tools/HIP/tree/develop/tests/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
|
||||
|
||||
HIP does not support math functions with rounding modes ru (round up), rd (round down), and rz (round towards zero). HIP only supports math function with rounding mode rn (round to nearest). The math functions with postfixes _ru, _rd and _rz are implemented in the same way as math functions with postfix _rn. They serve as a workaround to get programs using them compiled.
|
||||
|
||||
## 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 samples/2_Cookbook/15_static_library/host_functions and samples/2_Cookbook/15_static_library/device_functions.
|
||||
Reference in New Issue
Block a user