Commit 9292a289 authored by neverlord's avatar neverlord

queue testing

parent 676601f6
......@@ -3,8 +3,8 @@
CXX = /opt/local/bin/g++-mp-4.5
#CXX = /opt/local/bin/g++-mp-4.6
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0
LIBS =
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0 -I/opt/local/include/
LIBS = -L/opt/local/lib -lboost_thread-mt
INCLUDES = -I./
HEADERS = cppa/actor.hpp \
cppa/any_type.hpp \
......@@ -62,6 +62,7 @@ SOURCES = src/decorated_tuple.cpp \
src/test__a_matches_b.cpp \
src/test__atom.cpp \
src/test__intrusive_ptr.cpp \
src/test__queue_performance.cpp \
src/test__serialization.cpp \
src/test__spawn.cpp \
src/test__tuple.cpp \
......
Homepage: http://libcppa.blogspot.com/
This project is in a very early / experimental stage.
It makes use of variadic templates, type inference and other features not included in the current language specification for C++.
......
......@@ -77,3 +77,4 @@ src/untyped_tuple.cpp
cppa/util/abstract_type_list.hpp
cppa/detail/serialize_tuple.hpp
src/test__atom.cpp
src/test__queue_performance.cpp
/Users/neverlord/libcppa
/opt/local/include/gcc45/c++
......@@ -23,7 +23,7 @@ class ref_counted_impl
inline bool deref() { return (--m_rc > 0); }
inline bool unique() { return (m_rc == 0); }
inline bool unique() { return (m_rc == 1); }
};
......
......@@ -16,6 +16,8 @@ struct cppa_test_scope \
} cppa_ts; \
std::size_t& error_count = cppa_ts.error_count
#define CPPA_TEST_RESULT cppa_ts.error_count
#define CPPA_CHECK(line_of_code) \
if (!(line_of_code)) \
{ \
......@@ -32,12 +34,14 @@ if ((line_of_code) != expected) \
++error_count; \
} ((void) 0)
void test__type_list();
void test__a_matches_b();
void test__atom();
void test__tuple();
void test__spawn();
void test__intrusive_ptr();
void test__serialization();
std::size_t test__type_list();
std::size_t test__a_matches_b();
std::size_t test__atom();
std::size_t test__tuple();
std::size_t test__spawn();
std::size_t test__intrusive_ptr();
std::size_t test__serialization();
void test__queue_performance();
#endif // TEST_HPP
#ifndef EVAL_TYPE_LISTS_HPP
#define EVAL_TYPE_LISTS_HPP
#include <type_traits>
#include "cppa/util/type_list.hpp"
#include "cppa/util/concat_type_lists.hpp"
......@@ -13,14 +15,18 @@ template <class ListA, class ListB,
template <typename, typename> class What>
struct eval_type_lists
{
typedef typename ListA::head_type head_type_a;
typedef typename ListA::tail_type tail_type_a;
typedef typename ListB::head_type head_type_b;
typedef typename ListB::tail_type tail_type_b;
static const bool value =
What<head_type_a, head_type_b>::value
!std::is_same<head_type_a, void_type>::value
&& !std::is_same<head_type_b, void_type>::value
&& What<head_type_a, head_type_b>::value
&& eval_type_lists<tail_type_a, tail_type_b, What>::value;
};
template <template <typename, typename> class What>
......
#include <map>
#include <atomic>
#include <string>
#include <limits>
#include <cassert>
......@@ -18,19 +19,31 @@
#define RUN_TEST(fun_name) \
std::cout << "run " << #fun_name << " ..." << std::endl; \
fun_name (); \
errors += fun_name (); \
std::cout << std::endl
using std::cout;
using std::endl;
typedef std::map<std::string, std::pair<std::string, std::string>> str3_map;
int main()
{
std::cout << std::boolalpha;
/*
std::atomic<std::int32_t> a(42);
std::int32_t b, c;
b = 42;
c = 10;
cout << "a.compare_exchange_weak(b, c, std::memory_order_acquire) = "
<< a.compare_exchange_weak(b, c, std::memory_order_acquire) << endl;
cout << "a = " << a << endl;
*/
std::size_t errors = 0;
RUN_TEST(test__a_matches_b);
RUN_TEST(test__intrusive_ptr);
RUN_TEST(test__spawn);
......@@ -39,6 +52,13 @@ int main()
RUN_TEST(test__serialization);
RUN_TEST(test__atom);
cout << endl
<< "error(s) in all tests: " << errors
<< endl;
cout << endl << "run queue performance test ... " << endl;
test__queue_performance();
return 0;
}
......@@ -7,7 +7,7 @@
using namespace cppa;
using namespace cppa::util;
void test__a_matches_b()
std::size_t test__a_matches_b()
{
CPPA_TEST(test__a_matches_b);
......@@ -37,4 +37,7 @@ void test__a_matches_b()
CPPA_CHECK((a_matches_b<type_list<any_type*, float>,
type_list<int, int, float>>::value));
return CPPA_TEST_RESULT;
}
......@@ -107,7 +107,8 @@ class atom_base
{
}
atom_base(atom_base&& rval) : m_str(std::move(rval.m_str)), m_hash(hash_of(m_str))
atom_base(atom_base&& rval)
: m_str(std::move(rval.m_str)), m_hash(hash_of(m_str))
{
}
......@@ -163,7 +164,7 @@ class atom : public atom_base
};
void test__atom()
std::size_t test__atom()
{
CPPA_TEST(test__atom);
......@@ -179,4 +180,6 @@ void test__atom()
// CPPA_CHECK(a1 == a3);
return CPPA_TEST_RESULT;
}
#include <list>
#include <cstddef>
#include "cppa/test.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/detail/ref_counted_impl.hpp"
using namespace cppa;
namespace { int rc_instances = 0; }
class test_rc
struct test_rc : public cppa::detail::ref_counted_impl<std::size_t>
{
std::size_t m_rc;
public:
test_rc() : m_rc(0) { ++rc_instances; }
void ref() { ++m_rc; }
bool deref() { return --m_rc > 0; }
std::size_t rc() const { return m_rc; }
test_rc() { ++rc_instances; }
virtual ~test_rc() { --rc_instances; }
......@@ -40,7 +33,7 @@ test_ptr get_test_ptr()
return get_test_rc();
}
void test__intrusive_ptr()
std::size_t test__intrusive_ptr()
{
CPPA_TEST(test__intrusive_ptr);
......@@ -48,7 +41,7 @@ void test__intrusive_ptr()
{
test_ptr p(new test_rc);
CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p->rc(), 1);
CPPA_CHECK(p->unique());
}
CPPA_CHECK_EQUAL(rc_instances, 0);
......@@ -56,7 +49,7 @@ void test__intrusive_ptr()
test_ptr p;
p = new test_rc;
CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p->rc(), 1);
CPPA_CHECK(p->unique());
}
CPPA_CHECK_EQUAL(rc_instances, 0);
......@@ -65,7 +58,7 @@ void test__intrusive_ptr()
p1 = get_test_rc();
test_ptr p2 = p1;
CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p1->rc(), 2);
CPPA_CHECK_EQUAL(p1->unique(), false);
}
CPPA_CHECK_EQUAL(rc_instances, 0);
......@@ -74,9 +67,11 @@ void test__intrusive_ptr()
pl.push_back(get_test_ptr());
pl.push_back(get_test_rc());
pl.push_back(pl.front()->create());
CPPA_CHECK_EQUAL(pl.front()->rc(), 1);
CPPA_CHECK(pl.front()->unique());
CPPA_CHECK_EQUAL(rc_instances, 3);
}
CPPA_CHECK_EQUAL(rc_instances, 0);
return CPPA_TEST_RESULT;
}
#include <list>
#include <atomic>
#include <iostream>
#include "cppa/test.hpp"
#include <boost/ref.hpp>
#include <boost/thread.hpp>
#include <boost/progress.hpp>
using std::cout;
using std::cerr;
using std::endl;
struct queue_element
{
queue_element* next;
std::size_t value;
queue_element(std::size_t val) : next(0), value(val) { }
};
/**
* @brief An intrusive, thread safe queue implementation.
*/
template<typename T>
class single_reader_queue
{
typedef boost::unique_lock<boost::mutex> lock_type;
public:
typedef T element_type;
element_type* pop()
{
wait_for_data();
element_type* result = take_head();
return result;
}
element_type* try_pop()
{
return take_head();
}
/*
element_type* front()
{
return (m_head || fetch_new_data()) ? m_head : 0;
}
*/
void push(element_type* new_element)
{
element_type* e = m_tail.load();
for (;;)
{
// element_type* e = const_cast<element_type*>(m_tail);
new_element->next = e;
if (!e)
{
lock_type guard(m_mtx);
// if (atomic_cas(&m_tail, (element_type*) 0, new_element))
if (m_tail.compare_exchange_weak(e, new_element))
{
m_cv.notify_one();
return;
}
}
else
{
// if (atomic_cas(&m_tail, e, new_element))
if (m_tail.compare_exchange_weak(e, new_element))
{
return;
}
}
}
}
single_reader_queue() : m_tail(0), m_head(0) { }
private:
// exposed to "outside" access
atomic<element_type*> m_tail;
// volatile element_type* m_tail;
// accessed only by the owner
element_type* m_head;
// locked on enqueue/dequeue operations to/from an empty list
boost::mutex m_mtx;
boost::condition_variable m_cv;
void wait_for_data()
{
if (!m_head && !(m_tail.load()))
{
lock_type guard(m_mtx);
while (!(m_tail.load())) m_cv.wait(guard);
}
}
// atomically set public_tail to nullptr and enqueue all
bool fetch_new_data()
{
element_type* e = m_tail.load();
while (e)
{
if (m_tail.compare_exchange_weak(e, 0))
// if (atomic_cas(&m_tail, e, (element_type*) 0))
{
// public_tail (e) has LIFO order,
// but private_head requires FIFO order
while (e)
{
// next iteration element
element_type* next = e->next;
// enqueue e to private_head
e->next = m_head;
m_head = e;
// next iteration
e = next;
}
return true;
}
// next iteration
// e = const_cast<element_type*>(m_tail);
}
// !public_tail
return false;
}
element_type* take_head()
{
if (m_head || fetch_new_data())
{
element_type* result = m_head;
m_head = result->next;
return result;
}
return 0;
}
};
template<typename T>
class locked_queue
{
typedef boost::unique_lock<boost::mutex> lock_type;
public:
typedef T element_type;
element_type* pop()
{
lock_type guard(m_mtx);
element_type* result;
while (m_impl.empty())
{
m_cv.wait(guard);
}
result = m_impl.front();
m_impl.pop_front();
return result;
}
void push(element_type* new_element)
{
lock_type guard(m_mtx);
if (m_impl.empty())
{
m_cv.notify_one();
}
m_impl.push_back(new_element);
}
private:
boost::mutex m_mtx;
boost::condition_variable m_cv;
std::list<element_type*> m_impl;
};
namespace {
//const std::size_t num_slaves = 1000;
//const std::size_t num_slave_msgs = 90000;
// 900 000
//const std::size_t num_msgs = (num_slaves) * (num_slave_msgs);
// uint32::max = 4 294 967 296
// (n (n+1)) / 2 = 4 050 045 000
//const std::size_t calc_result = ((num_msgs)*(num_msgs + 1)) / 2;
} // namespace <anonymous>
template<typename Queue>
void slave(Queue& q, std::size_t from, std::size_t to)
{
for (std::size_t x = from; x < to; ++x)
{
q.push(new queue_element(x));
}
}
template<typename Queue, std::size_t num_slaves, std::size_t num_slave_msgs>
void master(Queue& q)
{
static const std::size_t num_msgs = (num_slaves) * (num_slave_msgs);
static const std::size_t calc_result = ((num_msgs)*(num_msgs + 1)) / 2;
boost::timer t0;
for (std::size_t i = 0; i < num_slaves; ++i)
{
std::size_t from = (i * num_slave_msgs) + 1;
std::size_t to = from + num_slave_msgs;
boost::thread(slave<Queue>, boost::ref(q), from, to).detach();
}
std::size_t result = 0;
std::size_t min_val = calc_result;
std::size_t max_val = 0;
for (std::size_t i = 0; i < num_msgs; ++i)
{
queue_element* e = q.pop();
result += e->value;
min_val = std::min(min_val, e->value);
max_val = std::max(max_val, e->value);
delete e;
}
if (result != calc_result)
{
cerr << "ERROR: result = " << result
<< " (should be: " << calc_result << ")" << endl
<< "min: " << min_val << endl
<< "max: " << max_val << endl;
}
cout << t0.elapsed() << " " << num_msgs << endl;
}
template<typename Queue>
void test_q_impl()
{
typedef Queue queue_type;
{
queue_type q0;
boost::thread t0(master<queue_type, 10, 10000>, boost::ref(q0));
t0.join();
}
{
queue_type q0;
boost::thread t0(master<queue_type, 100, 10000>, boost::ref(q0));
t0.join();
}
{
queue_type q0;
boost::thread t0(master<queue_type, 1000, 10000>, boost::ref(q0));
t0.join();
}
{
queue_type q0;
boost::thread t0(master<queue_type, 10000, 10000>, boost::ref(q0));
t0.join();
}
}
void test__queue_performance()
{
cout << "single_reader_queue:" << endl;
test_q_impl<single_reader_queue<queue_element>>();
cout << endl << "locked_queue:" << endl;
test_q_impl<locked_queue<queue_element>>();
}
......@@ -395,7 +395,7 @@ deserializer& operator>>(deserializer& d, untyped_tuple& ut)
return d;
}
void test__serialization()
std::size_t test__serialization()
{
CPPA_TEST(test__serialization);
......@@ -549,4 +549,6 @@ void test__serialization()
}
}
return CPPA_TEST_RESULT;
}
......@@ -10,7 +10,7 @@ actor spawn(F)
return actor();
}
void test__spawn()
std::size_t test__spawn()
{
CPPA_TEST(test__spawn);
......@@ -25,4 +25,6 @@ void test__spawn()
CPPA_CHECK(true);
return CPPA_TEST_RESULT;
}
......@@ -38,7 +38,7 @@ void fun(const std::string&)
} // namespace <anonymous>
void test__tuple()
std::size_t test__tuple()
{
CPPA_TEST(test__tuple);
......@@ -216,4 +216,6 @@ void test__tuple()
CPPA_CHECK(t1_copy.get<3>() == t1.get<3>());
CPPA_CHECK(t1 == t4);
return CPPA_TEST_RESULT;
}
......@@ -18,7 +18,7 @@ struct apply
typedef typename What<T>::type type;
};
void test__type_list()
std::size_t test__type_list()
{
CPPA_TEST(test__type_list);
......@@ -45,4 +45,6 @@ void test__type_list()
CPPA_CHECK((is_same<int, l2::head_type>::value));
CPPA_CHECK((is_same<l1, l2::tail_type>::value));
return CPPA_TEST_RESULT;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment