'Gerçek', 'kullanıcı' ve 'sys' zamanın çıktısında ne anlama gelir?


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

Zamanın çıktısında 'gerçek', 'kullanıcı' ve 'sys' ne anlama geliyor?

Uygulamamı karşılaştırırken hangisi anlamlı?


2
bunlardan sadece birine nasıl erişebilirim? örneğin sadece gerçek zamanlı?
Mojtaba Ahmadi

1
@ConcernedOfTunbridgeWells
Mojtaba Ahmadi


7
Programınız bu kadar hızlı çıkarsa, hiçbiri anlamlı değildir, hepsi sadece başlangıç ​​ek yüküdür. Tüm programı ölçmek istiyorsanız, programın timeen az bir saniye sürecek bir şey yapmasını sağlayın.
Peter Cordes

5
Bunun timebir bash anahtar kelimesi olduğunu belirtmek gerçekten önemlidir . Yani yazarak man timeedilir değil partisi yüzünden size bir adam sayfası vererek time, daha çok man sayfasını veriyor /usr/bin/time. Bu beni harekete geçirdi.
irritable_phd_syndrom

Yanıtlar:


2060

Gerçek, Kullanıcı ve Sys işlem süresi istatistikleri

Bunlardan biri diğeri gibi değil. Gerçek, geçen gerçek zamanı ifade eder; Kullanıcı ve Sys yalnızca işlem tarafından kullanılan CPU zamanını ifade eder .

  • Gerçek duvar saati süresidir - çağrının başından sonuna kadar geçen süredir. Bunların tümü, diğer işlemler tarafından kullanılan zaman dilimleri ve işlemin engelleneceği zaman da dahil olmak üzere geçen süredir (örneğin G / Ç'nin tamamlanmasını bekliyorsa).

  • Kullanıcı (Çekirdek dışında) kullanıcı modu kodu harcanan CPU süredir içinde süreç. Bu, yalnızca işlemin yürütülmesinde kullanılan gerçek CPU süresidir. İşlemin bloke edildiği diğer işlemler ve süre bu şekle dahil değildir.

  • Sys , işlem içinde çekirdeğe harcanan CPU zamanıdır. Bu , kullanıcı alanında hala çalışan kütüphane kodunun aksine , çekirdek içindeki sistem çağrılarında harcanan CPU zamanının yürütülmesi anlamına gelir . 'Kullanıcı' gibi, bu da yalnızca işlem tarafından kullanılan CPU süresidir. Çekirdek modunun ('süpervizör' modu olarak da bilinir) ve sistem çağrı mekanizmasının kısa bir açıklaması için aşağıya bakın.

User+Sysişleminizin ne kadar gerçek CPU zamanı kullandığını size söyleyecektir. Bunun tüm CPU'lar arasında olduğunu unutmayın, bu nedenle işlemin birden fazla iş parçacığı varsa (ve bu işlem birden fazla işlemciye sahip bir bilgisayarda çalışıyorsa), bildirilen duvar saati süresini aşabilir Real(genellikle oluşur). Çıktıda bu rakamların tüm alt süreçlerin (ve onların torunlarının) Userve Syszamanını içerdiğini , örneğin wait(2)ya da tarafından waitpid(2)temel alınan sistem çağrıları, sürecin ve çocuklarının ayrı ayrı istatistiklerini döndürmesine rağmen, ya da tarafından toplanabileceklerini unutmayın .

Tarafından rapor edilen istatistiklerin kökenleri time (1)

Tarafından rapor edilen istatistikler timeçeşitli sistem çağrılarından toplanır. 'Kullanıcı' ve 'Sistem' , ilgili sisteme bağlı olarak wait (2)( POSIX ) veya times (2)( POSIX ) 'ten gelir . 'Gerçek' gettimeofday (2)çağrıdan toplanan bir başlangıç ​​ve bitiş zamanından hesaplanır . Sistemin sürümüne bağlı olarak, bağlam anahtarlarının sayısı gibi çeşitli diğer istatistikler de toplanabilir time.

Çok işlemcili bir makinede, çok iş parçacıklı bir işlem veya çocukları çatallayan bir işlemin toplam CPU süresinden daha kısa geçen bir süresi olabilir - farklı iş parçacıkları veya işlemler paralel olarak çalışabilir. Ayrıca, rapor edilen zaman istatistikleri farklı kökenlerden gelir, bu nedenle çok kısa çalışan görevler için kaydedilen süreler, orijinal posterde verilen örnekte gösterildiği gibi yuvarlama hatalarına maruz kalabilir.

Çekirdek ve Kullanıcı modu hakkında kısa bir astar

Unix'te veya herhangi bir korumalı bellek işletim sisteminde, 'Çekirdek' veya 'Süpervizör' modu , CPU'nun çalışabileceği ayrıcalıklı bir modu ifade eder . Güvenliği veya kararlılığı etkileyebilecek bazı ayrıcalıklı eylemler yalnızca CPU çalışırken kullanılabilir bu mod; bu eylemler uygulama kodu tarafından kullanılamaz. Böyle bir eylemin bir örneği , başka bir işlemin adres alanına erişmek için MMU'nun manipülasyonu olabilir . Normalde, kullanıcı modu o talep edebilirse de kod, bu (ile iyi bir nedeni) yapamaz paylaşılan hafızayı çekirdeğinden hangi couldbirden fazla işlemle okunabilir veya yazılabilir. Bu durumda, paylaşılan bellek çekirdekten güvenli bir mekanizma aracılığıyla açıkça istenir ve her iki işlem de kullanmak için belleğe açıkça bağlanmak zorundadır.

Ayrıcalıklı moda genellikle 'çekirdek' modu denir, çünkü çekirdek bu modda çalışan CPU tarafından yürütülür. Çekirdek moduna geçmek için , CPU'yu çekirdek modunda çalışmaya geçiren ve atlama tablosunda tutulan belirli bir konumdan kod çalıştıran belirli bir talimat (genellikle tuzak olarak adlandırılır ) vermeniz gerekir . Güvenlik nedeniyle, çekirdek moduna geçemez ve rasgele kod yürütemezsiniz - tuzaklar, CPU denetleyici modunda çalışmadığı sürece yazılamayan bir adres tablosu aracılığıyla yönetilir. Açık bir tuzak numarası ile tuzak ve adres atlama tablosunda aranır; çekirdek sınırlı sayıda kontrollü giriş noktasına sahiptir.

C kütüphanesindeki 'sistem' çağrıları (özellikle man sayfalarının 2. Bölümünde tarif edilenler) bir kullanıcı modu bileşenine sahiptir, ki bu aslında C programınızdan çağırırsınız. Perde arkasında, G / Ç gibi belirli hizmetleri yapmak için çekirdeğe bir veya daha fazla sistem çağrısı yapabilirler, ancak yine de kullanıcı modunda çalışan kodları vardır. İsterseniz, herhangi bir kullanıcı alanı kodundan doğrudan çekirdek moduna bir tuzak vermek de mümkündür, ancak çağrı için kayıtları doğru bir şekilde ayarlamak için bir montaj dil snippet'i yazmanız gerekebilir.

'Sys' hakkında daha fazla bilgi

Kodunuzun kullanıcı modundan yapamayacağı şeyler vardır - bellek ayırma veya donanıma (HDD, ağ vb.) Erişme gibi şeyler. Bunlar çekirdeğin gözetimi altındadır ve tek başına bunları yapabilir. Bazı çekirdek işlevleri gibi mallocveya fread/ veya fwritebu işlemler çağrılacaktır ve bu işlem 'sys' zamanı olarak sayılır. Ne yazık ki, "malloc'a yapılan her çağrı 'sys' zamanında sayılacak" kadar basit değil. Çağrı malloc, kendi işlemlerini gerçekleştirir (hala 'kullanıcı' zamanında sayılır) ve daha sonra işlevi çekirdek içinde ('sys' zamanında sayılır) çağırabileceği yol boyunca bir yerde yapılır. Çekirdek çağrısından döndükten sonra, 'kullanıcı'da biraz daha zaman olacak vemallockodunuza geri dönecektir. Anahtarın ne zaman gerçekleştiğine ve bunun çekirdek modunda ne kadar harcandığına gelince ... söyleyemezsiniz. Kütüphanenin uygulanmasına bağlıdır. Ayrıca, görünüşte masum olan diğer fonksiyonlar da mallocarka planda kullanılabilir ve benzerleri, o zaman yine 'sys'de biraz zaman geçirir.


15
Çocuk süreçleri tarafından harcanan zaman gerçek / sys olarak sayılıyor mu?
ron

1
@ron - Linux man sayfasına göre, 'c' sürelerini işlem süreleriyle birleştiriyor, bence öyle. Ebeveyn saatleri ve çocuk saatleri (2) çağrısından ayrı olarak mevcuttur. Solaris / SysV versiyonunun (1) benzer bir şey yaptığını tahmin ediyorum.
ConcernedOfTunbridgeWells

3
Kullanıcı + Sys, bir işlemin CPU kullanımını ölçmenizi sağlar. Performansı karşılaştırmak için kullanabilirsiniz. Bu özellikle bir hesaplama üzerinde birden fazla CPU çekirdeğinin çalışabileceği çok iş parçacıklı kod için kullanışlıdır.
ConcernedOfTunbridgeWells

1
Tam olarak konuya değil, yine de: "\ time <cmd>" çalıştırmak ilginç - daha fazla ayrıntı sağlar: (yorumda zayıf biçimlendirmeyi affet): $ time ps PID TTY TIME CMD 9437 puan / 19 00:00:00 bash 11459 pts / 19 00:00:00 ps gerçek 0m0.025s kullanıcı 0m0.004s sys 0m0.018s $ \ time ps PID TTY TIME CMD 9437 puan / 19 00:00:00 bash 11461 puan / 19 00:00:00 zaman 11462 pts / 19 00:00:00 ps 0.00user 0.01sistem 0: 00.02elmiş% 95 CPU (0avgtext + 0avgdata 2160maxresident) k 0 girişler + 0 çıkışlar (0major + 103minor) pagefaults 0swaps $
kaiwan 9:15

1
(Önceki yorumda karakter tükendi): Daha fazla ayrıntı? Perf [1], [2] kullanın. [1] perf.wiki.kernel.org/index.php/Main_Page [2] brendangregg.com/perf.html
kaiwan

286

Kabul edilen cevabı genişletmek için sadece realuser+ 'nın başka bir nedenini sunmak istedim sys.

realGerçek geçen süreyi userve sysdeğerlerin CPU yürütme süresini temsil ettiğini unutmayın . Sonuç olarak, bir çok çekirdekli sistemi üzerinde userve / veya syssüresi (aynı zamanda bunların toplamı) gerçekten yapabilen aşan gerçek zamanlı. Örneğin, sınıf için çalıştırdığım bir Java uygulamasında bu değerler kümesini alıyorum:

real    1m47.363s
user    2m41.318s
sys     0m4.013s

11
Bunu hep merak ederdim. Programlarımın tek iş parçacıklı olduğunu bildiğim için, kullanıcı ile gerçek zamanlı arasındaki fark VM yükü olmalı, doğru mu?
Quantum7

9
şart değil; Solaris makinelerde Sun JVM ve Mac OS X üzerinde Apple'ın JVM'si tek iş parçacıklı uygulamalarda bile birden fazla çekirdek kullanmayı başarıyor. Java işleminin bir örneğini yaparsanız, çöp toplama gibi şeylerin ayrı iş parçacıklarında (ve başımın üstünden hatırlamadığım başka şeyler) çalıştığını görürsünüz. Gerçi bu "VM ek yükü" terimini gerçekten belirtmek isteyip istemediğinizi bilmiyorum.
lensovet

4
Sanırım oyların miktarı size yeterince ün kazandırdı: D. Peki, realaşma userve systoplam hakkında ne düşünüyorsunuz ? Iş parçacığı bağlam anahtarlama gibi OS yükü olabilir?
Muhammad Gelbana

19
Başka bir potansiyel sorun G / Ç olabilir: uygulamanız bir dosya veya akış almak için çok fazla zaman harcarsa, o zaman gerçek zaman kullanıcı / sys süresini büyük ölçüde aşacaktır, çünkü erişim elde etmeyi beklerken CPU zamanı kullanılmaz bir dosyaya veya benzer bir şeye.
lensovet

1
@MuhammadGelbana - uygulamanın herhangi bir nedenle yürütülmesi engellenirse bu gerçekleşebilir. Örneğin, G / Ç, IPC veya soket bağlantılarında bekliyorsa, boşta kalarak engelleme çağrısı geri gelene kadar CPU zamanı biriktirmez.
ConcernedOfTunbridgeWells

41

gerçek : İşlemi baştan sona çalıştırmak için harcanan gerçek zaman, sanki kronometreli bir insan tarafından ölçülmüş gibi

kullanıcı : Hesaplama sırasında tüm CPU'lar tarafından harcanan toplam süre

sys : Bellek ayırma gibi sistemle ilgili görevler sırasında tüm CPU'lar tarafından harcanan toplam süre.

Birden çok işlemci paralel çalışabileceğinden, bazen kullanıcı + sys değerinin gerçek değerden daha büyük olabileceğine dikkat edin.


sysçağrıları (ve sayfa hatası işleyicileri için harcanan CPU zamanı) nedir?
Peter Cordes

1
realgenellikle "duvar saati" zamanı olarak tanımlanır.
Peter Cordes

30

Minimum çalıştırılabilir POSIX C örnekleri

İşleri daha somut hale getirmek için time, bazı minimum C test programlarıyla ilgili birkaç uç durumu örneklendirmek istiyorum .

Tüm programlar aşağıdakilerle derlenebilir ve çalıştırılabilir:

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

ve Ubuntu 18.10, GCC 8.2.0, glibc 2.28, Linux çekirdeği 4.18, ThinkPad P51 dizüstü bilgisayar, Intel Core i7-7820HQ CPU (4 çekirdek / 8 iş parçacığı), 2x Samsung M471A2K43BB1-CRC RAM (2x 16GiB) ile test edilmiştir.

uyku

Sigara meşgul uyku saymak ya gelmez userya syssadece real.

Örneğin, bir saniyeliğine uyuyan bir program:

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

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

GitHub akış yukarı .

gibi bir şey çıktılar:

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

Aynı şey ES'nin kullanıma sunulmasıyla engellenen programlar için de geçerlidir.

Örneğin, aşağıdaki program kullanıcının bir karakter girmesini ve enter tuşuna basmasını bekler:

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

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

GitHub akış yukarı .

Ve yaklaşık bir saniye beklerseniz, uyku örneğinde olduğu gibi çıktı:

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

Bu nedenle timeCPU ve IO bağlı programları ayırt etmenize yardımcı olabilir: "CPU bağlı" ve "I / O bağlı" terimleri ne anlama gelir?

Birden çok iş parçacığı

Aşağıdaki örnek, nitersnthreadsparçacığı üzerinde tamamen CPU'ya bağlı yararsız yinelemeler yapar :

#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 akış yukarı + çizim kodu .

Sonra 8 hiper-iplik işlemcimdeki sabit 10 ^ 10 yinelemeleri için iş parçacığı sayısının bir fonksiyonu olarak wall, user ve sys'yi çiziyoruz:

resim açıklamasını buraya girin

Verileri çizin .

Grafikten şunu görüyoruz:

  • CPU yoğunluklu tek çekirdekli bir uygulama için duvar ve kullanıcı hemen hemen aynıdır

  • 2 çekirdek için, kullanıcı yaklaşık 2x duvardır, yani kullanıcı süresi bütün dişlerde sayılır.

    kullanıcı temelde iki katına çıktı ve duvar aynı kaldı.

  • Bu, bilgisayarımdaki hyperthreads sayımla eşleşen 8 iş parçacığına kadar devam eder.

    8'den sonra, duvar da artmaya başlar, çünkü belirli bir sürede daha fazla iş koyacak ekstra CPU'larımız yok!

    Bu noktada yaylalar oranı.

Hafıza bağlanmış olsaydı tarafta gösterildiği gibi hafıza erişimler bir darboğaz olacaktır çünkü, o zaman çok daha erken az çekirdekli performansında bir düşüş alacağı: iş tamamen CPU bağımlı olduğundan bu grafik yalnızca bu kadar açık ve basit olduğunu Not Ne CPU bağlı "ve" I / O bağlı "terimleri ne anlama geliyor?

Sys ağır iş ile sendfile

Gelebildiğim en ağır sys iş yükü sendfile, çekirdek alanında bir dosya kopyalama işlemi yapan: Dosyayı aklı başında, güvenli ve verimli bir şekilde kopyalamaktı.

Bu yüzden, bu çekirdek içi memcpyCPU yoğunluklu bir işlem olacağını hayal ettim .

İlk önce büyük bir 10GiB rastgele dosya ile başlat:

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

Sonra kodu çalıştırın:

#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 akış yukarı .

temelde çoğunlukla beklendiği gibi sistem zamanı verir:

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

Ayrıca timefarklı süreçlerin sistem çağrılarını ayırt edip etmeyeceğini merak ettim, bu yüzden denedim:

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

Ve sonuç şuydu:

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

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

Sys süresi her ikisi için de tek bir işlemle aynıdır, ancak işlemler disk okuma erişimi için rekabet edebileceğinden duvar süresi daha büyüktür.

Öyle görünüyor ki aslında hangi sürecin belirli bir çekirdek çalışmasını başlattığını açıklıyor.

Bash kaynak kodu

Yalnızca time <cmd>Ubuntu'da yaptığınızda, Bash anahtar sözcüğünü şu şekilde görülebileceği gibi kullanır:

type time

hangi çıktılar:

time is a shell keyword

Bu yüzden çıkış dizesi için Bash 4.19 kaynak kodunda grep kaynağı:

git grep '"user\b'

hangi potansiyel müşteriler bize execute_cmd.c fonksiyonu time_commandkullanır:

  • gettimeofday()ve getrusage()eğer ikisi de mevcutsa
  • times() aksi takdirde

bunların hepsi Linux sistem çağrıları ve POSIX işlevleridir .

GNU Coreutils kaynak kodu

Biz şöyle diyoruz:

/usr/bin/time

daha sonra GNU Coreutils uygulamasını kullanır.

Bu biraz daha karmaşık, ancak ilgili kaynak yeniden kullanımda gibi görünüyor. C ve öyle:

  • wait3varsa POSIX olmayan bir BSD çağrısı
  • timesve gettimeofdaybaşka türlü

14

Real, bir işlem için toplam geri dönüş süresini gösterir; Kullanıcı, kullanıcı tanımlı talimatlar için yürütme süresini gösterirken Sys sistem çağrılarını yürütme zamanıdır!

Gerçek zamanlı bekleme süresini de içerir (G / Ç vb. İçin bekleme süresi)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.