LinuxでC ++がミリ秒の時間を取得— clock()が正しく機能していないようです


102

Windowsではclock()時間をミリ秒単位で返しますが、私が作業しているこのLinuxボックスでは、最も近い1000に四捨五入するため、精度は「秒」レベルのみであり、ミリ秒レベルではありません。

QTimeクラスを使用してQtで解決策を見つけ、オブジェクトをインスタンス化start()して呼び出しelapsed()、ミリ秒数を取得するために呼び出しました。

そもそもQtで作業しているので、ちょっとラッキーですが、サードパーティのライブラリに依存しないソリューションが欲しいのですが、

これを行うための標準的な方法はありませんか?

更新

Boostを推奨しないでください。

BoostとQtがそれを実行できる場合、それは魔法ではありません。彼らが使用している標準があるはずです。


2
編集について-しかし、移植可能な方法でそれを行うことは、いくつかの苦痛です。
匿名

回答:


37

メソッドの最初と最後でgettimeofdayを使用して、2つの戻り構造体を区別できます。次のような構造になります。

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

編集:以下の2つのコメントが示唆しているように、利用可能な場合、clock_gettime(CLOCK_MONOTONIC)の方がはるかに良い選択です。

編集:他の誰かがstd :: chrono :: high_resolution_clockで最新のC ++を使用することもできるとコメントしましたが、単調であるとは限りません。代わりにsteady_clockを使用してください。


38
深刻な仕事のためにひどい。年に2回、大きな問題が発生します。誰かがdate -sを実行すると、もちろんNTP同期が実行されます。clock_gettime(CLOCK_MONOTONIC、)を使用
AndrewStone

9
@AndrewStone:UNIX時間は1年に2回変更されません。または年に1回。しかし、はい、CLOCK_MONOTONICローカライズされたシステム時間調整を回避するのに最適です。
オービットのライトネスレース

138
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    struct timeval start, end;

    long mtime, seconds, useconds;    

    gettimeofday(&start, NULL);
    usleep(2000);
    gettimeofday(&end, NULL);

    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;

    printf("Elapsed time: %ld milliseconds\n", mtime);

    return 0;
}

4
なぜその差に+0.5を加えるのですか?
Mahmoud Al-Qudsi 2009年

19
@Computer Guru、正の値を丸めるための一般的な手法です。添加は0に切り捨てられ、そして0.5と0.9999の間... 1に切り捨てられますされる前値...整数値、0.0と0.4999の間で何かに切り捨てを取得したときに
マークランサム

8
tv_usecはミリ秒ではなく、マイクロ秒です。
NebulaFox 2011

13
深刻な仕事のためにひどい。年に2回大きな問題が発生し、誰かが日付-s、そしてもちろんNTP同期を行う
AndrewStone

14
@AndrewStoneは正しいです。CLOCK_REALTIMEでclock_gettime(2)を使用して、同じコンピューター上の時間を比較します。gettimeofday(2)のマンページ:POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT struct timevalからstruct timespec、をgettimeofday(&start, NULL)に変更して例を更新し、clock_gettime(CLOCK_MONOTONIC, &start)人々が問題に遭遇しないようにできますか?
Bobby Powers、

58

clockは実時間を測定しないことに注意してください。つまり、プログラムに5秒かかる場合、clock必ずしも5秒は測定されませんが、それ以上(プログラムが複数のスレッドを実行する可能性があるため、リアルタイムよりも多くのCPUを消費する可能性があります)以下になる可能性があります。使用されたCPU時間の概算を測定します。違いを確認するには、このコードを検討してください

#include <iostream>
#include <ctime>
#include <unistd.h>

int main() {
    std::clock_t a = std::clock();
    sleep(5); // sleep 5s
    std::clock_t b = std::clock();

    std::cout << "difference: " << (b - a) << std::endl;
    return 0;
}

私のシステムに出力します

$ difference: 0

私たちがやったのは寝ているだけでCPU時間を使わなかったからです!ただし、使用gettimeofdayすると必要なものが得られます(?)

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

