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() ...@@ -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() CounterRWMP::CounterRWMP()
{ {
_atomic = 1; _atomic = 1;
...@@ -435,10 +514,10 @@ CounterRWMP::initialize(ErrorHandler *errh) { ...@@ -435,10 +514,10 @@ CounterRWMP::initialize(ErrorHandler *errh) {
Packet* Packet*
CounterRWMP::simple_action(Packet *p) CounterRWMP::simple_action(Packet *p)
{ {
_stats->lock.acquire(); _stats->lock.write_begin();
_stats->s._count++; _stats->s._count++;
_stats->s._byte_count += p->length(); _stats->s._byte_count += p->length();
_stats->lock.release(); _stats->lock.write_end();
if (unlikely(!_simple)) if (unlikely(!_simple))
check_handlers(CounterRWMP::count(), CounterRWMP::byte_count()); //BUG : if not atomic, then handler may be called twice check_handlers(CounterRWMP::count(), CounterRWMP::byte_count()); //BUG : if not atomic, then handler may be called twice
return p; return p;
...@@ -459,10 +538,10 @@ CounterRWMP::simple_action_batch(PacketBatch *batch) ...@@ -459,10 +538,10 @@ CounterRWMP::simple_action_batch(PacketBatch *batch)
bc += p->length(); bc += p->length();
} }
_stats->lock.acquire(); _stats->lock.write_begin();
_stats->s._count += batch->count(); _stats->s._count += batch->count();
_stats->s._byte_count += bc; _stats->s._byte_count += bc;
_stats->lock.release(); _stats->lock.write_end();
if (unlikely(!_simple)) if (unlikely(!_simple))
check_handlers(CounterRWMP::count(), CounterRWMP::byte_count()); check_handlers(CounterRWMP::count(), CounterRWMP::byte_count());
...@@ -473,12 +552,12 @@ CounterRWMP::simple_action_batch(PacketBatch *batch) ...@@ -473,12 +552,12 @@ CounterRWMP::simple_action_batch(PacketBatch *batch)
void void
CounterRWMP::reset() CounterRWMP::reset()
{ {
acquire(); acquire_write();
for (unsigned i = 0; i < _stats.weight(); i++) { \ for (unsigned i = 0; i < _stats.weight(); i++) { \
_stats.get_value(i).s._count = 0; _stats.get_value(i).s._count = 0;
_stats.get_value(i).s._byte_count = 0; _stats.get_value(i).s._byte_count = 0;
} }
release(); release_write();
CounterBase::reset(); CounterBase::reset();
} }
...@@ -834,11 +913,14 @@ EXPORT_ELEMENT(CounterMP) ...@@ -834,11 +913,14 @@ EXPORT_ELEMENT(CounterMP)
ELEMENT_MT_SAFE(CounterMP) ELEMENT_MT_SAFE(CounterMP)
EXPORT_ELEMENT(CounterRxWMP) EXPORT_ELEMENT(CounterRxWMP)
ELEMENT_MT_SAFE(CounterRxWMP) ELEMENT_MT_SAFE(CounterRxWMP)
EXPORT_ELEMENT(CounterLockMP)
ELEMENT_MT_SAFE(CounterLockMP)
EXPORT_ELEMENT(CounterPLockMP)
ELEMENT_MT_SAFE(CounterPLockMP)
EXPORT_ELEMENT(CounterRWMP) EXPORT_ELEMENT(CounterRWMP)
ELEMENT_MT_SAFE(CounterRWMP) ELEMENT_MT_SAFE(CounterRWMP)
EXPORT_ELEMENT(CounterPRWMP) EXPORT_ELEMENT(CounterPRWMP)
ELEMENT_MT_SAFE(CounterPRWMP) ELEMENT_MT_SAFE(CounterPRWMP)
EXPORT_ELEMENT(CounterRW) EXPORT_ELEMENT(CounterRW)
ELEMENT_MT_SAFE(CounterRW) ELEMENT_MT_SAFE(CounterRW)
EXPORT_ELEMENT(CounterPRW) EXPORT_ELEMENT(CounterPRW)
......
...@@ -343,12 +343,12 @@ class CounterRxWMP : public CounterMP { public: ...@@ -343,12 +343,12 @@ class CounterRxWMP : public CounterMP { public:
const char *port_count() const { return PORTS_1_1; } const char *port_count() const { return PORTS_1_1; }
}; };
class CounterRWMP : public CounterBase { public: class CounterLockMP : public CounterBase { public:
CounterRWMP() CLICK_COLD; CounterLockMP() CLICK_COLD;
~CounterRWMP() 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 *processing() const { return AGNOSTIC; }
const char *port_count() const { return PORTS_1_1; } const char *port_count() const { return PORTS_1_1; }
...@@ -387,12 +387,14 @@ class CounterRWMP : public CounterBase { public: ...@@ -387,12 +387,14 @@ class CounterRWMP : public CounterBase { public:
inline void acquire() { inline void acquire() {
loop: loop:
for (unsigned i = 0; i < _stats.weight(); i++) { 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++) { for (unsigned j = 0; j < i; j++) {
_stats.get_value(j).lock.release(); _stats.get_value(j).lock.release();
} }
goto loop; goto loop;
} }*/
_stats.get_value(i).lock.acquire();
} }
} }
...@@ -446,6 +448,131 @@ protected: ...@@ -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: class CounterPRWMP : public CounterRWMP { public:
CounterPRWMP() CLICK_COLD; CounterPRWMP() CLICK_COLD;
...@@ -456,6 +583,7 @@ class CounterPRWMP : public CounterRWMP { public: ...@@ -456,6 +583,7 @@ class CounterPRWMP : public CounterRWMP { public:
const char *port_count() const { return PORTS_1_1; } const char *port_count() const { return PORTS_1_1; }
}; };
/* /*
class CounterRCUMP : public CounterBase { public: class CounterRCUMP : public CounterBase { public:
......
...@@ -541,13 +541,8 @@ private: ...@@ -541,13 +541,8 @@ private:
* Carefull : calling write_begin while read is held or vice versa will end up in deadlock * Carefull : calling write_begin while read is held or vice versa will end up in deadlock
*/ */
template <class V> class RWLock { public:
class __rwlock { public: RWLock() {
__rwlock() : _v(){
_refcnt = 0;
}
__rwlock(V v) : _v(v) {
_refcnt = 0; _refcnt = 0;
} }
...@@ -571,6 +566,10 @@ class __rwlock { public: ...@@ -571,6 +566,10 @@ class __rwlock { public:
while (_refcnt.compare_swap(0,-1) != 0) click_relax_fence(); 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 * Grab a second write reference on an already held write
* @pre refcnt < 0 * @pre refcnt < 0
...@@ -601,12 +600,26 @@ class __rwlock { public: ...@@ -601,12 +600,26 @@ class __rwlock { public:
* TLDR : if false, you have loosed your read lock and neither * TLDR : if false, you have loosed your read lock and neither
* acquired the write * 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; 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 _v;
V* operator->() { V* operator->() {
...@@ -616,9 +629,6 @@ class __rwlock { public: ...@@ -616,9 +629,6 @@ class __rwlock { public:
V& operator*() { V& operator*() {
return _v; return _v;
} }
private:
atomic_uint32_t _refcnt;
}; };
/** /**
...@@ -897,8 +907,8 @@ private: ...@@ -897,8 +907,8 @@ private:
__rwlock<V> _v; __rwlock<V> _v;
}; };
template <typename V> inline bool
bool __rwlock<V>::read_to_write() { RWLock::read_to_write() {
/* Sadly, read_to_write is more complex than write_to_read, /* Sadly, read_to_write is more complex than write_to_read,
* because * because
* two readers could want to become writer at the same time, * 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