Должен ли я переписать свои процедуры DSP на C/C++ или я хорошо разбираюсь в небезопасных указателях C#?

StackOverflow https://stackoverflow.com/questions/261591

Вопрос

В настоящее время я пишу приложение на C#, которое выполняет большую часть цифровой обработки сигналов, что включает в себя множество небольших точно настроенных операций xfer памяти.Я написал эти процедуры, используя небезопасные указатели, и они работают намного лучше, чем я думал.Однако я хочу, чтобы приложение работало как можно быстрее.

Получу ли я какой-либо выигрыш в производительности от переписывания этих подпрограмм на C или C++ или мне следует придерживаться небезопасных указателей?Я хотел бы знать, что небезопасные указатели привносят в таблицу с точки зрения производительности по сравнению с C/C++.

РЕДАКТИРОВАТЬ:Я не делаю ничего особенного внутри этих процедур, просто обычные вещи DSP:дружественная к кэшу передача данных из одного массива в другой с большим количеством умножений, сложений, битовых сдвигов и т. д.в пути.Я ожидаю, что подпрограммы C/C++ будут выглядеть почти так же (если не идентично), как их аналоги на C#.

РЕДАКТИРОВАТЬ:Большое спасибо всем за умные ответы.Я понял, что не получу значительного повышения производительности, просто выполнив прямой порт, если не будет проведена какая-то оптимизация SSE.Предполагая, что все современные компиляторы C/C++ могут этим воспользоваться, я с нетерпением жду возможности попробовать.Если кого-то заинтересуют результаты, просто дайте мне знать, и я опубликую их где-нибудь.(Хотя это может занять некоторое время).

Это было полезно?

Решение

На самом деле я сделал почти то же, что и вы, только в области обработки изображений. Я начал с C # небезопасных указателей, затем перешел на C ++ / CLI и теперь я все кодирую на C ++. На самом деле, оттуда я перешел с указателей в C ++ на инструкции процессора SSE, так что я прошел весь путь. Еще не достигли ассемблера, хотя я не знаю, нужно ли мне, я видел статью о CodeProject, в которой показано, что SSE может работать так же быстро, как встроенный ассемблер, я могу найти его, если вы хотите, чтобы я это сделал.

По мере того, как я продвигался, мой алгоритм изменил скорость с 1,5-2 кадра в секунду в C # с небезопасными указателями до 40 кадров в секунду. C # и C ++ / CLI были определенно медленнее, чем C ++, даже с указателями, я не смог получить более 10 кадров в секунду с этими языками. Как только я переключился на C ++, я сразу получил примерно 15-20 кадров в секунду. Еще несколько хитрых изменений, и SSE увеличил до 40 кадров в секунду. Так что да, это стоит понизить, если вы хотите скорость в моем опыте. Наблюдается явный прирост производительности.

Другие советы

Еще один способ оптимизировать код DSP - сделать его более удобным для кэширования. Если у вас есть много фильтров, которые нужно применить к вашему сигналу, вы должны применить все фильтры к каждой точке, т.е. ваш самый внутренний цикл должен быть над фильтрами, а не над данными, например:

for each n do t´[n] = h(g(f(t[n])))

Таким образом, вы будете намного меньше загружать кеш и, скорее всего, получите хороший прирост скорости.

Я думаю, что вы должны написать свои подпрограммы DSP либо на C ++ (управляемом или неуправляемом), либо на C #, используя надежный дизайн, но не пытаясь оптимизировать все с самого начала, а затем вам следует профилировать свой код, найти узкие места и попробовать чтобы оптимизировать их.

Попытка создать " оптимальную " код с самого начала будет отвлекать вас от написания рабочего кода в первую очередь. Помните, что 80% вашей оптимизации повлияет только на 20% вашего кода, так как во многих случаях только 10% вашего кода отвечают за 90% вашего процессорного времени. (YMMV, в зависимости от типа приложения)

Когда я пытался оптимизировать использование альфа-смешивания в нашем графическом наборе инструментов, я пытался использовать SIMD «голый металл»; Первый путь: встроенный ассемблер. Вскоре я обнаружил, что встроенные функции SIMD лучше использовать вместо чистой сборки, поскольку компилятор может оптимизировать читаемый C ++ с помощью встроенных функций, переставляя отдельные коды операций и максимально используя различные процессорные модули в ЦП.

Не стоит недооценивать силу вашего компилятора!

Получу ли я какую -либо выгоду от переписывания этих процедур в C/C ++ или я должен придерживаться небезопасных указателей?

Теоретически это не имеет значения — идеальный компилятор оптимизирует код, будь то C или C++, до наилучшего ассемблерного кода.

Однако на практике C почти всегда быстрее, особенно для алгоритмов типа указателя. Он максимально приближен к машинному коду без написания кода на ассемблере.

C++ не имеет ничего общего с точки зрения производительности — он построен как объектно-ориентированная версия C, обладающая гораздо большими возможностями и простотой использования для программиста.Хотя в некоторых случаях он будет работать лучше, поскольку данное приложение выиграет с объектно-ориентированной точки зрения, он не должен был работать лучше — он был предназначен для обеспечения другого уровня абстракции, чтобы упростить программирование сложных приложений.

Так что нет, вы, скорее всего, не увидите увеличения производительности при переходе на C++.

Однако для вас, вероятно, важнее выяснить это, чем не тратить на это время - я думаю, было бы полезно перенести это и проанализировать.Вполне возможно, что если в вашем процессоре есть определенные инструкции по использованию C++ или Java и компилятор знает о них, он сможет воспользоваться возможностями, недоступными в C.Маловероятно, но возможно.

