Commit 9292a289 authored by neverlord's avatar neverlord

queue testing

parent 676601f6
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
CXX = /opt/local/bin/g++-mp-4.5 CXX = /opt/local/bin/g++-mp-4.5
#CXX = /opt/local/bin/g++-mp-4.6 #CXX = /opt/local/bin/g++-mp-4.6
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0 CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0 -I/opt/local/include/
LIBS = LIBS = -L/opt/local/lib -lboost_thread-mt
INCLUDES = -I./ INCLUDES = -I./
HEADERS = cppa/actor.hpp \ HEADERS = cppa/actor.hpp \
cppa/any_type.hpp \ cppa/any_type.hpp \
...@@ -62,6 +62,7 @@ SOURCES = src/decorated_tuple.cpp \ ...@@ -62,6 +62,7 @@ SOURCES = src/decorated_tuple.cpp \
src/test__a_matches_b.cpp \ src/test__a_matches_b.cpp \
src/test__atom.cpp \ src/test__atom.cpp \
src/test__intrusive_ptr.cpp \ src/test__intrusive_ptr.cpp \
src/test__queue_performance.cpp \
src/test__serialization.cpp \ src/test__serialization.cpp \
src/test__spawn.cpp \ src/test__spawn.cpp \
src/test__tuple.cpp \ src/test__tuple.cpp \
......
Homepage: http://libcppa.blogspot.com/
This project is in a very early / experimental stage. 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++. 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 ...@@ -77,3 +77,4 @@ src/untyped_tuple.cpp
cppa/util/abstract_type_list.hpp cppa/util/abstract_type_list.hpp
cppa/detail/serialize_tuple.hpp cppa/detail/serialize_tuple.hpp
src/test__atom.cpp src/test__atom.cpp
src/test__queue_performance.cpp
/Users/neverlord/libcppa /Users/neverlord/libcppa
/opt/local/include/gcc45/c++
...@@ -23,7 +23,7 @@ class ref_counted_impl ...@@ -23,7 +23,7 @@ class ref_counted_impl
inline bool deref() { return (--m_rc > 0); } 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 \ ...@@ -16,6 +16,8 @@ struct cppa_test_scope \
} cppa_ts; \ } cppa_ts; \
std::size_t& error_count = cppa_ts.error_count std::size_t& error_count = cppa_ts.error_count
#define CPPA_TEST_RESULT cppa_ts.error_count
#define CPPA_CHECK(line_of_code) \ #define CPPA_CHECK(line_of_code) \
if (!(line_of_code)) \ if (!(line_of_code)) \
{ \ { \
...@@ -32,12 +34,14 @@ if ((line_of_code) != expected) \ ...@@ -32,12 +34,14 @@ if ((line_of_code) != expected) \
++error_count; \ ++error_count; \
} ((void) 0) } ((void) 0)
void test__type_list(); std::size_t test__type_list();
void test__a_matches_b(); std::size_t test__a_matches_b();
void test__atom(); std::size_t test__atom();
void test__tuple(); std::size_t test__tuple();
void test__spawn(); std::size_t test__spawn();
void test__intrusive_ptr(); std::size_t test__intrusive_ptr();
void test__serialization(); std::size_t test__serialization();
void test__queue_performance();
#endif // TEST_HPP #endif // TEST_HPP
#ifndef EVAL_TYPE_LISTS_HPP #ifndef EVAL_TYPE_LISTS_HPP
#define EVAL_TYPE_LISTS_HPP #define EVAL_TYPE_LISTS_HPP
#include <type_traits>
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/concat_type_lists.hpp" #include "cppa/util/concat_type_lists.hpp"
...@@ -13,14 +15,18 @@ template <class ListA, class ListB, ...@@ -13,14 +15,18 @@ template <class ListA, class ListB,
template <typename, typename> class What> template <typename, typename> class What>
struct eval_type_lists struct eval_type_lists
{ {
typedef typename ListA::head_type head_type_a; typedef typename ListA::head_type head_type_a;
typedef typename ListA::tail_type tail_type_a; typedef typename ListA::tail_type tail_type_a;
typedef typename ListB::head_type head_type_b; typedef typename ListB::head_type head_type_b;
typedef typename ListB::tail_type tail_type_b; typedef typename ListB::tail_type tail_type_b;
static const bool value = 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; && eval_type_lists<tail_type_a, tail_type_b, What>::value;
}; };
template <template <typename, typename> class What> template <template <typename, typename> class What>
......
#include <map> #include <map>
#include <atomic>
#include <string> #include <string>
#include <limits> #include <limits>
#include <cassert> #include <cassert>
...@@ -18,19 +19,31 @@ ...@@ -18,19 +19,31 @@
#define RUN_TEST(fun_name) \ #define RUN_TEST(fun_name) \
std::cout << "run " << #fun_name << " ..." << std::endl; \ std::cout << "run " << #fun_name << " ..." << std::endl; \
fun_name (); \ errors += fun_name (); \
std::cout << std::endl std::cout << std::endl
using std::cout; using std::cout;
using std::endl; using std::endl;
typedef std::map<std::string, std::pair<std::string, std::string>> str3_map;
int main() int main()
{ {
std::cout << std::boolalpha; 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__a_matches_b);
RUN_TEST(test__intrusive_ptr); RUN_TEST(test__intrusive_ptr);
RUN_TEST(test__spawn); RUN_TEST(test__spawn);
...@@ -39,6 +52,13 @@ int main() ...@@ -39,6 +52,13 @@ int main()
RUN_TEST(test__serialization); RUN_TEST(test__serialization);
RUN_TEST(test__atom); 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; return 0;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
using namespace cppa; using namespace cppa;
using namespace cppa::util; using namespace cppa::util;
void test__a_matches_b() std::size_t test__a_matches_b()
{ {
CPPA_TEST(test__a_matches_b); CPPA_TEST(test__a_matches_b);
...@@ -37,4 +37,7 @@ void test__a_matches_b() ...@@ -37,4 +37,7 @@ void test__a_matches_b()
CPPA_CHECK((a_matches_b<type_list<any_type*, float>, CPPA_CHECK((a_matches_b<type_list<any_type*, float>,
type_list<int, int, float>>::value)); type_list<int, int, float>>::value));
return CPPA_TEST_RESULT;
} }
...@@ -107,7 +107,8 @@ class atom_base ...@@ -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 ...@@ -163,7 +164,7 @@ class atom : public atom_base
}; };
void test__atom() std::size_t test__atom()
{ {
CPPA_TEST(test__atom); CPPA_TEST(test__atom);
...@@ -179,4 +180,6 @@ void test__atom() ...@@ -179,4 +180,6 @@ void test__atom()
// CPPA_CHECK(a1 == a3); // CPPA_CHECK(a1 == a3);
return CPPA_TEST_RESULT;
} }
#include <list> #include <list>
#include <cstddef> #include <cstddef>
#include "cppa/test.hpp" #include "cppa/test.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/detail/ref_counted_impl.hpp"
using namespace cppa; using namespace cppa;
namespace { int rc_instances = 0; } 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; test_rc() { ++rc_instances; }
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; }
virtual ~test_rc() { --rc_instances; } virtual ~test_rc() { --rc_instances; }
...@@ -40,7 +33,7 @@ test_ptr get_test_ptr() ...@@ -40,7 +33,7 @@ test_ptr get_test_ptr()
return get_test_rc(); return get_test_rc();
} }
void test__intrusive_ptr() std::size_t test__intrusive_ptr()
{ {
CPPA_TEST(test__intrusive_ptr); CPPA_TEST(test__intrusive_ptr);
...@@ -48,7 +41,7 @@ void test__intrusive_ptr() ...@@ -48,7 +41,7 @@ void test__intrusive_ptr()
{ {
test_ptr p(new test_rc); test_ptr p(new test_rc);
CPPA_CHECK_EQUAL(rc_instances, 1); CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p->rc(), 1); CPPA_CHECK(p->unique());
} }
CPPA_CHECK_EQUAL(rc_instances, 0); CPPA_CHECK_EQUAL(rc_instances, 0);
...@@ -56,7 +49,7 @@ void test__intrusive_ptr() ...@@ -56,7 +49,7 @@ void test__intrusive_ptr()
test_ptr p; test_ptr p;
p = new test_rc; p = new test_rc;
CPPA_CHECK_EQUAL(rc_instances, 1); CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p->rc(), 1); CPPA_CHECK(p->unique());
} }
CPPA_CHECK_EQUAL(rc_instances, 0); CPPA_CHECK_EQUAL(rc_instances, 0);
...@@ -65,7 +58,7 @@ void test__intrusive_ptr() ...@@ -65,7 +58,7 @@ void test__intrusive_ptr()
p1 = get_test_rc(); p1 = get_test_rc();
test_ptr p2 = p1; test_ptr p2 = p1;
CPPA_CHECK_EQUAL(rc_instances, 1); CPPA_CHECK_EQUAL(rc_instances, 1);
CPPA_CHECK_EQUAL(p1->rc(), 2); CPPA_CHECK_EQUAL(p1->unique(), false);
} }
CPPA_CHECK_EQUAL(rc_instances, 0); CPPA_CHECK_EQUAL(rc_instances, 0);
...@@ -74,9 +67,11 @@ void test__intrusive_ptr() ...@@ -74,9 +67,11 @@ void test__intrusive_ptr()
pl.push_back(get_test_ptr()); pl.push_back(get_test_ptr());
pl.push_back(get_test_rc()); pl.push_back(get_test_rc());
pl.push_back(pl.front()->create()); 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, 3);
} }
CPPA_CHECK_EQUAL(rc_instances, 0); 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) ...@@ -395,7 +395,7 @@ deserializer& operator>>(deserializer& d, untyped_tuple& ut)
return d; return d;
} }
void test__serialization() std::size_t test__serialization()
{ {
CPPA_TEST(test__serialization); CPPA_TEST(test__serialization);
...@@ -549,4 +549,6 @@ void test__serialization() ...@@ -549,4 +549,6 @@ void test__serialization()
} }
} }
return CPPA_TEST_RESULT;
} }
...@@ -10,7 +10,7 @@ actor spawn(F) ...@@ -10,7 +10,7 @@ actor spawn(F)
return actor(); return actor();
} }
void test__spawn() std::size_t test__spawn()
{ {
CPPA_TEST(test__spawn); CPPA_TEST(test__spawn);
...@@ -25,4 +25,6 @@ void test__spawn() ...@@ -25,4 +25,6 @@ void test__spawn()
CPPA_CHECK(true); CPPA_CHECK(true);
return CPPA_TEST_RESULT;
} }
...@@ -38,7 +38,7 @@ void fun(const std::string&) ...@@ -38,7 +38,7 @@ void fun(const std::string&)
} // namespace <anonymous> } // namespace <anonymous>
void test__tuple() std::size_t test__tuple()
{ {
CPPA_TEST(test__tuple); CPPA_TEST(test__tuple);
...@@ -216,4 +216,6 @@ void test__tuple() ...@@ -216,4 +216,6 @@ void test__tuple()
CPPA_CHECK(t1_copy.get<3>() == t1.get<3>()); CPPA_CHECK(t1_copy.get<3>() == t1.get<3>());
CPPA_CHECK(t1 == t4); CPPA_CHECK(t1 == t4);
return CPPA_TEST_RESULT;
} }
...@@ -18,7 +18,7 @@ struct apply ...@@ -18,7 +18,7 @@ struct apply
typedef typename What<T>::type type; typedef typename What<T>::type type;
}; };
void test__type_list() std::size_t test__type_list()
{ {
CPPA_TEST(test__type_list); CPPA_TEST(test__type_list);
...@@ -45,4 +45,6 @@ void test__type_list() ...@@ -45,4 +45,6 @@ void test__type_list()
CPPA_CHECK((is_same<int, l2::head_type>::value)); CPPA_CHECK((is_same<int, l2::head_type>::value));
CPPA_CHECK((is_same<l1, l2::tail_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