C ++ mendapatkan waktu milidetik di Linux - clock () sepertinya tidak berfungsi dengan benar


102

Di Windows, clock()mengembalikan waktu dalam milidetik, tetapi di kotak Linux yang sedang saya kerjakan, ini membulatkannya ke 1000 terdekat sehingga presisi hanya ke tingkat "kedua" dan bukan ke tingkat milidetik.

Saya menemukan solusi dengan Qt menggunakan QTimekelas, membuat instance objek dan memanggilnya start()kemudian memanggil elapsed()untuk mendapatkan jumlah milidetik yang telah berlalu.

Saya agak beruntung karena saya bekerja dengan Qt untuk memulai, tetapi saya ingin solusi yang tidak bergantung pada pustaka pihak ketiga,

Apakah tidak ada cara standar untuk melakukan ini?

MEMPERBARUI

Tolong jangan rekomendasikan Boost ..

Kalau Boost dan Qt bisa melakukannya, tentunya bukan sihir, pasti ada standar yang mereka gunakan!


2
Tentang mengedit - tetapi melakukannya dengan cara portabel memang merepotkan.
Anonim

Jawaban:


37

Anda bisa menggunakan gettimeofday di awal dan akhir metode Anda dan kemudian membedakan dua struktur pengembalian. Anda akan mendapatkan struktur seperti berikut:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

EDIT: Seperti yang disarankan oleh dua komentar di bawah ini, clock_gettime (CLOCK_MONOTONIC) adalah pilihan yang jauh lebih baik jika Anda memilikinya, yang seharusnya ada di hampir semua tempat saat ini.

EDIT: Orang lain berkomentar bahwa Anda juga dapat menggunakan C ++ modern dengan std :: chrono :: high_resolution_clock, tetapi itu tidak dijamin monotonik. Gunakan jam stabil sebagai gantinya.


38
buruk untuk pekerjaan serius. Masalah besar dua kali setahun, ketika seseorang melakukan tanggal -s, dan tentu saja sinkronisasi NTP. Gunakan clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: Waktu UNIX tidak berubah dua kali per tahun. Atau bahkan setahun sekali. Tapi, ya, CLOCK_MONOTONICbagus untuk menghindari penyesuaian waktu sistem yang dilokalkan.
Balapan Ringan di Orbit

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
Mengapa Anda menambahkan +0.5 ke selisihnya?
Mahmoud Al-Qudsi

19
@Computer Guru, ini adalah teknik umum untuk membulatkan nilai positif. Ketika nilai dipotong menjadi nilai bilangan bulat, apa pun antara 0,0 dan 0,4999 ... sebelum penambahan dipotong menjadi 0, dan antara 0,5 dan 0,9999 ... akan dipotong menjadi 1.
Markus Tebusan

8
tv_usec bukan milidetik, ini mikrodetik.
NebulaFox

13
buruk untuk pekerjaan serius. Masalah besar dua kali setahun, ketika seseorang melakukan tanggal -s, dan tentu saja sinkronisasi NTP
AndrewStone

14
@AndrewStone benar, gunakan clock_gettime (2) dengan CLOCK_REALTIME untuk membandingkan waktu di komputer yang sama. Dari gettimeofday yang (2) manualnya: POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, bisa Anda memperbarui contoh dengan mengubah struct timevalke struct timespec, dan gettimeofday(&start, NULL)untuk clock_gettime(CLOCK_MONOTONIC, &start)agar orang tidak mengalami kesulitan?
Bobby Powers

58

Harap dicatat bahwa clocktidak tidak mengukur waktu jam dinding. Itu berarti jika program Anda membutuhkan waktu 5 detik, clocktidak akan mengukur 5 detik, tetapi bisa lebih (program Anda dapat menjalankan beberapa utas sehingga dapat menggunakan lebih banyak CPU daripada waktu nyata) atau kurang. Ini mengukur perkiraan waktu CPU yang digunakan. Untuk melihat perbedaannya perhatikan kode ini

#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;
}

Ini dihasilkan di sistem saya

$ difference: 0

Karena yang kami lakukan hanyalah tidur dan tidak menggunakan waktu CPU! Namun, menggunakan gettimeofdaykita mendapatkan apa yang kita inginkan (?)

#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;
}

Keluaran di sistem saya

$ difference: 5

Jika Anda membutuhkan lebih banyak presisi tetapi ingin mendapatkan waktu CPU , maka Anda dapat mempertimbangkan untuk menggunakan getrusagefungsi tersebut.


⁺¹ tentang menyebutkan a sleep()- Saya sudah berpikir untuk mengajukan pertanyaan (mengapa ini berfungsi dengan baik untuk semua orang kecuali saya ?!) , ketika menemukan jawaban Anda.
Hi-Angel

18

Saya juga merekomendasikan alat yang ditawarkan oleh Boost. Baik Boost Timer yang disebutkan, atau retas sesuatu dari Boost.DateTime atau ada perpustakaan baru yang diusulkan di kotak pasir - Boost.Chrono : Yang terakhir ini akan menjadi pengganti Timer dan akan menampilkan:

  • Utilitas waktu C ++ 0x Standard Library, termasuk:
    • Template kelas duration
    • Template kelas time_point
    • Jam:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Template kelas timer, dengan typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Jam dan timer proses:
    • process_clock, merekam waktu nyata, CPU pengguna, dan CPU sistem.
    • process_timer, merekam waktu nyata, CPU pengguna, dan sistem-CPU yang telah berlalu.
    • run_timer, pelaporan nyaman dari | process_timer | hasil.
  • Aritmatika rasional waktu kompilasi C ++ 0x Standard Library.

