встроенное программирование - PullRequest
2 голосов
/ 11 января 2011

Я нашел эти вопросы и ответы в Интернете:

Q: Какой тип char, short или int лучше подходит для оптимизации?

A: Где это возможно, лучше всегоИзбегайте использования char и short в качестве локальных переменных.Для типов char и short компилятору необходимо уменьшать размер локальной переменной до 8 или 16 бит после каждого назначения.Это называется расширением знака для знаковых переменных и расширением нуля для беззнаковых переменных.Это реализуется путем сдвига регистра влево на 24 или 16 бит, за которым следует сдвиг со знаком или без знака вправо на ту же величину, принимая две инструкции (расширение нуля беззнакового символа занимает одну инструкцию).Этих сдвигов можно избежать, используя int и unsigned int для локальных переменных.Это особенно важно для вычислений, которые сначала загружают данные в локальные переменные, а затем обрабатывают данные внутри локальных переменных.Даже если данные вводятся и выводятся как 8- или 16-битные величины, стоит рассмотреть их обработку как 32-битные величины.

Это правильно?Я думал, что лучше избегать char и short из-за арифметического преобразования (скорее всего они будут преобразованы в целые или длинные, и это заставит компилятор генерировать дополнительные инструкции).

Q: Какуменьшить издержки вызова функций в системах на основе ARM?

A: Избегать функций с параметром, который передается частично в регистр и частично в стек (аргумент split).Это не эффективно обрабатывается текущими компиляторами: все аргументы регистров помещаются в стек.

· Избегайте функций с переменным числом параметров.Varargs функции....

Относительно 'varargs' - это потому, что аргументы будут переданы по стеку?Что это за функция с аргументами, частично передаваемыми в регистрах и частично через стек, не могли бы вы привести пример?

Можно ли сказать, что способ передачи аргументов функции (либо через регистры, либо через стек) сильно зависит от архитектуры?

Спасибо!

Ответы [ 6 ]

7 голосов
/ 11 января 2011

Проще говоря: этот совет по оптимизации вводит в заблуждение.Не обязательно неправильно, но не полностью.

Похоже, ваш источник был CodeProject .Он утверждает, что в основном говорит об оптимизации для ARM.

Во-первых, процесс обработки символов и коротких строк сильно зависит от процессора.В зависимости от архитектуры преобразования могут иметь нулевую или минимальную стоимость, в зависимости от того, когда и как они происходят - во время загрузки, типа операции, какие инструкции могут выполняться параллельно и, по сути, могут быть бесплатными, в зависимости от остальной частикод - например, в архитектуре TI DSP c64, которая может выполнять 8 операций за такт.Как правило, наиболее эффективным использованием будет «родной» целочисленный размер, но это также зависит от того, откуда поступают данные - может быть более эффективно загружать, изменять и сохранять данные char / short, чем загружать и преобразовывать в int,изменить и сохранить обратно как char / short.Или нет - это зависит от архитектуры и выполняемых операций.Компилятор часто лучше смотрит, стоит ли делать это за вас или нет.

Во-вторых, во многих многих архитектурах char и short такие же быстрые, как int, особенно если в вычислениях избегаются неявные преобразования в int.Примечание: это легко испортить в C, например, "x = y + 1" - это приводит к преобразованию до int (при условии, что x & y - char или short), но хорошо то, что почти все компиляторы достаточно умны, чтобыоптимизировать конверсию для вас.Во многих других случаях наличия локального be char / short компилятор оптимизирует любые преобразования в зависимости от того, как он будет использован позже.Это подтверждается тем фактом, что в типичных процессорах переполнение / обертывание char / short - это тот же результат, что и вычисление его как int и преобразование в хранилище (или просто обращение к этому регистру как char / short в более позднемоперация - получение преобразования для «free»).

В их примере:

int wordinc (int a)
{ 
   return a + 1;
}
short shortinc (short a)
{ 
    return a + 1;
}
char charinc (char a)
{ 
    return a + 1;
}

Во многих архитектурах / компиляторах они будут работать на практике одинаково быстро.

