Showing Posts From

어제

월요일 아침, 어제 밤 테스트가 또 실패했다

월요일 아침, 어제 밤 테스트가 또 실패했다

월요일 아침, 또 실패했다 지난 금요일 오후 5시. 나는 한 가지 결정을 했다. 이번 주말은 펌웨어 테스트에 바치겠다고. 양산 일정이 2주 남았고, 메모리 누수 문제가 자꾸만 나타나고 있었다. 재현율도 일정하지 않아서 더 답답했다. 혹시 특정 시나리오에서만 발생하는 건 아닐까 싶어서, 토요일 밤 10시부터 테스트 케이스를 짜기 시작했다. 테스트 자동화 스크립트를 짜고, 보드에 펌웨어를 올렸다. 그리고 돌렸다. 50번. 100번. 200번. 중간에 서버를 켜서 로그를 쌓기도 했다. 무언가 패턴이 있을 거야. 뭔가 타이밍 이슈가 분명히 있어. 그렇게 스스로를 다독였다.결국 새벽 2시. 내 눈은 이미 초점을 잃은 지 오래였지만, 모니터는 계속 켜져 있었다. 테스트 로그가 한 줄씩 쌓여간다. 잠에서 깨어나다를 반복하면서, 나는 휴대폰 알람을 6시로 맞춰놨다. 지금이라도 테스트 결과를 다시 확인할 수 있으려고. 일요일 아침. 침대에서 일어나자마자 가장 먼저 한 일은 회사 랩탑을 켜는 것이었다. 아내가 있었다면 지금쯤 싸웠을 것 같다. 하지만 나는 혼자였고, 혼자라는 건 아무도 나를 막을 수 없다는 뜻이었다. 테스트 결과 폴더를 열었다. test_result_20250120.txt 손가락이 떨렸다. 마우스를 클릭했다. Test Run 1: PASS Test Run 2: PASS Test Run 3: PASS ... Test Run 127: FAIL - Stack Overflow detected Test Run 128: PASS ... Test Run 200: FAIL - Memory corruption at 0x20019A4C한숨이 나왔다. 스택 오버플로우라니. 내가 이미 다 확인했는데? 재귀 함수도 없는데? malloc도 거의 안 쓰는데? 스택 사이즈는 충분하게 잡아놨는데?일요일 하루 종일 로그를 뒤졌다. 스택 오버플로우 전에 어떤 함수가 호출되었는가. 뭔가 재귀 호출이 숨어 있는 건 아닐까. 콜스택을 추적했다. 라이브러리 함수도 다시 읽어봤다. 혹시 RTOS 태스크 스위칭 중에 문제가 생기는 건 아닐까. 밤 11시. 나는 결론을 내렸다. 이건 펌웨어 이슈가 맞는 것 같은데, 타이밍이 맞아야 재현된다. 아마도 특정 조건—아마도 센서 데이터 처리와 블루투스 통신이 동시에 일어날 때—에서 벌어지는 문제인 것 같다. 그렇다면 월요일 아침, 하드웨어팀에 질문해야 한다.월요일 아침 8시 47분. 회사 자리에 앉자마자 모니터를 켰다. 본메일을 열었다. 토요일 밤 11시에 내가 보낸 이메일이 보였다.제목: 메모리 이슈 관련 질문 - 혹시 하드웨어 문제 아닐까요? 안녕하세요. 펌웨어 테스트 중 다음과 같은 증상을 발견했습니다.약 200번 중 2-3번 스택 오버플로우 발생 재현율이 일정하지 않음 센서 값 읽기와 BLE 전송 중에 주로 발생?혹시 센서 전원 공급 라인이 불안정하거나, 아니면 크리스탈 타이밍이 미세하게 어긋나는 건 아닐까요?제목을 다시 읽으니 한숨이 나왔다. 또 '펌웨어 문제 아니겠죠?' 하는 톤이다. 매번 이런 식이다. 내가 물어보는 것처럼 보이지만, 사실 나는 이미 내 것은 다 확인했다. 이제 남은 건 하드웨어 팀의 회신뿐이다. 카톡이 울렸다. 하드웨어팀 선임: "펌웨어 맞나? 우리 회로는 다 문제없는데..." 당연하다. 매번 이 반복이다. 나 혼자만 자기 것을 의심하고, 상대팀은 절대 자기 것을 의심하지 않는다.나는 다시 펌웨어 코드를 열었다. 이번엔 다르게 접근해보겠다. 스택 오버플로우가 맞다면, 스택 사용량을 동적으로 모니터링하는 코드를 삽입해야겠다. 높이수 마크를 남겨놓고, 런타임에 계속 확인한다면 어디서 스택이 터지는지 알 수 있을 것 같다. 코드를 작성했다. extern unsigned int _estack; extern unsigned int _sstack;uint32_t stack_high_water_mark = 0; uint32_t* stack_top = (uint32_t*)&_sstack;void update_stack_monitor() { uint32_t current_sp; asm volatile ("mov %0, sp" : "=r" (current_sp)); uint32_t used = (uint32_t)stack_top - current_sp; if (used > stack_high_water_mark) { stack_high_water_mark = used; // Log this } }이런 식으로 계속 모니터링하면, 진짜 스택이 얼마나 사용되는지 알 수 있다. 그리고 혹시 내가 놓친 부분이 있다면—혹은 라이브러리에서 몰래 큰 배열을 선언한다면—그걸 잡을 수 있을 것이다. 오전 10시. 회의실에서 양산 미팅이 있었다. 영업팀, 하드웨어팀, 펌웨어팀이 모였다. 일정을 확인했다. 14일 뒤 중국 공장으로 샘플을 보낸다고 했다. 샘플. 그 단어만 들어도 가슴이 철렁했다. 샘플이 괜찮으면 양산이 결정된다. 양산이 결정되면 내 코드는 이제 수정 불가다. 딱 이 상태 그대로 나간다. 나는 손을 들었다. "죄송한데, 아직 메모리 스태빌리티 이슈가 남아있어서요. 최소 1주일이 더 필요할 것 같습니다." 회의실이 조용해졌다. 영업팀 과장이 말했다. "메모리 문제라고? 그게 뭔 문제야?" 하드웨어팀 선임이 말했다. "펌웨어 쪽 문제 아닐까요?" 부장이 나를 봤다. "정확한 원인이 뭐야?" 나는 깊게 숨을 쉬었다. "저... 아직 정확히는 모릅니다. 타이밍 이슈인 것 같은데, 센서 입력과 BLE 통신 사이의 레이스 컨디션일 수도 있고, 아니면 진짜 스택 오버플로우일 수도 있습니다. 자동화 테스트로 재현을 기다리고 있어요. 로그에서 패턴을 찾으면 원인을 특정할 수 있을 것 같습니다." 부장은 고개를 끄덕였다. "좋아, 원인을 빨리 찾아." 회의실을 나왔을 때, 내 머리는 이미 다음 시도를 생각하고 있었다. 혹시 센서 드라이버에서 문제가 있는 건 아닐까. 아니면 타이머 인터럽트의 우선순위 설정이 잘못된 건 아닐까. 혹은 그냥 운이 없었을 거고, 계속 테스트하면 한 번은 성공할 거야. 오후 3시. 다시 보드 위의 LED를 본다. 초록 불이 깜박인다. 실행 중이다. 또 테스트를 돌리고 있다. 200번. 500번. 아마 밤새도록 돌릴 것 같다. 그리고 내일 아침, 월요일과 같은 절망감으로 깨어날 것 같다.결국 오늘도 또 다른 월요일의 시작일 뿐이다.