Исполняемый в 3 раза медленнее в Windows (Mingw64), чем в Linux - PullRequest
0 голосов
/ 06 ноября 2018

Я разрабатываю игровой движок, который примерно в 3-4 раза медленнее в Windows, чем в Linux. Я попытался профилировать приложение и не вижу особой проблемы, за исключением того, что в Windows все кажется более медленным. Я извлек очень небольшую часть приложения. Я компилирую его с g++ -O3 perf.cpp и выполняю следующим образом: a.exe 500000000. Вот результаты:

  • Linux: 10 секунд (среднее из 5 выполнений): g ++ 8.2 [также протестировано с g ++ 7.3]
  • Windows: 27 секунд (среднее из 5 выполнений): g ++ (x86_64-posix-seh-rev0, созданный проектом MinGW-W64) 8.1.0 [также протестировано с g ++ 7.1]

Исходный код:

#include <iostream>
#include <cmath>
#include <vector>
#include <chrono>

struct Vector{
    float X, Y, Z;

    Vector(float X, float Y, float Z) : X(X), Y(Y), Z(Z){}

    Vector vector(const Vector &target) const{
        return Vector(target.X - X, target.Y - Y, target.Z - Z);
    }

    float dotProduct(const Vector &v) const{
        return (X*v.X + Y*v.Y + Z*v.Z);
    }
};

float compute(const std::vector<Vector> &v){
    Vector vec1 = v[0].vector(v[2]);
    Vector vec2 = v[1].vector(v[0]);
    return vec1.dotProduct(vec2);
}

int main(int argc, char *argv[]){
    unsigned int loopMax = atoi(argv[1]);

    Vector va(1.5f, 3.0f, 8.0f*loopMax);
    Vector vb(1.2f, 2.3f, 11.0f*loopMax);
    Vector vc(8.2f, 5.0f, 12.0f*loopMax);

    auto frameStartTime = std::chrono::high_resolution_clock::now();

    float res = 0.0f;
    for(unsigned int i=0; i<loopMax; ++i)
    {       
        res += compute({va, vb, vc});
    }

    auto frameEndTime = std::chrono::high_resolution_clock::now();
    auto diffTimeMicroSeconds = std::chrono::duration_cast<std::chrono::microseconds>(frameEndTime - frameStartTime).count();

    std::cout<<"Time: "<<diffTimeMicroSeconds / 1000000.0 <<" sec, res: "<<res<<std::endl;
    return 0;
}

Я знаю, что разница для одной итерации нелепа (<1 нас), но в итоге мое приложение работает в 3-4 раза медленнее. </p>

Чем можно объяснить такую ​​разницу? Как найти проблему?

1 Ответ

0 голосов
/ 06 ноября 2018

Попробуйте построить аргумент для compute один раз за пределами цикла. Если компилятор не исключает создание аргумента std::vector<Vector>, это, скорее всего, приведет к выделению кучи:

std::vector<Vector> arg{va, vb, vc};
for(unsigned int i=0; i<loopMax; ++i)
{       
    res += compute(arg);
}

Если есть выделение кучи, это, скорее всего, займет гораздо больше времени, чем остальная часть содержимого цикла. Время, которое занимает выделение кучи, может сильно различаться в зависимости от системы и реализации. Удаление его, вероятно, значительно повысит производительность в обоих случаях.

Если в вашем фактическом коде необходимо каждый раз создавать вектор, то вам следует рассмотреть возможность использования массива фиксированного размера (raw-массив или std :: array), который будет размещаться не в куче, а в стеке, что намного быстрее. Это кажется применимым, потому что вы используете именно три элемента в вашей реализации compute.

Если вы не знаете длину вектора во время компиляции, и необходимо восстанавливать его каждый раз в цикле с горячей передачей, тогда вы можете быть в состоянии использовать повторно выделенную кучу пробел, тем более если вы можете указать правильное предположение для максимальной длины:

std::vector<Vector> arg;
arg.reserve(1000); // Allocate for up to 1000 element
for(unsigned int i=0; i<loopMax; ++i)
{   
    arg.clear();
    arg.push_back(va);
    [...]
    arg.push_back(vn);
    res += compute(arg);
}
...