带错误检测的CUDA资源管理

        项目中发现很多cuda代码很冗余,主要是有一些cuda内存相关的操作,比如cudaMemcpy之后,要进行错误检测,所以修改了一版,实现接口内部自己检测,这样代码看起来不会那么乱。

        为什么使用宏定义,而不是函数定义,是因为函数定义的话,如果希望在出错误的时候直接输出出错位置的文件和行号,就需要在使用接口的时候,将__FILE__和__LINE__传入进去,有点麻烦,因此使用了宏定义的方式

下面是具体代码:

        

#pragma once
#include <assert.h>
#include <cuda_runtime.h>
#include <string>

// 向上取整
#define iDIV_UP(a, b) ((a + b - 1) / b)
#define ALG_MAX(x,y) ((x)>(y)?(x):(y))
#define ALG_MIN(x,y) ((x)<(y)?(x):(y))
#define FLOAT_EPS  1e-6
#define FLOAT_EQUAL(v1, v2) ((fabs((v1)-(v2))) < (FLOAT_EPS))

// cblas错误检查
#define CheckCBlasError(ErrorID)        \
{                                       \
    if(CUBLAS_STATUS_SUCCESS != ErrorID)\
    {                                   \
        printf("=====Imaging Error CBlas: %s, line: %d of file: %s\n", cublasGetStatusString(ErrorID), __LINE__, __FILE__);\
        assert(false);                  \
    }                                   \
}

#define CheckCudaError(ErrorId){\
    if (cudaSuccess != ErrorId)\
    { \
        printf("=====Imaging Error Cuda: %s, file: %s : %d\n", cudaGetErrorString(ErrorId), __FILE__, __LINE__);assert(false);\
    }\
}

// Cuda显存释放
#define Cuda_Free(pData){ \
    if (nullptr != pData){\
        cudaError_t error_id = cudaFree(pData);\
        pData = nullptr;\
        CheckCudaError(error_id);\
    }\
}

// Cuda显存设置值
#define Cuda_Memset(devPtr, iValue, iSize){\
    void** ptr = (void**)&devPtr;\
    if (ptr != nullptr){\
        auto error_id = cudaMemset(*ptr, iValue, iSize);\
        CheckCudaError(error_id);\
    }\
}

// 显存申请(这个宏有问题,应该使用后面那个)
// 该宏的问题是,如果外面传进来的pData是个空指针的话,那这个位置访问空指针,肯定是不对的
#define Cuda_Malloc(pData, iSize){\
    Cuda_Free(*pData);\
    cudaError_t error_id = cudaMalloc(pData, iSize);\
    CheckCudaError(error_id);\
}



// 显存申请
// 普通显存申请是cudMalloc(void**)&ptr, size);
// 使用下面宏的话,只需要Cuda_Malloc(ptr, size)即可
#define Cuda_Malloc(pData, iSize){\
    Cuda_Free(pData);\
    auto p_cu_malloc_data = (void**)&pData;\
    cudaError_t error_id = cudaMalloc(p_cu_malloc_data, iSize);\
    CheckCudaError(error_id);\
}


#define Cuda_Memcpy(pDst, pSrc, iSize, cpyKind){\
    auto error_id = cudaMemcpy(pDst, pSrc, iSize, cpyKind);\
    CheckCudaError(error_id);\
}

第二版本

        项目中发现,现存使用统计起来比较麻烦,需要自己手动去计算使用了多少,因此在上一版本的基础上进行了部分优化,能够初步实现在申请的时候就记录申请了多少显存

头文件:

#pragma once
#include <assert.h>
#include <cuda_runtime.h>
#include <string>
#include <map>
#include <thread>
#include <mutex>
#include <sstream>
#include <fstream>

// 向上取整
#define iDIV_UP(a, b) ((a + b - 1) / b)
#define ALG_MAX(x,y) ((x)>(y)?(x):(y))
#define ALG_MIN(x,y) ((x)<(y)?(x):(y))
#define FLOAT_EPS  1e-6
#define FLOAT_EQUAL(v1, v2) ((fabs((v1)-(v2))) < (FLOAT_EPS))

//-------------------
// 显存统计检测代码
// ------------------
extern std::map<std::thread::id, std::map<std::string, std::pair<std::string, size_t>>> gAlgCudaMemCheckMap;
extern std::mutex gAlgCudaMemCheckMutex;
extern bool gbAlgCudaCheckFlag;
void OutCudaMemoryMessage();

