Улучшение производительности кода C

Параметры сценария JavaScript на всем протяжении усложнения вещей. Сделайте как Jon Galloway или предложенный daniels0xff.

5
задан MrDatabase 24 November 2009 в 02:47
поделиться

15 ответов

In my experience the most unorthodox way of optimizing C code is to profile the application, identify slowly performing structures and or db hits and then design reasonable solutions around them using Big O analysis.

19
ответ дан 18 December 2019 в 05:13
поделиться

See this chapter, It’s a plain Wonderful Life by Abrash (it's about 5 pages: click 'Next' at the bottom of each screen).

Summary (some quotes from the article):

  • Table-driven magic (huge lookup table and incredible state machine)
  • An approach to performance programming that operates at a more efficient, tightly integrated level than you may ever see again
  • Astonishing economy of effort
1
ответ дан 18 December 2019 в 05:13
поделиться

There is nothing unorthodox left to do for C code performance. All of the effective techniques have been "orthodoxed".

The best I've found is to use a profiler with access to CPU performance counters and pay special attention to cache and branch misses. Add cache prefetches wherever you can and remove unpredictable branches wherever you can.

Don't bother with loop unrolling. If the branch is predictable it is almost free. Let the compiler worry about it.

On some very parallel architectures like IA64 it can be faster to unroll a loop all the way to the end. One example of this is avoiding the C string functions. Use memset to zero a string array, memcpy to set the string and memcmp to compare the entire array against another similar array. This can use 64-bit loads, never has to check for the zero terminator and can be optimized to not loop or branch at all if using a "small" array size of 64 or 128. The memxxx() functions are usually compiler built-ins and very optimized.

1
ответ дан 18 December 2019 в 05:13
поделиться

В приложениях DSP все же стоит перейти на язык ассемблера, чтобы получить максимальную производительность от инструкций SIMD, которые компиляторы C не используют т очень хорошо с. Но на самом деле это не решение "C."

Я довольно часто использую программное обеспечение для подбора кривой, чтобы заменить функции приближениями, которые вычисляются быстрее. Иногда LUT все еще быстрее, чем выполнение кучи вычислений, но не так часто, как раньше.

1
ответ дан 18 December 2019 в 05:13
поделиться

1) Loop unrolling. You save a jump, comparison, and increment every iteration if you don't actually loop.
2) Избегайте двойного косвенного обращения. Обычно арифметические операции выполнять быстрее, чем извлечение, поэтому [y * height + x] обычно быстрее, чем [y] [x]. Кроме того, одномерный массив размера MxN экономит указатели на M (или N) слов по сравнению с прямоугольной матрицей размеров MxN.
3) По возможности используйте нелепые оптимизации сборки. Например, в архитектуре x86 вы можете использовать инструкцию BSWAP для обмена байтами за одну операцию вместо обычного temp = a; а = б; b = temp; шаблон.

И, конечно, не забывайте:
4) Не выполняйте проверку границ или обработку ошибок.

С учетом сказанного, на практике я бы избегал всего этого, кроме (2).

3
ответ дан 18 December 2019 в 05:13
поделиться

You're looking for an unorthodox, no holds-barred, yet general-purpose solution to optimizing C?

Rewrite it in assembly language.

3
ответ дан 18 December 2019 в 05:13
поделиться

Использовать встроенную сборку?

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

Несколько исключений:

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

2) Возможно, удастся скопировать кадры стека умными способами, если вы знаете порядок памяти, в котором вы компилятор назначает локальные переменные. Это может позволить вам реализовать совместные подпрограммы, которые язык иначе не поддерживает. Сопрограммы часто являются более простым и быстрым способом реализации некоторых видов управления циклами.

3) Объединения всегда немного "взломаны", как бы вы их ни использовали. Это способ реализации полиморфизма с довольно слабой проверкой типов.

4) Использование препроцессора C как способ автогенерирования кода обычно очень трудно отлаживать и читать. Таким образом, люди склонны избегать этого.

4
ответ дан 18 December 2019 в 05:13
поделиться

Profile your code, find the slow spots, and use inline assembly to optimize them.

4
ответ дан 18 December 2019 в 05:13
поделиться

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

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

1
ответ дан 18 December 2019 в 05:13
поделиться

Duff's Device is the canonical example. It's so weird that Tom Duff admitted, "This code forms some sort of argument in [the debate about fall-through in case statements], but I'm not sure whether it's for or against".

6
ответ дан 18 December 2019 в 05:13
поделиться

Злоупотребление константой 0x5f3759df для быстрого вычисления обратных квадратных корней должно иметь довольно высокий ранг ...

5
ответ дан 18 December 2019 в 05:13
поделиться
1
ответ дан 18 December 2019 в 05:13
поделиться

Для пункта 3 выше в ответе Датана, еще один способ обмена, вы можете поменять местами переменные нетрадиционным способом, используя xor.

int = 3, y = 4;
x = x ^ y; 
y = y ^ x; 
x = x ^ y; 

Теперь x и y поменяны местами! :)

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

В старом компиляторе Borland C было свойство _stklen , которое можно было назначить, чтобы уменьшить размер стека и код. Я не видел ничего подобного в настоящее время, поскольку с тех пор технология компиляторов продвинулась вперед.

При использовании malloc вместо этого было бы лучше использовать calloc, поскольку он инициализирует память нулем.

Использование тернарного оператора вместо if Оператор / else, по-видимому, быстрее, Я полагаю, что составители компиляторов стали умнее в отношении генерации машинного кода. Я просто не могу предоставить доказательства этого в этом отношении, но это было верно тогда, когда Borland C 3.01 правил на насесте.

Встраивание кода в ассемблерные подпрограммы.

Мне нравится этот вопрос, поскольку он напоминает мне о былых временах, когда память была драгоценна, когда приходилось втискивать пинту в квартовую емкость и использовать фокус-фокусы кода x86. Спасибо за вопрос, господин База данных.

Будьте осторожны,

Мне нравится эта тема вопроса, поскольку она напоминает мне о былых временах, когда память была драгоценна, и приходилось втискивать пинту в квартовую кастрюлю и использовать фокус-фокусы кода x86. Спасибо за вопрос, господин База данных.

Будьте осторожны,

Мне нравится эта тема вопроса, поскольку она напоминает мне о былых временах, когда память была драгоценна, и приходилось втискивать пинту в квартовую кастрюлю и использовать фокус-фокусы кода x86. Спасибо за вопрос, господин База данных.

Будьте осторожны, Том.

2
ответ дан 18 December 2019 в 05:13
поделиться

Я часто слышу ответы в форме «Попробуйте сделать X, Y или Z», но это все равно, что сказать «Слушай, поешь рыбы и хорошо ешь в течение дня».

Я бы лучше научил вас ловить рыбу - из-за проблем с производительностью. Люди, которые говорят «Сначала профиль», находятся на правильном пути, но (ИМХО) слишком робки.

Вот пример агрессивной настройки производительности.

Вот краткое объяснение того, почему это работает.

Вот длинное объяснение того, почему это работает.

Это научит вас ловить рыбу, показывая вам, как узнать, где находятся рыбы и насколько они велики. Как только вы их найдете, вы можете их приготовить (исправить) многими замечательными способами. Замечательно то, что как только вы найдете и выбросите одну рыбу (проблема производительности) , остальные станут крупнее и их будет легче поймать.

2
ответ дан 18 December 2019 в 05:13
поделиться
1
ответ дан 18 December 2019 в 05:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: