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 9 #include <fbl/function.h> 10 #include <fbl/string.h> 11 12 namespace cobalt_client { 13 14 // Defines basic set of options for instantiating a metric. 15 struct MetricOptions { 16 17 enum class Mode : uint8_t { 18 // This mode marks a set of options as a placeholder, allowing metric instantiations to 19 // defer initialization to a later stage. 20 kLazy, 21 // Metric is aggregated locally and published via collector interface. 22 kLocal, 23 // Metric deltas are aggregated locally, and sent for global aggregation to a remote 24 // service. 25 kRemote, 26 // Combination of kLocal and kRemote. 27 kRemoteAndLocal, 28 }; 29 SetModeMetricOptions30 void SetMode(Mode mode) { this->mode = mode; } 31 32 // Returns true if the metrics supports remote collection. 33 // This is values collected by another service, such as Cobalt. IsRemoteMetricOptions34 bool IsRemote() const { return mode == Mode::kRemote || mode == Mode::kRemoteAndLocal; } 35 36 // Returns true if the metric supports in process collection. 37 // This is values tied to the process life-time. IsLocalMetricOptions38 bool IsLocal() const { return mode == Mode::kLocal || mode == Mode::kRemoteAndLocal; } 39 40 // Returns true if this does not represent a valid configuration, and is in |kLazy| mode. IsLazyMetricOptions41 bool IsLazy() const { return mode == Mode::kLazy; } 42 43 // Required for local metrics. If not set, and metric is both Local and Remote, 44 // this will be generated from the |metric_id|, |event_code|(if not 0) and |component|(if not 45 // empty). 46 fbl::String name; 47 48 // Provides refined metric collection for remote and local metrics. 49 // Warning: |component| is not yet supported in the backend, so it will be ignored. 50 fbl::String component; 51 52 // Function that translates |metric_id| to a human readable name. 53 // If returns |nullptr| or is unset, the stringified version of |uint32_t| will be used. 54 const char* (*get_metric_name)(uint32_t); 55 56 // Function that translates |event_code| to a human readable name. 57 // If returns |nullptr| or is unset, the stringified version of |uint32_t| will be used. 58 const char* (*get_event_name)(uint32_t); 59 60 // Used by remote metrics to match with the respective unique id for the projects defined 61 // metrics in the backend. 62 uint32_t metric_id; 63 64 // Provides refined metric collection for |kRemote| and |kLocal| metrics. 65 // |event_code| 0 is reserved for Unknown events. 66 // Warning: |event_code| is not yet supported in the backend, so it will be set to 0. 67 uint32_t event_code; 68 69 // Defines whether the metric is local or remote. 70 // Internal use, should not be set manually. 71 Mode mode = Mode::kLazy; 72 }; 73 74 // Describes an histogram, and provides data for mapping a value to a given bucket. 75 // Every histogram contains two additional buckets, one at index 0 and bucket_count + 1. 76 // These buckets are used to store underflow and overflow respectively. 77 // 78 // buckets = [-inf, min_value) ...... [max_value, +inf) 79 // 80 // Parameters are calculated by the factory methods based on the input parameters, 81 // so that expectations are met. 82 // 83 // If using cobalt to flush your observations to the backend, this options should match 84 // your metric definitions for correct behavior. Mismatch with the respective metric definition 85 // will not allow proper collection and aggregation of metrics in the backend. 86 struct HistogramOptions : public MetricOptions { 87 enum class Type { 88 // Each bucket is described in the following form: 89 // range(i) = [ b * i + c, b * {i +1} + c) 90 // i = (val - c) / b 91 kLinear, 92 // Each bucket is described in the following form: 93 // range(i) = [ b * a^i + c, b * a^{i+1} + c) 94 // The cost of this type is O(1), because: 95 // i = floor(log (val - c) - log b)/log a 96 kExponential, 97 }; 98 99 // Returns HistogramOptions that: 100 // * Exponential bucket range with base 2 => lower_bound[i] = a*2^i-1 - 1 101 // * Has underflow bucket from (-inf, 0) 102 // * The first bucket contains [0, 1) 103 // * a is an integer greater or equal to 1. 104 // * if |max| % (2^|bucket_count| - 1): 105 // - Is not 0, then |max| is contained in the last bucket. 106 // - Is 0, then |max| is the lower bound of the overflow bucket. 107 // 108 // For example: 109 // - With bucket_count 12 and max 40950, we get scalar 10, base 2, 110 // and offset -10. 111 // - With bucket_count 12 and max 40960, we get scalar 11, base 2, 112 // and offset -11. 113 static HistogramOptions Exponential(uint32_t bucket_count, int64_t max); 114 115 // Returns HistogramOptions that: 116 // * Exponential bucket range with base 2 => lower_bound[i] = a*2^i-1 - 1 117 // * Has underflow bucket from (-inf, min) 118 // * The first bucket contains [min, min+1) 119 // * a is an integer greater or equal to 1. 120 // * if |max - min| % (2^|bucket_count| - 1): 121 // - Is not, then |max| is contained in the last bucket. 122 // - Is 0, then |max| is the lower bound of the overflow bucket. 123 static HistogramOptions Exponential(uint32_t bucket_count, int64_t min, int64_t max); 124 125 // Returns HistogramOptions that: 126 // * Has an extra underflow bucket. 127 // * Has an extra overflow bucket. 128 // * For every bucket from i = 1 to |bucket_count| has a lower bound defined by: 129 // scalar * (base^(i-1) - 1) + min 130 static HistogramOptions CustomizedExponential(uint32_t bucket_count, uint32_t base, 131 uint32_t scalar, int64_t min); 132 133 // Returns HistogramOptions that: 134 // * Linear bucket range with fixed step size ceil(|max|/|bucket_count|). 135 // * Has underflow bucket from (-inf, 0) 136 // * The first bucket contains [0, step_size) 137 // * |max| is contained in the last bucket if its not a multiple of |bucket_count|. 138 static HistogramOptions Linear(uint32_t bucket_count, int64_t max); 139 140 // Returns HistogramOptions that: 141 // * Linear bucket range with fixed step size ceil(|max|/|bucket_count|). 142 // * Has underflow bucket from (-inf, 0) 143 // * The first bucket contains [0, step_size) 144 // * |max| is contained in the last bucket if its not a multiple of |bucket_count|. 145 static HistogramOptions Linear(uint32_t bucket_count, int64_t min, int64_t max); 146 147 // Returns HistogramOptions that: 148 // * Has an extra underflow bucket. 149 // * Has an extra overflow bucket. 150 // * For every bucket from i = 1 to |bucket_count| has a lower bound defined by: 151 // min + step_size * (i-1) 152 static HistogramOptions CustomizedLinear(uint32_t bucket_count, uint32_t step_size, 153 int64_t min); 154 155 HistogramOptions() = default; 156 HistogramOptions(const HistogramOptions&); 157 158 // Sanity check. 159 bool IsValid() const; 160 161 // This parameters should not be set manually. 162 163 // Function used for mapping a value to a given bucket. 164 uint32_t (*map_fn)(double, uint32_t, const HistogramOptions&) = nullptr; 165 166 // Function used for mapping a bucket to its lowerbound. 167 double (*reverse_map_fn)(uint32_t, uint32_t, const HistogramOptions&) = nullptr; 168 169 // Base to describe the width of each step, in |kExponentialWidth|. 170 double base = 1; 171 172 // Scalar used by the type. This scales the width of each step. 173 double scalar = 1; 174 175 // This matchest offset', which is calculated depending on the histogram type. 176 double offset = 0; 177 178 // Bounds for the histogram. 179 double max_value = 0; 180 181 // Type of the histogram to be constructed. 182 Type type; 183 }; 184 185 } // namespace cobalt_client 186