// cblas错误检查
#define CheckCBlasError(ErrorID)        \
{                                       \
    if(CUBLAS_STATUS_SUCCESS != ErrorID)\
    {                                   \
        printf("=====Imaging Error CBlas: %s, line: %d of file: %s\n", cublasGetStatusString(ErrorID), __LINE__, __FILE__);\
        assert(false);                  \
    }                                   \
}


#define CheckCudaError(ErrorId){\
    if (cudaSuccess != ErrorId)\
    { \
        printf("=====Imaging Error Cuda: %s, file: %s : %d\n", cudaGetErrorString(ErrorId), __FILE__, __LINE__);assert(false);\
    }\
}


// Cuda显存释放
#define Cuda_Free(pData){ \
    /*下面是显存申请统计的相关代码*/   
    if (gbAlgCudaCheckFlag && nullptr != pData){                           \
        auto p_cu_malloc_data = (void**)&pData;                            \
        std::lock_guard<std::mutex> lock(gAlgCudaMemCheckMutex);           \
        auto iter = gAlgCudaMemCheckMap.find(std::this_thread::get_id());  \
        if (iter != gAlgCudaMemCheckMap.end())                             \
        {   std::stringstream ss;                                          \
            ss << *p_cu_malloc_data;                                       \
            auto iter_ptr = iter->second.find(ss.str());                   \
            if (iter_ptr != iter->second.end())                            \
                iter->second.erase(iter_ptr);                              \
        }
    }                                                                      \
    if (nullptr != pData){                      \
        cudaError_t error_id = cudaFree(pData); \
        pData = nullptr;                        \
        CheckCudaError(error_id);               \
    }                                           \
} 


// Cuda显存设置值
#define Cuda_Memset(devPtr, iValue, iSize){\
    void** ptr = (void**)&devPtr;\
    if (ptr != nullptr){\
        auto error_id = cudaMemset(*ptr, iValue, iSize);\
        CheckCudaError(error_id);\
    }\
}


// 显存申请
#define Cuda_Malloc(pData, iSize){\
    Cuda_Free(pData);\
    auto p_cu_malloc_data = (void**)&pData;\
    cudaError_t error_id = cudaMalloc(p_cu_malloc_data, iSize);\
    CheckCudaError(error_id);\
                                                              \
    /*下面是显存申请统计的相关代码*/                            \
    if (gbAlgCudaCheckFlag)                                     \
    {                                                           \
        std::lock_guard<std::mutex> lock(gAlgCudaMemCheckMutex);    \
        std::stringstream ss;                                       \
        ss <<*p_cu_malloc_data;                                                 \
        gAlgCudaMemCheckMap[std::this_thread::get_id()][ss.str()] =                 
        std::make_pair(__FILE__ + std::string(":") + std::to_string(__LINE__), iSize);\
    }\
}


#define Cuda_Memcpy(pDst, pSrc, iSize, cpyKind){\
    auto error_id = cudaMemcpy(pDst, pSrc, iSize, cpyKind);\
    CheckCudaError(error_id);\
}

.cu文件

#include "cudaCommon.cuh"

std::map<std::thread::id, std::map<std::string, std::pair<std::string, size_t>>> gAlgCudaMemCheckMap;
std::mutex gAlgCudaMemCheckMutex;
bool gbAlgCudaCheckFlag = false;

void OutCudaMemoryMessage()
{
    if (!gbAlgCudaCheckFlag)
    {
        return;
    }

    std::lock_guard<std::mutex> lock(gAlgCudaMemCheckMutex);
    for (auto& iter_thread : gAlgCudaMemCheckMap)
    {
        if (iter_thread.second.size() > 0)
        {
            std::stringstream ss;
            ss << iter_thread.first;
            std::string str_path = ss.str() + "MemInfo.txt";
            std::ofstream ofile;

            ofile.open(str_path, std::ios::app);
            if (ofile.is_open())
            {
                ofile << "===================================\n";
                ofile << "===================================\n";
                ofile << "===================================\n";
                auto& addr_map = iter_thread.second;
                for (auto& addr_iter : addr_map)
                {
                    ofile << "File: " << addr_iter.second.first << " : " <<addr_iter.second.second << "\n";
                }
                addr_map.clear();
            }
            ofile.close();
        }
    }
}

如果哪个小伙伴知道更好的实现方式,或者有现成的工具方便统计的话,希望能留言告知交流,感谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值