Что такое пример простой функции C, которая быстрее реализована во встроенном ассемблерном коде?

не используйте этот рецепт, если Ваша ситуация не является той, описанной в вопросе. Этот рецепт для фиксации плохого слияния и воспроизведения Ваших хороших фиксаций на фиксированное слияние.

, Хотя filter-branch сделает то, что Вы хотите, это - вполне сложная команда, и я, вероятно, принял бы решение сделать это с git rebase. Это - вероятно, персональное предпочтение. filter-branch может сделать это в единственной, немного более сложной команде, тогда как rebase решение выполняет эквивалентные логические операции один шаг за один раз.

Попытка следующий рецепт:

# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>

# remove the incorrectly added file
git rm somefile.orig

# commit the amended merge
git commit --amend

# go back to the master branch
git checkout master

# replant the master branch onto the corrected merge
git rebase tmpfix

# delete the temporary branch
git branch -d tmpfix

(Отмечают, что Вам на самом деле не нужно временное ответвление, можно сделать это с 'отдельной ГОЛОВОЙ', но необходимо обратить внимание на идентификатор фиксации, сгенерированный эти git commit --amend шаг для предоставления к эти git rebase команда вместо того, чтобы использовать временное имя ответвления.)

10
задан Hans Sjunnesson 16 July 2009 в 17:20
поделиться

7 ответов

Поскольку это связано с iPhone и кодом сборки, я приведу пример, который будет уместен в мире iPhone (а не какой-нибудь sse или x86 asm). Если кто-то решит написать ассемблерный код для какого-нибудь реального приложения, то, скорее всего, это будет какая-то обработка цифрового сигнала или манипулирование изображениями. Примеры: преобразование цветового пространства пикселей RGB, кодирование изображений в формат jpeg / png или кодирование звука в mp3, amr или g729 для приложений voip. В случае кодирования звука есть много подпрограмм, которые не могут быть преобразованы компилятором в эффективный код asm, у них просто нет эквивалента в C. Примеры обычно используемых вещей в обработке звука: насыщенная математика, подпрограммы умножения-накопления, умножение матриц.

Пример насыщенного сложения: 32-разрядное целое число со знаком имеет диапазон: 0x8000 0000 <= int32 <= 0x7fff ffff. Если вы добавите два int, результат может переполниться, но это может быть неприемлемо в некоторых случаях при цифровой обработке сигналов. В основном, если результат переполнен или недостаточен, насыщенный add должен вернуть 0x8000 0000 или 0x7fff ffff. Это была бы полноценная функция c, чтобы это проверить. оптимизированная версия насыщенного добавления может быть такой:

int saturated_add(int a, int b)
{
    int result = a + b;

    if (((a ^ b) & 0x80000000) == 0)
    {
        if ((result ^ a) & 0x80000000)
        {
            result = (a < 0) ? 0x80000000 : 0x7fffffff;
        }
    }
    return result;
} 

вы также можете выполнить несколько if / else для проверки переполнения или на x86 вы можете проверить флаг переполнения (что также требует от вас использования asm). iPhone использует процессор armv6 или v7 с dsp asm. Таким образом, функция saturation_add с несколькими ветвями (операторы if / else) и двумя 32-битными константами может быть одной простой инструкцией asm, которая использует только один цикл процессора. Таким образом, простое использование saturation_add для использования инструкции asm может сделать весь алгоритм в два-три раза быстрее (и меньше по размеру). Вот руководство по QADD: QADD

другие примеры кода, который часто выполняется в длинных циклах,

res1 = a + b1*c1;
res2 = a + b2*c2;
res3 = a + b3*c3;

кажется, что здесь ничего нельзя оптимизировать, но на процессоре ARM вы можете использовать определенные инструкции dsp, которые занимают меньше циклов, чем простое умножение ! Правильно, a + b * c с конкретными инструкциями может выполняться быстрее, чем простой a * b. Для такого рода случаев компиляторы просто не могут понять логику вашего кода и не могут напрямую использовать эти инструкции dsp, поэтому вам нужно вручную писать asm для оптимизации кода, НО вам следует вручную писать только некоторые части кода, которые действительно должны быть оптимизирован. Если вы начнете писать простые циклы вручную, то почти наверняка вы не победите компилятор! В сети есть множество хороших статей по встроенной ассемблере для кодирования фильтров, кодирования / декодирования AMR и т. Д.

7
ответ дан 3 December 2019 в 14:34
поделиться

Если вы не считаете, что операции SIMD обманывают, вы обычно можете написать сборку SIMD, которая работает намного лучше, чем возможности автовекторизации вашего компилятора (если она даже имеет автовекторизацию!)

Вот очень простой учебник по SSE (один из наборов инструкций SIMD для x86). Это для встроенной сборки Visual C ++.

Изменить: Вот небольшая пара функций, если вы хотите попробовать сами. Это вычисление скалярного произведения длины n. В одном используются встроенные инструкции SSE 2 (встроенный синтаксис GCC), в другом - очень простой C.

