Программа на основе C ++ libm занимает слишком много времени на чистом сервере ubuntu 16 по сравнению с VM ubuntu server 12.

Я пытаюсь запустить интенсивную математическую программу на C++ на сервере Ubuntu, и удивительно, что Ubuntu Server 16, работающий на чистом Core i7 6700, занимает больше времени, чем двухъядерный сервер Ubuntu 12.04.5, работающий на виртуальной машине поверх Windows 10 на той же машине. . Совершенно удивительно видеть такой результат. Я использую GCC версии 5.4.1 на обоих. Также пытался скомпилировать с использованием -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. Виртуальная машина показала небольшое улучшение, но ubuntu без операционной системы снова и снова показывает одно и то же число. Кроме того, поскольку большая часть времени проводится в libm, есть ли способ обновить эту библиотеку? (glibc)? Однако не вижу никакой новой версии в apt-cache.

Использовал callgrind и построил график с помощью точки. В соответствии с этим требуется 42,27% времени в libm exp (версия 2.23) и 15,18% времени в журнале libm.

Наконец нашел аналогичный пост (поэтому вставьте его сюда для других): Программа работает в 3 раза медленнее при компиляции с g++ 5.3.1, чем та же программа, скомпилированная с помощью g++ 4.8.4, та же команда

Проблема, как и предполагалось, была связана с библиотеками (согласно сообщению). А установив LD_BIND_NOW, время выполнения резко сократилось (и теперь меньше, чем у VM). Также в этом сообщении есть несколько ссылок на ошибки, которые были зарегистрированы для этой версии glibc. Пройду и дам более подробную информацию здесь. Однако спасибо за все ценные материалы.


person Siril    schedule 15.09.2017    source источник
comment
Покажите точные команды компиляции в вашем вопросе, поэтому отредактируйте его, чтобы улучшить и показать исходный код.   -  person Basile Starynkevitch    schedule 15.09.2017
comment
Спасибо за ответ Василий. Надеюсь, я добавил необходимую информацию. Если нет, пожалуйста, дайте мне знать.   -  person Siril    schedule 15.09.2017
comment
Вы можете скомпилировать с помощью g++ -O3 -march=native, а также использовать OpenMP, OpenACC и т. д. Вы также должны использовать время(1) для сравнения   -  person Basile Starynkevitch    schedule 15.09.2017
comment
Я также рекомендую обновить GCC как минимум до GCC 7.   -  person Basile Starynkevitch    schedule 15.09.2017
comment
Пробовал -fopenacc и -fopenmp как на baremetal, так и на vm ubuntu на том же g++ 5.4.1. Виртуальная машина показала небольшое улучшение, но ubuntu без операционной системы снова и снова показывает одно и то же число.   -  person Siril    schedule 15.09.2017
comment
Пробовал -fopenacc и -fopenmp как на baremetal, так и на vm ubuntu на том же g++ 7.2. Виртуальная машина показала небольшое улучшение, но ubuntu без операционной системы снова и снова показывает одно и то же число. Кроме того, поскольку большая часть времени проводится в libm, есть ли способ обновить эту библиотеку? (glibc)? Однако не вижу никакой новой версии в apt-cache.   -  person Siril    schedule 15.09.2017
comment
Откуда вы знаете, что большую часть времени вы проводите в libm ?   -  person Basile Starynkevitch    schedule 15.09.2017
comment
Использовал callgrind и построил график с помощью точки. В соответствии с этим требуется 42,27% времени в libm exp (версия 2.23) и 15,18% времени в журнале libm.   -  person Siril    schedule 15.09.2017
comment
Не комментируйте свой вопрос. Отредактируйте его, чтобы улучшить   -  person Basile Starynkevitch    schedule 15.09.2017
comment
Я обновил свой вопрос с последними выводами. Пожалуйста, дайте мне знать, если у вас есть еще предложения.   -  person Siril    schedule 18.09.2017
comment
Почему бы не использовать одну и ту же версию Ubuntu на виртуальной машине и на металле? В качестве альтернативы, почему бы не использовать две разные версии как на виртуальной машине, так и на металле? Устранение неизвестных.   -  person n. 1.8e9-where's-my-share m.    schedule 18.09.2017
comment
Спасибо за информацию. Я обновил пост другой ссылкой, которая решает ту же проблему. Мне удалось сократить время, установив переменную окружения LD_BIND_NOW.   -  person Siril    schedule 18.09.2017