]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
histogram: move to common, add unit tests
authorSage Weil <sage@inktank.com>
Fri, 24 Jan 2014 02:09:43 +0000 (18:09 -0800)
committerSage Weil <sage@inktank.com>
Sun, 16 Feb 2014 06:07:04 +0000 (22:07 -0800)
Signed-off-by: Sage Weil <sage@inktank.com>
12 files changed:
src/common/Makefile.am
src/common/TrackedOp.h
src/common/histogram.cc [new file with mode: 0644]
src/common/histogram.h [new file with mode: 0644]
src/include/Makefile.am
src/include/histogram.h [deleted file]
src/mon/PGMonitor.h
src/osd/osd_types.cc
src/osd/osd_types.h
src/test/Makefile.am
src/test/common/histogram.cc [new file with mode: 0644]
src/test/encoding/types.h

index ec1f31e24ae41f928ecb34aa568d9669d1a9c091..b8ce83be9efa0d137fb01b334b301f2132a8bbfc 100644 (file)
@@ -40,6 +40,7 @@ libcommon_la_SOURCES = \
        common/buffer.cc \
        common/code_environment.cc \
        common/dout.cc \
+       common/histogram.cc \
        common/signal.cc \
        common/simple_spin.cc \
        common/Thread.cc \
@@ -141,6 +142,7 @@ noinst_HEADERS += \
        common/fd.h \
        common/version.h \
        common/hex.h \
+       common/histogram.h \
        common/entity_name.h \
        common/errno.h \
        common/environment.h \
index 97c657424e8b813be78185b634e6b9358a20e083..4673c1b80f4f824684858cdd9b0442cb48e7308f 100644 (file)
@@ -17,7 +17,7 @@
 #include <stdint.h>
 #include <include/utime.h>
 #include "common/Mutex.h"
-#include "include/histogram.h"
+#include "common/histogram.h"
 #include "include/xlist.h"
 #include "msg/Message.h"
 #include "include/memory.h"
diff --git a/src/common/histogram.cc b/src/common/histogram.cc
new file mode 100644 (file)
index 0000000..a9431d9
--- /dev/null
@@ -0,0 +1,50 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "common/histogram.h"
+#include "common/Formatter.h"
+
+// -- pow2_hist_t --
+void pow2_hist_t::dump(Formatter *f) const
+{
+  f->open_array_section("histogram");
+  for (std::vector<int32_t>::const_iterator p = h.begin(); p != h.end(); ++p)
+    f->dump_int("count", *p);
+  f->close_section();
+  f->dump_int("upper_bound", upper_bound());
+}
+
+void pow2_hist_t::encode(bufferlist& bl) const
+{
+  ENCODE_START(1, 1, bl);
+  ::encode(h, bl);
+  ENCODE_FINISH(bl);
+}
+
+void pow2_hist_t::decode(bufferlist::iterator& p)
+{
+  DECODE_START(1, p);
+  ::decode(h, p);
+  DECODE_FINISH(p);
+}
+
+void pow2_hist_t::generate_test_instances(std::list<pow2_hist_t*>& ls)
+{
+  ls.push_back(new pow2_hist_t);
+  ls.push_back(new pow2_hist_t);
+  ls.back()->h.push_back(1);
+  ls.back()->h.push_back(3);
+  ls.back()->h.push_back(0);
+  ls.back()->h.push_back(2);
+}
diff --git a/src/common/histogram.h b/src/common/histogram.h
new file mode 100644 (file)
index 0000000..1497bc9
--- /dev/null
@@ -0,0 +1,126 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ * Copyright 2013 Inktank
+ */
+
+#ifndef CEPH_HISTOGRAM_H
+#define CEPH_HISTOGRAM_H
+
+#include <vector>
+#include <list>
+
+#include "include/encoding.h"
+
+namespace ceph {
+  class Formatter;
+}
+
+/**
+ * power of 2 histogram
+ */
+struct pow2_hist_t { //
+  /**
+   * histogram
+   *
+   * bin size is 2^index
+   * value is count of elements that are <= the current bin but > the previous bin.
+   */
+  std::vector<int32_t> h;
+
+private:
+  /// expand to at least another's size
+  void _expand_to(unsigned s) {
+    if (s > h.size())
+      h.resize(s, 0);
+  }
+  /// drop useless trailing 0's
+  void _contract() {
+    unsigned p = h.size();
+    while (p > 0 && h[p-1] == 0)
+      --p;
+    h.resize(p);
+  }
+
+public:
+  void clear() {
+    h.clear();
+  }
+  void set_bin(int bin, int32_t count) {
+    _expand_to(bin + 1);
+    h[bin] = count;
+    _contract();
+  }
+
+  void add(int32_t v) {
+    int bin = calc_bits_of(v);
+    _expand_to(bin + 1);
+    h[bin]++;
+    _contract();
+  }
+
+  static int calc_bits_of(int t) {
+    int b = 0;
+    while (t > 0) {
+      t = t >> 1;
+      b++;
+    }
+    return b;
+  }
+
+  /// get a value's position in the histogram.
+  ///
+  /// positions are represented as values in the range [0..1000000]
+  /// (millionths on the unit interval).
+  ///
+  /// @param v [in] value (non-negative)
+  /// @param lower [out] pointer to lower-bound (0..1000000)
+  /// @param upper [out] pointer to the upper bound (0..1000000)
+  int get_position_micro(int32_t v, unsigned *lower, unsigned *upper) {
+    if (v < 0)
+      return -1;
+    unsigned bin = calc_bits_of(v);
+    unsigned lower_sum = 0, upper_sum = 0, total = 0;
+    for (unsigned i=0; i<h.size(); ++i) {
+      if (i <= bin)
+       upper_sum += h[i];
+      if (i < bin)
+       lower_sum += h[i];
+      total += h[i];
+    }
+    *lower = lower_sum * 1000000 / total;
+    *upper = upper_sum * 1000000 / total;
+    return 0;
+  }
+
+  void add(const pow2_hist_t& o) {
+    _expand_to(o.h.size());
+    for (unsigned p = 0; p < o.h.size(); ++p)
+      h[p] += o.h[p];
+    _contract();
+  }
+  void sub(const pow2_hist_t& o) {
+    _expand_to(o.h.size());
+    for (unsigned p = 0; p < o.h.size(); ++p)
+      h[p] -= o.h[p];
+    _contract();
+  }
+
+  int32_t upper_bound() const {
+    return 1 << h.size();
+  }
+
+  void dump(Formatter *f) const;
+  void encode(bufferlist &bl) const;
+  void decode(bufferlist::iterator &bl);
+  static void generate_test_instances(std::list<pow2_hist_t*>& o);
+};
+WRITE_CLASS_ENCODER(pow2_hist_t)
+
+#endif /* CEPH_HISTOGRAM_H */
index 62cd62ca2052a22e4240a10830e0454b4eaf5424..20cac9ad37799843678d37b74b28b474468324bc 100644 (file)
@@ -45,7 +45,6 @@ noinst_HEADERS += \
        include/filepath.h \
        include/frag.h \
        include/hash.h \
-       include/histogram.h \
        include/intarith.h \
        include/interval_set.h \
        include/int_types.h \
diff --git a/src/include/histogram.h b/src/include/histogram.h
deleted file mode 100644 (file)
index 5feebfc..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- * Copyright 2013 Inktank
- */
-
-#ifndef HISTOGRAM_H_
-#define HISTOGRAM_H_
-
-/**
- * power of 2 histogram
- */
-struct pow2_hist_t { //
-  /**
-   * histogram
-   *
-   * bin size is 2^index
-   * value is count of elements that are <= the current bin but > the previous bin.
-   */
-  vector<int32_t> h;
-
-private:
-  /// expand to at least another's size
-  void _expand_to(unsigned s) {
-    if (s > h.size())
-      h.resize(s, 0);
-  }
-  /// drop useless trailing 0's
-  void _contract() {
-    unsigned p = h.size();
-    while (p > 0 && h[p-1] == 0)
-      --p;
-    h.resize(p);
-  }
-
-public:
-  void clear() {
-    h.clear();
-  }
-  void set_bin(int bin, int32_t count) {
-    _expand_to(bin + 1);
-    h[bin] = count;
-    _contract();
-  }
-
-  static int calc_bits_of(int t) {
-    int b = 0;
-    while (t > 0) {
-      t = t >> 1;
-      b++;
-    }
-    return b;
-  }
-
-  /// get a value's position in the histogram.
-  ///
-  /// positions are represented as values in the range [0..1000000]
-  /// (millionths on the unit interval).
-  ///
-  /// @param v [in] value (non-negative)
-  /// @param lower [out] pointer to lower-bound (0..1000000)
-  /// @param upper [out] pointer to the upper bound (0..1000000)
-  int get_position_micro(int32_t v, unsigned *lower, unsigned *upper) {
-    if (v < 0)
-      return -ERANGE;
-    unsigned bin = calc_bits_of(v);
-    unsigned lower_sum = 0, upper_sum = 0, total = 0;
-    for (unsigned i=0; i<h.size(); ++i) {
-      if (i <= bin)
-       upper_sum += h[i];
-      if (i < bin)
-       lower_sum += h[i];
-      total += h[i];
-    }
-    *lower = lower_sum * 1000000 / total;
-    *upper = upper_sum * 1000000 / total;
-    return 0;
-  }
-
-  void add(const pow2_hist_t& o) {
-    _expand_to(o.h.size());
-    for (unsigned p = 0; p < o.h.size(); ++p)
-      h[p] += o.h[p];
-    _contract();
-  }
-  void sub(const pow2_hist_t& o) {
-    _expand_to(o.h.size());
-    for (unsigned p = 0; p < o.h.size(); ++p)
-      h[p] -= o.h[p];
-    _contract();
-  }
-
-  int32_t upper_bound() const {
-    return 1 << h.size();
-  }
-
-  void dump(Formatter *f) const;
-  void encode(bufferlist &bl) const;
-  void decode(bufferlist::iterator &bl);
-  static void generate_test_instances(std::list<pow2_hist_t*>& o);
-};
-WRITE_CLASS_ENCODER(pow2_hist_t)
-
-#endif /* HISTOGRAM_H_ */
index d29f47c1c43c44c4052935b123eb62747317a715..09dd00946ac6ce86070799adcc551846332be6ab 100644 (file)
@@ -28,7 +28,7 @@ using namespace std;
 #include "PaxosService.h"
 #include "include/types.h"
 #include "include/utime.h"
-#include "include/histogram.h"
+#include "common/histogram.h"
 #include "msg/Messenger.h"
 #include "common/config.h"
 #include "mon/MonitorDBStore.h"
index 59a40d841338dba662c28be2de4af57dd5611ed1..fbc4aadffb33db194bac36452ce47f1917bed48a 100644 (file)
@@ -193,40 +193,6 @@ void request_redirect_t::generate_test_instances(list<request_redirect_t*>& o)
   o.push_back(new request_redirect_t(loc));
 }
 
