Rust의 derive는 종종 inline을 암묵적으로 포함함
요약
본 글은 Rust의 `derive` 매크로가 `Debug` 트레이트에까지 암묵적으로 `#[inline]` 속성을 포함하는 현상에 대한 분석과 개선 제안을 담고 있습니다. 작성자는 이 기본 동작이 의외이며, 코드 크기, 컴파일 시간, 실행 시간 사이에서 완벽한 절충점을 찾기 어렵다는 점을 지적합니다. 궁극적으로는 인라인 가능성을 추정하여 `#[can_inline]` 같은 안정적인 인터페이스가 필요하다고 제안합니다.
핵심 포인트
- `Debug` 트레이트의 암묵적 `#[inline]` 포함은 예상 밖의 동작입니다.
- 코드 크기, 컴파일 시간, 실행 시간 간의 최적화 절충점 찾기가 어렵습니다.
- 컴파일러가 인라인 가능성을 추정하여 `#[can_inline]` 같은 속성을 자동으로 붙여주면 좋겠습니다.
- Cargo.toml 메타데이터 등 더 높은 수준의 의도 전달 인터페이스가 필요합니다.
Ord와 Eq, 어쩌면 Clone에 #[inline]이 붙는 건 예상할 만하지만, Debug에까지 붙는 건 의외임. 내 fn fmt 구현에는 오히려 #[cold]를 붙임!
rust-lang/rust 저장소에 버그로 보고할 만함. 과거에도 Debug의 #[inline]을 변경한 적이 있고, 다시 바꿀 수도 있음. 다만 코드 크기, 컴파일 시간, 실행 시간 사이에서 적절한 절충점을 고르기가 어려움.
이번 주에 보고할 예정임. 처음에 보고하지 않은 건 다른 컴파일러 작업을 해본 입장에서, Rust가 여기서 선택할 완벽한 기본값이나 휴리스틱은 없다는 데 충분히 공감했기 때문임.
더 높은 수준의 의도를 전달할 안정적이거나 준안정적인 인터페이스는 어떤 모습일지 궁금함. Cargo.toml 메타데이터가 떠오름. 예를 들어 최종 바이너리 크기의 상한을 지정하고, 상한에 도달하면 컴파일러가 최적화를 줄여보게 할 수도 있음. 다만 너무 세밀하고 작은 변화에도 취약한 설정이 될 수 있음.
다행히 이 구체적인 문제는 크레이트로도 해결 가능함. cold::Debug, inline::Debug 등을 제공하거나 컨테이너 속성으로 설정하게 할 수 있음.
많은 Debug 구현은 실제로 호출되지 않는데, #[inline]을 붙이면 아예 코드 생성을 하지 않아도 되는 것이 이유 중 하나일 듯함.
Rust의 절차적 매크로가 실제 타입이 아닌 토큰을 다루는 한계에서 비롯된 것 같음. 매크로에 타입 정보가 있다면 인라인이 몇 단계 중첩되는지 살펴보고, 너무 깊으면 #[inline]을 더 붙이지 않을 수 있음.
#[inline]이 단순한 힌트라는 건 정확하지 않음. cross-crate inlining도 활성화함. 제네릭에서는 크레이트 간 인라이닝이 항상 가능하지만, 비제네릭 함수에서는 기본적으로 불가능함. 힌트 부분만 뺀 #[can_inline] 이 없다는 게 아쉬움.
C++을 쓰다 넘어왔는데, 접근자 함수에 인라인 속성을 빠뜨려 성능 문제를 겪었음. 다른 크레이트에서는 함수 내부를 볼 수 없는 호출이 되어버렸기 때문임. C++이었다면 헤더에 멤버 함수를 정의해 자동으로 inline이 됐을 것임.
한발 더 나아가 컴파일러가 인라인 가능성을 추정해 #[can_inline]을 자동으로 붙여주면 좋겠음.
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기