Berikut adalah sumber dari daftar fitur


Untuk saat ini Anda dapat menggunakan Boost Timer dan kemudian bermigrasi dengan anggun ke Chrono saat ditinjau / diterima.
Anonim

13

Saya telah menulis Timerkelas berdasarkan jawaban CTT . Ini dapat digunakan dengan cara berikut:

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

Berikut implementasinya:

#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
Ini keren tapi "nseconds" menyesatkan karena timeval tidak menahan nanodetik, ini memegang mikrodetik, jadi saya sarankan orang menyebutnya "useconds".
pho0

Terima kasih. Koreksi dilakukan.
Chris Redford

9

Jika Anda tidak memerlukan kode untuk menjadi portabel ke unix lama, Anda dapat menggunakan clock_gettime (), yang akan memberi Anda waktu dalam nanodetik (jika prosesor Anda mendukung resolusi tersebut). Ini POSIX, tapi dari 2001.


4

clock () sering kali memiliki resolusi yang cukup buruk. Jika Anda ingin mengukur waktu pada tingkat milidetik, salah satu alternatifnya adalah menggunakan clock_gettime (), seperti yang dijelaskan dalam pertanyaan ini.

(Ingatlah bahwa Anda perlu menghubungkan dengan -lrt di Linux).


4

Dengan C ++ 11 dan std::chrono::high_resolution_clockAnda dapat melakukan ini:

#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;
}

Keluaran:

Delta t2-t1: 3 milliseconds

Tautan ke demo: http://cpp.sh/2zdtu


2

clock () tidak mengembalikan milidetik atau detik di linux. Biasanya clock () mengembalikan mikrodetik pada sistem linux. Cara yang tepat untuk menafsirkan nilai yang dikembalikan oleh clock () adalah membaginya dengan CLOCKS_PER_SEC untuk mengetahui berapa lama waktu telah berlalu.


tidak di dalam kotak yang sedang saya kerjakan! ditambah, saya sedang membagi dengan CLOCKS_PER_SEC, tapi itu sia-sia karena resolusinya hanya turun ke kedua
Hasen

agar adil, satuannya adalah mikrodetik (CLOCKS_PER_SEC adalah 1000000 di semua sistem POSIX). Hanya memiliki resolusi detik. :-P.
Evan Teran

1

Ini harus bekerja ... diuji di 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);
}

Ya ... jalankan dua kali dan kurangi ...


1

Dalam standar POSIX, clocknilai kembaliannya ditentukan dalam istilah simbol CLOCKS_PER_SEC dan implementasi bebas untuk mendefinisikan ini dengan cara apa pun yang nyaman. Di Linux, saya cukup beruntung dengan times()fungsinya.


1

gettimeofday - masalahnya adalah itu dapat memiliki nilai yang lebih rendah jika Anda mengubah jam perangkat keras Anda (dengan NTP misalnya) Boost - tidak tersedia untuk jam proyek ini () - biasanya mengembalikan integer 4 byte, yang berarti kapasitasnya rendah, dan setelah beberapa waktu itu mengembalikan angka negatif.

Saya lebih suka membuat kelas saya sendiri dan memperbarui setiap 10 milidetik, jadi cara ini lebih fleksibel, dan saya bahkan dapat meningkatkannya untuk memiliki pelanggan.

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;

untuk menyegarkannya saya menggunakan 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); 
.....

Lihat setitimer dan ITIMER_VIRTUAL dan ITIMER_REAL.

Jangan gunakan fungsi alarm atau ualarm, Anda akan memiliki presisi yang rendah saat proses Anda membutuhkan kerja keras.


0

Saya lebih suka pustaka Boost Timer karena kesederhanaannya, tetapi jika Anda tidak ingin menggunakan pustaka pihak ketiga, menggunakan clock () tampaknya masuk akal.


0

Sebagai pembaruan, tampak bahwa pada jam windows () mengukur waktu jam dinding (dengan presisi CLOCKS_PER_SEC)

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

sedangkan di Linux mengukur waktu cpu di seluruh inti yang digunakan oleh proses saat ini

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

dan (muncul, dan seperti yang dicatat oleh poster asli) sebenarnya dengan presisi kurang dari CLOCKS_PER_SEC, meskipun mungkin ini tergantung pada versi Linux tertentu.


0

Saya suka metode Hola Soy yang tidak menggunakan gettimeofday (). Itu terjadi pada saya di server yang berjalan, admin mengubah zona waktu. Jam telah diperbarui untuk menunjukkan nilai lokal (benar) yang sama. Ini menyebabkan fungsi time () dan gettimeofday () bergeser 2 jam dan semua stempel waktu di beberapa layanan macet.


0

Saya menulis C++kelas menggunakan timeb.

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

Fungsi anggota:

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);
}

Contoh penggunaan:

#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;
}

Output di komputer saya adalah '19'. Keakuratan msTimerkelas adalah urutan milidetik. Dalam contoh penggunaan di atas, total waktu eksekusi yang digunakan oleh for-loop dilacak. Kali ini termasuk sistem operasi yang beralih keluar masuk konteks eksekusi main()karena multitasking.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.