В-третьих, в некоторых архитектурах char / short на 1017 * быстрее, чем int.В качестве примера можно привести встроенные архитектуры с естественным размером 8 или 16 бит (по общему признанию, это не тот вид развития, о котором вы думаете в настоящее время).

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

С другой стороны,Если компилятор не достаточно умен, чтобы скрыть его от вас, локальные символы / шорты, передаваемые в качестве аргументов другим функциям (особенно не файловым «статическим» функциям) могут повлечь преобразование с повышением в int .Опять же, как указано выше, компилятор вполне может быть достаточно умным, чтобы скрыть преобразование.

I do согласен с этим утверждением в начале цитируемого вами сайта:

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

2 голосов
/ 11 января 2011
  1. Да, в соответствии со стандартом почти все вычисления и сравнения выполняются с целочисленными типами, которые имеют ширину не менее int.Таким образом, использование меньших типов «только» экономит место и может, с другой стороны, иметь накладные расходы.
  2. Varargs должен использовать стек, поскольку соответствующие макросы, обрабатывающие эти аргументы, обычно просто используют указатель для отслеживанияфактическая позиция аргумента, который обрабатывается.
1 голос
/ 11 января 2011

Это зависит от цели и / или компилятора.Это также может зависеть от того, что вы хотите оптимизировать, от использования памяти, места для кода или времени выполнения.

Что касается вызовов функций ARM, ARI ABI определяет стандарт, которому будет соответствовать большинство компиляторов ARM.Это довольно бесполезный ответ, поскольку вы, как правило, не реализуете и не вызываете функцию с переменным числом, если она вам действительно не нужна.

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

1 голос
/ 11 января 2011

На некоторых процессорах unsigned char - самый быстрый тип. На некоторых это будет последовательно медленнее, чем int. В ARM неподписанный символ, который хранится в памяти, должен работать с той же скоростью, что и int, хранящийся в памяти, но без знака, который хранится в регистре, часто приходится «нормализовать» до значения 0-255 за счет инструкция; беззнаковый шорт должен быть «нормализован» до 0-65535 за счет двух инструкций. Я ожидал бы, что хороший компилятор мог бы устранить много ненужных нормализаций, либо работая с 65536-кратным значением интереса, либо наблюдая, что старшие биты не будут иметь значения; Я не знаю, в какой степени фактические компиляторы делают любую из этих вещей.

Кстати, стоит отметить, что, хотя стандарт C требует, чтобы добавление 1 к 16-разрядному целому числу без знака, содержащему 65 535, давало ноль (а не 65 536), аналогичных требований для целых чисел со знаком не существует. Компилятор может рассматривать подписанный короткий или подписанный символ как int, если он хранится в регистре, и как его тип надлежащего размера, когда хранится в памяти. Таким образом, использование подписанных типов позволит избежать необходимости в дополнительных инструкциях по усечению значений.

1 голос
/ 11 января 2011

Я бы не подумал, что уменьшение размера при назначении 8 или 16 битов будет иметь место только при назначении с большего значения.Например, если функция возвращает char, зачем ей вообще нужно изменять значение при присваивании char?Может быть исключение, если есть некоторые операции, которые можно выполнить только с большими переменными, но в зависимости от компилятора и процессора, я не уверен, что это будет происходить так часто.

1 голос
/ 11 января 2011

По поводу «варагс» - это потому что аргументы будут переданы через стек? Что такое функция с аргументами, частично переданными в регистры, и частично через стек, не могли бы вы привести пример?

если у вас есть такая функция:

int my_func(int v1, int v2)

Компилятор может использовать внутренний регистр процессора для передачи аргумента v1, v2 во время вызова функции.

если у вас есть:

int my_func(int v1, int v2, ...., int v10)

Пространство, используемое вашим параметром, слишком велико для использования внутреннего регистра процессора (недостаточно места), поэтому вы используете внутренний регистр и стек.

Можно ли сказать, что функция пути аргументы передаются (либо регистры или стек) сильно зависит по архитектуре?

Да, это также сильно зависит от компилятора.

...