백엔드 시험 시간은 벽시계가 아니라 CPU 시간으로 잰다
CI가 붐비면 1초 근처 시험이 빌드마다 번갈아 떨어진다. 프로세스가 쓴 CPU 시간에 자식 프로세스 몫을 더해 재면 부하에 흔들리지 않는다.
시험마다 시간 한도를 두면, CI가 붐비는 시간에 1초 근처에서 끝나던 시험이 빌드마다 번갈아 떨어진다. 코드는 그대로인데 결과만 흔들린다.
원인은 벽시계다. 벽시계 시간은 같은 기계에서 도는 다른 일(다른 빌드, 전체 시험, 다른 작업)에 끌려간다. 잴 때 무거운 일과 겹치면 같은 시험이 2배까지 흔들린다.
백엔드 시험은 프로세스가 실제로 쓴 CPU 시간으로 잰다. time.process_time()에 resource.getrusage(RUSAGE_CHILDREN)의 utime·stime을 더한다. forkserver로 띄운 자식은 RUSAGE_CHILDREN에 잡히지 않으니, 자식이 쓴 몫을 돌려받아 따로 더한다.
import resource
import time
def cpu_seconds() -> float:
kids = resource.getrusage(resource.RUSAGE_CHILDREN)
return time.process_time() + kids.ru_utime + kids.ru_stime
start = cpu_seconds()
run_test()
spent = cpu_seconds() - start
한계도 안다. DB 서버가 쓰는 시간은 다른 프로세스라 잡히지 않으니 DB가 느린 것은 따로 본다. 기다림이 대부분인 브라우저 E2E는 벽시계가 맞다. 시험 층마다 맞는 시계를 고른다.