Apa arti 'nyata', 'pengguna' dan 'sistem' dalam output waktu (1)?

1750
$ time foo
real        0m0.003s
user        0m0.000s
sys         0m0.004s
$

Apa arti 'nyata', 'pengguna' dan 'sistem' dalam output waktu?

Yang mana yang berarti ketika membandingkan aplikasi saya?

rayryeng
sumber
2
bagaimana saya bisa mengakses hanya ke salah satu dari mereka? misalnya hanya waktu nyata?
Mojtaba Ahmadi
1
@ConcernedOfTunbridgeWells
Mojtaba Ahmadi
2
@Casillass Real - stackoverflow.com/questions/2408981/…
ConcernedOfTunbridgeWells
7
Jika program Anda keluar secepat itu, tidak ada yang bermakna, itu semua hanya overhead startup. Jika Anda ingin mengukur keseluruhan program time, minta ia melakukan sesuatu yang akan memakan waktu setidaknya satu detik.
Peter Cordes
5
Sangat penting untuk dicatat bahwa itu timeadalah kata kunci bash. Jadi mengetik man timeini tidak memberikan Anda halaman manual untuk bash time, melainkan memberikan halaman manual untuk /usr/bin/time. Ini telah membuat saya tersandung.
irritable_phd_syndrom

Jawaban:

2064

Statistik waktu proses nyata, Pengguna dan Sys

salah satu dari benda ini tidak seperti yang lain. Real mengacu pada waktu aktual yang telah berlalu; Pengguna dan Sistem mengacu pada waktu CPU yang hanya digunakan oleh proses.

  • Real adalah jam dinding - waktu dari awal hingga akhir panggilan. Ini semua waktu yang telah berlalu termasuk irisan waktu yang digunakan oleh proses lain dan waktu proses yang dihabiskan diblokir (misalnya jika menunggu I / O untuk menyelesaikan).

  • Pengguna adalah jumlah waktu CPU yang dihabiskan dalam kode mode pengguna (di luar kernel) dalam proses. Ini hanya waktu CPU aktual yang digunakan dalam menjalankan proses. Proses dan waktu lain yang dihabiskan proses tidak termasuk dalam angka ini.

  • Sys adalah jumlah waktu CPU yang dihabiskan di kernel dalam proses. Ini berarti mengeksekusi waktu CPU yang dihabiskan dalam panggilan sistem di dalam kernel, sebagai lawan dari kode perpustakaan, yang masih berjalan di ruang pengguna. Seperti 'pengguna', ini hanya waktu CPU yang digunakan oleh proses. Lihat di bawah untuk penjelasan singkat tentang mode kernel (juga dikenal sebagai mode 'supervisor') dan mekanisme panggilan sistem.

User+Sysakan memberi tahu Anda berapa sebenarnya waktu CPU yang digunakan proses Anda. Perhatikan bahwa ini ada di semua CPU, jadi jika prosesnya memiliki banyak utas (dan proses ini berjalan pada komputer dengan lebih dari satu prosesor) ini berpotensi melebihi waktu jam dinding yang dilaporkan oleh Real(yang biasanya terjadi). Perhatikan bahwa dalam output angka-angka ini termasuk waktu Userdan Syssemua proses anak (dan turunannya) serta kapan mereka bisa dikumpulkan, misalnya oleh wait(2)atauwaitpid(2) , meskipun sistem yang mendasari panggilan mengembalikan statistik untuk proses dan anak-anaknya secara terpisah.

Asal-usul statistik yang dilaporkan oleh time (1)

Statistik yang dilaporkan timedikumpulkan dari berbagai panggilan sistem. 'Pengguna' dan 'Sistem' berasal dari wait (2)( POSIX ) atau times (2)( POSIX ), tergantung pada sistem tertentu. 'Nyata' dihitung dari waktu mulai dan berakhir dikumpulkan dari gettimeofday (2)panggilan. Bergantung pada versi sistem, berbagai statistik lain seperti jumlah sakelar konteks juga dapat dikumpulkan time.

Pada mesin multi-prosesor, proses multi-utas atau proses forking anak dapat memiliki waktu yang berlalu lebih kecil dari total waktu CPU - karena berbagai utas atau proses dapat berjalan secara paralel. Juga, statistik waktu yang dilaporkan berasal dari asal yang berbeda, jadi waktu yang direkam untuk tugas yang berjalan sangat singkat dapat mengalami kesalahan pembulatan, seperti contoh yang diberikan oleh poster asli menunjukkan.

