
ARM Cortex-M4 기반 자동차 ECU 환경에서 C와 Rust의 성능 비교 분석
Copyright Ⓒ 2026 KSAE / 249-05
This is an Open-Access article distributed under the terms of the Creative Commons Attribution Non-Commercial License(http://creativecommons.org/licenses/by-nc/3.0) which permits unrestricted non-commercial use, distribution, and reproduction in any medium provided the original work is properly cited.
Abstract
C and C++ have long been the standard programming languages for automotive software due to their performance and low-level hardware control. However, memory-safety issues such as null-pointer dereferences, buffer overflows, and data races make compliance with functional safety standards, such as ISO 26262 increasingly challenging. This study evaluates whether Rust can serve as a safe alternative by comparing its performance with C in a bare-metal environment on an STM32F446RE MCU (ARM Cortex-M4, 16 MHz). To ensure a fair comparison by eliminating backend differences, both C (Clang/LLVM 20.1.7) and Rust (rustc 1.84.0 with LLVM 20.1.7) were compiled using the same LLVM backend version. Sixteen benchmarks covering integer operations, array processing, memory copying, cryptography, control flow, and signal processing were implemented idiomatically in both languages, with CPU cycles measured using the DWT cycle counter. The results show that Rust outperformed C in seven benchmarks, while C was faster in eight, with one tie. Assembly-level analysis revealed that Rust’s performance gains stem from LLVM’s aggressive loop unrolling, function inlining, ARM-optimized library substitution, and noalias optimization enabled by its ownership system. C’s performance advantages derive from omitting frame pointers and effective use of ARM ITE (If-Then-Else) conditional execution instructions. This study empirically demonstrates that, with the same LLVM backend, Rust can achieve comparable or better performance than that of C in specific domains while providing compile-time memory safety guarantees. Furthermore, the results confirm that Rust’s zero-cost abstractions, such as iterators and ownership-based alias analysis, are realized at the assembly level without runtime overhead, providing both memory safety guarantees and additional optimization opportunities.
Keywords:
Rust, C language, Memory safety, Real-time performance, Embedded systems, Automotive software키워드:
러스트, C 언어, 메모리 안전성, 실시간 성능, 임베디드 시스템, 차량용 소프트웨어1. 서 론
1.1 연구 배경
최신 자동차의 전자제어장치(ECU)는 복잡한 소프트웨어로 구동되며, 대부분 C/C++ 기반으로 개발되어 왔다. 그러나 전통적인 언어 구조는 메모리 안전성 측면에서 취약점을 내포하고 있다는 평가가 많다. 구글은 안드로이드 플랫폼에서 메모리 안전 언어를 도입한 이후 메모리 안전성 취약점 비율이 76 %에서 24 %로 감소했다고 보고하였다.1) 또한 CISA(Cybersecurity and Infrastructure Security Agency) 등은 C/C++의 메모리 안전성 문제를 지적하며 메모리-안전 언어로의 전환을 권고하고 있다.2)
자동차 산업에서도 메모리 안전성을 확보하려는 움직임이 나타나고 있다. 예컨대 Infineon Technologies는 자사의 AURIX™ MCU 계열에서 Rust 언어 지원을 공식 발표하며 임베디드 Rust 생태계를 조성하고 있다.3) 또한 AUTOSAR Consortium은 Classic 및 Adaptive 플랫폼에서의 기능 안전 및 실시간 요구사항을 고려한 표준 아키텍처를 제공하고 있다.4) 이런 자동차 EUC에 탑재되는 소트웨어의 안정성이 대두되면서, C언어보다 메모리 안정성이 우수한 Rust의 적용을 위한 실증적인 연구가 필요하다.
1.2 관련 연구
Rust의 성능 및 안전성에 관한 기존 연구들은 다양한 관점에서 이 언어의 가능성을 탐색해 왔다. RustBelt 프로젝트는 Rust의 타입 시스템과 소유권 모델의 형식적 건전성을 증명하였으며,6) 여러 벤치마크 연구에서 Rust가 C/C++과 유사한 수준의 런타임 성능을 달성할 수 있음이 확인되었다.7) 자동차 산업에서도 Infineon의 AURIX/TRAVEO 계열 Rust 지원,3,8) Vector의 AUTOSAR Classic 환경에서의 Rust 적용 사례9) 등 도입 논의가 활발히 진행되고 있다.
그러나 기존 연구들에는 다음과 같은 한계가 존재한다. 첫째, 대부분의 성능 비교 연구에서 C는 GCC, Rust는 LLVM으로 컴파일하여 컴파일러 백엔드의 차이가 성능 결과에 혼재되어 있다.10) 둘째, 범용 시스템 환경에서의 벤치마크가 주를 이루며, 자동차 ECU 특화 연산 패턴(신호 처리, 제어 흐름, CAN 통신 등)에 대한 정량적 검증이 부족하다.5,7) 셋째, 성능 차이의 원인을 블랙박스 수준에서 보고하는 데 그쳐, 어셈블리 수준의 근본 원인 분석이 이루어지지 않았다.7)
기존 연구들은 주로 Rust의 언어적 특성이나 메모리 안전성 확보 메커니즘에 초점을 맞추어 왔지만, 실제 차량용 임베디드 환경에서 Rust가 C를 대체 가능한지 정량적으로 검증된 연구는 제한적이다. 또한 차량용 임베디드 환경은 OSEK/VDX 기반의 실시간 운영체제(OS)와 엄격한 타이밍 요구사항을 갖추고 있으므로 일반 임베디드 연구 결과를 그대로 적용하기 어렵다. 특히 기존 비교 연구에서는 C를 GCC로, Rust를 LLVM으로 컴파일하여 컴파일러 백엔드의 차이가 성능 결과에 영향을 미쳤을 가능성이 있다.
1.3 연구 필요성 및 목적
차량용 임베디드 환경을 위한 엄격한 타이밍 요구사항과 백엔드의 성능 차이에 의한 영향을 최소로 한 연구의 필요성이 있다. 따라서 본 연구는 C(Clang/LLVM)와 Rust(LLVM) 모두 동일한 LLVM 20.1.7 백엔드를 사용함으로써, 컴파일러 백엔드 차이를 제거하고 언어 및 관용적 구현 방식의 차이를 비교하였다.
아울러 본 연구는 STM32F446RE MCU (ARM Cortex-M4, 16 MHz) 임베디드 환경에서 C와 Rust의 실시간성을 비교하였다. 이를 통해 차량용 임베디드 시스템에서 Rust가 C의 현실적 대안이 될 수 있는지 실증적으로 평가하고, 향후 차량용 임베디드 환경에서의 언어 선택 방향을 제시하는 것을 목적으로 한다.
본 연구의 독창적 기여는 다음과 같다. 첫째, 동일 LLVM 백엔드 기반 비교를 통해 언어 프론트엔드의 IR 생성 차이가 최종 성능에 미치는 영향을 최초로 분리 측정하였다. 둘째, 어셈블리 수준 분석이라는 화이트박스 접근을 통해 성능 차이의 근본 원인을 규명하였으며, 이는 기존의 블랙박스 성능 비교와 차별화되는 학술적 가치를 갖는다.
2. 실험 방법 및 결과
2.1 실험 방법
본 연구에서는 자동차 ECU에서 널리 사용되는 ARM Cortex-M 계열 마이크로컨트롤러를 실험 플랫폼으로 선정하였다. 구체적으로 STMicroelectronics의 Nucleo-F446RE 개발 보드를 사용하였으며, 주요 사양은 다음과 같다. 클럭 소스로 내부 고속 발진기(HSI, 16 MHz)를 사용한 이유는 외부 크리스탈 없이 조건을 동일하게 유지해 재현성을 확보하고, PLL 설정에 따른 변수를 제거해 구성을 단순화하며, 저전력 모드에서의 일반적인 동작 조건을 대표하기 위해서이다.
본 연구는 절대 실행 시간(ms)이 아닌 CPU 사이클 수를 측정하므로, 클럭 주파수는 C와 Rust 간 상대 비교 결과에 영향을 미치지 않는다.
STM32F446RE를 실험 플랫폼으로 선정한 이유는 다음과 같다. 첫째, ARM Cortex-M4는 자동차 ECU에서 가장 널리 사용되는 마이크로컨트롤러 아키텍처 중 하나이며, 본 실험 결과의 자동차 산업 적용 가능성을 높인다. 둘째, 단순한 3단계 파이프라인 구조로 결정론적 실행이 가능하여, 측정 결과의 재현성을 보장한다. 셋째, FPU (Floating Point Unit)를 탑재하여 부동소수점 연산 벤치마크의 실행이 가능하다.
본 연구의 핵심적인 차별점은 C와 Rust 모두 동일한 LLVM 백엔드(버전 20.1.7)를 사용하여 컴파일했다는 점이다. 컴파일러 백엔드 차이에 의한 성능 변동을 제거하고, 프론트엔드 IR 생성 방식과 관용적 구현 방식이 결합된 성능 특성을 비교할 수 있다.
주요 설정 차이는 다음과 같다.
- 1) 루프 언롤링: 양쪽 모두 언롤링 억제를 시도했으나, 일부 케이스(Array, Matrix 등)에서는 LLVM이 루프를 소거/전개하는 최적화가 관찰됨
- 2) 프레임 포인터: Clang은 기본적으로 생략(-fomit-framepointer), Rust는 본 실험 환경에서 생성됨이 관찰됨
사이클 카운팅에는 ARM Cortex-M의 DWT(Data Watchpoint and Trace) 유닛을 활용하였다. DWT는 코어 클럭과 동기화된 32비트 사이클 카운터(CYCCNT)를 제공하며, 오버헤드 없이 정확한 사이클 측정이 가능하다.
컴파일러 최적화로 인한 코드 제거(Dead code elimination)를 방지하기 위해 다음 기법을 적용하였다.
- 1) C: volatile 변수에 계산 결과 저장
- 2) Rust: core::hint::black_box() 매크로로 결과 래핑
이를 통해 측정 대상 코드가 최적화 과정에서 제거되지 않음을 보장하였다.
이러한 빌드 설정 차이는 실험 결과 해석에 중요한 의미를 갖는다. 루프 언롤링 억제 시도에도 불구하고 일부 케이스에서 관찰된 비대칭적 최적화는, 동일 백엔드에서도 프론트엔드 IR 생성 방식에 따라 최적화 패스의 적용 여부가 달라질 수 있음을 시사한다. 프레임 포인터 설정의 차이는 함수 호출 집약적 벤치마크에서 유의미한 성능 차이의 원인이 되며, 이는 2.5절의 결과 분석에서 상세히 다룬다.
2.2 시스템 구성도
실험 장치는 크게 호스트 PC(Host PC), 인터페이스(ST-LINK), 대상 보드(Target board)의 세 부분으로 구성된다.
- 1) Host PC: 인텔 코어 i7 프로세서 기반의 워크스테이션에서 C와 Rust 소스 코드를 빌드한다. 본 연구의 핵심 차별점인 동일 백엔드 비교를 위해 두 언어 모두 LLVM 20.1.7 버전을 공유하는 통합 툴체인을 구축하였다. 빌드된 바이너리는 ST-LINK를 통해 보드로 전송된다.
- 2) Target Board (Nucleo-F446RE): ARM Cortex-M4F 코어를 탑재한 대상 보드에서 실제 연산이 수행된다. 내부의 DWT(Data Watchpoint and Trace) 유닛을 활성화하여 CPU 사이클 단위의 정밀한 측정을 수행하며, 결과값은 측정 간섭을 피하기 위해 즉시 SRAM 배열에 버퍼링된다.
- 3) Interface & Data Flow: ST-LINK/V2를 통해 바이너리 플래싱(Flashing)이 이루어지며, 측정 완료 후의 통계 데이터는 UART(Virtual COM Port)를 통해 호스트 PC의 시리얼 터미널로 전송되어 수집된다.
2.3 벤치마크 설계
차량 소프트웨어의 특성을 반영한 16개 벤치마크를 설계하였다. 선정 기준은 다음과 같다.
- 1) 차량 관련성: ECU 소프트웨어에서 실제 사용되는 연산 패턴
- 2) 다양성: 정수, 부동소수점, 메모리, 제어 흐름 등 다양한 영역 포함
- 3) 측정 가능성: 충분한 실행 시간으로 측정 오차 최소화
- 4) 재현성: 입력 데이터와 알고리즘의 결정론적 동작
이러한 기준에 따라 차량 ECU 소프트웨어의 핵심 연산 패턴을 6개 카테고리, 16개 벤치마크로 분류하였다 (Tables 4~9). 각 벤치마크의 실행 규모는 반복 설정을 통해 결정하였다. 외부 반복 횟수인 ITERATIONS는 100으로 설정했고, 각 외부 반복 내부에서 수행되는 INNER_LOOP는 50으로 설정하였다. 또한 통계적 신뢰도를 확보하기 위해 전체 실행을 NUM_RUNS만큼 30회 반복 측정하였다. 따라서 한 번의 실행에서 수행되는 총 반복 횟수는 ITERATIONS × INNER_LOOP = 100 × 50 = 5,000회이다.
각 카테고리는 실제 자동차 ECU 소프트웨어의 핵심 연산 패턴을 반영하여 선정되었다. Category 1(기본 연산)은 엔진 제어 루프의 정수/고정소수점 연산, Category 2(배열/메모리)는 센서 데이터 버퍼링 및 CAN 메시지 처리, Category 3(알고리즘)은 진단 테이블 탐색 및 데이터 정렬, Category 4(신호 처리)는 필터링 및 주파수 분석, Category 5(제어/보안)는 상태 기반 제어 로직 및 보안 통신, Category 6(수학 연산)은 차량 동역학 계산에 각각 대응된다.
본 연구는 “각 언어에서 실무적으로 사용되는 관용적 코드(Idiomatic code)의 성능”을 비교한 것이다. 예를 들어 메모리 복사에서 C는 명시적 for 루프를, Rust는 copy_from_slice를 사용하였는데, 이는 각 언어 커뮤니티에서 권장하는 표준적인 방식이다. 따라서 본 결과는 “동일 알고리즘의 순수 언어 차이”라기보다 “실무 코드 스타일에서의 컴파일러 최적화 차이”로 해석되어야 한다.
참고로, C에서도 memcpy() 표준 라이브러리를 사용하면 Rust와 유사한 최적화 경로를 기대할 수 있으나, 본 연구에서는 명시적 루프 구현을 사용하였다.
2.4 측정 방법 및 실험 결과
측정 프로토콜은 다음과 같다(아울러 각 언어별, 벤치마크 별로 Batch를 램덤화하여 무작위성을 부여하였다).
- 1) 보드 전원 인가 및 리셋
- 2) DWT 사이클 카운터 초기화
- 3) 각 벤치마크에 대해:
- ① 30회 반복 측정
- ② 각 측정 후 결과 배열에 저장
- ③ 통계 계산 (평균, 최소, 최대, 표준편차)
- ④ UART로 결과 출력
- 4) “Benchmark complete” 출력 후 종료
측정 결과의 신뢰성을 확보하기 위해, 본 연구에서는 DWT 카운터 동작, 측정-출력 구간 분리, Flash ART 영향 및 실행 환경의 안정성에 대해 추가적으로 분석하였다.
(1) DWT 카운터 안정성 검증
본 연구에서는 DWT 32-bit 사이클 카운터를 사용하였다. CPU 클럭 16 MHz(HSI) 기준 오버플로우 주기는 약 268.4초이다.
본 실험의 단일 벤치마크 측정 구간은 최대 17,525,706 cycles(약 1.09초)에 해당하며, 전체 반복 루프 역시 오버플로우 주기보다 충분히 짧다. 따라서 DWT 오버플로우가 표준편차 0 결과에 영향을 미쳤을 가능성은 배제된다.
(2) 측정 구간과 출력 구간의 완전 분리
측정 구간과 UART 출력 구간은 완전히 분리하였다. 각 벤치마크의 30회 반복 측정은 인터럽트 비활성화 상태에서 수행되었으며, Cycle 값은 RAM 배열에 저장되었다.
통계 계산 또한 메모리 상에서 수행되었으며, 모든 측정 및 계산이 완료된 이후에만 UART 출력이 수행되었다. 측정 루프 내에서는 printf, DMA 전송, 인터럽트 기반 송신 등 어떠한 I/O 동작도 포함되지 않았다. 따라서 UART 출력이 측정 결과에 영향을 미쳤을 가능성은 없다.
(3) Flash ART Accelerator의 영향
STM32F446RE는 Flash ART(Adaptive Real-Time) Accelerator를 포함하며, 이는 Flash 접근 지연을 완화하기 위해 명령어 Prefetch 및 Line buffer 기능을 제공한다.
본 실험은 16 MHz HSI 조건에서 수행되었으며, 해당 주파수에서는 Flash wait state가 0으로 설정된다. 동일 코드 주소 및 동일 입력 데이터 경로에서 반복 실행이 이루어졌으며, 초기 실행 이후 ART line hit 상태가 유지되었다. 이로 인해 Flash fetch 변동 요인이 제거되었으며, 반복 실행 시 Cycle-accurate 실행이 가능하였다.
(4) 파이프라인 및 결정론적 실행 환경
Cortex-M4는 단순 3-stage 파이프라인 구조를 가지며, Out-of-order execution이나 Speculative execution을 수행하지 않는다. 동일 입력 데이터와 동일 분기 경로가 유지되는 조건에서는 파이프라인 상태가 반복 실행마다 동일하게 유지된다.
본 연구에서는 인터럽트를 비활성화하고 입력을 고정하여 외부 변동 요인을 제거하였다. 이와 같은 통제 조건 하에서는 반복 실행 시 Cycle 수가 완전히 동일하게 나타날 수 있다.
(5) 표준편차 계산 방식에 대한 해석
표준편차는 정수 기반으로 계산되므로, 1 cycle 미만의 변동은 0으로 표현될 수 있다. 그러나 본 실험에서는 원시 Cycle 데이터에서 최소값과 최대값이 완전히 동일하게 관측되었다. 따라서 표준편차 0은 단순한 계산상의 반올림 효과가 아니라, 반복 실행 결과가 동일한 Cycle 값으로 수렴하였음을 의미한다.
표의 표준편차 0은 ‘정수 분해능(1 cycle)에서 변동이 관측되지 않음’을 의미한다.
(6) 선행 연구와의 정합성
본 실험의 표준편차 0은 계산상의 반올림 산물이 아니라, 30회 반복 측정의 원시 Cycle count에서 모든 벤치마크에 대해 최소값과 최대값이 동일하게 관측된 결과이다. 즉, 1-cycle 분해능(정수 기반 측정)에서 변동이 관측되지 않았음을 의미한다. 이러한 결과는 WCET 분석 문헌에서 제시하는 프로세서 분류 체계와 부합한다. Wilhelm 등은 투기적 실행(Speculative execution)이나 비순차 실행(Out-of-order execution)과 같은 복잡한 마이크로아키텍처 기능이 없는 단순 스칼라 파이프라인 프로세서에서는 타이밍 이상(Timing anomaly)이 발생하지 않아 타이밍 예측성이 높다고 보고하였다.11) Cortex-M4의 3단계 In-order 파이프라인은 이러한 예측 가능한 구조로 해석할 수 있으며, 본 실험의 통제 조건과 결합하여 결정론적 실행이 가능한 환경을 구성한다. 또한 Kannwischer 등은 동일한 Cortex-M4 플랫폼(STM32F4)에서 포스트양자암호 벤치마크를 수행하며, Flash 메모리 컨트롤러의 Wait cycle을 제거하기 위해 24 MHz로 클럭을 낮추는 방법론을 적용하였다.12) 본 연구의 16 MHz HSI 설정은 이와 동일한 원리에 기반한다. 한편, Microchip의 기술 노트에서도 Cortex-M 계열에서 메모리 접근 경로를 통제할 경우 실행 시간 변동이 크게 줄어들 수 있음을 보조적으로 확인한 바 있다.13) 다만, 본 결과는 일반적인 임베디드 시스템 전체에 대한 주장이 아니라 본 논문에서 명시한 통제된 Bare-metal 측정 환경에서의 결과로 해석되어야 한다.
(7) 대조 실험에 의한 추가 검증
본 실험의 통제 조건이 표준편차 0의 원인임을 검증하기 위해, 동일한 벤치마크 코드를 인터럽트 활성화 조건에서 재실행하는 대조 실험을 수행하였다. SysTick 타이머를 1 kHz(16,000 cycles 주기)로 설정하여 주기적 인터럽트를 발생시킨 상태에서 Integer 및 Array 벤치마크를 30회 반복 측정한 결과는 Table 10과 같다.
정상 측정(인터럽트 비활성화) 조건에서 동일 벤치마크의 표준편차는 0이었으나, 인터럽트를 활성화하면 SysTick ISR 진입/복귀에 의한 파이프라인 상태 변동으로 인해 표준편차가 양수로 관측되었다. 이는 본 실험의 표준편차 0이 측정 오류가 아니라, 통제된 실행 환경의 결과임을 실증적으로 확인한다.
Tables 11과 12는 각각 C(Clang)와 Rust의 벤치마크별 측정 결과를 요약하며, Table 13은 두 언어의 성능을 직접 비교한다. 전반적으로 Rust는 메모리 접근 및 수학 연산 영역에서 우수하고, C는 함수 호출 및 제어 흐름 영역에서 우수한 경향을 보인다. 이러한 패턴은 각 언어의 컴파일러 프론트엔드가 LLVM IR을 생성하는 방식과 런타임 안전성 검사의 유무에 기인하며, 2.5절에서 어셈블리 수준으로 상세 분석한다.
성능 비교에서 Tie(동등) 판정 기준은 Ratio가 0.95~1.05 범위(±5 % 이내)인 경우로 정의하였다. 이는 측정 분해능(1 cycle) 및 미세한 구현 차이를 고려한 것이다.
결과 요약은 다음과 같다.
- 1) Rust 우위: 7개 (Integer, Fixed, Array, Matrix, Crypto, FloatTrig, DMA_Mem)
- 2) C 우위: 8개 (Bitwise, Control, FuncCall, Sorting, Search, Filter, Signal, PriQueue)
- 3) 동등: 1개 (RingBuf)
Fig. 2는 Table 13의 벤치마크별 성능 비교 결과를 시작적으로 나타낸 것으로, C와 Rust 실행 Cycle 수를 로그 스케일로 표현하였다. 이를 통해 벤치마크 간 절대적인 Cycle수 차이와 함께 두 언어 간 상대적인 성능 우위를 동시에 확인할 수 있다. 특히 DMA_Mem, Array, Matrix와 같이 메모리 접근 패턴 최적화 또는 컴파일 타임 구조 인식의 영향을 크게 받는 벤치마크에서는 Rust가 C보다 낮은 Cycle 수를 보여 상대적으로 우수한 성능을 나타냈다. 반면 FuncCall, Control, Search와 같이 함수 호출 오버헤드, 분기 구조, 경계 검사 등의 영향이 크게 작용하는 벤치마크에서는 C가 더 낮은 Cycle 수를 보여 우세한 경향을 보였다. 또한 RingBuf와 같이 두 언어의 실행 Cycle 차이가 거의 없는 항목도 존재하여, 모든 영역에서 일방적인 우위가 나타나는 것은 아님을 확인할 수 있다. 즉, Fig. 2는 Rust와 C의 성능 차이가 단순히 언어 자체의 우열에 의해 결정되기보다는, 각 벤치마크의 연산 특성과 컴파일러가 생성한 최종 코드 구조에 따라 달라질 수 있음을 시각적으로 보여준다.
본 실험에서 모든 벤치마크의 표준편차가 0으로 측정된 것은 다음과 같은 결정론적 실행 환경 구성에 기인한다.
- 1) 측정 전 PRIMASK 레지스터를 설정하여 모든 인터럽트를 비활성화하였다.
- 2) 16 MHz HSI 클럭에서는 Flash 접근 지연(Wait state)이 0으로 설정된다.
- 3) ART Accelerator의 프리페치 버퍼가 활성화되어 명령어 페치 지연이 일정하게 유지된다.
- 4) 각 벤치마크의 30회 측정 전에 1회 워밍업 실행을 수행하여 명령어 캐시와 파이프라인 상태를 안정화하였다.
2.5 결과 분석
본 실험에서 Rust가 C 대비 우수한 성능을 보인 벤치마크는 7개 항목으로, C가 우수한 것은 8개 항목, 동등은 1개로 나타났다. 각 항목 별로 어디서 성능 차이가 났는지 분석하였다.
본 절의 분석은 동일한 LLVM 20.1.7 백엔드를 사용한 실험 설계에 기반하며, 이를 통해 프론트엔드 IR 생성 차이만을 분리하여 비교할 수 있다는 방법론적 의의를 갖는다.
DMA_Mem 벤치마크에서 Rust는 68 %의 성능 향상을 달성했다. 어셈블리 분석결과, LLVM은 Rust의 슬라이스 복사 루프를 인식하여 ARM 최적화 라이브러리 함수(__aeabi_memcpy4)로 자동 변환하였다. 반면 Clang은 C의 동일한 루프를 단순한 바이트 단위 load/store 루프로 컴파일하였다.
또한 fill_pattern 함수에서 Rust/LLVM은 32배 루프 언롤링을 적용하여 각 반복에서 32바이트를 처리하는 반면, Clang은 바이트 단위 루프를 생성하였다. 이러한 패턴 인식과 라이브러리 대체 최적화가 68 % 성능 향상의 주요 원인이다.
Array 벤치마크에서도 33 %의 성능 향상이 관찰되었다. 어셈블리 분석 결과, Rust/LLVM은 64개 요소 배열에 대해 완전 루프 언롤링과 LDMIA(Load Multiple) 명령어를 적용하였다.
LLVM은 배열 크기가 컴파일 타임에 알려진 경우 완전 언롤링을 적용하고, LDMIA 명령어로 여러 레지스터에 동시 로드하여 메모리 대역폭을 최대화한다. 이로써 64회의 분기 오버헤드가 완전히 제거되어 33 % 성능 향상이 달성되었다.
Crypto 벤치마크에서 Rust는 24 %의 성능 향상을 보였다. ChaCha 레지스터 최적화로 Rust는 4개의 상태 값을 함수 시작 시 레지스터에 로드하여 모든 연산을 레지스터에서 수행하고 마지막에만 메모리에 저장한다. C는 매 연산마다 인덱스를 계산하여 메모리에 접근한다.
FloatTrig 벤치마크에서 10 % 성능 향상이 관찰되었다. 두 언어 모두 동일한 Taylor 급수 알고리즘을 직접 구현하였으며(libm 미사용), 어셈블리 분석 결과 Rust(LLVM)가 C(Clang)보다 FPU 명령어 스케줄링이 더 효율적이어서 파이프라인 활용도가 높은 것으로 확인되었다.
Matrix 벤치마크(3×3 행렬 곱셈)에서 57 % 성능 향상이 관찰되었다. 어셈블리 분석 결과, Rust/LLVM은 3×3×3=27개의 곱셈 연산을 완전 언롤링하여 루프 분기를 제거한 반면, Clang은 2중 루프를 유지하였다.
FuncCall 벤치마크에서 C는 83 %의 성능 우위를 보였다. 두 언어 모두 인라인을 금지하는 속성(C: __attribute__((noinline)), Rust: #[inline(never)])을 사용하여 실제 함수 호출 오버헤드를 측정하였다. 어셈블리 분석 결과, 성능 차이의 원인은 프레임 포인터 설정 여부이다.
1) 프레임 포인터 생성 원인 분석
리프 함수(Leaf function)임에도 불구하고 Rust에서 프레임 포인터가 생성된 구체적인 원인을 분석한 결과는 다음과 같다.
- ① 표준 최적화 정책 준수: 본 실험은 각 언어의 표준 성능을 비교하기 위해 인위적인 최적화 플래그를 배제하였다. C(Clang)에서 프레임 포인터 제거 옵션을 명시하지 않은 것과 동일하게, Rust에서도 -C force-frame-pointers=no 등의 옵션을 사용하지 않았다. 이는 각 언어 환경이 제공하는 기본(Default) 최적화 수준에서의 공정한 비교를 위함이다.
- ② 패닉 정책(Panic policy)과의 독립성: 일반적으로 스택 언와인딩(Unwinding)을 위해 프레임 포인터가 활용되기도 하지만, 본 실험은 panic = abort 설정을 통해 관련 오버헤드를 제거한 상태였다. 그럼에도 프레임 포인터가 유지된 것은 해당 동작이 예외 처리 로직이 아닌, 프론트엔드의 코드 생성 방식에 고정되어 있음을 의미한다.
- ③ 타겟별 코드 생성 기본값(Default target policy) 차이: 가장 핵심적인 원인은 컴파일러 타겟별 기본 정책의 차이다. Clang은 -O2 수준에서 리프 함수의 프레임 포인터를 기본적으로 제거(Omission)하지만, Rust 컴파일러(v1.84.0)의 thumbv7em 타겟 프로필은 디버깅 신뢰성과 정확한 콜 스택 복원을 위해 프레임 포인터(r7)를 유지하는 보수적인 코드 생성을 기본 전략으로 채택하고 있다.
본 실험 환경에서 Rust는 단순한 리프 함수에서도 프레임 포인터를 설정한 것이 관찰되었다. 이는 하드폴트(HardFault) 등 예외 발생 시 정확한 콜 스택 복원을 가능하게 하며, GDB/JTAG 디버거에서 신뢰할 수 있는 백트레이스를 제공한다. 이는 Rust의 “기본적으로 안전함(Safe by default)” 철학을 반영한 것으로 해석된다.
Control 벤치마크에서 C는 36 %의 성능 우위를 나타냈다. 어셈블리 분석 결과, 두 가지 주요 원인이 확인되었다.
첫째, 프레임 포인터 오버헤드이다. FuncCall과 마가지로 Rust의 모든 분기 함수가 push {r7, lr} / pop {r7, pc}를 포함한다.
둘째, 복귀점 구조의 차이이다. Clang은 ARM의 ITE(If-Then-Else) 조건부 실행 명령어를 적극 활용하여 분기 없이 조건부 연산을 수행하고, 모든 경로가 단일 bx lr로 수렴한다. 반면 Rust/LLVM은 각 분기마다 별도의 pop {r7, pc} 복귀점을 생성하여 코드 크기가 증가하고, 명령어 캐시 효율이 저하된다.
Search 벤치마크(이진 탐색)에서 C는 46 %의 성능 우위를 보였다. 어셈블리 분석 결과, 루프 내 경계 검사와 프레임 포인터 오버헤드가 주요 원인으로 확인되었다. 이진 탐색은 O(log n) 알고리즘으로 루프 반복이 적지만, Rust에서는 매 반복마다 cmp.w lr, #64 경계 검사가 수행된다. 또한 Rust는 부호있는 나눗셈 보정을 위한 추가 명령어(add.w r2, r2, r2, lsr #31)가 필요하다.
Signal, PriQueue, Sorting 벤치마크에서 C가 9~21 %의 성능 우위를 보인 공통 원인은 경계 검사 오버헤드와 프레임 포인터 설정이다. 복잡한 자료구조에서 반복적인 배열 접근이 발생하며, 각 접근마다 경계 검사가 누적되어 성능 차이로 이어진다.
Integer 벤치마크는 덧셈, 뺄셈, 곱셈, 나눗셈의 기본 정수 연산을 측정한다. Rust가 9 % 빠른 것으로 나타났는데, 이는 LLVM이 동일하게 처리하면서도 Rust/LLVM이 더 효율적인 레지스터 할당을 수행한 것으로 분석된다.
RingBuf 벤치마크에서 1.00의 비율(동등)이 나타난 것은 링 버퍼의 예측 가능한 접근 패턴으로 인해 Rust의 경계 검사가 효과적으로 제거되었기 때문이다.
2.6 논의
본 절에서는 실험 결과를 바탕으로 Rust와 C의 성능 차이 요인을 심층적으로 논의한다. 본 연구는 어셈블리 수준 분석이라는 차별적 접근을 통해, 기존의 블랙박스 성능 비교를 넘어 성능 차이의 근본 원인을 규명하였다. 이하에서는 각 언어의 성능 우위 요인과 안전성-성능 트레이드오프를 분석한다.
본 연구의 핵심적 발견 중 하나는 Rust의 소유권 시스템이 단순한 안전성 도구가 아닌 컴파일러 최적화 Enabler로 작용한다는 점이다. 이는 기존 연구에서 충분히 인식되지 않았던 독창적 기여이다.
본 연구를 통해 Rust가 C 대비 성능 우위를 보이는 핵심 요인을 다음과 같이 식별하였다.
2.6.1.1 소유권 기반의 별칭 분석
Rust의 소유권 시스템은 단순한 메모리 안전성 도구가 아니라, 강력한 컴파일러 최적화 Enabler로 작용한다. C에서 포인터 별칭 문제는 컴파일러 최적화의 주요 장애물이다. 즉 C 컴파일러는 a와 b가 같은 메모리를 가리킬 수 있다고 가정해야 한다. 하지만 Rust의 경우 소유권 규칙에 의해 중복 불가능을 보장한다. Rust에서 &mut 참조는 배타적임이 컴파일 타임에 보장되므로, LLVM은 다음 최적화를 적용할 수 있다.
- 1) 루프 벡터화 (SIMD 명령어 사용)
- 2) 메모리 접근 재배열
- 3) 레지스터 할당 최적화
- 4) 루프 불변 코드 이동
DMA_Mem 벤치마크에서 68 %의 성능 향상은 LLVM이 슬라이스 복사 패턴을 인식하여 ARM 최적화 라이브러리(__aeabi_memcpy4)로 대체하고, fill_pattern에 32배 루프 언롤링을 적용한 결과이다.
단, C에서도 restrict 키워드를 명시적으로 사용하면 유사한 최적화가 가능하나, 본 벤치마크의 C 코드에서는 restrict를 사용하지 않았다. 따라서 noalias로 인한 성능 차이는 언어 특성이 아닌 벤치마크 코드 작성 방식의 차이로 해석할 수도 있다.
2.6.1.2 Zero-Cost Abstractions의 실현
Rust의 추상화가 실제로 런타임 비용 없이 구현되는 사례를 확인하였다. 특히 Iterator의 fold 메서드는 컴파일러에 의해 수동 루프와 동등한 코드로 최적화된다.
2.6.1.3 프론트엔드 IR 생성 차이
본 연구의 핵심 발견 중 하나는, 동일한 LLVM 백엔드를 사용하더라도 rustc와 clang의 IR 생성 방식 차이로 인해 최종 코드 품질이 달라질 수 있다는 점이다.
Matrix 벤치마크(3×3 행렬 곱셈)에서 57 % 성능 향상은 rustc가 LLVM에 더 최적화하기 쉬운 IR을 생성했기 때문으로 분석된다.
C(Clang)가 Rust 대비 성능 우위를 보이는 요인은 다음과 같다.
2.6.2.1 최소 런타임 오버헤드
C는 설계 철학상 런타임 검사를 최소화한다. Rust는 안전성을 위해 다음과 같은 런타임 코드를 생성할 수 있다.
FuncCall 벤치마크에서 83 %의 성능 차이는 본 실험 환경에서 Rust가 단순한 리프 함수에서도 프레임 포인터를 설정했기 때문이다. 어셈블리 분석 결과, C는 adds r0, #1; bx lr (2개 명령어)로 함수를 구현하는 반면, Rust는 push {r7, lr}; mov r7, sp; adds r0, #1; pop {r7, pc} (4개 명령어)를 생성한다.
2.6.2.2 ITE 조건부 실행 명령어 활용
Clang은 ARM의 ITE(If-Then-Else) 조건부 실행 명령어를 적극 활용하여 분기 없이 조건부 연산을 수행한다. Control 벤치마크에서 36 % 성능 차이는 Clang의 ITE 활용과 단일 복귀점 구조에 기인한다. C는 ite le; movle r0, #2; movgt r0, #1; bx lr로 단일 복귀점을 사용하는 반면, Rust는 각 분기마다 별도의 pop {r7, pc} 복귀점을 생성하여 코드 크기가 증가한다.
2.6.2.3 예측 가능한 코드 생성
C의 단순한 메모리 모델은 생성되는 어셈블리 코드를 예측하기 쉽게 만든다. 임베디드 개발자는 이를 활용하여 성능 튜닝을 수행할 수 있다.
본 연구의 핵심 발견은 Rust의 메모리 안전성 보장이 반드시 성능 저하를 의미하지 않는다는 것이다.
2.6.3.1 안전성이 성능을 개선하는 경우
소유권 시스템과 불변성 기본값은 컴파일러에게 추가 정보를 제공하여 최적화를 가능하게 한다. 이는 “안전성 세금(Safety tax)”이 아니라 “안전성 기반 최적화 이점(Safety-driven optimization benefit)”로 작용한다. 7개 벤치마크에서 성능 향상이 관찰되었으며, 이는 소유권 기반 최적화의 효과를 입증한다.
2.6.3.2 안전성이 성능을 저하시키는 경우
경계 검사와 패턴 매칭 완전성 검사는 런타임 오버헤드를 유발한다. 다만 성능이 필요한 경우 unsafe와 get_unchecked()를 사용하거나, 컴파일러에게 힌트를 제공하거나 Iterator를 사용해서 경계 검사를 자동으로 제거할 수 있다.
2.6.3.3 실무적 권장사항
본 연구 결과를 바탕으로 한 자동차 소프트웨어 개발 권장사항은 다음과 같다.
3. 결 론
기존 C/C++ 기반 자동차 ECU 개발은 메모리 안전성 문제로 인한 보안 취약점과 높은 검증 비용을 수반한다. 본 연구는 이러한 한계를 극복할 수 있는 대안으로서 Rust의 실시간 성능을 정량적으로 검증하고자 하였다.
STM32F446RE MCU에서 수행한 16개 벤치마크 실험 결과, Rust는 7개 항목에서 C 대비 우수한 성능을, C는 8개 항목에서 우위를, 1개 항목에서 동등한 성능을 보였다. 어셈블리 수준 분석을 통해 Rust의 성능 우위가 소유권 시스템에 기반한 noalias 최적화, 루프 언롤링, 라이브러리 함수 대체에서 비롯됨을 확인하였으며, C의 우위는 프레임 포인터 생략과 ITE 조건부 실행 명령어 활용에 기인함을 규명하였다.
추가적으로 NXP S32K312 기반 AUTOSAR Classic 4.4 환경에서 동일 벤치마크를 검증한 결과, ISR 및 Task 컨텍스트 내부의 순수 계산 구간에서 Bare-metal 환경과 동일한 상대적 성능 경향이 유지됨을 확인하였다. 이는 본 연구의 Bare-metal 실험 결과가 실제 자동차 소프트웨어 플랫폼에서도 유효함을 시사한다. AUTOSAR Classic Platform은 기본적으로 C 언어 중심으로 설계되어 있지만, Application SW 레이어를 시작점으로 한 단계적 Rust 도입이 현실적 전략이 될 수 있다.
본 연구의 기술적 기여는 다음과 같다. 첫째, 동일 LLVM 백엔드 기반의 공정한 비교 방법론을 제시하여, 향후 프로그래밍 언어 성능 비교 연구의 기준을 마련하였다. 둘째, 어셈블리 수준 분석을 통해 Rust 소유권 시스템이 단순 안전성 도구가 아닌 컴파일러 최적화 Enabler로 작용함을 실증하였다. 셋째, 자동차 ECU 특화 벤치마크를 통해 임베디드 Rust의 실무 적용 가능성에 대한 정량적 근거를 제공하였다. 학문적으로는, 언어 프론트엔드 IR 생성 차이가 동일 백엔드에서도 최종 코드 품질에 유의미한 영향을 미친다는 발견이 컴파일러 연구에 시사점을 제공한다.
본 연구 결과의 해석 시 다음 사항을 고려해야 한다.
- 1) Baseline 정의: 본 연구는 각 언어의 이론적 최적 성능이 아닌, 관용적 구현과 기본 컴파일 설정에서의 성능을 비교하였다. 따라서 특정 최적화 플래그(예: C의 restrict 키워드, Rust의 -C force-frame-pointers = no)를 적용하면 결과가 달라질 수 있다.
- 2) 루프 변환 영향: 동일 LLVM 백엔드에서도 프론트엔드 IR 생성 차이로 인해 상수 전파, 루프 소거, 완전 전개 등의 최적화가 비대칭적으로 적용될 수 있다. 본 연구는 -fno-unroll-loops와 llvm-args=-unroll-threshold = 0을 적용했으나, 이는 모든 형태의 루프변환을 차단하지 않는다. Array, Matrix 등 컴파일 타임 상수 크기 벤치마크에서 이 효과가 관찰되었다.
- 3) 프레임 포인터 영향: 관용적 비교 원칙에 따라 각 언어의 기본 설정을 유지하였으며, FuncCall 등 일부 벤치마크에서 프레임 포인터 생성 여부가 성능에 유의미한 영향을 주었다. 본 결과는 기본 설정에서의 실무적 경향을 제시하며, 프레임 포인터 강제/제거는 별도의 조건 통제 실험으로 해석되어야 한다.
- 4) 별칭(Aliasing) 가정: Rust의 &mut는 언어 차원에서 비별칭(Noalias) 가정을 제공하나, C에서는 restrict로 명시적 제공이 필요하다. 본 연구는 관용적 C 코드 관행을 반영하여 restrict를 사용하지 않았으며, 이 선택은 실무적 대표성을 높이지만 일부 벤치마크에서 별칭 정보 차이가 최적화 결과에 영향을 줄 수 있다.
- 5) 라이브러리 경로 영향: 메모리 복사 등 일부 연산은 표준 라이브러리 또는 컴파일러 내장 함수 경로로 연결되어 성능에 영향을 줄 수 있다. DMA_Mem 벤치마크에서 관찰된 성능 차이는 언어 자체보다 라이브러리 경로 선택(Rust의 copy_from_slice -> __aeabi_memcpy4 vs C의 수동 루프)의 영향을 포함한다.
따라서 본 연구의 결과는 ‘관용적 구현 + 기본 설정’ 하에서의 실무적 경향으로 해석되어야 한다.
향후 연구에서는 단일 코어 환경을 넘어 멀티코어 MCU 환경에서의 성능 및 안전성 특성을 분석할 필요가 있다. 특히 Rust의 소유권 및 대여(Ownership and borrowing) 모델이 동시성 환경에서 데이터 레이스를 어떻게 방지하며, 실제 시스템 성능과 설계 복잡도에 어떤 영향을 미치는지에 대한 정량적 분석이 요구된다.
Flash 메모리 용량이 제한된 MCU 환경을 고려하여, C와 Rust로 작성된 코드의 바이너리 크기를 비교 분석할 필요가 있다. 이는 Rust의 런타임 지원 코드와 안전성 검사가 코드 크기에 미치는 영향을 평가하는 데 중요한 지표가 될 것이다.
마지막으로 차량용 소프트웨어 적용을 위해 Rust 컴파일러 및 관련 툴체인의 ASIL 기능안전 인증 가능성에 대한 검토가 필요하다. 특히 기존 AUTOSAR 개발 프로세스와의 정합성, 인증 범위 설정, 그리고 C 기반 개발 대비 추가적으로 요구되는 검증 항목을 중심으로 연구가 진행되어야 한다.
References
- V. Stoep and A. Rebert, “Eliminating Memory Safety Vulnerabilities at the Source,” Google Online Security Blog, https://security.googleblog.com/2024/09/eliminating-memory-safety-vulnerabilities-Android.html, , 2024.
- U.S. Cybersecurity and Infrastructure Security Agency (CISA), “The Case for Memory Safe Roadmaps,” https://www.cisa.gov/case-memory-safe-roadmaps, , 2025.
- Infineon Technologies AG, “RUST | Infineon Technologies: Design Resources Development Tools SDK Rust,” https://www.infineon.com/design-resources/development-tools/sdk/rust, , 2025.
- AUTOSAR, “Classic Platform,” https://www.autosar.org/standards/classic-platform, , 2025.
-
A. Sharma, S. Sharma, S. Torres-Arias and A. Machiry, “Rust for Embedded Systems: Current State, Challenges and Open Problems (Extended Report),” arXiv preprint arXiv:2311.05063, , 2024.
[https://doi.org/10.1145/3658644.3690275]
- M. Jung, T. Levacic, O. Annenkov, R. Jung, L. Birkedal and D. Dreyer, RustBelt: Securing the Foundations of Rust, Technical Report, Max Planck Institute for Software Systems and Aarhus University, 2022.
-
Y. Zhang, Y. Zhang, G. Portokalidis and J. Xu, “Towards Understanding the Runtime Performance of Rust,” Proceedings of the 37th IEEE/ACM International Conference on Automated Software Engineering (ASE '22), Paper No.140, 2022.
[https://doi.org/10.1145/3551349.3559494]
- Infineon Technologies AG, “Infineon Expands Rust Ecosystem for AURIX™ with HighTec’s ISO 26262 ASIL D Qualified Rust Compiler and Other Solutions,” https://www.infineon.com/market-news/2024/infatv202404-089, , 2025.
- V. Bapp, “Safety-Applications with Rust and AUTOSAR Classic,” Vector Informatik News, https://www.vector.com/int/en/news/news/safety-applications-with-rust-and-autosar-classic/, , 2025.
-
R. Pereira, M. Couto, F. Ribeiro, R. Rua, J. Cunha, J. P. Fernandes and J. Saraiva, “Energy Efficiency across Programming Languages: How Do Energy, Time, and Memory Relate?,” Proceedings of the 10th ACM SIGPLAN International Conference on Software Language Engineering (SLE '17), pp.256-267, 2017.
[https://doi.org/10.1145/3136014.3136031]
-
R. Wilhelm, J. Engblom, A. Ermedahl, N. Holsti, S. Thesing, D. Whalley, G. Bernat, C. Ferdinand, R. Heckmann, T. Mitra, F. Mueller, I. Puaut, P. Puschner, J. Staschulat and P. Stenstrom, “The Worst-Case Execution-Time Problem: Overview of Methods and Survey of Tools,” ACM Transactions on Embedded Computing Systems, Vol.7, No.3, pp.1-53, 2008.
[https://doi.org/10.1145/1347375.1347389]
- M. J. Kannwischer, J. Rijneveld, P. Schwabe and K. Stoffelen, “pqm4: Testing and Benchmarking NIST PQC on ARM Cortex-M4,” IACR Cryptology ePrint Archive, Report 2019/844, 2019.
- Microchip Technology Inc., “How to Achieve Deterministic Code Performance Using a Cortex-M Cache Controller,” Technical Brief TB3186, 2019.





