【问题标题】:Getting timing consistency in Linux在 Linux 中获得时序一致性
【发布时间】:2011-02-04 12:44:59
【问题描述】:

我似乎无法获得一个简单的程序(具有大量内存访问)来在 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;
}

【问题讨论】:

  • 您是否以 root 身份运行`(否则您将无法使用 SCHED_FIFO)。此外, volatile 不会绕过 CPU 缓存效果。另见stackoverflow.com/questions/88
  • 是的 - 我以 root 身份运行它。另外,我看不到那篇文章的哪一部分谈到了缓存。
  • 它谈论的是 gettimeofday 分辨率,而不是缓存 :)

标签: c linux memory benchmarking timing


【解决方案1】:

确保没有其他进程占用 CPU 时间。特别要注意屏幕保护程序和任何定期进行 GUI 更新的东西(例如时钟或类似物)。尝试为您的基准测试进程设置 CPU 亲和性,以将其锁定到一个核心上(例如,来自命令行的taskset)。如果不分页,请进行基准测试 - 通常您希望有一个运行 N 次的外部循环,然后为最后 N-1 次执行计时。

【讨论】:

  • 我很确定将进程设置为实时优先级可以保护我免受所有这些 GUI 的影响。音频有时也是 RT,但我确保没有任何那种类型的东西在运行。正如您所说,我确实将其限制为一个核心。正如您从结果中看到的那样,有 7 个异常值,因此排除第一个异常值是行不通的。异常值在试验中均匀分布。
  • @Jim:我不太确定实时优先级 - 尝试完全摆脱 GUI 并从控制台 (sudo init 1) 运行并使用 taskset 以确保 CPU亲和力。
  • init 1 成功了。很高兴知道有 GUI 的东西会搞乱 RT 进程。不过,我不太明白那里发生了什么。我系统上唯一的 RT 进程是 migration/0migration/1watchdog/0watchdog/1。谢谢!
  • @Jim:酷!我希望一切都那么容易解决。 ;-) 当您启用 GUI 时,可能会出现某种 60 Hz 中断驱动的过程,这可能不会出现在 top 之类的东西中,但这足以扰乱您的时间安排。通常所有中断都由系统上的第一个内核 (0) 处理,因此使用taskset 在第二个内核 (1) 上运行您的代码也可能是一种解决方案。
  • Linux 不是硬实时系统,这意味着即使进程具有实时优先级,仍然有一些东西可以抢占您的进程,尤其是 irq 处理程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
相关资源
最近更新 更多