thread_local内联优化疑问:重复初始化检查必要性及代码优化咨询
关于C++ thread_local变量优化与重复初始化检查的疑问
以下是测试代码:
#include <cstdint> #include <stdio.h> struct ThreadStateLogger { static thread_local struct Instance { char TLS_byteLoc[3] {' ', 0, 0}; uint8_t TLS_numBytes {1}; // 4 wasted bytes here... char* TLS_byteLocPtr {TLS_byteLoc}; void Log(char v) { TLS_byteLocPtr[0] = v; } void Log(char v1, char v2) { TLS_byteLocPtr[0] = v1; if (TLS_numBytes>1) TLS_byteLocPtr[1] = v2; } } instance; static void Log(char v1, char v2) { instance.Log(v1, v2); } // static void Log(char v1, char v2) // { // instance.TLS_byteLocPtr[0] = v1; // if (instance.TLS_numBytes>1) // instance.TLS_byteLocPtr[1] = v2; // } }; extern ThreadStateLogger theThreadStateLogger; int main() { ThreadStateLogger::Log('a', 'b'); // printf("Hello world"); ThreadStateLogger::Log('c', 'd'); return 0; }
在-O3优化级别下,核心实现已被内联,符合预期。首次Log调用正确检查TLS是否需要分配,并通过__tls_get_addr@PLT获取转换后的地址;但第二次Log调用同样执行初始化检查,却复用了第一次缓存的rbx地址,若此时触发初始化,该行为是否存在问题?
clang16生成的汇编代码如下:
main: # @main push rbx cmp qword ptr [rip + _ZTHN17ThreadStateLogger8instanceE@GOTPCREL], 0 je .LBB0_2 call TLS init function for ThreadStateLogger::instance@PLT .LBB0_2: data16 lea rdi, [rip + ThreadStateLogger::instance@TLSGD] data16 data16 rex64 call __tls_get_addr@PLT mov rbx, rax mov rax, qword ptr [rax + 8] mov byte ptr [rax], 97 cmp byte ptr [rbx + 3], 2 jae .LBB0_3 cmp qword ptr [rip + _ZTHN17ThreadStateLogger8instanceE@GOTPCREL], 0 jne .LBB0_5 .LBB0_6: mov rax, qword ptr [rbx + 8] mov byte ptr [rax], 99 cmp byte ptr [rbx + 3], 2 jae .LBB0_7 .LBB0_8: xor eax, eax pop rbx ret .LBB0_3: mov rax, qword ptr [rbx + 8] mov byte ptr [rax + 1], 98 cmp qword ptr [rip + _ZTHN17ThreadStateLogger8instanceE@GOTPCREL], 0 je .LBB0_6 .LBB0_5: call TLS init function for ThreadStateLogger::instance@PLT mov rax, qword ptr [rbx + 8] mov byte ptr [rax], 99 cmp byte ptr [rbx + 3], 2 jb .LBB0_8 .LBB0_7: mov rax, qword ptr [rbx + 8] mov byte ptr [rax + 1], 100 xor eax, eax pop rbx ret
移除printf后,初始化检查次数增加,但__tls_get_addr仍被缓存。当前仅存在重复的TLS单例初始化检查(已知已完成初始化),导致代码膨胀。
核心疑问:
- 为何重复执行初始化检查?
- 若该检查必要,为何无需重新生成地址?
- 这是否是未被优化的点?
- 是否可通过调整代码结构实现更优的优化效果?
注:需保留此类日志类的功能,通过类封装3个TLS变量以确保它们被一同构造。
内容的提问来源于stack exchange,提问作者Gem Taylor
相关产品推荐
相关产品推荐

