Por que o 'w' aqui requer mais chamadas de sistema do que um simples script python?

0

Eu gostaria de mergulhar mais fundo no Linux e ter jogado com uma boa ferramenta strace ( Versão: 4.11 ) no Ubuntu 16.04 LTS e estou curioso para saber por que chamar como o seguinte

# strace -c w

requer um número maior de chamadas de sistema do que, digamos, um script simples python que pode imprimir uma string 10 vezes?

Para ser mais específico, aqui está a saída de 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

Para 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

Inferência

  • w requer 1965 chamadas no total em comparação com 576 chamadas do script python.

Pergunta

  • Esta implementação é específica? Por exemplo, se eu tivesse escrito um código em C / C ++ em vez de python, as chamadas read seriam mais?

  • as chamadas aumentam com o aumento da complexidade do programa ou da ferramenta usada? Existe alguma correlação?

  • Por que há mais erros na execução do script em comparação com w ?

Nota

  • o script python é um loop simples que imprime Check como uma string 10 vezes e não tem nenhum nível de complexidade. (Código não incluído para brewity )
por Shan-Desai 25.01.2017 / 17:09

1 resposta

3

As chamadas do sistema são independentes da linguagem; é fácil escrever uma ferramenta em uma montagem mais lenta do que uma implementação equivalente em uma linguagem de alto nível, se alguém fizer uso ineficiente de chamadas do sistema; Um exemplo altamente planejado, porém simples, para ilustrar esse ponto seria:

$ 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

Onde ./max é o seguinte programa de montagem IA-64 para Linux:

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

Como compilado via

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

Os programas devem executar a mesma tarefa para que uma comparação direta seja válida.

As chamadas provavelmente aumentam geralmente com a complexidade da ferramenta usada, embora se possa inventar um caso contraditório de uma rede neural fantasticamente complicada que usa apenas sys_read (para obter entrada) sys_write (para emitir saída) e então talvez sys_exit . Eu acho que você poderia analisar o número de chamadas do sistema versus "complexidade" (talvez linhas de código?) E traçar isso para ver se há alguma tendência? (A leitura em "unikernel" pode ser informativa em relação à disputa de complexidade.)

A coluna de erro é quantos erros existem, como mostrado fechando a saída padrão e, em seguida, chamando algo que grava nela e, obviamente, falha:

$ 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
    
por 25.01.2017 / 19:03