Record & Replay 와 관련한 논문인 'Using Deterministic Replay for Debugging of Distributed Real-Time Systems' 을 나름대로 정리해봤다.
Abstract
Cyclic debugging 은 프로그램 개발에 있어서 가장 중요하고, 자주 사용되는 것 중에 하나다. cyclic debugging 중에 프로그램은 실패가 발생했을 때는 관찰하기 위해 반복적으로 재실행 되어진다. 이 과정은 프로그램 실행을 재생산하기 위해서 필요하다.
만일 할 수 없다면, real-time 시스템에서 breakpoint 나 single stepping 을 이용한 예전 debugging 기술을 적용하는 것은 임시적인 동작과 덜 디버기 동안에 실패를 관찰의 재생산으로 바뀐다.
따라서, 이 방법들은 real-time 시스템의 cyclic debugging 에 바로 적용할 수 없다.
이 논문에서 우리는 분산 real-time 시스템의 cyclic debugging 을 위한 새로운 software-base 의 방법을 설명할 것이다.
중요한 system event 를 on-line 으로 record 하고, off-line 에서 결정적인 replay 를 함으로서 우리는 real-time 시스템의 자세하게 real-time 동작을 보존하고 살펴볼 수 있다.
Introduction
테스팅은 시스템 명세의 오류를 런타임상에서 동작을 탐험함으로서 실패를 노출시키는 과정이다.
디버깅은 반면에 실패의 원인이 되는 에러를 노출시키는데 관계가 있다. 시스템의 상태가 에러의 실행은 예를 들면, 변수, 메모리 등에 의해서, 그리고 마침내 감염된 상태를 출력해낸다. 디버깅의 과정은 그래서 에러가 발생하기전까지 따라가는 것이다. 에러를 노출시키기 위하여, 실패를 반복하여 재생산해야 한다. 이 것은 시작 상태와 결정적 실행의 지식이 수반되어야 한다. real-time 의 필요성이 없는 순차적인 소프트웨어를 위해서는 실패를 재생산하기 위해서 같은 입력과 같은 내부 상태를 적용하면 된다.
분산 real-time 소프트웨어에서는 타이밍과 이벤트 때문에 좀더 복잡하다. 순차적 프로그램 디버깅에서 분산 real-time 프로그램 디버깅으로 옮겨가면서 몇가지 문제점들이 해결되었다. 우리는 3 가지 단계의 변화를 만듬으로서 주요 이슈에 대해서 간단히 토론할 것이다.
Debugging sequential real-time programs
순차적인 non real-time 프로그램 디버깅에서 순차적인 real-time 프로그램으로 옮겨 오면서, 외부 프로세스와의 상호 통신이 일시적으로 제한되었다.
이 뜻은 breakpoint 와 single-stepping 과 같은 고전적인 디버깅은 외부 프로세스를 시간에 재생산 하도록 직접적으로 적용하는 것은 불가능하다는 것이다.
마찬가지로 디버거를 사용함으로서, 프로그램이 실행될 때(센서의 값을 읽고, local real-time clock) 시간에 의존적인 시스템의 입력을 직접적으로 재생산할 수 없다. 이 방법은 디버깅 도중에 정확하고 결정적으로 상호 연동하면서 재생산되어져야 한다.
Debugging multi-tasking real-time programs
순차적 real-time 프로그램 디버깅에서 멀티 태스킹 real-time 프로그램 디버깅으로 옮겨오면서, 이것을 하나의 프로세서 상에서 실행할 때 태스크 간에 인터리빙을 위한 방법이 필요하다. 우선권, 인터럽트 그리고 임계영역에 접근하는 것을 추적하는 것이 필요하다.
우리는 실행하는 태스크들 간에 상호 연동과 동기화를 재생산하기 위한 방법을 가지고 있어야 한다.
태스크들 간의 집합을 재생산하는 것은 Tei 라는 사람에 의해서 보호되어졌다. 특별한 하드웨어를 사용함으로서 인터럽트와 태스크 스위칭을 재생산 할 수 있었다. 특별한 하드웨어와 소프트웨어를 사용함으로서 인터럽트와 태스크 스위칭을 재생산하는 것은 Dodd 라는 사람에 의해서 보호되어졌다.
그러나, 두 사람이 사용한 방법은 특별한 하드웨어와 profiling 툴에 의존적이고, 매우 유용하게 실행적이지 못하다.
그들은 또한 분산된 real-time 시스템의 디버깅을 지원하는 데 부족했다.
Debugging of distributed real-time systems
single 노드 real-time 시스템 디버깅에서 분산된 real-time 시스템 디버깅으로의 변화는 정확히 같은 시간에 다른 노드들 상에서 break-pointing 태스크들과 다른 노드들의 관찰을 연관시키는 추가적인 문제가 발생하게 된다.
분산된 breakpoint 를 실행하기 위해서는 우리는 하나의 노드에서 다른 노드들로 stop 또는 continue 메세지를 보내야할 필요가 있다.
또는 실행이 멈추거나 resume 될때, 우리는 직후의 시간을 동의할(동기화할) 필요가 있다. 논문에서는 완벽한 동기화된 clock 의 부족에 의해 복잡하게 되었다.
이것은 우리는 태스크들이 정확히 같은 시간에 halt 되거나 resume 되는 것을 안전하게 할 수 없다. 따라서, 다른 방법이 필요하다.
Debugging by deterministic replay
우리는 이 논문에서 결정적인 replay 기반의 소프트웨어 기반 디버깅 기술에 대해서 설명할 것이다. 런타임 시에 중요한 이벤트를 record 하고, 오프라인에 시스템의 행동을 재생산하고 검사한다. 검사는 record 된 이벤트를 좀 더 자세하게 할 수 있다. 예를 들면, 태스크에 실제적인 입력을 record 함으로서 우리는 디버거를 사용하고 record 된 것보다 더 자세한 단계까지 내부의 동작을 검사함으로서 오프라인에 태스크를 재실행할 수 있다.
결정적인 replay 는 발견된 실패의 원인이 되는 에러를 추적하는 데 유용하다. 그러나 오직 record 된 실행을 재실행하는 것 이래로 프로그램의 수행을 추론적인 조사에 대해서는 적당하지 않다.
우리는 single 태스킹, 멀티 태스킹, 분산 real-time 시스템의 결정적 재실행을 채택했다. 모든 동기화, 스케줄링, 서로 통신하는 이벤트들, 외부 프로세스와 통신하는 것이 포함된 것을 record 함으로서 실제 실시간으로 수행되지 않고도 그리고 탐침효과 없이 오프라인에서 검사할 수 있다.
탐침 효과는 관찰에 의해서 동요된 시스템의 상대적인 타이밍에서 발생한다. 예를 들면, 관찰을 용이하게 하기 위한 breakpoint.
우리는 그래서 태스크 실행, 태스크 스위칭, 인터럽트 방해 그리고 시스템 동작을 반복적으로 결정적인 재실행을 할 수 있다.
이것은 또한 범용적인 동기화된 시간을 기반으로한 분산된 real-time 시스템을 규모로 한다. 만일 노드 사이의 모든 상호작용을 모두 record 한다면, 우리는 각 노드을 지역적으로 결정적으로 재생산할 수 있고 그리고 다른 노드들 상의 일치하는 record 된 이벤트를 범용적으로 서로 관련시킨다.
Contribution
이 논문의 contribution 은 real-time 시스템을 디버깅하기 위한 방법이다. 우리의 지식은
- single 태스킹과 멀티 태스킹 real-time 시스템의 결정적인 디버깅을 위한 소프트웨어 기반의 방법
- 분산 real-time 시스템의 결정적인 디버깅을 위한 방법
위와 같다. 섹션 2 에서는 우리의 시스템 모델을 설명하고, 섹션 3 에서는 real-time 시스템 디버깅을 위한 방법을 설명한다. 섹션 4 에서는 방법을 묘사하는 간단한 예제를 제공한다. 섹션 5 에서는 결정적인 재실행에 관련한 일반적인 이슈에 대해서 논의한다. 섹션 6 에서는 관련 연구를 설명한다. 섹션 7 에서는 우리는 어떤 힌트와 앞으로의 연구에 대해서 결론을 내릴 것이다.
The System Model
우리는 노드들의 집합으로 분산 시스템이 이루어졌다고 가정한다. 각 노드들은 CPU, 메모리, 네트워크, local clock, i/o 유닛, 외부 프로세스의 발동을 가지고 스스로 효율적인 컴퓨팅 요소를 가지고 있다. 우리는 기호 'Q
' 로 알고 있는 전역 동기화된 시간이 존재한다고 가정한다. 그리고 이것은 시스템의 2 개의 노드도 'Q
' 이상에 의해 달라지지 않도록 한다.
소프트웨어는 인터럽트 루틴과 동시의 태스크 집합 그리고 메세지 패싱이나 공유 메모리를 통한 통신으로 구성된 분산된 시스템 상에서 동작한다.
태스크와 인터럽트는 우선권, 메세지 패싱과 공유 메모리 때문에 기능적이고 임시적인 부가적인 작용을 가질 수도 있다.
우리는 우선적인 스케줄링을 지원하는 런타임 real-time 커널을 가정한다. 그리고 커널은 태스크 시작, 우선권, 회수, 종료와 그림 1 에서 보여주는 것과 같이 real-time clock 을 접근하여 record 하는 것과 같이 중요한 시스템 이벤트들을 record 하는 메커니즘을 가진다.
모니터링의 세부는 우선권, 인터럽트 방해가 결정될 수 있는 정확한 발생의 레벨을 간파할 수 있다. 예를 들면, 이벤트가 발생한 곳의 PC 값을 record 한다. 모든 이벤트는 또한 local real-time clock 에 따라 타임 스탬프 될 수 있다.
우리는 장차 프로그래머가 record 하느 것을 정의할 수 있는 것을 지원하는 run-time 커널에 의해서 record 메커니즘을 제어할 수 있는 것을 요구한다.
이것은 i/o 오퍼레이션, local state, real-time clock 의 접근, 메세지 수신, 공유 데이터의 접근을 record 하기 위한 시스템 콜이다.
모든 모니터링 메커니즘이 real-time kernel 안에 있던지 또는 태스크 안에 존재할 때, 만일 그것들이 타겟시스템에서 지워진다면, 탐침효과가 발생할 것이다. 이 때문에 잠재적으로 새롭고 테스트 되지 않은 동작을 유도한다.
프로브는 그러므로 타겟 시스템에 남는다. 그 결과로서 프로브를 위해 자원을 할당하고 프로세스를 디자인하는 것을 일찍 모니터링하는 것을 본질적으로 고려해야 한다. 따라서 모니터링을 설계 과정의 초기에 고려하고, 리소스를 프로브에 할당하는 것은 본질적이라고 할 수 있다.
우리는 real-time 커널의 오프라인 버전을 가지는 것을 가정한다(그림 2). real-time clock 과 스케줄링은 비활성화된다. 오프라인 커널은 보통의 디버거가 모든 record 된 중요한 시스템 이벤트를 재실행 할 수 있는 것을 지원한다. 이것은 record 되는 순서의 시작한 태스크, 태스크 스위칭이 발생하는 것, 인터럽트 방해의 반복 의 PC 값을 record 한 것을 포함한다. replay scheme 는 또한 local clock 에 접근하는 것, i/o 에 읽고 쓰는 것, record 된 값에 의해 제공되는 공유 데이터를 접근하는 것을 재생산 한다.
Real-time systems debugging
우리는 현재 결정적 재실행을 달성하기 위한 우리의 방법을 자세히 논의하고 설명할 것이다. 우리는 real-time 제약이 있는 순차적 소프트웨어, 그리고 멀티 태스킹 real-time 시스템, 그리고 분산 멀티태스킹 real-time 시스템을 제어하기위한 우리의 솔루션을 제공함으로서 구조의 소개와 시작을 할 것이다.
Debugging single task real-time systems
real-time 제약이 있는 순차적 소프트웨어의 디버깅은 환경이 아직도 이행됨으로서 임시적인 요구를 강요하는 것을 수행한다.
real-time 제약이 있는 순차적 소프트웨어의 디버깅은 디버깅이 수행되었던 환경에서 수행되는 것을 요구한다.
이 의미는 처음 소개에서 언급했듯이 breakpoint 와 single-stepping 의 전통적인 디버깅은 직접적으로 적용할 수 없다. 출력과 입력의 시기적절한 재생산이 무효로 만듬으로 부터.
그러나, 만일 우리가 순차적인 프로그램의 실행에서 중요한 이벤트를 확인하고 record 한다면, 예를 들면 외부 프로세스로 부터의 읽은 값, local clock 의 접근, 그리고 외부 프로세스의 출력을 순서대로 정리한다.
그러나, 만일 외부 프로세서로 부터의 읽은 값, local clock 의 접근 그리고 외부 프로세스의 출력같은 순차적인 프로그램의 실행에서 중요한 이벤트를 기록하면, 우리는 그것들에 주문(명령)을 내릴 수 있다.
local clock 과 이벤트(읽은 값)의 내용을 record 하는 것과 발생한 시간과 함께 모든 이벤트를 정렬함으로서 우리는 시기적절한 방법을 오프라인상에서 재생산할 수 있다.
이것은 디버깅하는 동안 실제적인 읽은 값을 record 된 값으로 대신함으로서 'short-circuit' 모든 이벤트들은 하나로 대응(일치)시킨다.
우리의 방법은 외부 프로세서의 시뮬레이터를 사용하는 것과 디버그하는 시스템의 시뮬레이터 시간을 동기화 하는 것이다.
그러나 만일 우리가 이미 실패의 원인을 output 으로 확인했디면 시뮬레이션은 요구되지 않는다.
Debugging multitasking real-time systems
멀티 태스킹 real-time 시스템을 디버깅하기 위해서는 single 태스크 real-time 시스템에서 record 하는 것에 더해서, 추가적으로 태스크의 인터리빙을 record 할 필요가 있다.
우리는 콘트롤의 이동을 record 해야 한다. 전송의 시간과 위치를 확인하기 위해서는 우리는 반드시 각 전송 이벤트에 할당된 타임 스탬프, PC 값을 record 해야만 한다.
디버깅 동안에 런타임 동작을 재생산하기 위해서는 모든 입출력을 record 된 값으로 바꾸고 모든 태스크에 콘트롤 전송이 발생한 곳의 PC 값에 trap(트랩) 호출을 추가시킨다.
트랩 호출은 오프라인 커널에서 수행되고, 이 오프라인 커널은 리얼 타임 커널의 모든 기능을 가지지만 그러나 콘트롤의 모든 전송, 임계영역의 모든 접근, 높은 우선 순위 태스크의 모든 해제, 그리고 인터럽트에 의한 모든 우선권은 record 한 것에 의해서 지시를 받는다.
프로세스간 통신은 그러나 런타임 커널로서 제어된다. 그것은 프로그램 코드를 재실행함으로서 그것을 결정적으로 재생산할 수 있다.
그림 3 은 태스크 a,b,c 가 스케줄 된다. 우리는 a 가 태스크 b, c 에 의해 선점당한다.
디버깅 되는 동안 이 시나리오는 A`s PC=x 와 PC=y 때의 커널을 호출하는 task A 의 도구를 이용해서 재생산할 수 있다.
위 이론은 우리가 루프나 재구호출, 실행되는 복수의 시간에 같은 PC 값을 가지는 구조, 따라서 PC 값은 유일한 프로그램 상태를 정의할 수 없다는 것을 단순화한 일부분이다. 이것은 만일 타겟 프로세서가 명령어또는 사이클 카운터를 지원한다면 완화시킬 수 있다. PC 는 유일한 상태를 정의한 어떤 카운터와 함께 쓰일 것이다. 그러나 이 하드웨어의 특징이 상업적인 임베디드 마이크로콘트롤러에서 일반적이지 않은 관계로 우리는 다음의 대체 접근을 사용할 것 이다.
PC 를 단지 저장하는 것 대신에 우리는 컨텍스트 스위치, CPU 레지스터(주소와 데이터), 뿐만 아니라 선점된 태스크의 속하는 스택과 프로그램 카운터에 레지스터에 의한 모든 정보를 저장한다. 전체의 저장된 컨텍스트는 선점된 프로그램을 위한 유일한 marker 로서 사용될 수 있다. 프로그램 카운터와 스택 레지스터의 내용은 재귀호출 사이에서도 차이를 위해서 충분하다.
루프에서 이 방법은 유일한 상태을 확인하는 것을 보장하지 않는다. 이론상으로 루프는 레지스터를 바꾸지 않기 때문에. 그러나 대부분의 현실적인 프로그램 컨텍스트는 PC 와 함께 유일한 상태를 정의할 것이다. 어찌되었건, replay 동안에 있음직하지 않은 상황에서 구별할 수 없는 컨텍스트 때문에 선점된 루프의 잘못된 반복을 가지면, replay 의 행동(기능)은 record 된 것과 다를 것이다. 그러므로 발견할 수 있다. 또는 만일 동일하다면 그것은 중요하지 않다.
어떤 멀티 태스킹 커널이라도 다시 시작하기 위해서 중지된 태스크를 컨텍스트를 반드시 저장한다. 그리고 재실행을 위한 record 을 하는 과정에서 우리는 반드시 추가적인 시간의 컨텍스트를 저장해야 한다. 이 오버헤드를 제거하기 위해서 우리는 커널에 recording 으로 부터 중단된 태스크의 모든 컨텍스트를 저장하고 복원할 수 있다. 대신에 우리는 한때 컨텍스트를 저장해야 한다.
우리의 방법은 특별한 하드웨어 명령 카운터의 필요를 없앴다. real-time 커널 상에서 다른 추가적인 record 매커니즘이 요구되지 않는다.
만일 그럼에도 불구하고, 타겟 프로세서에 명령 카운터나 사이클 카운터를 가지고 있다면 그것들을 record 되는 컨텍스트안에 그리고 유일한 상태를 쉽게 보장할 수 있다.
record 된 이벤트 히스토리의 재실행을 활성화 시키기 위해서는 모든 record 된 PC 값에 오프라인 커널에 트랩호출을 추가한다.
replay 하는 동안 그 결과로서 루프안에 레코드된 PC 값의 커널로의 많은 횟수의 호출을 가진다. 그러나 커널은 레코드된 것으로부터 다른 컨텍스트를 위한 행동은 하지 않을 것이다.
루프 실행의 계속 정보를 얻는 접근방법은 어셈블리 코드에서 뒤쪽(backward) 분기와 서브루틴 호출을 카운트하는 소프트웨어 명령 카운터를 이용하는 것이다. 그러나 이 방법은 어셈블리 코드와 장치를 통한 모든 뒤쪽(backward) 분기를 스캔하는 타겟 특정의 도구를 필요로 한다.
이 방법은 보통 하나 이상의 CPU 레지스터를 명령 카운터로 사용되고, 그러므로 컴파일러 최적화에 대한 가능성을 줄이는 이래로 성능에 영향을 미친다.
Debugging distributed real-time systems
우리는 어떻게 local record 를 결정적인 분산 재실행에서 달성할 수 있는지 보여줄 것이다. 기본 생각은 클럭 동기화의 정확도를 local 타임 스탬프와 서로 연관시키는 것이다. 이것은 다른 노드들 상에서 record 하는 것을 연관시키는 것을 허락할 것이다. i/o 샘플링과 프로세스 간의 통신 같은 중요한 이벤트를 record 하게끔 디자인함으로서 다른 노드들로 부터 메세지의 도착 시간과 각 노드의 내용을 record 할 수 있다.
메세지의 record 하는 것은 그러므로 동시에 전체의 시스템을 재실행없이 시스템의 다른 노드들과 교환하는 어느 한 시간에 하나의 노드를 locally replay 가 가능하다.
모든 이벤트의 타임 스탬프는 분산 real-time 시스템을 디버깅할 수 있고, 시스템에서 모든 record 되고 재 계산된 이벤트를 시각화해준다.
양자택일로 record 되는 정보의 양을 줄이기 위해서, 우리는 오프라인에서 노드들 사이의 통신을 재실행할 수 있다.
그러나 노드들 간의 모든 통신을 현명한 순서로 동기화 시키는 것이 필요하다. 빠른 노드가 느린 노드가 따라 붙을 때까지 기다리는 것.
이것은 몇 대의 노드를 사용해서 정말로 동시에 실행할 수 있거나, 동일한 노드들의 세트를 위해 싱글 노드 상에서 에뮬레이트 될 수 있다.
Global states
시스템에서 관련있는 관찰을 위해서는 순서에 대해서 알 필요가 있다. 예를 들면, 관찰이 동시에 발생할 때, 앞서고, 특별한 이벤트가 계속될 때.
single 노드 시스템 또는 문제가 되지 않는 공통의 클럭을 가지는 단단한 멀티 프로세서 시스템은 문제가 되지 않는다. 분산 시스템은 공통의 클럭이 없기 때문에 중요한 문제이다. 각 노드의 순서 정렬은 local 클럭을 사용함으로서 확정된다. 그러나 어떻게 관련된 노드들 사이에서 관찰할 것인가?
한가지 방법은 관찰된 이벤트들 사이의 원인의 순서를 확립하는 것이다. 예를 들면, 노드들 사이의 메세지를 보내는 것으로 부터 유래된 local 클럭을 이용함으로서. 그러나 만일 공통의 외부 프로세스를 작업하는 다른 노드상의 태스크라면, 메세지의 주고 받음 없이, 또는 중요한 관찰된 이벤트들이 지속될 때, 이것은 확실한 방법이 아니다. 그런 경우에 시스템에서 관찰된 이벤트의 총 순서를 확립할 필요가 있다. 이것은 동기화된 global time base 형태로 달성할 수 있다. 이것은 어떤 2 개의 노드도 local 클럭이 Q 이상으로 틀리도록 하지 않는 것을 의미하는 Q 를 모든 local 클럭을 동기화시키게 둔다.
그림 4 는 3 대의 분산된 노드의 local tick 을 나타낸다. 모든 tick rate 는 'ㅠ
' 이고 동기화 되는 부분은 Q 이다.
Q 가 읽는(reading) 클럭의 에러 마진(범위)를 알려주기 때문에 어떤 것도 Q 가 ㅠ 보다 크지 않다.
그러므로 Q 가 ㅠ 보다 크거나 같은 것은 동기화된 local tick 이 발생할지도 모르는 동안에 Q 인터벌의 오버랩을 가져올 것이다.
그림 5 는 3 대의 모든 노드가 관찰할 수 있는 2 개의 외부 이벤트와 그들의 타임 스탬프를 나타내고 있다.
부족한 시간 기준과 Q 때문에, global time base 의 정확성 Q 를 아직 준수하는 동안 우리는 1 time unit 에 의해 다른 같은 이벤트의 타임스탬프와 더불어 끝난다.
이 뜻은 다른 노드가 별개의 타임 스탬프를 같은 이벤트에 할당할 때, 어떤 노드들은 동시에 발생하는 이벤트(예를 들면, 동일한 타임스탬프를 가지는)를 고려해야만 한다는 것이다.
그림 5 에서 각각 노드 1 과 3 에서 이벤트 2 와 1 이 차이를 가지는 동안, 노드 2는 이벤트 e1 과 e2 에 동일한 타임 스탬프를 줄 것이다.
이것은 오직 2ㅠ 이상으로 분리된 이벤트들은 전체적으로 정렬될 수 있다.
A small example
우리는 이제 어떻게 전체의 record 하는 것과 재실행하는 것의 예제를 보여줄 것이다. 그림 6 과 같이 태스크 A,B,C,D 가 있다.
태스트 A,B 그리고 D 는 기능적으로 관련이 있고, 정보를 교환한다. 태스크 A 는 A/D 컨버터를 거쳐 외부 프로세스를 시험한다. 태스크 B 는 태스크 D 로 부터 예전에 받은 메세지를 계산하여 수행하고, 그리고 태스크 D 는 A/D 값과 B 로부터의 메세지를 프로세싱하여 받는다. 그 결과로서, D 는 새로운 메세지를 B 로 보낸다. 태스크 C 는 다른 태스크들과 연관이 없다. 그러나 확실히 드문 경우에 B 를 선점한다. 예를 들면, 그림 7 과 같이 B 가 인터럽트 간섭을 영향받기 쉬운때에.
그러나 태스크 C 와 B 는 양쪽 프로그래밍 실수로 인해서 다 재진입을 하지 않게 만드는 함수를 사용한다. 이 함수는 B 가 실패가 되는 원인이다. 결과적으로 에러 메세지를 D 에게 보낸다. 외부 프로세스에 오류 명령어를 차례로 적용시킨다. 실패한다.
인터럽트 Q 가 B 를 hit 하면, B 의 완료 시간은 지연된다. B 의 경우에 Q 가 원인으로 C 에 의해서 선점되고, 그러므로 잘못된 재진입 되지 않는 함수에 의해서 오염되게 된다. 이 드문 시나리오는 실패의 원인이 된다. 지금, 이 실패를 발견하고, 에러를 추적하기를 원한다고 가정한다.
- 우리는 0 ~ 16 의 시간동안 record 전송 제어를 한다.
- Task A 가 time 0 에 시작한다.
- Task A 가 time 2 에 정지한다.
- Task B 가 time 4 에 시작한다.
- 인터럽트 Q 가 time 6 에 시작하고, Task B 를 선점한다.(이때 PC=X)
- 인터럽트는 time 6.5 에 정지한다.
- Task B 는 time 6.5 에 다시 시작한다.(이때 PC=X)
- Task C 는 time 8 에 시작하고, Task B 를 선점한다.(이때 PC=Y)
- Task C 는 time 10 에 정지한다.
- Task B 는 time 10 에 다시 시작한다.(이때 PC=Y)
- Task B 는 time 10.3 에 정지한다.
- Task D 는 time 14 에 시작한다.
- Task D 는 time 16 에 정지한다.
data record 는 다음과 같다.
- Task A 는 time 1 에서, read_ad() 함수 리턴 값 : 234
- Task B 는 time 4 에서, D 로 부터 메세지를 받은 값 : 78
디버깅 하는 동안 모든 태크스들은 종료될 때, 오프라인 커널에 호출하기 위해서 설치되고, 선점된 태스크 B 와 C 는 그들이 PC 값이 record 될 때 오프라인 커널에 호출하기 위해 설치된다.
태스크 A 의 접근하는 read_ad() 함수는 짧게 순회하고, 적은 리소스를 소비한다. record 된 값 대신에.
태스크 B 는 시작에 태스크 D 로 부터 메세지를 알아 듣는다. 그리고 그것은 time 0 에 이전에 record 한다.
A 와 B 에서 C 로 전송되는 메세지는 온라인 커널에서의 같은 방법으로 오프라인 커널에서 수행된다. 프로그래머/분석사는 breakpoint, single step 그리고 태스크의 콘트롤과 데이터 플로우를 면밀히 살핀다. 에러를 찾는 것을 추적하는데 보기에 적합하도록.
재실행 메커니즘은 모든 어떤 탐침효과의 원인이 되지 않는 시스템 디버깅의 real-time 동작에 속하는 중요한 이벤트들을 재생산한다.
예제에서 모아지는 것에 따라서 record 되었던 것을 재실행하는 것은 꽤 공정할 수 있다.
에러는 태스크와 인터럽트를 반복적으로 정확히 인터리빙을 재생산하기 때문에 추적할 수 있다. 실패를 재생산하는 것의 종류의 예제는 실행하기가 매우 어렵다는 경험을 가지고 있다.
결정적인 재실행 매커니즘은 매우 귀중한 도구이다.
Discussion
Schutz 라는 사람은 일반적으로 결정적인 재실행에 대해서 3 가지 주장을 가진다. 이에 대한 코맨트이다.
주장 1 : 단지 이전에 관찰되엇던 것을 재실행 할수 있다. 그리고 어떤 보증이 아니더라도 모든 중요한 시스템 동작은 정확히 관찰되어 제공되어야 한다.
요청된 필요로하는 정보의 양은 물론 디자인 이슈이고, 모든 입력과 중개자 메세지를 반드시 record 해야 한다는 것은 사실이 아니다. 재실행은 실질적으로 record 된 이벤트 히스토리에 있는 태스크를 재실행하는 것을 보여줌으로서 수행한다. 오직 그것들의 입력과 메세지는 재계산되어지지 않거나, 재전송되지 않고 재실행하는 동안 유지된다. 이것은 특히 주기적인 태스크, 우리가 스케줄(우선순위 관계)에 관한 지식의 사용을 할 수 있는 곳과 자신이 스케줄을 되풀이 하기 전에 지속하는 것을 할 수 있다. (LCM - 가장 적은 공통 태스크 주기 시간)
이전에 사용된 결정적인 재실행 시스템 예를 들면, 분산 시스템과 병렬 프로그래밍(ADA) 는 이런 경우가 아니다. 제한과 확률, RTS 가 스케줄되는 고유한 재실행 하는 동안 record 된 데이터는 재계산하지 않아도 됨으로서 좋은 이점을 준다.
주장 2 : 만일 프로그램이 수정되었을 때, 예전 history 가 아직도 유효하다고 보증할 수 없다.
만일 프로그램이 수정되면, 태스크들 사이의 타이밍이 바뀌고, record 된 히스토리는 유효하지 않게 된다. 타이밍의 차이는 데이터 플로우가 변경되거나, 수정된 태스크의 실제적인 실행시간이 바뀌는 것으로 부터 막는다. 그런 경우 새로이 record 를 해야한다. 그러나 실제적으로 순차적 이벤트를 record 하는 것의 확률은 아주 낮다.
일찍 설명 됨으로서, 일반적인 디버깅과 결정적인 재실행은 특히 시스템 동작의 이론적인 조사에 알맞지 않다. 15, 16 에서 설명되는 것으로 이것은 복귀 테스트를 위한 이슈다.
주장 3 : record 은 오직 같은 하드웨어 상에서만 replay 되는가
이벤트 히스토리는 오직 타겟 하드웨어에서 재실행 된다. 이것은 어떤 범위에서만 가능하다. 만일 원격 디버깅을 사용한다면, 문제가 되지 않는다.
만일 타겟 CPU 의 명령어 셋을 실행할 수 있는 하드웨어 시뮬레이터를 가지고 있다면, 호스트 컴퓨터에서 재실행이 가능하다.
다른 가능성으로는 정확한 기계 코드 명령을 재실행하기 보다는 오히려 태스크 스위칭이나 인터럽트가 발생했을 때 하이레벨 언어의 실제 상태를 확인할 수 있다. 이러한 진행은 기계에 의존적이다. 그러나 후자의 경우에 우리는 루프의 반복에서 구별할 때 유일한 상태를 정의할 수 있는 문제를 만난다.
Related work
글에서 결정적인 재실행 매커니즘(real-time 시스템과 관련한)의 몇가지 설명이다.
- 동시적인 Ada 프로그램을 위한 결정적 재실행 방법은 Tai 라는 사람에 의해서 설명되었다. 입력 X 와 동시 프로그램 P 를 위한 동기화 순서를 기록한다. 소스 코드는 재실행을 용이하게 하기 위해 수정했다.; 랑데부를 강요한다. 입력 X 의 같은 동기화 순서를 따라간다. 이 방법은 동시에 발생하는 Ada 프로그램을 위해 동기화 순서를 재생산할 수 있다. 그러나 중요한 이벤트 사이에 특별한 동기화 순서의 실행(코드가 바뀌는 것)은 엄청난 프로브효과를 발생시킨다. replay 계획은 실시간 시스템에 적합하지 않다. 둘다 선점한 태스크에 의해 불필요한 부작용이 있다. 요소를 위한 선점 또는 인터럽트 허용하지 않는다. replay 된다. 어떻게 외부의 인터럽트를 콘트롤하는지, 그리고 어떻게 분산된 환경에서 그것을 사용하는지 잘 나와있지 않다.
- Tsai 는 최근에 실시간 단일 프로세서들을 위한 하드웨어 모니터링과 replay 매커니즘을 만들었다. 그것의 방법은 순서, 접근시간, 비동기적 인터럽트를 고려한 중요한 이벤트를 replay 할 수 있다. 동기는 최소한의 프로브 효과와 그에 의한 실시간 시스템을 위해 적당하게 만들기 위함이다. 비록 그것이 최소한의 프로브효과 가질지라도, 오버헤드를 예측할 수 없다. 그것의 이중 모니터링 프로세싱 유닛이 모든 이벤트를 모니터하기 위한 인터럽트를 만듬으로서 타겟 시스템 상에서 예측할 수 없는 방해(간섭)의 원인이 되기 때문이다. 그것들은 또한 지나치게 자세한 타겟 프로세서의 실행을 record 한다. 예를 들면, 68000 모토로라 프로세서의 6 byte 정도 AND 명령어에 265 byte 의 데이터를 record 한다. 만일 타겟 CPU 가 hardware instruction counter 전용이었다면, 이방법은 오직 비동기적인 인터럽트만 재생산 할 수 있다. 사용되는 하드웨어 접근법은 원래의 타겟에 특별하고, 그리고 다른 시스템에서 채택하기 힘들다. 시스템은 싱글 프로세서 시스템들과 분산 실시간 시스템을 지원하지 않은 것을 위해 만들어졌다.
- 소프트웨어 기반의 HMON 방법은 분산 실시간 멀티프로세서 아키텍처를 위해 만들어졌다. 범용(다목적) 프로세서는 각 멀티프로세서 상에서 모니터링하기 위함이다. 모니터는 공유된 메모리를 통해서 타겟 프로세서를 관찰할 수 있다. 타겟 시스템 소프트웨어는 모니터링 루틴을 설치함으로서, 시스템 서비스 호출(시스템콜), 인터럽트 서비스 루틴을 수정하고 태스크 스위칭을 모니터링하기 위한 PSOS 실시간 커널의 특징을 사용한다. 공유된 변수 참조는 또한 모니터링되고, 프로그래머는 특별한 이벤트를 프로그램에 정의할 수 있다. record 된 이벤트는 debugger 에 의해 오프라인에서 replay 될 수 있다. 이와 대조를 이루어 instruction counter 를 지원하는 하드웨어는 Tsai 에 의해 사용되어 졌다. 그들은 소프트웨어 기반의 instruction counter 를 사용했다. 프로그램 카운터와 함께, 소프트웨어 instruction counter 는 태스크 상에서 인터럽트 간섭을 재생산하기 위해 사용될 수 있다. 논문에서는 이 문제(이슈)에 대해서 고심하지 않았다. record 된 이벤트 히스토리를 사용함으로서, 오프라인 디버거는 실시간 동안 같은 머신 코드 명령어에 인터럽트와 태스크 스위칭이 발생할 때까지 실행한다. 인터럽트 발생은 record 된 프로그램 카운터 값에 trap 명령어를 추가함으로서 오프라인상에서 보장될 수 있다. 논문에서는 어떻게 모순이 없는 global state 를 만드는지에 대한 정보가 없다. 다시말해, 다른 노드들 상에서 어떻게 이벤트를 record 하는지 각각의 관련된 모순없이. 그들은 그들의 방법이 분산 실시간 시스템에 적당하다고 주장한다. global time, clock 동기화, 이벤트의 순서에 관한 의논의 부족은 다른 흥미로운 접근을 줄였다. 그들의 기본 가정은 멀티 프로세서 노드로 이루어진 분산된 시스템이 그들의 소프트웨어 접근이 덜 범용적이라는 것이다. 사실, 그것은 하드웨어적 접근이다. 그들의 타겟 아키텍처가 공유된 메모리 멀티프로세서이고, 그리고 그들의 간섭하지 않는 기본 가정이 이 공유된 메모리 기반이었다. 그래서 분산된 단일 프로세서에는 적용할 수 없기 때문이다.
Conclusions
분산 real-time 시스템에서 결정적인 디버깅을 위한 방법을 설명했다. 이 방법은 중요한 시스템 이벤트의 타이밍과 발생하는 것을 온라인상에서 record 하기 위해 설치된 커널에 의존한다. record 하는 것은 특별한 디버깅 커널을 사용하고, record 된 실행의 기능적이고 임시적인 동작을 충실히 재생산하기 위해 오프라인에 재실행된다. breakpoint 을 사용하는 표준적인 디버깅을 허용한다.
극적으로 증가된 디버깅 능력의 비용은 애플리케이션 코드에 설치됨으로서 그리고 커널에 설치됨으로서 오버헤드를 야기시킨다.
탐침효과를 줄이기 위해서는 설치를 전개된 시스템에 남아있어야 한다. 우리는 그러나 많은 애플리케이션에서 이것이 정당한 벌금이라는 것을 확신하고 있다.
우리는 현재 설명한 디버깅 방법의 실험을 위한 실험적인 커널을 만들고 있다. 그러나 또한 결정적인 재실행을 지원하는 현존하는 real-time 커널의 수정을 조사하고 있다.
논문에서 중요한 점
발표를 하면서, 중요한 쟁점이 된 사안들을 정리한다.
- 재귀호출이나 루프에서 타임스탬프와 PC 값으로도 충분히 유일한 marker 를 만들 수 있지 않나?
일반적으로 생각할 때는 두 개만으로도 가능할 것 같지만, 타임스탬프의 단위(예를 들면, ms 인지 ns 인지)에 의해서 세밀한 순간을 기록할 수 없는 경우에는 불가능하다. 논문 상에서 이에 대한 언급은 없었지만, 중요하게 고려해야할 사항이다.
전체적으로 멀티 태스킹 또는 분산 시스템 상에서 어느정도 만큼이나 정밀하게 record 를 할 것인가가 중요한 것 같다.