Astree를 활용해 병렬 프로그램을 분석하는 방법에 대해 소개하고자 한다. 또한 차량 소프트웨어에 적용된 사례를 통해 Astree가 병렬 프로그램을 효율적으로 분석하는 방법에 대해서도 알아본다.
서론
임베디드 시스템에서 소프트웨어 비중이 지속적으로 커지고 안전에 중요한 기능 또한 소프트웨어로 구현되고 있다. 그렇지만 소프트웨어의 오류로 인한 시스템 오동작은 많은 비용과 인명피해까지 발생시킬 수 있다. 심각한 오류에는 소프트웨어 런타임 에러가 있으며, 데이터 경쟁(Data Race) 문제 및 소프트웨어의 병렬처리 상의 동기화 오류, 잘못된 포인터 사용, 산술 오버플로, 0 나눗셈 연산 수행 등이 있다.
특히 데이터 경쟁 및 병렬 소프트웨어의 동기화 오류 등 공유 자원에 대한 잘못된 접근문제는 멀티코어 애플리케이션에서 자주 발생하는 문제의 원인이 될 수 있다. 따라서 DO-178B, DO-178C, IEC 61508, ISO 26262 및 EN 50128 등 최신 국제 기능안전 표준에서는 이러한 잠재된 위험을 식별하고 소프트웨어 관련 안전 항목을 위반하지 않음을 입증하도록 하고 있다. 즉 소프트웨어 런타임 에러가 없음을 증명하기 위해서는 런타임 에러를 확인하고 제거해야 한다.
소프트웨어 런타임 에러를 제거하는데 가장 널리 사용되고 있는 방식은 정적 분석도구를 사용해 사전에 확인하는 것이다. 하지만 기존의 정적 분석도구들은 병렬 프로그램에서 발생할 수 있는 모든 프로세스의 인터리빙(상호연관성) 관계에 관한 분석을 고려하지 않았다. 따라서 병렬 프로그램에서 발생할 수 있는 데이터 경쟁 문제나 병렬처리 상의 동기화 오류 문제 같은 공유 자원의 잘못된 접근 문제를 검출하지 못하는 한계가 있다.
이 글에서는 Astree라는 솔루션을 활용해 병렬 프로그램을 분석하는 방법에 대해 간략하게 소개한다. 아울러 차량 소프트웨어에 적용된 사례를 통해 Astree가 병렬 프로그램을 효율적으로 분석하는 방법에 대해 알아본다.
병렬 프로그램 처리
일반적인 정적 분석도구는 순차 프로그램에 한해 분석이 가능했지만, Astree는 그 기능을 확장해 모든 인터리빙 가능성을 판단해 병렬적인 소프트웨어 동작을 분석한다. 다시 말해 기존 정적 분석도구의 런타임 에러 검출 항목에서 인터리빙 의미 분석이 추가된 것이다.
병렬 프로그램의 특징으로 순차적인 프로그램보다 훨씬 복잡한 제어 구조를 갖고 있어 전체 흐름에 대한 분석은 현실적이지 않다. 왜냐하면 병렬 소프트웨어에서는 인터리빙 가능성이 폭발적으로 증가하고, 인터리빙 가능성이 있는 코드의 위치마다 변수가 가질 수 있는 값을 판단하는데 많은 비용이 소요되기 때문이다. 그런 특징 때문에 기존 정적 분석도구에서는 병렬 프로그램을 분석하는데 어려움이 있다.
반면, Astree는 Thread 우선순위 정보를 입력 받아 추상화 과정에서 인터리빙 가능성을 간소화한다. 그리고 Task의 우선순위는 Priority Ceiling Protocol과 같은 동작에서 동적으로 변할 수 있는데, Astree는 운영체제에서 제공하는 실제 동기화 메커니즘을 모델링할 수 있도록 Mutex와 같은 개념이 포함돼 있다. 따라서 Astree는 인터리빙 가능성을 줄여 효율적으로 분석한다. 한 예로, Astree는 서로 다른 Thread에서 하나의 공유 메모리를 동시에 접근해 메모리를 Read/Write 또는 Write/Write로 접근하는 데이터 경쟁 문제를 검출할 수 있다. 그림 1은 Astree에서 검출한 데이터 경쟁 문제를 검출한 화면이다.
OS 모델링
프로그램이 OS 상에서 실행되는 경우, 시스템 라이브러리에 대한 함수 호출을 할 수 있다. 라이브러리를 사용하는 프로그램을 분석하는 방법으로는 분석 대상에 라이브러리 코드를 포함하여 분석하는 것이다. 하지만 이 방법은 소스코드가 없거나 Kernel 서비스에 영향을 받는 경우 어려울 수 있다.
그 대안으로 가상으로 그 기능을 구현하는 것이다. 이에 Astree는 ARINC 653, OSEK/AUTOSAR 및 POSIX thread에 대한 Stub 라이브러리를 제공한다. 애플리케이션과 Astree에서 제공하는 OSEK Stub 코드, OIL 파일로부터 자동 생성된 C 파일을 결합해 Astree에 의해 독립적으로 분석할 수 있는 애플리케이션을 손쉽게 얻을 수 있게 된다. 그림 2는 Astree에서 OSEK OS를 설정하는 화면이다.
Case Study
다음에서 설명하는 2개의 프로젝트는 별도의 추가 설정을 하지 않고 Astree의 기본 설정을 이용해 분석한 사례이다.
(1) 사례 A: 트럭 브레이크 시스템 개발
이 프로젝트에서는 ECU 전체 소프트웨어가 아닌 2개의 제어 컴포넌트와 1개의 Logic 컴포넌트 등 총 3개의 컴포넌트를 분석했다. 제어 컴포넌트 중 하나는 개발자가 직접 작성하고, 나머지 2개 컴포넌트는 dSPACE의 TargetLink에서 자동 생성한 코드이다. 프로젝트는 2개의 Task로 구성돼 있고 177,608 라인의 전처리 코드를 분석했다.
또한 애플리케이션 스케줄링 정보 설정을 위해 사용자가 번거롭게 스케줄링 정보를 입력할 필요 없이 OIL 파일의 정보를 Import하여 스케줄링 정보를 설정했다. 분석에 56분이 소요됐고 725 MB 메모리를 사용했다. Astree는 동기화 오류를 판단했고 공유 변수에 대한 올바른 변수 접근과 잘못된 변수 접근을 구분해 동시 접근 오류가 발생하는 변수에 대해서만 결함을 검출했다.
전체 1,041개 전역변수 중 14개 변수가 2개의 Task에서 공유되고 있었다. 그 중 4개의 변수에서 6개의 데이터 경쟁과 관련 있는 결함이 검출됐으며, 그 결함은 Read/Write 데이터 경쟁 문제였다. 검출된 모든 결함은 오검출이 아님을 확인했다.
(2) 사례 B: 차량 유류 탱크 제어 시스템 개발
이 프로젝트에서 차량 유류 탱크 제어 모듈은 AUTOSAR 3.2 기반으로 만들어졌으며 AUTOSAR 전체가 포함된 ECU 전체 코드를 분석했다. 애플리케이션 코드는 대부분이 TargetLink에서 생성됐지만(AUTOSAR Basic 소프트웨어가 아닌), 모듈(Device Driver)의 경우 직접 작성됐다. 2,854,057 라인의 전처리 코드가 분석됐으며 11개 Task, 13개 Interrupt 및 2개의 Counter가 존재했다. 두 번째 프로젝트 또한 OIL 파일의 정보를 Import 해 스케줄링 정보를 설정했다.
이 프로젝트에서는 설정 차이로 생길 수 있는 분석결과 차이를 확인하기 위해 3번의 서로 다른 설정을 하여 분석했다. 첫 번째는 Task 우선순위를 고려하지 않은 분석(B-1), 두 번째는 Dem/NvM 등 AUTOSAR 컴포넌트를 Stub 처리한 후 분석(B-2) 했다. 세 번째는 Task 우선순위를 고려해 분석(B-3) 했다. 아래의 결과는 Astree를 통해 분석된 데이터에 관한 설명이다.
① 분석방법 B-1
분석 결과 2,179개의 전역변수 중 1,329개의 변수가 공유되고 1,142개의 데이터 경쟁과 관련된 변수를 확인할 수 있었다. 분석시간 17시간 5분 동안 48.9 GB 메모리가 사용됐다. 총 1,142개의 데이터 경쟁과 관련된 변수에 대해 12,731개 동시 접근 문제가 검출됐는데, 8,839개는 Read/Write 동작 관련, 3,886개는 Write/Write 동작 관련 결함이었다. 추가적으로 OS 서비스의 잘못된 사용문제로 6개의 결함이 검출됐다. 3가지는 AUTOSAR API인 TerminateTask 또는 ChainTask가 실행되기 전 Task가 종료되는 결함이었고, 나머지 3가지는 일관되지 않은 자원 사용에 따른 결함이었다.
② 분석방법 B-2
AUTOSAR 컴포넌트 Stub 처리 후 분석을 진행했다. Stub 처리의 이유는 Astree(분석에 걸린 시간을 추적할 수 있게)가 각 함수별 시간 통계를 제공하는데 B-1 설정에서 얻은 분석 시간 정보를 통해 Dem과 NvM AUTOSAR 컴포넌트에서 많은 시간이 소요된 것을 확인할 수 있었기 때문이다. 따라서 AUTOSAR Stub 라이브러리에 추가로 Dem과 NvM 컴포넌트까지 Stub 처리를 했다. 그 결과 분석 시간은 약 70% 단축됐고, 총 메모리 사용량은 18.4 GB로 줄일 수 있었다. 하지만 첫 번째 설정과 검출된 결과 값은 유사하게 나온 것을 확인할 수 있다.
총 1,983개의 전역변수가 사용됐는데, 그 중 1,184개가 공유 변수였다. 다시 그 중에서도 1,044개의 변수가 데이터 경쟁 대상이 될 수 있었다. B-1 설정과 비교했을 때 보다 적은 양의 결함이 검출된 이유는 2가지가 있다. 우선, 전체 구현된 코드에서 Dem과 NvM 컴포넌트에 구현된 코드를 Stub으로 대체했기 때문이다. 그 결과 B-1 설정의 분석결과를 비교했을 때보다 적은 양의 결함이 검출된 것이다. 또한 Dem/NvM 컴포넌트가 호출하는 기능들이 호출되지 않아 결함이 검출될 수 있는 데이터 흐름을 분석하지 않았기 때문이다.
위 두 번의 분석결과를 비교해 보면 Dem/NvM 컴포넌트를 Stub으로 대체하면서 약간의 분석 결과 차이가 발생한다. 하지만 차이가 발생하는 것에 비해 분석 시간과 메모리 사용량이 크게 줄어든 것을 고려하면 개발 초기 단계에서 빠르게 결과를 확인하고자 할 때 사용할 수 있는 설정이 될 수 있다.
③ 분석방법 B-3
Stub 처리는 적용하지 않고 Task의 우선순위를 입력한 설정이다. Task 우선순위를 고려하지 않고 분석하는 것(B-1)은 모든 인터리빙을 고려하기 때문에, 분석은 완벽하지만 무의미한 데이터를 만들어 다수의 오검출을 발생시킬 수 있다. 따라서 Task의 우선순위 반영 및 Priority Ceiling Protocol을 반영한 동적으로 우선순위가 변하는 것을 설정했다.
보통 애플리케이션은 가장 우선순위가 높은 Task가 EEPROM에 데이터를 쓰고 이외의 낮은 우선순위를 가진 Task에서 읽기 동작만 이뤄진다. 스케줄러는 위에서 언급한 우선순위가 높은 초기화 Task를 Startup 단계에서 수행시키고 다른 Task에 의해 Interrupt 되지 않게 한다. 첫 번째 설정(우선순위를 입력하지 않은 설정)에서는 우선순위를 무시하기 때문에 모든 Task가 동시에 실행된다는 것을 가정하게 된다. 그에 따라 초기화 Task가 수행 중에도 다른 Task가 선점되는 것을 고려하기 때문에 공유 자원의 잘못된 접근 문제에 대한 오검출이 발생할 수 있다. 따라서 Astree에서는 오검출을 줄이면서 설명한 OS와 동일한 동작을 하기 위해 서로 다른 수행 단계를 제공한다.
첫 번째 단계는 초기화 Task만 수행한 후 StartOS를 호출한다. 이후에 ISR(Interrupt Service Routine)과 Task를 병렬로 수행하면서 인터리빙을 고려한 분석을 하게 된다.
B-3 설정으로 분석했을 때 16시간 24분간 42.7 GB 메모리 사용량을 보였다. B-2 설정과 비교하면 데이터 경쟁 관련 변수의 개수가 1,184개에서 215개로 약 80% 줄었다. 즉 우선순위를 입력함으로써 80%의 오검출 데이터가 확연히 줄어드는 결과를 확인할 수 있다.
결론
병렬 소프트웨어 아키텍처의 중요성이 커지면서 기존 방법과 달리 병렬 프로그램에서 발생할 수 있는 모든 프로세스의 인터리빙 관계를 파악하는 것이 중요해졌다. 그러나 엄청난 양의 인터리빙 관계 파악에는 오랜 시간이 걸린다. 하지만 Astree가 제공하는 다양한 방법을 활용함으로써 오류 검증과 분석 시간을 최소화시킬 수 있다. Task 우선순위 정보를 입력해 분석할 데이터양을 줄이거나, 분석시간이 오래 걸리는 컴포넌트를 Stub 처리해 공유 자원의 잘못된 접근 결함을 빠르게 확인할 수 있다. 이후 Stub을 제거해 전체 프로젝트에 대한 결함을 재확인하면 안전한 소프트웨어를 개발하는데 걸리는 시간을 최소화할 수 있다.
자동차, 의료, 국방/항공 소프트웨어의 경우 사람의 생명과 직결될 수 있기 때문에 안전한 소프트웨어를 개발하는 것은 매우 중요하다. 국제 기능안전 표준에서도 런타임 에러의 제거를 요구하므로 요구사항을 충족하기 위해서는 자동화된 도구를 필수적으로 사용해야 한다. 병렬 프로그램에 대해 효율적으로 분석하는 Astree를 활용한다면 개발에 소요되는 비용을 절감하면서 안전한 소프트웨어를 개발하는 데 도움이 될 것이다.
<저작권자 © AEM. 무단전재 및 재배포, AI학습 이용 금지>