본문으로 건너뛰기

[Triton] 모듈 언로드 테스트 비결정적 실패 수정 — GC 비활성화로 안정성 확보

PR 링크: triton-lang/triton#9520 상태: Merged | 변경: +7 / -1

들어가며

Triton의 런타임은 커널 모듈의 생명주기를 관리하며, 모듈이 언로드될 때 사용자 정의 hook을 호출할 수 있다. test_module_load_unload 테스트는 이 메커니즘이 올바르게 동작하는지 검증하는데, 간헐적으로 실패하는 비결정적(non-deterministic) 버그가 있었다.

원인은 Python의 garbage collector다. GC가 테스트 도중 예기치 않은 시점에 객체를 수거하면서 module_unload callback이 추가로 호출되어 counter 값이 기대와 달라지는 문제였다.

핵심 코드 분석

Before: GC 간섭 가능

def test_module_load_unload():

    @triton.jit
    def kernel(out_ptr, val) -> None:
        tl.store(out_ptr, val)

    counter = 0
    def module_unload(*args, **kwargs):
        nonlocal counter
        counter -= 1

    triton.knobs.runtime.module_unload_hook.add(module_unload)
    # ... 테스트 실행
    assert counter == 0

After: GC 비활성화로 결정적 실행 보장

def test_module_load_unload(fresh_knobs):

    @triton.jit
    def kernel(out_ptr, val) -> None:
        tl.store(out_ptr, val)

    counter = 0
    def module_unload(*args, **kwargs):
        nonlocal counter
        counter -= 1

    # turn off python garbage collector, so the callback is not called
    # in the garbage collector
    gc.disable()
    triton.knobs.runtime.module_unload_hook.add(module_unload)
    # ... 테스트 실행
    assert counter == 0
    assert pre_compile.module is None
    # turn on garbage collector
    gc.enable()

변경 사항은 세 가지다:

  1. fresh_knobs fixture 추가: 테스트 간 knob 상태 격리를 보장한다.
  2. gc.disable(): hook 등록 전에 GC를 꺼서 테스트 도중 예기치 않은 객체 수거를 방지한다.
  3. gc.enable(): 테스트 완료 후 GC를 다시 활성화한다.

왜 이게 좋은가

  1. 비결정적 실패 해소: GC 타이밍에 의존하던 테스트가 이제 결정적으로 동작한다. CI에서 간헐적으로 빨간불이 들어오는 문제가 사라진다.
  2. 최소한의 변경: 테스트 로직 자체를 바꾸지 않고, GC 제어만 추가하여 근본 원인을 해결했다.
  3. fixture 기반 격리: fresh_knobs를 통해 다른 테스트와의 상태 간섭도 차단했다.

정리

Python GC는 예측 불가능한 시점에 객체를 수거하므로, callback 기반 테스트에서 비결정적 실패의 원인이 될 수 있다. 이 PR은 테스트 구간에서 GC를 명시적으로 비활성화하는 간단한 방법으로 문제를 해결한다.

참고 자료


이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 핵심 코드와 explaination은 실제 PR diff를 기반으로 합니다.

댓글

관련 포스트

PR Analysis 의 다른글