기능 커버리지와 코드 커버리지 차이, 수치가 말해 주는 것

기능 커버리지와 코드 커버리지 차이, 수치가 말해 주는 것

시내버스 새 노선을 열기 전에 시험 운행을 한다고 해 보겠습니다. 운행 기록을 보니 노선에 있는 정류장과 도로 구간은 모두 한 번씩 지나갔습니다. 그렇다면 이 노선은 준비가 끝난 걸까요?

만원인 출근 시간대, 폭우로 속도를 줄여야 하는 길, 휠체어 승객이 타는 정류장 같은 상황은 지나간 길의 기록만으로는 알 수 없습니다. 칩 검증에서 기능 커버리지와 코드 커버리지가 각각 이 두 질문에 해당합니다. 하나는 어디를 지나갔는지를, 다른 하나는 어떤 상황을 겪어 봤는지를 묻습니다.

비유와 다른 점이 있습니다. 칩에서는 지나간 길의 기록이 시뮬레이터에서 자동으로 나오지만, 겪어 봐야 할 상황의 목록은 사람이 스펙을 읽고 직접 적어야 합니다. 그 목록의 품질이 기능 커버리지의 품질을 결정합니다.

기능 커버리지와 코드 커버리지가 따로 있는 이유

커버리지(coverage)는 검증이 설계의 어느 부분과 어떤 동작을 얼마나 확인했는지를 나타내는 지표입니다. 시뮬레이션은 시험하지 않은 입력에 대해서는 아무 말도 해 주지 않으므로, 어디까지 확인했는지를 숫자로 보는 장치가 필요합니다.

문제는 확인의 범위를 재는 잣대가 하나가 아니라는 점입니다. 코드에서 출발해 재는 방법과 스펙에서 출발해 재는 방법은 서로 다른 구멍을 찾아 줍니다. 제조 후 결함을 얼마나 잡는지 재는 테스트 커버리지와도 다른 개념이므로, 이름이 비슷해도 같은 지표로 보면 안 됩니다.

코드 커버리지, 코드의 어디를 실행했는가

코드 커버리지(code coverage)는 RTL 코드의 어느 줄과 어느 분기가 시뮬레이션 중 실제로 실행되었는지를 시뮬레이터가 자동으로 기록한 지표입니다. 설계자가 따로 정의하지 않아도 켜 두면 측정된다는 점이 장점입니다.

코드 커버리지의 대표 종류

  • 라인 커버리지: 각 줄이 한 번이라도 실행되었는가
  • 분기 커버리지: if와 case의 각 갈래가 선택되었는가
  • 조건 커버리지: 조건식을 이루는 각 항이 참과 거짓으로 모두 평가되었는가
  • 토글 커버리지: 각 신호 비트가 0에서 1로, 1에서 0으로 바뀌었는가
  • FSM 커버리지: 상태 기계의 각 상태와 상태 전이가 방문되었는가

코드 커버리지가 확실하게 말해 주는 것은 어느 부분이 한 번도 실행되지 않았는가입니다. 실행되지 않은 줄은 시험되지 않았다는 분명한 증거이므로, 낮은 수치는 곧바로 시나리오 부족의 신호가 됩니다.

기능 커버리지, 스펙의 무엇을 시험했는가

기능 커버리지(functional coverage)는 스펙이 요구하는 기능과 상황이 시험되었는지를 재는 지표입니다. 패킷 길이가 최소와 최대일 때, 오류가 낀 패킷과 우선순위가 높은 패킷이 겹칠 때처럼 코드만 봐서는 알 수 없는 의미 있는 조합이 다뤄졌는지를 묻습니다.

이 지표는 자동으로 나오지 않고 검증 엔지니어가 정의합니다. SystemVerilog에서는 커버그룹(covergroup) 안에 관찰할 값인 커버포인트와 값의 구간인 bin을 적고, 여러 값의 조합은 교차(cross)로 만듭니다.

가상 예시, 기능 커버리지 정의와 계산패킷 길이를 최소, 짧음, 보통, 최대의 4개 구간으로 나누고, 우선순위를 낮음, 보통, 높음의 3개 구간으로, 오류 여부를 2개 구간으로 둔다고 가정합니다.

세 값을 교차하면 4 × 3 × 2 = 24개의 조합이 생기고, 시뮬레이션에서 이 중 18개가 관찰되었다면 기능 커버리지는 18 ÷ 24 = 75%입니다.

비어 있는 6개 조합이 지금까지 시험되지 않은 상황의 목록이 됩니다.

수치와 함께 어떤 조합이 비었는지를 보여 준다는 점이 기능 커버리지의 쓸모입니다. 다음 시나리오를 어디에 집중해야 하는지 알려 주기 때문입니다.

두 수치를 함께 읽는 법

기능 커버리지와 코드 커버리지를 함께 보면 상태가 구분됩니다. 코드 커버리지가 높고 기능 커버리지가 낮으면 코드는 대부분 지나갔지만 의미 있는 조합은 덜 시험된 상태이고, 반대로 기능 커버리지는 높은데 코드 커버리지가 낮으면 실행되지 않는 코드가 남은 상태입니다.

수치 조합별 해석

  • 코드 낮음, 기능 낮음: 시나리오가 전반적으로 부족합니다. 시험을 더 늘려야 합니다.
  • 코드 높음, 기능 낮음: 줄은 실행했지만 조합을 놓쳤습니다. 교차 조합을 겨냥한 시나리오가 필요합니다.
  • 코드 낮음, 기능 높음: 도달할 수 없는 코드, 스펙에 없는 기능, 기능 정의의 누락 중 하나일 수 있어 원인을 따로 판단합니다.
  • 코드 높음, 기능 높음: 목표에 가깝지만 체커가 제대로 있는지를 마지막으로 확인합니다.

예를 들어 FIFO에 데이터를 넣는 조건이 쓰기 요청이 있고 가득 차지 않았을 때라고 하겠습니다. 쓰기 요청이 없는 경우와 요청이 있고 여유가 있는 경우만 시험해도 분기 커버리지는 모두 채워지지만, 가득 찬 상태에서 쓰기 요청이 들어오는 상황은 한 번도 시험되지 않을 수 있습니다. 이런 빈 조합은 조건 커버리지나 기능 커버리지의 교차로 찾아냅니다.

커버리지 수치가 말해 주지 못하는 것

커버리지가 100%이면 버그가 없다는 것은 흔한 오해입니다. 커버리지는 시뮬레이션이 실행된 범위를 재는 것이지 결과가 맞았는지를 재는 것이 아닙니다.

실행되었더라도 출력을 기대값과 비교하는 체커나 어서션이 없으면 오류는 그냥 지나갑니다. 코드 커버리지에는 구현되지 않은 기능이 들어 있지 않으므로 빠진 기능도 알려 주지 못합니다. 기능 커버리지는 정의한 항목에 대해서만 말하고, 정의에서 빠진 상황에는 침묵합니다.

그래서 커버리지는 완료의 증명이 아니라 부족한 곳을 찾는 도구로 읽는 편이 안전합니다. 목표 수치를 몇 퍼센트로 둘지, 제외할 항목을 어떻게 검토할지는 팀의 검증 계획과 사인오프 기준에 따라 달라집니다.

커버리지 클로저의 흐름

커버리지를 채워 가는 과정을 커버리지 클로저(coverage closure)라고 합니다. 한 번에 끝나지 않고 측정과 분석, 보완을 반복합니다.

커버리지 클로저의 진행 흐름

  1. 스펙에서 검증 계획을 만들고 기능 커버리지 항목(커버그룹)을 정의합니다.
  2. 시뮬레이션을 돌려 코드 커버리지와 기능 커버리지를 함께 수집합니다.
  3. 채워지지 않은 구멍(hole)을 분석해 원인을 가립니다.
  4. 시나리오가 부족하면 테스트를 추가하거나 무작위 제약을 조정합니다.
  5. 도달할 수 없는 코드나 의도적으로 제외할 항목은 근거를 남기고 리뷰를 거쳐 제외합니다.
  6. 목표에 도달할 때까지 반복하며 사인오프 기준과 비교합니다.

구멍의 원인은 세 가지로 나눠 볼 수 있습니다. 시나리오가 부족한 경우, 설계에서 도달이 불가능한 경우, 커버리지 정의가 잘못된 경우입니다. 뒤의 둘을 시험을 늘려서 풀려고 하면 시간만 쓰게 되므로 원인부터 구분합니다.

기능 커버리지와 코드 커버리지 비교 표

구분코드 커버리지기능 커버리지
측정 기준설계 코드스펙과 검증 계획
정의하는 주체시뮬레이터가 자동 측정검증 엔지니어가 직접 정의
알려 주는 것실행되지 않은 코드시험되지 않은 기능과 조합
놓치는 것구현되지 않은 기능, 조합의 의미정의에서 빠진 상황
대표 종류라인, 분기, 조건, 토글, FSM커버포인트, bin, 교차
잘 맞는 활용시험되지 않은 코드 찾기시나리오 보완 방향 정하기

핵심 정리

기능 커버리지와 코드 커버리지는 하나가 다른 하나를 대신하지 못하는 두 잣대입니다. 코드 커버리지는 코드의 어디가 실행되지 않았는지를, 기능 커버리지는 스펙의 어떤 조합이 시험되지 않았는지를 알려 주며, 둘 다 체커와 어서션이 있어야 의미가 있습니다.

버스 노선으로 돌아가면 모든 정류장을 지나갔다는 기록과 만원 시간대, 폭우, 휠체어 승차를 겪어 봤다는 기록은 서로 다른 안심을 줍니다. 칩에서는 두 수치로 빈 곳을 찾고, 그 빈 곳이 시나리오 부족인지 도달 불가능인지 정의 오류인지를 가려 채우는 일이 검증의 마무리 단계가 됩니다.

면접 대비 질문

면접 대비 질문기능 커버리지와 코드 커버리지의 차이를 설명하고, 코드 커버리지가 100%인데도 검증이 끝났다고 말할 수 없는 이유를 말해 보세요.

[답변 포인트] 코드 커버리지는 RTL의 줄, 분기, 조건, 토글, FSM이 실행되었는지를 시뮬레이터가 자동으로 재고, 기능 커버리지는 스펙에서 뽑은 기능과 조합이 시험되었는지를 검증 엔지니어가 커버그룹으로 정의해 잰다고 구분합니다. 코드 커버리지는 구현되지 않은 기능이나 조건의 조합을 알지 못하고, 실행된 것과 올바르게 동작한 것은 다르므로 체커와 어서션이 필요하다는 점을 설명합니다. 두 수치의 조합별 해석과 구멍의 원인(시나리오 부족, 도달 불가, 정의 오류)을 가려 클로저를 진행한다는 흐름까지 연결하면 좋습니다.