← System Programming DUJINLABS.COM

Observe / Harden · Linux userspace / kernel ABI

/proc, strace, perf로 실행 경로 확인

source 해석을 syscall trace, process snapshot, hardware/software counter와 대조하고 관찰 도구 자체의 영향과 race를 구분합니다.

Series
37 / 37
Build
cc -std=c17 -Wall -Wextra -O2 observe_me.c -o observe_me
Run
./observe_me
Kernel
Linux 6.18.37 LTS

strace에 보이지 않는 시간은 어디에서 확인해야 하는가?

strace는 ptrace/seccomp 기반으로 syscall 진입·종료와 signal을 보여 주지만 userspace 계산과 kernel 내부 함수 구간을 직접 나누지 못한다. /proc는 특정 시점의 fd, maps, status, sched 정보를 제공하고 perf는 counter, sampling, tracepoint로 CPU와 kernel event를 관찰한다.

한 도구 출력만으로 원인을 단정하지 않는다. syscall wall time, off-CPU wait, page fault, scheduler delay, userspace CPU sample을 같은 request timeline에 맞춘다.

구조 그림

그림 1. 관찰 질문별 도구와 보이는 범위
질문도구관찰 객체보이지 않는 것 어떤 syscall이 느린가strace -ttT진입/반환·errnosyscall 사이 CPU codefd가 어디서 샜나/proc/PID/fd현재 fd table이미 닫힌 과거 수명RSS가 왜 큰가smaps_rollupmapping/accountingallocation call stackCPU hot path는perf recordsampled IP/call graph정확한 모든 호출 횟수왜 runnable인데 늦나perf sched/tracepointscheduler eventapplication predicate

도구마다 관찰 단위가 다르다. syscall trace로 userspace CPU hot path를 설명하거나 RSS snapshot으로 page fault latency를 설명할 수 없다.

호출 흐름

그림 2. 사용자 코드에서 관찰 가능한 결과까지
symptom latency/CPU/RSS/fd
strace syscall과 errno
/proc object snapshot
perf counter/sample/trace
source 조건문과 수명 대조

관찰 질문을 먼저 고른다. fd leak에는 fd table, page fault latency에는 fault counter, CPU hot path에는 sampling처럼 대상 객체와 도구를 맞춘다.

그림 3. 커널 내부에서 지나가는 주요 지점
syscall trace entry/exit timestamps
procfs show task/mm/files 조회
perf_event PMU/software event
tracepoint stable event fields
analysis correlation ID/timebase

함수 이름을 외우기 위한 그림이 아니다. 반환값, 파일 디스크립터, 메모리 매핑, 대기 큐 가운데 무엇이 다음 단계로 전달되는지 확인한다.

Linux 6.18.37 LTS 소스 위치

glibc 함수에서 멈추지 않고 syscall 구현과 커널 객체가 만나는 파일까지 내려간다. 링크는 동일한 태그의 원본 파일을 가리킨다.

파일함수·구조체여기서 볼 것
fs/proc/base.c proc_pid_status(), proc_pid_fd_operations PID별 status/fd 파일이 어떤 task 정보를 노출하는지 확인
kernel/events/core.c perf_event_open(), perf_event_alloc() perf event context와 fd 수명
kernel/trace/trace_events.c event_trace_add_tracer() tracepoint event enable과 ring buffer 연결

실행 예제 원본

아래 코드는 설명을 위해 중간 줄을 생략한 의사 코드가 아니다. 파일로 빌드해 실행할 수 있는 최소 예제다.

