Оптимизировать функцию записи битов в файл - PullRequest
0 голосов
/ 05 декабря 2010

Вот функция, которая записывает n битов в двоичный файл.

Параметры:

  • Данные: битовая последовательность для записи в файл (lsb справа)
  • Длина: количество записываемых битов
  • OutFile: файл назначения.

Первая версия функции:

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
    static unsigned long long BitBuffer = 0;
    static unsigned BitCounter = 0;

    for (unsigned i = Length; i --; ) {
        (BitBuffer <<= 1) |= ((Data >> i) & 0x1);
        BitCounter ++;

        if (BitCounter == 64) {
            OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
            BitCounter = 0;
        }
    }
}

Вторая версия:

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
    static unsigned long long BitBuffer = 0;
    static unsigned FreeBitCounter = sizeof(BitBuffer) << 3;

    Data &= (1 << Length) - 1;

    if (FreeBitCounter > Length) {
        BitBuffer |= (Data << (FreeBitCounter -= Length));
    } else if (FreeBitCounter < Length) {
        BitBuffer |= (Data >> (Length -= FreeBitCounter));
        OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
        BitBuffer = Data << ((sizeof(BitBuffer) << 3) - Length);
        FreeBitCounter = (sizeof(BitBuffer) << 3) - Length;
    } else {
        BitBuffer |= Data;
        OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
        BitBuffer = 0; FreeBitCounter = (sizeof(BitBuffer) << 3);
    }
}

Они оба выполняют свою работу, но вторая быстрее первой. Любая идея сделать это еще быстрее?

Спасибо всем за помощь!

Ответы [ 6 ]

1 голос
/ 06 декабря 2010

Вместо вызова write() попробуйте следующее:

OutFile.rdbuf()->sputn((char *) & BitBuffer, sizeof(BitBuffer));
1 голос
/ 05 декабря 2010
  1. Я бы начал с удаления статических переменных из вашего тела функции.Они немного медленнее, так как должны проверять свое состояние (уже инициализированное или нет) при каждом вызове функции.Просто переместите их за пределы функции.

  2. Почему вы используете такой короткий буфер?Вы уверены, что вам нужно записывать каждую длинную подпись в файл?Я бы предложил использовать что-то вроде unsigned char buffer[1024].

  3. Тогда вы должны подумать, как избавиться от других «if операторов».

0 голосов
/ 06 декабря 2010

Вот один из способов сделать это с большим буфером. (в псевдо-C #)

const int wordSz= sizeof(unsigned long long)*8;

void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) { 
   static unsigned long long BitBuffer[BUFSZ+1] ={0};  
   static unsigned bitsSoFar = 0;

   Data &= (1 << Length) - 1; 
   int index = bitsSoFar/wordSz;
   int offset = bitsSoFar - (index*wordSz);
   BitBuffer[index]|=Data<<offset;
   int remainder = offset+length-wordSz;
   if (remainder > 0)
   {
      index++;
      BitBuffer[index]=Data>>(length-remainder);
   }
   bitsSoFar+=length;
   if (bitsPacked > BUFSZ*wordSz)
   {
      OutFile.write((char*)BitBuffer, BUFSZ*sizeof(unsigned long long));
      bitsSoFar-=BUFSZ*wordSz;
      BitBuffer[0]=BitBuffer[BUFSZ];
   }
}
0 голосов
/ 05 декабря 2010

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

/**
 * @brief Write some bits to a file.
 *
 * The bits are written MSB-first to a temporary 64-bit integer, which is
 * then written to the file in host byte-order.
 *
 * @param Data The data to write to the file.  Only the least-significant
 *             Length bits are written.  Of the bits that are written, the
 *             most significant bit is written first.
 * @param Length The length of the data to write, in bits.  Must be <= 64.
 * @param OutFile The file to write to
 *
 * @note This function is not thread-safe
 * @note This function stores some state in a static variable.  You must
 *       ensure that the total data written is a multiple of 64 bits, or
 *       some data will be lost.  You can only switch from one OutFile to
 *       another on a 64-bit boundry.
 */
void WriteBitsToFile(unsigned long long Data,
                     unsigned Length,
                     std::ofstream & OutFile)
{
   static unsigned long long BitBuffer = 0;
   static unsigned BitCounter = 0; 

   // Loop through input bits, one bit at a time
   for (int i = (int)Length; i >= 0; --i)
   {
      // Get the input bit
      unsigned long long NextBit = ((Data >> i) & 1);

      // Add it to the temporary buffer
      BitBuffer = ((BitBuffer << 1) | NextBit);
      BitCounter++;

      // If the temporary buffer is full, write it out
      if (BitCounter == 64)
      {
         OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
         BitCounter = 0;
      }
   }
}

Теперь, когда я понимаю, что вы пытаетесь сделать ...

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

Одной из возможных оптимизаций является запись в гораздо больший буфер (я бы предложил по крайней мере 4 КБ). Это означает, что вам не нужно вызывать write () так часто. Вызов write () может быть относительно медленным.

0 голосов
/ 05 декабря 2010

Если я вас правильно понимаю, вы хотите записать length младшие биты длинного целого числа без знака, которое вы получите.Вы можете сохранить цикл ввода входных битов, маскируя необходимые биты:

unsigned long long mask = (1ull << length) - 1; // creates a mask of 'length' 1's
BitBuffer = Data & mask;

как примечание, я не понимаю, почему ваш тест и запись находятся внутри цикла, в первой версии.

0 голосов
/ 05 декабря 2010

Открытие файла, вероятно, будет намного медленнее, чем запись в него.В своем дизайне вы минимизируете вызовы открытия файлов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...