Primer singkat tentang mode Kernel vs. Pengguna

Pada Unix, atau sistem operasi memori terproteksi, mode 'Kernel' atau 'Supervisor' mengacu pada mode istimewa yang dapat dioperasikan CPU. Tindakan istimewa tertentu yang dapat memengaruhi keamanan atau stabilitas hanya dapat dilakukan ketika CPU beroperasi di mode ini; tindakan ini tidak tersedia untuk kode aplikasi. Contoh dari tindakan semacam itu mungkin adalah manipulasi MMU untuk mendapatkan akses ke ruang alamat proses lain. Biasanya, kode mode pengguna tidak dapat melakukan ini (dengan alasan yang baik), meskipun dapat meminta memori bersama dari kernel, yang bisadibaca atau ditulis oleh lebih dari satu proses. Dalam hal ini, memori bersama secara eksplisit diminta dari kernel melalui mekanisme aman dan kedua proses harus secara eksplisit melampirkan padanya untuk menggunakannya.

Mode istimewa biasanya disebut sebagai mode 'kernel' karena kernel dijalankan oleh CPU yang berjalan dalam mode ini. Untuk beralih ke mode kernel Anda harus mengeluarkan instruksi khusus (sering disebut jebakan ) yang mengalihkan CPU untuk berjalan dalam mode kernel dan menjalankan kode dari lokasi tertentu yang disimpan dalam tabel lompatan. Untuk alasan keamanan, Anda tidak dapat beralih ke mode kernel dan menjalankan kode arbitrer - jebakan dikelola melalui daftar alamat yang tidak dapat dituliskan kecuali CPU sedang berjalan dalam mode supervisor. Anda menjebak dengan nomor perangkap eksplisit dan alamatnya terlihat di tabel lompatan; kernel memiliki sejumlah titik masuk yang terkontrol.

Panggilan 'sistem' di pustaka C (khususnya yang dijelaskan dalam Bagian 2 halaman manual) memiliki komponen mode pengguna, yang sebenarnya Anda panggil dari program C Anda. Di belakang layar, mereka mungkin mengeluarkan satu atau lebih panggilan sistem ke kernel untuk melakukan layanan tertentu seperti I / O, tetapi mereka juga masih memiliki kode yang berjalan dalam mode pengguna. Dimungkinkan juga untuk secara langsung mengeluarkan jebakan ke mode kernel dari kode ruang pengguna mana pun jika diinginkan, walaupun Anda mungkin perlu menulis cuplikan bahasa rakitan untuk mengatur register dengan benar untuk panggilan tersebut.

Lebih lanjut tentang 'sys'

Ada beberapa hal yang tidak bisa dilakukan oleh kode Anda dari mode pengguna - hal-hal seperti mengalokasikan memori atau mengakses perangkat keras (HDD, jaringan, dll.). Ini berada di bawah pengawasan kernel, dan itu saja yang dapat melakukannya. Beberapa operasi seperti mallocatau fread/ fwriteakan menjalankan fungsi-fungsi kernel ini dan itu akan dihitung sebagai waktu 'sys'. Sayangnya itu tidak sesederhana "setiap panggilan ke malloc akan dihitung dalam waktu 'sys'". Panggilan untuk mallocakan melakukan pemrosesan sendiri (masih dihitung dalam waktu 'pengguna') dan kemudian di suatu tempat di sepanjang jalan itu dapat memanggil fungsi dalam kernel (dihitung dalam waktu 'sys'). Setelah kembali dari panggilan kernel, akan ada lebih banyak waktu di 'pengguna' dan kemudianmalloc akan kembali ke kode Anda. Adapun ketika saklar terjadi, dan berapa banyak yang dihabiskan dalam mode kernel ... Anda tidak bisa mengatakannya. Itu tergantung pada implementasi perpustakaan. Juga, fungsi-fungsi lain yang tampaknya tidak bersalah juga dapat digunakan mallocdan sejenisnya di latar belakang, yang lagi-lagi akan memiliki waktu di 'sys'.

