Cプログラムの実行時間


209

複数のプロセッサーで並列実行することを目的としたCプログラムがあります。実行時間を記録できるようにする必要があります(1秒から数分の場合もあります)。私は答えを探しましたが、それらはすべて、clock()関数の使用を提案しているようです。この関数は、プログラムが取ったクロック数をClocks_per_second値で割って計算します。

Clocks_per_second値の計算方法がわかりません。

Javaでは、実行の前後に現在の時間をミリ秒単位で取得します。

Cにも同様のものはありますか?私は見ましたが、2番目の解像度よりも優れたものを得る方法を見つけることができないようです。

プロファイラーがオプションになることも知っていますが、タイマーを自分で実装することを検討しています。

ありがとう


3
どのOS / APIフレームワークを使用/利用していますか?単純なC?
typo.pl 2011年

4
それはかなり小さなプログラムですが、単純なC
ロジャー

この回答には、ポータブルソリューションの実装に関する詳細を記述しました
。stackoverflow.com/ questions / 361363

完全な関数を実行するのにかかる時間stackoverflow.com/a/40380118/6180077
Abdullah Farweez

回答:


344

CLOCKS_PER_SECで宣言されている定数<time.h>です。Cアプリケーション内のタスクで使用されるCPU時間を取得するには、次のコマンドを使用します。

clock_t begin = clock();

/* here, do your time-consuming job */

clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

これは、浮動小数点型として時間を返すことに注意してください。これは1秒よりも正確である可能性があります(例:4.52秒を測定)。精度はアーキテクチャによって異なります。最近のシステムでは10ミリ秒以下になりがちですが、(Win98時代の)古いWindowsマシンでは60ミリ秒近くでした。

clock()標準Cです。「どこでも」機能します。getrusage()Unixライクなシステムなど、システム固有の機能があります。

Java System.currentTimeMillis()は同じことを測定しません。これは「壁時計」です。プログラムの実行にかかった時間を測定するのに役立ちますが、使用されたCPU時間はわかりません。マルチタスクシステム(つまり、それらすべて)では、これらは大きく異なる場合があります。


1
それは私に非常にランダムな結果を与えます-私は同じコード部分で大きな/小さな/負の数の混合を取得します。GCC 4.7 Linux 3.2 AMD64

3
はい:clock()「クロック」と呼ばれる内部スケールで時間を返します。これはCLOCKS_PER_SEC1秒あたりのクロック数であるため、割るCLOCKS_PER_SECと秒単位の時間が得られます。上記のコードでは、値はa doubleなので、自由にスケーリングできます。
Thomas Pornin 2015年

18
大きな警告:clock()は、OSがプロセスの実行に費やした時間を返し、実際の経過時間は返しません。ただし、これはコードブロックのタイミングを測定する場合には問題ありませんが、実際の経過時間を測定するものではありません。

2
彼はマルチスレッドプログラムを測定したいと言った。すべてのスレッドの実行時間を合計するため、clock()がこれに適しているかどうかはわかりません。したがって、コードが順次実行された場合の結果は次のようになります。そのようなことのためにomp_get_wtime()を使用しますが、もちろん、システムが他のプロセスでビジー状態でないことを確認する必要があります。
Youda008

1
私は、このスレッドが前年より適切だったにも関わらず、いくつかの事柄に言及すべきである:CLOCKS_PER_SECあるlong int値と1000000、分割されていないとき、マイクロ秒単位の時間を与えると、CPUクロックサイクルではありません。したがって、ここでのクロックはマイクロ秒単位であるため、動的周波数を考慮する必要はありません(1 MHz CPUのクロックサイクルでしょうか)。その値を出力する短いCプログラムを作成し、i7-2640Mラップトップでは1000000動的周波数により、ターボブーストを使用して3.5 GHzまで高くしても800 MHz〜2.8 GHzが可能です。
DDPWNAGE 2017

