aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/core/lib
diff options
context:
space:
mode:
authorGravatar A. Unique TensorFlower <gardener@tensorflow.org>2017-11-13 11:24:47 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-11-13 11:31:28 -0800
commit5be2065205be06e491be9d0676ee273f3aba218d (patch)
tree9db15682d9d1b9a916d21e7c83f696e26db2de27 /tensorflow/core/lib
parentaefd2377aec2a970264e77a26aa2bcebdf4e2247 (diff)
Gauge API for monitoring.
- Allowed value types are int64 and string. PiperOrigin-RevId: 175560740
Diffstat (limited to 'tensorflow/core/lib')
-rw-r--r--tensorflow/core/lib/monitoring/collected_metrics.h1
-rw-r--r--tensorflow/core/lib/monitoring/collection_registry.h6
-rw-r--r--tensorflow/core/lib/monitoring/collection_registry_test.cc91
-rw-r--r--tensorflow/core/lib/monitoring/counter.h2
-rw-r--r--tensorflow/core/lib/monitoring/gauge.h215
-rw-r--r--tensorflow/core/lib/monitoring/gauge_test.cc92
-rw-r--r--tensorflow/core/lib/monitoring/metric_def.h12
-rw-r--r--tensorflow/core/lib/monitoring/mobile_gauge.h72
-rw-r--r--tensorflow/core/lib/monitoring/sampler.h5
9 files changed, 490 insertions, 6 deletions
diff --git a/tensorflow/core/lib/monitoring/collected_metrics.h b/tensorflow/core/lib/monitoring/collected_metrics.h
index 3dde55342e..fbef25619f 100644
--- a/tensorflow/core/lib/monitoring/collected_metrics.h
+++ b/tensorflow/core/lib/monitoring/collected_metrics.h
@@ -87,6 +87,7 @@ struct Point {
// The actual metric value, dependent on the value_type enum.
ValueType value_type;
int64 int64_value;
+ string string_value;
HistogramProto histogram_value;
// start_timestamp and end_timestamp indicate the time period over which this
diff --git a/tensorflow/core/lib/monitoring/collection_registry.h b/tensorflow/core/lib/monitoring/collection_registry.h
index 2eff468436..030f8e360a 100644
--- a/tensorflow/core/lib/monitoring/collection_registry.h
+++ b/tensorflow/core/lib/monitoring/collection_registry.h
@@ -219,6 +219,12 @@ inline void CollectValue(const int64& value, Point* const point) {
}
template <>
+inline void CollectValue(const string& value, Point* const point) {
+ point->value_type = ValueType::kString;
+ point->string_value = value;
+}
+
+template <>
inline void CollectValue(const HistogramProto& value, Point* const point) {
point->value_type = ValueType::kHistogram;
// This is inefficient. If and when we hit snags, we can change the API to do
diff --git a/tensorflow/core/lib/monitoring/collection_registry_test.cc b/tensorflow/core/lib/monitoring/collection_registry_test.cc
index 5b9c100690..ca25f508da 100644
--- a/tensorflow/core/lib/monitoring/collection_registry_test.cc
+++ b/tensorflow/core/lib/monitoring/collection_registry_test.cc
@@ -16,6 +16,7 @@ limitations under the License.
#include "tensorflow/core/lib/monitoring/collection_registry.h"
#include "tensorflow/core/lib/monitoring/counter.h"
+#include "tensorflow/core/lib/monitoring/gauge.h"
#include "tensorflow/core/lib/monitoring/sampler.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/protobuf.h"
@@ -176,6 +177,96 @@ TEST(CollectMetricsTest, Counter) {
}
}
+TEST(CollectMetricsTest, Gauge) {
+ auto string_gauge_with_labels =
+ std::unique_ptr<Gauge<string, 2>>(Gauge<string, 2>::New(
+ "/tensorflow/test/string_gauge_with_labels",
+ "String gauge with labels.", "MyLabel0", "MyLabel1"));
+ auto inteter_gauge_without_labels = std::unique_ptr<Gauge<int64, 0>>(
+ Gauge<int64, 0>::New("/tensorflow/test/integer_gauge_without_labels",
+ "Integer gauge without labels."));
+
+ string_gauge_with_labels->GetCell("Label00", "Label10")->Set("test1");
+ string_gauge_with_labels->GetCell("Label01", "Label11")->Set("test2");
+ inteter_gauge_without_labels->GetCell()->Set(7);
+
+ for (const bool collect_metric_descriptors : {true, false}) {
+ SCOPED_TRACE(strings::StrCat("collect_metric_descriptors: ",
+ collect_metric_descriptors));
+
+ auto* collection_registry = CollectionRegistry::Default();
+ CollectionRegistry::CollectMetricsOptions options;
+ options.collect_metric_descriptors = collect_metric_descriptors;
+ const std::unique_ptr<CollectedMetrics> collected_metrics =
+ collection_registry->CollectMetrics(options);
+
+ if (collect_metric_descriptors) {
+ ASSERT_EQ(2, collected_metrics->metric_descriptor_map.size());
+
+ const MetricDescriptor& ld = *collected_metrics->metric_descriptor_map.at(
+ "/tensorflow/test/string_gauge_with_labels");
+ EXPECT_EQ("/tensorflow/test/string_gauge_with_labels", ld.name);
+ EXPECT_EQ("String gauge with labels.", ld.description);
+ ASSERT_EQ(2, ld.label_names.size());
+ EXPECT_EQ("MyLabel0", ld.label_names[0]);
+ EXPECT_EQ("MyLabel1", ld.label_names[1]);
+ EXPECT_EQ(MetricKind::kGauge, ld.metric_kind);
+ EXPECT_EQ(ValueType::kString, ld.value_type);
+
+ const MetricDescriptor& ud = *collected_metrics->metric_descriptor_map.at(
+ "/tensorflow/test/integer_gauge_without_labels");
+ EXPECT_EQ("/tensorflow/test/integer_gauge_without_labels", ud.name);
+ EXPECT_EQ("Integer gauge without labels.", ud.description);
+ ASSERT_EQ(0, ud.label_names.size());
+ EXPECT_EQ(MetricKind::kGauge, ud.metric_kind);
+ EXPECT_EQ(ValueType::kInt64, ud.value_type);
+ } else {
+ EXPECT_EQ(0, collected_metrics->metric_descriptor_map.size());
+ }
+
+ ASSERT_EQ(2, collected_metrics->point_set_map.size());
+
+ const PointSet& lps = *collected_metrics->point_set_map.at(
+ "/tensorflow/test/string_gauge_with_labels");
+ EXPECT_EQ("/tensorflow/test/string_gauge_with_labels", lps.metric_name);
+ ASSERT_EQ(2, lps.points.size());
+ ASSERT_EQ(2, lps.points[0]->labels.size());
+ EXPECT_EQ("MyLabel0", lps.points[0]->labels[0].name);
+ EXPECT_EQ("Label00", lps.points[0]->labels[0].value);
+ EXPECT_EQ("MyLabel1", lps.points[0]->labels[1].name);
+ EXPECT_EQ("Label10", lps.points[0]->labels[1].value);
+ EXPECT_EQ(ValueType::kString, lps.points[0]->value_type);
+ EXPECT_EQ("test1", lps.points[0]->string_value);
+ EXPECT_LT(0, lps.points[0]->start_timestamp_millis);
+ EXPECT_LT(0, lps.points[0]->end_timestamp_millis);
+ EXPECT_GE(lps.points[0]->end_timestamp_millis,
+ lps.points[0]->start_timestamp_millis);
+ ASSERT_EQ(2, lps.points[1]->labels.size());
+ EXPECT_EQ("MyLabel0", lps.points[1]->labels[0].name);
+ EXPECT_EQ("Label01", lps.points[1]->labels[0].value);
+ EXPECT_EQ("MyLabel1", lps.points[1]->labels[1].name);
+ EXPECT_EQ("Label11", lps.points[1]->labels[1].value);
+ EXPECT_EQ(ValueType::kString, lps.points[1]->value_type);
+ EXPECT_EQ("test2", lps.points[1]->string_value);
+ EXPECT_LT(0, lps.points[1]->start_timestamp_millis);
+ EXPECT_LT(0, lps.points[1]->end_timestamp_millis);
+ EXPECT_GE(lps.points[1]->end_timestamp_millis,
+ lps.points[1]->start_timestamp_millis);
+
+ const PointSet& ups = *collected_metrics->point_set_map.at(
+ "/tensorflow/test/integer_gauge_without_labels");
+ EXPECT_EQ("/tensorflow/test/integer_gauge_without_labels", ups.metric_name);
+ ASSERT_EQ(1, ups.points.size());
+ EXPECT_EQ(0, ups.points[0]->labels.size());
+ EXPECT_EQ(ValueType::kInt64, ups.points[0]->value_type);
+ EXPECT_EQ(7, ups.points[0]->int64_value);
+ EXPECT_LT(0, ups.points[0]->start_timestamp_millis);
+ EXPECT_LT(0, ups.points[0]->end_timestamp_millis);
+ EXPECT_GE(ups.points[0]->end_timestamp_millis,
+ ups.points[0]->start_timestamp_millis);
+ }
+}
+
void EqHistograms(const Histogram& expected,
const HistogramProto& actual_proto) {
Histogram actual;
diff --git a/tensorflow/core/lib/monitoring/counter.h b/tensorflow/core/lib/monitoring/counter.h
index 4b84e9d928..7240348a9b 100644
--- a/tensorflow/core/lib/monitoring/counter.h
+++ b/tensorflow/core/lib/monitoring/counter.h
@@ -48,7 +48,7 @@ namespace monitoring {
// This class is thread-safe.
class CounterCell {
public:
- CounterCell(const int64 value) : value_(value) {}
+ CounterCell(int64 value) : value_(value) {}
~CounterCell() {}
// Atomically increments the value by step.
diff --git a/tensorflow/core/lib/monitoring/gauge.h b/tensorflow/core/lib/monitoring/gauge.h
new file mode 100644
index 0000000000..75471cfb22
--- /dev/null
+++ b/tensorflow/core/lib/monitoring/gauge.h
@@ -0,0 +1,215 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_
+#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_
+
+// We replace this implementation with a null implementation for mobile
+// platforms.
+#include "tensorflow/core/platform/platform.h"
+#ifdef IS_MOBILE_PLATFORM
+#include "tensorflow/core/lib/monitoring/mobile_gauge.h"
+#else
+
+#include <array>
+#include <atomic>
+#include <map>
+
+#include "tensorflow/core/lib/monitoring/collection_registry.h"
+#include "tensorflow/core/lib/monitoring/metric_def.h"
+#include "tensorflow/core/platform/macros.h"
+#include "tensorflow/core/platform/mutex.h"
+#include "tensorflow/core/platform/thread_annotations.h"
+#include "tensorflow/core/platform/types.h"
+
+namespace tensorflow {
+namespace monitoring {
+
+// GaugeCell stores each value of a gauge.
+//
+// A cell can be passed off to a module which may repeatedly update it without
+// needing further map-indexing computations. This improves both encapsulation
+// (separate modules can own a cell each, without needing to know about the map
+// to which both cells belong) and performance (since map indexing and
+// associated locking are both avoided).
+//
+// This class is thread-safe.
+template <typename T>
+class GaugeCell {
+ public:
+ explicit GaugeCell(const T& value) : value_(value) {}
+ ~GaugeCell() {}
+
+ // Atomically sets the value.
+ void Set(const T& value) LOCKS_EXCLUDED(mu_);
+
+ // Retrieves the current value.
+ T value() const LOCKS_EXCLUDED(mu_);
+
+ private:
+ T value_ GUARDED_BY(mu_);
+ mutable mutex mu_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(GaugeCell);
+};
+
+// Explicit specialization of GaugeCell<int64>. Compared to the primary
+// template, it uses atomic values as opposed to mutex. This class is
+// thread-safe.
+template <>
+class GaugeCell<int64> {
+ public:
+ explicit GaugeCell(int64 value) : value_(value) {}
+ ~GaugeCell() {}
+
+ // Atomically sets the value.
+ void Set(int64 value);
+
+ // Retrieves the current value.
+ int64 value() const;
+
+ private:
+ std::atomic<int64> value_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(GaugeCell);
+};
+
+// A stateful class for updating a gauge-like metric. Allowed ValueType are
+// int64 and string.
+//
+// This class encapsulates a set of values (or a single value for a label-less
+// metric). Each value is identified by a tuple of labels. The class allows the
+// user to set each value.
+//
+// Gauge allocates storage and maintains a cell for each value. You can
+// retrieve an individual cell using a label-tuple and update it separately.
+// This improves performance since operations related to retrieval, like
+// map-indexing and locking, are avoided.
+//
+// This class is thread-safe.
+template <typename ValueType, int NumLabels>
+class Gauge {
+ public:
+ ~Gauge() {
+ // Deleted here, before the metric_def is destroyed.
+ registration_handle_.reset();
+ }
+
+ // Creates the metric based on the metric-definition arguments.
+ //
+ // Example:
+ //
+ // auto* string_gauge_with_label = Gauge<string,1>::New(
+ // "/tensorflow/string_gauge_with_label",
+ // "String gauge with one label.", "MyLabelName");
+ //
+ // auto* integer_gauge = Gauge<int64, 0>::New("/tensorflow/integer_gauge",
+ // "Integer gauge")
+ template <typename... MetricDefArgs>
+ static Gauge* New(MetricDefArgs&&... metric_def_args);
+
+ // Retrieves the cell for the specified labels, creating it on demand if not
+ // already present.
+ template <typename... Labels>
+ GaugeCell<ValueType>* GetCell(const Labels&... labels) LOCKS_EXCLUDED(mu_);
+
+ private:
+ explicit Gauge(
+ const MetricDef<MetricKind::kGauge, ValueType, NumLabels>& metric_def)
+ : metric_def_(metric_def),
+ registration_handle_(CollectionRegistry::Default()->Register(
+ &metric_def_, [&](MetricCollectorGetter getter) {
+ auto metric_collector = getter.Get(&metric_def_);
+
+ mutex_lock l(mu_);
+ for (const auto& cell : cells_) {
+ metric_collector.CollectValue(cell.first, cell.second.value());
+ }
+ })) {}
+
+ mutable mutex mu_;
+
+ // The metric definition. This will be used to identify the metric when we
+ // register it for collection.
+ const MetricDef<MetricKind::kGauge, ValueType, NumLabels> metric_def_;
+
+ std::unique_ptr<CollectionRegistry::RegistrationHandle> registration_handle_;
+
+ using LabelArray = std::array<string, NumLabels>;
+ std::map<LabelArray, GaugeCell<ValueType> > cells_ GUARDED_BY(mu_);
+
+ TF_DISALLOW_COPY_AND_ASSIGN(Gauge);
+};
+
+////
+// Implementation details follow. API readers may skip.
+////
+template <typename T>
+void GaugeCell<T>::Set(const T& value) {
+ mutex_lock l(mu_);
+ value_ = value;
+}
+
+template <typename T>
+T GaugeCell<T>::value() const {
+ mutex_lock l(mu_);
+ return value_;
+}
+
+inline void GaugeCell<int64>::Set(int64 value) { value_ = value; }
+
+inline int64 GaugeCell<int64>::value() const { return value_; }
+
+template <typename ValueType, int NumLabels>
+template <typename... MetricDefArgs>
+Gauge<ValueType, NumLabels>* Gauge<ValueType, NumLabels>::New(
+ MetricDefArgs&&... metric_def_args) {
+ static_assert(std::is_same<ValueType, int64>::value ||
+ std::is_same<ValueType, string>::value,
+ "Gauge only allows int64 and string types.");
+ return new Gauge<ValueType, NumLabels>(
+ MetricDef<MetricKind::kGauge, ValueType, NumLabels>(
+ std::forward<MetricDefArgs>(metric_def_args)...));
+}
+
+template <typename ValueType, int NumLabels>
+template <typename... Labels>
+GaugeCell<ValueType>* Gauge<ValueType, NumLabels>::GetCell(
+ const Labels&... labels) LOCKS_EXCLUDED(mu_) {
+ // Provides a more informative error message than the one during array
+ // construction below.
+ static_assert(
+ sizeof...(Labels) == NumLabels,
+ "Mismatch between Gauge<ValueType, NumLabels> and number of labels "
+ "provided in GetCell(...).");
+
+ const LabelArray& label_array = {{labels...}};
+ mutex_lock l(mu_);
+ const auto found_it = cells_.find(label_array);
+ if (found_it != cells_.end()) {
+ return &(found_it->second);
+ }
+ return &(cells_
+ .emplace(std::piecewise_construct,
+ std::forward_as_tuple(label_array),
+ std::forward_as_tuple(ValueType()))
+ .first->second);
+}
+
+} // namespace monitoring
+} // namespace tensorflow
+
+#endif // IS_MOBILE_PLATFORM
+#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_
diff --git a/tensorflow/core/lib/monitoring/gauge_test.cc b/tensorflow/core/lib/monitoring/gauge_test.cc
new file mode 100644
index 0000000000..f98cfe2a3b
--- /dev/null
+++ b/tensorflow/core/lib/monitoring/gauge_test.cc
@@ -0,0 +1,92 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include "tensorflow/core/lib/monitoring/gauge.h"
+
+#include "tensorflow/core/platform/test.h"
+
+namespace tensorflow {
+namespace monitoring {
+namespace {
+
+auto* gauge_with_labels = Gauge<int64, 1>::New(
+ "/tensorflow/test/gauge_with_labels", "Gauge with one label.", "MyLabel");
+
+TEST(LabeledGaugeTest, InitializedWithZero) {
+ EXPECT_EQ(0, gauge_with_labels->GetCell("Empty")->value());
+}
+
+TEST(LabeledGaugeTest, GetCell) {
+ auto* cell = gauge_with_labels->GetCell("GetCellOp");
+ EXPECT_EQ(0, cell->value());
+
+ cell->Set(1);
+ EXPECT_EQ(1, cell->value());
+
+ auto* same_cell = gauge_with_labels->GetCell("GetCellOp");
+ EXPECT_EQ(1, same_cell->value());
+
+ same_cell->Set(10);
+ EXPECT_EQ(10, cell->value());
+ EXPECT_EQ(10, same_cell->value());
+}
+
+auto* gauge_without_labels = Gauge<int64, 0>::New(
+ "/tensorflow/test/gauge_without_labels", "Gauge without any labels.");
+
+TEST(UnlabeledGaugeTest, InitializedWithZero) {
+ EXPECT_EQ(0, gauge_without_labels->GetCell()->value());
+}
+
+TEST(UnlabeledGaugeTest, GetCell) {
+ auto* cell = gauge_without_labels->GetCell();
+ EXPECT_EQ(0, cell->value());
+
+ cell->Set(1);
+ EXPECT_EQ(1, cell->value());
+
+ auto* same_cell = gauge_without_labels->GetCell();
+ EXPECT_EQ(1, same_cell->value());
+
+ same_cell->Set(10);
+ EXPECT_EQ(10, cell->value());
+ EXPECT_EQ(10, same_cell->value());
+}
+
+auto* string_gauge = Gauge<string, 0>::New("/tensorflow/test/string_gauge",
+ "Gauge of string value.");
+
+TEST(GaugeOfStringValue, InitializedWithEmptyString) {
+ EXPECT_EQ("", string_gauge->GetCell()->value());
+}
+
+TEST(GaugeOfStringValue, GetCell) {
+ auto* cell = string_gauge->GetCell();
+ EXPECT_EQ("", cell->value());
+
+ cell->Set("foo");
+ EXPECT_EQ("foo", cell->value());
+
+ auto* same_cell = string_gauge->GetCell();
+ EXPECT_EQ("foo", cell->value());
+
+ same_cell->Set("bar");
+ EXPECT_EQ("bar", cell->value());
+ EXPECT_EQ("bar", same_cell->value());
+}
+
+} // namespace
+} // namespace monitoring
+} // namespace tensorflow
diff --git a/tensorflow/core/lib/monitoring/metric_def.h b/tensorflow/core/lib/monitoring/metric_def.h
index 116a73823d..3459c2ab82 100644
--- a/tensorflow/core/lib/monitoring/metric_def.h
+++ b/tensorflow/core/lib/monitoring/metric_def.h
@@ -28,15 +28,16 @@ namespace monitoring {
// The different metric kinds available.
//
// Gauge indicates that the metric's values are instantaneous measurements of a
-// (typically) continuously varying quantity. Examples: a process's current heap
-// size, a queue's current length.
+// (typically) continuously varying quantity or a string value. Examples: a
+// process's current heap size, a queue's current length, the name of the binary
+// used by a process.
//
// Cumulative indicates that the metric's values represent non-negative changes
// over specified time periods. Example: the number of rpc calls to a service.
enum class MetricKind : int { kGauge = 0, kCumulative };
// The type of the metric values.
-enum class ValueType : int { kInt64 = 0, kHistogram };
+enum class ValueType : int { kInt64 = 0, kHistogram, kString };
// Everything in the internal namespace is implementation details. Do not depend
// on this.
@@ -73,6 +74,11 @@ inline ValueType GetValueType<HistogramProto>() {
return ValueType::kHistogram;
}
+template <>
+inline ValueType GetValueType<string>() {
+ return ValueType::kString;
+}
+
} // namespace internal
// Abstract base class for a metric definition.
diff --git a/tensorflow/core/lib/monitoring/mobile_gauge.h b/tensorflow/core/lib/monitoring/mobile_gauge.h
new file mode 100644
index 0000000000..ac13ad35c0
--- /dev/null
+++ b/tensorflow/core/lib/monitoring/mobile_gauge.h
@@ -0,0 +1,72 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+// Null implementation of the Gauge metric for mobile platforms.
+
+#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_
+#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_
+
+#include "tensorflow/core/platform/macros.h"
+#include "tensorflow/core/platform/types.h"
+
+namespace tensorflow {
+namespace monitoring {
+
+// GaugeCell which has a null implementation.
+template <typename T>
+class GaugeCell {
+ public:
+ public:
+ GaugeCell() {}
+ ~GaugeCell() {}
+
+ void Set(const T& value) {}
+ T value() const { return T(); }
+
+ private:
+ TF_DISALLOW_COPY_AND_ASSIGN(GaugeCell);
+};
+
+// Gauge which has a null implementation.
+template <typename ValueType, int NumLabels>
+class Gauge {
+ public:
+ ~Gauge() {}
+
+ template <typename... MetricDefArgs>
+ static Gauge* New(MetricDefArgs&&... metric_def_args) {
+ static_assert(std::is_same<ValueType, int64>::value ||
+ std::is_same<ValueType, string>::value,
+ "Gauge only allows int64 and string types.");
+ return new Gauge();
+ }
+
+ template <typename... Labels>
+ GaugeCell<ValueType>* GetCell(const Labels&... labels) {
+ return &default_gauge_cell_;
+ }
+
+ private:
+ Gauge() {}
+
+ GaugeCell<ValueType> default_gauge_cell_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(Gauge);
+};
+
+} // namespace monitoring
+} // namespace tensorflow
+
+#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_
diff --git a/tensorflow/core/lib/monitoring/sampler.h b/tensorflow/core/lib/monitoring/sampler.h
index 5a4d49d5d4..c7a05428e2 100644
--- a/tensorflow/core/lib/monitoring/sampler.h
+++ b/tensorflow/core/lib/monitoring/sampler.h
@@ -159,9 +159,10 @@ class Sampler {
// Registration handle with the CollectionRegistry.
std::unique_ptr<CollectionRegistry::RegistrationHandle> registration_handle_;
- // We use a std::map here because we give out pointers to the SamplerCells,
- // which need to remain valid even after more cells.
using LabelArray = std::array<string, NumLabels>;
+ // we need a container here that guarantees pointer stability of the value,
+ // namely, the pointer of the value should remain valid even after more cells
+ // are inserted.
std::map<LabelArray, SamplerCell> cells_ GUARDED_BY(mu_);
TF_DISALLOW_COPY_AND_ASSIGN(Sampler);