원문 캡처 · github.com
원문 캡처 · github.com

uringscope는 리눅스의 io_uring을 사용하는 프로세스를 추적해 요청별 지연 시간, 비동기 작업자 경로 이탈, 배치 효율, 멈춤 현상을 보고하는 도구다. 데이터베이스나 저장 엔진처럼 io_uring을 쓰는 프로그램의 성능 문제를 살펴볼 때 활용할 수 있으며, 보고서에는 문제 근거와 수정 제안도 담긴다.

GitHub 저장소에서 아키텍처별 정적 바이너리(x86_64, aarch64)나 .deb, .rpm 패키지를 받을 수 있다. 실행에는 BTF가 활성화된 커널(CONFIG_DEBUG_INFO_BTF=y)과 CAP_BPF·CAP_PERFMON 권한 또는 root 권한이 필요하다. 프로젝트는 주류 배포판에서 대체로 5.15 이후 커널에 BTF가 포함된다고 설명한다.

프로그램을 감싸 실행하려면 sudo uringscope ./myapp, 실행 중인 프로세스를 30초 동안 관찰하려면 sudo uringscope -p 31337 -d 30을 사용한다. -a는 시스템의 모든 대상을 관찰하고, --json은 기계 판독 가능한 보고서를 만든다. JSON 결과는 버전이 지정된 스키마를 사용하며, --fail-on으로 특정 심각도 이상의 발견 사항이 있을 때 종료 코드에 반영할 수 있다. 자세한 내용은 JSON 보고서 문서에 있다.

기본 모드는 커널 안에서 통계와 지연 시간 히스토그램을 집계하고 종료 시 사용자 공간에서 결과를 읽는다. --trace는 요청별 타임라인을 내보내며 Perfetto에서 열 수 있다. 실시간 출력과 OpenMetrics 엔드포인트도 제공한다. --check는 겹치는 메모리 범위의 요청이나 등록 버퍼 수명 위반 등 버퍼 관련 위험을 찾는 디버깅 모드지만, 일반 실행보다 오버헤드가 높다.

커널 지원 수준은 버전에 따라 다르다. 6.1 이상은 전체 기능을 지원하고, 5.15 LTS는 카운터와 배치 측정만 제공하며 비동기 작업자 경로 이탈의 원인을 구분하지 못한다. 5.15 미만은 지원하지 않는다. Docker 기본 seccomp 프로필은 io_uring 시스템 호출을 차단하므로 컨테이너보다 베어메탈과 가상 머신 환경을 주요 대상으로 삼는다. 프로젝트는 초기 단계라고 밝히며, 커널별 기능 차이도 안내한다.

PostgreSQL 18에서 io_uring을 살펴보는 가이드와 설치·빌드 안내는 저장소에서 확인할 수 있다. 오류 제보와 기능 관련 논의는 이슈 트래커에서 받는다.

부록: 원문 예시

원문에 실린 예시 1

text
$ sudo uringscope ./myapp ... myapp runs ... uringscope report (12.4s, 8 cpus) ================================= ring #0 fd=5  sq=256 cq=512  flags: (none)        myapp pid 31337 submission   io_uring_enter() calls          1,204,332   SQEs submitted                  1,209,544     avg batch 1.0/enter   <-- !   completions                     1,209,540 per-op latency (submit -> complete)   READ      1,102,238 reqs   p50 14us   p99 1.2ms   punted 63.1%      <-- !   WRITE        91,002 reqs   p50 22us   p99 410us   punted  2.0%   ... findings   [BATCH]  You average 1.0 SQEs per io_uring_enter(). You are paying a            syscall per request -- the thing io_uring exists to avoid.            Queue more SQEs before calling submit.   [PUNT]   63% of READ requests fell off the fast path into io-wq worker            threads (likely buffered reads missing the page cache). This            is where your p99 lives. Consider O_DIRECT + registered            buffers, or provoke readahead.