В поддержку Qt

статьи в помощь разработчику

   

Главная

Статьи:

Выбор инструментов разработки

Установка MinGW

Установка Qt 4

Установка Qt 5

Сборка Qt 5

Установка Qt Creator

Проблемы Qt 4.8.3

Распараллеливание компиляции

Распараллеливание для Qt 5.0.1

Сборка отладчика GDB

Установка библиотеки Qwt

Плагин Qwt

Установка QwtPolar

Установка QwtPplot3D

Изменение палитры цветов QwtPlot3D

Конфигурация сборки по умолчанию

Сборка Qt Creator из исходников

Пример использования QwtPlot

Масштабирование QwtPlot в стиле TChart

Синхронное масштабирование

Пример использования QwtPolar

Пример использования QwtPlot3D

Редактирование QSplitter

Сборка в Ubuntu для Windows

Установка пакетов без интернета

Установка драйвера NVIDIA

 

Главная > Распараллеливание компиляции

 

Методы распараллеливания компиляции

Сборка больших проектов Qt, таких как Qt Creator, например, может занимать значительное время. Существенно сократить это время на компьютере с многоядерным процессором позволяет распараллеливание компиляции. Данная статья посвящена этой задаче применительно к MinGW на платформе Windows. Существует два способа решения проблемы.

Далее для определенности будем полагать, что MinGW установлен в папку C:\Qt\mingw-4.6, а библиотека Qt – в папку C:\Qt\qt-4.8.2.

1) Пересборка qmake

Утилита mingw32-make распознает ключ -jX, где X – число одновременно выполняемых потоков компиляции, которое зависит от количества ядер процессора N. Обычно рекомендуется брать X = N + 1. Если процессор поддерживает технологию Hyper-trheading, то число потоков X = 2 · N + 1. Таким образом, если выполнить команду

mingw32-make -j9 -f Makefile.Release

будет выполнен сценарий сборки из файла Makefile.Release (в конфигурации release), и при этом будет создано до 9-ти потоков. Казалось бы проблема распараллеливания компиляции решена, так полагает, например, автор поста на Хабрахабре. Но не все так просто.

Если посмотреть проект Qt Creator 2.5.0, то можно убедиться, что qmake генерирует в нем 71 файл Makefile.Release. Выполнение сценариев этих файлов вызывается из файлов Makefile, которых еще больше. Они также сгенерированы qmake, и вызов выполнения сценариев в них осуществляется без ключа -jX в каком-либо виде. Напрашивается вывод – единственный способ кардинально решить проблему это заставить qmake генерировать файлы Makefile таким образом, чтобы желаемый ключ в них присутствовал. А это означает, что его нужно пересобрать с некоторыми изменениями. Эту идею выдвинул участник Russian Qt Forum, зарегистрированный под логином lesav, в комментариях к одному из постов.

Рассмотрим подробно порядок действий.

1. Открываем для редактирования файл

C:\Qt\qt-4.8.2\qmake\generators\makefile.cpp

правим в нем строку

QString makefilein = " -f " + subtarget->makefile;

которая встречается в этом файле 2 раза. Новая редакция строки выглядит, например, так

QString makefilein = " -j9 -f " + subtarget->makefile;

Число потоков компиляции в ключе -jX в Вашем случае Вы определяете, пользуясь соотношениями, приведенными выше.

Возможно, что для достижения большей эффективности число потоков компиляции надо увеличить еще на 1 или 2.

2. Делаем, на всякий случай, бэкап файла C:\Qt\qt-4.8.2\bin\qmake.exe

3. Запускаем терминал Qt 4.8.2 Command Prompt (см. группу ярлыков библиотеки Qt в меню Пуск). При запуске автоматически будут определены переменные

QTDIR     = C:\Qt\qt-4.8.2
PATH      = C:\Qt\qt-4.8.2\bin;C:\Qt\mingw-4.6\bin;C:\Windows\System32
QMAKESPEC = win32-g++

и в качестве текущего будет установлен каталог C:\Qt\qt-4.8.2. Вводя следующие команды, дополнительно модифицируем переменные

set MAKEFLAGS=
set INCLUDE=%INCLUDE%;%QTDIR%/include

