2016-04-17 21 views
3

私は現在、オペレーティングシステムの操作のオーバーヘッドに取り組んでいます。システムコールのコスト

私は実際にシステムコールを行うためのコストを勉強しており、それを観察するための簡単なC++プログラムを開発しました。

#include <iostream> 
#include <unistd.h> 
#include <sys/time.h> 

uint64_t 
rdtscp(void) { 
    uint32_t eax, edx; 

    __asm__ __volatile__("rdtscp" //! rdtscp instruction 
       : "+a" (eax), "=d" (edx) //! output 
       : //! input 
       : "%ecx"); //! registers 

    return (((uint64_t)edx << 32) | eax); 
} 

int main(void) { 
    uint64_t before; 
    uint64_t after; 
    struct timeval t; 
    for (unsigned int i = 0; i < 10; ++i) { 
    before = rdtscp(); 
    gettimeofday(&t, NULL); 
    after = rdtscp(); 
    std::cout << after - before << std::endl; 
    std::cout << t.tv_usec << std::endl; 
    } 

    return 0; 
} 

このプログラムは非常に簡単です。

  • rdtscp関数は、RTDSCP命令(64ビットサイクルカウントを2つの32ビットレジスタにロードするプロセッサ命令)を呼び出すための単なるラッパーです。この機能は、タイミングを取るために使用されます。
  • 私は10回反復します。それぞれの反復で、私はgettimeofdayを呼び出し、それを実行するのに要した時間を(CPUサイクルの数として)決定します。

結果は全く予想外である:出力

8984 
64008 
376 
64049 
164 
64053 
160 
64056 
160 
64060 
160 
64063 
164 
64067 
160 
64070 
160 
64073 
160 
64077 

奇数ラインシステムコールを実行するために必要なサイクル数です。偶数行は、t.tv_usec(私が勉強しているシステムコールであるgettimeofdayによって設定される)の値を含んでいます。

私は、それが可能であることを本当に理解していません。サイクル数は、ほぼ10,000から約150に大幅に減少します。しかし、timeval構造体は各呼び出しで更新されます!

私は別のオペレーティングシステム(debianとmacos)で試してみたところ、結果は似ています。

キャッシュを使用しても、どのように可能かはわかりません。システムコールを作成すると、コンテキスト切り替えがユーザーモードからカーネルモードに切り替わる必要があり、時刻を更新するためにはクロックを読み取る必要があります。

誰かがアイデアを持っていますか?

+0

私は答えは分かりませんが、キャッシングがそれを説明しない理由は何故思いますか? – Pemdas

+6

これは、ダイナミックリンカによるシンボル解決の遅延(レイジーバインディング)になります。実行時に 'LD_BIND_NOW = 1'(Linux)または' DYLD_BIND_AT_LAUNCH = 1'(MacOS)でリンカにすべてのシンボルを解決させてください。 'gettimeofday()'に対する最初の呼び出しのサイクル数は大幅に減少するはずです。 – xbug

+0

良い考えですが、それは大幅に低下していますが、最初のコール(〜770サイクルは最初のコールでカウントされ、まだ150〜 –

答えて

3

答えは?別のシステムコールを試みてください。 What are vdso and vsyscall?

ショートバージョン:syscallは実行されませんが、カーネルはプロセスが時刻情報にアクセスできるメモリ領域をマップします。これは、Linuxでvsyscallsが実行されていることを示しています。コスト?あまり(コンテキストスイッチなし)。

+0

まさに私が探していたもの! –

関連する問題