먼저 무엇부터 무엇까지 재는지 적는다
'추론 10 ms'만으로 로봇이 최신 관측을 10 ms 만에 반영한다고 말할 수 없다. 센서의 취득, 장치/프로세스 수신, 전처리 대기·계산, 모델 입력 복사/실행, 결과 통신, 제어기 적용이 서로 다른 사건이기 때문이다. latency는 정한 시작 사건부터 끝 사건까지의 경과 시간이고, deadline은 그 경로가 완료되어야 할 기한이다. 처리 주기나 초당 처리 수와도 다르다.
센서 stamp가 노출 시작/중간/끝인지 수신 시각인지는 장치 계약으로 확인한다. 카메라의 노출/전송 시간을 이미 취득→수신 구간에 포함했다면 같은 구간을 다시 더하지 않는다. 이 단위의 취득 시각은 과제에서 주어진 관측 기준 시각이며 실제 센서의 세부 정의를 대신하지 않는다. 제어기 적용도 명령이 전달/적용된 사건과 기계가 목표에 도달한 사건을 구별한다.
각 관측/명령에 ID를 붙여 같은 관측에서 나온 결과를 연결한다. 다른 프레임의 수신 시각과 이전 명령의 적용 시각을 빼면 엉뚱한 지연이 된다. 로그에는 ID, stage 이름, 시작/끝·clock 종류/호스트, 입력/출력 크기와 오류/누락을 남긴다. 역전/음수 차이는 빠른 실행이라고 받아들이지 않고 ID/clock/재시작을 확인한다.
한 시계로 정렬된 직렬 로그를 차분한다
다음 합성 로그는 같은 단조 시계의 ms 단위이고 하나의 관측/명령 경로다. 이전 단계가 끝나야 다음 단계가 시작하는 직렬 처리로 가정한다. 단조 시계는 시간 보정으로 뒤로 뛰지 않는 경과 시간 기준을 뜻하지만, 서로 다른 컴퓨터의 기준점까지 같다는 뜻은 아니다.
그림 M27.03-1. 각 칸은 서로 다른 역할/근거다. 아래 방향은 자료/처리의 연결이며 실제 성공을 자동으로 보장하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
| 사건 | 시각(ms) |
|---|---|
| 관측 취득 | 1000 |
| 컴퓨터 수신 | 1008 |
| 전처리 시작 | 1013 |
| 전처리 완료 | 1019 |
| 모델 완료 | 1037 |
| 명령 수신 | 1042 |
| 제어기 적용 | 1050 |
취득→수신은 8 ms, 전처리 대기 5 ms, 전처리 계산 6 ms, 모델 18 ms, 통신 5 ms, 제어기 대기/적용까지 8 ms다. 모델 구간은 전처리 완료 직후 시작하며 이 예에서는 필요한 입력 준비/실행 완료까지를 포함한다고 정의한다. 합은 50 ms로 1050−1000과 같다. 모델만의 18 ms와 관측의 적용 나이 50 ms를 다른 열에 적는다.
기한 45 ms라면 5 ms 초과다. 모델 구간을 18→10 ms로 줄이고 나머지 구간이 그대로라는 가정에서는 42 ms/여유 3 ms가 된다. 원래 전체 50 ms의 시간 비율은 50/42≈1.19배 개선이며 모델만의 1.8배가 전체의 1.8배는 아니다. 이 결과도 실제 최적화 성과가 아니라 한 항목만 바꾸는 가상 계산이다. 입력 해상도/정밀도를 바꾸었다면 다른 구간/품질도 바뀔 수 있다.
겹쳐 진행한 경로는 무조건 합하지 않는다
병렬 처리는 여러 경로가 시간상 겹치는 구성이다. 공통 준비 6 ms 뒤 영상 경로 18 ms와 상태 경로 8 ms가 동시에 시작하고, 둘 다 끝난 뒤 결합 4 ms가 필요하면 전체는 6+max(18,8)+4=28 ms다. 두 경로가 독립 자원에서 위 시간대로 진행하고 별도 동기화/복사 비용이 없다는 입력 가정이다. 직렬로 합한 36 ms와 다르다.
긴 영상 경로가 완료 시점을 정하는 임계 경로다. 상태 경로를 8→2 ms로 줄여도 긴 경로가 18 ms라 전체는 여전히 28 ms다. 반대로 영상 경로를 10 ms로 줄이면 전체 20 ms가 된다. 실제로 CPU/메모리 대역폭을 공유하면 동시 실행 시간이 늘 수 있어 별도 측정해야 한다. 프로그램에 스레드를 두 개 만들었다고 이상적인 max 식이 자동 성립하지 않는다.
파이프라인은 서로 다른 프레임의 단계를 겹쳐 처리량을 높일 수 있지만, 각 프레임이 거치는 전체 나이가 줄었다는 증거는 아니다. 측정할 때 같은 ID를 끝까지 추적하고 큐 대기와 처리 시간을 분리한다. 이번 표에는 정상상태 입력률/큐 증가를 넣지 않았으므로 처리량이나 누락률을 추론하지 않는다.
호스트 호출 시간과 장치 완료 시간을 구분한다
비동기 호출은 작업을 제출하고 완료 전에 호출이 돌아올 수 있는 방식이다. 호스트에서 호출 전후만 재면 장치 계산이 끝날 때까지가 아니라 제출 비용만 측정할 수 있다. PyTorch의 공식 CUDA 구현은 synchronize가 지정 장치의 모든 stream kernel 완료를 기다리는 API임을 설명한다. 다른 작업까지 기다리는 경계일 수 있으므로 개별 kernel의 순수 시간과도 구분한다.
예를 들어 제출 전 0 ms/호스트 반환 1 ms/필요 결과 준비 13 ms라면 1 ms는 제출 구간이고 결과 준비까지는 13 ms다. 정확한 경계를 정하려면 장치 event나 적절한 완료 대기를 사용하며 어떤 복사/동기화가 포함되는지 명시한다. 매 stage마다 강제로 기다리면 원래의 겹침을 없애 실제 운영 성능을 바꿀 수 있다. 이 단위는 GPU를 실행하지 않고 합성 사건의 의미만 비교한다.
같은 호스트의 짧은 경과 시간에는 Python의 perf_counter/perf_counter_ns를 사용할 수 있다. 기준점 자체의 절대 의미 대신 두 호출의 차이를 사용한다. 다른 호스트의 counter나 ROS simulation time과 직접 빼지 않는다. ROS 시간 설계의 simulation clock은 정지/점프할 수 있으므로 실제 경과 시간 계측과 관측 stamp의 목적을 분리한다. 원격 구간은 시계 정합/오차를 기록하거나 같은 클라이언트 시계의 왕복 시간을 측정한다.
개별 사건의 합과 꼬리 통계의 합은 다르다
같은 ID의 겹치지 않는 직렬 구간은 더하면 전체 경과 시간이 된다. 그러나 각 구간의 p95를 더한 값이 전체 p95라는 법칙은 없다. p95는 정한 표본/계산 규칙에서 약 95%가 그 이하인 분위수이고, stage 간 느린 사건이 같은 표본에서 겹치는지에 따라 전체 분포가 달라진다. 전체는 ID별 합으로 만든 표본에서 다시 계산한다. 최대/평균만으로도 드문 deadline 누락을 놓칠 수 있다.
처음 실행의 모델 로드/컴파일과 준비 실행 뒤의 정상 구간을 나누고 표본 수/입력·스레드/지속 부하를 기록한다. 로그 출력/시계 호출도 비용이 있으므로 원래 동작을 크게 바꾸지 않는지 확인한다. 모델 구간이 줄었어도 품질·큐/통신·적용 나이가 나빠졌을 수 있어 같은 입력/버전에서 전체 경로를 재측정한다. 기존 6.2 정량 진단의 경로 분해와 연결해 보자.