2017-12-11 3 views
2

編集をキャッシュされていない:確かにコンパイラのバグであると思われる:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82803結果は

私はstd::stringstreamバッファを保存するためにTLSを使用して書き込みログのラッパーを書いています。このコードは共有ライブラリによって使用されます。 godbolt.orgのコードを見ると、gccもclangもTLSルックアップの結果をキャッシュしていないように思えます(私はループを設計していると信じてループに繰り返し__tls_get_addr()を呼び出します)。

打ち鳴らす5.0.0:

xor ebx, ebx 
.LBB0_3: # =>This Inner Loop Header: Depth=1 
data16 
lea rdi, [rip + LogStream::getBuffer[abi:cxx11]()::buffer[abi:cxx11]@TLSGD] 
data16 
data16 
rex64 
call [email protected] // Called on every loop iteration. 
lea rdi, [rax + 16] 
mov esi, ebx 
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@PLT 
inc ebx 
cmp ebx, 12345678 
jne .LBB0_3 

GCC 7.2:

アセンブリコードの出力を見てみる
#include <sstream> 

class LogStream 
{ 
public: 
    LogStream() 
    : m_buffer(getBuffer()) 
    { 
    } 

    LogStream(std::stringstream& buffer) 
    : m_buffer(buffer) 
    { 
    } 

    static std::stringstream& getBuffer() 
    { 
     thread_local std::stringstream buffer; 
     return buffer; 
    } 

    template <typename T> 
    inline LogStream& operator<<(const T& t) 
    { 
     m_buffer << t; 
     return *this; 
    } 

private: 
    std::stringstream& m_buffer; 
}; 


int main() 
{ 
    LogStream log{}; 

    for (int i = 0; i < 12345678; ++i) 
    { 
     log << i; 
    } 
} 

両方GCCと打ち鳴らすはかなり似た出力を生成します

どのようにして両方のコンパイラにルックアップを繰り返し実行する必要はないのだろうか?

コンパイラオプション:-std=c++11 -O3 -fPIC

Godbolt link

+0

インラインしないようにgetbufferを強制的にまたは動的にされるLogStreamは私のために働くように思わ割り当て... dunnow ... –

+0

は指定しません'-fPIC'はまた、奇妙なコードを生成しません。 –

+0

@SebastianRedlはい、スタンドアロンアプリの世代は大丈夫です – James

答えて

2

これは本当にクランとGCCの両方で最適化のバグのように見えます。

ここで私は起こると思います。 (私は完全にオフになる場合もあります。)コンパイラは、完全にこのコードに至るまで、すべてをインライン化:

int main() 
{ 
    // pseudo-access 
    std::stringstream& m_buffer = LogStream::getBuffer::buffer; 
    for (int i = 0; i < 12345678; ++i) 
    { 
     m_buffer << i; 
    } 
} 

そして、-fPICの下で非常に高価なスレッドローカルへのアクセスをされて実現していない、それは決定している一時的な参照にグローバルは必要ではなく、インラインでも同様です。

int main() 
{ 
    for (int i = 0; i < 12345678; ++i) 
    { 
     // pseudo-access 
     LogStream::getBuffer::buffer << i; 
    } 
} 

実際に何が起こったとしても、これは明らかにあなたが書いたコードの悲観化です。これをGCCとClangのバグとして報告してください。

GCCのバグトラッカー:https://gcc.gnu.org/bugzilla/
クランバグトラッカー:、それは私に悪いインライン化ロジックを思わなぜhttps://bugs.llvm.org/

+0

これは既に報告されているようですgcc以上:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82803 – James