Embedded 기기의 양산 제품에 대한 SW 테스트는, 거쳐야 하는 관문이 꽤 많다.
보통은, 개발자에 의한 (1)Unit test, QA 팀의 (2)Integration test / (3)Stress test, 그리고 SW 인력의 손을 떠난 (4)Monkey test나 (5)극한테스트(가칭)가 있다. 그 중에서 극한테스트(가칭)의 경우는 나에게 잊을 수 없는 개발 경험을 준 적이 있다.
때는 5~6년 전 어느 날, 갑자기 양산 검증 쪽에서 급보가 날아 들었다.
고온의 불가마에서 TV가 제대로 나오는지를 테스트 하는 실험이었는데 20일 정도를 계속 켜 놓았더니 TV가 죽었다는 것이다. 시리얼로 덤프를 받아서 개발팀에 넘겼고, 문제를 일으킨 것은 나의 코드였다. 양산 검증 막판에 이런 식의 에러가 발생하면 생산 라인이 가동을 멈추어야 하기에 이것은 꽤 큰 일이었다.
급하게 문제의 소스를 확인 해보니 다음의 위치였다.
(방금 창작한 코드라 당시의 코드와 조금은 다를 수 있다)
if (dst_alpha > 0)
{
unsigned long src_rate = (src_alpha * (MAX_ALPHA_VALUE - dst_alpha)) / MAX_ALPHA_VALUE;
unsigned long last_rate = src_rate + dst_alpha;
assert(src_rate < 256);
assert(last_rate < 256);
assert(last_rate > 0);
}
양산 제품에 왜 assert()가 빠지지 않았냐는 일단 차치하고(최종 버전을 릴리즈 모드로 하지 않은 듯 하다) 어떤 상황에서 assert()에서 죽을 수 있는 지를 검토해 보았다.
다음과 같은 검증 코드를 만들어서 돌렸고, 모든 유효한 값을 다 넣어 봐도 assert(false)는 일어 날 수 없다는 것을 증명하고서야 나의 혐의는 풀렸다.
void probe(unsigned long src_color, unsigned long dst_color)
{
#define MAX_ALPHA_VALUE 255
unsigned long src_alpha = (src_color >> 24);
unsigned long dst_alpha = (dst_color >> 24);
if (dst_alpha > 0)
{
unsigned long src_rate = (src_alpha * (MAX_ALPHA_VALUE - dst_alpha)) / MAX_ALPHA_VALUE;
unsigned long last_rate = src_rate + dst_alpha;
assert(src_rate < 256);
assert(last_rate < 256);
assert(last_rate > 0);
}
}
테스트
for (unsigned long s = 0; s <= 0xFF; s++)
for (unsigned long d = 0; d <= 0xFF; d++)
{
unsigned long src_color = (s << 24);
unsigned long dst_color = (d << 24);
probe(src_color, src_color);
}
정상적인 상황에서는 절대 발생할 수 없다는 것이 쉽게 증명이 되는 상황이었기에 다행인 것이지, 만약 이런 것을 증명하기 애매한 경우라면, 며칠을 밤을 새워 가며 시달렸을지도 모른다.
이 경우는 극악한 환경에서의 CPU 오동작과 관계가 있었겠지만, 이런 것 이외에도 memory cache의 타이밍 문제나, LCD controller의 전송 특징과 같이 S/W와는 직접적으로 관련 없어 보이는 것도 S/W의 문제로서 처리해야 하는 경우가 많다. 그리고 우리가 그런 문제점을 통보 받게 되면 S/W에서 처리 가능한 문제가 아니라는 것을 증명하기 위래 아까운 시간을 낭비하게 된다.
그나마 다행인 것은, 이런 문제를 많이 접하면 접할수록 과거의 경험을 통해 S/W의 문제가 아니라는 증명을 그나마 빨리 해낼 수 있게 되었다는 점이다. (물론, H/W device나 compiler를 의심하는 것은 S/W 엔지니어가 가장 마지막에 검토해야 하는 것이다)
Posted by 안영기