빌드cc -std=c17 -Wall -Wextra -O2 observe_me.c -o observe_me
01#define _DEFAULT_SOURCE
02#include <fcntl.h>
03#include <stdio.h>
04#include <stdlib.h>
05#include <sys/mman.h>
06#include <unistd.h>
07
08int main(void)
09{
10    long page = sysconf(_SC_PAGESIZE);
11    size_t length = 32UL * 1024 * 1024;
12    unsigned char *area = mmap(NULL, length, PROT_READ | PROT_WRITE,
13                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
14    if (area == MAP_FAILED)
15        return 1;
16    for (size_t offset = 0; offset < length; offset += (size_t)page)
17        area[offset] = (unsigned char)(offset / (size_t)page);
18
19    int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
20    if (fd < 0)
21        return 1;
22    dprintf(fd, "pid=%ld pages=%zu\n", (long)getpid(), length / (size_t)page);
23    close(fd);
24    printf("pid=%ld checksum=%u\n", (long)getpid(), area[length - page]);
25    munmap(area, length);
26    return 0;
27}

코드 조각별 설명

실제 코드 10행sysconf(_SC_PAGESIZE)

계측 loop 단위를 실제 base page 크기에 맞춰 fault 수와 접근 수를 비교할 수 있게 한다.

실제 코드 12행mmap(NULL, length

strace에는 빠른 mmap syscall 하나로 보이지만 실제 page 비용은 아래 write loop의 minor fault에서 발생한다.

실제 코드 17행area[offset] =

perf stat의 page-faults/minor-faults가 증가하고 userspace loop CPU 시간이 생기는 지점이다.

실제 코드 19행open("/dev/null"

/proc/self/fd에는 잠깐 fd가 나타나며 strace에서 openat/close 수명을 확인할 수 있다.

실제 코드 25행munmap(area

mapping 수명을 명시적으로 끝낸다. process exit가 정리해 주더라도 장기 process의 반복 동작에서는 unmap 시점이 RSS/VA에 중요하다.

세부 동작

01

strace 시간은 syscall 안과 밖을 나눈다

-T는 syscall 진입부터 반환까지 경과를 보여 주지만 ptrace overhead가 짧은 호출과 multithread scheduling에 영향을 준다. -ttt/clock 기준으로 application request log와 맞춘다.

unfinished/resumed 표시는 thread가 syscall에서 block된 동안 다른 trace line이 끼었음을 뜻한다.

02

/proc 파일도 읽는 순간 변한다

fd directory를 순회하는 동안 process가 fd를 닫고 재사용할 수 있다. maps와 smaps 사이에도 VMA가 바뀔 수 있다. snapshot처럼 보이지만 전체 process state transaction은 아니다.

정확한 dump가 필요하면 process stop, ptrace, application safepoint 등 consistency 방법을 정한다.

03

perf sampling은 확률적 관찰이다

sample frequency가 낮으면 짧은 hot path를 놓치고 높으면 overhead와 lost sample이 늘어난다. call graph 방식 frame pointer/DWARF/LBR의 tradeoff를 기록한다.

counter multiplexing이 있으면 time_enabled/time_running 비율과 scaled value를 확인한다.

객체와 수명

대상언제 생기고 없어지는가확인할 값
tracee taskstrace attach부터 detach/exit까지 ptrace 관계가 유지된다stop reason, syscall state, signal
proc file snapshotopen/read 시 task 객체를 조회하며 각 파일마다 consistency 범위가 다르다PID reuse, namespace, permission
perf event fdperf_event_open에서 생기고 enable/disable/read/close로 관리된다counter, sample ring, time scaling

실패 조건과 오해하기 쉬운 부분

겉으로 보이는 현상실제 원인 후보확인 방법
strace에서 병목이 안 보임userspace CPU 또는 scheduler delayperf record/sched와 wall timeline
PID 대상이 바뀜숫자 PID 재사용pidfd와 starttime 확인
perf 결과 불안정sampling 부족/multiplex/주파수 변화반복, scaling, CPU pinning

직접 확인

  1. strace -c와 -ttT로 syscall count와 개별 latency를 보고 perf stat page-faults와 결과를 맞춘다.
  2. 프로그램을 getchar로 멈춘 변형에서 /proc/PID/maps, smaps_rollup, fd, status를 한 번에 수집한다.
  3. perf record -g와 flame graph 이전에 compiler frame pointer 설정, debug symbol, sample loss를 확인한다.
실행./observe_me
추적strace -ttT -f ./observe_me && perf stat -d ./observe_me

원문