2011-03-16 71 views
1

我试图测试我有权访问的计算机的缓存属性。要做到这一点,我正在尝试阅读记忆和时间。我改变工作集大小和跨步访问模式以获得不同的测量结果。控制海湾合作委员会优化

代码看起来像这样:

clock1 = get_ticks() 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    *array[j]; 
    } 
} 
clock2 = get_ticks() 

现在的问题是,有一个合理的优化级别,GCC将优化出来读,因为它没有副作用。我不能没有优化级别,否则所有循环变量都会导致读取到内存。我已经尝试了一些不同的东西,比如使数组变为volatile,并且使用内联函数来将其转换为volatile,但gcc对volatile变量的处理很难预测。什么是适当的方式来做到这一点?

+1

不知道这是多么可行:编译成汇编器,没有优化,你想要的代码,然后用'asm {}'块代替C代码并编译整个程序。 – pmg 2011-03-16 22:42:01

+1

Ulrich Drepper的“每个程序员应该知道的内存”(http://www.akkadia.org/drepper/cpumemory.pdf)包含一些缓存属性的基准。 – ninjalj 2011-03-16 23:47:42

+0

舌头:确保循环计算一个开放的数学问题的解决方案,以便编译器无法优化它:http://blog.regehr.org/archives/140 – 2011-03-17 00:05:28

回答

2

一种可能性是以不易被优化的方式使用阵列数据,例如,

clock1 = get_ticks(); 
sum = 0; 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    sum += array[j]; 
    } 
} 
clock2 = get_ticks(); 
return sum; 

sum应在寄存器中,并且加载操作应该添加什么可循环定时显著。

如果测试函数和调用者都在同一个编译单元中,您可能还需要确保您实际上对返回的总和值做了一些处理,例如,通过printf输出。

+0

GCC将优化它。例如,gcc可以将内循环的一次运行后的和的值乘以1000000,并且它是正确的。 – dschatz 2011-03-16 22:33:46

+0

@dschatz:您可能需要确保您确实使用返回的总和值进行了处理,例如通过printf输出。 – 2011-03-16 22:35:48

+0

输出它并不重要,它可以优化两个循环并获得值。 – dschatz 2011-03-16 22:37:04

1

对于GCC尝试指定usedattribute所有指标变量(ij),以避免对他们(即使启用了全局优化选项)编译器优化:

int i __attribute__((used)); 
int j __attribute__((used)); 

clock1 = get_ticks() 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    *array[j]; 
    asm (""); // help to avoid cycle's body elimination 
    } 
} 
clock2 = get_ticks(); 

也不错知道,asm(...)表达式永远不会被优化。你甚至可以在没有任何汇编表达式的情况下使用它,像这样:asm("");

0

我想你应该真的试着用汇编语言编写它,如果你不想让编译器模糊它的话。你不能确保任何“诀窍”将永远工作。现在有效的东西可能会在未来版本的编译器中得到优化。也很难预测它是否有效。如果你能够检查汇编代码,看它是否工作(即没有优化它),你应该可以从头开始编写它?

0

在每次迭代中将值存储到一个volatile全局变量。这将确保实际写入发生(例如,确保在信号处理程序中可以看到正确的值)。

另外,使用类似

sum += *array[j]^i; 

这是很简单的计算,但可以确保编译器无法轻松地优化了循环与求和公式。

相关问题