inline operator TestType() const { return this->first; }
};
+template<typename Container>
+ void
+ do_loop()
+ {
+ Container obj;
+ int test_iterations = 0;
+ value_type<test_type> test_value;
+ while (test_iterations < iterations)
+ {
+ for (int j = 0; j < insert_values; ++j)
+ obj.insert(obj.end(), ++test_value);
+ ++test_iterations;
+ }
+ }
+
template<typename Container>
void*
- do_loop(void* p = NULL)
+ do_test(void* p = NULL)
{
- Container obj;
try
{
- int test_iterations = 0;
- value_type<test_type> test_value;
- while (test_iterations < iterations)
- {
- for (int j = 0; j < insert_values; ++j)
- obj.insert(obj.end(), ++test_value);
- ++test_iterations;
- }
- // NB: Don't use clear() here, instead force deallocation.
- obj = Container();
- test_iterations = 0;
- test_value = value_type<test_type>();
- while (test_iterations < iterations)
- {
- for (int j = 0; j < insert_values; ++j)
- obj.insert(obj.end(), ++test_value);
- ++test_iterations;
- }
+ do_loop<Container>();
+ do_loop<Container>();
}
catch(...)
{
- // No point allocating all available memory, repeatedly.
+ // No point allocating all available memory, repeatedly.
}
}
start_counters(time, resource);
pthread_t t1, t2, t3, t4;
- pthread_create(&t1, 0, &do_loop<Container>, 0);
- pthread_create(&t2, 0, &do_loop<Container>, 0);
- pthread_create(&t3, 0, &do_loop<Container>, 0);
- pthread_create(&t4, 0, &do_loop<Container>, 0);
+ pthread_create(&t1, 0, &do_test<Container>, 0);
+ pthread_create(&t2, 0, &do_test<Container>, 0);
+ pthread_create(&t3, 0, &do_test<Container>, 0);
+ pthread_create(&t4, 0, &do_test<Container>, 0);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
--- /dev/null
+// Copyright (C) 2004 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+/*
+ * The goal with this application is to compare the performance of
+ * different allocators in a simple producer-consumer scenario.
+ */
+
+// 2004-02-04 Felix Yen <fwy@alumni.brown.edu>
+
+#include <vector>
+#include <list>
+#include <map>
+#include <typeinfo>
+#include <sstream>
+#include <pthread.h>
+#include <ext/mt_allocator.h>
+#include <ext/new_allocator.h>
+#include <ext/malloc_allocator.h>
+#include <cxxabi.h>
+#include <testsuite_performance.h>
+
+
+using namespace std;
+using __gnu_cxx::__mt_alloc;
+using __gnu_cxx::new_allocator;
+using __gnu_cxx::malloc_allocator;
+using abi::__cxa_demangle;
+
+typedef int test_type;
+typedef less<test_type> compare_type;
+typedef malloc_allocator<test_type> malloc_alloc_type;
+typedef new_allocator<test_type> new_alloc_type;
+typedef __mt_alloc<test_type> so_alloc_type;
+
+// The number of iterations to be performed.
+int iterations = 25000;
+
+// TODO - restore Stefan's comment? i don't understand it. -- fwy
+int insert_values = 128;
+
+class Lock
+{
+public:
+ Lock() {pthread_mutex_init(&mutex, 0);}
+ ~Lock() {pthread_mutex_destroy(&mutex);}
+
+public:
+ inline pthread_mutex_t* operator&() {return &mutex;}
+
+public:
+ inline void lock() {pthread_mutex_lock(&mutex);}
+ inline void unlock() {pthread_mutex_unlock(&mutex);}
+
+private:
+ Lock(const Lock&);
+ Lock& operator=(Lock&);
+
+private:
+ pthread_mutex_t mutex;
+};
+
+class AutoLock
+{
+public:
+ AutoLock(Lock& _lock)
+ : lock(_lock)
+ {lock.lock();}
+
+ ~AutoLock() {lock.unlock();}
+
+private:
+ AutoLock(AutoLock&);
+ AutoLock& operator=(AutoLock&);
+
+private:
+ Lock& lock;
+};
+
+template<typename Container>
+ class Queue
+ {
+ public:
+ Queue() {pthread_cond_init(&condition, 0);}
+ ~Queue() {pthread_cond_destroy(&condition);}
+
+ public:
+ void push_back(const typename Container::value_type& x);
+ void swap(Container& container);
+
+ private:
+ pthread_cond_t condition;
+ Lock lock;
+ Container queue;
+ };
+
+template<typename Container>
+ void
+ Queue<Container>::push_back(const typename Container::value_type& value)
+ {
+ AutoLock auto_lock(lock);
+ queue.insert(queue.end(), value);
+ if (queue.size() == 1) pthread_cond_signal(&condition);
+ }
+
+template<typename Container>
+ void
+ Queue<Container>::swap(Container& container)
+ {
+ AutoLock auto_lock(lock);
+ while (queue.empty()) pthread_cond_wait(&condition, &lock);
+ queue.swap(container);
+ }
+
+class Thread
+{
+ // NB: Make this the last data member of an object defining operator()().
+public:
+ class Attributes
+ {
+ public:
+ Attributes(int state = PTHREAD_CREATE_JOINABLE);
+ ~Attributes() {pthread_attr_destroy(&attributes);}
+
+ public:
+ inline pthread_attr_t* operator&() {return &attributes;}
+
+ private:
+ pthread_attr_t attributes;
+ };
+
+public:
+ Thread() {thread = pthread_self();}
+ ~Thread();
+
+public:
+ template <typename ThreadOwner>
+ void create(ThreadOwner* owner);
+
+private:
+ pthread_t thread;
+};
+
+Thread::Attributes::Attributes(int state)
+{
+ pthread_attr_init(&attributes);
+ pthread_attr_setdetachstate(&attributes, state);
+}
+
+Thread::~Thread()
+{
+ if (!pthread_equal(thread, pthread_self()))
+ pthread_join(thread, 0);
+}
+
+template<typename ThreadOwner>
+ void*
+ create_thread(void* _this)
+ {
+ ThreadOwner* owner = static_cast<ThreadOwner*>(_this);
+ (*owner)();
+ return 0;
+ }
+
+template<typename ThreadOwner>
+ void
+ Thread::create(ThreadOwner* owner)
+ {
+ Thread::Attributes attributes;
+ pthread_create(&thread, &attributes, create_thread<ThreadOwner>, owner);
+ }
+
+template<typename Container>
+ class Consumer
+ {
+ public:
+ Consumer(Queue<Container>& _queue)
+ : queue(_queue)
+ {thread.create(this);}
+
+ public:
+ void operator()();
+
+ private:
+ Queue<Container>& queue;
+ Thread thread;
+ };
+
+template<typename Container>
+ void
+ Consumer<Container>::operator()()
+ {
+ for (int j = insert_values * iterations; j > 0;)
+ {
+ Container container;
+ queue.swap(container);
+ j -= container.size();
+ }
+ }
+
+template<typename TestType>
+ struct Value : public pair<TestType, TestType>
+ {
+ Value()
+ : pair<TestType, TestType>(0, 0)
+ { }
+
+ inline Value operator++() {return ++this->first, *this;}
+ inline operator TestType() const {return this->first;}
+ };
+
+template<typename Container>
+ class ProducerConsumer : private Queue<Container>
+ {
+ public:
+ ProducerConsumer() {thread.create(this);}
+
+ public:
+ void operator()();
+
+ private:
+ Thread thread;
+ };
+
+template<typename Container>
+ void
+ ProducerConsumer<Container>::operator()()
+ {
+ Consumer<Container> consumer(*this);
+ Value<test_type> test_value;
+ for (int j = insert_values * iterations; j-- > 0;)
+ this->push_back(++test_value);
+ }
+
+template<typename Container>
+ void
+ test_container(Container obj)
+ {
+ using namespace __gnu_test;
+ int status;
+
+ time_counter time;
+ resource_counter resource;
+
+ clear_counters(time, resource);
+ start_counters(time, resource);
+ {
+ ProducerConsumer<Container> pc1;
+ ProducerConsumer<Container> pc2;
+ }
+ stop_counters(time, resource);
+
+ std::ostringstream comment;
+ comment << "iterations: " << iterations << '\t';
+ comment << "type: " << __cxa_demangle(typeid(obj).name(), 0, 0, &status);
+ report_header(__FILE__, comment.str());
+ report_performance(__FILE__, string(), time, resource);
+ }
+
+int main(void)
+{
+#ifdef TEST_T1
+ test_container(vector<test_type, malloc_alloc_type>());
+#endif
+#ifdef TEST_T2
+ test_container(vector<test_type, new_alloc_type>());
+#endif
+#ifdef TEST_T3
+ test_container(vector<test_type, so_alloc_type>());
+#endif
+
+#ifdef TEST_T5
+ test_container(list<test_type, malloc_alloc_type>());
+#endif
+#ifdef TEST_T6
+ test_container(list<test_type, new_alloc_type>());
+#endif
+#ifdef TEST_T7
+ test_container(list<test_type, so_alloc_type>());
+#endif
+
+#ifdef TEST_T9
+ test_container(map<test_type, test_type, compare_type, malloc_alloc_type>());
+#endif
+#ifdef TEST_T10
+ test_container(map<test_type, test_type, compare_type, new_alloc_type>());
+#endif
+#ifdef TEST_T11
+ test_container(map<test_type, test_type, compare_type, so_alloc_type>());
+#endif
+
+ return 0;
+}
+