Commit e1d37894 authored by Tom Barbette's avatar Tom Barbette

Separate LockMP and RWMP

parent 148d26aa
Pipeline #1846 passed with stage
in 11 minutes and 42 seconds
......@@ -403,6 +403,85 @@ CounterRxWMP::~CounterRxWMP()
{
}
CounterLockMP::CounterLockMP()
{
_atomic = 1;
}
CounterLockMP::~CounterLockMP()
{
}
CounterPLockMP::CounterPLockMP()
{
_atomic = 2;
}
CounterPLockMP::~CounterPLockMP()
{
}
int
CounterLockMP::initialize(ErrorHandler *errh) {
if (CounterBase::initialize(errh) != 0)
return -1;
//If not in simple mode, we only allow one writer so we can sum up the total number of threads
return 0;
}
Packet*
CounterLockMP::simple_action(Packet *p)
{
_stats->lock.acquire();
_stats->s._count++;
_stats->s._byte_count += p->length();
_stats->lock.release();
if (unlikely(!_simple))
check_handlers(CounterLockMP::count(), CounterLockMP::byte_count()); //BUG : if not atomic, then handler may be called twice
return p;
}
#if HAVE_BATCH
PacketBatch*
CounterLockMP::simple_action_batch(PacketBatch *batch)
{
if (unlikely(_batch_precise)) {
FOR_EACH_PACKET(batch, p)
CounterLockMP::simple_action(p);
return batch;
}
counter_int_type bc = 0;
FOR_EACH_PACKET(batch,p) {
bc += p->length();
}
_stats->lock.acquire();
_stats->s._count += batch->count();
_stats->s._byte_count += bc;
_stats->lock.release();
if (unlikely(!_simple))
check_handlers(CounterLockMP::count(), CounterLockMP::byte_count());
return batch;
}
#endif
void
CounterLockMP::reset()
{
acquire();
for (unsigned i = 0; i < _stats.weight(); i++) { \
_stats.get_value(i).s._count = 0;
_stats.get_value(i).s._byte_count = 0;
}
release();
CounterBase::reset();
}
CounterRWMP::CounterRWMP()
{
_atomic = 1;
......@@ -435,10 +514,10 @@ CounterRWMP::initialize(ErrorHandler *errh) {
Packet*
CounterRWMP::simple_action(Packet *p)
{
_stats->lock.acquire();
_stats->lock.write_begin();
_stats->s._count++;
_stats->s._byte_count += p->length();
_stats->lock.release();
_stats->lock.write_end();
if (unlikely(!_simple))
check_handlers(CounterRWMP::count(), CounterRWMP::byte_count()); //BUG : if not atomic, then handler may be called twice
return p;
......@@ -459,10 +538,10 @@ CounterRWMP::simple_action_batch(PacketBatch *batch)
bc += p->length();
}
_stats->lock.acquire();
_stats->lock.write_begin();
_stats->s._count += batch->count();
_stats->s._byte_count += bc;
_stats->lock.release();
_stats->lock.write_end();
if (unlikely(!_simple))
check_handlers(CounterRWMP::count(), CounterRWMP::byte_count());
......@@ -473,12 +552,12 @@ CounterRWMP::simple_action_batch(PacketBatch *batch)
void
CounterRWMP::reset()
{
acquire();
acquire_write();
for (unsigned i = 0; i < _stats.weight(); i++) { \
_stats.get_value(i).s._count = 0;
_stats.get_value(i).s._byte_count = 0;
}
release();
release_write();
CounterBase::reset();
}
......@@ -834,11 +913,14 @@ EXPORT_ELEMENT(CounterMP)
ELEMENT_MT_SAFE(CounterMP)
EXPORT_ELEMENT(CounterRxWMP)
ELEMENT_MT_SAFE(CounterRxWMP)
EXPORT_ELEMENT(CounterLockMP)
ELEMENT_MT_SAFE(CounterLockMP)
EXPORT_ELEMENT(CounterPLockMP)
ELEMENT_MT_SAFE(CounterPLockMP)
EXPORT_ELEMENT(CounterRWMP)
ELEMENT_MT_SAFE(CounterRWMP)
EXPORT_ELEMENT(CounterPRWMP)
ELEMENT_MT_SAFE(CounterPRWMP)
EXPORT_ELEMENT(CounterRW)
ELEMENT_MT_SAFE(CounterRW)
EXPORT_ELEMENT(CounterPRW)
......
......@@ -343,12 +343,12 @@ class CounterRxWMP : public CounterMP { public:
const char *port_count() const { return PORTS_1_1; }
};
class CounterRWMP : public CounterBase { public:
class CounterLockMP : public CounterBase { public:
CounterRWMP() CLICK_COLD;
~CounterRWMP() CLICK_COLD;
CounterLockMP() CLICK_COLD;
~CounterLockMP() CLICK_COLD;
const char *class_name() const { return "CounterRWMP"; }
const char *class_name() const { return "CounterLockMP"; }
const char *processing() const { return AGNOSTIC; }
const char *port_count() const { return PORTS_1_1; }
......@@ -387,12 +387,14 @@ class CounterRWMP : public CounterBase { public:
inline void acquire() {
loop:
for (unsigned i = 0; i < _stats.weight(); i++) {
if (!_stats.get_value(i).lock.attempt()) {
/* if (!_stats.get_value(i).lock.attempt()) {
for (unsigned j = 0; j < i; j++) {
_stats.get_value(j).lock.release();
}
goto loop;
}
}*/
_stats.get_value(i).lock.acquire();
}
}
......@@ -446,6 +448,131 @@ protected:
};
class CounterPLockMP : public CounterLockMP { public:
CounterPLockMP() CLICK_COLD;
~CounterPLockMP() CLICK_COLD;
const char *class_name() const { return "CounterPLockMP"; }
const char *processing() const { return AGNOSTIC; }
const char *port_count() const { return PORTS_1_1; }
};
class CounterRWMP : public CounterBase { public:
CounterRWMP() CLICK_COLD;
~CounterRWMP() CLICK_COLD;
const char *class_name() const { return "CounterRWMP"; }
const char *processing() const { return AGNOSTIC; }
const char *port_count() const { return PORTS_1_1; }
int initialize(ErrorHandler *) CLICK_COLD;
int can_atomic() { return 2; } CLICK_COLD;
Packet *simple_action(Packet *);
#if HAVE_BATCH
PacketBatch *simple_action_batch(PacketBatch* batch);
#endif
void reset();
counter_int_type count() override {
PER_THREAD_MEMBER_SUM(counter_int_type,sum,_stats,s._count);
return sum;
}
counter_int_type byte_count() override {
PER_THREAD_MEMBER_SUM(counter_int_type,sum,_stats,s._byte_count);
return sum;
}
stats read() {
counter_int_type count = 0;
counter_int_type byte_count = 0;
for (unsigned i = 0; i < _stats.weight(); i++) { \
count += _stats.get_value(i).s._count;
byte_count += _stats.get_value(i).s._byte_count;
}
return {count,byte_count};
}
inline void acquire_read() {
loop:
for (unsigned i = 0; i < _stats.weight(); i++) {
_stats.get_value(i).lock.read_begin();
}
}
inline void release_read() {
for (unsigned i = 0; i < _stats.weight(); i++)
_stats.get_value(i).lock.read_end();
}
inline void acquire_write() {
loop:
for (unsigned i = 0; i < _stats.weight(); i++) {
/* if (!_stats.get_value(i).lock.write_attempt()) {
for (unsigned j = 0; j < i; j++) {
_stats.get_value(j).lock.write_release();
}
goto loop;
}*/
_stats.get_value(i).lock.write_begin();
}
}
inline void release_write() {
for (unsigned i = 0; i < _stats.weight(); i++)
_stats.get_value(i).lock.write_end();
}
stats atomic_read() {
counter_int_type count = 0;
counter_int_type byte_count = 0;
if (_atomic == 2) {
acquire_read();
for (unsigned i = 0; i < _stats.weight(); i++) {
count += _stats.get_value(i).s._count;
byte_count += _stats.get_value(i).s._byte_count;
}
release_read();
} else {
for (unsigned i = 0; i < _stats.weight(); i++) {
_stats.get_value(i).lock.read_begin();
count += _stats.get_value(i).s._count;
byte_count += _stats.get_value(i).s._byte_count;
_stats.get_value(i).lock.read_end();
}
}
return {count,byte_count};
}
void add(stats s) override {
_stats->s._count += s._count;
_stats->s._byte_count += s._byte_count;
}
void atomic_add(stats s) override {
_stats->lock.write_begin();
_stats->s._count += s._count;
_stats->s._byte_count += s._byte_count;
_stats->lock.write_end();
}
protected:
class bucket { public:
bucket() : s(), lock() {
}
stats s;
RWLock lock;
};
per_thread<bucket> _stats CLICK_CACHE_ALIGN;
};
class CounterPRWMP : public CounterRWMP { public:
CounterPRWMP() CLICK_COLD;
......@@ -456,6 +583,7 @@ class CounterPRWMP : public CounterRWMP { public:
const char *port_count() const { return PORTS_1_1; }
};
/*
class CounterRCUMP : public CounterBase { public:
......
......@@ -541,13 +541,8 @@ private:
* Carefull : calling write_begin while read is held or vice versa will end up in deadlock
*/
template <class V>
class __rwlock { public:
__rwlock() : _v(){
_refcnt = 0;
}
__rwlock(V v) : _v(v) {
class RWLock { public:
RWLock() {
_refcnt = 0;
}
......@@ -571,6 +566,10 @@ class __rwlock { public:
while (_refcnt.compare_swap(0,-1) != 0) click_relax_fence();
}
inline bool write_attempt() {
return (_refcnt.compare_swap(0,-1) == 0);
}
/**
* Grab a second write reference on an already held write
* @pre refcnt < 0
......@@ -601,12 +600,26 @@ class __rwlock { public:
* TLDR : if false, you have loosed your read lock and neither
* acquired the write
*/
bool read_to_write() CLICK_WARN_UNUSED_RESULT;
inline bool read_to_write() CLICK_WARN_UNUSED_RESULT;
uint32_t refcnt() {
inline uint32_t refcnt() {
return _refcnt;
}
private:
atomic_uint32_t _refcnt;
};
template <class V>
class __rwlock : public RWLock { public:
__rwlock() : _v(){
}
__rwlock(V v) : _v(v) {
}
V _v;
V* operator->() {
......@@ -616,9 +629,6 @@ class __rwlock { public:
V& operator*() {
return _v;
}
private:
atomic_uint32_t _refcnt;
};
/**
......@@ -897,8 +907,8 @@ private:
__rwlock<V> _v;
};
template <typename V>
bool __rwlock<V>::read_to_write() {
inline bool
RWLock::read_to_write() {
/* Sadly, read_to_write is more complex than write_to_read,
* because
* two readers could want to become writer at the same time,
......
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