Study/CUDA

CUDA를 C++/CLI로 만들어보자

BlueBright 2020. 2. 4. 15:14

아직 코드 연구중인 부분입니다.....



기준 VS2017


  1. 새 프로젝트를 생성한다.
    • Visual C++ → Windows 데스크톱 → DLL(동적 연결 라이브러리)



  2. 구성 관리자에 프로젝트 타겟 설정 변경
    • 자신이 설계하고자 하는 목적에 맞게 구성 (Debug, Release 등) 및 플랫폼 (x86, x64 등)을 설정한다.


  3. 프로젝트의 빌드설정을 변경한다.
    1. 프로젝트 우클릭 → 빌드 종속성 → 사용자 지정 빌드

    2. 자신의 버전에 맞는 CUDA를 체크한다.
      1. 현재 자신의 CUDA 설정 확인해볼 것!  


  4. 프로젝트의 빌드 순서를 변경한다.
    1. 프로젝트 우클릭 → 빌드 종속성 → 프로젝트 종속성 또는 프로젝트 빌드 순서

    2. DLL을 생성하는 프로젝트가 DLL을 사용하는 프로젝트 보다 먼저 빌드되어야 한다.


  5. 생성한 프로젝트의 속성 페이지로 진입한다.
    • 생성한 프로젝트 우클릭 → 속성

    1. 구성속성 → 일반
      • 관리되는 증분 빌드 사용 : 예 ← 공용 언어 런타임 지원 옵션을 변경하면 자동으로 바뀜
      • 구성 형식 : 동적 라이브러리 (.dll)
      • 문자 집합 : 자유
      • 공용 언어 런타임 지원 : 공용 언어 런타임 지원 (/clr) ← 중요!!
      • .NET 대상 프레임워크 버전 : 사용할 C#의 .NET 버전에 맞게 입력



    2. 구성속성 → C/C++
      • 일반
        • 추가 포함 디렉터리 : $(CudaToolkitIncludeDir)
      • 미리 컴파일된 헤더
        • 미리 컴파일된 헤더 : 미리 컴파일된 헤더 사용 안 함 ← 사용을 해도 무방할 듯



    3. 구성속성 → CUDA C/C++
      • Common
        • Target Machine Platform : 플랫폼 버전에 맞게 변경


    4. 구성속성 → 링커
      1. 일반
        1. 추가 라이브러리 디렉터리 : $(CudaToolkitLibDir)
      2. 입력
        1. 추가 종속성 : cudart_static.lib;


  6. 생성한 프로젝트의 참조 파일을 추가한다.
    1. 프로젝트 하위 트링에 "참조" 부분 우클릭 → 참조 추가
    2. 어셈블리 부분에서 "mscorlib" 파일을 찾아서 체크
  7. CUDA 코드 속성
    • 코드 파일의 속성 페이지로 진입한다.
      • "일반 → 항목 형식" 부분이 CUDA C/C++ 로 설정되어 있는지 확인
  8. 닷넷 프로젝트에 참조 추가
    • 사용하려는 닷넷(C#) 프로젝트의 "참조"에 CUDA C++/CLI 프로젝트를 추가한다.





※ 코드 예시

<C++/CLI 헤더 부분>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once
 
#include <stdio.h>
#include <windows.h>
#include <iostream>
 
using namespace System;
using namespace System::Runtime::InteropServices;
 
namespace ManagedCu
{
 
    public ref class MyCudaCliWrap {
 
    public:
        MyCudaCliWrap();
        ~MyCudaCliWrap();
 
        void RunAdd(cli::array<int> ^c, cli::array<int> ^a, cli::array<int> ^b, int size);
        
    };
 
}
 
cs



<C++/CLI 코드 부분>


주의 사항!

nvcc는 C++/CLI의 문법을 인식하지 못한다고함.

따라서 <<<grid,block>>>() 부분을 cudaLaunchKernel()로 바꾸어야 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "MyCudaCliWrapper.h"
 
#include "MyCliKernel.cuh"
 
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
 
 
namespace ManagedCu
{
    MyCudaCliWrap::MyCudaCliWrap() {
 
    }
    
    MyCudaCliWrap::~MyCudaCliWrap() {
 
    }
    
    void MyCudaCliWrap::RunAdd(cli::array<int> ^c, cli::array<int> ^a, cli::array<int> ^b, int size)
    {
        //extern void addKernel(int* c, int const* a, const int* b);
 
        pin_ptr<int> pin_a = &a[0];
        pin_ptr<int> pin_b = &b[0];
        pin_ptr<int> pin_c = &c[0];
 
        int *p_a = pin_a;
        int *p_b = pin_b;
        int *p_c = pin_c;
 
        int* dev_a = 0;
        int* dev_b = 0;
        int* dev_c = 0;
 
        cudaError_t cudaStatus;
        cudaStatus = cudaSetDevice(0);
        cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
        cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
        cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
 
        cudaStatus = cudaMemcpy(dev_a, p_a, size * sizeof(int), cudaMemcpyHostToDevice);
        cudaStatus = cudaMemcpy(dev_b, p_b, size * sizeof(int), cudaMemcpyHostToDevice);
        
        void* args[] = { &dev_c, &dev_a, &dev_b };
 
        cudaLaunchKernel(
            (const void*)&addKernel, // pointer to kernel func.
            dim3(1), // grid
            dim3(size), // block
            args  // arguments
        );
 
        cudaStatus = cudaDeviceSynchronize();
 
        cudaStatus = cudaMemcpy(p_c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
        
        cudaFree(dev_c);
        cudaFree(dev_a);
        cudaFree(dev_b);
 
    }
 
}
 
cs



<CUDA 코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
////////////////////////////////////////////////////////////////
//Cuda 헤더 부분//
#pragma once
 
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
 
__global__ void addKernel(int *c, int const* a, int const* b);
/////////////////////////////////////////////////////////////////
 
/////////////////////////////////////////////////////////////////
//Cuda 코드 부분//
#include "MyCliKernel.cuh"
 
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
 
__global__ void addKernel(int *c, int const* a, int const* b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}
//////////////////////////////////////////////////////////////////
 
cs




<C#에서 이런 식으로 받아 쓰면 된다>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void BtnRun3_Click(object sender, RoutedEventArgs e)
{
    try
    {
 
        int[] a = { 12345 };
        int[] b = { 110220330440550 };
        int[] c = new int[5];
 
        ManagedCu.MyCudaCliWrap obj = new ManagedCu.MyCudaCliWrap();
 
        obj.RunAdd(c, a, b, 5);
 
        foreach (int i in c)
        {
            System.Console.Write("{0} ", i);
        }
 
        Console.WriteLine();
 
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
 
}
cs






참고

http://www.orangeowlsolutions.com/archives/199

https://qiita.com/episteme/items/55b321cec427048d0c0c

https://devtalk.nvidia.com/default/topic/979462/how-can-i-compile-cuda-code-then-link-it-to-a-c-clr-project/

https://gist.github.com/parsa/aff600b60b1410d252f6192e797f287d



https://diehard98.tistory.com/entry/Quick-CCLI-Learn-CCLI-in-less-than-10-minutes

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=8283

https://huiyu.tistory.com/entry/CCLI-%EA%B8%B0%EB%B3%B8-%EC%98%88%EC%A0%9C

https://andromedarabbit.net/cplusplus_cli_lecture_2009_01/

https://six605.tistory.com/391







'Study > CUDA' 카테고리의 다른 글

CUDA를 C#에서 사용해보자  (2) 2019.07.08
CUDA  (0) 2019.02.20