Исполняемый файл в 3 раза медленнее в Windows (Mingw64), чем в Linux

Я разрабатываю игровой движок, который в Windows примерно в 3-4 раза медленнее, чем в 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 раза медленнее.

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

Сгенерированная сборка для обоих случаев может быть полезна. Также вы должны вставить код в свой вопрос в виде текста.

user10605163 06.11.2018 20:16

Вы пробовали другой компилятор в Windows? Я имею в виду, что gcc довольно хорош, но в Windows компилятор Visual Studio лучше довольно часто ... может также попробовать clang.

Jesper Juhl 06.11.2018 20:22

В цикле есть потенциальное выделение кучи для аргумента std::vector<Vector> для compute. Это могло вызвать зависимость производительности от реализации ОС / стандартной библиотеки.

user10605163 06.11.2018 20:26

@eukaryota, это, вероятно, так - распределение кучи гарантировано, только clang может выполнять удаление кучи в настоящее время AFAIK.

Asu 06.11.2018 20:43

Пожалуйста, не ссылайтесь на код. Укажите соответствующий код в вопроса, как текст.

Jesper Juhl 06.11.2018 21:04

Как насчет -march=native -flto?

HolyBlackCat 06.11.2018 21:15

Спасибо за ответы. Протестировано с "-march = native -flto": без разницы. Протестировано с лязгом: немного хуже (31 сек).

Olivier Martin 06.11.2018 22:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
256
1

Ответы 1

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

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

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

Если есть необходимость конструировать вектор каждый раз в вашем фактическом коде, вам следует рассмотреть возможность использования массива фиксированного размера (необработанный массив или 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);
}

В самом деле, я не говорю, что код сильно оптимизирован. Я уже пытаюсь передать методу 3 аргумента вместо вектора, и разница огромна. Меня беспокоит разница во времени выполнения между Linux и Windows. Может ли в Windows выделение памяти в 3 раза медленнее? Это кажется мне огромным. Что вы думаете?

Olivier Martin 06.11.2018 21:25

@OlivierMartin Как уже было сказано, трудно сказать, не видя сгенерированной сборки. Компилятор также может нести ответственность за разницу. Не знаю, разумна ли разница в 3 раза, но меня это не слишком удивляет. Фактически вы просто сравниваете вызов распределения. Что вы имеете в виду под already try to pass 3 arguments to method instead of vector? Вы по-прежнему выделяете память в куче с помощью compute({va, vb, vc}), потому что это сокращение для создания нового аргумента типа параметра функции с заданным списком инициализаторов.

user10605163 06.11.2018 21:32

Я имею в виду, что я изменил сигнатуру метода на «compute (const Vector & v0, const Vector & v1, const Vector & v2)» и вызов метода с «compute (va, vb, vc)». Я постараюсь получить сборку (никогда не делайте этого раньше), а также попробую другой компилятор. Спасибо за ваш ответ.

Olivier Martin 06.11.2018 21:37

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

user10605163 06.11.2018 21:40

Без выделения кучи результаты аналогичны. Я не ожидал, что распределение между ОС так сильно различается! Я проверю все свое приложение и гарантирую, что медленное выделение может объяснить время выполнения, которое у меня есть. Спасибо.

Olivier Martin 06.11.2018 22:33

Возможно, вы используете антивирус только в Windows. Они перехватывают системные вызовы и замедляют работу ваших приложений. Я обнаружил, что разница между запуском с включенным / выключенным антивирусом незначительна, когда почти нет распределения динамической памяти (нет системных вызовов), но намного медленнее, когда их много.

user14789259 01.09.2021 18:12

Другие вопросы по теме