Как измерить, сколько времени занимает выполнение функции (linux C)?


У меня есть определенная функция (ну, набор функций), которую я хочу запускать каждые 400 мс. я не очень хорошо программирую на C, и поэтому все, что находится за пределами стандартных библиотек, является для меня загадкой, а также довольно много в них.

Моя первая мысль - использовать nanosleep для приостановки выполнения на 400 мс в каком-то цикле, но это, конечно, не учитывает время выполнения кода, который я буду запускать. Если бы я мог измерить его, и если бы он казался достаточно уверенным, что он бежит в течение той же приблизительной продолжительности после 10 или 20 тестов я мог бы затем nanosleep() для разницы. Конечно, это было бы не идеально... но для первой попытки он может оказаться достаточно близко.

Как измерить время выполнения функции C? Или есть лучший способ сделать это вообще, и какие ключевые слова мне нужно гуглить?

6 2

6 ответов:

Вы должны уметь использовать сеттимер

int setitimer(int which, const struct itimerval *value,
              struct itimerval *ovalue);

Просто поместите код, который вы хотите выполнить каждые 400 мс внутри обработчика SIGALRM. Таким образом, вам не нужно учитывать время, которое ваш код занимает для выполнения, что потенциально может варьироваться. Я не уверен, что произойдет, если обработчик сигнала не вернется до того, как будет сгенерирован следующий сигнал.

Схема того, как может выглядеть часть кода, показана ниже.

void periodic_fuc(int signal_num)
{
  ...
  signam(SIGALRM, periodic_func);
}

int main(...)
{
  struct itimerval timerval = {0};

  signal(SIGALRM, periodic_func);      
  ...
  timerval.it_interval.tv_usec = 400000;
  timerval.it_value.tv_usec = 400000; // Wait 400ms for first trigger
  settimer(ITIMER_REAL, &timerval, NULL);

  while (!exit)
    sleep(1);
  return 0;
}

Взгляните на gprof. Это позволяет быстро перекомпилировать код и генерировать информацию о том, какие функции вызываются и что занимает больше всего времени в вашей программе.

Я согласен с тораком об использовании setitimer(). Однако, поскольку неясно, перезапускается ли интервал, когда обработчик SIGALRM завершает работу, и вы действительно не должны делать много работы в обработчике сигнала в любом случае, лучше просто установить флаг и выполнить работу в основной подпрограмме:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>

volatile sig_atomic_t wakeup = 0;

void alarm_handler(int signal_num)
{
    wakeup = 1;
}

int main()
{
    struct itimerval timerval = { 0 };
    struct sigaction sigact = { 0 };
    int finished = 0;

    timerval.it_interval.tv_usec = 400000;
    timerval.it_value.tv_usec = 400000;

    sigact.sa_handler = alarm_handler;

    sigaction(SIGALRM, &sigact, NULL);
    setitimer(ITIMER_REAL, &timerval, NULL);

    while (!finished)
    {
        /* Wait for alarm wakeup */
        while (!wakeup)
            pause();
        wakeup = 0;

        /* Code here... */
        printf("(Wakeup)\n");
    }

    return 0;
}

Вы могли бы использовать gettimeofday() или clock_gettime() до и после функции времени, а затем вычислить дельту между двумя временами.

Для Linux можно использовать gettimeofday. Вызовите gettimeofday в начале функции. Бегите, что вам нужно бежать. Затем получите конечное время и выясните, сколько еще вам нужно спать. Затем вызовите usleep на соответствующее количество микросекунд.

Посмотрите на таймеры POSIX. Вотнекоторая документация в HP .

Вы можете выполнять те же функции, что и с setitimer, но у вас также есть функция timer_getoverrun (), чтобы сообщить вам, если вы пропустили какие-либо события таймера во время выполнения функции.