AlexGin:
AG>Смею заверить товарищей, тормозов не будет — всё будет работать великолепно — если вместо работы с GUI поставить прокачку сообщений OS Windows
А почему бы тяжёлое вычисление синуса просто не вынести во внешний цикл, вместо того чтобы надеяться на то, что до этого додумается компилятор? Или, может, оптимизирующие компиляторы у нас теперь дают какие-то документированные стопроцентные гарантии насчёт подобных случаев?
Здравствуйте, N. I., Вы писали:
NI>А почему бы тяжёлое вычисление синуса просто не вынести во внешний цикл, вместо того чтобы надеяться на то, что до этого додумается компилятор? Или, может, оптимизирующие компиляторы у нас теперь дают какие-то документированные стопроцентные гарантии насчёт подобных случаев?
Выбросил из внутреннего цикла вычисление синуса — время выполнения тригонометрического теста — практически не поменялось (для MSVC 2015) —
на моей домашней машинке 11 секунд. Завтра посмотрю время выполнения на быстром рабочем компе.
Вот коды консольной версии: https://github.com/AlexGin/MathConsole/blob/master/MathConcole.cpp
Здравствуйте, AlexGin, Вы писали: AG>В этой теме я приводил ссылки на мои тесты производительности, выложенные на гит-хабе: AG>https://github.com/AlexGin/Math.git AG>Некоторые наши коллеги заметили, что если в приведенном ниже тесте: AG>Блокировать / комментировать участок работы с GUI, начинаются жуткие тормоза:
Скрытый текст
AG>
AG>void MainWindow::nativeComputeTrg() // Trigonometry
AG>{
ui->>labelMode->setText("Trigonometry - start of perform...");
ui->>progressBar->setValue(2); // start position of progress-bar
AG> std::time_t timeStart = std::time(0);
AG> double resultDbl = 0.0;
AG> for(int i = 2; i < N_MULTIPLY; i++)
AG> {
AG> for( int j = 0; j < N_GENERATED; j++ )
AG> {
AG> double dbMult = (double)(i * 2 * M_PI);
AG> resultDbl = randDbl[j] + sin(dbMult);
AG> resultDbl += 0.375;
AG> outpDbl[j] = resultDbl;
AG> }
AG>// Если блокировать (комментировать) данный участок - в тригонометрическом тесте видим жуткие тормоза:
AG> // if (!(i % 100000))
AG> // {
AG> // int val = ui->progressBar->value();
AG> // ui->progressBar->setValue(++val);
AG> //}
AG> }
AG> std::time_t timeStop = std::time(0);
ui->>labelMode->setText("Trigonometry - complete!");
AG> std::string strMode("Trigonometry");
AG> ShowDuration(timeStart, timeStop, strMode);
ui->>pushBtnStart->setEnabled(false);
AG>}
AG>
Разницу в кодогенерации в зависимости от наличия if (xx) во внешнем цикле я показал тут
, причем условие в if (как и само "тело") может быть любым, в том числе никогда не выполняемым, достаточно вставить:
if(i==0) break;
AG>Смею заверить товарищей, тормозов не будет — всё будет работать великолепно — если вместо работы с GUI поставить прокачку сообщений OS Windows:
Содержимое "тела" в этом блоке if НИКАК не влияет на кодогенерацию, что за магию с "прокачкой сообщений OS Windows" ты себе надумал хз, поставь в тело if'а break; — все будет тоже самое.
... AG>Итак, соотношение времен выполнения (в пользу MSVC) восстановлено — легким движением руки
, причем условие в if (как и само "тело") может быть любым, в том числе никогда не выполняемым, достаточно вставить: _>
_>if(i==0) break;
_>
Кстати, да!
Вы правы, уважаемый pilgrim_!
Очень похоже на bug в нашем любимом компиляторе MSVC 2015
AG>>Смею заверить товарищей, тормозов не будет — всё будет работать великолепно — если вместо работы с GUI поставить прокачку сообщений OS Windows:
_>Содержимое "тела" в этом блоке if НИКАК не влияет на кодогенерацию, что за магию с "прокачкой сообщений OS Windows" ты себе надумал хз, поставь в тело if'а break; — все будет тоже самое.
Магия с прокачкой — это как бы достаточно привычное действие для таких вычислений.
Однако, да — тут собака зарыта!
Я попробую еще вынести эти вычисления в отдельный рабочий поток.
AG>>Итак, соотношение времен выполнения (в пользу MSVC) восстановлено — легким движением руки _>Но вот выводы сделаны неверные.
По ходу неверные
Скажем так — мои потуги оказались успешными, но собака зарыта — в чём-то другом...
P.S. Сделаю этот тест в working thread и посмотрю на результат!
P.P.S. Кстати — для теста тригонометрии — выбрасывание вычисления синуса из внутреннего цикла во внешний — также даёт эффект:
время прогона становиться нормальным даже без прокачки сообщений...
Интересные наблюдения:
Вынос расчёта синуса во внешний цикл, приводит к тому, что можно даже не проводить прокачку сообщений — время всё равно будет считаться корректно.
Возможно, что компилятор сам пытается провести оптимизацию — вынести синус, но это приводит к проблемам — то есть bug MSVC всё-таки есть
Когда же мы вручную выносим расчёт синуса на внешний цикл — всё идёт корректно, и дополнительная прокачка сообщений не требуется...
Здравствуйте, AlexGin, Вы писали:
AG>P.P.S. Кстати — для теста тригонометрии — выбрасывание вычисления синуса из внутреннего цикла во внешний — также даёт эффект: AG>время прогона становиться нормальным даже без прокачки сообщений...
Здравствуйте, AlexGin, Вы писали:
AG>Кстати, да! AG>Вы правы, уважаемый pilgrim_! AG>Очень похоже на bug в нашем любимом компиляторе MSVC 2015
Ой, да не уж то осознал, чудо случилось. ) А где же извинения за "попытки притянуть за уши", "пытаетесь навесить ярлык" и т.п.? )))
AG>Магия с прокачкой — это как бы достаточно привычное действие для таких вычислений.
Это не должно быть привычным действием, если ты хоть немного понимаешь происходящее. Никаким циклами сообщений и т.п. ты не можешь ускорить вычисления — это невозможно в принципе. Добавление цикла сообщений может позволить твоему GUI не зависать в процессе проведения вычислений (кстати, это достигается ценой небольшого их замедления) и только. Если ты думаешь по другому, то тебе надо серьёзно переосмыслить всё своё понимание работы современных компьютеров. )
т.е. наличие if принуждает cl использовать SSE (+ небольшая раскрутка цикла — в итоге всего 125 итераций вместо 1000).
И кстати, в варианте с синусом этот if, помимо того что синус вычислялся во внешнем цикле, также приводил к использованию SSE для сложения (по 4 дабла за раз), в отличие от варианта без if.
Что характерно, в обоих вариантах с if (ссинусом и без) "мертвое" условие if(i==0) break; приводит к генерации if (true) continue;, вместо ожидаемого удаления нафик.
test edx, edx //тогда как edx никогда не будет нулем: mov edx, 2
je SHORT $LN12@f2
упрощённом коде, в котором нечего "выносить на другой уровень". )))
На самом деле там несколько лишней операцией является преобразование из int в float (причём она, видимо, оказывается затратной не столько с точки зрения времени её выполнения, сколько просто по факту её присутствия, от которого оптимизатор приходит в ступор и выбирает другой способ генерации кода). При её вынесении во внешний цикл код начинает работать быстрее примерно на 10% по сравнению с вариантом, использующим фэйковую строчку.
void f1()
{
for (int i = 2; i < N_MULTIPLY; i++)
{
float const multiplier = static_cast<float>(i);
for (int j = 0; j < N_GENERATED; j++)
outputs[j] = inputs[j] * multiplier;
}
}
Однако, если хочется ещё большей комичности происходящего, можно попробовать в f1 заменить
outputs[j] = inputs[j] * i;
на
outputs[j] = i;
У меня это приводит к увеличению времени выполнения f1 примерно на 20%.
ПРИМЕЧАНИЕ:
В результате экспериментов было выяснено — что: Это явление имеет место в результате бага компилятора MSVC 2015!
Здесь даже не обязательна прокачка сообщений! Так, если вставить в данный участок:
if (i == 0)
std::cout << "it's bullshit"; // Мы никогда не достигнем данной точки
Всё восстанавливается.
Также всё восстанавливается, если вычисление sin(dbMult) вынести из внутреннего цикла.
Sorry, если во время дискуссии кого-либо обидел,
например того же alex_public
Следует заметить, что тут у меня не было моего злого умысла, просто желание разобраться по сути!