Rust의 Tree Borrows 모델 분석 시 발생하는 이차적 시간 복잡도(Quadratic Time Complexity) 문제를 발견했습니다.
OCaml로 작성된 Soteria Rust 도구에서 OCaml GC를 활용하여 이 문제를 해결했습니다.
약 40줄의 코드 변경으로 성능을 최대 10배 향상시키고 선형 시간 복잡도(Linear Time Complexity)를 달성했습니다.
커뮤니티에서는 Rust의 Tree Borrows 모델이 메모리 접근 시 발생하는 상태 전이(State Transition)와 트리 노드(Tree Node) 관리로 인해 성능 저하를 일으킨다고 지적합니다. 특히 반복문 내에서 발생하는 재대여(Reborrow) 작업이 트리 구조를 기하급수적으로 증가시키며, 이는 이차적 시간 복잡도(Quadratic Time Complexity)의 주된 원인으로 분석됩니다. 최적화되지 않은 코드에서는 이러한 복잡성이 더욱 두드러져 분석 도구의 실행 시간을 크게 증가시킵니다.
이 글은 Soteria Rust가 OCaml로 작성되었다는 점을 활용하여, Rust 코드 분석 시 발생하는 Tree Borrows 상태 관리 부담을 OCaml의 가비지 컬렉터(Garbage Collector)에 위임하는 메타 가비지 컬렉션(Meta Garbage Collection) 기법을 제안합니다. OCaml의 약한 참조(Weak References)와 에페메론(Ephemeron) 자료구조를 사용하여 Rust의 참조가 살아있는 동안 OCaml 객체가 수집되지 않도록 보장하며, 이를 통해 데이터 격리 아키텍처(Data Isolation Architecture)를 효과적으로 관리합니다.
초기 OCaml GC 통합 시 주기적인 실행 부족으로 성능이 오히려 저하되는 문제가 발생했습니다. 이에 따라 트리 크기 임계값(Tree Size Threshold, T)을 설정하고, 해당 임계값을 초과할 때 `Gc.major()` 함수를 호출하여 수동으로 GC를 트리거하는 방식을 도입했습니다. 또한, GC가 노드를 해제하지 못할 경우 백오프 메커니즘(Backoff Mechanism)을 적용하여 T를 두 배로 늘림으로써, GC 실행 빈도와 비용 사이의 균형을 맞추는 최적화 전략을 사용했습니다.
개선된 GC 전략 적용 후, Tokio 초기화 코드와 같은 실제 벤치마크에서 8.7배의 성능 향상을 확인했습니다. 특히 N=1000일 때 5.6배, N=2000일 때 10.6배의 속도 개선을 달성하며, 기존의 이차적 시간 복잡도에서 벗어나 선형적 실행 시간(Linear Execution Time)을 확보했습니다. 이는 복잡한 Rust aliasing 모델 분석 도구의 실용성을 크게 높이는 결과입니다.
이 사례는 호스트 언어(Host Language)의 강력한 기능을 최대한 활용하는 것이 복잡한 문제를 해결하는 데 얼마나 효과적인지를 보여줍니다. Soteria Rust 팀은 OCaml의 GC 기능을 직접 구현하는 대신, 40줄의 코드만으로 성능 문제를 해결했습니다. 이는 Soteria 라이브러리 설계의 핵심 결정 사항 중 하나로, 개발자가 언어의 내장 기능을 잘 이해하고 활용할 때 얻을 수 있는 이점을 강조합니다.