我有兴趣探索变量中的某些写入可以跨线程反射(reflect)的最短时间。 为此,我使用全局原子变量并定期更新它。同时,另一个线程旋转并检查更新的值。两个线程都附加到单独的隔离核心(操作系统 - ubuntu)。
//global
constexpr int total = 100;
atomic<int64_t> var;
void reader()
{
int count = 0;
int64_t tps[total];
int64_t last = 0;
while(count < total)
{
int64_t send_tp = var.load(std::memory_order_seq_cst);
auto tp = high_resolution_clock::now();
int64_t curr = duration_cast<nanoseconds>(tp.time_since_epoch()).count();
if (send_tp != last)
{
last = send_tp;
tps[count] = curr - send_tp;
count++;
}
}
for(auto i = 0; i<total; i++)
cout << tps[i] << endl;
}
void writer()
{
for (int i=0; i<total; i++)
{
auto tp = high_resolution_clock::now();
int64_t curr = duration_cast<nanoseconds>(tp.time_since_epoch()).count();
var.store(curr, std::memory_order_seq_cst);
// adding delay in writes, so that none are missed
while(duration_cast<nanoseconds>(high_resolution_clock::now() - tp).count() < 100000000);
}
}
使用这个程序,我得到了大约 70 纳秒的中位时间。
我还尝试衡量管理费用
void overhead() {
int count = 0;
int64_t tps[total];
int64_t last = 0;
while(count < total)
{
auto tp1 = high_resolution_clock::now();
int64_t to_send = duration_cast<nanoseconds>(tp1.time_since_epoch()).count();
var.store(to_send, std::memory_order_seq_cst);
int64_t send_tp = var.load(std::memory_order_seq_cst);
auto tp = high_resolution_clock::now();
int64_t curr = duration_cast<nanoseconds>(tp.time_since_epoch()).count();
if (send_tp != last)
{
last = send_tp;
tps[count] = curr - send_tp;
count++;
}
}
for(auto i = 0; i<total; i++)
cout << tps[i] << endl;
}
我知道原子在单线程访问中不会有太多开销,结果中位数为 30 纳秒(我猜是由于 chrono::high_resolution_clock())。
因此得出的结论是延迟约为 40 纳秒(中值)。我尝试了不同的内存顺序,例如 memory_order_relaxed
或 release-acquire
,但结果非常相似。
根据我的理解,所需的同步只是从相邻核心获取 L1 缓存行,所以为什么要花费大约 40 纳秒的时间。我是否遗漏了某些内容,或者对如何改进设置有任何建议?
硬件详细信息 -
Intel(R) Core(TM) i9-9900K CPU(禁用超线程)
编译:g++ file.cpp -lpthread -O3
最佳答案
40ns 线程间延迟(包括测量开销)听起来很适合现代 x86 CPU。
是的,存储时间戳并根据读取器中的时间测量结果检查它听起来很合理。
内核之间的缓存一致性消息必须通过环形总线到达 L3 切片。当加载请求(在 L2 中丢失)到达正确的 L3 切片时,它将检测(从包含的 L3 标记)另一个线程拥有处于 MESI 独占或修改状态的行,并向该核心生成一条消息。然后该核心将进行写回(并且可能将数据直接发送到请求它的核心?)
这是在桌面 CPU 上,我们知道没有其他插槽可以窥探一致性:英特尔服务器 CPU 的内存延迟和内核间延迟明显更高。
关于c++ - 跨线程原子变量更新反射的延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76304040/