xref: /aosp_15_r20/external/tensorflow/tensorflow/core/lib/monitoring/cell_reader.h (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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