在主机端window系统远程调试服务器端linux系统的cuda代码

        学习任何一门语言,如何有效进行调试都是至关重要的一环。最近在学习cuda编程,自然cuda调试是我首先要掌握的基本技能。首先按照“star“原则介绍我的步骤:

情境(Situation)

一台window台式机,win7系统,硬件参数如下:

 一台装有centos系统的服务器,只罗列gpu相关的参数:

任务(Task)

使用ide调试向量相加的cuda程序(cuda-gdb太不直观了!!!)

行动(Action)

一,安装以下软件:

1window端安装vscode最新版(别问什么版本,就是最新版!)

2.linux端安装cuda

3.linux端安装cmake

4.vscode安装c++插件和nsight插件,如下图所示:

 这里补充一下:

vscode是一个集成开发环境,不限制语言,你可以调试python,c++等任何语言,前提是你得安装对应的插件以及插件对应的软件,比如,安装C/C++插件之前你得确保你安装了gcc/g++,同理,安装cmake插件之前你得保证先安装了cmake,安装nsight插件之前你得安装了cuda-toolkit。vscode只负责安装插件,不负责安装对应的软件,这是要分清楚的! 

二,准备调试相关文件

1.一个极具代表性的“向量相加“cuda程序main.cu:

#include </usr/local/cuda-10.1/targets/x86_64-linux/include/cuda_runtime.h>
#include <stdio.h>
 
__global__ void addKernel( int* c, const int* a, const int* b )
{
         int i = threadIdx.x;
         c[i]= a[i] + b[i];
}
 
cudaError_t CUDA_Add( const int* a, const int* b, int* out, int size )
{ 

         int*dev_a;
         int*dev_b;
         int*dev_c;
 
         //1、设置设备
         cudaError_t cudaStatus = cudaSetDevice( 0 );
 
         switch( true )
         {
         default:
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "调用cudaSetDevice()函数失败!" );
                            return cudaStatus;
                   }
 
                   //2、分配显存空间
                   cudaStatus= cudaMalloc( (void**)&dev_a, size * sizeof(int) );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "调用cudaMalloc()函数初始化显卡中a数组时失败!" );
                            break;
                   }
 
                   cudaStatus= cudaMalloc( (void**)&dev_b, size * sizeof(int) );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "调用cudaMalloc()函数初始化显卡中b数组时失败!" );
                            break;
                   }
 
                   cudaStatus= cudaMalloc( (void**)&dev_c, size * sizeof(int) );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "调用cudaMalloc()函数初始化显卡中c数组时失败!" );
                            break;
                   }
 
                   //3、将宿主程序数据复制到显存中
                   cudaStatus= cudaMemcpy( dev_a, a, size * sizeof( int ), cudaMemcpyHostToDevice );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf( stderr, "调用cudaMemcpy()函数初始化宿主程序数据a数组到显卡时失败!");
                            break;
                   }
                   cudaStatus= cudaMemcpy( dev_b, b, size * sizeof( int ), cudaMemcpyHostToDevice );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "调用cudaMemcpy()函数初始化宿主程序数据b数组到显卡时失败!" );
                            break;
                   }
 
                   //4、执行程序,宿主程序等待显卡执行完毕
                   addKernel<<<1,size>>>( dev_c, dev_a, dev_b );
 
                   //5、查询内核初始化的时候是否出错
                   cudaStatus= cudaGetLastError( );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "显卡执行程序时失败!" );
                            break;
                   }
 
                   //6、与内核同步等待执行完毕
                   cudaStatus= cudaDeviceSynchronize( );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "在与内核同步的过程中发生问题!" );
                            break;
                   }
 
                   //7、获取数据
                   cudaStatus= cudaMemcpy( out, dev_c, size * sizeof( int ), cudaMemcpyDeviceToHost );
                   if( cudaStatus != cudaSuccess )
                   {
                            fprintf(stderr, "在将结果数据从显卡复制到宿主程序中失败!" );
                            break;
                   }
         }
 
         cudaFree(dev_c );
         cudaFree(dev_a );
         cudaFree(dev_b );
 
         return cudaStatus;
}
 
