Здравствуйте, Sinix, Вы писали:
S>Выше по ветке уже был похожий примерАвтор: PM
Дата: 05.06.15
. Компилятор c++ в vs2013 местами не блещет.
Да я вообще не пойму кто там ещё пользуется этим убожеством. И дело даже не в оптимизациях, а в стандартах. Кругом уже все на C++14 работают (полиморфные лямбды крайне удобны), а в у MS ещё даже C++11 целиком не реализован.
S>Угу, нынешний JIT на числомолотилки не заточен, это давно известно. Чисто ради интереса: какой фреймворк и x64 или x86 вариант проверялся?
Ммм, а у меня вроде как нет никакой разницы... Т.е. все изначальные тесты я делал для x64 (на всех языках), но сейчас отдельно глянул — 32-ух битный код ничего не меняет.
S>UPD Не из-за них, протупил. Для варианта с указателями на 7 сложений меньше, т.к. аналог (a[p + x]) вычисляется 1 раз. Вот этот вариант с указателями, но с доступом по индексу не отличается от safe-варианта:
Всё верно, я как раз на это и указывал здесь. Что многие алгоритмы записываются максимально эффективно только при наличие в языке арифметики указателей. Т.е. в Java вообще без шансов. В C# ещё можно вывернуться, но тут уже многие говорили, что программировать на unsafe C# смысла нет — это даже ещё более печально, чем на чистом C.
Да, и что самое главное... В таком варианте код не только быстрее, но и удобнее. Т.е. в отличие от вариантов во многих других языках, где нам надо уродовать код для достижения производительности, здесь у нас самый красивый код является самым быстрым.
S>UPD2 Ну да, собственно этим твои варианты под шарп и c++ и отличаются
S>Как только я их привёл к одному виду на автомате — время совпало с нативным результатом без автовекторизации.
На самом деле не совпадает (разве что с результатом убогого компилятора от MS), но действительно уже близко. Могу показать свои результаты в виде единой таблички:
C++ — 1,3 с.
C++ с отключённой векторизацией — 3,5 с.
D — 4,9 с.
C# unsafe + страшный код с обращением к массиву через * — 5 с.
C# unsafe — 5,9 с.
Java — 7,3 с.
C# — 8,7 с.
Показательно значение для языка D (оригинальный компилятор, а не gdc) — там мы имеем полностью нативный код с указателями, без всяких рантайм проверок, но при этом со слабеньким оптимизатором.
Кстати, видно, что у C++ варианта есть большой простор по ручной SIMD оптимизации. Т.к. прирост в 3 раза — это явно меньше того, что можно получить на современных процессорах. Автовекторизация пока ещё отстаёт от ручной, но думаю через несколько лет это исправится. Так же как когда-то исправилось с обычной оптимизацией.
А ещё на C++ это всё можно распараллелить на все ядра процессора или вообще посчитать на gpu с помощью добавления одной инструкции (openmp или openacc) над циклом. Но это уже другая тема. Просто вспомнилось в контексте обсуждения максимальной эффективности вычислений. )
S>Ручную векторизацию конечно можно попробовать сделать с RyuJIT + SIMD, но это уже за гранью добра и зла имхо. Нужна производительность — проще вытащить кусок в unmanaged-код и не страдать из-за "если добавить 7 лишних сложений, то шарп медленный".
Вообще то .net умеет автовекторизацию, правда в самых тривиальных случаях. Кстати старый компилятор C# (на моём старом компьютере) справлялся даже с примером выше, но только в unsafe варианте (где он в точности как C++ вариант). А вот новый что-то не может ни в каком варианте. Странно даже. Но в любом случае наличие автовекторизации в компиляторе не поможет на таких примерах без использования unsafe. А поводу смысла программирования на unsafe C# тут уже высказали много чего. )))