Я пытаюсь запустить интенсивную математическую программу C ++ на сервере Ubuntu, и, что удивительно, Ubuntu Server 16, работающий на базовом Core i7 6700, отнимает больше времени, чем двухъядерный сервер Ubuntu 12.04.5, работающий на виртуальной машине через Windows 10 на той же машине , Совершенно удивительно видеть этот результат. Я использую версию 5.4.1 GCC на обоих. Также пытался компилировать с использованием -Ofast и -ffast-math, но без разницы. Также попытался получить последнюю версию gcc 7.2 на голом металле, но опять же это не имело никакого значения. Также попытался получить последнюю версию libm (glibc) и попытался без разницы в количестве. Может ли кто-нибудь помочь мне сообщить, где что-то идет не так?
Также выполняя callgrind над программой (я использую стороннюю библиотеку и поэтому не могу ее контролировать), я вижу большую часть времени, проводимого в libm. Единственной разницей между двумя средами, отличными от версии сервера, является версия libm. На ВМ, которая показала хорошие результаты, она составила 2,15, а на голом металле, который занимает больше времени, — 2,23. Любые предложения будут с благодарностью. Благодарю.
Команда построения:
g++ -std=c++14 -O3 -o scicomplintest EuroFutureOption_test.cpp -L. -lFEOption
Программа рассчитывает греки опционов для набора из 22 страйк-цен, используя библиотеку, исходный код которой недоступен. Однако сможет ответить на любые вопросы по тестовому коду.
Упростили расчет задержки, используя класс ниже:
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;
Теперь я получаю время, как показано ниже:
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
Я могу понять, что Windows 10 работает быстрее, чем Linux на виртуальной машине, но почему Ubuntu с открытым исходным кодом так медленно?
Невозможно прийти к какому-либо заключению, я вставляю весь код теста ниже. Пожалуйста, помогите (очень любопытно узнать, почему так себя ведет).
#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;
}
Граф callgrind выглядит следующим образом:
граф callgrind
Больше обновлений:
Пробовал -fopenacc и -fopenmp как на baremetal, так и на vm ubuntu на одном и том же g ++ 7.2. Vm показал небольшое улучшение, но Ubuntu из биметалла снова и снова показывает одно и то же число. Кроме того, поскольку большая часть времени проводится в libm, есть ли способ обновить эту библиотеку? (Glibc)? Не вижу никакой новой версии в apt-cache
Использовал callgrind и построил график, используя точку. В соответствии с этим это занимает 42,27% времени в libm exp (версия 2.23) и 15,18% времени в libm log.
Наконец-то нашел похожий пост (так вот вставив его сюда для других): Программа работает в 3 раза медленнее при компиляции с g ++ 5.3.1, чем та же программа, скомпилированная с g ++ 4.8.4, той же командой
Проблема, как подозревается, была от libs (согласно посту). И установив LD_BIND_NOW, время выполнения резко сократилось (и теперь меньше, чем у VM). Также в этом посте есть несколько ссылок на ошибки, которые были поданы для этой версии glibc. Пройдет и даст более подробную информацию здесь. Однако спасибо за все ценные материалы.
Задача ещё не решена.
Других решений пока нет …