JIT를 인식하는 프로파일러¶
목표: PyPy JIT를 인식하고, 어느 루프에서 전체 시간의 몇 퍼센트가 소비되었는지 보여 주는 프로파일러를 갖추는 것입니다.
장기 목표: 프로파일러가 수집한 데이터를 jitviewer와 통합하는 것입니다.
루프나 브리지에 진입하고 빠져나갈 때마다 PYPYLOG에 이벤트를 기록하자는 것이 핵심 아이디어입니다.
예상 출력¶
[100] {jit-profile-enter loop1 # 예: 진입 브리지(entry bridge) [101] jit-profile-enter} … [200] {jit-profile-enter loop0 # loop1에서 loop0으로 JUMP [201] jit-profile-enter} … [500] {jit-profile-exit loop0 # 예: 가드(guard) 실패로 인해 [501] jit-profile-exit}
이 예제에서는 loop0에 진입하므로 loop1에서 빠져나오는 것은 암묵적으로 이루어집니다. 따라서 진입 브리지에서 200-100=100틱을, 실제 루프에서 500-200=300틱을 소비했습니다.
“내부” 브리지는 어떻게 처리해야 합니까?¶
“내부 브리지(inner bridge)”는 자신이 시작된 루프로 다시 점프하는 브리지를 말합니다. 이를 처리하는 방법에는 두 가지가 있습니다.
- 이들은 무시합니다. 루프에 진입할 때는 기록하지만, 컴파일된 내부 브리지로 점프할 때는 기록하지 않습니다. 종료 이벤트는 컴파일되지 않은 가드(guard)가 실패하거나 다른 루프로 JUMP하는 경우에만 기록됩니다
- 각 내부 브리지(bridge)의 진입과 종료를 기록합니다
해결책 (2)의 단점은 매 반복마다 브리지를 타는 루프가 존재한다는 것입니다. 따라서 이 경우에는 엄청나게 많은 이벤트를 기록하게 되므로 상당한 오버헤드가 추가될 수 있으며, 그 결과 프로파일링한 데이터가 쓸모없어질 수 있습니다.
루프 진입 및 탈출 감지¶
진입 방법:
- 트레이싱/컴파일 직후
- 루프가 이미 컴파일된 경우, 인터프리터에서
- 다른 루프에서 JUMP 연산을 통해
- 자주 발생하는(hot) 가드(guard) 실패로부터 (위의 해결책 (1)을 선택하는 경우에는 이를 무시합니다)
- XXX: 제가 빠뜨린 것이 있습니까?
종료하는 방법은 다음과 같습니다:
- 가드(guard) 실패 (블랙홀 진입)
- 가드(guard) 실패(브리지로 점프)(해결 방법 (1)의 경우 무시됨)
- 다른 루프로 점프
- XXX: 제가 놓친 것이 있습니까?
call_assembler에 관해서는, 처음에는 call_assembler를 그냥 무시하는 것이 좋다고 생각합니다. 호출 내부에서 소요된 시간은 그 호출을 수행한 루프의 시간으로 계산될 것입니다.