Merge pull request #1811 from ceph/wip-perf-atomic

perf_counter: use atomics instead of mutex

Reviewed-by: Greg Farnum <greg@inktank.com>
Reviewed-by: Samuel Just <sam.just@inktank.com>
This commit is contained in:
Samuel Just 2014-05-27 15:04:31 -07:00
commit f0316411fa
4 changed files with 151 additions and 95 deletions

View File

@ -483,9 +483,14 @@ AS_IF([test "x$with_libatomic_ops" != xno],
[no libatomic-ops found (use --without-libatomic-ops to disable)])
])])
AS_IF([test "$HAVE_ATOMIC_OPS" = "1"],
[],
[
AC_CHECK_SIZEOF(AO_t, [], [
#include <atomic_ops.h>
])
],
[AC_DEFINE([NO_ATOMIC_OPS], [1], [Defined if you do not have atomic_ops])])
AM_CONDITIONAL(WITH_LIBATOMIC, [test "$HAVE_ATOMIC_OPS" = "1"])
# newsyn? requires mpi.

View File

@ -101,15 +101,18 @@ void PerfCounters::inc(int idx, uint64_t amt)
if (!m_cct->_conf->perf)
return;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_U64))
return;
data.u64 += amt;
if (data.type & PERFCOUNTER_LONGRUNAVG)
data.avgcount++;
if (data.type & PERFCOUNTER_LONGRUNAVG) {
data.avgcount.inc();
data.u64.add(amt);
data.avgcount2.inc();
} else {
data.u64.add(amt);
}
}
void PerfCounters::dec(int idx, uint64_t amt)
@ -117,15 +120,13 @@ void PerfCounters::dec(int idx, uint64_t amt)
if (!m_cct->_conf->perf)
return;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
assert(!(data.type & PERFCOUNTER_LONGRUNAVG));
if (!(data.type & PERFCOUNTER_U64))
return;
assert(data.u64 >= amt);
data.u64 -= amt;
data.u64.sub(amt);
}
void PerfCounters::set(int idx, uint64_t amt)
@ -133,15 +134,19 @@ void PerfCounters::set(int idx, uint64_t amt)
if (!m_cct->_conf->perf)
return;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_U64))
return;
data.u64 = amt;
if (data.type & PERFCOUNTER_LONGRUNAVG)
data.avgcount++;
data.u64.set(amt);
if (data.type & PERFCOUNTER_LONGRUNAVG) {
data.avgcount.inc();
data.u64.set(amt);
data.avgcount2.inc();
} else {
data.u64.set(amt);
}
}
uint64_t PerfCounters::get(int idx) const
@ -149,13 +154,12 @@ uint64_t PerfCounters::get(int idx) const
if (!m_cct->_conf->perf)
return 0;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_U64))
return 0;
return data.u64;
return data.u64.read();
}
void PerfCounters::tinc(int idx, utime_t amt)
@ -163,15 +167,18 @@ void PerfCounters::tinc(int idx, utime_t amt)
if (!m_cct->_conf->perf)
return;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_TIME))
return;
data.u64 += amt.to_nsec();
if (data.type & PERFCOUNTER_LONGRUNAVG)
data.avgcount++;
if (data.type & PERFCOUNTER_LONGRUNAVG) {
data.avgcount.inc();
data.u64.add(amt.to_nsec());
data.avgcount2.inc();
} else {
data.u64.add(amt.to_nsec());
}
}
void PerfCounters::tset(int idx, utime_t amt)
@ -179,13 +186,12 @@ void PerfCounters::tset(int idx, utime_t amt)
if (!m_cct->_conf->perf)
return;
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_TIME))
return;
data.u64 = amt.to_nsec();
data.u64.set(amt.to_nsec());
if (data.type & PERFCOUNTER_LONGRUNAVG)
assert(0);
}
@ -195,13 +201,13 @@ utime_t PerfCounters::tget(int idx) const
if (!m_cct->_conf->perf)
return utime_t();
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (!(data.type & PERFCOUNTER_TIME))
return utime_t();
return utime_t(data.u64 / 1000000000ull, data.u64 % 1000000000ull);
uint64_t v = data.u64.read();
return utime_t(v / 1000000000ull, v % 1000000000ull);
}
pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
@ -209,7 +215,6 @@ pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
if (!m_cct->_conf->perf)
return make_pair(0, 0);
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
@ -217,13 +222,12 @@ pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
return make_pair(0, 0);
if (!(data.type & PERFCOUNTER_LONGRUNAVG))
return make_pair(0, 0);
return make_pair(data.avgcount, data.u64/1000000);
pair<uint64_t,uint64_t> a = data.read_avg();
return make_pair(a.second, a.first / 1000000ull);
}
void PerfCounters::dump_formatted(Formatter *f, bool schema)
{
Mutex::Locker lck(m_lock);
f->open_object_section(m_name.c_str());
perf_counter_data_vec_t::const_iterator d = m_data.begin();
perf_counter_data_vec_t::const_iterator d_end = m_data.end();
@ -239,25 +243,27 @@ void PerfCounters::dump_formatted(Formatter *f, bool schema)
} else {
if (d->type & PERFCOUNTER_LONGRUNAVG) {
f->open_object_section(d->name);
pair<uint64_t,uint64_t> a = d->read_avg();
if (d->type & PERFCOUNTER_U64) {
f->dump_unsigned("avgcount", d->avgcount);
f->dump_unsigned("sum", d->u64);
f->dump_unsigned("avgcount", a.second);
f->dump_unsigned("sum", a.first);
} else if (d->type & PERFCOUNTER_TIME) {
f->dump_unsigned("avgcount", d->avgcount);
f->dump_unsigned("avgcount", a.second);
f->dump_format_unquoted("sum", "%"PRId64".%09"PRId64,
d->u64 / 1000000000ull,
d->u64 % 1000000000ull);
a.first / 1000000000ull,
a.first % 1000000000ull);
} else {
assert(0);
}
f->close_section();
} else {
uint64_t v = d->u64.read();
if (d->type & PERFCOUNTER_U64) {
f->dump_unsigned(d->name, d->u64);
f->dump_unsigned(d->name, v);
} else if (d->type & PERFCOUNTER_TIME) {
f->dump_format_unquoted(d->name, "%"PRId64".%09"PRId64,
d->u64 / 1000000000ull,
d->u64 % 1000000000ull);
v / 1000000000ull,
v % 1000000000ull);
} else {
assert(0);
}
@ -287,14 +293,6 @@ PerfCounters::PerfCounters(CephContext *cct, const std::string &name,
m_data.resize(upper_bound - lower_bound - 1);
}
PerfCounters::perf_counter_data_any_d::perf_counter_data_any_d()
: name(NULL),
type(PERFCOUNTER_NONE),
u64(0),
avgcount(0)
{
}
PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name,
int first, int last)
: m_perf_counters(new PerfCounters(cct, name, first, last))

