파이썬 디스어셈블러를 이용해서 동작 이해하기

(ganadist님의 append vs new를 보고 이유를 살펴보는 겸 해서 써 봅니다.)

위 소스 둘을 보면 결과적으로는 아래 소스가 40% 정도 빠르게 동작합니다. 그렇지만, 왜 그런지 파악하는 것은 VM 내부 구조에 대한 연습을 무척 많이 하지 않고서는 쉽게 알기가 힘듭니다. 우선은 비슷한 라인이기 때문에 t += []는 inplace_add에서 resize가 일어나지 않을까 하고, 뒤의 것에서는 리스트가 계속 생성되지 않을까 하는 생각이 먼저 듭니다.

그런데, 이런 것을 진짜로 분석해보려면 파이썬 프로파일러로 해보면 라인단위로 나와서 그다지 큰 도움이 안 되고, C 프로파일러로 해봐도 대부분 인터프리터 루프가 먹고 있다는 것 정도만 파악이 되고.. 흐흐.. 그래서, 파이썬 VM 구조를 잘 모를 때도 쓸 수 있는 좋은 방법을 하나 소개합니다. 표준 파이썬에 dis 라는 디스컴파일러 모듈이 있는데, dis.dis 함수를 쓰면 코드/함수를 디스어셈블해 줍니다. 그래서 저 프로그램을 적당히 함수로 만들어서 디스어셈블을 해 보면 주요 부분이 이렇게..

그러면 디스어셈블 결과만 대충 봐도 앞의 소스는 LOAD_GLOBAL을 쓰고 있고 뒤의 것은 안 쓴다는 것을 알 수 있습니다. LOAD_GLOBAL은 딕셔너리 검색이 최소 1번에서 나쁜 경우 3~5번까지도 일어날 수 있는 옵코드이기 때문에, 있고 없고가 굉장한 성능 차이를 줄 수 있다는 것을 알 수 있습니다. 그리고, 두번째 것은 INPLACE_ADD 없이 그냥 BUILD_LIST해서 저장해버린 반면에, 첫번째 것은 INPLACE_ADD가 중간에 들어 있기 때문에, LOAD_GLOBAL 없이도 복잡한 것을 눈치챌 수 있습니다.

오늘의 연습문제: LOAD_GLOBAL/STORE_GLOBAL 외에 LOAD_FAST/STORE_FAST를 쓰면 위와 같은 소스가 굉장히 빨라질 가능성이 있습니다. 어떻게 하면 LOAD_FAST를 쓰도록 유도할 수 있을까요! (힌트: _GLOBAL은 딕셔너리 서치가 일어나고, _FAST는 미리 할당된 슬랏에서 인덱스로 바로 가져옵니다.)

4 thoughts on “파이썬 디스어셈블러를 이용해서 동작 이해하기”

  1. 아이쿠 어려워. 좀 더 풀어주세요. LOAD_GLOBAL, STORE_GLOBAL에서 글로벌의 대상이 t인가요?

  2. 킁.. _GLOBAL의 이름에서 눈치채실 수 있는데, _FAST는 지역변수에 적용됩니다.
    그래서, 단순히 전역에 나와 있는 코드를 함수 안에 집어넣기만 해도 빨라지죠. ^_^;;;

  3. 켁. local변수로 하면 되지 않을까 싶었는데 function안에 두어도 차이가 없길래 __slot__이나 다른 머시기를 써야 하려나 찾아보고 했건만, 정작 답을 보고 다시 dis 확인해보니 FAST적용되어 나오고 있었군요.ㅋㅎㅎ
    바부.ㅠ.ㅠ;

Comments are closed.