목적: 핵심 연산은 C++/CUDA로, 파이썬 바인딩은 포인터/스트림만 전달하는 얇은 어댑터로 구성하여, 제로-카피·고성능·모듈 재사용성을 달성한다. 이 문서는 디렉터리 구조, 인터페이스 규약, 빌드/배포, 파이썬 상호운용(CuPy/PyTorch/NumPy), 테스트/디버깅, 자주 겪는 이슈까지 한 번에 정리한다.
핵심 철학 (TL;DR)
- 경계 최소화: Python ↔ Core 사이에 포인터(void*)/크기/shape·stride/스트림만 오간다.
- 소유권 비침투: 바인딩은 메모리를 소유하지 않는다(해제 책임은 호출자).
- 동기화는 선택: 기본 비동기, 필요 시 sync_after 옵션으로 동기화.
- GIL 해제: 커널 실행 구간은 항상 GIL을 해제한다.
- 플러그형 코어: Core는 언어 비의존+안정 ABI. pybind는 매우 얇게 유지.
개발 워크 플로
- 기능 설계
- 시그니처 확정 : 버퍼 포인터, shape/stride, dtype, cudaStream_t
- 동기화 정책 : 기본 비동기, 필요 시 sync_after 플래그
- 코어 (C++/CUDA) 구현
- .hpp 헤더 추가
- .cu 커널 작성
- 코어 라이브러리 빌드
- CMake 에 소스 추가
- 정적 또는 공유 빌드
- 바인딩 추가
- 바인딩 내 함수 추가
- 포인터/스트림을 캐스팅해서 코어 함수 호출
- 파이썬 모듈 빌드
- 파이썬 유틸
더보기
동기화 synchronization 개념
GPU 연산은 기본적으로 비동기 asynchronous 로 동작
- CPU -> GPU : CPU 가 커널을 실행시키면 GPU 에 작업 명령만 던져주고 바로 리턴 ( CPU 는 다른 동작 )
- 즉, CPU 코드가 끝나도 GPU 연산은 끝나지 않았을 수 있음
- GPU 는 수천 개의 스레드를 병렬 실행시켜, CPU 와 다르게 파이프라인이 길고 준비 시간 존재
- CPU 를 대기 시키면 성능 저하 - 필요시 결과를 동기화해서 확인하는 방식으로 작동
동기화 방법
- cudaStreamSynchronize(stream) 특정 스트림의 작업이 다 끝날 때까지 CPU 를 블록
- cudaDeviceSynchronize() : GPU 전체의 모든 작업이 끝날 때까지 대기
- cudaMemcpy (host <-> device) : 기본적으로 동기화 동작을 내포
// 비동기 커널 실행
my_kernel<<<grid, block, 0, stream>>>(...);
// CPU는 바로 리턴 → 아래 코드 바로 실행됨
printf("GPU가 아직 안 끝났어도 이건 찍힘!\n");
// 결과를 확인하려면 반드시 동기화 필요
cudaStreamSynchronize(stream);
그래서 바인딩 함수에서 sync_after=True 옵션을 주면, 내부에서 cudaStreamSynchronize 를 호출해서 CPU, GPU 가 맞춰진 상태로 리턴
False 의 경우 사용자가 sync 를 책임져야 함
정적, 공유 라이브러리 개념
c++/CUDA 코드는 라이브러리 형태로 묶을 수 있고, static, shared 두 가지로 나뉜다.
정적 라이브러리는 빌드할 때 라이브러리 안의 코드가 그대로 실행 파일에 복사, 합쳐짐
공유 라이브러리는 실행 파일에는 함수 심볼 이름만 들어가고 실제 구현은 런타임에서 불러옴
'dev_AI_framework' 카테고리의 다른 글
| row bias, column bias - pern, perm (0) | 2025.09.20 |
|---|---|
| graph_executor_v2 — 아키텍처 개요 & 통합 가이드 (0) | 2025.09.19 |
| GEMM + Bias + Activation “1-Write” 설계 노트 (Register-Epilogue 방식) (0) | 2025.09.04 |
| 커널 선택 방식의 고민 - epilogue 방식이 아닌 다른 방식을 사용해보자 (accumulate 내부 수정 ) (0) | 2025.09.04 |
| epilogue 동작과정 이해 (0) | 2025.09.04 |