Как уменьшить загрузку процессора? - PullRequest
1 голос
/ 15 февраля 2012

Мне нужно декодировать некоторый байтовый массив (необработанные данные).Он может состоять из базовых типов данных (int, unsigned int, char, short и т. Д.). В соответствии с определенной структурой, мне нужно интерпретировать их.Ниже приведен пример:

struct testData
{ 
 int a;
char c;
};
   unsigned char** buf = {0x01,0x00,0x00,0x00,0x41}
   example byte array(in little endian) : 0100000041

   should give decoding like : a = 1, c = 'A'

Данные выборки могут быть очень большими, и структура выборки (например, testData) может содержать от 200 до 3000 полей.Если я использую приведение, чтобы прочитать соответствующие данные из ** buf и установить указатель, как показано ниже:

    int a = *(reinterpret_cast<int*>(*buf);
    *buf += 4;
    char c = **buf;
    *buf += 1;

Мой ЦП довольно высок, если число файлов, которые необходимо декодировать, велико.пример:

    struct testData
    {
     int element1;
     char element2;
     int element3;
      ... ...
     ... ...
      short element200;
     char element201;
     char element202;
    }

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

У меня есть два ограничения:

  1. "Структураможет содержать дополнительный байт. "
  2. У меня нет контроля над тем, как будет определена структура.Структура также может содержать вложенные элементы.

Ответы [ 3 ]

5 голосов
/ 15 февраля 2012
int a = *(reinterpret_cast<int*>(*buf);

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

int a=static_cast<int>(*buf[0]) |
     (static_cast<int>(*buf[1])<<8) |
     (static_cast<int>(*buf[2])<<16) |
     (static_cast<int>(*buf[3])<<24);

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

2 голосов
/ 15 февраля 2012

Вы должны иметь возможность просто отобразить структуру в буфер, если структура правильно упакована:

#pragma pack(push, 1)
struct testData
    {
     int element1;
     char element2;
     int element3;
      ... ...
     ... ...
      short element200;
     char element201;
     char element202;
    }
#pragma pack(pop)

Вы также должны объявлять структуру разумным способом выравнивания, не смешивайтеint с последующим char с последующим int ... Тогда, если вы прочитаете данные в выровненном буфере, простое приведение буфера к testData* даст вам доступ ко всем членам.Таким образом, вы избежите всех этих бесплатных копий.Если вы читаете структуру в прямом направлении (p->element1, затем читаете p->element2, затем p->element3 и т. Д.) аппаратная предварительная выборка должна сработать и дать большой импульс.

Дальнейшие усовершенствования потребуют реальных измерений горячих точек.Также прочитайте эту книгу в библиотеке и прочитайте: Поваренная книга по оптимизации программного обеспечения .

1 голос
/ 15 февраля 2012

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

template<typename T>
const unsigned char * read_from_buffer( T* value, const unsigned char * buffer);

template<>
const unsigned char * read_from_buffer<int>( int* value, const unsigned char * buffer)
{
   *value = static_cast<int>(*buf[0]) |
     (static_cast<int>(*buf[1])<<8) |
     (static_cast<int>(*buf[2])<<16) |
     (static_cast<int>(*buf[3])<<24);
   return buffer+4'
}

template<>
const unsigned char * read_from_buffer<char>( char * value, const unsigned char * buffer )
{
  *value = *buffer;
  return buffer+1;
}

struct TestData
{
  int a;
  char c;
};

int main()
{
  unsigned char buf[] = {0x01,0x00,0x00,0x00,0x41};
  unsigned char * ptr = buf;

  TestData data;
  ptr = read_from_buffer( &data.a, ptr );
  ptr = read_from_buffer( &data.c, ptr );
}

Вы можете инкапсулировать это еще дальше, добавить проверку ошибок и т. Д., И у вас будет хороший двоичный поток, такой как интерфейс.

...