This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Diff mt_allocator
- From: Stefan Olsson <stefan at xapa dot se>
- To: Benjamin Kosnik <bkoz at redhat dot com>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 22 Jan 2004 17:51:30 +0100
- Subject: 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;
}