int main() {
    timeval a;
    timeval b;

    gettimeofday(&a, 0);
    sleep(5); // sleep 5s
    gettimeofday(&b, 0);

    std::cout << "difference: " << (b.tv_sec - a.tv_sec) << std::endl;
    return 0;
}

私のシステムの出力

$ difference: 5

より高い精度が必要だが、CPU時間を取得したい場合は、getrusage関数のます。


mention言及についてa sleep()—私はすでにあなたの答えを見つけたとき、質問をすると考えられています(なぜ私を除くすべての人にとってうまくいくのですか?)
Hi-Angel 14

18

Boostが提供するツールもお勧めします。言及されたBoostタイマー、またはBoost.DateTimeから何かをハックするか、サンドボックスに新しい提案されたライブラリー-Boost.Chronoがあります:この最後の1つはタイマーの代替となり、機能します:

  • 以下を含むC ++ 0x標準ライブラリの時間ユーティリティ:
    • クラステンプレート duration
    • クラステンプレート time_point
    • 時計:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • timertypedefを含むクラステンプレート:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • プロセスクロックとタイマー:
    • process_clock、実際のユーザーCPU時間、システムCPU時間をキャプチャします。
    • process_timer、実際の経過時間、ユーザーCPU時間、システムCPU時間をキャプチャします。
    • run_timer、| process_timer |の便利なレポート 結果。
  • C ++ 0x標準ライブラリのコンパイル時の有理演算。

ここに機能リストのソースがあります


現時点では、ブーストタイマーを使用して、レビューまたは承認されたときにChronoに適切に移行できます。
匿名

13

私が書いたことTimerに基づいて、クラスをCTTの答え。次のように使用できます。

Timer timer = Timer();
timer.start();
/* perform task */
double duration = timer.stop();
timer.printTime(duration);

ここにその実装があります:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
using namespace std;

class Timer {
private:

    timeval startTime;

public:

    void start(){
        gettimeofday(&startTime, NULL);
    }

    double stop(){
        timeval endTime;
        long seconds, useconds;
        double duration;

        gettimeofday(&endTime, NULL);

        seconds  = endTime.tv_sec  - startTime.tv_sec;
        useconds = endTime.tv_usec - startTime.tv_usec;

        duration = seconds + useconds/1000000.0;

        return duration;
    }

    static void printTime(double duration){
        printf("%5.6f seconds\n", duration);
    }
};

2
これはクールですが、timevalはナノ秒を保持せず、マイクロ秒を保持するため、「nseconds」は誤解を招くので、これを「useconds」と呼ぶことをお勧めします。
pho0

ありがとう。訂正しました。
Chris Redford、

9

コードを古いuniceに移植する必要がない場合は、clock_gettime()を使用できます。これにより、ナノ秒単位の時間が得られます(プロセッサーがその解像度をサポートしている場合)。それはPOSIXですが、2001年からです。



4

C ++ 11では、std::chrono::high_resolution_clockこれを行うことができます:

#include <iostream>
#include <chrono>
#include <thread>
typedef std::chrono::high_resolution_clock Clock;

int main()
{
    std::chrono::milliseconds three_milliseconds{3};

    auto t1 = Clock::now();
    std::this_thread::sleep_for(three_milliseconds);
    auto t2 = Clock::now();

    std::cout << "Delta t2-t1: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
              << " milliseconds" << std::endl;
}

出力:

Delta t2-t1: 3 milliseconds

デモへのリンク:http : //cpp.sh/2zdtu


2

Linuxでは、clock()はミリ秒または秒を返しません。通常、Linuxシステムでは、clock()はマイクロ秒を返します。clock()によって返された値を解釈する適切な方法は、CLOCKS_PER_SECで除算して、経過した時間を計算することです。


私が取り組んでいる箱にはありません!プラス、私は午前 CLOCKS_PER_SECで割るが、解像度が唯一のダウン秒にあるので、それは無意味だ
HASEN

公平に言うと、単位マイクロ秒です(CLOCKS_PER_SECはすべてのPOSIXシステムで1000000)。ちょうどそれは秒の解像度を持っています。:-P。
エヴァンテラン

