Faster buffer

After you have edited the source code, post your patch here.
Forum rules
Home | Wiki | Rules

Faster buffer

Postby ivan386 » 02 Mar 2014 13:28

Code: Select all
Index: Buffer.cpp
===================================================================
--- Buffer.cpp   (revision 9363)
+++ Buffer.cpp   (working copy)
@@ -44,7 +44,9 @@
 CBuffer::CBuffer() :
    m_pNext      ( NULL )   // This object isn't in a list yet
 ,   m_pBuffer   ( NULL )   // No memory block has been allocated for this object yet
-,   m_nBuffer   ( 0 )      // The size of the memory block is 0
+,   m_pMBlock   ( NULL )   
+,   m_nRemoved   ( 0 )
+,   m_nMBlock   ( 0 )      // The size of the memory block is 0
 ,   m_nLength   ( 0 )      // No bytes have been written here yet
 {
 }
@@ -52,9 +54,28 @@
 CBuffer::~CBuffer()
 {
    // If the member variable points to some memory, free it
-   if ( m_pBuffer ) free( m_pBuffer );
+   if ( m_pMBlock ) free( m_pMBlock );
 }
 
+void CBuffer::SetTo(BYTE* pData, DWORD nSize)
+{
+   if ( m_pMBlock ) free( m_pMBlock );
+   m_pMBlock = m_pBuffer = pData;
+   m_nMBlock = m_nLength = nSize;
+   m_nRemoved = 0;
+}
+
+void CBuffer::Align()
+{
+   ASSERT( m_pMBlock + m_nRemoved == m_pBuffer );
+   if ( m_nRemoved > 0 )
+   {
+      MoveMemory( m_pMBlock, m_pBuffer, m_nLength );
+      m_pBuffer = m_pMBlock;
+      m_nRemoved = 0;
+   }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // CBuffer add
 
@@ -111,12 +132,14 @@
    if ( nLength >= m_nLength )
    {
       ASSERT( nLength == m_nLength );
-      m_nLength = 0;
+      Clear();
    }
    else if ( nLength )
    {
+      ASSERT( m_pMBlock + m_nRemoved == m_pBuffer );
       m_nLength -= static_cast< DWORD >( nLength );
-      MoveMemory( m_pBuffer, m_pBuffer + nLength, m_nLength );
+      m_nRemoved += static_cast< DWORD >( nLength );
+      m_pBuffer = m_pMBlock + m_nRemoved; // Move pointer not memory
    }
 }
 
@@ -135,19 +158,13 @@
    // primitive overflow protection (relevant for 64bit)
    if ( nLength > INT_MAX ) return 0;
 
+   size_t nMinLength = min( (size_t) pBuffer->m_nLength, nLength );
+
    // If the call specified a length, use it, otherwise use the length of pBuffer
-   if( pBuffer->m_nLength < nLength )
-   {
-      Add( pBuffer->m_pBuffer, pBuffer->m_nLength );   // Copy the memory across
-      pBuffer->Clear();                        // Remove the memory from the source buffer
-      return pBuffer->m_nLength;                  // Report how many bytes we moved
-   }
-   else
-   {
-      Add( pBuffer->m_pBuffer, nLength );            // Copy the memory across
-      pBuffer->Remove( nLength );                  // Remove the memory from the source buffer
-      return static_cast< DWORD >( nLength );         // Report how many bytes we moved
-   }
+   Add( pBuffer->m_pBuffer, nMinLength );            // Copy the memory across
+   pBuffer->Remove( nMinLength );                  // Remove the memory from the source buffer
+   return nMinLength;      // Report how many bytes we moved
+   
 }
 
 void CBuffer::Attach(CBuffer* pBuffer)
@@ -156,15 +173,13 @@
    if ( pBuffer == NULL || pBuffer == this )
       return;
 
-   if ( m_pBuffer ) free( m_pBuffer );
-   m_pBuffer = pBuffer->m_pBuffer;
-   pBuffer->m_pBuffer = NULL;
+   SetTo( pBuffer->m_pMBlock, pBuffer->m_nMBlock );
+   m_nLength = pBuffer->m_nLength;
+   m_nRemoved = pBuffer->m_nRemoved;
 
-   m_nBuffer = pBuffer->m_nBuffer;
-   pBuffer->m_nBuffer = 0;
-
-   m_nLength = pBuffer->m_nLength;
-   pBuffer->m_nLength = 0;
+   pBuffer->m_pMBlock = pBuffer->m_pBuffer = NULL;
+   pBuffer->m_nMBlock = pBuffer->m_nLength = 0;
+   pBuffer->m_nRemoved = 0;
 }
 
 // Takes a pointer to some memory, and the number of bytes we can read there
