SDB는 기존 스택 프로파일러의 한계를 극복하기 위해 1밀리초의 낮은 샘플링 간격, 3% 미만의 CPU 사용률, 그리고 스택 스캔 시 GVL 미사용이라는 세 가지 핵심 목표를 설정했습니다.
SDB 설계 원칙
- 지연 및 오프라인 분석: 스택 스캐너는 스택 함수 정보만 수집하여 기록하고, 실제 분석 및 데이터 변환은 오프라인으로 수행하여 온라인 서버 부하를 줄입니다.
- 캐싱된 심볼화: 메모리 주소를 심볼로 변환하는 작업을 캐싱하여 반복 작업을 최소화합니다.
GVL 없이 스택 스캔하는 방법
가장 중요한 GVL 없이 스택을 스캔하는 부분은 ISEQ
필드의 원자성(atomicity)에 기반합니다.
* 64비트 메모리 읽기/쓰기의 원자성: GVL은 Ruby 객체를 보호하지만, 64비트 메모리 읽기/쓰기는 하드웨어 수준에서 원자성이 보장됩니다. SDB는 Ruby 메서드 내부 표현인 ISEQ
구조체 주소를 담는 64비트 ISEQ
필드에만 의존하므로 GVL 없이 안전하게 읽을 수 있습니다.
* 활성 스레드만 스캔: SDB는 스레드 생성 및 종료 시 Ruby VM과 동기화하여 활성 스레드의 유효한 스택만 스캔합니다.
* Ruby GC 호환성: SDB는 활성 스레드만 스캔하며, 의존하는 실행 컨텍스트 및 스택이 Ruby VM에서 이동하지 않는 고정(fixed) 객체이므로 GC의 메모리 컴팩션과 안전하게 작동합니다.
데이터 경합(Data Race) 문제
Ruby VM이 스택을 업데이트하고 SDB가 GVL 없이 읽는 과정에서 데이터 경합이 발생할 수 있습니다. 그러나 프로파일러의 목적이 엄격한 정확성보다는 실질적인 정보 제공에 있음을 강조합니다. SDB는 고지연 함수 탐지에 중점을 두므로, 짧은 시간 동안의 경합으로 인한 부정확성은 실제 문제 해결에 큰 영향을 미치지 않는다고 판단합니다.