Skip to content
Snippets Groups Projects
amd.md 15.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jan Siwiec's avatar
    Jan Siwiec committed
    # Using AMD Partition
    
    For testing your application on the AMD partition,
    you need to prepare a job script for that partition or use the interactive job:
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    salloc -N 1 -c 64 -A PROJECT-ID -p p03-amd --gres=gpu:4 --time=08:00:00
    ```
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    where:
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    - `-N 1` means allocating one server,
    - `-c 64` means allocating 64 cores,
    - `-A` is your project,
    - `-p p03-amd` is AMD partition,
    - `--gres=gpu:4` means allocating all 4 GPUs of the node,
    - `--time=08:00:00` means allocation for 8 hours.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    You have also an option to allocate subset of the resources only,
    by reducing the `-c` and `--gres=gpu` to smaller values.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    salloc -N 1 -c 48 -A PROJECT-ID -p p03-amd --gres=gpu:3 --time=08:00:00
    salloc -N 1 -c 32 -A PROJECT-ID -p p03-amd --gres=gpu:2 --time=08:00:00
    salloc -N 1 -c 16 -A PROJECT-ID -p p03-amd --gres=gpu:1 --time=08:00:00
    ```
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    !!! Note
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        p03-amd01 server has hyperthreading **enabled** therefore htop shows 128 cores.<br>
        p03-amd02 server has hyperthreading **disabled** therefore htop shows 64 cores.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ## Using AMD MI100 GPUs
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The AMD GPUs can be programmed using the [ROCm open-source platform](https://docs.amd.com/).
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    ROCm and related libraries are installed directly in the system.
    You can find it here:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    /opt/rocm/
    ```
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The actual version can be found here:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    [user@p03-amd02.cs]$ cat /opt/rocm/.info/version
    
    5.5.1-74
    ```
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ## Basic HIP Code
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The first way how to program AMD GPUs is to use HIP.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The basic vector addition code in HIP looks like this.
    This a full code and you can copy and paste it into a file.
    For this example we use `vector_add.hip.cpp`.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    #include <cstdio>
    #include <hip/hip_runtime.h>
    
    
    
    __global__ void add_vectors(float * x, float * y, float alpha, int count)
    {
        long long idx = blockIdx.x * blockDim.x + threadIdx.x;
    
        if(idx < count)
            y[idx] += alpha * x[idx];
    }
    
    int main()
    {
        // number of elements in the vectors
        long long count = 10;
    
        // allocation and initialization of data on the host (CPU memory)
        float * h_x = new float[count];
        float * h_y = new float[count];
        for(long long i = 0; i < count; i++)
        {
            h_x[i] = i;
            h_y[i] = 10 * i;
        }
    
        // print the input data
        printf("X:");
        for(long long i = 0; i < count; i++)
            printf(" %7.2f", h_x[i]);
        printf("\n");
        printf("Y:");
        for(long long i = 0; i < count; i++)
            printf(" %7.2f", h_y[i]);
        printf("\n");
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        // allocation of memory on the GPU device
        float * d_x;
        float * d_y;
        hipMalloc(&d_x, count * sizeof(float));
        hipMalloc(&d_y, count * sizeof(float));
    
        // copy the data from host memory to the device
        hipMemcpy(d_x, h_x, count * sizeof(float), hipMemcpyHostToDevice);
        hipMemcpy(d_y, h_y, count * sizeof(float), hipMemcpyHostToDevice);
    
        int tpb = 256;
        int bpg = (count - 1) / tpb + 1;
        // launch the kernel on the GPU
        add_vectors<<< bpg, tpb >>>(d_x, d_y, 100, count);
        // hipLaunchKernelGGL(add_vectors, bpg, tpb, 0, 0, d_x, d_y, 100, count);
    
        // copy the result back to CPU memory
        hipMemcpy(h_y, d_y, count * sizeof(float), hipMemcpyDeviceToHost);
    
        // print the results
        printf("Y:");
        for(long long i = 0; i < count; i++)
            printf(" %7.2f", h_y[i]);
        printf("\n");
    
        // free the allocated memory
        hipFree(d_x);
        hipFree(d_y);
        delete[] h_x;
        delete[] h_y;
    
        return 0;
    }
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    To compile the code we use `hipcc` compiler.
    For compiler information, use `hipcc --version`:
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    [user@p03-amd02.cs ~]$ hipcc --version
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    HIP version: 5.5.30202-eaf00c0b
    AMD clang version 16.0.0 (https://github.com/RadeonOpenCompute/llvm-project roc-5.5.1 23194 69ef12a7c3cc5b0ccf820bc007bd87e8b3ac3037)
    Target: x86_64-unknown-linux-gnu
    Thread model: posix
    InstalledDir: /opt/rocm-5.5.1/llvm/bin
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The code is compiled a follows:
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    hipcc vector_add.hip.cpp -o vector_add.x
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The correct output of the code is:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    [user@p03-amd02.cs ~]$ ./vector_add.x
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    X:    0.00    1.00    2.00    3.00    4.00    5.00    6.00    7.00    8.00    9.00
    Y:    0.00   10.00   20.00   30.00   40.00   50.00   60.00   70.00   80.00   90.00
    Y:    0.00  110.00  220.00  330.00  440.00  550.00  660.00  770.00  880.00  990.00
    ```
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    More details on HIP programming is in the [HIP Programming Guide](https://docs.amd.com/bundle/HIP-Programming-Guide-v5.5/page/Introduction_to_HIP_Programming_Guide.html)
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ## HIP and ROCm Libraries
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The list of official AMD libraries can be found [here](https://docs.amd.com/category/libraries).
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The libraries are installed in the same directory is ROCm
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    /opt/rocm/
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    Following libraries are installed:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    drwxr-xr-x  4 root root   44 Jun  7 14:09 hipblas
    drwxr-xr-x  3 root root   17 Jun  7 14:09 hipblas-clients
    drwxr-xr-x  3 root root   29 Jun  7 14:09 hipcub
    drwxr-xr-x  4 root root   44 Jun  7 14:09 hipfft
    drwxr-xr-x  3 root root   25 Jun  7 14:09 hipfort
    drwxr-xr-x  4 root root   32 Jun  7 14:09 hiprand
    drwxr-xr-x  4 root root   44 Jun  7 14:09 hipsolver
    drwxr-xr-x  4 root root   44 Jun  7 14:09 hipsparse
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    and
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    drwxr-xr-x  4 root root   32 Jun  7 14:09 rocalution
    drwxr-xr-x  4 root root   44 Jun  7 14:09 rocblas
    drwxr-xr-x  4 root root   44 Jun  7 14:09 rocfft
    drwxr-xr-x  4 root root   32 Jun  7 14:09 rocprim
    drwxr-xr-x  4 root root   32 Jun  7 14:09 rocrand
    drwxr-xr-x  4 root root   44 Jun  7 14:09 rocsolver
    drwxr-xr-x  4 root root   44 Jun  7 14:09 rocsparse
    drwxr-xr-x  3 root root   29 Jun  7 14:09 rocthrust
    ```
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ## Using HipBlas Library
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The basic code in HIP that uses hipBlas looks like this.
    This a full code and you can copy and paste it into a file.
    For this example we use `hipblas.hip.cpp`.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    #include <cstdio>
    #include <vector>
    #include <cstdlib>
    #include <hip/hip_runtime.h>
    #include <hipblas/hipblas.h>
    
    
    int main()
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    {
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        srand(9600);
    
        int width = 10;
        int height = 7;
        int elem_count = width * height;
    
    
        // initialization of data in CPU memory
    
        float * h_A;
        hipHostMalloc(&h_A, elem_count * sizeof(*h_A));
        for(int i = 0; i < elem_count; i++)
            h_A[i] = (100.0f * rand()) / (float)RAND_MAX;
        printf("Matrix A:\n");
        for(int r = 0; r < height; r++)
        {
            for(int c = 0; c < width; c++)
                printf("%6.3f  ", h_A[r + height * c]);
            printf("\n");
        }
    
        float * h_x;
        hipHostMalloc(&h_x, width * sizeof(*h_x));
        for(int i = 0; i < width; i++)
            h_x[i] = (100.0f * rand()) / (float)RAND_MAX;
        printf("vector x:\n");
        for(int i = 0; i < width; i++)
            printf("%6.3f  ", h_x[i]);
        printf("\n");
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        float * h_y;
        hipHostMalloc(&h_y, height * sizeof(*h_y));
        for(int i = 0; i < height; i++)
            h_x[i] = 100.0f + i;
        printf("vector y:\n");
        for(int i = 0; i < height; i++)
            printf("%6.3f  ", h_x[i]);
        printf("\n");
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        // initialization of data in GPU memory
    
        float * d_A;
        size_t pitch_A;
        hipMallocPitch((void**)&d_A, &pitch_A, height * sizeof(*d_A), width);
        hipMemcpy2D(d_A, pitch_A, h_A, height * sizeof(*d_A), height * sizeof(*d_A), width, hipMemcpyHostToDevice);
        int lda = pitch_A / sizeof(float);
    
        float * d_x;
        hipMalloc(&d_x, width * sizeof(*d_x));
        hipMemcpy(d_x, h_x, width * sizeof(*d_x), hipMemcpyHostToDevice);
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        float * d_y;
        hipMalloc(&d_y, height * sizeof(*d_y));
        hipMemcpy(d_y, h_y, height * sizeof(*d_y), hipMemcpyHostToDevice);
    
    
        // basic calculation of the result on the CPU
    
        float alpha=2.0f, beta=10.0f;
    
        for(int i = 0; i < height; i++)
            h_y[i] *= beta;
        for(int r = 0; r < height; r++)
            for(int c = 0; c < width; c++)
                h_y[r] += alpha * h_x[c] * h_A[r + height * c];
        printf("result y CPU:\n");
        for(int i = 0; i < height; i++)
            printf("%6.3f  ", h_y[i]);
        printf("\n");
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        // calculation of the result on the GPU using the hipBLAS library
    
        hipblasHandle_t blas_handle;
        hipblasCreate(&blas_handle);
    
        hipblasSgemv(blas_handle, HIPBLAS_OP_N, height, width, &alpha, d_A, lda, d_x, 1, &beta, d_y, 1);
        hipDeviceSynchronize();
    
        hipblasDestroy(blas_handle);
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
        // copy the GPU result to CPU memory and print it
        hipMemcpy(h_y, d_y, height * sizeof(*d_y), hipMemcpyDeviceToHost);
        printf("result y BLAS:\n");
        for(int i = 0; i < height; i++)
            printf("%6.3f  ", h_y[i]);
        printf("\n");
    
    
        // free all the allocated memory
        hipFree(d_A);
        hipFree(d_x);
        hipFree(d_y);
        hipHostFree(h_A);
        hipHostFree(h_x);
        hipHostFree(h_y);
    
        return 0;
    }
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The code compilation can be done as follows:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    hipcc hipblas.hip.cpp -o hipblas.x -lhipblas
    ```
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ## Using HipSolver Library
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The basic code in HIP that uses hipSolver looks like this.
    This a full code and you can copy and paste it into a file.
    For this example we use `hipsolver.hip.cpp`.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    #include <cstdio>
    #include <vector>
    #include <cstdlib>
    #include <algorithm>
    #include <hipsolver/hipsolver.h>
    #include <hipblas/hipblas.h>
    
    int main()
    {
        srand(63456);
    
        int size = 10;
    
    
        // allocation and initialization of data on host. this time we use std::vector
    
        int h_A_ld = size;
        int h_A_pitch = h_A_ld * sizeof(float);
        std::vector<float> h_A(size * h_A_ld);
        for(int r = 0; r < size; r++)
            for(int c = 0; c < size; c++)
                h_A[r * h_A_ld + c] = (10.0 * rand()) / RAND_MAX;
        printf("System matrix A:\n");
        for(int r = 0; r < size; r++)
        {
            for(int c = 0; c < size; c++)
                printf("%6.3f  ", h_A[r * h_A_ld + c]);
            printf("\n");
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        }
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        std::vector<float> h_b(size);
        for(int i = 0; i < size; i++)
            h_b[i] = (10.0 * rand()) / RAND_MAX;
        printf("RHS vector b:\n");
        for(int i = 0; i < size; i++)
            printf("%6.3f  ", h_b[i]);
        printf("\n");
    
        std::vector<float> h_x(size);
    
    
        // memory allocation on the device and initialization
    
        float * d_A;
        size_t d_A_pitch;
        hipMallocPitch((void**)&d_A, &d_A_pitch, size, size);
        int d_A_ld = d_A_pitch / sizeof(float);
    
        float * d_b;
        hipMalloc(&d_b, size * sizeof(float));
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        float * d_x;
        hipMalloc(&d_x, size * sizeof(float));
    
        int * d_piv;
        hipMalloc(&d_piv, size * sizeof(int));
    
        int * info;
        hipMallocManaged(&info, sizeof(int));
    
        hipMemcpy2D(d_A, d_A_pitch, h_A.data(), h_A_pitch, size * sizeof(float), size, hipMemcpyHostToDevice);
        hipMemcpy(d_b, h_b.data(), size * sizeof(float), hipMemcpyHostToDevice);
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
        // solving the system using hipSOLVER
    
        hipsolverHandle_t solverHandle;
        hipsolverCreate(&solverHandle);
    
        int wss_trf, wss_trs; // wss = WorkSpace Size
        hipsolverSgetrf_bufferSize(solverHandle, size, size, d_A, d_A_ld, &wss_trf);
        hipsolverSgetrs_bufferSize(solverHandle, HIPSOLVER_OP_N, size, 1, d_A, d_A_ld, d_piv, d_b, size, &wss_trs);
        float * workspace;
        int wss = std::max(wss_trf, wss_trs);
        hipMalloc(&workspace, wss * sizeof(float));
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
        hipsolverSgetrf(solverHandle, size, size, d_A, d_A_ld, workspace, wss, d_piv, info);
        hipsolverSgetrs(solverHandle, HIPSOLVER_OP_N, size, 1, d_A, d_A_ld, d_piv, d_b, size, workspace, wss, info);
    
        hipMemcpy(d_x, d_b, size * sizeof(float), hipMemcpyDeviceToDevice);
        hipMemcpy(h_x.data(), d_x, size * sizeof(float), hipMemcpyDeviceToHost);
        printf("Solution vector x:\n");
        for(int i = 0; i < size; i++)
            printf("%6.3f  ", h_x[i]);
        printf("\n");
    
        hipFree(workspace);
    
        hipsolverDestroy(solverHandle);
    
    
        // perform matrix-vector multiplication A*x using hipBLAS to check if the solution is correct
    
        hipblasHandle_t blasHandle;
        hipblasCreate(&blasHandle);
    
        float alpha = 1;
        float beta = 0;
        hipMemcpy2D(d_A, d_A_pitch, h_A.data(), h_A_pitch, size * sizeof(float), size, hipMemcpyHostToDevice);
        hipblasSgemv(blasHandle, HIPBLAS_OP_N, size, size, &alpha, d_A, d_A_ld, d_x, 1, &beta, d_b, 1);
        hipDeviceSynchronize();
    
        hipblasDestroy(blasHandle);
    
        for(int i = 0; i < size; i++)
            h_b[i] = 0;
        hipMemcpy(h_b.data(), d_b, size * sizeof(float), hipMemcpyDeviceToHost);
        printf("Check multiplication vector Ax:\n");
        for(int i = 0; i < size; i++)
            printf("%6.3f  ", h_b[i]);
        printf("\n");
    
    
        // free all the allocated memory
    
        hipFree(info);
        hipFree(d_piv);
        hipFree(d_x);
        hipFree(d_b);
        hipFree(d_A);
    
        return 0;
    }
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The code compilation can be done as follows:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    ```console
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    hipcc hipsolver.hip.cpp -o hipsolver.x -lhipblas -lhipsolver
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    ## Using OpenMP Offload to Program AMD GPUs
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The ROCm™ installation includes an LLVM-based implementation that fully supports the OpenMP 4.5 standard
    and a subset of the OpenMP 5.0 standard.
    Fortran, C/C++ compilers, and corresponding runtime libraries are included.
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    The OpenMP toolchain is automatically installed as part of the standard ROCm installation
    and is available under `/opt/rocm/llvm`. The sub-directories are:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    
    - `bin` : Compilers (flang and clang) and other binaries.
    - `examples` : The usage section below shows how to compile and run these programs.
    - `include` : Header files.
    - `lib` : Libraries including those required for target offload.
    - `lib-debug` : Debug versions of the above libraries.
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    More information can be found in the [AMD OpenMP Support Guide](https://docs.amd.com/bundle/OpenMP-Support-Guide-v5.5/page/Introduction_to_OpenMP_Support_Guide.html).
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    ## Compilation of OpenMP Code
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    Basic example that uses OpenMP offload is here.
    Again, code is complete and can be copied and pasted into a file.
    Here we use `vadd.cpp`.
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    #include <cstdio>
    #include <cstdlib>
    
    int main(int argc, char ** argv)
    {
        long long count = 1 << 20;
        if(argc > 1)
            count = atoll(argv[1]);
        long long print_count = 16;
        if(argc > 2)
            print_count = atoll(argv[2]);
    
        long long * a = new long long[count];
        long long * b = new long long[count];
        long long * c = new long long[count];
    
    #pragma omp parallel for
        for(long long i = 0; i < count; i++)
        {
            a[i] = i;
            b[i] = 10 * i;
        }
    
        printf("A: ");
        for(long long i = 0; i < print_count; i++)
            printf("%3lld ", a[i]);
        printf("\n");
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
        printf("B: ");
        for(long long i = 0; i < print_count; i++)
            printf("%3lld ", b[i]);
        printf("\n");
    
    #pragma omp target map(to: a[0:count],b[0:count]) map(from: c[0:count])
    #pragma omp teams distribute parallel for
        for(long long i = 0; i < count; i++)
        {
            c[i] = a[i] + b[i];
        }
    
        printf("C: ");
        for(long long i = 0; i < print_count; i++)
            printf("%3lld ", c[i]);
        printf("\n");
    
        delete[] a;
        delete[] b;
        delete[] c;
    
        return 0;
    }
    ```
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    This code can be compiled like this:
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    ```console
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    /opt/rocm/llvm/bin/clang++ -O3 -target x86_64-pc-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx908 vadd.cpp -o vadd.x
    ```
    
    These options are required for target offload from an OpenMP program:
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    - `-target x86_64-pc-linux-gnu`
    - `-fopenmp`
    - `-fopenmp-targets=amdgcn-amd-amdhsa`
    - `-Xopenmp-target=amdgcn-amd-amdhsa`
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    This flag specifies the GPU architecture of targeted GPU.
    You need to chage this when moving for instance to LUMI with MI250X GPU.
    The MI100 GPUs presented in CS have code `gfx908`:
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    - `-march=gfx908`
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    
    
    Jan Siwiec's avatar
    Jan Siwiec committed
    Note: You also have to include the `O0`, `O2`, `O3` or `O3` flag.
    Without this flag the execution of the compiled code fails.