int main( int argc, char** argv )
{
         const int arraySize = 5;
         const int a[arraySize] = { 1, 2, 3, 4, 5 };
         const int b[arraySize] = { 10, 20, 30, 40, 50 };
         int c[arraySize] = { 0 };
 
         cudaError_t cudaStatus;
 
         cudaStatus= CUDA_Add( a, b, c, arraySize );
 
         printf("运算结果是:\nc数组[%d, %d, %d, %d, %d]\n",
                   c[0],c[1], c[2], c[3], c[4] );
 
         cudaStatus= cudaDeviceReset( );
         if( cudaStatus != cudaSuccess )
         {
                   fprintf(stderr, "调用cudaDeviceReset()函数失败!" );
                   return 1;
         }
 
         return 0;
}

2,一个CMakeLists.txt文件

# 设置最低cmake版本要求
cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR) 
 
#支持 pkg-config
#include(FindPkgConfig)
#检查 libcurl cairo 等模块, 并获取它们的LIBS和INCLUDE, 结果保存到变量 LB_LIBS_XXX 中
# LB_LIBS_INCLUDE_DIRS # 保存包含路径
# LB_LIBS_LIBRARIES # 保存连接库
#pkg_check_modules(LB_LIBS REQUIRED libcurl cairo)
 
 
# 设置项目名称
project(myproject LANGUAGES CXX CUDA) 
 
# 检查编译目录和源码是否为同一目录, 如果是则提示错误
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
    message(FATAL_ERROR "Do not build in-source.\nPlease remove CMakeCache.txt and the CMakeFiles/ directory.\nThen: mkdir build ; cd build ; cmake .. ; make")
endif()
 
if( CMAKE_BUILD_TYPE STREQUAL "Debug" )
    add_definitions(-DNODEBUG)
else()
    add_definitions(-DDEBUG)# 添加宏定义
	#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -O0 -ggdb")
	#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -ggdb")
    # 设置CMAKE_C_FLAGS, `${CMAKE_C_FLAGS}` 可取出CMAKE_C_FLAGS的值
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O0 -ggdb")
	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb")
endif()
	
set(CMAKE_CXX_STANDARD 11)
 
# 设置变量 PROJECT_NAME 并初始化, 使用 ${XXX} 引用, 如: ${PROJECT_NAME} 
#set(PROJECT_NAME "xxx")
 
# 添加include目录(-l)
#include_directories(src) 
# include_directories(src) 
  
# 设置 XXX_TESTS 为 OFF
#set(XXX_TESTS OFF CACHE BOOL "")
# 添加子目录, 子目录要包含CMakeLists.txt文件
# add_subdirectory(src) 
 
# 添加可执行文件 example 的生成规则, 后面接依赖文件或者文件列表
add_executable(myproject main.cu) 
# 设置可执行文件 example 的链接库, 后面接的可以是系统库, 也可以是 子目录下的自定义库
# target_link_libraries(myproject lib) 
 
# 检测是否配置了编译类型[Release|Debug], 如果没有配置则配置为Release
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
  "Choose the type of build, options are: Debug Profile Release Asan Ubsan." FORCE)
endif(NOT CMAKE_BUILD_TYPE)

3.一个tasks.json文件

{
    "tasks": [
        {
            "type": "shell",
            "label": "C/C++: g++ build active file",
            "command": "mkdir build -p &&  cd  build &&  cmake -DCMAKE_BUILD_TYPE=debug .. &&  make -j4",
            //"command": "mkdir build -p &&  cd  build &&  cmake -DCMAKE_BUILD_TYPE=debug .. &&  make -j4",
            "args": [],
            "options": {
                "cwd": "${workspaceFolder}"
            },                       
            "detail": "Task generated by Debugger.",
            "problemMatcher":{
                "$nvcc"
            }
        }
    ],
    "version": "2.0.0"
}

截图如下:

4 .一个launch.json文件

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        
        {
            "name": "CUDA C++: Launch",
            "type": "cuda-gdb",
            "request": "launch",
            "program": "${workspaceFolder}/build/myproject",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "cuda-gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: g++ build active file",
            "miDebuggerPath": "/usr/local/cuda-10.1/doc/html/cuda-gdb"
        },
    ]
}


截图如下:

 整个工程鸟图如下:

5.远程连接服务器

点击左边的设置按钮,出现右边的选项,选择第一个文件,配置如下:

 

然后再点击左侧的 按钮, 此时选择你的工程所在目录即可,输入密码后就可以远程连接了

三,开始调试

1.建立目录build

2.直接F5调试即可

结果(Result)

效果如下:

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值