111

実行にUnixシェルを使用している場合は、timeコマンドを使用できます。

している

$ time ./a.out

実行可能ファイルとしてa.outを想定すると、これを実行するのにかかる時間がuになります。


3
@acgtyrant(ただし、入力、出力などを含むプログラム全体の時間がかかるため、単純なプログラムのみ)
phuclv

1
Linuxを使用していて、(マイクロ)ベンチマークを起動オーバーヘッドが無視できるプログラムに減らした場合(例:ホットループを数秒間実行する静的実行可能ファイル)perf stat ./a.out、キャッシュミスのHWパフォーマンスカウンターを取得するために使用できます。ブランチの予測ミス、IPC。
Peter Cordes

61

プレーンバニラC:

#include <time.h>
#include <stdio.h>

int main()
{
    clock_t tic = clock();

    my_expensive_function_which_can_spawn_threads();

    clock_t toc = clock();

    printf("Elapsed: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);

    return 0;
}

6
しばらく見てきた中で最高の変数名。tic = "time in clock"、toc = "time out clock"。しかし、tic-toc = "tick-tock"でもあります。これは、これから私が時間グラブにラベルを付ける方法です。
ローガンシェリー

60

あなたは機能的にこれが欲しい:

#include <sys/time.h>

struct timeval  tv1, tv2;
gettimeofday(&tv1, NULL);
/* stuff to do! */
gettimeofday(&tv2, NULL);

printf ("Total time = %f seconds\n",
         (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
         (double) (tv2.tv_sec - tv1.tv_sec));

これは、秒単位ではなく、マイクロ秒単位で測定されることに注意してください。


2
MinGWコンパイラはGCCベースです。だからそれで動作します。ただし、ビジュアルCコンパイラを使用すると、エラーが発生します。
user2550754 14年

11
はい、gettimeofday呼び出しをサポートするCライブラリを備えたWindowsで動作します。実際にはコンパイラが何であるかは関係ありません。適切なlibcライブラリにリンクするだけです。これは、mingwの場合、デフォルトのウィンドウではありません。
Wes Hardaker 2014年

1
これは、cygwin gccとLinux UbuntuがインストールされたWindows XPで動作します。これはまさに私が欲しかったものです。
愛と平和-Joe Codeswell、2015年

gettimeofday廃止され、新しいコードには推奨されません。そのPOSIXマニュアルページでは、代わりにclock_gettimeを推奨しています。これによりCLOCK_MONOTONIC、システムクロックの変更の影響を受けないように要求できるため、インターバル時間としてはより優れています。(JohnSllの回答を参照してください)。たとえば、最近のLinuxシステムでは、gettimeofdayは基本的に、ナノ秒をマイクロ秒に変換するclock_gettimeのラッパーです。
Peter Cordes

12

ほとんどの単純なプログラムの計算時間はミリ秒です。だから、私はあなたがこれが便利だと思うでしょう。

#include <time.h>
#include <stdio.h>

int main(){
    clock_t start = clock();
    // Execuatable code
    clock_t stop = clock();
    double elapsed = (double)(stop - start) * 1000.0 / CLOCKS_PER_SEC;
    printf("Time elapsed in ms: %f", elapsed);
}

プログラム全体のランタイムを計算する必要があり、UNIXシステムを使用している場合は、次のようなtimeコマンドを使用してプログラムを実行します。time ./a.out


Windowsでは、少なくとも係数は100ではなく1000ではなく、正確ではありません
boctulus

6
この回答は、2年前のAlexandre C回答になかったものを追加しません。
Jonathan Leffler、2016

3
@boctulus:1sは常に 1000msで、Windowsでも同様です。
alk

9

多くの回答が示唆されておりclock()、それCLOCKS_PER_SECからtime.h。これは私の/bits/time.hファイルが言うことなので、おそらく悪い考えです:

/* ISO/IEC 9899:1990 7.12.1: <time.h>
The macro `CLOCKS_PER_SEC' is the number per second of the value
returned by the `clock' function. */
/* CAE XSH, Issue 4, Version 2: <time.h>
The value of CLOCKS_PER_SEC is required to be 1 million on all
XSI-conformant systems. */
#  define CLOCKS_PER_SEC  1000000l

#  if !defined __STRICT_ANSI__ && !defined __USE_XOPEN2K
/* Even though CLOCKS_PER_SEC has such a strange value CLK_TCK
presents the real value for clock ticks per second for the system.  */
#   include <bits/types.h>
extern long int __sysconf (int);
#   define CLK_TCK ((__clock_t) __sysconf (2))  /* 2 is _SC_CLK_TCK */
#  endif

したがってCLOCKS_PER_SEC、コンパイルに使用するオプションによっては、1000000と定義される可能性があるため、適切なソリューションとは思えません。


1
情報をありがとうございましたが、より良い代替案はまだありますか?
ozanmuyes 2014年

4
これは実際的な問題ではありません。Posixシステムには常にがCLOCK_PER_SEC==1000000ありますが、同時に、すべてのシステムでclock()の実装に1 µsの精度を使用しています。ちなみに、それは共有の問題を減らすための素晴らしい特性を持っています。1 ms未満などの非常に速い可能性のあるイベントを測定する場合は、最初にclock()関数の精度(または解像度)を考慮する必要があります。これは、Posixでは必然的に1µs より粗くなりますが、多くの場合、はるかに粗くなります。通常の解決策は、テストを何度も実行することです。しかし、尋ねられた質問はそれを必要としないようでした。
AntoineL 2015

なぜそれが良い解決策にならないのですか?からいくつかの値を取得clock()CLOCK_PER_SECます。その値を割り算すると、CPUにかかった秒数で時間を取得できることが保証されます。実際のクロック速度を測定する責任はclock()、あなたではなく機能の責任です。
Zaffy

9

マクロとしてのThomas Porninの答え:

#define TICK(X) clock_t X = clock()
#define TOCK(X) printf("time %s: %g sec.\n", (#X), (double)(clock() - (X)) / CLOCKS_PER_SEC)

次のように使用します。

TICK(TIME_A);
functionA();
TOCK(TIME_A);

TICK(TIME_B);
functionB();
TOCK(TIME_B);

出力:

time TIME_A: 0.001652 sec.
time TIME_B: 0.004028 sec.

4

プログラムの実行にかかった時間の測定は、マシンがその特定の瞬間に持つ負荷に大きく依存することを考慮する必要があります。

Cで現在の時刻を取得する方法はさまざまな方法で実現できるため、より簡単な方法は次のとおりです。

#include <time.h>

#define CPU_TIME (getrusage(RUSAGE_SELF,&ruse), ruse.ru_utime.tv_sec + \
  ruse.ru_stime.tv_sec + 1e-6 * \
  (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec))

int main(void) {
    time_t start, end;
    double first, second;

    // Save user and CPU start time
    time(&start);
    first = CPU_TIME;

    // Perform operations
    ...

    // Save end time
    time(&end);
    second = CPU_TIME;

    printf("cpu  : %.2f secs\n", second - first); 
    printf("user : %d secs\n", (int)(end - start));
}

それが役に立てば幸い。

よろしく!


4

(システム管理者がシステム時間を変更した場合、またはタイムゾーンの冬時間と夏時間が異なる場合、ここでの回答はすべて欠けています。したがって...)

Linuxでの使用:clock_gettime(CLOCK_MONOTONIC_RAW, &time_variable); system-adminが時刻を変更した場合、または冬時間と夏時間とが異なる国に住んでいる場合などは影響を受けません。

#include <stdio.h>
#include <time.h>

#include <unistd.h> /* for sleep() */

int main() {
    struct timespec begin, end;
    clock_gettime(CLOCK_MONOTONIC_RAW, &begin);

    sleep(1);      // waste some time

    clock_gettime(CLOCK_MONOTONIC_RAW, &end);

    printf ("Total time = %f seconds\n",
            (end.tv_nsec - begin.tv_nsec) / 1000000000.0 +
            (end.tv_sec  - begin.tv_sec));

}

man clock_gettime 状態:

CLOCK_MONOTONIC
              Clock  that  cannot  be set and represents monotonic time since some unspecified starting point.  This clock is not affected by discontinuous jumps in the system time
              (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.

秒数を取得するために使用した計算を説明できますか?何が起こっているのかは明らかではありません。
コリンキーナン2017年

1
これ(end.tv_nsec - begin.tv_nsec) / 1000000000.00常に結果になりませんか?
アルク

@alk:いいえ、で割るdoubleリテラルトリガintまたはlongdouble変換する前に、分割。もちろん、整数に固執してtv_sec部分を印刷し、次にのよう%ld.%09ldにゼロで小数部分を印刷することもできますが、倍精度浮動小数点数への変換は簡単で、通常、ベンチマーク時間には53ビットの精度で十分です。
Peter Cordes

1
(おっと、ナノ秒部分の減算は秒部分に持ち込む必要があるかもしれないので、doubleを使用し、それを負にすることでその問題を回避できます。純粋な整数フォーマット文字列を使用するには、glibcマニュアルで提案されているtimespec_subtractようなものが必要です。timeval_subtractgnu.org/software/libc/manual/html_node/Elapsed-Time.html
Peter Cordes

3

ANSI Cは、2番目の精度の時間関数のみを指定します。ただし、POSIX環境で実行している場合は、UNIXエポックから経過した時間をマイクロ秒単位で解決するgettimeofday()関数を使用できます。

余談ですが、clock()の使用はお勧めしません。クロック()は多くの(すべてではないにしても)システムに正しく実装されておらず、正確ではなく、プログラムがCPUとプログラムの全寿命ではありません。あなたの質問によれば、それは私があなたが測定したいと思うものです。


ISO C標準(これがANSI Cの意味であると仮定)は、時間関数の精度を意図的に指定していません。次に、具体的にはPOSIX実装またはWindowsでは、掛け時計(トーマスの回答を参照)の精度は秒単位です。しかし、clock()の精度は通常より高く、Posixでは常に1µs(精度とは
関係なく

2

すべてのソリューションが私のシステムで機能していません。

私は使うことができます

#include <time.h>

double difftime(time_t time1, time_t time0);

2
これにより、2つのtime_t値の差がdoubleになります。以来time_tの値だけ第二に正確であり、それは長時間実行することをプログラムするために有用であり得るが、それは、短い実行中のプログラムによって撮影された時間を印刷に限定された値です。
ジョナサンレフラー、2016

何らかの理由で、clock_tsのペアを渡すdifftimeと、100分の1秒の精度でうまくいくようです。これはLinux x86上にあります。私はまたの減算得ることができないstopstart仕事にします。
ragerdl 2016

@ragerdl:difftime() clock() / CLOCKS_PER_SEC秒を想定しているため、に渡す必要があります。
アルク

2
    #include<time.h>
    #include<stdio.h>
    int main(){
clock_t begin=clock();

    int i;
for(i=0;i<100000;i++){
printf("%d",i);

}
clock_t end=clock();
printf("Time taken:%lf",(double)(end-begin)/CLOCKS_PER_SEC);
}

このプログラムは魅力のように動作します。


2

画面への描画やファイルの読み取りなどの副作用のない静的コードであっても、何らかの理由で実行から実行に大きく逸脱する、通常のclock()がここで推奨されていることがわかりました。CPUが電力消費モードを変更したり、OSが異なる優先順位を与えたりするなどの理由が考えられます。

したがって、clock()を使用して毎回確実に同じ結果を得る唯一の方法は、測定されたコードを複数回(数分間)ループで実行し、コンパイラーが最適化しないように予防策を講じることです。最新のコンパイラーはコードを事前計算できますループで実行されている副作用なしで、ループの外に移動します。つまり、反復ごとにランダム入力を使用するようなものです。

十分なサンプルが配列に収集された後、1つはその配列を並べ替え、中央値と呼ばれる中央の要素を取ります。中央値は平均よりも優れています。これは、ウイルス対策がCPUをすべて占有したり、OSが更新を行ったりするなど、極端な偏差を捨てるからです。

C / C ++コードの実行パフォーマンスを測定し、中央値に近い値を平均化する簡単なユーティリティを次に示します。https//github.com/saniv/gauge

私はまだ、コードを測定するためのより堅牢でより高速な方法を探しています。おそらくOSなしでベアメタルの制御された条件でコードを実行してみることができますが、実際にはOSが関与するため、非現実的な結果が得られます。

x86には、実行された実際の命令数を含むこれらのハードウェアパフォーマンスカウンターがありますが、OSのヘルプなしではアクセスが難しく、解釈が難しく、独自の問題があります(http://archive.gamedev.net/archive/reference/articles /article213.html)。それでも、ボトルネックの性質(データアクセスまたはそのデータの実際の計算)を調査するのに役立ちます。


はい、最新のx86 CPUは、max turboよりもはるかに遅くアイドルします。「ガバナー」の設定によっては、最大クロック速度まで立ち上がるのに1ミリ秒(ハードウェアP状態管理を使用したSkylake、特にenergy_performance_preferenceをに設定した場合performance)または数十ミリ秒かかる場合があります。 en.wikipedia.org/wiki/Dynamic_frequency_scaling。通常、パフォーマンスの中央値が適切な選択です。ハイエンドには通常、干渉によるスパイクがあります。
Peter Cordes

多くの場合、作業を最適化することを避けるための最善策は、コマンドライン入力で結果を返すことです。またはmain、引数を取り、結果を返す別のファイルに関数を記述し、リンク時の最適化を使用しないでください。その後、コンパイラーはそれを呼び出し元にインライン化できません。関数がすでに何らかのループを含んでいる場合にのみ機能します。それ以外の場合は、呼び出し/ retオーバーヘッドが高すぎます。
Peter Cordes

コンパイラーは、副作用のない静的コードで処理する場合、ループからの単一のコマンドライン入力を最適化できます。そのため、反復ごとにランダムな入力を生成するのが最善です。当然、rand()は、最初のclock()の前に、測定されたコードの外で呼び出す必要があります。出力のすべてのビットをprintfすることを忘れないでください。そうしないと、コンパイラは、出力全体またはその一部を必要としないと判断する場合があります。これは、CRC32などで実行できます。
SmugLispWeenie

テスト対象のコードが別のファイルにあり、リンク時の最適化を使用していない場合、コンパイラーがCSEを実行して呼び出し間で最適化する方法はありません。呼び出し元は、目に見える副作用がない呼び出し先について何も想定できません。これにより、繰り返しループ内に比較的短いものを配置して、呼び出し/ retオーバーヘッドのみで、時間まで十分長くすることができます。インライン化する場合は、生成されたasmをチェックして、言うようにループから計算を引き上げていないことを確認する必要があります。
Peter Cordes

コンパイラー固有の方法は、GNU Cインラインasmを使用して、コンパイラーに結果をレジスターに具体化させたり、実際に余分な命令を導入することなく、変数の値について知っていることを忘れたりすることです。 MSVCの「Escape」および「Clobber」に相当するものは、プロファイリングとマイクロベンチマークに関するビデオにリンクしています(clang開発者Chandler CarruthのCppCon 2015の講演)。
Peter Cordes

0

別の種類の入力が役立つと感じる人もいます。NVidiaCUDAを使用したGPGPUプログラミングに関する大学のコースの一部として、この時間を測定する方法が与えられました(コースの説明)。それは以前の投稿で見られた方法を組み合わせたものであり、要件によって信頼性が与えられるため、私は単に投稿します。

unsigned long int elapsed;
struct timeval t_start, t_end, t_diff;
gettimeofday(&t_start, NULL);

// perform computations ...

gettimeofday(&t_end, NULL);
timeval_subtract(&t_diff, &t_end, &t_start);
elapsed = (t_diff.tv_sec*1e6 + t_diff.tv_usec);
printf("GPU version runs in: %lu microsecs\n", elapsed);

たとえば1.0 / 1000.0、ニーズに合った測定単位を取得するために乗算することができると思います。


1
gettimeofdayは廃止され、推奨されていません。そのclock_gettime代わりに、POSIXのマニュアルページで推奨されています。これによりCLOCK_MONOTONIC、システムクロックの変更の影響を受けないように要求できるため、インターバルタイマーとしてより適しています。たとえば、最近のLinuxシステムでgettimeofdayは、基本的にclock_gettimeナノ秒をマイクロ秒に変換するためのラッパーです。(JohnSllの回答を参照してください)。
Peter Cordes

このメソッドは@Wes Hardakerによって追加されましたtimeval_subtract。主な違いはを使用していることです。
ワイキんぐ

さて、あなたの答えの唯一の有用な部分は、あなたが定義していない関数の名前であり、それは標準ライブラリにはありません。(glibcマニュアルのみ:gnu.org/software/libc/manual/html_node/Elapsed-Time.html)。
Peter Cordes

-2

バブルソートと選択ソートの実行時間の比較バブルソートと選択ソートの実行時間を比較するプログラムを持っています。コードブロックの実行時間を調べるには、次のようにブロックの前後の時間を計算します。

 clock_t start=clock();
 
 clock_t end=clock();
 CLOCKS_PER_SEC is constant in time.h library

コード例:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
   int a[10000],i,j,min,temp;
   for(i=0;i<10000;i++)
   {
      a[i]=rand()%10000;
   }
   //The bubble Sort
   clock_t start,end;
   start=clock();
   for(i=0;i<10000;i++)
   {
     for(j=i+1;j<10000;j++)
     {
       if(a[i]>a[j])
       {
         int temp=a[i];
         a[i]=a[j];
         a[j]=temp;
       }
     }
   }
   end=clock();
   double extime=(double) (end-start)/CLOCKS_PER_SEC;
   printf("\n\tExecution time for the bubble sort is %f seconds\n ",extime);

   for(i=0;i<10000;i++)
   {
     a[i]=rand()%10000;
   }
   clock_t start1,end1;
   start1=clock();
   // The Selection Sort
   for(i=0;i<10000;i++)
   {
     min=i;
     for(j=i+1;j<10000;j++)
     {
       if(a[min]>a[j])
       {
         min=j;
       }
     }
     temp=a[min];
     a[min]=a[i];
     a[i]=temp;
   }
   end1=clock();
   double extime1=(double) (end1-start1)/CLOCKS_PER_SEC;
   printf("\n");
   printf("\tExecution time for the selection sort is %f seconds\n\n", extime1);
   if(extime1<extime)
     printf("\tSelection sort is faster than Bubble sort by %f seconds\n\n", extime - extime1);
   else if(extime1>extime)
     printf("\tBubble sort is faster than Selection sort by %f seconds\n\n", extime1 - extime);
   else
     printf("\tBoth algorithms have the same execution time\n\n");
}

4
これは、実際のコードで「実行可能コード」ブロック(またはそれらの2つ)を埋めることを除いて、実際にはadimoh回答と比較して新しいものを追加しません。そして、その答えは、2年前のAlexandre C答えになかったものを追加しません。
ジョナサンレフラー、2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.