Почему компиляция кода, влияющего на лямбду, в std :: function является такой медленной, особенно с Clang? - PullRequest
0 голосов
/ 25 сентября 2018

Я обнаружил, что время компиляции сравнительно небольшого объема кода, преобразования лямбда-функций в значения std::function<>, может быть очень высоким, в частности, с помощью компилятора Clang.

Рассмотрим следующий фиктивный код, который создает 100лямбда-функции:

#if MODE==1
#include <functional>
using LambdaType = std::function<int()>;
#elif MODE==2
using LambdaType = int(*)();
#elif MODE==3
#include "function.h" // https://github.com/skarupke/std_function
using LambdaType = func::function<int()>;
#endif

static int total=0;

void add(LambdaType lambda)
{
    total += lambda();
}

int main(int argc, const char* argv[])
{
    add([]{ return 1; });
    add([]{ return 2; });
    add([]{ return 3; });
    // 96 more such lines...
    add([]{ return 100; });

    return total == 5050 ? 0 : 1;
}

В зависимости от макроса препроцессора MODE этот код может выбирать один из следующих трех способов передачи лямбда-функции в add функцию:

  1. std::function<> шаблон класса
  2. простой указатель C на функцию (возможно здесь только потому, что нет захвата)
  3. быстрая замена std::function, написанная Malte Skarupke (https://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction/)

Независимо от режима, программа всегда завершает работу с обычным кодом ошибки 0. Но теперь посмотрите на время компиляции с помощью Clang:

$ time clang++ -c -std=c++11 -DMODE=1 lambdas.cpp 
real    0m8.162s
user    0m7.828s
sys 0m0.318s

$ time clang++ -c -std=c++11 -DMODE=2 lambdas.cpp 
real    0m0.109s
user    0m0.056s
sys 0m0.046s

$ time clang++ -c -std=c++11 -DMODE=3 lambdas.cpp 
real    0m0.870s
user    0m0.814s
sys 0m0.051s

$ clang++ --version
Apple LLVM version 10.0.0 (clang-1000.11.45.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Whow. Компиляция в 80 разразница во времени между std::function и указателем на режимы работы! И даже 10-кратная разница между std::function и его заменой.

Как это может быть? Есть ли производительность?проблема, специфичная для Clang, или это связано с присущей ей сложностью std::function требование?

Я пытался скомпилировать один и тот же код с помощью GCC 5.4 и Visual Studio 2015. Существуют также большие различия во времени компиляции, но не такмного.

GCC :

$ time g++ -c -std=c++11 -DMODE=1 lambdas.cpp 
real    0m1.179s
user    0m1.080s
sys 0m0.092s

$ time g++ -c -std=c++11 -DMODE=2 lambdas.cpp 
real    0m0.136s
user    0m0.120s
sys 0m0.012s

$ time g++ -c -std=c++11 -DMODE=3 lambdas.cpp 
real    0m1.994s
user    0m1.792s
sys 0m0.196s

Visual Studio :

C:\>ptime cl /c /DMODE=1 /EHsc /nologo lambdas.cpp
Execution time: 2.411 s

C:\>ptime cl /c /DMODE=2 /EHsc /nologo lambdas.cpp
Execution time: 0.270 s

C:\>ptime cl /c /DMODE=3 /EHsc /nologo lambdas.cpp
Execution time: 1.122 s

Сейчас я рассматриваю возможность использования Malte Skarupke'sреализация, как для немного лучшей производительности во время выполнения, так и для значительного улучшения времени компиляции.

1 Ответ

0 голосов
/ 12 апреля 2019

Посмотрите, что компилятор должен обрабатывать в каждом случае с опцией --save-temps.На моей машине с clang 6.0.1, MODE = 1 генерирует предварительно обработанный файл размером 575 КБ, поскольку в него включено множество стандартных заголовков библиотеки.MODE = 1 создает файл размером 416 байт , в 1000 раз меньший.Сгенерированная сборка также отличается в 10 раз.

...