2010-12-05 5 views
0

Вот функция, которая записывает 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); 
    } 
} 

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

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

ответ

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

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

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

0

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

+0

Спасибо вам ответить. Файл открывается и закрывается только один раз во всей программе. – 2010-12-05 15:58:19

0

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

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

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

+0

Благодарим вас за ответ. Вы правы в том, что делает функция. Тестирование и запись внутри цикла необходимы, потому что BitBuffer должен быть написан только тогда, когда он заполнен – 2010-12-05 15:57:07

+0

@Danilo Brambilla: О, я вижу, вы вызываете эту функцию ** несколько раз ** и очищаете буфер до файла только тогда, когда он заполнен? Если это так, то, как упоминалось в @ user9876, было бы полезно, если бы вы это сказали. Как вы обеспечиваете запись последнего фрагмента, если буфер еще не заполнен? – davka 2010-12-05 16:03:23

+0

В конце программы я вызову функцию с данными = 0 и длиной = 64, чтобы заставить запись последнего фрагмента в конечном итоге с помощью последовательности 0 :-) – 2010-12-05 16:10:04

0

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

/** 
* @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() может быть относительно медленным.

1

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

OutFile.rdbuf()->sputn((char *) & BitBuffer, sizeof(BitBuffer)); 
0

Вот один из способов сделать это с большим буфером. (в Псевдо-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]; 
    } 
} 
Смежные вопросы