This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Diff mt_allocator


Hi,

here's the diff that allocates chunks of memory directly to threads according to rfc.
I have tested it quite a bit (including recompiling a 10k line MT application and running that) but I appriciate all reviewing and testing - it's been a long day =)


The numbers are good! The attached test program (comp.cpp) exercises the allocator quite a bit and caused massive global locking/context switching before.
Here's the before numbers (on the dual 2.4 Ghz machine):
real 0m18.026s
user 0m12.620s
sys 0m13.480s


And this is after this diff:
real    0m4.123s
user    0m13.740s
sys     0m1.460s

One thing that I noticed when recompiling the real application was that the compiler complained about missing == and != operators. I added those (and they are part of the diff) but I have no idea if they should be here or somewhere else?

Brgds

/Stefan
272c272
<         block_record* block;
---
>         block_record* block = NULL;
283,285c283,287
<              * - Yes, lock and check if there are free blocks on the global
<              *   list (and if not add new ones), get the first one
<              *   and change owner.
---
>              * - Yes, check if there are free blocks on the global
>              *   list. If so, grab up to block_count blocks in one
>              *   lock and change ownership. If the global list is 
>              *   empty, we allocate a new chunk and add those blocks 
>              *   directly to our own freelist (with us as owner).
293a296,299
>                 size_t bin_t = 1 << bin;
>                 size_t block_count =
>                   _S_chunk_size /(bin_t + sizeof(block_record));
> 
298,299c304,308
<                     _S_bin[bin].first[0] =
<                       (block_record*)malloc(_S_chunk_size);
---
>                     /*
>                      * No need to hold the lock when we are adding a
>                      * whole chunk to our own list
>                      */
>                     __gthread_mutex_unlock(_S_bin[bin].mutex);
301,305c310,311
<                     if (!_S_bin[bin].first[0])
<                       {
<                         __gthread_mutex_unlock(_S_bin[bin].mutex);
<                         __throw_bad_alloc();
<                       }
---
>                     _S_bin[bin].first[thread_id] =
>                       (block_record*)malloc(_S_chunk_size);
307,309c313,314
<                     size_t bin_t = 1 << bin;
<                     size_t block_count =
<                       _S_chunk_size /(bin_t + sizeof(block_record));
---
>                     if (!_S_bin[bin].first[thread_id])
>                       __throw_bad_alloc();
311c316
<                     _S_bin[bin].free[0] = block_count;
---
>                     _S_bin[bin].free[thread_id] = block_count;
314c319
<                     block = _S_bin[bin].first[0];
---
>                     block = _S_bin[bin].first[thread_id];
319a325
>                         block->thread_id = thread_id;
325c331,332
<                     _S_bin[bin].last[0] = block;
---
>                     block->thread_id = thread_id;
>                     _S_bin[bin].last[thread_id] = block;
326a334,336
>                 else
>                   {
>                     size_t global_count = 0;
328c338,341
<                 block = _S_bin[bin].first[0];
---
>                     while( _S_bin[bin].first[0] != NULL &&
>                            global_count < block_count )
>                       {
>                         block = _S_bin[bin].first[0];
330,335c343,346
<                 /*
<                  * Remove from list and count down the available counter on
<                  * global pool 0.
<                  */
<                 _S_bin[bin].first[0] = _S_bin[bin].first[0]->next;
<                 _S_bin[bin].free[0]--;
---
>                         if (_S_bin[bin].first[thread_id] == NULL)
>                           _S_bin[bin].first[thread_id] = block;
>                         else
>                           _S_bin[bin].last[thread_id]->next = block;
337c348,362
<                 __gthread_mutex_unlock(_S_bin[bin].mutex);
---
>                         _S_bin[bin].last[thread_id] = block;
> 
>                         block->thread_id = thread_id;
> 
>                         _S_bin[bin].free[thread_id]++;
> 
>                         _S_bin[bin].first[0] = _S_bin[bin].first[0]->next;
> 
>                         global_count++;
>                       }
> 
>                     block->next = NULL;
> 
>                     __gthread_mutex_unlock(_S_bin[bin].mutex);
>                   }
340,342c365,366
<                  * Now that we have removed the block from the global
<                  * freelist we can change owner and update the used
<                  * counter for this thread without locking.
---
>                  * Return the first newly added block in our list and
>                  * update the counters
344c368,372
<                 block->thread_id = thread_id;
---
>                 block = _S_bin[bin].first[thread_id];
>                 _S_bin[bin].first[thread_id] = 
>                   _S_bin[bin].first[thread_id]->next;
> 
>                 _S_bin[bin].free[thread_id]--;
469d496
<                     _S_bin[bin].free[0]++;
796a824,835
> 
>   template<typename _Tp>
>     inline bool
>     operator==(const __mt_alloc<_Tp>&,
>                const __mt_alloc<_Tp>&)
>     { return true; }
>   
>   template<typename _Tp>
>     inline bool
>     operator!=(const __mt_alloc<_Tp>&,
>                const __mt_alloc<_Tp>&)
>     { return false; }
#include <ext/mt_allocator.h>
#include <pthread.h>
#include <vector>

void* Worker( void* arg )
{
  std::vector< std::vector< int, __gnu_cxx::__mt_alloc< int > >, 
               __gnu_cxx::__mt_alloc< std::vector< int, 
               __gnu_cxx::__mt_alloc< int > > > > v1;

  for( int i = 0; i < 100000; i++ )
    {
      std::vector< int, __gnu_cxx::__mt_alloc< int > > v2;

      for( int j = 0; j < 32; j++ )
        {
          v2.push_back( 1 );
        }

      v1.push_back( v2 );
    }

  return NULL;
}

int main()
{
  pthread_attr_t pthread_attr_default;
  pthread_attr_init( &pthread_attr_default );

  int nowo = 8;

  pthread_t *workers[ nowo ];
  for( int i = 0; i < nowo; i++ )
    {
      workers[ i ] = new pthread_t;
      pthread_create( workers[ i ], &pthread_attr_default, Worker, NULL );
    }

  for( int i = 0; i < nowo; i++ )
    {
      pthread_join( *workers[ i ], NULL );
    }

  return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]