1 /* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
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 #ifndef TENSORFLOW_CORE_LIB_MONITORING_CELL_READER_H_
16 #define TENSORFLOW_CORE_LIB_MONITORING_CELL_READER_H_
17
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/container/flat_hash_map.h"
24 #include "tensorflow/core/lib/monitoring/cell_reader-inl.h"
25 #include "tensorflow/core/lib/monitoring/collected_metrics.h"
26 #include "tensorflow/core/lib/monitoring/metric_def.h"
27
28 namespace tensorflow {
29 namespace monitoring {
30 namespace testing {
31
32 // `CellReader` is a testing class which allows a user to read the current value
33 // of a tfstreamz cell.
34 //
35 // For tfstreamz metrics like the following:
36 //
37 // ```
38 // auto* test_counter = monitoring::Counter<1>::New(
39 // "/tensorflow/monitoring/test/counter", "label",
40 // "Test tfstreamz counter.");
41 // auto* test_sampler = monitoring::Sampler<2>::New(
42 // "/tensorflow/monitoring/test/sampler", "label1", "label2",
43 // "Test tfstreamz sampler.");
44 // auto* test_string_gauge = monitoring::Gauge<2>::New(
45 // "/tensorflow/monitoring/test/gauge", "label1", "label2",
46 // "Test tfstreamz gauge.");
47 // auto* test_percentiles = monitoring::PercentileSampler<2>::New(
48 // {"/tensorflow/monitoring/test/percentiles", "Test percentiles.",
49 // "label1", "label2"},
50 // /*percentiles=*/{25.0, 50.0, 80.0, 90.0, 95.0, 99.0},
51 // /*max_samples=*/1024,
52 // monitoring::UnitOfMeasure::kNumber);
53 // ```
54 //
55 // one could read the exported tfstreamz values using a `CellReader` like this:
56 //
57 // ```
58 // using tensorflow::monitoring::testing::Histogram;
59 // using tensorflow::monitoring::testing::Percentiles;
60 //
61 // CellReader<int64_t> counter_reader("/tensorflow/monitoring/test/counter");
62 // CellReader<Histogram> sampler_reader("/tensorflow/monitoring/test/sampler");
63 // CellReader<std::string> gauge_reader("/tensorflow/monitoring/test/gauge");
64 // CellReader<Percentiles> percentiles_reader(
65 // "/tensorflow/monitoring/test/percentiles");
66 // EXPECT_EQ(counter_reader.Delta("label_value"), 0);
67 // EXPECT_FLOAT_EQ(sampler_reader.Delta("x", "y").num(), 0.0);
68 // EXPECT_EQ(gauge_reader.Delta("x", "y"), "");
69 // EXPECT_EQ(percentiles_reader.Delta("x", "y").num(), 0);
70 //
71 // CodeThatUpdateMetrics();
72 // EXPECT_EQ(counter_reader.Delta("label_value"), 5);
73 // Histogram histogram = sampler_reader.Delta("x", "y");
74 // EXPECT_FLOAT_EQ(histogram.num(), 5.0);
75 // EXPECT_GT(histogram.sum(), 0.0);
76 // EXPECT_EQ(gauge_reader.Delta("x", "y"), "gauge value");
77 // EXPECT_EQ(percentiles_reader.Delta("x", "y").num(), 5);
78 // ```
79 template <typename ValueType>
80 class CellReader {
81 public:
82 // Constructs a `CellReader` that reads values exported for `metric_name`.
83 //
84 // REQUIRES: a tfstreamz with `metric_name` exists. Otherwise, the
85 // `CellReader` will construct without issue, but the `Read` and `Delta` calls
86 // will CHECK-fail.
87 explicit CellReader(const std::string& metric_name);
88 virtual ~CellReader() = default;
89 CellReader(const CellReader&) = delete;
90 CellReader& operator=(const CellReader&) = delete;
91
92 // Returns the current value of the cell with the given `labels`. A metric can
93 // have zero or more labels, depending on its definition. If the metric has
94 // not been modified, it returns a default value appropriate for `ValueType`.
95 //
96 // REQUIRES: The tfstreamz exists, and `labels` contains a correct number of
97 // labels per tfstreamz definition. Otherwise, it will CHECK-fail.
98 template <typename... LabelType>
99 ValueType Read(const LabelType&... labels);
100
101 // Returns the difference in the value of this cell since the last time
102 // `Delta()` was called for this cell, or when the `CellReader` was created,
103 // whichever was most recent. If the metric has not been modified, it returns
104 // a default value appropriate for `ValueType`. `Delta` is not supported for
105 // string and bool gauges.
106 //
107 // REQUIRES: The tfstreamz exists, `labels` contains a correct number of
108 // labels per tfstreamz definition, and the ValueType is not string or bool.
109 // Otherwise, it will CHECK-fail.
110 template <typename... LabelType>
111 ValueType Delta(const LabelType&... labels);
112
113 private:
114 const std::string metric_name_;
115
116 // Metrics collected at the time of construction. It is needed because data
117 // may have been collected when this object is constructed. The initial values
118 // need to be subtracted from the result of the `Read()` call to compute the
119 // correct values.
120 std::unique_ptr<CollectedMetrics> initial_metrics_;
121
122 // Records the value of the cells since the last time `Delta()` was called.
123 // This is used to compute the next delta value.
124 absl::flat_hash_map<std::vector<std::string>, ValueType> delta_map_;
125 };
126
127 template <typename ValueType>
CellReader(const std::string & metric_name)128 CellReader<ValueType>::CellReader(const std::string& metric_name)
129 : metric_name_(metric_name), initial_metrics_(internal::CollectMetrics()) {}
130
131 template <typename ValueType>
132 template <typename... LabelType>
Read(const LabelType &...labels)133 ValueType CellReader<ValueType>::Read(const LabelType&... labels) {
134 std::vector<std::string> labels_list{labels...};
135 std::unique_ptr<CollectedMetrics> metrics = internal::CollectMetrics();
136 ValueType value = internal::GetLatestValueOrDefault<ValueType>(
137 *metrics, metric_name_, labels_list);
138 if (internal::GetMetricKind(*metrics, metric_name_) == MetricKind::kGauge) {
139 return value;
140 }
141 ValueType initial_value = internal::GetLatestValueOrDefault<ValueType>(
142 *initial_metrics_, metric_name_, labels_list);
143 return internal::GetDelta<ValueType>(value, initial_value);
144 }
145
146 template <typename ValueType>
147 template <typename... LabelType>
Delta(const LabelType &...labels)148 ValueType CellReader<ValueType>::Delta(const LabelType&... labels) {
149 std::vector<std::string> labels_list{labels...};
150 std::unique_ptr<CollectedMetrics> metrics = internal::CollectMetrics();
151 ValueType value = internal::GetLatestValueOrDefault<ValueType>(
152 *metrics, metric_name_, labels_list);
153 ValueType initial_value = internal::GetLatestValueOrDefault<ValueType>(
154 *initial_metrics_, metric_name_, labels_list);
155 if (delta_map_.contains(labels_list)) {
156 initial_value = delta_map_[labels_list];
157 }
158 delta_map_[labels_list] = value;
159 return internal::GetDelta<ValueType>(value, initial_value);
160 }
161
162 } // namespace testing
163 } // namespace monitoring
164 } // namespace tensorflow
165
166 #endif // TENSORFLOW_CORE_LIB_MONITORING_CELL_READER_H_
167