ConcernedOfTunbridgeWells
sumber
15
Apakah waktu yang dihabiskan oleh proses anak masuk dalam hitungan nyata?
ron
1
@ron - Menurut halaman manual Linux, ini mengagregasi waktu 'c' dengan waktu proses, jadi saya pikir memang demikian. Waktu induk dan waktu anak tersedia secara terpisah dari waktu (2) panggilan, meskipun. Saya kira versi Solaris / SysV waktu (1) melakukan sesuatu yang serupa.
ConcernedOfTunbridgeWells
3
User + Sys memungkinkan Anda mengukur penggunaan CPU dari suatu proses. Anda dapat menggunakannya untuk mengukur kinerja. Ini sangat berguna untuk kode multi-threaded di mana lebih dari satu inti CPU mungkin bekerja pada perhitungan.
ConcernedOfTunbridgeWells
1
Namun tidak tepat pada topik: Menjalankan "\ time <cmd>" menarik - ia memberikan lebih detail: (maafkan pemformatan yang buruk dalam komentar): $ time ps PID TTY WAKTU CMD 9437 poin / 19 00:00:00 bash 11459 Poin / 19 00:00:00 ps nyata 0m0.025s pengguna 0m0.004s sys 0m0.018s $ \ waktu ps PID TTY WAKTU CMD 9437 Poin / 19 00:00:00 bash 11461 Poin / 19 00:00:00 waktu 11462 Poin / 19 00:00:00 ps 0.00user 0.01system 0: 00.02elapsed 95% CPU (0avgtext + 0avgdata 2160maxresident) 0inputs k + 0outputs (0major + 103minor) pagefaults 0swaps $
kaiwan
1
(Kehabisan karakter di komentar sebelumnya jadi): Lebih detail? Gunakan perf [1], [2]. [1] perf.wiki.kernel.org/index.php/Main_Page [2] brendangregg.com/perf.html
kaiwan
286

Untuk memperluas jawaban yang diterima , saya hanya ingin memberikan alasan lain mengapa realuser+ sys.

Ingatlah bahwa itu realmewakili waktu berlalu sebenarnya, sementara userdan sysnilai - nilai mewakili waktu eksekusi CPU. Akibatnya, pada sistem multicore, waktu userdan / atau syswaktu (serta jumlah mereka) benar-benar dapat melebihi waktu sebenarnya. Misalnya, pada aplikasi Java yang saya jalankan untuk kelas saya mendapatkan serangkaian nilai ini:

real    1m47.363s
user    2m41.318s
sys     0m4.013s
lensovet
sumber
11
Saya selalu bertanya-tanya tentang ini. Karena saya tahu bahwa program saya satu threaded, perbedaan antara pengguna dan waktu nyata harus overhead VM, benar?
Quantum7
9
belum tentu; Sun JVM pada mesin Solaris serta JVM Apple pada Mac OS X berhasil menggunakan lebih dari satu inti bahkan dalam aplikasi single-threaded. Jika Anda melakukan sampel proses java, Anda akan melihat bahwa hal-hal seperti pengumpulan sampah dijalankan pada utas yang terpisah (dan beberapa hal lain juga yang saya tidak ingat dari atas kepala saya). Saya tidak tahu apakah Anda benar-benar ingin menyebut "VM overhead" itu.
lensovet
4
Saya kira jumlah suara-up memberi Anda reputasi yang cukup sekarang: D. Jadi, apa yang Anda pikirkan tentang realmelebihi userdan systotal? OS overhead seperti switching konteks konteks mungkin?
Muhammad Gelbana
19
Masalah potensial lainnya adalah I / O: jika aplikasi Anda menghabiskan banyak waktu menunggu untuk menerima file atau streaming, maka jelas waktu nyata akan sangat melebihi waktu pengguna / sistem karena tidak ada waktu CPU digunakan saat menunggu untuk mendapatkan akses ke file atau yang serupa.
lensovet
1
@MuhammadGelbana - ini bisa terjadi jika aplikasi diblokir dari mengeksekusi karena alasan apa pun. Misalnya, jika menunggu pada I / O, IPC atau koneksi soket, ia akan diam, tidak mengakumulasi waktu CPU hingga panggilan yang diblokir kembali.
ConcernedOfTunbridgeWells
41

nyata : Waktu aktual yang dihabiskan dalam menjalankan proses dari awal hingga selesai, seolah-olah itu diukur oleh manusia dengan stopwatch

pengguna : Waktu kumulatif yang dihabiskan oleh semua CPU selama perhitungan

sys : Waktu kumulatif yang dihabiskan oleh semua CPU selama tugas yang berkaitan dengan sistem seperti alokasi memori.

