Здравствуйте, vdimas, Вы писали:
V>Стек аудио-эффектов для гитары, например.
А нельзя композицию эффектов свести к композитному эффекту?
V>Т.е., даже если импульсная характеристика порождена не аналоговым процессом, а цифровым, то делается это примерно так: V>- на некоей модели, оперирующей большой точностью, моделируется некая обработка сигнала; V>- с этой модели снимается итоговая импульсная характеристика; V>- в реалтайме затем происходит свёртка входного сигнала с импульсной характеристикой.
Хм. Это должно работать только с линейными фильтрами. V>Суть в том, что "точная модель" оперирует большой разрядностью и кратной передискетизацией унутре, поэтому эта модель не работает в реалтайм, она используется один раз при вычислении IR.
Как-то это сложно. Непонятно, зачем вообще вся эта суперпередискретизация, если мы всё равно пропускаем через эту модель единичный сигнал, а на выход записываем коэффициенты в "финальной" дискретизации и разрядности. V>Нелинейщина обычно проще. Это разного рода пороговые ф-ии, типа sqrt, log и т.д. и они часто реализованы через табличную аппроксимацию, т.е. практически бесплатны.
Ну, по сравнению с арифметикой даже они гораздо дороже. Как сделать табличную аппроксимацию в SIMD?
V>Компилятор Intel С++ разворачивает циклы именно при работе с SIMD в N=16, 32, ..., 128 раз.
В примерах, которые видел я, развёртки SIMD циклов от ICC ~ 2, от GCC — ~4. И это при простейшем коде цикла, где вроде бы и нагрузки на CPU на итерацию мало, и до пределов кэша коду ещё далеко. V>Кеш данных 1-го уровня имеет в точности быстродействие файла регистров (и там и там косвенная адресация из-за ассоциативности, для кеша данных — с данными, для файла регистров — из-за переименований регистров, где внутренний файл регистров в несколько раз больше "публичного" его отображения).
Ну... хз. Всё равно юнитов исполнительных в одном ядре не очень много; даже если я разверну цикл 128 раз, никто мне не будет 128 пар сложений одновременно выполнять.
V>Другое дело, что там много инфы и она достаточно "муторная". ))
Ну вот в том-то и дело. Формально вроде бы интел и переходы предсказывает, и инструкции перемещает, а на практике — всё равно разница есть.
Вот то же предсказание переходов: по идее, проверка выхода за диапазон вообще не должна влиять на массивах размером в 33мегапиксела. Там же ровно всегда один и тот же бранч выбирается.
Ан нет — жрёт до 25% времени в скалярном варианте фильтра C4.
Вот и перемешивание инструкций — есть подозрение, что даже формальная независимость по данным не обеспечит идеальный тайминг; а ICC как раз их располагает с учётом знания устройства конвеера.
Впрочем, мне всё равно до этого далеко. Мой оптимизатор даже эвристическим назвать нельзя — он тупой табличный. В то время, как взрослые пацаны работают как минимум со стоимостями, т.е. рассматривают для любой комбинации операций разные варианты её кодирования в бинарь, и выбирают наиболее дешёвый.
Способность ещё и анализировать инструкции с точки зрения возможности наложения друг на друга — вообще космос по сравнению с тем, что уже сделано в linq2d.
V>Но для второго канала для рекурсивного фильтра надо подгрузить уже другие минус N отсчётов.
Почему другие-то? На выходе-то оба канала точно так же идут в памяти вместе: LRLRLRLRLR.
V>Соотв, кол-во отсчётов IR зависит от отношения частоты дискретизации / частоты фильтра и от заданной точности. V>В реальности это от нескольких десятков отсчётов, до нескольких тысяч, чаще всего в пределах нескольких сотен для низких порядков фильтра (до ~8 порядков). V>Для ревербераторов+эха длина IR может составлять секунды, умножай на частоту дискретизации.
Омг. То есть мы говорим о ~10^6 отсчётов. Да, тут есть шанс вылететь за кэш.
С другой стороны, тут никакой мотивации для linq нету. Все фильтры устроены одинаково — тупо свёртка IR с входом и выходом. Один раз пишем оптимальную функцию; можно её специализировать для пяти-шести вариантов аппаратуры — и вперёд, на танки.
V>Исходники есть, можно подключить гитару и играть. )) V>Могу переслать куда-нить.
Пересылай. Хотя я скорее гитару подключу к готовой железке V>Можно. V>Вернее, нужно, чтобы стимулировать желание экспериментировать задёшево. ))
Пока непонятно. То есть понятно, что можно давать, скажем, описывать частотный фильтр его графиком, а потом конвертировать это в IR при помощи Фурье. (Я такие штуки видел ещё в 1980х, вряд ли кого чем-то тут можно удивить).
И вообще, если мы всё сводим к IR, то любой фильтр — это просто набор чиселок. Ну, или функция от N аргументов, которая порождает этот набор чиселок.
Что тут можно придумать, кроме того, что уже сто лет как придумано?
V>ОК, это была инфа — эксперименты/рассчёты ИИ делают сегодня в основном на Питоне. V>Т.е., в реальных железках работают уже плюсы с вычисленными на Питоне коэф. сетки.
Ну, для ML уже есть кому экспериментировать. https://devblogs.microsoft.com/dotnet/using-net-hardware-intrinsics-api-to-accelerate-machine-learning-scenarios/
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Производительность .Net на вычислительных задачах
Я счел эту задачу подходящей для того что б подтянуть ассеиблер с SSE.
Переделал первый цикл (for for) на SSE и получил 20% прирост скорости. Собираюсь переделать всю sauvolaBinarize
Даже в твоем случае если double заменить на float (а так можно без потери смысла?) то С++ убыстряется на ~ 3%.
Re[15]: Производительность .Net на вычислительных задачах
Здравствуйте, Sinclair, Вы писали: S>Ну, критерий истины — замеры. Ща прикручу тесты, можно будет развлекаться переписыванием кода, и заменами компиляторов.
Привинтил тесты.
Проверяется запуском в студии, либо из командной строки — см. https://github.com/evilguest/linq2d/blob/master/.github/workflows/dotnet-core.yml
Бенчмаркнуться можно из командной строки при помощи
cd Linq2d.Benchmarks
dotnet run -c Release --no-build --filter "*"
Результаты замеров в облаке:
Intel Xeon Platinum 8171M CPU 2.60GHz, 1 CPU, 2 logical and 2 physical cores
.NET Core SDK=3.1.403
[Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
Job=InProcess Toolchain=InProcessEmitToolchain
| Method | FileName | Mean | Error | StdDev | Ratio | RatioSD |
|------------------- |-------------- |----------:|---------:|---------:|------:|--------:|
| CppC4 | p00743.bmp.gz | 47.14 ms | 0.490 ms | 0.458 ms | 0.38 | 0.00 |
| NaturalC4 | p00743.bmp.gz | 321.79 ms | 3.111 ms | 2.758 ms | 2.62 | 0.03 |
| UnsafeC4 | p00743.bmp.gz | 122.62 ms | 1.104 ms | 0.979 ms | 1.00 | 0.00 |
| LinqC4 | p00743.bmp.gz | 62.87 ms | 0.823 ms | 0.770 ms | 0.51 | 0.01 |
| LinqC4VectorCached | p00743.bmp.gz | 51.53 ms | 0.603 ms | 0.535 ms | 0.42 | 0.01 |
| Method | WHalf | FileName | Mean | Error | StdDev | Ratio | RatioSD |
|------------------------ |------ |-------------- |-----------:|---------:|---------:|------:|--------:|
| SafeSauvola | 5 | p00743.bmp.gz | 1,806.3 ms | 6.15 ms | 5.13 ms | 1.69 | 0.01 |
| UnsafeSauvolaScalar | 5 | p00743.bmp.gz | 1,068.0 ms | 8.79 ms | 7.79 ms | 1.00 | 0.00 |
| CppSauvola | 5 | p00743.bmp.gz | 573.0 ms | 3.60 ms | 3.01 ms | 0.54 | 0.00 |
| LinqSauvolaVector | 5 | p00743.bmp.gz | 1,313.3 ms | 7.65 ms | 7.16 ms | 1.23 | 0.01 |
| LinqSauvolaScalar | 5 | p00743.bmp.gz | 1,638.8 ms | 17.83 ms | 16.68 ms | 1.53 | 0.02 |
| CachedLinqSauvolaVector | 5 | p00743.bmp.gz | 687.8 ms | 4.95 ms | 4.39 ms | 0.64 | 0.01 |
| CachedLinqSauvolaScalar | 5 | p00743.bmp.gz | 1,016.4 ms | 6.32 ms | 5.60 ms | 0.95 | 0.01 |
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Производительность .Net на вычислительных задачах
Здравствуйте, кубик, Вы писали: К>Переделал первый цикл (for for) на SSE и получил 20% прирост скорости.
Сравниваешь с AVX2? К>Даже в твоем случае если double заменить на float (а так можно без потери смысла?) то С++ убыстряется на ~ 3%.
Не, давай не будем заменять на float. Если это делать, то надо во всём коде его систематически заменять — и в c# тоже. Не то, чтобы это было долго, но лучше, чтобы все были в равных условиях.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Производительность .Net на вычислительных задачах
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, кубик, Вы писали: К>>Переделал первый цикл (for for) на SSE и получил 20% прирост скорости. S>Сравниваешь с AVX2?
А что , уже переписали на асме или просто опцию компилятора добавили ? Я что то не заметил.
Re[4]: Производительность .Net на вычислительных задачах
К>>Даже в твоем случае если double заменить на float (а так можно без потери смысла?) то С++ убыстряется на ~ 3%. S>Не, давай не будем заменять на float. Если это делать, то надо во всём коде его систематически заменять — и в c# тоже. Не то, чтобы это было долго, но лучше, чтобы все были в равных условиях.
Ну можно размер картинки считать кратным чему либо типа 4,8,16?
Это хобби, не хочу возится с некратными размерами.
Re[4]: Производительность .Net на вычислительных задачах
Здравствуйте, кубик, Вы писали:
К>>>Даже в твоем случае если double заменить на float (а так можно без потери смысла?) то С++ убыстряется на ~ 3%. S>>Не, давай не будем заменять на float. Если это делать, то надо во всём коде его систематически заменять — и в c# тоже. Не то, чтобы это было долго, но лучше, чтобы все были в равных условиях.
К>Ну можно размер картинки считать кратным чему либо типа 4,8,16? К>Это хобби, не хочу возится с некратными размерами.
В принципе можно, но тогда придётся подправить тесты.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Производительность .Net на вычислительных задачах
Здравствуйте, omgOnoz, Вы писали: O>А как же java / scala паралельные коллекции и т.п. которые из-под коробки юзают многопоточность?
Ничего про это не знаю. Начнём с того, что в java в принципе нет многомерных массивов. А также нет value-типов и нормальных генериков; то есть сделать обёртку вокруг линейного массива, которая будет переводить item(i, j) в item[i*w+j], придётся для каждого типа отдельно.
Насколько там возможно получить аналог Expression<T> для анализа — х.з.
O>Голые циклы в 2020 году как бы не очень...
А где в linq2d голые циклы?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Производительность .Net на вычислительных задачах
Здравствуйте, Sinclair, Вы писали:
S>Ничего про это не знаю. Начнём с того, что в java в принципе нет многомерных массивов.
Многомерный массив всегда можно представить в виде обычного массива.
S>А также нет value-типов и нормальных генериков; то есть сделать обёртку вокруг линейного массива, которая будет переводить item(i, j) в item[i*w+j], придётся для каждого типа отдельно.
В скале это можно. Даже есть перегрузка операторов. S>А где в linq2d голые циклы?
я так называю ... for i for j
К>>Ну можно размер картинки считать кратным чему либо типа 4,8,16? К>>Это хобби, не хочу возится с некратными размерами. S>В принципе можно, но тогда придётся подправить тесты.
А можешь сказать почему у тебя в c4filter output это int. На мой взгляд достаточно word
Re[4]: Производительность .Net на вычислительных задачах
Здравствуйте, omgOnoz, Вы писали: S>>Ничего про это не знаю. Начнём с того, что в java в принципе нет многомерных массивов. O>Многомерный массив всегда можно представить в виде обычного массива.
Наверное, можно. Ну, я на java ничего не писал почти 20 лет. S>>А также нет value-типов и нормальных генериков; то есть сделать обёртку вокруг линейного массива, которая будет переводить item(i, j) в item[i*w+j], придётся для каждого типа отдельно. O>В скале это можно. Даже есть перегрузка операторов.
Ок, а дальше что? Как будет выглядеть этот EDSL на джаве или, скажем, на скале?
S>>А где в linq2d голые циклы? O>я так называю ... for i for j
Ну, ок. И где в linq2d for i for j?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Производительность .Net на вычислительных задачах
Здравствуйте, кубик, Вы писали:
К>А можешь сказать почему у тебя в c4filter output это int. На мой взгляд достаточно word
Для упрощения кода. Просто в дотнете нет никакой арифметики ни на byte, ни на word — есть только на int и на long.
Поэтому когда мы складываем byte + byte, получается сразу int, а к word придётся кастить руками.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Производительность .Net на вычислительных задачах
Здравствуйте, a_g_99, Вы писали:
__>вообще идея говорения что си щарп, пхп, вижуал бэсик и тп быстрее С++ это как то с душком не правда ли? Отдает какой то граничащей с безумием продажностью. Или клиническим идиотизмом
Подгорело знатно.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[8]: Производительность .Net на вычислительных задачах
S>Для упрощения кода. Просто в дотнете нет никакой арифметики ни на byte, ни на word — есть только на int и на long. S>Поэтому когда мы складываем byte + byte, получается сразу int, а к word придётся кастить руками.
Но у нас воспрос не простоты, а производительности... Надеюсь ты в докладе осветил этот недостаток
Переписаная на SSE с AVX c4_filter с WORD в 3-4 раза быстрее чем C++ (старенький VS 2008, проц Xeon старенький)
А с int в 2 раза быстрее чем C++
Результаты сверял.
в c4_filter я заменил только главный цикл. Думаю этого достаточно.
Так как Xeon у меня старый, инетересно, как моя функа (она тоже наивная, переписана с твоей) посчитает на новых и посоревнуется с современным оптимизатором?
Update: нашел gcc современный с -march=native и -mtune=native и -O2 так же как и VS 2008.
Он ничего не векторизировал в асме. Как я и ожидал. Если б так было б, то можно на пенсию было собираться.
Здравствуйте, кубик, Вы писали:
К>Результаты сверял.
К>в c4_filter я заменил только главный цикл. Думаю этого достаточно.
Да, конечно. К>Так как Xeon у меня старый, инетересно, как моя функа (она тоже наивная, переписана с твоей) посчитает на новых и посоревнуется с современным оптимизатором?
Отлично, ждём pull request. К>Update: нашел gcc современный с -march=native и -mtune=native и -O2 так же как и VS 2008. К>Он ничего не векторизировал в асме. Как я и ожидал. Если б так было б, то можно на пенсию было собираться.
S>Хм, странно. S>Я вот тут вижу какую-то векторизацию внутреннего цикла:
да, вижу. Я пробовал с O2, а оно появляется при O3. Думаю что оптимизатору мало хинтов что б сделать красиво.
Я тебе послал файлик. Более чем в 2 раза быстрее на выровненых данных.
Re[10]: Производительность .Net на вычислительных задачах
Здравствуйте, кубик, Вы писали: К>да, вижу. Я пробовал с O2, а оно появляется при O3. Думаю что оптимизатору мало хинтов что б сделать красиво. К>Я тебе послал файлик. Более чем в 2 раза быстрее на выровненых данных.
Ок, файлик получил, сейчас разберусь, как это собрать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.