C 在Linux中获得时间一致性

C 在Linux中获得时间一致性,c,linux,memory,benchmarking,timing,C,Linux,Memory,Benchmarking,Timing,我似乎无法获得一个简单的程序(具有大量内存访问)来在Linux中实现一致的计时。我使用的是2.6内核,程序运行在具有实时优先级的双核处理器上。我试图通过将内存阵列声明为volatile来禁用缓存效果。以下是结果和程序。异常值的可能来源是什么 结果: Number of trials: 100 Range: 0.021732s to 0.085596s Average Time: 0.058094s Standard Deviation: 0.006944s Extreme Outliers (2

我似乎无法获得一个简单的程序(具有大量内存访问)来在Linux中实现一致的计时。我使用的是2.6内核,程序运行在具有实时优先级的双核处理器上。我试图通过将内存阵列声明为volatile来禁用缓存效果。以下是结果和程序。异常值的可能来源是什么

结果:

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;
}
#包括
#包括
#包括
#包括
#包括
#定义点数5000000
#定义重复100次
未签名的long-long getTimestamp(){
未签名的长使用帐户;
结构timeval-timeval;
gettimeofday(&timeVal,0);
UseCount=timeVal.tv_sec*(无符号长-长)1000000;
UseCount+=timeVal.tv\u usec;
返回(使用帐户);
}
双convertTimestampToSecs(无符号长时间戳){
返回(时间戳/(双)1000000);
}
int main(int argc,char*argv[]){
无符号长-长启动、停止;
两次[重复];
双和=0;
双刻度,平均值,新平均值,中位数;
双标准差=0;
双maxval=-1.0,minval=1000000.0;
int i,j,freq,count;
int异常值=0;
结构sched_param sparam;
sched_getparam(getpid(),&sparam);
sparam.sched_priority=sched_get_priority_max(sched_FIFO);
sched_setscheduler(getpid()、sched_FIFO和sparam);
易变浮动*数据;
浮动浮动*结果;
数据=calloc(点数、大小(浮动));
结果=calloc(NUM_POINTS,sizeof(float));
对于(i=0;imaxval)
maxval=次[i];
if(乘以[i]avg+2*STDEV | |次[i]
确保没有其他占用CPU时间的进程。尤其要注意屏幕保护程序和任何定期进行GUI更新的东西(例如时钟或类似的东西)。尝试为基准进程设置CPU相关性,以将其锁定到一个核心上(例如,从命令行执行
taskset
)。如果不分页,则创建基准进程-通常您希望有一个运行N次的外部循环,然后对最后N-1次执行进行计时。

您是否以root`身份运行(否则您将无法使用SCHED_FIFO)。此外,volatile不会绕过CPU缓存效果。另请参见:是的,我以root用户身份运行此程序。另外,我不知道那篇文章的哪一部分谈到了缓存。它谈到的是gettimeofday解析,而不是缓存:)我非常确定,将进程设置为实时优先级可以保护我免受所有GUI方面的影响。音频有时也是RT,但我确保没有任何这种类型的运行。正如你所说,我把它限制在一个核心。从结果中可以看出,有7个异常值,因此排除第一个异常值不会起作用。异常值平均分布在各个测试中。@Jim:我不太确定实时优先级-尝试完全摆脱GUI,只需从控制台(
sudo init 1
)运行,并使用
taskset
确保CPU亲和力。
init 1
做到了这一点。很高兴知道有GUI的东西会扰乱RT过程。不过,我不太明白那里发生了什么。我的系统上唯一的RT进程是
migration/0
migration/1
watchdog/0
watchdog/1
。谢谢@吉姆:酷!我希望一切都那么容易解决当您启用GUI时,可能会出现某种60 Hz的中断驱动过程,这种过程可能不会出现在
top
之类的内容中,但其重要性足以干扰您的计时。通常,所有中断都由系统(0)上的第一个内核处理,因此使用
任务集
在第二个内核(1)上运行代码也可能是一种解决方案。Linux不是硬实时系统,这意味着即使进程具有实时优先级,仍然有一些东西可以抢占进程,特别是irq处理程序。