Получение согласованности по времени в Linux

Кажется, я не могу получить простую программу (с большим количеством доступа к памяти) для достижения согласованного времени в Linux. Я использую ядро ​​2.6, и программа запускается на двухъядерном процессоре с приоритетом реального времени. Я пытаюсь отключить эффекты кеширования, объявив массивы памяти энергозависимыми. Ниже представлены результаты и программа. Каковы возможные источники выбросов?

Результаты:

Number of trials: 100
Range: 0.021732s to 0.085596s
Average Time: 0.058094s
Standard Deviation: 0.006944s
Extreme Outliers (2 SDs away from mean): 7
Average Time, excluding extreme outliers: 0.059273s

Программа:

#include <stdio.h>
#include <stdlib.h> 
#include <math.h>

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

#define NUM_POINTS 5000000
#define REPS 100

unsigned long long getTimestamp() {
  unsigned long long usecCount;
  struct timeval timeVal;
  gettimeofday(&timeVal, 0);
  usecCount = timeVal.tv_sec * (unsigned long long) 1000000;
  usecCount += timeVal.tv_usec;
  return (usecCount);
}

double convertTimestampToSecs(unsigned long long timestamp) {
  return (timestamp / (double) 1000000);
}

int main(int argc, char* argv[]) {
  unsigned long long start, stop;
  double times[REPS];
  double sum = 0;
  double scale, avg, newavg, median;
  double stddev = 0;
  double maxval = -1.0, minval = 1000000.0;
  int i, j, freq, count;
  int outliers = 0;
  struct sched_param sparam;

  sched_getparam(getpid(), &sparam);
  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
  sched_setscheduler(getpid(), SCHED_FIFO, &sparam);

  volatile float* data;
  volatile float* results;

  data = calloc(NUM_POINTS, sizeof(float)); 
  results = calloc(NUM_POINTS, sizeof(float)); 

  for (i = 0; i < REPS; ++i) {
    start = getTimestamp();
    for (j = 0; j < NUM_POINTS; ++j) {
      results[j] = data[j];
    }
    stop = getTimestamp();
    times[i] = convertTimestampToSecs(stop-start);
  }

  free(data);
  free(results);

  for (i = 0; i < REPS; i++) {
    sum += times[i];

    if (times[i] > maxval)
      maxval = times[i];

    if (times[i] < minval)
      minval = times[i];
  }
  avg = sum/REPS;

  for (i = 0; i < REPS; i++)
    stddev += (times[i] - avg)*(times[i] - avg);
  stddev /= REPS;
  stddev = sqrt(stddev);

  for (i = 0; i < REPS; i++) {
    if (times[i] > avg + 2*stddev || times[i] < avg - 2*stddev) {
      sum -= times[i];
      outliers++;
    }
  }
  newavg = sum/(REPS-outliers);

  printf("Number of trials: %d\n", REPS);
  printf("Range: %fs to %fs\n", minval, maxval);
  printf("Average Time: %fs\n", avg);
  printf("Standard Deviation: %fs\n", stddev);
  printf("Extreme Outliers (2 SDs away from mean): %d\n", outliers);
  printf("Average Time, excluding extreme outliers: %fs\n", newavg);

  return 0;
}

person Jim Hunziker    schedule 05.04.2010    source источник
comment
Вы работаете как root` (иначе вы не сможете использовать SCHED_FIFO). Кроме того, volatile не обходится без эффектов кеш-памяти ЦП. См. Также stackoverflow.com/questions/88.   -  person nos    schedule 05.04.2010
comment
Ага - я запускаю это как root. Кроме того, я не понимаю, в какой части этой статьи говорится о кеше.   -  person Jim Hunziker    schedule 05.04.2010
comment
Здесь говорится о разрешении gettimeofday, а не о кешах :)   -  person nos    schedule 06.04.2010


Ответы (1)


Убедитесь, что у вас нет других процессов, занимающих процессорное время. В частности, обратите внимание на хранители экрана и все, что регулярно обновляет графический интерфейс (например, часы или подобное). Попробуйте установить привязку к процессору для вашего тестового процесса, чтобы привязать его к одному ядру (например, taskset из командной строки). Сделайте свой тестовый процесс, если не пейджинг - обычно вы хотите иметь внешний цикл, который выполняется N раз, а затем время последнего выполнения N-1.

person Paul R    schedule 05.04.2010
comment
Я почти уверен, что установка приоритета процесса в реальном времени защищает меня от всех этих проблем с графическим интерфейсом. Аудио иногда тоже RT, но я убедился, что ничего подобного не работает. Я ограничился одним ядром, как вы сказали. Как видно из результатов, имеется 7 выбросов, поэтому исключение первого не поможет. Выбросы равномерно распределяются по испытаниям. - person Jim Hunziker; 05.04.2010
comment
@ Джим: Я бы не был слишком уверен насчет приоритета в реальном времени - попробуйте полностью избавиться от графического интерфейса пользователя и просто запустите его с консоли (sudo init 1) и используйте taskset, чтобы обеспечить привязку к процессору. - person Paul R; 05.04.2010
comment
init 1 сделал свое дело. Приятно знать, что есть вещи с графическим интерфейсом, которые могут испортить процесс RT. Однако я не совсем понимаю, что там происходит. Единственными процессами RT в моей системе являются migration/0, migration/1, watchdog/0 и watchdog/1. Спасибо! - person Jim Hunziker; 06.04.2010
comment
@ Джим: Круто! Я бы хотел, чтобы все было так легко исправить. ;-) Возможно, когда у вас включен графический интерфейс, будет происходить какой-то процесс, управляемый прерыванием с частотой 60 Гц, который, возможно, не отображается в чем-то вроде top, но достаточно значительный, чтобы нарушить ваше время. Обычно все прерывания обрабатываются первым ядром системы (0), поэтому использование taskset для запуска вашего кода на втором ядре (1) также может быть решением. - person Paul R; 06.04.2010
comment
Linux не является системой жесткого реального времени, а это означает, что есть вещи, которые могут вытеснить ваш процесс, даже если он имеет приоритет реального времени, в частности обработчики irq. - person nos; 06.04.2010
comment
Разве в настройках BIOS тоже что-то не нужно делать? Если я правильно понял, современные процессоры Intel меняют частоту на лету. Разумно предположить, что эти корректировки могут повлиять на тайминги. Я был бы очень признателен, если бы кто-нибудь мог пролить свет на эту сторону вопроса. - person AlwaysLearning; 12.01.2015