2013-05-06 2 views
0

В настоящее время я пытаюсь оптимизировать свой код, чтобы работать немного быстрее. В настоящее время он занимает около + 30 мс для обновления около 3776000 байт. Если я удалю outPx обновлений внутри моей функции, она будет работать примерно в 3 мс, что означает, что обновления до outPx - это то, что делает функцию медленнее.Модифицировать данные из массива uint8_t очень медленно?

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

uint8_t* outPx = (uint8_t*)out.data; 
for (int px=0; px<pxSize; px+=4) 
    { 
     newTopAlpha = (alpha*inPx[px+3]); 

     if (0xff == newTopAlpha) 
     { 
      // top is opaque covers entire bottom 

      // set copy over BGR colors 
      outPx[px] = inPx[px]; 
      outPx[px+1] = inPx[px+1]; 
      outPx[px+2] = inPx[px+2]; 
      outPx[px+3] = 0xff; //Fully opaque 
     } 
     else if (0x00 != newTopAlpha) 
     { 
      // top is not completely transparent 
      topAlpha = newTopAlpha/(float)0xff; 
      bottomAlpha = outPx[px+3]/(float)0xff; 
      newAlpha = topAlpha + bottomAlpha*(1-topAlpha); 
      alphaChange = bottomAlpha*(1-topAlpha); 

      outPx[px] = (uint8_t)((inPx[px]*topAlpha + outPx[px]*alphaChange)/newAlpha); 
      outPx[px+1] = (uint8_t)((inPx[px+1]*topAlpha + outPx[px+1]*alphaChange)/newAlpha); 
      outPx[px+2] = (uint8_t)((inPx[px+2]*topAlpha + outPx[px+2]*alphaChange)/newAlpha); 
      outPx[px+3] = (uint8_t)(newAlpha*0xff); 
     } 
    } 
+0

Вы беспокоитесь о 27 миллисекундах ?! – Dave

+3

Также вам нужно помнить, что любой достойный компилятор будет оптимизировать код. Если вы удалите строки 'outPx', это также удалит остальную часть кода и, вероятно, весь цикл, как мертвый код. В том же примечании, самый простой способ ускорить любой код - это установить настройки оптимизации вашего компилятора выше. – Dave

+0

Без обновления 'outPx' функция почти не пишет. Вы уверены, что код не просто оптимизирован? – Angew

ответ

0

Хорошо, если это действительно является узким местом, и вы не можете использовать/встроенные методы GPU для некоторой случайной причины, то есть много вы можете сделать:

uint8_t *outPx = (uint8_t*) out.data; 
const int cAlpha = (int) (alpha * 256.0f + 0.5f); 
for(int px = 0; px < pxSize; px += 4) { 
    const int topAlpha = (cAlpha * (int) inPx[px|3]) >> 8; // note | not + for tiny speed boost 

    if(topAlpha == 255) { 
     memcpy(&outPx[px], &inPx[px], 4); // might be slower than per-component copying; benchmark! 
    } else if(topAlpha) { 
     const int bottomAlpha = (int) outPx[px|3]; 
     const int alphaChange = (bottomAlpha * (255 - topAlpha))/255; 
     const int newAlpha = topAlpha + alphaChange; 

     outPx[px ] = (uint8_t) ((inPx[px ]*topAlpha + outPx[px ]*alphaChange)/newAlpha); 
     outPx[px|1] = (uint8_t) ((inPx[px|1]*topAlpha + outPx[px|1]*alphaChange)/newAlpha); 
     outPx[px|2] = (uint8_t) ((inPx[px|2]*topAlpha + outPx[px|2]*alphaChange)/newAlpha); 
     outPx[px|3] = (uint8_t) newAlpha; 
    } 
} 

Основного изменение что нет никакой арифметики с плавающей запятой (я мог бы пропустить /255 или что-то, но вы поняли эту идею). Я также удалил повторные вычисления и использовал битовые операторы, где это возможно. Другая оптимизация будет заключаться в использовании арифметики с фиксированной точностью для изменения 3 делений на один разделитель и 3 умножения/бит-сдвига. Но вам нужно будет проверить, что на самом деле помогает. memcpyможет быть быть быстрее. Опять же, вам нужно ориентироваться.

Наконец, если вы что-то знаете об изображениях, вы можете дать подсказки компилятора о ветвлении. Например, в GCC вы можете сказать if(__builtin_expect(topAlpha == 255, 1)), если знаете, что большая часть изображения является сплошным цветом, а alpha - 1,0.


Обновление на основе комментариев:

И за любовь к здравомыслию, никогда (никогда) тест с оптимизаций выключен.

+0

'>> 8' делит на 256, а не 255. Кроме того, добавление битовых операторов вручную, скорее всего, преждевременная оптимизация, компилятор сможет сделать это за вас. Избавление от поплавка должно быть единственной ручной оптимизацией. – Lundin

+0

@ Lundin да, поэтому я умножил 'cAlpha' на 256 вместо 255. – Dave

+0

Ага, я пропустил это. Тем не менее, неясные оптимизации, подобные этим, не должны быть необходимы. – Lundin

1

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

Изменить uint8_t . Это говорит компилятору, что вы хотите, чтобы эта переменная была 8 бит, если это возможно, но что это нормально использовать больший размер, если он делает код быстрее.

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

+0

За исключением, вероятно, данных, которые должны быть представлены 8-разрядными пиксельными данными по завершении. Я уверен, что, как и мой комментарий выше, это не проблема. Проблема - это все вычисления с плавающей запятой. –

+0

@MatsPetersson Конечный результат может быть исправлен с помощью нажатия на uint8_t в конце. И кажется вероятным, что поплавки являются виновниками, хотя, не зная, в какой конкретной системе работает код, трудно вручную оптимизировать что-либо. Система, возможно, даже не имеет FPU, насколько нам известно. – Lundin

+0

Следовательно, я просил в комментарии выше «какой процессор для этого» –

2

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

Даже делая это простое преобразование умножать вместо разрыва может помочь совсем немного:

newAlpha = 1/(topAlpha + bottomAlpha*(1-topAlpha)); 

... 

outpx = (uint8_t)((inPx[px]*topAlpha + outPx[px]*alphaChange)*newAlpha); 

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

+0

Удивительный! Позвольте мне попытаться сделать это изменение посмотреть, куда оно меня вставляет ... – Jona

+0

+1 Если у CPU есть FPU, это может фактически замедлить код. Например, блок FPU и целочисленный блок могут конвейерно работать. Вероятно, в вопрос оптимизации нет ответа *. Конечно, это хороший совет попробовать. –

Смежные вопросы