Оптимизация Bitshift в массив

У меня есть фрагмент кода, который выполняется со скоростью ~ 1,2 миллиона циклов в секунду после выполнения некоторых задач. Самым громоздким является установка массива uint8_t с битовыми сдвигами данных из двух фрагментов данных uint32_t. Код выдержки выглядит следующим образом:

    static inline uint32_t RotateRight(uint32_t val, int n)
{
return (val >> n) + (val << (32 - n));

}

static inline uint32_t CSUInt32BE(const uint8_t *b)
{
return ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3];
}

static uint32_t ReverseBits(uint32_t val) // Usually just static, tried inline/static inline
{
//  uint32_t res = 0;
//  for (int i = 0; i<32; i++)
//  {
//      res <<= 1;
//      res |= val & 1;
//      val >>= 1;
//  }
// Original code above, benched ~220k l/s

//val = ((val & 0x55555555) << 1) | ((val >> 1) & 0x55555555);
//val = ((val & 0x33333333) << 2) | ((val >> 2) & 0x33333333);
//val = ((val & 0x0F0F0F0F) << 4) | ((val >> 4) & 0x0F0F0F0F);
//val = ((val & 0x00FF00FF) << 8) | ((val >> 8) & 0x00FF00FF);
//val = (val << 16) | (val >> 16);
// Option 0, benched ~770k on MBP

uint32_t c = 0;
c = (BitReverseTable256[val & 0xff] << 24) |
(BitReverseTable256[(val >> 8) & 0xff] << 16) |
(BitReverseTable256[(val >> 16) & 0xff] << 8) |
(BitReverseTable256[val >> 24]); // was (val >> 24) & 0xff
// Option 1, benched ~970k l/s on MBP, Current, minor tweak to 24

//unsigned char * p = (unsigned char *)&val;
//unsigned char * q = (unsigned char *)&c;
//q[3] = BitReverseTable256[p[0]];
//q[2] = BitReverseTable256[p[1]];
//q[1] = BitReverseTable256[p[2]];
//q[0] = BitReverseTable256[p[3]];
// Option 2 at ~970k l/s on MBP from http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-creturn c; // Current
//    return val; // option 0
//    return res; // original//uint32_t m;
//val = (val >> 16) | (val << 16);                            // swap halfwords
//m = 0x00ff00ff; val = ((val >> 8) & m) | ((val << 8) & ~m); // swap bytes
//m = m^(m << 4); val = ((val >> 4) & m) | ((val << 4) & ~m); // swap nibbles
//m = m^(m << 2); val = ((val >> 2) & m) | ((val << 2) & ~m);
//m = m^(m << 1); val = ((val >> 1) & m) | ((val << 1) & ~m);
//return val;
// Benches at 850k l/s on MBP

//uint32_t t;
//val = (val << 15) | (val >> 17);
//t = (val ^ (val >> 10)) & 0x003f801f;
//val = (t + (t << 10)) ^ val;
//t = (val ^ (val >>  4)) & 0x0e038421;
//val = (t + (t <<  4)) ^ val;
//t = (val ^ (val >>  2)) & 0x22488842;
//val = (t + (t <<  2)) ^ val;
//return val;
// Benches at 820k l/s on MBP
}
static void StuffItDESCrypt(uint8_t data[8], StuffItDESKeySchedule *ks, BOOL enc)
{
uint32_t left = ReverseBits(CSUInt32BE(&data[0]));
uint32_t right = ReverseBits(CSUInt32BE(&data[4]));

right = RotateRight(right, 29);
left = RotateRight(left, 29);

//Encryption function runs here

left = RotateRight(left, 3);
right = RotateRight(right, 3);

uint32_t left1 = ReverseBits(left);
uint32_t right1 = ReverseBits(right);

data[0] = right1 >> 24;
data[1] = (right1 >> 16) & 0xff;
data[2] = (right1 >> 8) & 0xff;
data[3] = right1 & 0xff;
data[4] = left1 >> 24;
data[5] = (left1 >> 16) & 0xff;
data[6] = (left1 >> 8) & 0xff;
data[7] = left1 & 0xff;

Это самый оптимальный способ сделать это? У меня есть версия uint64_t:

uint64_t both = ((uint64_t)ReverseBits(left) << 32) | (uint64_t)ReverseBits(right);

data[0] = (both >> 24 & 0xff);
data[1] = (both >> 16) & 0xff;
data[2] = (both >> 8) & 0xff;
data[3] = both & 0xff;
data[4] = (both >> 56);
data[5] = (both >> 48) & 0xff;
data[6] = (both >> 40) & 0xff;
data[7] = (both >> 32) & 0xff;

Я проверил, что произойдет, если я полностью пропущу это назначение (функция ReverseBits все еще выполняется), и код выполняется со скоростью ~ 6,5 млн. Циклов в секунду. Кроме того, этот удар по скорости произойдет, если я тоже сделаю только одно, с уровнем 1,2 миллиона, даже не касаясь остальных 7 заданий.

Я не хотел бы думать, что эта операция требует огромного 80% -го удара скорости из-за этой работы и не может быть сделана быстрее.

Это в Windows Visual Studio 2015 (хотя я стараюсь сделать исходный код максимально переносимым для macOS и Linux).

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

Этим файлам более 20 лет, и они успешно восстанавливали файлы, хотя и с низкой скоростью в течение многих лет. Увидеть Сообщение блога.

1

Решение

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

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

3

Другие решения

Моей непосредственной мыслью было «посмотреть» int32_t как будто они были массивом int8_t лайк

uint8_t data2[8];
*((uint32_t*)&data2[0]) = right1;
*((uint32_t*)&data2[4]) = left1;

Тем не менее, вы храните наиболее значимые биты right1 в data[0]в то время как этот подход позволяет младшим битам data[0], Во всяком случае, так как я не знаю, что ReverseBits и может ли вы также адаптировать свой код в соответствии с другим порядком, может быть, это поможет …

0

По вопросам рекламы [email protected]