Day 90

GPU Kernels Learning Journey

Description

### Files: `FrobeniusNorm.cu` I implemented a code that performs thee Frobenius Norm.

Code Files

FrobeniusNorm.cu

#include <cuda_runtime.h>


__global__ void calculateSumOfSquares(const float* X, float* partialSums, size_t size) {
    extern __shared__ float sharedData[];
    
   
    unsigned int tid = threadIdx.x;
    unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;
    

    sharedData[tid] = 0.0f;
    
    
    while (i < size) {
        sharedData[tid] += X[i] * X[i];
        i += blockDim.x * gridDim.x;
    }
    
    
    __syncthreads();
    
   
    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
        if (tid < s) {
            sharedData[tid] += sharedData[tid + s];
        }
        __syncthreads();
    }
    
    
    if (tid == 0) {
        partialSums[blockIdx.x] = sharedData[0];
    }
}


__global__ void normalizeByFrobeniusNorm(const float* X, float* Y, size_t size, float frobeniusNorm) {
    unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;
    
    if (i < size) {
        Y[i] = X[i] / frobeniusNorm;
    }
}

extern "C" void solution(const float* X, float* Y, size_t size) {
    
    int blockSize = 256;
    int gridSize = (size + blockSize - 1) / blockSize;
    int maxBlocks = 1024; 
    
    if (gridSize > maxBlocks) {
        gridSize = maxBlocks;
    }
    
    float* d_partialSums;
    cudaMalloc(&d_partialSums, gridSize * sizeof(float));
    
    calculateSumOfSquares<<<gridSize, blockSize, blockSize * sizeof(float)>>>(X, d_partialSums, size);
    
    float* h_partialSums = new float[gridSize];
    cudaMemcpy(h_partialSums, d_partialSums, gridSize * sizeof(float), cudaMemcpyDeviceToHost);
    
    float sumOfSquares = 0.0f;
    for (int i = 0; i < gridSize; i++) {
        sumOfSquares += h_partialSums[i];
    }
    
    float frobeniusNorm = sqrt(sumOfSquares);
    
    if (frobeniusNorm < 1e-10) {
        frobeniusNorm = 1.0f; 
    }
    
    normalizeByFrobeniusNorm<<<(size + blockSize - 1) / blockSize, blockSize>>>(X, Y, size, frobeniusNorm);
    
    delete[] h_partialSums;
    cudaFree(d_partialSums);
}