4. Далее вводим

configure.exe -opensource -release -shared -debug-and-release -phonon -phonon-backend

и, когда будет предложено, соглашаемся с лицензией, напечатав y и нажав Enter. Начнется процесс сборки qmake, о чем будет свидетельствовать самое первое сообщение

Creating qmake...

и многочисленные вызовы компиляции файлов типа

g++ -c ...

Об окончании сборки qmake нам поведают сообщения

copy qmake.exe C:\Qt\qt-4.8.2\bin\qmake.exe
Скоприровано файлов:      1.

Это, собственно, то, чего мы добивались. Далее команда configure.exe займется генерацией сценариев сборки всей библиотеки Qt, о чем будут свидетельствовать строки

Creating makefiles in src...
Generating MakeFiles...

и многочисленные сообщения вида

Reading C:/Qt/qt-4.8.2/ ...

Поскольку данный процесс нам уже не интересен, можно прервать выполнение команды комбинацией клавиш <Ctrl-C>. Более того, прерывание процесса генерации сценариев сборки позволит сэкономить около 200 MB дискового пространства.

Чтобы убедиться, что все получилось, смотрим дату создания файлов C:\Qt\qt-4.8.2\qmake\qmake.exe и C:\Qt\qt-4.8.2\bin\qmake.exe. Она должна обновиться, и размер файлов, скорее всего, изменится. Теперь можно для пробы пересобрать какой-либо проект и заглянуть в Makefile. Там где раньше было

$(MAKE) -f $(MAKEFILE)

должно стать

$(MAKE) -j9 -f $(MAKEFILE)

(или ваше значение в ключе -jX).

2) Использование jom

Добиться эффекта распараллеливания компиляции можно путем использования утилиты jom вместо mingw32-make. Она умеет автоматически определять количество ядер процессора и создает нужное число потоков компиляции для достижения максимальной эффективности.

Рассмотрим порядок действий.

1. Скачиваем с ресурса архив

jom.zip   615 KB
(размер архива на момент написания статьи)

2. Распаковываем содержимое архива в папку

C:\Qt\mingw-4.6\bin

Предполагается, что данный путь прописан в переменной среды Path.

Для сборки проекта из командной строки с использованием jom следует вводить, например, следущее

qmake project.pro -r -spec win32-g++
jom
jom install

где project.pro собираемый проект. Таким образом утилита jom просто заменяет mingw32-make.

Для использования jom в Qt Creator необходимо вносить изменения в настройки каждого проекта так, как показано на рисунке.

Результаты тестирования

Тестирование производительности сборки проекта Qt Creator 2.5.0 осуществлялось на 3-х компьютерах со следующими характеристиками

1. Desktop, i7-2600K

CPU Intel Core i7-2600K 3.4 GHz (разогнан до 3.7 GHz), DDR3-1333 8Gb
Windows 7 64bit, Avast 7.0.1426

2. Desktop, i5-750

CPU Intel Core i5-750 2.66 GHz (разогнан до 3.2 GHz), DDR3-1333 2Gb
Windows XP, Avast 6.0.1203

3. Notebook, T2330

CPU Intel Pentium Dual T2330 1.60 GHz, DDR2-667 2Gb
Windows 7 32bit, Avast 6.0.1203

Можно догадаться, что работающий антивирус оказывает влияние на скорость сборки. Результаты тестирования приведены в таблице


 Конфигурация 
 
 Оригинальный qmake и mingw32-make   Пересобранный qmake и mingw32-make   Оригинальный qmake и jom 
 
 
 
 Desktop, i7-2600K 
 
 
 
 
 
 
 30 мин 35 сек
 
 
 
 8 мин 35 сек
 8 мин 25 сек
 8 мин 25 сек
 8 мин 20 сек
 8 мин 25 сек
 8 мин 30 сек
 8 мин 30 сек
 -j6
 -j7
 -j8
 -j9
 -j10
 -j11
 -j12
 
 
 
 7 мин 35 сек
 
 
 
 
 
 Desktop, i5-750 
 
 
 
 
 1 час 6 мин 0 сек
 
 
 33 мин 50 сек
 33мин 20 сек
 33мин 0 сек
 33мин 20 сек
 33мин 20 сек
 -j4
 -j5
 -j6
 -j7
 -j8
 
 
 27 мин 20 сек
 
 
 
 Notebook, T2330 
 
 
 2 час 2 мин 25 сек
 
 1 час 24 мин 20 сек
 1 час 15 мин 40 сек
 1 час 28 мин 50 сек
 -j2
 -j3
 -j4
 
 1 час 8 мин 50 сек
 

