아.. 쿠다 일단 미뤄둘라고 했는데, 며칠만 더 쪼물딱해봐야겠다.
먼저 cudaMemcpy, cudaMalloc은 호스트에서 돌려야 한다. 디바이스 코드에서 돌릴 수 없다. 그러면 쓰레드로 도는 커널 코드에서는 동적할당을 어찌 할 것인가? malloc, free를 쓰면 된다. 아마도 nvcc가 컴파일 할 때 후킹해서 libc로 안 가는 것 같은데, 잘은 모르겠다. unified memory이므로 주소의 주인이 호스트이냐 디바이스냐에 따라 움직이도록 후킹처리하는 것은 아닐가 싶은데 역시 모르겠다. 그런데, 커널 코드에서 malloc을 대량으로 해보니 실패가 막 일어난다. 이것은 힙 크기 부족이다. 쿠다 코드가 아니라면 malloc으로 512M정도 땡긴다고 문제가 될 일이 없으나 쿠다에서는 실패가 일어난다. 즉슨, 커널 코드는 디바이스 메모리를 힙으로 쓰고 있다고 생각해 볼 수 있다. unified memory이므로 좀 더 복잡할 지 모른다.
그렇다면 작은 힙으로 버텨야 하는가?
호스트 코드 단에서 다음과 같이 미리 선언하면 된다.
cudaThreadSetLimit(cudaLimitMallocHeapSize,1024*1024*1024);
이제 커널 코드에서 malloc, free를 할 수 있게 되었는데 호스트 메모리에서 디바이스 메모리로 퍼담고 싶으면 어떻게 하나? cudaMemcpy도 역시 커널코드에서는 사용할 수 없다. 이 때는 역시 memcpy를 쓰면 된다. 이게 뭣꼬? 쉽다 못해 헷갈린다. -_-; 여튼 테스트 상 그랬다.
이런 방식으로 작업을 할 때의 장점은 쓰레드에 의해 고속/대량으로 힙 확보/복사를 할 수 있다는 것이다. 호스트에서 cudaMemcpy를 쓰면 아마도 DMA에 의해 빠른 복사가 될 것 같긴 한데, 동적으로 처리해야 할 때도 있다. 그거슨 다음에..
본디 목적은 filebacked mmap으로 붙어있는 메모리를 대량의 쓰레드로 퍼올릴 수 있지 않을까 한 것인데, 결과적으로 매우 느리다. 디바이스 코드 안에 있는 memcpy는 DMA를 이용하는 코드로 우회 후킹되어있지 않은 것으로 판단된다. 뭐 다 가정이네... 여튼 이 방식은 씰데 없는 것으로.. 결국 호스트에서 멀티쓰레드를 구성한다음, 메모리로 퍼올리는 놈과 뮤텍스 대기타고 있다가 디바이스 쓰레드를 쫙 뿌리는 놈으로 나누고 처리해야 할 것 같다. 디바이스 쓰레드가 실행 중일 때에는 다시 퍼올리고.. 그런데 IO 처리에 걸리는 속도가 압도적이라 아무짝에도 쓸모없겠구나..