-// -- pow2_hist_t --
-void pow2_hist_t::dump(Formatter *f) const
-{
-  f->open_array_section("histogram");
-  for (vector<int>::const_iterator p = h.begin(); p != h.end(); ++p)
-    f->dump_int("count", *p);
-  f->close_section();
-  f->dump_int("upper_bound", upper_bound());
-}
-
-void pow2_hist_t::encode(bufferlist& bl) const
-{
-  ENCODE_START(1, 1, bl);
-  ::encode(h, bl);
-  ENCODE_FINISH(bl);
-}
-
-void pow2_hist_t::decode(bufferlist::iterator& p)
-{
-  DECODE_START(1, p);
-  ::decode(h, p);
-  DECODE_FINISH(p);
-}
-
-void pow2_hist_t::generate_test_instances(list<pow2_hist_t*>& ls)
-{
-  ls.push_back(new pow2_hist_t);
-  ls.push_back(new pow2_hist_t);
-  ls.back()->h.push_back(1);
-  ls.back()->h.push_back(3);
-  ls.back()->h.push_back(0);
-  ls.back()->h.push_back(2);
-}
-
 void objectstore_perf_stat_t::dump(Formatter *f) const
 {
   f->dump_unsigned("commit_latency_ms", filestore_commit_latency);
index d253dd2e49ad73ae4cbffa226a2d8033dca882e9..416535953907e03a02b40cf85e9a3f9851a49cc6 100644 (file)
@@ -27,7 +27,7 @@
 #include "include/types.h"
 #include "include/utime.h"
 #include "include/CompatSet.h"
-#include "include/histogram.h"
+#include "common/histogram.h"
 #include "include/interval_set.h"
 #include "common/Formatter.h"
 #include "common/bloom_filter.hpp"
index 7af43bbd20c051076cfc50b5ab8fd4266c515483..a5d47597d1c3df48dc3a84a598ca1d360ae56b8b 100644 (file)
@@ -271,6 +271,11 @@ unittest_bloom_filter_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 unittest_bloom_filter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 check_PROGRAMS += unittest_bloom_filter
 
+unittest_histogram_SOURCES = test/common/histogram.cc
+unittest_histogram_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+unittest_histogram_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
+check_PROGRAMS += unittest_histogram
+
 unittest_str_map_SOURCES = test/common/test_str_map.cc
 unittest_str_map_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 unittest_str_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
diff --git a/src/test/common/histogram.cc b/src/test/common/histogram.cc
new file mode 100644 (file)
index 0000000..c07d6c2
--- /dev/null
@@ -0,0 +1,95 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2014 Inktank <info@inktank.com>
+ *
+ * LGPL2.1 (see COPYING-LGPL2.1) or later
+ */
+
+#include <iostream>
+#include <gtest/gtest.h>
+
+#include "common/histogram.h"
+#include "include/stringify.h"
+
+TEST(Histogram, Basic) {
+  pow2_hist_t h;
+
+  h.add(0);
+  h.add(0);
+  h.add(0);
+  ASSERT_EQ(3, h.h[0]);
+  ASSERT_EQ(1u, h.h.size());
+
+  h.add(1);
+  ASSERT_EQ(3, h.h[0]);
+  ASSERT_EQ(1, h.h[1]);
+  ASSERT_EQ(2u, h.h.size());
+
+  h.add(2);
+  h.add(2);
+  ASSERT_EQ(3, h.h[0]);
+  ASSERT_EQ(1, h.h[1]);
+  ASSERT_EQ(2, h.h[2]);
+  ASSERT_EQ(3u, h.h.size());
+}
+
+TEST(Histogram, Set) {
+  pow2_hist_t h;
+  h.set_bin(0, 12);
+  h.set_bin(2, 12);
+  ASSERT_EQ(12, h.h[0]);
+  ASSERT_EQ(0, h.h[1]);
+  ASSERT_EQ(12, h.h[2]);
+  ASSERT_EQ(3u, h.h.size());
+}
+
+TEST(Histogram, Position) {
+  {
+    pow2_hist_t h;
+    unsigned lb, ub;
+    h.add(0);
+    ASSERT_EQ(-1, h.get_position_micro(-20, &lb, &ub));
+  }
+  {
+    pow2_hist_t h;
+    h.add(0);
+    unsigned lb, ub;
+    h.get_position_micro(0, &lb, &ub);
+    ASSERT_EQ(0, lb);
+    ASSERT_EQ(1000000, ub);
+    h.add(0);
+    h.add(0);
+    h.add(0);
+    h.get_position_micro(0, &lb, &ub);
+    ASSERT_EQ(0, lb);
+    ASSERT_EQ(1000000, ub);
+  }
+  {
+    pow2_hist_t h;
+    h.add(1);
+    h.add(1);
+    unsigned lb, ub;
+    h.get_position_micro(0, &lb, &ub);
+    ASSERT_EQ(0, lb);
+    ASSERT_EQ(0, ub);
+    h.add(0);
+    h.get_position_micro(0, &lb, &ub);
+    ASSERT_EQ(0, lb);
+    ASSERT_EQ(333333, ub);
+    h.get_position_micro(1, &lb, &ub);
+    ASSERT_EQ(333333, lb);
+    ASSERT_EQ(1000000, ub);
+  }
+  {
+    pow2_hist_t h;
+    h.add(1);
+    h.add(10);
+    unsigned lb, ub;
+    h.get_position_micro(4, &lb, &ub);
+    ASSERT_EQ(500000, lb);
+    ASSERT_EQ(500000, ub);
+  }
+}
index ce0af02d807cf7090f3c50e7843194353d7a4956..2b79bfbac072b55018601afcb20c1c4a9d4882f9 100644 (file)
@@ -36,7 +36,7 @@ TYPEWITHSTRAYDATA(OSDMap::Incremental)
 #include "crush/CrushWrapper.h"
 TYPE_NOCOPY(CrushWrapper)
 
-#include "include/histogram.h"
+#include "common/histogram.h"
 TYPE(pow2_hist_t)
 
 #include "osd/osd_types.h"