Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Python Korea Seminar] 하늘과 바람과 별과 (Python과) C

[Python Korea Seminar] 하늘과 바람과 별과 (Python과) C

Python C 확장 모듈을 제작하는 방법들(C API, ctypes, Cython, CFFI) 소개와 간단한 장단점 비교.

Avatar for Joongi Kim

Joongi Kim

May 18, 2013
Tweet

More Decks by Joongi Kim

Other Decks in Programming

Transcript

  1. / 20 자기 소개  KAIST 전산학과 박사과정 2년차 

    Microsoft Research Cambridge@UK 인턴  NexR 인턴/프리랜서  TNF Needlworks ­– 태터툴즈/텍스트큐브 개발  Team Popong ­– 국회 의안 크롤러,
  2. / 20 현재 하는 연구(=삽질)  GPU를 이용한 고속 network

    packet 처리 시스템 개발  일반 PC나 x86 서버 같은 general-purpose 플랫폼과 Linux 를 이용한 상용 라우터에 버금가는 성능의 framework  이때 고속 연산을 위해 GPU를 활용  다루는 기술  C/C++ on Linux kernel + user space  NVIDIA CUDA  and Python! 4
  3. / 20 Python을 쓰는 이유  Python으로 Django, Flask 프로그래밍도

    좀 해봤습니다.  하지만 연구에서 쓰는 가장 큰 이유는 scripting!  Python으로 하는 일  시스템 부팅 후 X 환경 없이 GPU 초기화  Custom NIC driver의 IRQ 설정  실험 조건 별로 한번에 수십 ~ 수백 번 반복 실행  각 실험마다 CPU 코어별 점유율, throughput 등 기록  실험 후 summary 및 graph 작성 5
  4. / 20 Python에서 C 사용하기  보통 속도에 민감한 알고리즘

    구현이나, C로만 제공되는 라이브러리를 사용하기 위해 사용한다.  방법 0: Python C API로 직접 import 가능한 C 모듈 짜기  방법 1: ctypes로 C 라이브러리 직접 호출하기  방법 2: Cython ­– Python처럼 쓴 코드를 C로 번역해서 import 가능한 C 모듈로 만들어준다.  방법 3: CFFI로 Python 안에서 C 코드 직접 쓰기 6
  5. / 20 Python C API  http://docs.python.org/3/c-api/  장점 

    Python 코드 실행보다 Python C API 사용한 C 코드가 빠르다. (Cython의 motivation)  단점  Python 버전 바뀌면 컴파일도 다시 해야 함. (특히 윈도용으로 배포하기 귀찮다)  Reference counting 지옥  명시적으로 해야 하는 경우 vs. 특정 API가 자동으로 하는 경우 7 C API ctypes Cython CFFI 결론
  6. / 20 Python C API example  Python 공식 문서의

    예제  직접 찾아보세요!  NumPy의 C API와 함께하는 예제  C API로 짠 importable 모듈 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-capi/_chi2.c  사용하는 순수 Python 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-capi/test.py 8 C API ctypes Cython CFFI 결론
  7. / 20 ctypes  http://docs.python.org/3/library/ctypes.html  장점  표준라이브러리! 컴파일

    필요 없다!  Python 버전에 따른 코드 변경 필요 없고, portable하다.  시스템에 library 존재 여부를 런타임에 검사 가능.  단점  C 함수를 자주 많이 부를수록 성능 오버헤드가 크다.  복잡한 구조체, 많은 수의 상수(#define
  8. / 20 ctypes example (1)  CUDA 런타임 불러서 GPU

    개수 검사 및 관련 초기화  count를 포인터로 넘기기 위해 ctypes.byref 사용  참고 : https://gist.github.com/achimnol/3404967 10 import ctypes, ctypes.util def set_gpu_affinity(): … cuda = ctypes.CDLL(ctypes.util.find_library('cudart')) count = ctypes.c_int(0) … ret = cuda.cudaGetDeviceCount(ctypes.byref(count)) assert ret == 0, 'cudaGetDeviceCount() has failed.' logger.info('Grabbed a CUDA context.') … C API ctypes Cython CFFI 결론
  9. / 20 ctypes example (2) 11 from ctypes import CDLL,

    Structure, c_char, c_int, c_byte, byref from ctypes.util import find_library class Device(Structure): _fields_ = [ ('name', c_char * 16), ('dev_addr', c_char * 6), ('ip_addr', c_byte * 4), ('ifindex', c_int), ('kifindex', c_int), ('numa_node', c_int), ('num_rx_queues', c_int), ('num_tx_queues', c_int), ] if __name__ == '__main__': libpsio = CDLL(find_library('psio')) AllDevices = Device * 64 # pre-allocated array of struct devices = AllDevices() num_devices = libpsio.ps_list_devices(byref(devices)) print('Detected devices: {}'.format( ', '.join(map(lambda dev: '{}@{}'.format(dev.name.decode('ascii'), dev.numa_node), devices[:num_devices])) )) struct ps_device { char name[IFNAMSIZ]; char dev_addr[ETH_ALEN]; uint32_t ip_addr; int ifindex; int kifindex; int numa_node; int num_rx_queues; int num_tx_queues; }; C API ctypes Cython CFFI 결론
  10. / 20 ctypes example (3)  아까 보았던 C API

    + NumPy example의 ctypes 버전  https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-ctypes/test.py  훨씬 간단!  생각해볼 점  C 함수를 반복 호출하는 경우 또는 많은 양의 데이터로 for loop를 돌리는 경우 해당 부분은 C 코드로 짜는 것이 좋다. 즉,
  11. / 20 Cython  http://www.cython.org/  장점  Python 유사

    문법으로 C 코드를 쓸 수 있다. 간결하다. (cdef
  12. / 20 Cython example  아까 보았던 C API +

    NumPy example의 Cython 버전  Cython interfacing (.pyx) https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cython/chi2.pyx  Cython 코드(.pyx)의 C 코드 번역 결과 (!!) https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2- cython/example_chi2_generated.c  사용하는 순수 Python 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cython/test.py  사람이 작성하는 코드는 가장 간단하다! 14 wrapper.pyx native.c .so (Python importable) Cython translates to .c Compile into C module C API ctypes Cython CFFI 결론
  13. / 20 CFFI (C Foreign Function Interface)  https://bitbucket.org/cffi/cffi 

    장점  C 선언문을 그대로 쓰므로 가장 직관적이다.  ctypes처럼, 별도의 컴파일 과정이 필요 없다.  ABI (app. binary interface)와 API (app. programming interface) 모델을 둘 다 지원한다.  단점  제품용으로 쓰기엔 아직 충분히 성숙하지 않았다.  문서화가 덜 되어 있다. 15 C API ctypes Cython CFFI 결론
  14. / 20 CFFI example  아까 보았던 C API +

    NumPy example의 CFFI 버전  https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cffi/test.py  ctypes의 장점을 가지면서도 C 선언을 그대로 사용할 수 있 어서 훨씬 직관적이다. 16 C API ctypes Cython CFFI 결론
  15. / 20 성능은 어떨까? 방법 수행 시간 (단위 : sec)

    C API 0.391 ctypes 0.450 Cython 0.403 CFFI 0.485 17  성능 좋은 순서: C API > Cython > ctypes > CFFI 실험 조건: • input random 생성과 API 호출을 함께 1000회 반복 • 각 방법 별로 4회씩 실행하여 뒤 3회의 user time 평균 (첫번째는 cache warm-up 용도) C API ctypes Cython CFFI 결론
  16. / 20 장단점 요약 방법 표준 여부 Portability 모듈 개발자의

    Cost 모듈 사용자의 Cost C API Yes 낮음 매우 높음 없음 ctypes Yes 높음 없음 중간 Cython No 높음 중간 없음 CFFI No 높음 없음 낮음 18 C API ctypes Cython CFFI 결론
  17. / 20 정리  Python에서 C 코드를 부르고 싶다면: 

    현재 가장 추천할 수 있는 방법은 ctypes! (표준 + portable)  C 함수 호출 성능이 중요하다면 Cython 권장.  CFFI는 미래의 기대주, 아직 실제로 쓰기엔…⋯  여기서 다루지 못한 내용  SWIG (Simplified Wrapper & Interface Generator)  interface 정의 1개로 여러 언어(Tcl, Python, Perl, Java 등등) 의 importable module을 컴파일할 수 있다.  Python의 경우 C API를 사용한 것과 같은 효과 19 C API ctypes Cython CFFI 결론