Однако процессоры DSP — общеизвестно сложные звери, и чем ближе вы подходите к сборке, тем выше производительность вы можете получить (т. е. тем больше вручную настраивается ваш код).C гораздо ближе к ассемблеру, чем C++.

-Адам

Сначала позвольте мне ответить на вопрос о "безопасности" vs "unsafe". Вы сказали в своем сообщении "Я хочу, чтобы приложение работало как можно быстрее". и это означает, что вы не хотите связываться с " безопасным " или "управляемый" указатели (даже не упоминать сборку мусора).

Относительно вашего выбора языков: C / C ++ позволяет вам гораздо проще работать с базовыми данными без каких-либо накладных расходов, связанных с модными контейнерами, которые все используют в наши дни. Да, приятно , когда вас обнимают контейнеры, которые не допускают ошибок сегментов ... но более высокий уровень абстракции, связанный с контейнерами, рулит вашу производительность.

На моей работе наш код должен работать быстро. В качестве примера можно привести наши многофазные реамплеры, работающие с указателями и маскирующими операциями и фильтрацией DSP с фиксированной запятой ... ни один из этих умных приемов не возможен без контроля уровня памяти и манипуляций с битами == > поэтому я говорю придерживаться C / C ++.

Если вы действительно хотите быть умным, напишите весь свой код DSP на низком уровне C. А затем смешайте его с более безопасными контейнерами / управляемыми указателями ... когда он достигнет скорости, вам нужно снять учебные колеса ... они слишком сильно тормозят.

(К вашему сведению, по поводу снятия обучающих колес: вам нужно протестировать свой код C DSP в автономном режиме, чтобы убедиться, что их использование указателя хорошее ... о / ж это вызовет ошибку.)

РЕДАКТИРОВАТЬ: p.s. " seg faulting " это ЛЮКС для всех вас, разработчиков ПК / x86. Когда вы пишете встроенный код ... ошибка сегмента означает, что ваш процессор войдет в wuides и будет восстановлен только при выключении питания;).

Чтобы узнать, как получить прирост производительности, полезно знать части кода, которые могут вызвать узкие места.

Поскольку вы говорите о небольших передачах памяти, я предполагаю, что все данные будут помещаться в кэш процессора. В этом случае единственная выгода, которую вы можете получить, - это знать, как работать с внутренними процессорами. Как правило, компилятор, наиболее знакомый с внутренними процессорами, - это компилятор Си. Так что здесь, я думаю, вы можете улучшить производительность, портируя.

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

Но поскольку вы уже используете небезопасные указатели, у вас есть этот бит под вашим собственным контролем, поэтому я предполагаю: в этом аспекте вы не получите много пользы от порта на C (или C ++).

Заключение: вы можете портировать небольшие части вашего приложения на C.

Поскольку вы уже пишете в небезопасном коде, я предполагаю, что было бы относительно легко преобразовать его в C dll и вызывать их из C #. Сделайте это после того, как вы определили самые медленные части вашей программы, а затем замените их на C.

Ваш вопрос в значительной степени философский. Ответ таков: не оптимизируйте, пока вы не профилируете.

Вы спрашиваете, получите ли вы улучшение. Хорошо, вы получите улучшение на N процентов. Если этого достаточно (например, вам нужен код, который выполняется 200 раз за 20 миллисекунд на некоторой встроенной системе), то все в порядке. Но что, если этого недостаточно?

Сначала нужно измерить, а затем выяснить, можно ли переписать некоторые части кода на том же языке, но быстрее. Может быть, вы можете изменить структуру данных, чтобы избежать ненужных вычислений. Может быть, вы можете пропустить перераспределение памяти. Может быть, что-то сделано с квадратичной сложностью, когда это может быть сделано с линейной сложностью. Вы не увидите этого, пока не измерите. Как правило, это гораздо меньше трата времени, чем просто переписать все на другом языке.

C # не поддерживает SSE (пока существует монопроект для операций SSE). Поэтому C / C ++ с SSE определенно будет быстрее.

Однако вы должны быть осторожны с переходами между управляемыми и нативными системами, поскольку они довольно дорогие. Оставайтесь как можно дольше в любом мире.

Вы действительно хотите, чтобы приложение было максимально быстрым или просто быстрым? Это говорит вам, что вы должны делать дальше.

Если вы настаиваете на том, чтобы придерживаться своего ручного рулона, без ручной оптимизации в ассемблере или подобном, C # должен подойти. К сожалению, на этот вопрос можно ответить только экспериментально. Вы уже находитесь в неуправляемом пространстве указателей, поэтому мне кажется, что прямой порт на C ++ не будет видеть существенной разницы в скорости.

Я должен сказать, однако, что у меня недавно была похожая проблема, и мы закончили тем, что выбросили ручную свиток после попытки библиотека Intel® Integrated Performance Primitives . Улучшения производительности, которые мы видели, были очень впечатляющими.

Mono 2.2 теперь имеет SIMD поддержку, благодаря которой вы можете получить лучшую из обоих миров управляемый код и сырая скорость.

Возможно, вы также захотите взглянуть на использование SSE в c #, возможно ли это?

Я бы предложил, чтобы в вашем DSP-коде были алгоритмы, которые нужно оптимизировать, то вы должны писать их на ассемблере, а не на C или C ++.

В целом, при использовании современных процессоров и оборудования не так много сценариев, которые требуют или требуют усилий, связанных с оптимизацией. Вы на самом деле выявили какие-либо проблемы с производительностью? Если нет, то, вероятно, лучше придерживаться того, что у вас есть. Небезопасный C # вряд ли будет значительно медленнее, чем C / C ++, в большинстве случаев простой арифметики.

Рассматривали ли вы C ++ / CLI? Тогда вы можете получить лучшее из обоих миров. Это даже позволит вам использовать встроенный ассемблер при необходимости.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top