Test multiple profloggers, and removing profloggers.
Add a clear function which removes all profloggers.
Make the order in which profloggers are output to JSON determininstic.
Const cleanup on get() methods.
Signed-off-by: Colin McCabe <colin.mccabe@dreamhost.com>
{
Mutex::Locker lck(m_parent->m_lock); // Take lock to access m_loggers
buffer.push_back('{');
- for (std::set <ProfLogger*>::iterator l = m_parent->m_loggers.begin();
+ for (prof_logger_set_t::iterator l = m_parent->m_loggers.begin();
l != m_parent->m_loggers.end(); ++l)
{
(*l)->write_json_to_buf(buffer);
{
Mutex::Locker lck(m_lock);
shutdown();
- for (std::set <ProfLogger*>::iterator l = m_loggers.begin();
+ for (prof_logger_set_t::iterator l = m_loggers.begin();
l != m_loggers.end(); ++l) {
delete *l;
}
logger_add(class ProfLogger *l)
{
Mutex::Locker lck(m_lock);
- std::set<ProfLogger*>::iterator i = m_loggers.find(l);
+ prof_logger_set_t::iterator i = m_loggers.find(l);
assert(i == m_loggers.end());
m_loggers.insert(l);
}
logger_remove(class ProfLogger *l)
{
Mutex::Locker lck(m_lock);
- std::set<ProfLogger*>::iterator i = m_loggers.find(l);
+ prof_logger_set_t::iterator i = m_loggers.find(l);
assert(i != m_loggers.end());
+ delete *i;
m_loggers.erase(i);
}
+void ProfLoggerCollection::
+logger_clear()
+{
+ Mutex::Locker lck(m_lock);
+ prof_logger_set_t::iterator i = m_loggers.begin();
+ prof_logger_set_t::iterator i_end = m_loggers.end();
+ for (; i != i_end; ) {
+ delete *i;
+ m_loggers.erase(i++);
+ }
+}
+
bool ProfLoggerCollection::
init(const std::string &uri)
{
}
uint64_t ProfLogger::
-get(int idx)
+get(int idx) const
{
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
- prof_log_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+ const prof_log_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (data.type != PROF_LOG_DATA_ANY_DOUBLE)
return 0;
return data.u.u64;
}
double ProfLogger::
-fget(int idx)
+fget(int idx) const
{
Mutex::Locker lck(m_lock);
assert(idx > m_lower_bound);
assert(idx < m_upper_bound);
- prof_log_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+ const prof_log_data_any_d& data(m_data[idx - m_lower_bound - 1]);
if (data.type != PROF_LOG_DATA_ANY_DOUBLE)
return 0.0;
return data.u.dbl;
}
}
+const std::string &ProfLogger::
+get_name() const
+{
+ return m_name;
+}
+
ProfLogger::
ProfLogger(CephContext *cct, const std::string &name,
int lower_bound, int upper_bound)
#include <string>
#include <vector>
+class CephContext;
class ProfLoggerBuilder;
class ProfLoggerCollectionTest;
-class CephContext;
class Thread;
/*
- * ProfLog manages the profiler logging for a Ceph process.
+ * A ProfLogger is usually associated with a single subsystem.
+ * It contains counters which we modify to track performance and throughput
+ * over time.
+ *
+ * ProfLogger is thread-safe. However, it is better to avoid sharing
+ * ProfLoggers between multiple threads to avoid cacheline ping-pong.
*/
-class ProfLoggerCollection : public md_config_obs_t
-{
-public:
- ProfLoggerCollection(CephContext *cct);
- ~ProfLoggerCollection();
- virtual const char** get_tracked_conf_keys() const;
- virtual void handle_conf_change(const md_config_t *conf,
- const std::set <std::string> &changed);
- void logger_add(class ProfLogger *l);
- void logger_remove(class ProfLogger *l);
-private:
- bool init(const std::string &uri);
- void shutdown();
-
- CephContext *m_cct;
- Thread* m_thread;
-
- /** Protects m_loggers */
- Mutex m_lock;
-
- int m_shutdown_fd;
- std::set <ProfLogger*> m_loggers;
- std::string m_uri;
-
- friend class ProfLogThread;
- friend class ProfLoggerCollectionTest;
-};
-
class ProfLogger
{
public:
void inc(int idx, uint64_t v = 1);
void set(int idx, uint64_t v);
- uint64_t get(int idx);
+ uint64_t get(int idx) const;
void fset(int idx, double v);
void finc(int idx, double v);
- double fget(int idx);
+ double fget(int idx) const;
void write_json_to_buf(std::vector <char> &buffer);
+ const std::string& get_name() const;
+
private:
ProfLogger(CephContext *cct, const std::string &name,
int lower_bound, int upper_bound);
const std::string m_name;
/** Protects m_data */
- Mutex m_lock;
+ mutable Mutex m_lock;
prof_log_data_vec_t m_data;
friend class ProfLoggerBuilder;
};
+class SortProfLoggersByName {
+public:
+ bool operator()(const ProfLogger* lhs, const ProfLogger* rhs) const {
+ return (lhs->get_name() < rhs->get_name());
+ }
+};
+
+typedef std::set <ProfLogger*, SortProfLoggersByName> prof_logger_set_t;
+
+/*
+ * ProfLoggerCollection manages the set of ProfLoggers for a Ceph process.
+ */
+class ProfLoggerCollection : public md_config_obs_t
+{
+public:
+ ProfLoggerCollection(CephContext *cct);
+ ~ProfLoggerCollection();
+ virtual const char** get_tracked_conf_keys() const;
+ virtual void handle_conf_change(const md_config_t *conf,
+ const std::set <std::string> &changed);
+ void logger_add(class ProfLogger *l);
+ void logger_remove(class ProfLogger *l);
+ void logger_clear();
+private:
+ bool init(const std::string &uri);
+ void shutdown();
+
+ CephContext *m_cct;
+ Thread* m_thread;
+
+ /** Protects m_loggers */
+ mutable Mutex m_lock;
+
+ int m_shutdown_fd;
+ prof_logger_set_t m_loggers;
+ std::string m_uri;
+
+ friend class ProfLogThread;
+ friend class ProfLoggerCollectionTest;
+};
+
/* Class for constructing ProfLoggers.
*
* This class peforms some validation that the parameters we have supplied are
return bld.create_proflogger();
}
-TEST(ProfLogger, FakeProflogger1) {
+TEST(ProfLogger, SingleProfLogger) {
ProfLoggerCollection *coll = g_ceph_context->GetProfLoggerCollection();
ProfLogger* fake_pf = setup_fake_proflogger1(g_ceph_context);
coll->logger_add(fake_pf);
ASSERT_EQ("", test_client.get_message(&msg));
ASSERT_EQ("{'element1':1,'element2':0.5,'element3':{'count':3,'sum':125},}", msg);
}
+
+enum {
+ FAKE_PROFLOGGER2_ELEMENT_FIRST = 400,
+ FAKE_PROFLOGGER2_ELEMENT_FOO,
+ FAKE_PROFLOGGER2_ELEMENT_BAR,
+ FAKE_PROFLOGGER2_ELEMENT_LAST,
+};
+
+static ProfLogger* setup_fake_proflogger2(CephContext *cct)
+{
+ ProfLoggerBuilder bld(cct, "fake_proflogger_2",
+ FAKE_PROFLOGGER2_ELEMENT_FIRST, FAKE_PROFLOGGER2_ELEMENT_LAST);
+ bld.add_u64(FAKE_PROFLOGGER2_ELEMENT_FOO, "foo");
+ bld.add_fl(FAKE_PROFLOGGER2_ELEMENT_BAR, "bar");
+ return bld.create_proflogger();
+}
+
+TEST(ProfLogger, MultipleProfloggers) {
+ ProfLoggerCollection *coll = g_ceph_context->GetProfLoggerCollection();
+ coll->logger_clear();
+ ProfLogger* fake_pf1 = setup_fake_proflogger1(g_ceph_context);
+ ProfLogger* fake_pf2 = setup_fake_proflogger2(g_ceph_context);
+ coll->logger_add(fake_pf1);
+ coll->logger_add(fake_pf2);
+ ProfLoggerCollectionTest plct(coll);
+ ASSERT_EQ(true, plct.shutdown());
+ ASSERT_EQ(true, plct.init(get_socket_path()));
+ ProfLoggerTestClient test_client(get_socket_path());
+ std::string msg;
+
+ ASSERT_EQ("", test_client.get_message(&msg));
+ ASSERT_EQ("{'element1':0,'element2':0,'element3':{'count':0,'sum':0},'foo':0,'bar':0,}", msg);
+
+ fake_pf1->inc(FAKE_PROFLOGGER1_ELEMENT_1);
+ fake_pf1->inc(FAKE_PROFLOGGER1_ELEMENT_1, 5);
+ ASSERT_EQ("", test_client.get_message(&msg));
+ ASSERT_EQ("{'element1':6,'element2':0,'element3':{'count':0,'sum':0},'foo':0,'bar':0,}", msg);
+
+ coll->logger_remove(fake_pf2);
+ ASSERT_EQ("", test_client.get_message(&msg));
+ ASSERT_EQ("{'element1':6,'element2':0,'element3':{'count':0,'sum':0},}", msg);
+
+ coll->logger_clear();
+ ASSERT_EQ("", test_client.get_message(&msg));
+ ASSERT_EQ("{}", msg);
+}