C ++ отримання мілісекундного часу на Linux - годинник () здається, не працює належним чином


102

У Windows clock()повертає час у мілісекундах, але в цьому вікні Linux, над яким я працюю, він округляє його до найближчої 1000, тому точність лише до рівня "другий", а не до рівня мілісекунд.

Я знайшов рішення з Qt за допомогою QTimeкласу, інстанціював об’єкт і викликав start()його, а потім викликав, elapsed()щоб отримати кількість мілісекунд.

Мені пощастило, тому що для початку я працюю з Qt, але мені хотілося б рішення, яке не покладається на сторонні бібліотеки,

Чи немає стандартного способу зробити це?

ОНОВЛЕННЯ

Будь-ласка, не рекомендую.

Якщо Boost і Qt можуть це зробити, це, звичайно, не магія, має бути щось стандартне, що вони використовують!


2
Про редагування - але робити це на портативний спосіб - це біль.
Анонім

Відповіді:


37

Ви можете використовувати gettimeofday на початку та в кінці свого методу, а потім розрізняти дві структури повернення. У вас вийде така структура:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

EDIT: Як підказують два коментарі нижче, clock_gettime (CLOCK_MONOTONIC) є набагато кращим вибором, якщо у вас є його в наявності, який має бути майже скрізь у ці дні.

EDIT: Хтось ще прокоментував, що ви також можете використовувати сучасний C ++ за допомогою std :: chrono :: high_resolution_clock, але це не гарантовано буде монотонним. Замість цього використовуйте steady_clock.


38
страшний для серйозної роботи. Великі проблеми два рази на рік, коли хтось робить побачення, і звичайно синхронізацію NTP. Використовуйте clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: Час UNIX не змінюється двічі на рік. Або навіть раз на рік. Але, так, 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 до різниці?
Махмуд Аль-Кудсі

19
@ Комп'ютерний гуру, це звичайна методика округлення позитивних значень. Коли значення обрізається до цілого значення, то між 0,0 та 0,4999 ... перед тим, як додавання обрізається до 0, і від 0,5 до 0,9999 ... усікається до 1.
Марк Ransom

8
tv_usec не мілісекунд, це мікросекунди.
NebulaFox

13
страшний для серйозної роботи. Великі проблеми двічі на рік, коли хтось проводить побачення - і, звичайно, синхронізація NTP
AndrewStone

14
@AndrewStone вірно, використовуйте clock_gettime (2) з CLOCK_REALTIME для порівняння разів на одному комп’ютері. З 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 секунд, але може більше (ваша програма може запускати декілька потоків і так може споживати більше процесора, ніж у реальному часі) або менше. Він вимірює наближення використовуваного часу процесора . Щоб побачити різницю, врахуйте цей код

#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

Тому що все, що ми робили, спав і не використовував жодного часу процесора! Однак, використовуючи, 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

Якщо вам потрібна більша точність, але ви хочете отримати час процесора , тоді ви можете розглянути можливість використання getrusageфункції.


Про згадку про sleep()- я вже думав задати питання (чому це працює добре для всіх, крім мене ?!) , коли знайшов вашу відповідь.
Привіт-Ангел

18

Я також рекомендую інструменти, запропоновані Boost. Або згаданий Boost Timer, або зламайте щось із Boost.DateTime або є нова запропонована бібліотека в пісочниці - Boost.Chrono : Ця остання буде заміною Таймера і матиме:

  • Програми часу C ++ 0x Standard Library, включаючи:
    • Шаблон класу duration
    • Шаблон класу time_point
    • Годинники:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Шаблон класу timer, з typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Процесорні годинники та таймери:
    • process_clock, фіксуючи реальний, користувальницький процесор та системний процесор.
    • process_timer, захоплюючи минулі реальні, користувальницький процесор та системний процесор.
    • 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
Це круто, але "nseconds" вводить в оману, оскільки timeval не містить наносекунд, він містить мікросекунди, тому я б запропонував людям називати це "секундами".
pho0

Дякую. Виправлення зроблено.
Кріс Редфорд

9

Якщо код не потрібен для перенесення на старі пристрої, ви можете скористатися clock_gettime (), який надасть вам час у наносекундах (якщо ваш процесор підтримує цю роздільну здатність). Це POSIX, але з 2001 року.


4

clock () має часто досить паршиву роздільну здатність. Якщо ви хочете виміряти час на рівні мілісекунд, однією з альтернатив є використання clock_gettime (), як пояснено в цьому запитанні.

(Пам'ятайте, що вам потрібно зв’язатись з -lrt в Linux).


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

clock () не повертає ні мілісекунд, ні секунд на Linux. Зазвичай clock () повертає мікросекунди в системі Linux. Правильний спосіб інтерпретувати значення, повернене годинником (), - розділити його на CLOCKS_PER_SEC, щоб зрозуміти, скільки часу пройшло.


не в коробці, над якою я працюю! плюс, я маю ділячи CLOCKS_PER_SEC, але це безглуздо , тому що дозвіл тільки до другої
HASEN

добре, щоб бути справедливим, одиниці - це мікросекунди (CLOCKS_PER_SEC - 1000000 у всіх системах POSIX). Просто він має роздільну здатність секунди. :-P.
Еван Теран

1

Це повинно працювати ... перевірено на комп'ютері ...

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

Так ... запустіть її двічі і відніміть ...


1

У стандарті POSIX clockсвоє повернене значення визначається символом CLOCKS_PER_SEC, і реалізація може визначити це будь-яким зручним способом. У Linux мені пощастило з times()функцією.


1

gettimeofday - проблема полягає в тому, що він може мати менші значення, якщо змінити апаратний годинник (наприклад, з NTP). Boost - недоступний для цього годинника проекту () - зазвичай повертає ціле ціле число 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.

Не використовуйте функції тривоги та сигналізації, у вас буде низька точність, коли ваш процес буде важко працювати.


0

Я віддаю перевагу бібліотеці Boost Timer для простоти, але якщо ви не хочете використовувати бібліотеки третього паррті, використання годинника () здається розумним.


0

Як оновлення, з'являється, що на windows clock () вимірює час настінного годинника (з точністю CLOCKS_PER_SEC)

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

в той час як в Linux він вимірює час процесора в ядрах, використовуваних поточним процесом

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

і (здається, і як зазначає оригінальний плакат) насправді з меншою точністю, ніж CLOCKS_PER_SEC, хоча, можливо, це залежить від конкретної версії Linux.


0

Мені подобається метод Hola Soy не використовувати gettimeofday (). Сталося зі мною на запущеному сервері адміністратор змінив часовий пояс. Годинник було оновлено, щоб показати те саме (правильне) місцеве значення. Це спричинило зміщення часу функціонування () та 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()через багатозадачність.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.