2017-12-11 4 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

,488,353 어셈블리 코드 출력 찾고
#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 예. 독립 실행 형 응용 프로그램의 생성은 OK – 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의 bugtracker : https://gcc.gnu.org/bugzilla/
연타 bugtracker : 그것은 나에게 나쁜 인라인 논리를 보이는 이유 https://bugs.llvm.org/

+0

이미보고 된 것 같습니다. gcc 이상 : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82803 – James