View File

@ -111,14 +111,51 @@ private:
/** Represents a PerfCounters data element. */
struct perf_counter_data_any_d {
perf_counter_data_any_d();
perf_counter_data_any_d()
: name(NULL),
type(PERFCOUNTER_NONE),
u64(0),
avgcount(0),
avgcount2(0)
{}
perf_counter_data_any_d(const perf_counter_data_any_d& other)
: name(other.name),
type(other.type),
u64(other.u64.read()) {
pair<uint64_t,uint64_t> a = other.read_avg();
u64.set(a.first);
avgcount.set(a.second);
avgcount2.set(a.second);
}
void write_schema_json(char *buf, size_t buf_sz) const;
void write_json(char *buf, size_t buf_sz) const;
const char *name;
enum perfcounter_type_d type;
uint64_t u64;
uint64_t avgcount;
atomic64_t u64;
atomic64_t avgcount;
atomic64_t avgcount2;
perf_counter_data_any_d& operator=(const perf_counter_data_any_d& other) {
name = other.name;
type = other.type;
pair<uint64_t,uint64_t> a = other.read_avg();
u64.set(a.first);
avgcount.set(a.second);
avgcount2.set(a.second);
return *this;
}
/// read <sum, count> safely
pair<uint64_t,uint64_t> read_avg() const {
uint64_t sum, count;
do {
count = avgcount.read();
sum = u64.read();
} while (avgcount2.read() != count);
return make_pair(sum, count);
}
};
typedef std::vector<perf_counter_data_any_d> perf_counter_data_vec_t;

