I have a Python application where I uses the Python sh module multiple times to run commands. Also, I use LXD containers to run isolated tests.
I noticed a very different performance running my tests on LXD container, so I started to reduce the complexity of the Python script.
Now the scrip is a simple sh.nice() but there is heavy difference between the host and the lxc container.
Host
$ time python -c "import sh; sh.nice()"
real 0m0.077s
user 0m0.052s
sys 0m0.012s
Container
$ time python -c "import sh; sh.nice()"
real 0m0.215s
user 0m0.088s
sys 0m0.120s
My next step was use strace which says that the container version calls the syscall close
1,048,796 times!! The majority of the times it returns EBADF (Bad file descriptor).
Here is what I have done; what's happening?
$ uname -a
Linux cmp-1 4.4.0-96-generic #119-Ubuntu SMP Tue Sep 12 14:59:54 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
$ lxc launch ubuntu:precise new-precise-sh
$ lxc exec new-precise-sh -- bash
$ apt-get install python-pip
$ pip install sh
$ strace -f -e close python -c "import sh; sh.nice()" 2>&1 | wc -l
1048796
Running strace with output in different files. There is one too big strace.2618
$ strace -ff -o strace python -c "import sh; sh.nice()"
$ ls -la
total 75276
drwxrwxr-x 2 user user 4096 Sep 27 16:58 .
drwxr-xr-x 41 user user 4096 Sep 27 16:45 ..
-rw-r--r-- 1 root root 121780 Sep 27 16:33 strace.2615
-rw-r--r-- 1 root root 3995 Sep 27 16:33 strace.2616
-rw-r--r-- 1 root root 6108 Sep 27 16:33 strace.2617
-rw-r--r-- 1 root root 76558803 Sep 27 16:33 strace.2618
-rw-r--r-- 1 root root 362363 Sep 27 16:33 strace.2619
-rw-r--r-- 1 root root 10748 Sep 27 16:33 strace.2620
The content of the file something like this:
$ cat strace.2618
...................
...................
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
close(3) = 0
close(4) = 0
close(5) = -1 EBADF (Bad file descriptor)
close(6) = -1 EBADF (Bad file descriptor)
close(7) = 0
close(8) = 0
close(9) = -1 EBADF (Bad file descriptor)
close(10) = 0
close(11) = -1 EBADF (Bad file descriptor)
...................
...................
close(33) = -1 EBADF (Bad file descriptor)
close(34) = -1 EBADF (Bad file descriptor)
close(35) = -1 EBADF (Bad file descriptor)
close(36) = -1 EBADF (Bad file descriptor)
close(37) = -1 EBADF (Bad file descriptor)
close(38) = -1 EBADF (Bad file descriptor)
...................
...................
close(1048568) = -1 EBADF (Bad file descriptor)
close(1048569) = -1 EBADF (Bad file descriptor)
close(1048570) = -1 EBADF (Bad file descriptor)
close(1048571) = -1 EBADF (Bad file descriptor)
close(1048572) = -1 EBADF (Bad file descriptor)
close(1048573) = -1 EBADF (Bad file descriptor)
close(1048574) = -1 EBADF (Bad file descriptor)
close(1048575) = -1 EBADF (Bad file descriptor)
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0