Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > циклический буфер/очередь


Автор: bel_nikita 20.11.2004, 15:25
Понадобилась, давече, очередь, но непростая, а скоростная. И на ум пришло только: организовать циклический буфер. Т.к. мне кажется, что быстрее и проще ничего на свете не бывает.
Хотел бы, чтобы покритиковали и нашли узкие места: как еще оптимизировать и выкрасть асмовские инструкции smile
Код

#define __INLINE  FORCEINLINE  // нужно ли это?
#define __FAST    __fastcall         // нужно ли это?


 template<typename T>
 class cCyclicBuffer
 {
   typedef T   TYPE;
   typedef T*  PTYPE;
 public:
   cCyclicBuffer(size_t count): m_Head(0),m_Tail(0)
   {
     m_LenBuffer = count;
     m_pBuffer = (PTYPE)malloc(m_LenBuffer * sizeof(TYPE));
     if ( m_pBuffer == NULL ) throw ("not enough memory");
  }
   ~cCyclicBuffer()
   {
     free(m_pBuffer);
   }

   // получение свободного места в буфере
   __INLINE  size_t __FAST GetSpace()
   {
     return m_LenBuffer - GetLength();
   }
   
   // получение данных в буфере
   __INLINE  size_t __FAST GetLength()
   {
     size_t  len = m_Head - m_Tail;
     if ( len & (1 << (sizeof( size_t )*8 - 1))  )         // Buffer: Begin...m_Head...m_Tail...End
       len = m_LenBuffer - ( -len );                       // здесь зараза варнинг C4146 кидает
     return len;
   }

   // кладем в буфер
   __INLINE  size_t __FAST PutData(PTYPE pData, size_t count )
   {
     if ( GetSpace() < count ) return 0;                   // Not enough memory

     if ( m_Head + count < m_LenBuffer )                   // Buffer: Begin...m_Tail...m_Head...End
     {
       memcpy(m_pBuffer + m_Head,pData,sizeof(TYPE)*count);
     }
     else                                                  // Buffer: Begin...m_Head...m_Tail...End
     {
       size_t part1 = m_LenBuffer - m_Head;
       size_t part2 = count - part1;
       memcpy(m_pBuffer + m_Head,pData,sizeof(TYPE)*part1);
       memcpy(m_pBuffer,pData,sizeof(TYPE)*part2);
     }
     m_Head = (m_Head + count) % m_LenBuffer;
     return count;
   }

   // тяним из буфера
   __INLINE  size_t __FAST GetData(const PTYPE pData, size_t count )
   {
     size_t read = GetLength();                    // All Data from buffer
     if ( !Read ) return 0;
     if ( read >= count ) read = count;            // Length of Data from buffer
     if ( m_Tail + read < m_LenBuffer )            // Buffer: Begin...m_Tail...m_Head...End
     {
       memcpy(pData,m_pBuffer + m_Tail,read);
     }
     else                                          // Buffer: Begin...m_Head...m_Tail...End
     {
       size_t part1,part2;
       part1 = m_LenBuffer - m_Tail;               // Length from m_Tail to end buffer
       part2 = read - part1;                       // Last read
       memcpy(pData,m_pBuffer + m_Tail,part1);
       memcpy(pData + part1,m_pBuffer,part2);
     }
      m_Tail = ( m_Tail + read) % m_LenBuffer;
     return read;
   };  

 protected:
   size_t  m_Head;
   size_t  m_Tail;
   size_t  m_LenBuffer;
   PTYPE   m_pBuffer;
 };


Может стоит, заменить len = - len; на
Код
__asm {
             mov         eax,dword ptr [len];
             neg         eax;
             mov         dword ptr [len],eax ;
       }
Чтобы варнинг не генерила. Или отрубить варниг через прагму?

З.Ы.: Может в ФАКю кинуть? Пригодится ведь когда-то... smile

Автор: Adil' 20.11.2004, 17:20
1. Cтранная функция GetLength, даже не стал вникать, что в if происходит... м.б. так проще:
Код
// получение данных в буфере
  __INLINE  size_t __FAST GetLength()
  {
    size_t  len = m_Head - m_Tail;
    if(len<=0)
      return m_LenBuffer+len;
    return len;
  }

2. Если торопимся, то для больших по размеру типов м.б. лучше использовать буфер, в котором хранятся адреса объектов - меньше времени будет уходить на копирование объектов из памяти в память.


