Rust `image-rs`의 `fast_blur` 함수, 5.9배 빨라지다!
Rust `image-rs` 라이브러리의 `fast_blur` 함수를 최적화하여 이미지 처리 속도를 대폭 향상시킴
정수 연산(Integer Arithmetic)을 활용한 누산기(Accumulator) 구현 및 나눗셈 연산(Division Operation)을 대체하여 성능 개선
`BlurAccumulator` 트레이트(Trait)를 설계하여 다양한 픽셀 타입(Pixel Type)에 대한 유연성을 확보
최적화 결과, u8 이미지에서 최대 5.9배의 속도 향상을 달성하여 실시간 애플리케이션(Real-time Application) 적용 가능
`fast_blur` 알고리즘 분석 및 성능 병목 지점
본문에서는 `fast_blur` 알고리즘의 성능 병목 지점을 분석하고, 최적화 과정을 상세히 설명한다. 프로파일링 도구(Profiling Tool)를 사용하여 `roundf`, `to_f32`, `min/max` 함수가 주요 성능 저하 요인임을 파악했다. 특히, u8 픽셀을 f32로 변환하는 과정에서 발생하는 부동 소수점 연산(Floating-point Operation)이 주요 병목 지점임을 확인했다. 이러한 분석을 바탕으로 정수 연산을 활용하는 최적화 기법을 적용했다.
정수 누산기(Integer Accumulator)를 활용한 최적화
최적화의 핵심은 u8 픽셀의 값을 f32 대신 u32 정수형으로 누적하여 부동 소수점 연산(Floating-point Operation)을 제거하는 것이다. 이를 위해 `BlurAccumulator` 트레이트를 설계하여 픽셀 타입에 따라 적절한 누산기를 선택하도록 했다. u8 픽셀의 경우 u32를, 다른 타입의 경우 f32를 사용함으로써 타입별 최적화(Type-Specific Optimization)를 가능하게 했다. 이로 인해 1.83배의 속도 향상을 달성했다.
나눗셈 연산(Division Operation) 제거를 통한 성능 향상
정수 누산기 사용 후에도 나눗셈 연산이 여전히 병목 지점으로 작용했다. 이를 해결하기 위해 Granlund & Montgomery(1994)의 기법을 활용하여 나눗셈을 곱셈과 비트 시프트 연산(Bit Shift Operation)으로 대체했다. 커널 크기에 대한 역수를 미리 계산하여 곱셈 연산을 수행함으로써, CPU 파이프라인(CPU Pipeline)을 효율적으로 활용하고, 3배의 성능 향상을 추가로 달성했다.
BlurAccumulator 트레이트(Trait) 설계 및 구현
최적화 과정에서 다양한 픽셀 타입을 지원하기 위해 `BlurAccumulator` 트레이트를 설계했다. 이 트레이트는 `from_primitive`, `create_weight`, `to_store` 메서드를 통해 픽셀 타입별로 맞춤형 연산(Custom Operation)을 제공한다. 특히, `U8Weight` 구조체를 사용하여 역수와 라운딩 바이어스(Rounding Bias)를 저장함으로써, 정수 연산 기반의 최적화(Integer-based Optimization)를 효과적으로 구현했다. 이 설계는 코드의 유연성과 성능을 동시에 확보하는 데 기여했다.