syscall analysis

Nginx (v1.18.0)

以下為處理單個 HTTP GET request 時發出的系統呼叫:

  • Intel Pin 動態觀察系統呼叫的使用:

    ​​​​syscall #: 232
    ​​​​syscall #: 288
    ​​​​syscall #:  45  
    ​​​​syscall #:   4   
    ​​​​syscall #: 257
    ​​​​syscall #:   5
    ​​​​syscall #:  20
    ​​​​syscall #:  40
    ​​​​syscall #:   3
    ​​​​syscall #: 233
    ​​​​syscall #:  54
    ​​​​syscall #: 232
    ​​​​syscall #:  45
    ​​​​syscall #:   3
    

    對應系統呼叫名稱為:

    ​​​​epoll_wait
    ​​​​accept4
    ​​​​recvfrom
    ​​​​stat
    ​​​​openat
    ​​​​fstat
    ​​​​writev
    ​​​​sendfile
    ​​​​close
    ​​​​epoll_ctl
    ​​​​setsockopt
    ​​​​epoll_wait
    ​​​​recvfrom
    ​​​​close
    
  • Intel Pin 動態觀察同樣行為的 call trace: (Gist 連結)
    單個 HTTP request 的 call trace 約為 1.1k 行左右,上述大部份系統呼叫都可以在 call trace 中找到,找不到的可能是用其他 symbol name 包裝了,例如:fstat, stat 在 glibc 中分別以 __fxstat64 以及 __xstat64 包裝。

  • 以 strace 動態觀察同樣行為:

    ​​​​epoll_wait(7, [{EPOLLIN, {u32=1479659536, u64=140236456841232}}], 512, -1) = 1
    ​​​​accept4(5, {sa_family=AF_INET, sin_port=htons(53944), sin_addr=inet_addr("118.166.75.229")}, [112->16], SOCK_NONBLOCK) = 9       
    ​​​​recvfrom(9, "GET / HTTP/1.1\r\nHost: localhost:"..., 1024, 0, NULL, NULL) = 40
    ​​​​stat("custom_env/html/index.html", {st_mode=S_IFREG|0664, st_size=162, ...}) = 0
    ​​​​openat(AT_FDCWD, "custom_env/html/index.html", O_RDONLY|O_NONBLOCK) = 10
    ​​​​fstat(10, {st_mode=S_IFREG|0664, st_size=162, ...}) = 0 
    ​​​​writev(9, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=237}], 1) = 237
    ​​​​sendfile(9, 10, [0] => [162], 162) = 162
    ​​​​close(10) = 0 
    ​​​​epoll_ctl(7, EPOLL_CTL_ADD, 9, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=1479659969, u64=140236456841665}}) = 0
    ​​​​setsockopt(9, SOL_TCP, TCP_NODELAY, [1], 4) = 0
    ​​​​epoll_wait(7, [{EPOLLIN|EPOLLRDHUP, {u32=1479659969, u64=140236456841665}}], 512, 65000) = 1
    ​​​​recvfrom(9, "", 1024, 0, NULL, NULL)    = 0
    ​​​​close(9)
    ​​​​epoll_wait(7,
    

    其中最後一個系統呼叫 epoll_wait 的狀態為正在 blocking 等待 event。

筆記

  • Intel Pin 使用自己的 CRT (C runtime),因此有些 glibc 的函式無法使用 (例如: clock_gettime,需以 syscall() 直接呼叫。倘若粒度要求不高的話,可以使用 Pin CRT 提供的 OS_Time())。