З.Ы. Классы, шаблоны и malloc, free - как-то не гармонично? smile

Автор: bel_nikita 20.11.2004, 18:59
Adil'
Цитата
Cтранная функция GetLength, даже не стал вникать, что в if происходит... м.б. так проще

Да, будет проще. Если вместо size_t был бы int, то я бы так и сделал, но size_t - беззнаковый тип, поэтому
Код
// получение данных в буфере
 __INLINE  size_t __FAST GetLength()
 {
   size_t  len = m_Head - m_Tail;
   if(len<=0)
     return m_LenBuffer+len;
   return len;
 }
не подходит. Пришлось извратиться smile Кстати, данный вариант функции проигрывает по компактности из-за if(len<=0)

if ( len & (1 << (sizeof( size_t )*8 - 1)) ) - нахождение, является ли, полученный len отрицательным или нет, т.е. проверяется самый старший бит.
len = m_LenBuffer - ( -len ); - инвертируем len в представление положительного числа и отнимаем от m_LenBuffer.

Цитата
2. Если торопимся, то для больших по размеру типов м.б. лучше использовать буфер, в котором хранятся адреса объектов - меньше времени будет уходить на копирование объектов из памяти в память.

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

Цитата
З.Ы. Классы, шаблоны и malloc, free - как-то не гармонично?
Есть предложения smile

Автор: Adil' 21.11.2004, 11:23
Цитата(bel_nikita @ 20.11.2004, 18:59)
Да, будет проще. Если вместо size_t был бы int, то я бы так и сделал
Да, в самом деле, сорри, не обратил внимание. Правда тут же возникает вопрос (с учетом 2). - неужели физические устройства будут обмениваться данными размером больше, чем 2 ГигаОбъекта?
В погоне за универсальностью можно проиграть в той же скорости для некоего конкретного случая.

Цитата(bel_nikita @ 20.11.2004, 18:59)
Есть предложения
Код

m_pBuffer = new TYPE[m_LenBuffer];
delete[] m_pBuffer;



Автор: bel_nikita 22.11.2004, 00:24
Adil'
Цитата
Код
m_pBuffer = new TYPE[m_LenBuffer];
delete[] m_pBuffer;

Ага, точно smile

Цитата
м.б. лучше использовать буфер, в котором хранятся адреса объектов - меньше времени будет уходить на копирование объектов из памяти в память.
Это именно буффер для обмена пакетами между, грубо говоря, двумя объектами. И в конечной реализации не будет никакого выделения памяти и memcpy, а будет WriteDevice, ReadDevice.

З.Ы.: а данную циклическую очередь хочу отладить от и до. а то с периодичностью, раз в год приходится копаться в старых исходниках и искать циклический буфер или писать заново, как сейчас smile

Автор: cardinal 22.11.2004, 01:37
Цитата(bel_nikita @ 20.11.2004, 14:25)
sizeof( size_t )*8

можно заменить на
Код

sizeof( size_t )<<3

Цитата(bel_nikita @ 20.11.2004, 14:25)
if ( !Read ) return 0;

Цитата(bel_nikita @ 20.11.2004, 14:25)
size_t part1

А кто такие Read и size_t?

Автор: bel_nikita 22.11.2004, 02:13
cardinal
Цитата
sizeof( size_t )*8 можно заменить на sizeof( size_t )<<3
Ага, уже сделано. Просто засорять эфир неохота было еще одним листингом smile
Цитата
А кто такие Read и size_t?
smile
Read - это read;
size_t - беззнаковый тип, обычно unsigned int.


Автор: cardinal 22.11.2004, 03:33
Цитата(bel_nikita @ 20.11.2004, 14:25)
#define __INLINE  FORCEINLINE  // нужно ли это?
#define __FAST    __fastcall        // нужно ли это?

Хуже от этого не будет.
Цитата(bel_nikita @ 20.11.2004, 14:25)
Чтобы варнинг не генерила. Или отрубить варниг через прагму? ...

Может, а может просто стоит заменить на
Код

len = m_LenBuffer - ( -(int)len );
smile

Автор: bel_nikita 22.11.2004, 09:42
cardinal
Код
len = m_LenBuffer - ( -(int)len );

Как то не очень смотриться smile Тогда уж лучше не size_t, а int использовать.
Хотя... асмовская вставка, которая у меня сейчас стоит, тоже не смотриться...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)