/* Copyright (c) 1993-2017, NVIDIA CORPORATION. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NVIDIA CORPORATION nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include // Define some error checking macros. #define cudaErrCheck(stat) { cudaErrCheck_((stat), __FILE__, __LINE__); } void cudaErrCheck_(cudaError_t stat, const char *file, int line) { if (stat != cudaSuccess) { fprintf(stderr, "CUDA Error: %s %s %d\n", cudaGetErrorString(stat), file, line); } } #include using namespace nvcuda; // Must be multiples of 16 for wmma code to work #define MATRIX_M (16) #define MATRIX_N (16) #define MATRIX_K (16) // The only dimensions currently supported by WMMA const int WMMA_M = 16; const int WMMA_N = 16; const int WMMA_K = 16; // Performs an MxNxK GEMM (C=alpha*A*B + beta*C) assuming: // 1) Matrices are packed in memory. // 2) M, N and K are multiples of 16. // 3) Neither A nor B are transposed. // Note: This is NOT a high performance example but is for demonstration purposes only // For a high performance code please use the GEMM provided in cuBLAS. __global__ void wmma_example(half *a, half *b, float *c, int M, int N, int K, float alpha, float beta) { unsigned int start_time=0,end_time=0; // Leading dimensions. Packed with no transpositions. start_time=clock(); int lda = M; int ldb = K; int ldc = M; // Tile using a 2D grid/ int warpM = (blockIdx.x * blockDim.x + threadIdx.x) / warpSize; int warpN = (blockIdx.y * blockDim.y + threadIdx.y); // Declare the fragments wmma::fragment a_frag; wmma::fragment b_frag; wmma::fragment acc_frag; wmma::fragment c_frag; wmma::fill_fragment(c_frag, 0.0f); int i=0; int aRow = warpM * WMMA_M; int bCol = warpN * WMMA_N; int aCol = i; int bRow = i; // Bounds checking if (aRow < M && aCol < K && bRow < K && bCol < N) { wmma::load_matrix_sync(a_frag, a+aRow+aCol*lda, lda); wmma::load_matrix_sync(b_frag, b+bRow*ldb+bCol, ldb); wmma::mma_sync(c_frag, a_frag, b_frag, c_frag); //wmma::mma_sync(acc_frag, a_frag, b_frag, acc_frag); } int cRow = warpM * WMMA_M; int cCol = warpN * WMMA_N; wmma::store_matrix_sync(c + cRow + cCol * ldc, c_frag, ldc, wmma::mem_col_major); end_time=clock(); printf("clock=%d",end_time-start_time); } __global__ void convertFp32ToFp16 (half *out, float *in, int n) { int idx = blockDim.x * blockIdx.x + threadIdx.x; if (idx < n) { out[idx] = in[idx]; } } int main(int argc, char* argv[]) { float *a_fp32; float *b_fp32; half *a_fp16; half *b_fp16; float *c; float *c_cublas; float *c_wmma; float *c_host_cublas; float *c_host_wmma; float *a_host_wmma; float *b_host_wmma; float *c_init_host_wmma; cudaEvent_t startWMMA; cudaEvent_t stopWMMA; cudaErrCheck(cudaEventCreate(&startWMMA)); cudaErrCheck(cudaEventCreate(&stopWMMA)); // Use tensor cores cudaErrCheck(cudaMalloc((void**)&a_fp32, MATRIX_M * MATRIX_K * sizeof(float))); cudaErrCheck(cudaMalloc((void**)&b_fp32, MATRIX_K * MATRIX_N * sizeof(float))); cudaErrCheck(cudaMalloc((void**)&a_fp16, MATRIX_M * MATRIX_K * sizeof(half))); cudaErrCheck(cudaMalloc((void**)&b_fp16, MATRIX_K * MATRIX_N * sizeof(half))); cudaErrCheck(cudaMalloc((void**)&c, MATRIX_M * MATRIX_N * sizeof(float))); cudaErrCheck(cudaMalloc((void**)&c_wmma, MATRIX_M * MATRIX_N * sizeof(float))); c_host_wmma = (float*)malloc(MATRIX_M * MATRIX_N * sizeof(float)); c_init_host_wmma = (float*)malloc(MATRIX_M * MATRIX_N * sizeof(float)); a_host_wmma = (float*)malloc(MATRIX_M * MATRIX_K * sizeof(float)); b_host_wmma = (float*)malloc(MATRIX_K * MATRIX_N * sizeof(float)); // printf("a_fp32\n"); for(int m=0;m>> (a_fp16, a_fp32, MATRIX_M * MATRIX_K); convertFp32ToFp16 <<< (MATRIX_K * MATRIX_N + 255) / 256, 256 >>> (b_fp16, b_fp32, MATRIX_K * MATRIX_N); for(int m=0;m>> (a_fp16, b_fp16, c_wmma, MATRIX_M, MATRIX_N, MATRIX_K, alpha, beta); // wmma_example <<< gridDim, blockDim >>> (a_fp16, b_fp16, c_wmma, MATRIX_M, MATRIX_N, MATRIX_K, alpha, beta); cudaErrCheck(cudaEventRecord(stopWMMA)); // Error checking printf("\nChecking results...\n"); cudaErrCheck(cudaMemcpy(c_host_wmma, c_wmma, MATRIX_M * MATRIX_N * sizeof(float), cudaMemcpyDeviceToHost)); // printf("c_host\n"); // for(int m=0;m