View File

@ -21,6 +21,61 @@
#endif
#include <stdlib.h>
#include "include/Spinlock.h"
namespace ceph {
template <class T>
class atomic_spinlock_t {
mutable ceph_spinlock_t lock;
T val;
public:
atomic_spinlock_t(T i=0)
: val(i) {
ceph_spin_init(&lock);
}
~atomic_spinlock_t() {
ceph_spin_destroy(&lock);
}
void set(size_t v) {
ceph_spin_lock(&lock);
val = v;
ceph_spin_unlock(&lock);
}
T inc() {
ceph_spin_lock(&lock);
T r = ++val;
ceph_spin_unlock(&lock);
return r;
}
T dec() {
ceph_spin_lock(&lock);
T r = --val;
ceph_spin_unlock(&lock);
return r;
}
void add(T d) {
ceph_spin_lock(&lock);
val += d;
ceph_spin_unlock(&lock);
}
void sub(T d) {
ceph_spin_lock(&lock);
val -= d;
ceph_spin_unlock(&lock);
}
T read() const {
signed long ret;
ceph_spin_lock(&lock);
ret = val;
ceph_spin_unlock(&lock);
return ret;
}
private:
// forbid copying
atomic_spinlock_t(const atomic_spinlock_t<T> &other);
atomic_spinlock_t &operator=(const atomic_spinlock_t<T> &rhs);
};
}
#ifndef NO_ATOMIC_OPS
@ -63,7 +118,15 @@ namespace ceph {
atomic_t(const atomic_t &other);
atomic_t &operator=(const atomic_t &rhs);
};
#if SIZEOF_AO_T == 8
typedef atomic_t atomic64_t;
#else
typedef atomic_spinlock_t<long long> atomic64_t;
#endif
}
#else
/*
* crappy slow implementation that uses a pthreads spinlock.
@ -71,56 +134,9 @@ namespace ceph {
#include "include/Spinlock.h"
namespace ceph {
class atomic_t {
mutable ceph_spinlock_t lock;
signed long val;
public:
atomic_t(int i=0)
: val(i) {
ceph_spin_init(&lock);
}
~atomic_t() {
ceph_spin_destroy(&lock);
}
void set(size_t v) {
ceph_spin_lock(&lock);
val = v;
ceph_spin_unlock(&lock);
}
int inc() {
ceph_spin_lock(&lock);
int r = ++val;
ceph_spin_unlock(&lock);
return r;
}
int dec() {
ceph_spin_lock(&lock);
int r = --val;
ceph_spin_unlock(&lock);
return r;
}
void add(int d) {
ceph_spin_lock(&lock);
val += d;
ceph_spin_unlock(&lock);
}
void sub(int d) {
ceph_spin_lock(&lock);
val -= d;
ceph_spin_unlock(&lock);
}
int read() const {
signed long ret;
ceph_spin_lock(&lock);
ret = val;
ceph_spin_unlock(&lock);
return ret;
}
private:
// forbid copying
atomic_t(const atomic_t &other);
atomic_t &operator=(const atomic_t &rhs);
};
typedef atomic_spinlock_t<int> atomic_t;
typedef atomic_spinlock_t<long long> atomic64_t;
}
#endif
#endif