@@ -189,41 +204,56 @@
 bool CBuffer::EnsureBuffer(const size_t nLength) throw()
 {
    // Limit buffer size to a signed int. This is the most that can be sent/received from a socket in one call.
-   if ( nLength > 0xffffffff - m_nBuffer ) return false;
+   if ( nLength > 0xffffffff - m_nMBlock ) return false;
 
    // If the size of the buffer minus the size filled is bigger than or big enough for the given length, do nothing
-   if ( m_nBuffer - m_nLength >= nLength )
+   if ( m_nMBlock - m_nLength >= nLength )
    {
       // There is enough room to write nLength bytes without allocating anything
+      
+      if ( GetBufferFree() < nLength )
+         Align();
 
       // If the buffer is larger than 512 KB, but what it needs to hold is less than 256 KB
-      if ( m_nBuffer > 0x80000 && m_nLength + nLength < 0x40000 )
+      if ( m_nMBlock > 0x80000 && m_nLength + nLength < 0x40000 )
       {
+         Align();
          // Reallocate it to make it half as big
-         const DWORD nBuffer = 0x40000;
-         BYTE* pBuffer = (BYTE*)realloc( m_pBuffer, nBuffer ); // This may move the block, returning a different pointer
-         if ( ! pBuffer )
+         const DWORD nMBlock = 0x40000;
+         BYTE* pMBlock = (BYTE*)realloc( m_pMBlock, nMBlock ); // This may move the block, returning a different pointer
+         if ( ! pMBlock )
             // Out of memory - original block is left unchanged. It's ok.
             return true;
-         m_nBuffer = nBuffer;
-         m_pBuffer = pBuffer;
+
+         m_nMBlock = nMBlock;
+         m_pMBlock = m_pBuffer = pMBlock;
+         
       }
       return true;
    }
 
-   // Make m_nBuffer the size of what's written plus what's requested
-   DWORD nBuffer = m_nLength + static_cast< DWORD >( nLength );
+   Align();
 
+   // Make m_nMBlock the size of what's written plus what's requested
+   DWORD nMBlock = m_nLength + static_cast< DWORD >( nLength );
+
+   // Take more if nMBlock not big enough.
+   // To reduce the number of calls to realloc.
+   if ( ( nMBlock -  m_nMBlock ) < ( m_nMBlock / 16 ) )
+      nMBlock = m_nMBlock + m_nMBlock / 16;
+
    // Round that up to the nearest multiple of 1024, or 1 KB
-   nBuffer = ( nBuffer + BLOCK_SIZE - 1 ) & BLOCK_MASK;
+   nMBlock = ( nMBlock + BLOCK_SIZE - 1 ) & BLOCK_MASK;
 
    // Reallocate the memory block to this size
-   BYTE* pBuffer = (BYTE*)realloc( m_pBuffer, nBuffer ); // May return a different pointer
-   if ( ! pBuffer )
+   BYTE* pMBlock = (BYTE*)realloc( m_pMBlock, nMBlock ); // May return a different pointer
+   if ( ! pMBlock )
       // Out of memory - original block is left unchanged. Error.
       return false;
-   m_nBuffer = nBuffer;
-   m_pBuffer = pBuffer;
+
+   m_nMBlock = nMBlock;
+   m_pMBlock = m_pBuffer = pMBlock;
+   
    return true;
 }
 
@@ -390,9 +420,7 @@
       return FALSE;
    }
 
-   if ( m_pBuffer ) free( m_pBuffer );
-   m_pBuffer = pCompress;
-   m_nBuffer = m_nLength = nCompress;
+   SetTo( pCompress, nCompress );
 
    return TRUE;
 }
@@ -409,9 +437,7 @@
    if ( ! pCompress )
       return FALSE;
 
-   if ( m_pBuffer ) free( m_pBuffer );
-   m_pBuffer = pCompress;
-   m_nBuffer = m_nLength = nCompress;
+   SetTo( pCompress, nCompress );
 
    return TRUE;
 }
Index: Buffer.h
===================================================================
--- Buffer.h   (revision 9363)
+++ Buffer.h   (working copy)
@@ -33,11 +33,13 @@
    ~CBuffer();
 
    CBuffer*   m_pNext;   // A pointer to the next CBuffer object, letting them be linked together in a list
-   BYTE*      m_pBuffer;   // The block of allocated memory
+   BYTE*      m_pBuffer;   // A pointer to ( m_pMBlock + m_nRemoved )
    DWORD      m_nLength;   // The #bytes written into the block
 
 private:
-   DWORD      m_nBuffer;   // The size of the allocated block
+   DWORD      m_nRemoved; // The #bytes removed from the block
+   BYTE*      m_pMBlock;   // The block of allocated memory
+   DWORD      m_nMBlock;   // The size of the allocated block
 
    CBuffer(const CBuffer&);
    CBuffer& operator=(const CBuffer&);
@@ -44,11 +46,11 @@
 
 // Accessors
 public:
