Здравствуйте, kot--, Вы писали:
K> Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2). K> Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
В неоптимизированной версии данные, которыми оперируют разные потоки, разнесены дальше, а в оптимизированное попадают на одну cache line. Эта cache line постоянно инвалидируется, что замедляет работу программы.
Здравствуйте, kot--, Вы писали:
K> Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2). K> Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
K> Чем можно объяснить подобные результаты?
Вполне возможно, что в программе есть куски кода, которые действительно исполняются параллельно, а есть точки, в которых работа приостанавливается для взаимной синхронизации (даже на неявной, вроде копирования двух std::string). Без оптимизации параллельные куски кода работают дольше, поэтому время распределяется так, что несколько потоков редко одновременно оказываются на точках синхронизации. С оптимизацией куски кода работают быстрее, соответственно время распределяется по другому и потоки чаще одновременно входят в точки синхронизации и, соответственно, больше простаивают.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Переделал кое-что в одном алгоритме на предмет реализации многопоточности. Что оптимизировать — смотрел профайлером, соотв. дебаг версию.
Далее реализовал многопоточность одного узкого места.
Получил такой результат:
Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2).
Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
Чем можно объяснить подобные результаты?
p.s. т.к. писал на С++, то сообщение в эту тему.
---------------
c уважением, мохнато-полосатый kot--
Здравствуйте, kot--, Вы писали:
K>ку!
K> Переделал кое-что в одном алгоритме на предмет реализации многопоточности. Что оптимизировать — смотрел профайлером, соотв. дебаг версию.
Зачем было профилировать debug build? 80% уверен, что не то было оптимизировано.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, kot--, Вы писали:
K>> Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2). K>> Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
K>> Чем можно объяснить подобные результаты?
E>Вполне возможно, что в программе есть куски кода, которые действительно исполняются параллельно, а есть точки, в которых работа приостанавливается для взаимной синхронизации (даже на неявной, вроде копирования двух std::string). Без оптимизации параллельные куски кода работают дольше, поэтому время распределяется так, что несколько потоков редко одновременно оказываются на точках синхронизации. С оптимизацией куски кода работают быстрее, соответственно время распределяется по другому и потоки чаще одновременно входят в точки синхронизации и, соответственно, больше простаивают.
Полностью согласен. В релиз версии синхронизация стала чаще, соотв. больше конкуренции. А учитывая, что на современных компиляторах скорость релиз и дебаг могут отличаться порядка 10 раз, то соотв. синхронизация стала значительно чаще.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, eao197, Вы писали:
E>>Здравствуйте, kot--, Вы писали:
K>>> Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2). K>>> Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
прошу прощения за двоякое толкование только сейчас увидел.
разумеется, многопоточная дебаг-версия на 70% быстрее однопоточной дебаг-версии.
а многопоточная оптимизированная — быстрее только на 20% однопоточной оптимизированной.
---------------
c уважением, мохнато-полосатый kot--
Re[4]: FileIOPermission, доступ к файлам в каталоге
Здравствуйте, kot--, Вы писали:
K>>>> Скомпилированный с оптимизацией(/O2) по скорости экзешник считает на 20% чем его однопоточный(/O2). K>>>> Скомпилированный БЕЗ ОПТИМИЗАЦИИ(/Od) — на 77% быстрее однопоточный(/Od).
K> прошу прощения за двоякое толкование только сейчас увидел.
K> разумеется, многопоточная дебаг-версия на 70% быстрее однопоточной дебаг-версии.
K> а многопоточная оптимизированная — быстрее только на 20% однопоточной оптимизированной.
В таком контексте не так уж и важно на 20% она быстрее или медленнее однопоточной
Здравствуйте, alexeiz, Вы писали:
A>Как вариант: false sharing (ping-ponging): http://www.ddj.com/architect/208200273?pgno=3
A>В неоптимизированной версии данные, которыми оперируют разные потоки, разнесены дальше, а в оптимизированное попадают на одну cache line. Эта cache line постоянно инвалидируется, что замедляет работу программы.
жаль
задача — число-дробилка.
код, выполняющийся в два потока, находится в одном из методов класса. объект создается один. Все используемые в расчете данные были продублированы двумя способоми — создание еще одной размерности у массивов и переменных либо тупое дублирование array0 и array1.
Вариант 1 дал 9% скорости по сравнению с однопоточной, вариант 2 — 20%. Это для шестой студии /O2.
На интеле производительность еще более плачевна.
В идеале скорость должна была возрасти примерно на 30%, т.к. параллелизуемый код занимает около 60% шага расчета.
Профилировал дебаг-версию, т.к. вообще-то не представляю как можно профайлером(AQTime юзал) гонять оптимизированную
---------------
c уважением, мохнато-полосатый kot--
Здравствуйте, kot--, Вы писали:
K> задача — число-дробилка.
K> код, выполняющийся в два потока, находится в одном из методов класса. объект создается один. Все используемые в расчете данные были продублированы двумя способоми — создание еще одной размерности у массивов и переменных либо тупое дублирование array0 и array1.
Надо продублировать как:
struct X
{
// данные для первого потокаint var1_1;
int var2_1;
double var3_1;
int* var4_1;
...
double* varN_1;
// ВАЖНО!!!char pad [CACHE_LINE_SIZE];
// данные для второго потокаint var1_2;
int var2_2;
double var3_2;
int* var4_2;
...
double* varN_2;
};
Плюс, если выделяешь данные динамически, то выделять тоже с паддингом, что бы данные разных потоков не оказались на одной кэш-линии:
double* data = (double*) malloc (SIZE * sizeof(double) + CACHE_LINE_SIZE);