Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
metrics-test.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "util/metrics.h"
17 #include "util/memory-metrics.h"
18 
19 #include <gtest/gtest.h>
20 #include <boost/scoped_ptr.hpp>
21 #include <limits>
22 
23 #include "util/jni-util.h"
24 #include "util/thread.h"
25 
26 #include "common/names.h"
27 
28 using namespace rapidjson;
29 
30 namespace impala {
31 
32 template <typename M, typename T>
33 void AssertValue(M* metric, const T& value,
34  const string& human_readable) {
35  EXPECT_EQ(metric->value(), value);
36  if (!human_readable.empty()) {
37  EXPECT_EQ(metric->ToHumanReadable(), human_readable);
38  }
39 }
40 
41 TEST(MetricsTest, CounterMetrics) {
42  MetricGroup metrics("CounterMetrics");
43  IntCounter* int_counter = metrics.AddCounter("counter", 0L);
44  AssertValue(int_counter, 0, "0");
45  int_counter->Increment(1);
46  AssertValue(int_counter, 1, "1");
47  int_counter->Increment(10);
48  AssertValue(int_counter, 11, "11");
49  int_counter->set_value(3456);
50  AssertValue(int_counter, 3456, "3.46K");
51 
52  IntCounter* int_counter_with_units =
53  metrics.AddCounter("counter_with_units", 10L, TUnit::BYTES);
54  AssertValue(int_counter_with_units, 10, "10.00 B");
55 }
56 
57 TEST(MetricsTest, GaugeMetrics) {
58  MetricGroup metrics("GaugeMetrics");
59  IntGauge* int_gauge = metrics.AddGauge("gauge", 0L);
60  AssertValue(int_gauge, 0, "0");
61  int_gauge->Increment(-1);
62  AssertValue(int_gauge, -1, "-1");
63  int_gauge->Increment(10);
64  AssertValue(int_gauge, 9, "9");
65  int_gauge->set_value(3456);
66  AssertValue(int_gauge, 3456, "3456");
67 
68  IntGauge* int_gauge_with_units =
69  metrics.AddGauge("gauge_with_units", 10L, TUnit::TIME_S);
70  AssertValue(int_gauge_with_units, 10, "10s000ms");
71 }
72 
73 TEST(MetricsTest, PropertyMetrics) {
74  MetricGroup metrics("PropertyMetrics");
75  BooleanProperty* bool_property = metrics.AddProperty("bool_property", false);
76  AssertValue(bool_property, false, "false");
77  bool_property->set_value(true);
78  AssertValue(bool_property, true, "true");
79 
80  StringProperty* string_property = metrics.AddProperty("string_property",
81  string("string1"));
82  AssertValue(string_property, "string1", "string1");
83  string_property->set_value("string2");
84  AssertValue(string_property, "string2", "string2");
85 }
86 
87 TEST(MetricsTest, NonFiniteValues) {
88  MetricGroup metrics("NanValues");
89  double inf = numeric_limits<double>::infinity();
90  DoubleGauge* gauge = metrics.AddGauge("inf_value", inf);
91  AssertValue(gauge, inf, "inf");
92  double nan = numeric_limits<double>::quiet_NaN();
93  gauge->set_value(nan);
94  EXPECT_TRUE(isnan(gauge->value()));
95  EXPECT_TRUE(gauge->ToHumanReadable() == "nan");
96 }
97 
98 TEST(MetricsTest, SetMetrics) {
99  MetricGroup metrics("SetMetrics");
100  set<int> item_set;
101  item_set.insert(4); item_set.insert(5); item_set.insert(6);
102  SetMetric<int>* set_metric =
103  metrics.RegisterMetric(new SetMetric<int>("set", item_set));
104  EXPECT_EQ(set_metric->ToHumanReadable(), "[4, 5, 6]");
105 
106  set_metric->Add(7);
107  set_metric->Add(7);
108  set_metric->Remove(4);
109  set_metric->Remove(4);
110 
111  EXPECT_EQ(set_metric->ToHumanReadable(), "[5, 6, 7]");
112 }
113 
114 TEST(MetricsTest, StatsMetrics) {
115  // Uninitialised stats metrics don't print anything other than the count
116  MetricGroup metrics("StatsMetrics");
117  StatsMetric<double>* stats_metric = metrics.RegisterMetric(
118  new StatsMetric<double>("stats", TUnit::UNIT));
119  EXPECT_EQ(stats_metric->ToHumanReadable(), "count: 0");
120 
121  stats_metric->Update(0.0);
122  stats_metric->Update(1.0);
123  stats_metric->Update(2.0);
124 
125  EXPECT_EQ(stats_metric->ToHumanReadable(), "count: 3, last: 2.000000, min: 0.000000, "
126  "max: 2.000000, mean: 1.000000, stddev: 0.816497");
127 
128  StatsMetric<double>* stats_metric_with_units = metrics.RegisterMetric(
129  new StatsMetric<double>("stats_units", TUnit::BYTES));
130  EXPECT_EQ(stats_metric_with_units->ToHumanReadable(), "count: 0");
131 
132  stats_metric_with_units->Update(0.0);
133  stats_metric_with_units->Update(1.0);
134  stats_metric_with_units->Update(2.0);
135 
136  EXPECT_EQ(stats_metric_with_units->ToHumanReadable(), "count: 3, last: 2.00 B, min: 0, "
137  "max: 2.00 B, mean: 1.00 B, stddev: 0.82 B");
138 }
139 
140 TEST(MetricsTest, MemMetric) {
141 #ifndef ADDRESS_SANITIZER
142  MetricGroup metrics("MemMetrics");
143  RegisterMemoryMetrics(&metrics, false);
144  // Smoke test to confirm that tcmalloc metrics are returning reasonable values.
145  UIntGauge* bytes_in_use =
146  metrics.FindMetricForTesting<UIntGauge>("tcmalloc.bytes-in-use");
147  DCHECK(bytes_in_use != NULL);
148 
149  uint64_t cur_in_use = bytes_in_use->value();
150  EXPECT_GT(cur_in_use, 0);
151 
152  // Allocate 10MB to increase the number of bytes used. TCMalloc may also give up some
153  // bytes during this allocation, so this allocation is deliberately large to ensure that
154  // the bytes used metric goes up net.
155  scoped_ptr<vector<uint64_t> > chunk(new vector<uint64_t>(10 * 1024 * 1024));
156  EXPECT_GT(bytes_in_use->value(), cur_in_use);
157 
158  UIntGauge* total_bytes_reserved =
159  metrics.FindMetricForTesting<UIntGauge>("tcmalloc.total-bytes-reserved");
160  DCHECK(total_bytes_reserved != NULL);
161  DCHECK_GT(total_bytes_reserved->value(), 0);
162 
163  UIntGauge* pageheap_free_bytes =
164  metrics.FindMetricForTesting<UIntGauge>("tcmalloc.pageheap-free-bytes");
165  DCHECK(pageheap_free_bytes != NULL);
166 
167  UIntGauge* pageheap_unmapped_bytes =
168  metrics.FindMetricForTesting<UIntGauge>("tcmalloc.pageheap-unmapped-bytes");
169  EXPECT_TRUE(pageheap_unmapped_bytes != NULL);
170 #endif
171 }
172 
173 TEST(MetricsTest, JvmMetrics) {
174  MetricGroup metrics("JvmMetrics");
175  RegisterMemoryMetrics(&metrics, true);
176  UIntGauge* jvm_total_used =
178  "jvm.total.current-usage-bytes");
179  ASSERT_TRUE(jvm_total_used != NULL);
180  EXPECT_GT(jvm_total_used->value(), 0);
181  UIntGauge* jvm_peak_total_used =
183  "jvm.total.peak-current-usage-bytes");
184  ASSERT_TRUE(jvm_peak_total_used != NULL);
185  EXPECT_GT(jvm_peak_total_used->value(), 0);
186 }
187 
188 void AssertJson(const Value& val, const string& name, const string& value,
189  const string& description, const string& kind="", const string& units="") {
190  EXPECT_EQ(val["name"].GetString(), name);
191  EXPECT_EQ(val["human_readable"].GetString(), value);
192  EXPECT_EQ(val["description"].GetString(), description);
193  if (!kind.empty()) EXPECT_EQ(val["kind"].GetString(), kind);
194  if (!units.empty()) EXPECT_EQ(val["units"].GetString(), units);
195 }
196 
197 TEST(MetricsJsonTest, Counters) {
198  MetricGroup metrics("CounterMetrics");
199  metrics.AddCounter("counter", 0L);
200  Document document;
201  Value val;
202  metrics.ToJson(true, &document, &val);
203  const Value& counter_val = val["metrics"][0u];
204  AssertJson(counter_val, "counter", "0", "", "COUNTER", "UNIT");
205  EXPECT_EQ(counter_val["value"].GetInt(), 0);
206 }
207 
208 TEST(MetricsJsonTest, Gauges) {
209  MetricGroup metrics("GaugeMetrics");
210  metrics.AddGauge("gauge", 10L);
211  Document document;
212  Value val;
213  metrics.ToJson(true, &document, &val);
214  AssertJson(val["metrics"][0u], "gauge", "10", "", "GAUGE", "NONE");
215  EXPECT_EQ(val["metrics"][0u]["value"].GetInt(), 10);
216 }
217 
218 TEST(MetricsJsonTest, Properties) {
219  MetricGroup metrics("Properties");
220  metrics.AddProperty("property", string("my value"));
221  Document document;
222  Value val;
223  metrics.ToJson(true, &document, &val);
224 
225  AssertJson(val["metrics"][0u], "property", "my value", "", "PROPERTY", "NONE");
226  EXPECT_EQ(string(val["metrics"][0u]["value"].GetString()), "my value");
227 }
228 
229 TEST(MetricsJsonTest, SetMetrics) {
230  MetricGroup metrics("SetMetrics");
231  set<int> item_set;
232  item_set.insert(4); item_set.insert(5); item_set.insert(6);
233  metrics.RegisterMetric(new SetMetric<int>("set", item_set));
234 
235  Document document;
236  Value val;
237  metrics.ToJson(true, &document, &val);
238  const Value& set_val = val["metrics"][0u];
239  ASSERT_TRUE(set_val["items"].IsArray());
240  EXPECT_EQ(set_val["items"].Size(), 3);
241  EXPECT_EQ(set_val["items"][0u].GetInt(), 4);
242  EXPECT_EQ(set_val["items"][1].GetInt(), 5);
243  EXPECT_EQ(set_val["items"][2].GetInt(), 6);
244 
245  AssertJson(set_val, "set", "[4, 5, 6]", "");
246 }
247 
248 TEST(MetricsJsonTest, StatsMetrics) {
249  MetricGroup metrics("StatsMetrics");
250  StatsMetric<double>* metric =
251  metrics.RegisterMetric(new StatsMetric<double>("stats_metric", TUnit::UNIT));
252  metric->Update(10.0);
253  metric->Update(20.0);
254  Document document;
255  Value val;
256  metrics.ToJson(true, &document, &val);
257  const Value& stats_val = val["metrics"][0u];
258  AssertJson(stats_val, "stats_metric", "count: 2, last: 20.000000, min: 10.000000, "
259  "max: 20.000000, mean: 15.000000, stddev: 5.000000", "", "", "UNIT");
260 
261  EXPECT_EQ(stats_val["count"].GetInt(), 2);
262  EXPECT_EQ(stats_val["last"].GetDouble(), 20.0);
263  EXPECT_EQ(stats_val["min"].GetDouble(), 10.0);
264  EXPECT_EQ(stats_val["max"].GetDouble(), 20.0);
265  EXPECT_EQ(stats_val["mean"].GetDouble(), 15.0);
266  EXPECT_EQ(stats_val["stddev"].GetDouble(), 5.0);
267 }
268 
269 TEST(MetricsJsonTest, UnitsAndDescription) {
270  MetricGroup metrics("Units");
271  metrics.AddCounter("counter", 2048, TUnit::BYTES, "description");
272  Document document;
273  Value val;
274  metrics.ToJson(true, &document, &val);
275  const Value& counter_val = val["metrics"][0u];
276  AssertJson(counter_val, "counter", "2.00 KB", "description", "COUNTER", "BYTES");
277  EXPECT_EQ(counter_val["value"].GetInt(), 2048);
278 }
279 
280 TEST(MetricGroupTest, JsonTest) {
281  MetricGroup metrics("JsonTest");
282  metrics.AddCounter("counter1", 2048, TUnit::BYTES, "description");
283  metrics.AddCounter("counter2", 2048, TUnit::BYTES, "description");
284 
285  metrics.GetChildGroup("child1");
286  metrics.GetChildGroup("child2")->AddCounter("child_counter", 0);
287 
288  IntCounter* counter = metrics.FindMetricForTesting<IntCounter>(string("child_counter"));
289  ASSERT_NE(counter, reinterpret_cast<IntCounter*>(NULL));
290 
291  Document document;
292  Value val;
293  metrics.ToJson(true, &document, &val);
294  EXPECT_EQ(val["metrics"].Size(), 2);
295  EXPECT_EQ(val["name"].GetString(), string("JsonTest"));
296 
297  EXPECT_EQ(val["child_groups"].Size(), 2);
298  EXPECT_EQ(val["child_groups"][0u]["name"].GetString(), string("child1"));
299  EXPECT_EQ(val["child_groups"][0u]["metrics"].Size(), 0);
300  EXPECT_EQ(val["child_groups"][1]["name"].GetString(), string("child2"));
301  EXPECT_EQ(val["child_groups"][1]["metrics"].Size(), 1);
302 }
303 
304 }
305 
306 int main(int argc, char **argv) {
307  google::InitGoogleLogging(argv[0]);
308  ::testing::InitGoogleTest(&argc, argv);
311 
312  return RUN_ALL_TESTS();
313 }
SimpleMetric< T, TMetricKind::COUNTER > * AddCounter(const std::string &key, const T &value, const TUnit::type unit=TUnit::UNIT, const std::string &description="")
Definition: metrics.h:239
class SimpleMetric< std::string, TMetricKind::PROPERTY > StringProperty
Definition: metrics.h:323
void Remove(const T &item)
Remove an item from this set by value.
TEST(MetricGroupTest, JsonTest)
class SimpleMetric< int64_t, TMetricKind::COUNTER > IntCounter
Definition: metrics.h:320
M * RegisterMetric(M *metric)
Definition: metrics.h:211
MetricGroup * GetChildGroup(const std::string &name)
Creates or returns an already existing child metric group.
Definition: metrics.cc:169
Status RegisterMemoryMetrics(MetricGroup *metrics, bool register_jvm_metrics)
MetricGroups may be organised hierarchically as a tree.
Definition: metrics.h:200
void Add(const T &item)
Put an item in this set.
static Status Init()
Find JniUtil class, and get JniUtil.throwableToString method id.
Definition: jni-util.cc:74
void AssertJson(const Value &val, const string &name, const string &value, const string &description, const string &kind="", const string &units="")
M * FindMetricForTesting(const std::string &key)
Used for testing only.
Definition: metrics.h:253
virtual std::string ToHumanReadable()
void InitThreading()
Initialises the threading subsystem. Must be called before a Thread is created.
Definition: thread.cc:261
SimpleMetric< T, TMetricKind::PROPERTY > * AddProperty(const std::string &key, const T &value, const std::string &description="")
Definition: metrics.h:231
virtual std::string ToHumanReadable()
void Update(const T &value)
Metric whose value is a set of items.
void AssertValue(M *metric, const T &value, const string &human_readable)
Definition: metrics-test.cc:33
class SimpleMetric< bool, TMetricKind::PROPERTY > BooleanProperty
Definition: metrics.h:322
int main(int argc, char **argv)
class SimpleMetric< double, TMetricKind::GAUGE > DoubleGauge
Definition: metrics.h:319
void ToJson(bool include_children, rapidjson::Document *document, rapidjson::Value *out_val)
Converts this metric group (and optionally all of its children recursively) to JSON.
Definition: metrics.cc:145
SimpleMetric< T > * AddGauge(const std::string &key, const T &value, const TUnit::type unit=TUnit::NONE, const std::string &description="")
Create a gauge metric object with given key and initial value (owned by this object) ...
Definition: metrics.h:223
string name
Definition: cpu-info.cc:50