LINUX.ORG.RU

Очень сильно отличие производительности исполняемого файла в Linux (gcc) и Windows (mingw64)

 ,


2

7

К вопросу о «кроссплатформенной» разработке.

Есть такой фрагмент кода (сильно порезанный кусок, можно ещё сильнее порезать, но на нём демонстрируется проблема):

// g++ -Ofast -ffast-math

#include <cstdio>
#include <cstdlib>
#include <cmath>

int main() {
    const int N = 1200;
    double* A;
    double* B;
    double C;
    int m;
    
    A = new double[N*N];
    B = new double[N]; 
    
    //srand(time(0));
    //srand( (unsigned)time( NULL ) );
    
    for (int i  = 0; i < N; i++) {
        for (int j =  0; j < N; j++) {
            A[N*i+j] = (double)rand() / ((double)10000);
        }
        B[i] = 0.0;
    }

    // Сильно порезанный фрагмент кода:    
    for (int k = 0; k < N-1; k++ )  {
        m = (k + 1);
        
        for (int i = k + 1; i < N; i++ )   {
            if ( fabs(A[N*(i) + (k)]) > fabs(A[N*(m-1) + k]) ) m = (i + 1);
        }
        B[k] = m;
        
        if ( (m + 1) != k ) B[N-1] = -B[N-1];
        
        C = A[N*(m-1) + k];
        A[N*(m-1) + k] = A[N*k + k];
        A[N*k + k] = C;
        
        if (C == 0) continue;
        
        for (int i = k + 1; i < N; i++ ) A[N*i + k] = -A[N*i + k]/C;
        
        for (int j = k + 1; j < N; j++ )  {
            C = A[N*(m-1)+ j];
            A[N*(m-1) + j] = A[N*k + j];
            A[N*k + j] = C;
            if ( C != 0 )  {
                // дольше всего выполняется этот блок цикла:
                for (int i = k + 1; i < N; i++ )  {
                    A[N*i + j] = A[N*i + j] + A[N*i + k]*C;
                }
            }    
        }
    }
    
    delete [] A;
    delete [] B; 
    
    return 0;
}

Суть проблемы в том, что собранный с одинаковыми опциями этот кусок выполняется на моём железе в Linux за 2.7 сек (gcc 4.8.4), а в Windows7 (mingw64 4.9.3, tdm-gcc 4.9.2) за 8.4 (т.е. разница ~3 раза). Ни на одном другом примере я такого проседания не наблюдал (разве что TDM-GCC генерит в некоторых случаях код заметно быстрее чем MinGW64, но не в этом случае). Понятно, что в этом блоке, который третий по вложенности цикл

for (int i = k + 1; i < N; i++ ) {
    A[N*i + j] = A[N*i + j] + A[N*i + k]*С;
}
не самое эффективное обращение к элементам, так как часто приходится прыгать между элементами, но что есть, то есть - такой алгоритм попался. Но даже если просто оставить прибавление действительного числа «С», то в Linux это ускорит выполнение на 0.5 сек (насколько ускорит в Windows не проверял).

Сталкивался ли кто с подобным поведением MinGW64, TDM-GCCd в плане сильного проседания производительности? Какие ещё ключи компилятора могут заметно ускорить выполнение этого фрагмента?

★★★★★

Ответ на: комментарий от shielcody

Подтверждаю. Добавил в программку выделение памяти 4-х мегабайтными страницами, время выполнения упало с 9.5с до 1.3с, 4790К, Win10, компилировал под 64-бит.

red75prim ★★ ()
Ответ на: комментарий от red75prim

Добавил в программку выделение памяти 4-х мегабайтными страницами

Не подскажите, как это примерно выглядит? Через выравнивание, схожее с тем, что предалагали выше или с помощью определённых функций, наподобие valloc?

grem ★★★★★ ()
Ответ на: комментарий от grem
VirtualAlloc(null_ptr, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);

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

red75prim ★★ ()
Ответ на: комментарий от red75prim

Спасибо. Это в mingw работает тоже? У меня на параметры VirtualAlloc он ругается, а какой хидер (если он есть) подключить не знаю. Или в только для msvs?

Вот gpedit.msc это плохо, в домашних версиях его нет. И в реестре обычно нужные параметры отсутствуют.

grem ★★★★★ ()
Ответ на: комментарий от grem

Всё это должно включатся из windows.h, который, вместе со всем остальным, берётся с https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk . Но я, чтобы не возиться со всем этим, переписал на Rust.

https://github.com/red75prime/largepage/blob/master/src/main.rs

Если установить сборку раста x86_64-pc-windows-gnu с https://www.rust-lang.org/ru-RU/other-installers.html ,то соберётся и без Windows SDK.

red75prim ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.