为什么这里的“w”比简单的 python 脚本需要更多的系统调用?

为什么这里的“w”比简单的 python 脚本需要更多的系统调用?

我想潜入深处Linux更多并且一直在使用一个不错的工具strace(版本:4.11) 在Ubuntu 16.04 LTS我很好奇为什么像下面这样调用

# strace -c w

需要比简单的系统调用更多的数量Python可以打印字符串 10 次的脚本?

为了更具体,这里是输出strace -c w

USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
shan     tty7     :0               13:20    3:37m  8:14   0.72s /sbin/upstart --user
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 61.67    0.000037           0       487         4 open
 23.33    0.000014           0       478           read
 15.00    0.000009           0       485           close
  0.00    0.000000           0         3           write
  0.00    0.000000           0       226           stat
  0.00    0.000000           0        38           fstat
  0.00    0.000000           0        27           lseek
  0.00    0.000000           0        63           mmap
  0.00    0.000000           0        31           mprotect
  0.00    0.000000           0        14           munmap
  0.00    0.000000           0         5           brk
  0.00    0.000000           0        22           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         1           ioctl
  0.00    0.000000           0        19        19 access
  0.00    0.000000           0        30           alarm
  0.00    0.000000           0         2           socket
  0.00    0.000000           0         2         2 connect
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           uname
  0.00    0.000000           0        20           fcntl
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000060                  1965        27 total

为了strace -c /tmp/loop.py

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000160           9        18           getdents
  0.00    0.000000           0        54           read
  0.00    0.000000           0        10           write
  0.00    0.000000           0        44         2 open
  0.00    0.000000           0        45           close
  0.00    0.000000           0       108        16 stat
  0.00    0.000000           0        69           fstat
  0.00    0.000000           0        10           lstat
  0.00    0.000000           0        30         6 lseek
  0.00    0.000000           0        32           mmap
  0.00    0.000000           0        16           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0        14           brk
  0.00    0.000000           0        68           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0        13         1 ioctl
  0.00    0.000000           0         9         9 access
  0.00    0.000000           0        10           select
  0.00    0.000000           0         3           dup
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           fcntl
  0.00    0.000000           0         4         2 readlink
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           sysinfo
  0.00    0.000000           0         1           getuid
  0.00    0.000000           0         1           getgid
  0.00    0.000000           0         1           geteuid
  0.00    0.000000           0         1           getegid
  0.00    0.000000           0         1           sigaltstack
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           getrandom
------ ----------- ----------- --------- --------- ----------------
100.00    0.000160                   573        36 total

推理

  • w576与Python 脚本中的调用相比,总共需要 1965 次调用。

问题

  • 这个实现具体吗?即如果我用 C/C++ 而不是 python 编写代码,read调用会更多吗?

  • 调用是否会随着所使用的程序或工具的复杂性的增加而增加?有什么相关性吗?

  • 与执行脚本相比,为什么执行脚本时出现更多错误w

笔记

  • 这里的Python脚本是一个简单的循环,它打印查看作为字符串 10 次,并且没有任何复杂性。 (不包括代码啤酒

答案1

系统调用与语言无关;人们可以轻松地用汇编语言编写一个工具慢点如果系统调用的使用效率低下,则优于高级语言中的等效实现;一个精心设计但简单的例子来说明这一点是:

$ strace -c perl -e 'print "A"x9999' >/dev/null
...
100.00    0.000026                   224        23 total
$ strace -c ./max >/dev/null
...
100.00    0.000430                 10000           total

./max下面的 Linux 的 IA-64 汇编程序在哪里:

SECTION .text
Message: db "A"
global _start
_start:
mov r9,9999
_again:
        mov rax,1       ; sys_write
        mov rdi,1       ; stdout
        mov rsi,Message
        mov rdx,1
        syscall
        dec r9
        jnz _again
_finish:
        mov rax,60      ; sys_exit
        mov rdi,0       ; exit code
        syscall

通过编译

$ nasm -f elf64 -o max.o max.asm ; ld -o max max.o

节目必须执行相同的任务以使直接比较有效。

调用通常可能会随着所使用工具的复杂性而增加,尽管我们可以设计一种极其复杂的神经网络的矛盾情况,该神经网络只利用sys_read(获取输入)sys_write(发出输出),然后可能sys_exit。我想您可以分析系统调用的数量与“复杂性”(也许是代码行?)并绘制出来看看是否有任何趋势? (阅读“unikernel”可能会提供有关复杂性争论的信息。)

错误列是有多少错误,如关闭标准输出然后调用写入该内容的内容所示,然后显然失败:

$ strace -c ./max >&-
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000427           0      9999      9999 write
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.000427                 10000      9999 total

相关内容