我正在尝试在 Ubuntu 服务器上运行数学密集型 C++ 程序,令人惊讶的是,在裸机 Core i7 6700 上运行的 Ubuntu Server 16 比在同一台机器上的 Windows 10 上的 VM 上运行的双核 Ubuntu 服务器 12.04.5 花费的时间更多. 看到这个结果完全令人惊讶。我在两者上都使用 GCC 版本 5.4.1。还尝试使用 -Ofast 和 -ffast-math 进行编译,但没有任何区别。还尝试在裸机上获取最新的 gcc 7.2,但同样没有任何区别。还尝试获取最新的 libm (glibc) 并尝试在数字上没有任何差异。有人可以帮忙让我知道哪里出了问题吗?
还在程序上运行 callgrind(我使用第三方 so 库,因此无法控制它),我看到大部分时间都花在了 libm 上。除了服务器版本之外,这两个环境之间的唯一区别是 libm 版本。在表现良好的 VM 上是 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 在 VM 上的性能比 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 graph
更多更新:在同一 g++ 7.2 上的 baremetal 和 vm ubuntu 上尝试了 -fopenacc 和 -fopenmp。vm 显示了一些改进,但裸机 ubuntu 一次又一次地显示相同的数字。此外,由于大部分时间都花在 libm 中,有没有办法升级该库?(glibc)?虽然在 apt-cache 中看不到它的任何新版本
使用 callgrind 并使用点绘制图形。据此,在 libm exp(版本 2.23)中需要 42.27% 的时间,在 libm 日志中需要 15.18% 的时间。
终于找到了一个类似的帖子(所以贴在这里给别人看):The program running 3 times faster when compiled with g++ 5.3.1 than the same programcompile with g++ 4.8.4, the same command
怀疑的问题来自库(根据帖子)。通过设置 LD_BIND_NOW,执行时间大幅下降(现在少于 VM)。此外,该帖子还有几个指向为该版本的 glibc 提交的错误的链接。将通过并在此处提供更多详细信息。然而,感谢所有宝贵的投入。