lol*_*pop 5 c++ multithreading gcc thread-local-storage
我有使用 thread_local 缓冲区的代码,类似于:
int func() {
thread_local std::vector<int> buffer;
buffer.resize(0);
for (int i = 0; i < 10000; i++) {
buffer.push_back(i);
}
return processing(buffer);
}
Run Code Online (Sandbox Code Playgroud)
在分析我的代码时,我注意到 gcc 在循环体内调用了一个调用_tls_get_addr()
,以便访问buffer
. 循环体的Godbolt反汇编如下所示:
lea rbx, -20[rbp]
data16 lea rdi, f()::buffer@tlsgd[rip]
.value 0x6666
rex64
call __tls_get_addr@PLT ; <- This call!
mov rsi, rbx
mov rdi, rax
call std::vector<int, std::allocator<int> >::push_back(int const&)@PLT
Run Code Online (Sandbox Code Playgroud)
这些调用大大减慢了循环速度。我可以手动使用此版本并参考:
lea rbx, -20[rbp]
data16 lea rdi, f()::buffer@tlsgd[rip]
.value 0x6666
rex64
call __tls_get_addr@PLT ; <- This call!
mov rsi, rbx
mov rdi, rax
call std::vector<int, std::allocator<int> >::push_back(int const&)@PLT
Run Code Online (Sandbox Code Playgroud)
这消除了调用_tls_get_addr()
并解决了缓慢问题。我必须为每个这样的变量手动执行此操作,这似乎很愚蠢。为什么gcc不会自动缓存结果_tls_get_addr()
?Clang似乎能够使用来做到这一点-O3
,因此它表明这是 gcc 尚未实现的合法优化。是这样吗?
将 tls 模型更改为 init-exec 也消除了这些调用,但我的库通常作为 Python 扩展动态加载,所以我的理解是在这种情况下这是不可能的。
归档时间: |
|
查看次数: |
439 次 |
最近记录: |