Il seguente codice compilato con clang
corre quasi 60 volte più veloce di quello compilato con gcc
con bandiere identiche del compilatore (sia -O2
o -O3
):Perché clang produce un codice molto più veloce di gcc per questa semplice funzione che coinvolge l'esponenziazione?
#include <iostream>
#include <math.h>
#include <chrono>
#include <limits>
long double func(int num)
{
long double i=0;
long double k=0.7;
for(int t=1; t<num; t++){
for(int n=1; n<16; n++){
i += pow(k,n);
}
}
return i;
}
int main()
{
volatile auto num = 3000000; // avoid constant folding
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
auto i = func(num);
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed = end-start;
std::cout.precision(std::numeric_limits<long double>::max_digits10);
std::cout << "Result " << i << std::endl;
std::cout << "Elapsed time is " << elapsed.count() << std::endl;
return 0;
}
ho testato questo con tre gcc
versioni e due clang
versioni 3.5.1/3.6.1
e qui ci sono i tempi sulla mia macchina (per gcc 5.2.1
e clang 3.6.1
):
Timing -O3
:
gcc: 2.41888s
clang: 0.0396217s
Timing -O2
:
gcc: 2.41024s
clang: 0.0395114s
Timing -O1
:
gcc: 2.41766s
clang: 2.43113s
Così sembra che gcc
non ottimizza questa funzione a tutti, anche al di ottimizzazione maggiore livelli. L'output di assemblaggio di clang
è quasi di circa 100 righe più lunghe di gcc
e non penso sia necessario pubblicarlo qui, tutto quello che posso dire è che nell'output di gcc
c'è una chiamata a pow
che non viene visualizzata nell'assemblaggio clang
, presumibilmente perché lo standard clang
lo ottimizza in una serie di chiamate intrinseche.
Poiché i risultati sono identici (cioè i = 6966764.74717416727754
), la domanda è:
- Perché può
gcc
non ottimizzare questa funzione quandoclang
lattina? - Modificare il valore di
k
a1.0
egcc
diventa veloce, esiste un problema aritmetico in virgola mobile chegcc
non può escludere?
Ho provato a provare static_cast
e ho attivato gli avvisi per verificare se ci fosse qualche problema con le conversioni implicite, ma non proprio.
Update: Per completezza ecco i risultati per -Ofast
gcc: 0.00262204s
clang: 0.0013267s
Il punto è che gcc
non ottimizzare il codice a O2/O3
.
Hai stampato il linguaggio assembly, generato da entrambi i compilatori? –
Clang utilizza la stessa implementazione della libreria standard di gcc qui? Uno di questi potrebbe avere un'implementazione di Pow più veloce/meno accurata o qualcosa del genere. (Solo una supposizione) –
Quanto sono identici i risultati? '6.96676e + 06' non mostra abbastanza precisione per essere sicuro. Per una velocità come questa, direi che Clang è su impostazioni che permettono cose come scambiare l'ordine del ciclo, che non produce gli stessi risultati. – user2357112