mirror of
https://github.com/ceph/ceph
synced 2024-12-17 17:05:42 +00:00
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:
commit
f0316411fa
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user