1

これは動作するはずです... Macでテスト済み...

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

int main() {
        struct timeval tv;
        struct timezone tz;
        struct tm *tm;
        gettimeofday(&tv,&tz);
        tm=localtime(&tv.tv_sec);
        printf("StartTime: %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec);
}

うん...それを2回実行して減算...


1

POSIX標準でclockは、CLOCKS_PER_SECシンボルに関して定義された戻り値があり、実装はこれを任意の便利な方法で自由に定義できます。Linuxでは、私はそのtimes()機能に幸運を感じてきました。


1

gettimeofday-問題は、ハードウェアクロック(NTPなど)を変更すると、値が低くなる可能性があることですBoost-このプロジェクトでは使用できませんclock()-通常、4バイトの整数を返します。しばらくすると、負の数が返されます。

私は自分のクラスを作成し、10ミリ秒ごとに更新することを好みます。これにより、この方法はより柔軟になり、サブスクライバーを持つように改善することもできます。

class MyAlarm {
static int64_t tiempo;
static bool running;
public:
static int64_t getTime() {return tiempo;};
static void callback( int sig){
    if(running){
        tiempo+=10L;
    }
}
static void run(){ running = true;}
};

int64_t MyAlarm::tiempo = 0L;
bool MyAlarm::running = false;

それを更新するには、setitimerを使用します。

int main(){
struct sigaction sa; 
struct itimerval timer; 

MyAlarm::run();
memset (&sa, 0, sizeof (sa)); 
sa.sa_handler = &MyAlarm::callback; 

sigaction (SIGALRM, &sa, NULL); 


timer.it_value.tv_sec = 0; 
timer.it_value.tv_usec = 10000; 



timer.it_interval.tv_sec = 0; 
timer.it_interval.tv_usec = 10000; 


setitimer (ITIMER_REAL, &timer, NULL); 
.....

setitimerとITIMER_VIRTUALとITIMER_REALを見てください。

アラームまたはualarm機能を使用しないでください。プロセスが困難な場合、精度が低くなります。



0

更新として、Windowsではclock()が実時間を測定するように見える(CLOCKS_PER_SEC精度で)

 http://msdn.microsoft.com/en-us/library/4e2ess30(VS.71).aspx

Linuxでは、現在のプロセスで使用されているコア全体のCPU時間を測定します

http://www.manpagez.com/man/3/clock

そして、(それが表示され、元のポスターで述べたように)実際に少ない CLOCKS_PER_SECより精密に、しかし多分これは、Linuxの特定のバージョンに依存します。


0

私は、gettimeofday()を使用しないHola Soyメソッドが好きです。管理者がタイムゾーンを変更した実行中のサーバーでそれが起こりました。クロックは、同じ(正しい)ローカル値を表示するように更新されました。これにより、関数time()およびgettimeofday()が2時間シフトし、一部のサービスのすべてのタイムスタンプがスタックしました。


0

C++使用してクラスを作成しましたtimeb

#include <sys/timeb.h>
class msTimer 
{
public:
    msTimer();
    void restart();
    float elapsedMs();
private:
    timeb t_start;
};

メンバー関数:

msTimer::msTimer() 
{ 
    restart(); 
}

void msTimer::restart() 
{ 
    ftime(&t_start); 
}

float msTimer::elapsedMs() 
{
    timeb t_now;
    ftime(&t_now);
    return (float)(t_now.time - t_start.time) * 1000.0f +
           (float)(t_now.millitm - t_start.millitm);
}

使用例:

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{
    msTimer t;
    for (int i = 0; i < 5000000; i++)
        ;
    std::cout << t.elapsedMs() << endl;
    return 0;
}

私のコンピュータの出力は「19」です。msTimerクラスの精度はミリ秒のオーダーです。上記の使用例では、for-loop によって実行された合計実行時間が追跡されます。今回は、main()マルチタスクによるオペレーティングシステムの実行コンテキストの切り替えが含まれています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.