Как видно из таблицы, на каждом компьютере было произведено тестирование скорости сборки проекта с несколькими значениями количества потоков в ключе -jX. Для того чтобы каждый раз не пересобирать qmake, был использован код, позволяющий считывать значение, присутствующее в ключе, из текстового файла. Итак, открываем для редактирования файл C:\Qt\qt-4.8.2\qmake\generators\makefile.cpp и находим в нем реализацию функции

void MakefileGenerator::writeSubTargets( ... )

В самом начале тела этой функции помещаем следующий код

QString jstr;       // ключа пока нет
// полное имя qmake
QString jfnm(var("QMAKE_QMAKE"));
// ищем последний разделитель в имени
int jk = jfnm.lastIndexOf(QChar('\\'));
// заменяем имя файла
jfnm = jfnm.left(++jk) + QString("jnum.txt");
QFile file(jfnm);   // инициализируем файл
if (file.exists())  // если файл существует, то
{
    // открывем его только для чтения как текстовый
    file.open(QIODevice::ReadOnly|QIODevice::Text);
    QTextStream jin(&file); // организуем входной поток
    QString str;
    jin >> str;     // получаем из файла строку
    // убираем из нее пробелы
    str.replace(QChar(' '),QString(""));
    // в строке только цифры?
    jk = str.indexOf(QRegExp("\\d+"));
    // если да, то
    if (jk==0) {
        // получаем значение
        jk = str.toInt();
        // если оно > 1, то добавляем ключ -jX
        if (jk>1) jstr = QString(" -j") + str;
    }
    file.close();   // закрываем файл
}

В теле этой же функции дважды встречается упоминаемая выше строка, в которую необходимо вставить ключ -jX. Новая редакция этой строки теперь выглядит так

QString makefilein = jstr + " -f " + subtarget->makefile;

Данный код определяет, в какой папке расположен qmake и ищет в этой же папке текстовый файл jnum.txt, внем прописано количество потоков. В строковой переменной jstr формируется ключ в виде " -jX", где X – значение, считанное из файла и подвергнутое минимальной проверке. Если файл не существует, или значение в нем не поддается расшифровке, или оно равно 1, то в переменной jstr пустая строка, и, соответственно, ключ в Makefile добавлен не будет.

Таким образом, требуется пересобрать qmake, сборка отличается только изменениями, вносимыми в файл makefile.cpp, а в остальном производится также, как описано выше. Далее, необходимо создать файл C:\Qt\qt-4.8.2\bin\jnum.txt, в котором прописать количество потоков. Теперь чтобы изменить ключ -jX, достаточно отредактировать файл jnum.txt. Чтобы производить сборку без распараллеливания компиляции, надо прописать в файл 1.

По результатам тестирования можно отметить следущее

1. При сборке проекта с помощью mingw32-make проявляет высокую активность антивирус. Возможно это связано с многочисленными обращениями к динамическим библиотекам. Это, безусловно, могло повлиять на полученный результат тестирования.

2. Использование ключа -jX при вызове mingw32-make существенно сокращает время сборки проекта даже на процессоре с двумя ядрами. Приведенные выше формулы для определения числа потоков сборки X в ключе достаточно оптимальны.

3. Утилита jom успешно заменяет собой mingw32-make и даже показывает наилучший результат. Возможно это связано с тем, что антивирус довольно "вяло" реагирует на ее работу.

Противники использования jom вместо mingw32-make могут возразить: "А казачок-то засланный!" И будут абсолютно правы. Утилита jom разрабатывалась для замены nmake из Microsoft Visual Studio. И если уж Вы выбрали версию библиотеки Qt с MinGW, то использовать jom будет "не по Фэн-шуй". Но, в конце концов, эту проблему эстетического характера каждый разрешает для себя сам.