Perhatikan bahwa kadang-kadang pengguna + sistem mungkin lebih besar dari yang sebenarnya, karena beberapa prosesor dapat bekerja secara paralel.

varun
sumber
syswaktu CPU dihabiskan untuk panggilan sistem (dan penangan kesalahan halaman?)
Peter Cordes
1
realsering digambarkan sebagai waktu "jam dinding".
Peter Cordes
30

Contoh POSIX C runnable minimal

Untuk membuat segalanya lebih konkret, saya ingin memberikan contoh beberapa kasus ekstrem timedengan beberapa program uji C minimal.

Semua program dapat dikompilasi dan dijalankan dengan:

gcc -ggdb3 -o main.out -pthread -std=c99 -pedantic-errors -Wall -Wextra main.c
time ./main.out

dan telah diuji di Ubuntu 18.10, GCC 8.2.0, glibc 2.28, kernel Linux 4.18, laptop ThinkPad P51, CPU Intel Core i7-7820HQ (4 core / 8 thread), 2x Samsung M471A2K43BB1-CRC RAM (2x 16GiB).

tidur

Tidur yang tidak sibuk tidak dihitung dalam salah satu useratau sys, hanya real.

Misalnya, program yang tidur sebentar:

#define _XOPEN_SOURCE 700
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    sleep(1);
    return EXIT_SUCCESS;
}

GitHub hulu .

menghasilkan sesuatu seperti:

real    0m1.003s
user    0m0.001s
sys     0m0.003s

Hal yang sama berlaku untuk program yang diblokir pada IO menjadi tersedia.

Misalnya, program berikut menunggu pengguna untuk memasukkan karakter dan tekan enter:

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

int main(void) {
    printf("%c\n", getchar());
    return EXIT_SUCCESS;
}

GitHub hulu .

Dan jika Anda menunggu sekitar satu detik, itu output seperti contoh tidur seperti:

real    0m1.003s
user    0m0.001s
sys     0m0.003s

Untuk alasan ini timedapat membantu Anda membedakan antara program terikat CPU dan IO: Apa arti istilah "terikat CPU" dan "I / O terikat"?

Beberapa utas

Contoh berikut melakukan nitersiterasi dari pekerjaan CPU-murni yang tidak berguna pada nthreadsutas:

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

uint64_t niters;

void* my_thread(void *arg) {
    uint64_t *argument, i, result;
    argument = (uint64_t *)arg;
    result = *argument;
    for (i = 0; i < niters; ++i) {
        result = (result * result) - (3 * result) + 1;
    }
    *argument = result;
    return NULL;
}

int main(int argc, char **argv) {
    size_t nthreads;
    pthread_t *threads;
    uint64_t rc, i, *thread_args;

    /* CLI args. */
    if (argc > 1) {
        niters = strtoll(argv[1], NULL, 0);
    } else {
        niters = 1000000000;
    }
    if (argc > 2) {
        nthreads = strtoll(argv[2], NULL, 0);
    } else {
        nthreads = 1;
    }
    threads = malloc(nthreads * sizeof(*threads));
    thread_args = malloc(nthreads * sizeof(*thread_args));

    /* Create all threads */
    for (i = 0; i < nthreads; ++i) {
        thread_args[i] = i;
        rc = pthread_create(
            &threads[i],
            NULL,
            my_thread,
            (void*)&thread_args[i]
        );
        assert(rc == 0);
    }

    /* Wait for all threads to complete */
    for (i = 0; i < nthreads; ++i) {
        rc = pthread_join(threads[i], NULL);
        assert(rc == 0);
        printf("%" PRIu64 " %" PRIu64 "\n", i, thread_args[i]);
    }

    free(threads);
    free(thread_args);
    return EXIT_SUCCESS;
}

GitHub kode hulu + plot .

Kemudian kami memplot wall, user dan sys sebagai fungsi dari jumlah utas untuk iterasi 10 ^ 10 yang diperbaiki pada CPU 8 hyperthread saya:

masukkan deskripsi gambar di sini

Plot data .