Это очень и очень просто, и я был бы очень удивлен, если бы хороший компилятор не смог векторизовать простой цикл C, но если этого не произойдет, вы должны увидеть ускорение в SSE2. Версия SSE 2, вероятно, могла бы быть быстрее, если бы я использовал больше регистров, но я этого не делаю. Я не хочу расширять свои очень слабые навыки SSE :).

 float dot_asm(float *a, float*b, int n)
{
  float ans = 0;
  int i; 
  // I'm not doing checking for size % 8 != 0 arrays.
  while( n > 0) {
    float tmp[4] __attribute__ ((aligned(16)));

     __asm__ __volatile__(
            "xorps      %%xmm0, %%xmm0\n\t"
            "movups     (%0), %%xmm1\n\t"
            "movups     16(%0), %%xmm2\n\t"
            "movups     (%1), %%xmm3\n\t"
            "movups     16(%1), %%xmm4\n\t"
            "add        $32,%0\n\t"
            "add        $32,%1\n\t"
            "mulps      %%xmm3, %%xmm1\n\t"
            "mulps      %%xmm4, %%xmm2\n\t"
            "addps      %%xmm2, %%xmm1\n\t"
            "addps      %%xmm1, %%xmm0"
            :"+r" (a), "+r" (b)
            :
            :"xmm0", "xmm1", "xmm2", "xmm3", "xmm4");

    __asm__ __volatile__(
        "movaps     %%xmm0, %0"
        : "=m" (tmp)
        : 
        :"xmm0", "memory" );             

   for(i = 0; i < 4; i++) {
      ans += tmp[i];
   }
   n -= 8;
  }
  return ans;
}

float dot_c(float *a, float *b, int n) {

  float ans = 0;
  int i;
  for(i = 0;i < n; i++) {
    ans += a[i]*b[i];
  }
  return ans;
}
8
ответ дан 3 December 2019 в 14:34
поделиться

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

Фрагмент из приведенной выше ссылки,

Например, бит- ориентированный "XOR" % EAX,% EAX "была самый быстрый способ обнулить регистр в ранних поколениях x86, но большая часть кода генерируется компиляторы и компиляторы редко сгенерированная инструкция XOR. Итак, ИА дизайнеры решили переместить часто встречающийся компилятор сгенерированные инструкции до начала логики комбинационного декодирования превращая литерал "MOVL $ 0,% EAX" инструкция выполняется быстрее, чем Инструкция XOR.

6
ответ дан 3 December 2019 в 14:34
поделиться

Я реализовал простую взаимную корреляцию, используя общую реализацию "Strait C". И ЗАТЕМ, когда это заняло больше времени, чем у меня было доступное время, я прибег к явному распараллеливанию алгоритма и использованию встроенного процессора, чтобы заставить конкретные инструкции использоваться в вычислениях. В этом конкретном случае время вычислений было сокращено с> 30 мс до чуть более 4 мс. У меня было окно в 15 мс для завершения обработки до следующего сбора данных.

Это была оптимизация типа SIMD на процессоре VLWI. Для этого требуется всего 4 или около того встроенных функций процессора, которые в основном представляют собой инструкции на языке ассемблера, которые создают видимость вызова функции в исходном коде. Вы можете сделать то же самое с встроенным ассемблером, но синтаксис и управление регистрами немного лучше для встроенных функций процессора.

В остальном, если размер имеет значение, ассемблер - король. Я ходил в школу с парнем, который написал полноэкранный текстовый редактор размером менее 512 байт.

5
ответ дан 3 December 2019 в 14:34
поделиться

Если вы хотите выполнять такие вещи, как операции SIMD, вы можете превзойти компилятор. Однако для этого потребуется хорошее знание архитектуры и набора команд.

2
ответ дан 3 December 2019 в 14:34
поделиться

Моя лучшая победа над компилятором была на простой подпрограмме memcpy ... Я пропустил много основных настроек (например, мне не нужно было много кадров стека, поэтому Я сэкономил там несколько циклов) и сделал несколько довольно сложных вещей.

Это было лет 6 назад с каким-то проприетарным компилятором неизвестного качества. Теперь мне придется откопать код, который у меня был, и попробовать его против GCC; Я не знаю, может ли он стать быстрее, но я бы не исключил этого.

В конце концов, хотя мой memcpy был в среднем примерно в 15 раз быстрее, чем в нашей библиотеке C, я просто сохранил его в заднем кармане на случай, если это понадобится. Для меня это была игрушка - играть со сборкой PPC, и в нашем приложении не было необходимости в повышении скорости.

0
ответ дан 3 December 2019 в 14:34
поделиться

У меня есть алгоритм контрольной суммы, который требует, чтобы слова менялись на определенное количество бит. Для его реализации у меня есть этот макрос:

//rotate word n right by b bits
#define ROR16(n,b) (((n)>>(b))|(((n)<<(16-(b)))&0xFFFF))

//... and inside the inner loop: 
sum ^= ROR16(val, pos);

Сборка выпуска VisualStudio расширяется до следующего: ( val находится в ax, pos находится в dx, sum ] находится в bx)

mov         ecx,10h 
sub         ecx,edx 
mov         ebp,eax 
shl         ebp,cl 
mov         cx,dx 
sar         ax,cl 
add         esi,2 
or          bp,ax 
xor         bx,bp 

Более эффективным эквивалентом сборки, созданной вручную, может быть:

 mov       cl,dx
 ror       ax,cl
 xor       bx,ax

Я не понял, как сгенерировать инструкцию ror из чистого кода 'c'. Однако ...
Когда я писал это, я вспомнил о встроенных функциях компилятора. Я могу сгенерировать второй набор инструкций с помощью:

sum ^= _rotr16(val,pos);

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

5
ответ дан 3 December 2019 в 14:34
поделиться
Другие вопросы по тегам:

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