Utilizzando il modulo casuale di C++ 11, ho riscontrato un calo di prestazioni dispari quando si utilizza std::mt19937
(versioni a 32 e 64 bit) in combinazione con uno uniform_real_distribution
(mobile o doppio, non importa) . Rispetto ad una compilazione g ++, è più che un ordine di grandezza più lento!Riduzione delle prestazioni clan per generazione di numeri casuali C++ specifici
Il colpevole non è solo il generatore di mt, in quanto è veloce con uno uniform_int_distribution
. E non è un difetto generale nel uniform_real_distribution
dal momento che è veloce con altri generatori come default_random_engine
. Solo quella combinazione specifica è stranamente lenta.
Non ho molta familiarità con gli elementi intrinseci, ma l'algoritmo di Mersenne Twister è definito più o meno rigorosamente, quindi una differenza nell'implementazione potrebbe non tenere conto di questa differenza, immagino? misurare Programma sta seguendo, ma qui sono i miei risultati per clang 3.4 e gcc 4.8.1 su una macchina a 64 bit linux:
gcc 4.8.1
runtime_int_default: 185.6
runtime_int_mt: 179.198
runtime_int_mt_64: 175.195
runtime_float_default: 45.375
runtime_float_mt: 58.144
runtime_float_mt_64: 94.188
clang 3.4
runtime_int_default: 215.096
runtime_int_mt: 201.064
runtime_int_mt_64: 199.836
runtime_float_default: 55.143
runtime_float_mt: 744.072 <--- this and
runtime_float_mt_64: 783.293 <- this is slow
programma per generare questo e provare voi stessi:
#include <iostream>
#include <vector>
#include <chrono>
#include <random>
template< typename T_rng, typename T_dist>
double time_rngs(T_rng& rng, T_dist& dist, int n){
std::vector< typename T_dist::result_type > vec(n, 0);
auto t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < n; ++i)
vec[i] = dist(rng);
auto t2 = std::chrono::high_resolution_clock::now();
auto runtime = std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count()/1000.0;
auto sum = vec[0]; //access to avoid compiler skipping
return runtime;
}
int main(){
const int n = 10000000;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine rng_default(seed);
std::mt19937 rng_mt (seed);
std::mt19937_64 rng_mt_64 (seed);
std::uniform_int_distribution<int> dist_int(0,1000);
std::uniform_real_distribution<float> dist_float(0.0, 1.0);
// print max values
std::cout << "rng_default_random.max(): " << rng_default.max() << std::endl;
std::cout << "rng_mt.max(): " << rng_mt.max() << std::endl;
std::cout << "rng_mt_64.max(): " << rng_mt_64.max() << std::endl << std::endl;
std::cout << "runtime_int_default: " << time_rngs(rng_default, dist_int, n) << std::endl;
std::cout << "runtime_int_mt: " << time_rngs(rng_mt_64, dist_int, n) << std::endl;
std::cout << "runtime_int_mt_64: " << time_rngs(rng_mt_64, dist_int, n) << std::endl;
std::cout << "runtime_float_default: " << time_rngs(rng_default, dist_float, n) << std::endl;
std::cout << "runtime_float_mt: " << time_rngs(rng_mt, dist_float, n) << std::endl;
std::cout << "runtime_float_mt_64: " << time_rngs(rng_mt_64, dist_float, n) << std::endl;
}
compilare via clang++ -O3 -std=c++11 random.cpp
o g ++ rispettivamente. Qualche idea?
modifica: Infine, Matthieu M. ha avuto una grande idea: il colpevole è l'inlining, o piuttosto una sua mancanza. Aumentando il limite di inlining clang eliminato la penalità delle prestazioni. Questo ha effettivamente risolto un certo numero di stranezze di performance che ho incontrato. Grazie, ho imparato qualcosa di nuovo.
Forse vuoi profilare un po 'le cose (ad es. Con callgrind) e confrontare l'assemblatore generato ... – PlasmaHH
Posso solo riprodurlo per il caso 'float_mt', non per' float_mt_64'. Ho usato il tuo codice con clang3.4 su Fedora 20 64-bit. –
Stavo per pubblicare un bug report ma ho visto che l'hai già fatto, http://llvm.org/bugs/show_bug.cgi?id=19542 – pyCthon