Dari grafik, kita melihat bahwa:

  • untuk aplikasi inti tunggal CPU intensif, dinding dan pengguna hampir sama

  • untuk 2 core, pengguna sekitar 2x dinding, yang berarti bahwa waktu pengguna dihitung di semua utas.

    pengguna pada dasarnya dua kali lipat, dan sementara dinding tetap sama.

  • ini berlanjut hingga 8 utas, yang cocok dengan jumlah hyperthreads saya di komputer saya.

    Setelah 8, dinding mulai meningkat juga, karena kami tidak memiliki CPU tambahan untuk membuat lebih banyak pekerjaan dalam jumlah waktu tertentu!

    Rasio dataran tinggi pada titik ini.

Perhatikan bahwa grafik ini hanya sangat jelas dan sederhana karena pekerjaan itu murni terikat CPU: jika itu terikat memori, maka kita akan mendapatkan penurunan kinerja jauh lebih awal dengan lebih sedikit core karena akses memori akan menjadi hambatan seperti yang ditunjukkan pada Apa arti dari istilah "CPU terikat" dan "I / O terikat"?

Sys kerja berat dengan sendfile

Beban kerja sys terberat yang dapat saya lakukan adalah menggunakan sendfile, yang melakukan operasi penyalinan file pada ruang kernel: Menyalin file dengan cara yang waras, aman dan efisien

Jadi saya membayangkan bahwa in-kernel ini memcpyakan menjadi operasi intensif CPU.

Pertama saya menginisialisasi file acak 10GiB besar dengan:

dd if=/dev/urandom of=sendfile.in.tmp bs=1K count=10M

Kemudian jalankan kodenya:

#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char *source_path, *dest_path;
    int source, dest;
    struct stat stat_source;
    if (argc > 1) {
        source_path = argv[1];
    } else {
        source_path = "sendfile.in.tmp";
    }
    if (argc > 2) {
        dest_path = argv[2];
    } else {
        dest_path = "sendfile.out.tmp";
    }
    source = open(source_path, O_RDONLY);
    assert(source != -1);
    dest = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    assert(dest != -1);
    assert(fstat(source, &stat_source) != -1);
    assert(sendfile(dest, source, 0, stat_source.st_size) != -1);
    assert(close(source) != -1);
    assert(close(dest) != -1);
    return EXIT_SUCCESS;
}

GitHub hulu .

yang pada dasarnya memberi sebagian besar waktu sistem seperti yang diharapkan:

real    0m2.175s
user    0m0.001s
sys     0m1.476s

Saya juga ingin tahu apakah timeakan membedakan antara syscall dari proses yang berbeda, jadi saya mencoba:

time ./sendfile.out sendfile.in1.tmp sendfile.out1.tmp &
time ./sendfile.out sendfile.in2.tmp sendfile.out2.tmp &

Dan hasilnya adalah:

real    0m3.651s
user    0m0.000s
sys     0m1.516s

real    0m4.948s
user    0m0.000s
sys     0m1.562s

Waktu sistem hampir sama untuk keduanya seperti untuk satu proses tunggal, tetapi waktu dinding lebih besar karena proses bersaing kemungkinan untuk akses baca disk.

Jadi tampaknya itu memang menjelaskan proses yang memulai kerja kernel yang diberikan.

Kode sumber bash

Ketika Anda melakukannya hanya time <cmd>di Ubuntu, ia menggunakan kata kunci Bash seperti yang dapat dilihat dari:

type time

yang keluaran:

time is a shell keyword

Jadi kami mengambil sumber dalam kode sumber Bash 4.19 untuk string keluaran:

git grep '"user\b'

yang mengarahkan kita ke fungsi execute_cmd.ctime_command , yang menggunakan:

  • gettimeofday()dan getrusage()jika keduanya tersedia
  • times() jika tidak

semuanya adalah panggilan sistem Linux dan fungsi POSIX .

Kode sumber GNU Coreutils

Jika kita menyebutnya sebagai:

/usr/bin/time

kemudian menggunakan implementasi GNU Coreutils.

Yang ini sedikit lebih rumit, tetapi sumber yang relevan tampaknya berada di resuse.c dan memang:

  • wait3panggilan BSD non-POSIX jika tersedia
  • timesdan gettimeofdaysebaliknya
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
14

Real menunjukkan total waktu penyelesaian untuk suatu proses; sementara Pengguna menunjukkan waktu eksekusi untuk instruksi yang ditentukan pengguna dan Sys adalah waktu untuk mengeksekusi panggilan sistem!

Waktu nyata juga mencakup waktu tunggu (waktu tunggu untuk I / O dll.)

susenj
sumber