1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stdint.h>
8 #include <unistd.h>
9 
10 #include <cobalt-client/cpp/counter-internal.h>
11 #include <cobalt-client/cpp/types-internal.h>
12 #include <fbl/function.h>
13 #include <fbl/string.h>
14 #include <fbl/vector.h>
15 
16 namespace cobalt_client {
17 namespace internal {
18 
19 // Note: Everything on this namespace is internal, no external users should rely
20 // on the behaviour of any of these classes.
21 
22 // Base class for histogram, that provides a thin layer over a collection of buckets
23 // that represent a histogram. Once constructed, unless moved, the class is thread-safe.
24 // All allocations happen when constructed.
25 //
26 // This class is not moveable, not copyable or assignable.
27 // This class is thread-compatible.
28 template <uint32_t num_buckets>
29 class BaseHistogram {
30 public:
31     using Count = uint64_t;
32     using Bucket = uint32_t;
33 
34     BaseHistogram() = default;
35     BaseHistogram(const BaseHistogram&) = delete;
36     BaseHistogram(BaseHistogram&&) = delete;
37     BaseHistogram& operator=(const BaseHistogram&) = delete;
38     BaseHistogram& operator=(BaseHistogram&&) = delete;
39     ~BaseHistogram() = default;
40 
41     // Returns the number of buckets of this histogram.
size()42     constexpr uint32_t size() const { return num_buckets; }
43 
44     void IncrementCount(Bucket bucket, Count val = 1) {
45         ZX_DEBUG_ASSERT_MSG(bucket < size(), "IncrementCount bucket(%u) out of range(%u).", bucket,
46                             size());
47         buckets_[bucket].Increment(val);
48     }
49 
GetCount(uint32_t bucket)50     Count GetCount(uint32_t bucket) const {
51         ZX_DEBUG_ASSERT_MSG(bucket < size(), "GetCount bucket out of range.");
52         return buckets_[bucket].Load();
53     }
54 
55 protected:
56     // Counter for the abs frequency of every histogram bucket.
57     BaseCounter<uint64_t> buckets_[num_buckets];
58 };
59 
60 // Free functions to move logic outside the templated class.
61 
62 // Initializes buckets such that bucket[i].index = i and bucket[i].count = 0.
63 void InitBucketBuffer(HistogramBucket* buckets, uint32_t bucket_count);
64 
65 // Sets |metric_info| to respective values from |options|, and initializes the buckets.
66 void InitLazily(const MetricOptions& options, HistogramBucket* buckets, uint32_t num_buckets,
67                 RemoteMetricInfo* metric_info);
68 
69 // Sets the count of each bucket in |bucket_buffer| to the respective value in
70 // |buckets|, and sets the count in |buckets| to 0.
71 bool HistogramFlush(const RemoteMetricInfo& metric_info, Logger* logger,
72                     BaseCounter<uint64_t>* buckets, HistogramBucket* bucket_buffer,
73                     uint32_t num_buckets);
74 
75 // Undo's an ungoing Flush effects.
76 void HistogramUndoFlush(BaseCounter<uint64_t>* buckets, HistogramBucket* bucket_buffer,
77                         uint32_t num_buckets);
78 
79 // This class provides a histogram which represents a full fledged cobalt metric. The histogram
80 // owner will call |Flush| which is meant to incrementally persist data to cobalt.
81 //
82 // This class is not moveable, copyable or assignable.
83 // This class is thread-compatible.
84 template <uint32_t num_buckets>
85 class RemoteHistogram : public BaseHistogram<num_buckets>, public FlushInterface {
86 public:
87     RemoteHistogram() = default;
RemoteHistogram(const RemoteMetricInfo & metric_info)88     RemoteHistogram(const RemoteMetricInfo& metric_info)
89         : BaseHistogram<num_buckets>(), metric_info_(metric_info) {
90         InitBucketBuffer(bucket_buffer_, num_buckets);
91     }
92     RemoteHistogram(const RemoteHistogram&) = delete;
93     RemoteHistogram(RemoteHistogram&&) = delete;
94     RemoteHistogram& operator=(const RemoteHistogram&) = delete;
95     RemoteHistogram& operator=(RemoteHistogram&&) = delete;
96     ~RemoteHistogram() override = default;
97 
Initialize(const MetricOptions & options)98     void Initialize(const MetricOptions& options) {
99         InitLazily(options, bucket_buffer_, num_buckets, &metric_info_);
100     }
101 
Flush(Logger * logger)102     bool Flush(Logger* logger) override {
103         return HistogramFlush(metric_info_, logger, this->buckets_, bucket_buffer_, num_buckets);
104     }
105 
UndoFlush()106     void UndoFlush() override { HistogramUndoFlush(this->buckets_, bucket_buffer_, num_buckets); }
107 
108     // Returns the metric_id associated with this remote metric.
metric_info()109     const RemoteMetricInfo& metric_info() const { return metric_info_; }
110 
111 private:
112     // Buffer for out of line allocation for the data being sent
113     // through fidl. This buffer is rewritten on every flush, and contains
114     // an entry for each bucket.
115     HistogramBucket bucket_buffer_[num_buckets];
116 
117     // Metric information such as metric_id, event_code and component.
118     RemoteMetricInfo metric_info_;
119 };
120 
121 } // namespace internal
122 } // namespace cobalt_client
123