我不会打扰。我刚刚运行了这个基准测试:
#include<stdio.h>
#define SIZE 1000000
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
void print_avg(const char *str, const int *diff, int size)
{
int i;
long sum = 0;
int max = -1, min = 10000;
for(i = 0; i < size; i++)
{
int t = diff[i];
sum += t;
if (t > max) max = t;
if (t < min) min = t;
}
printf("%s average =%f clocks, max =%d, min =%d\n", str, (double)sum / size, max, min);
}
int main()
{
unsigned long long a, b;
int diff[SIZE];
int value = 0;
int i;
for(i = 0; i < SIZE; i++)
{
a = rdtsc();
__sync_fetch_and_add(&value, 2);
b = rdtsc();
diff[i] = (int)(b - a);
}
print_avg("Locked", diff, SIZE);
for(i = 0; i < SIZE; i++)
{
a = rdtsc();
value += 2;
b = rdtsc();
diff[i] = (int)(b - a);
}
print_avg("Not locked", diff, SIZE);
return 0;
}
使用 gcc -O2 编译,结果如下:
Locked average =105.672402 clocks, max =38756, min =86
Not locked average =80.540389 clocks, max =23433, min =73
我跑了好几次,每次的结果都非常相似。请忽略最大值的大数字 - 那是处理器接受中断或其他东西的时候 - 它来自我为不同目的编写的一些代码,我只是为了这个测试回收了它。这个微小的差异应该适用于所有现代处理器(Intel iCore 和 AMD Athlon64 以及那些世代)
除非由于某种原因您的编译器没有内联 InterlockedIncrement,否则在您的代码上添加一个 if 语句很可能会花费至少 5 个周期,因此您最多可以节省 10 个周期。希望您做的不是增加和减少引用计数器。
编辑:添加内存屏障也没有太大区别 - 大约 10 个周期。
诚然,如果我在第二个循环中添加 10 个加法,则每个循环大约需要 5 个时钟周期(因此平均每个加法需要半个时钟),而锁定加法每次加法需要大约 20 个时钟。在我看来,仍然不值得添加 if 语句。但是,如果您想添加“if (nr_threads == 1) a = a + 1; else a = __sync_fetch_and_add(a, 1);”,[或任何你需要做的事情] 我不会阻止你. 但是请确保您对整个应用程序进行基准测试,并确保它的改进超过 1%——我对此表示怀疑。请回来告诉我们有什么区别。我在 Linux 内核的“解除分配页表条目”中添加的 if 语句使它慢了 2-5%,所以不值得。但是,如果您在代码中发现了这一点,那就值得了,做我的客人吧。我说的是经验,