Programa basado en C++ libm que toma demasiado tiempo en el servidor baremetal ubuntu 16 en comparaciĆ³n con el servidor VM ubuntu 12
performance server (0)
Estoy intentando ejecutar un programa C ++ intensivo en matemáticas en el servidor Ubuntu y sorprendentemente el Ubuntu Server 16 corriendo en un Baremetal Core i7 6700 está tomando más tiempo que un servidor Ubuntu dual 12.04.5 corriendo en una VM sobre Windows 10 en la misma máquina . Es totalmente sorprendente ver este resultado. Estoy usando la versión 5.4.1 de GCC en ambos. También intenté compilar usando -Ofast y -ffast-math pero no hizo ninguna diferencia. También probé a buscar el último gcc 7.2 en el metal desnudo, pero una vez más no hizo ninguna diferencia en absoluto. También probé a buscar la última libm (glibc) y probé sin ninguna diferencia en los números. ¿Alguien puede por favor ayudarme a dejarme saber dónde van las cosas mal?
También ejecutando callgrind sobre el programa (estoy usando una biblioteca de terceros para que no tenga control sobre él), veo que la mayor parte del tiempo se gasta en libm. La única diferencia entre los dos entornos distintos de la versión del servidor es la versión de la libma. En VM, que tuvo un buen rendimiento, fue de 2,15 y en el bare metal, que demora más, es de 2,23. Cualquier sugerencia será muy apreciada. Gracias.
El comando de compilación es:
g++ -std=c++14 -O3 -o scicomplintest EuroFutureOption_test.cpp -L. -lFEOption
El programa consiste en calcular griegos de opciones para un conjunto de 22 precios de ejercicio usando una biblioteca cuyo código fuente no está disponible. Sin embargo, podría responder cualquier pregunta con el código de prueba.
Ha simplificado el cálculo de latencia usando la clase a continuación:
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::high_resolution_clock SteadyClock;
template <typename precision = std::chrono::microseconds>
class EventTimerWithPrecision
{
public:
EventTimerWithPrecision() { _beg = SteadyClock::now(); }
long long elapsed() {
return std::chrono::duration_cast<precision>(SteadyClock::now()
- _beg).count();
}
void reset() { _beg = SteadyClock::now(); }
private:
TimePoint _beg;
};
typedef EventTimerWithPrecision<> EventTimer;
Ahora estoy obteniendo los tiempos como a continuación:
Ubuntu server 12.04.5 on VM with dual core (over windows 10):
siril@ubuntu:/media/sf_workshare/scicompeurofuturestest$ ./scicomplintest
Mean time: 61418 us
Min time: 44990 us
Max time: 79033 us
Ubuntu server 16 on Core i7 6700 bare metal:
Mean time: 104888 us
Min time: 71015 us
Max time: 125928 us
on Windows 10 (MSVC 14) on Core i7 6700 bare metal:
D:/workshare/scicompeurofuturestest/x64/Release>scicompwintest.exe
Mean time: 53322 us
Min time: 39655 us
Max time: 64506 us
Puedo entender que Windows 10 funcione más rápido que Linux en VM, pero ¿por qué el ubuntu Baremetal es tan lento?
No se puede llegar a ninguna conclusión y pegar todo el código de prueba a continuación. Por favor ayuda (realmente curioso saber por qué se comporta así).
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include "FEOption.h"
#include <chrono>
#define PRINT_VAL(x) std::cout << #x << " = " << (x) << std::endl
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::high_resolution_clock SteadyClock;
template <typename precision = std::chrono::microseconds>
class EventTimerWithPrecision
{
public:
EventTimerWithPrecision() { _beg = SteadyClock::now(); }
long long elapsed() {
return std::chrono::duration_cast<precision>(SteadyClock::now() - _beg).count();
}
void reset() { _beg = SteadyClock::now(); }
private:
TimePoint _beg;
};
typedef EventTimerWithPrecision<> EventTimer;
int main(){
int cnt, nWarmup = 10, nTimer = 100000;
double CompuTime;
// Option Parameters
double Omega[] = {
-1,
-1,
-1,
1,
1,
1,
1,
-1,
-1,
-1,
1,
1,
1,
1,
-1,
-1,
-1,
1,
1,
1,
1,
-1,
-1,
-1,
1,
1,
1,
1,
-1,
-1,
-1,
1,
1,
1,
1,
-1,
-1,
-1,
1,
1,
1,
1
};
double Strike[] = {
92.77434863,
95.12294245,
97.5309912,
100,
102.5315121,
105.1271096,
107.7884151,
89.93652726,
93.17314234,
96.52623599,
100,
103.598777,
107.327066,
111.1895278,
85.61884708,
90.16671558,
94.95615598,
100,
105.311761,
110.90567,
116.796714,
80.28579206,
86.38250571,
92.9421894,
100,
107.5937641,
115.7641807,
124.5550395,
76.41994703,
83.58682355,
91.4258298,
100,
109.3782799,
119.6360811,
130.8558876,
73.30586976,
81.30036598,
90.16671558,
100,
110.90567,
123.0006763,
136.4147241
};
double Expiration[] = {
7,
7,
7,
7,
7,
7,
7,
14,
14,
14,
14,
14,
14,
14,
30,
30,
30,
30,
30,
30,
30,
60,
60,
60,
60,
60,
60,
60,
90,
90,
90,
90,
90,
90,
90,
120,
120,
120,
120,
120,
120,
120
};
int TradeDaysPerYr = 252;
// Market Parameters
double ValueDate = 0;
double Future = 100;
double annualSigma = 0.3;
double annualIR = 0.05;
// Numerical Parameters
int GreekSwitch = 2;
double annualSigmaBump = 0.01;
double annualIRBump = 0.0001;
double ValueDateBump = 1;
double PV;
double Delta;
double Gamma;
double Theta;
double Vega;
double Rho;
sciStatus_t res;
int nData = sizeof(Strike) / sizeof(double);
std::vector<long long> v(nData);
for (int i = 0; i < nData; i++)
{
for (cnt = 0; cnt < nWarmup; ++cnt){
res = EuroFutureOptionFuncC(annualIR, annualSigma, Omega[i], ValueDate, Expiration[i], Future, Strike[i], TradeDaysPerYr, annualIRBump + cnt*1.0e-16,
annualSigmaBump, ValueDateBump, GreekSwitch,
&PV,
&Delta,
&Gamma,
&Theta,
&Vega,
&Rho
);
if (res != SCI_STATUS_SUCCESS) {
std::cout << "Failure with error code " << res << std::endl;
return -1;
}
}
EventTimer sci;
for (cnt = 0; cnt < nTimer; ++cnt){
res = EuroFutureOptionFuncC(annualIR, annualSigma, Omega[i], ValueDate, Expiration[i], Future, Strike[i], TradeDaysPerYr, annualIRBump + cnt*1.0e-16,
annualSigmaBump, ValueDateBump, GreekSwitch,
&PV,
&Delta,
&Gamma,
&Theta,
&Vega,
&Rho
);
if (res != SCI_STATUS_SUCCESS) {
std::cout << "Failure with error code " << res << std::endl;
return -1;
}
}
v[i] = sci.elapsed();
}
long long sum = std::accumulate(v.begin(), v.end(), 0);
long long mean_t = (double)sum / v.size();
long long max_t = *std::max_element(v.begin(), v.end());
long long min_t = *std::min_element(v.begin(), v.end());
std::cout << "Mean time: " << mean_t << " us" << std::endl;
std::cout << "Min time: " << min_t << " us" << std::endl;
std::cout << "Max time: " << max_t << " us" << std::endl;
std::cout << std::endl;
PRINT_VAL(PV);
PRINT_VAL(Delta);
PRINT_VAL(Gamma);
PRINT_VAL(Theta);
PRINT_VAL(Vega);
PRINT_VAL(Rho);
return 0;
}
El gráfico callgrind es el siguiente: gráfico callgrind
Más actualizaciones: probado -fopenacc y -fopenmp en baremetal y vm ubuntu en el mismo g ++ 7.2. El vm mostró una pequeña mejora, pero el ubuntu baremetal está mostrando el mismo número una y otra vez. Además, dado que la mayor parte del tiempo está en libm, ¿hay alguna forma de actualizar esa biblioteca? (Glibc)? No veo ninguna versión nueva en apt-cache aunque
Usó callgrind y trazó un gráfico usando punto. De acuerdo con eso, lleva un 42.27% de tiempo en libm exp (versión 2.23) y un 15.18% de tiempo en log de libm.
Finalmente encontré una publicación similar (pegándola aquí para otros): el programa se ejecuta 3 veces más lento cuando se compila con g ++ 5.3.1 que con el mismo programa compilado con g ++ 4.8.4, el mismo comando
El problema como se sospechaba era de las libs (según la publicación). Y al configurar LD_BIND_NOW los tiempos de ejecución bajaron drásticamente (y ahora menos que VM). Además, esa publicación tiene un par de enlaces a los errores que se presentaron para esa versión de glibc. Continuará y dará más detalles aquí. Sin embargo, gracias por todas las valiosas aportaciones.