Почему компилятор не может оптимизировать чтение из TLS? - PullRequest
0 голосов
/ 17 декабря 2018

Рассмотрим следующий заголовочный файл "tls.h":

#include <stdint.h>

// calling this function is expensive
uint64_t foo(uint64_t x);

extern __thread uint64_t cache;

static inline uint64_t
get(uint64_t x)
{
    // if cache is not valid
    if (cache == UINT64_MAX)
        cache = foo(x);

    return cache + x;
}

и исходный файл "tls.c":

#include "tls.h"

__thread uint64_t cache = {0};

uint64_t foo(uint64_t x)
{
    // imagine some calculations are performed here
    return 0;
}

Ниже приведен пример использования функции get()в "main.c":

#include "tls.h"

uint64_t t = 0;

int main()
{
    uint64_t x = 0;

    for(uint64_t i = 0; i < 1024UL * 1024 * 1024; i++){
        t += get(i);
        x++;
    }
}

Представленные файлы компилируются следующим образом:

gcc -c -O3 tls.c
gcc -c -O3 main.c
gcc -O3 main.o tls.o

Изучение производительности цикла в "main.c" показало, что оптимизация компилятора очень плохая,После разборки двоичного файла становится ясно, что доступ к tls осуществляется на каждой итерации.Время выполнения на моей машине составляет 1.7 с.

Однако, если я уберу проверку проверки кэша в методе get(), чтобы он выглядел так:

static inline uint64_t
get(uint64_t x)
{
    return cache + x;
}

, компилятор теперь можетсоздавать гораздо более быстрый код - он полностью удаляет цикл и генерирует только одну инструкцию «добавить».Время выполнения составляет ~ 0,02 с.

Почему компилятор не может оптимизировать первый случай?Переменная TLS не может быть изменена другими потоками, поэтому компилятор должен быть в состоянии оптимизировать это, верно?

Есть ли другой способ оптимизировать функцию get()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...