Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are many system calls (getpid) captured only once using strace?

I invoked getpid() in a program for many times (to test the efficiency of system calls), however when I use strace to get the trace, only one getpid() call is captured.

The code is simple:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void print_usage(){
    printf("Usage: program count\n");
    exit(-1);
}

int main(int argc, char** argv){
    if(argc != 2)
        print_usage();
    int cnt = atoi(argv[1]);
    int i = 0;
    while(i++<cnt)
        getpid();
    return 0;
}

I used gdb and got this:

(gdb) disasse
Dump of assembler code for function getpid:
0xb76faac0 <getpid+0>:  mov    %gs:0x4c,%edx
0xb76faac7 <getpid+7>:  cmp    $0x0,%edx
0xb76faaca <getpid+10>: mov    %edx,%eax
0xb76faacc <getpid+12>: jle    0xb76faad0 <getpid+16>
0xb76faace <getpid+14>: repz ret 
0xb76faad0 <getpid+16>: jne    0xb76faadc <getpid+28>
0xb76faad2 <getpid+18>: mov    %gs:0x48,%eax
0xb76faad8 <getpid+24>: test   %eax,%eax
0xb76faada <getpid+26>: jne    0xb76faace <getpid+14>
0xb76faadc <getpid+28>: mov    $0x14,%eax
0xb76faae1 <getpid+33>: call   *%gs:0x10
0xb76faae8 <getpid+40>: test   %edx,%edx
0xb76faaea <getpid+42>: mov    %eax,%ecx
0xb76faaec <getpid+44>: jne    0xb76faace <getpid+14>
0xb76faaee <getpid+46>: mov    %ecx,%gs:0x48
0xb76faaf5 <getpid+53>: ret  

I don't quite understand the assembly code. It would also be helpful if somebody can give some detailed explanation about it. According to my observation, "call *%gs:0x10" (, which jumps into vdso) is not executed, except for the first getpid() call, that may be the reason why subsequent getpid() calls are not captured. But I don't know why.

The linux kernel: 2.6.24-29 gcc (GCC) 4.2.4 libc 2.7,

Thanks!

like image 275
Infinite Avatar asked Apr 23 '11 18:04

Infinite


People also ask

How does strace call work?

strace works by using the ptrace system call which causes the kernel to halt the program being traced each time it enters or exits the kernel via a system call. The tracing program (in this case strace ) can then inspect the state of the program by using ptrace .

Does strace slow down a process?

strace(1) is a great tool, but the current version (using ptrace()) can slow down the target severely. Be aware of the overhead strace causes, and consider other alternates for Linux that use lower-cost buffered tracing.

Why do we use strace?

strace is a diagnostic, debugging and instructional userspace utility for Linux. It is used to monitor and tamper with interactions between processes and the Linux kernel, which include system calls, signal deliveries, and changes of process state.

Which of the following option in strace gives time when system call is called?

To see the time at which each system call was called, use the -tt (absolute timestamps) option. This shows the “wall clock” time, with a microsecond resolution.


2 Answers

Glibc caches the result, since it can't change between calls. See the source code here for instance.

So the real syscall only gets executed once. The other calls just read from the cache. (The code is not very simple because it takes care of doing the Right Thing with threads.)

like image 145
Mat Avatar answered Oct 28 '22 21:10

Mat


glibc caches the pid value. The first time you call getpid it asks the kernel for the pid, the next time it just returns value it got from the first getpid syscall.

glibc code:

pid_t
__getpid (void)
{
#ifdef NOT_IN_libc
  INTERNAL_SYSCALL_DECL (err);
  pid_t result = INTERNAL_SYSCALL (getpid, err, 0);
#else
  pid_t result = THREAD_GETMEM (THREAD_SELF, pid);
  if (__builtin_expect (result <= 0, 0))
    result = really_getpid (result);
#endif
  return result;
}

If you want to test the overhead of syscalls, gettimeofday() is often used to do just that - the work done the kernel is very small, and neither the compiler nor the C library can optimize away calls to it.

like image 21
nos Avatar answered Oct 28 '22 21:10

nos