我的代码执行以下操作:
我发现执行延迟关键任务所需的时间比长时间运行计算要高,而不是没有它。
以下是一些重现此效果的独立C ++代码:
#include <stdio.h>
#include <stdint.h>
#define LEN 128
#define USELESS 1000000000
//#define USELESS 0
// Read timestamp counter
static inline long long get_cycles()
{
unsigned low, high;
unsigned long long val;
asm volatile ("rdtsc" : "=a" (low), "=d" (high));
val = high;
val = (val << 32) | low;
return val;
}
// Compute a simple hash
static inline uint32_t hash(uint32_t *arr, int n)
{
uint32_t ret = 0;
for(int i = 0; i < n; i++) {
ret = (ret + (324723947 + arr[i])) ^ 93485734985;
}
return ret;
}
int main()
{
uint32_t sum = 0; // For adding dependencies
uint32_t arr[LEN]; // We'll compute the hash of this array
for(int iter = 0; iter < 3; iter++) {
// Create a new array to hash for this iteration
for(int i = 0; i < LEN; i++) {
arr[i] = (iter + i);
}
// Do intense computation
for(int useless = 0; useless < USELESS; useless++) {
sum += (sum + useless) * (sum + useless);
}
// Do the latency-critical task
long long start_cycles = get_cycles() + (sum & 1);
sum += hash(arr, LEN);
long long end_cycles = get_cycles() + (sum & 1);
printf("Iteration %d cycles: %lld\n", iter, end_cycles - start_cycles);
}
}
当使用-O3
编译并将USELESS
设置为10亿时,三次迭代分别进行了588,4184和536次循环。在USELESS
设置为0的情况下进行编译时,迭代分别需要394,358和362个周期。
为什么会发生这种情况(尤其是4184次循环)?我怀疑由于强烈的计算引起的缓存未命中或分支错误预测。但是,如果没有强烈的计算,延迟关键任务的第0次迭代非常快,所以我不认为冷缓存/分支预测器是原因。
答案 0 :(得分:1)
将我的推测评论转移到答案:
当您的繁忙循环运行时,服务器上的其他任务可能会将缓存的arr
数据推出L1缓存,以便hash
中的第一个内存访问需要重新加载来自较低级别的缓存。没有计算循环,就不会发生这种情况。您可以尝试将arr
初始化移动到计算循环之后,只是为了看看效果是什么。