-   inline DWORD GetBufferSize() const { return m_nBuffer; }            // Return the total size of the buffer
+   inline DWORD GetBufferSize() const { return m_nMBlock - m_nRemoved; }            // Return the total size of the buffer
    inline BYTE* GetData() const { return m_pBuffer; }                  // Return a pointer to the start of the data in the buffer
    inline DWORD GetCount() const { return m_nLength; }                  // Return the filled size of the buffer
    inline BYTE* GetDataEnd() const { return m_pBuffer + m_nLength; }      // Return a pointer to the end of the data in the buffer
-   inline DWORD GetBufferFree() const { return m_nBuffer - m_nLength; }   // Return the unused #bytes in the buffer
+   inline DWORD GetBufferFree() const { return m_nMBlock - ( m_nLength + m_nRemoved ); }   // Return the unused #bytes in the buffer
 
 // Operations
 public:
@@ -99,6 +101,8 @@
    // Clears the memory from the buffer
    inline void   Clear() throw()
    {
+      m_pBuffer = m_pMBlock;
+      m_nRemoved = 0;
       m_nLength = 0;
    }
 
@@ -120,4 +124,7 @@
 
    // Static means you can call CBuffer::ReverseBuffer without having a CBuffer object at all
    static void ReverseBuffer(const void* pInput, void* pOutput, size_t nLength);
+private:
+   void SetTo(BYTE* pData, DWORD nSize);
+   void Align();
 };
Attachments
buffer.zip
(38.53 KiB) Downloaded 106 times
data:application/exe,%B4%09%BA%0D%01%CD%21%B4%08%CD%21%CD%20Hello,World!$
ivan386
 
Posts: 260
Joined: 17 Jun 2009 14:08

Re: Faster buffer

Postby raspopov » 02 Mar 2014 14:23

What is it?
User avatar
raspopov
Project Admin
 
Posts: 944
Joined: 13 Jun 2009 12:30
Location: Russian Federation

Re: Faster buffer

Postby ivan386 » 03 Mar 2014 12:58

Немного доработал буфер чтобы при удалении из него он не переписывал куски памяти на новое место а просто двигал указатель (m_pBuffer).

Code: Select all
void CBuffer::Remove(const size_t nLength) throw()
{
   if ( nLength >= m_nLength )
   {
      ASSERT( nLength == m_nLength );
      Clear();
   }
   else if ( nLength )
   {
      ASSERT( m_pMBlock + m_nRemoved == m_pBuffer );
      m_nLength -= static_cast< DWORD >( nLength );
      m_nRemoved += static_cast< DWORD >( nLength );
      m_pBuffer = m_pMBlock + m_nRemoved; // Move pointer not memory
   }
}


Ну и когда требуется дополнительное место в буфере тогда выравниваются данные на начало блока.

Code: Select all
void CBuffer::Align()
{
   ASSERT( m_pMBlock + m_nRemoved == m_pBuffer );
   if ( m_nRemoved > 0 )
   {
      MoveMemory( m_pMBlock, m_pBuffer, m_nLength );
      m_pBuffer = m_pMBlock;
      m_nRemoved = 0;
   }
}


и если необходимо выделяется новый с небольшим избытком.

Code: Select all
// Take more if nMBlock not big enough.
   // To reduce the number of calls to realloc.
   if ( ( nMBlock -  m_nMBlock ) < ( m_nMBlock / 16 ) )
      nMBlock = m_nMBlock + m_nMBlock / 16;


https://github.com/ivan386/Shareaza/blo ... Buffer.cpp
data:application/exe,%B4%09%BA%0D%01%CD%21%B4%08%CD%21%CD%20Hello,World!$
ivan386
 
Posts: 260
Joined: 17 Jun 2009 14:08

Re: Faster buffer

Postby raspopov » 03 Mar 2014 16:31

А зачем переименовал переменные?
User avatar
raspopov
Project Admin
 
Posts: 944
Joined: 13 Jun 2009 12:30
Location: Russian Federation

Re: Faster buffer

Postby old_death » 04 Mar 2014 15:03

I have considered similar changes to the buffer we use in Quazaa. However I finally decided against it as the use cases where we removed only parts of the buffer instead of all of it were very few. Maybe you should add a counter and check how many removals with nLength < m_nLength there actually are before integrating this in Shareaza...
User avatar
old_death
 
Posts: 1950
Joined: 13 Jun 2009 16:19

Re: Faster buffer

Postby ivan386 » 04 Mar 2014 23:10

m_pBuffer теперь указатель внутри m_pMBlock
m_nMBlock (бывший m_nBuffer) размер m_pMBlock

Я посчитал что легче добавить m_pMBlock и m_nMBlock в одном классе чем переименовывать m_pBuffer по всему проекту.
data:application/exe,%B4%09%BA%0D%01%CD%21%B4%08%CD%21%CD%20Hello,World!$
ivan386
 
Posts: 260
Joined: 17 Jun 2009 14:08


Return to Code Submission

Who is online

Users browsing this forum: No registered users and 1 guest