xref: /aosp_15_r20/external/pigweed/pw_metric/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_metric:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker=========
4*61c4878aSAndroid Build Coastguard Workerpw_metric
5*61c4878aSAndroid Build Coastguard Worker=========
6*61c4878aSAndroid Build Coastguard Worker
7*61c4878aSAndroid Build Coastguard Worker.. attention::
8*61c4878aSAndroid Build Coastguard Worker   This module is **not yet production ready**; ask us if you are interested in
9*61c4878aSAndroid Build Coastguard Worker   using it out or have ideas about how to improve it.
10*61c4878aSAndroid Build Coastguard Worker
11*61c4878aSAndroid Build Coastguard Worker--------
12*61c4878aSAndroid Build Coastguard WorkerOverview
13*61c4878aSAndroid Build Coastguard Worker--------
14*61c4878aSAndroid Build Coastguard WorkerPigweed's metric module is a **lightweight manual instrumentation system** for
15*61c4878aSAndroid Build Coastguard Workertracking system health metrics like counts or set values. For example,
16*61c4878aSAndroid Build Coastguard Worker``pw_metric`` could help with tracking the number of I2C bus writes, or the
17*61c4878aSAndroid Build Coastguard Workernumber of times a buffer was filled before it could drain in time, or safely
18*61c4878aSAndroid Build Coastguard Workerincrementing counters from ISRs.
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard WorkerKey features of ``pw_metric``:
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker- **Tokenized names** - Names are tokenized using the ``pw_tokenizer`` enabling
23*61c4878aSAndroid Build Coastguard Worker  long metric names that don't bloat your binary.
24*61c4878aSAndroid Build Coastguard Worker
25*61c4878aSAndroid Build Coastguard Worker- **Tree structure** - Metrics can form a tree, enabling grouping of related
26*61c4878aSAndroid Build Coastguard Worker  metrics for clearer organization.
27*61c4878aSAndroid Build Coastguard Worker
28*61c4878aSAndroid Build Coastguard Worker- **Per object collection** - Metrics and groups can live on object instances
29*61c4878aSAndroid Build Coastguard Worker  and be flexibly combined with metrics from other instances.
30*61c4878aSAndroid Build Coastguard Worker
31*61c4878aSAndroid Build Coastguard Worker- **Global registration** - For legacy code bases or just because it's easier,
32*61c4878aSAndroid Build Coastguard Worker  ``pw_metric`` supports automatic aggregation of metrics. This is optional but
33*61c4878aSAndroid Build Coastguard Worker  convenient in many cases.
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker- **Simple design** - There are only two core data structures: ``Metric`` and
36*61c4878aSAndroid Build Coastguard Worker  ``Group``, which are both simple to understand and use. The only type of
37*61c4878aSAndroid Build Coastguard Worker  metric supported is ``uint32_t`` and ``float``. This module does not support
38*61c4878aSAndroid Build Coastguard Worker  complicated aggregations like running average or min/max.
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard WorkerExample: Instrumenting a single object
41*61c4878aSAndroid Build Coastguard Worker--------------------------------------
42*61c4878aSAndroid Build Coastguard WorkerThe below example illustrates what instrumenting a class with a metric group
43*61c4878aSAndroid Build Coastguard Workerand metrics might look like. In this case, the object's
44*61c4878aSAndroid Build Coastguard Worker``MySubsystem::metrics()`` member is not globally registered; the user is on
45*61c4878aSAndroid Build Coastguard Workertheir own for combining this subsystem's metrics with others.
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
48*61c4878aSAndroid Build Coastguard Worker
49*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
50*61c4878aSAndroid Build Coastguard Worker
51*61c4878aSAndroid Build Coastguard Worker   class MySubsystem {
52*61c4878aSAndroid Build Coastguard Worker    public:
53*61c4878aSAndroid Build Coastguard Worker     void DoSomething() {
54*61c4878aSAndroid Build Coastguard Worker       attempts_.Increment();
55*61c4878aSAndroid Build Coastguard Worker       if (ActionSucceeds()) {
56*61c4878aSAndroid Build Coastguard Worker         successes_.Increment();
57*61c4878aSAndroid Build Coastguard Worker       }
58*61c4878aSAndroid Build Coastguard Worker     }
59*61c4878aSAndroid Build Coastguard Worker     Group& metrics() { return metrics_; }
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker    private:
62*61c4878aSAndroid Build Coastguard Worker     PW_METRIC_GROUP(metrics_, "my_subsystem");
63*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, attempts_, "attempts", 0u);
64*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, successes_, "successes", 0u);
65*61c4878aSAndroid Build Coastguard Worker   };
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard WorkerThe metrics subsystem has no canonical output format at this time, but a JSON
68*61c4878aSAndroid Build Coastguard Workerdump might look something like this:
69*61c4878aSAndroid Build Coastguard Worker
70*61c4878aSAndroid Build Coastguard Worker.. code-block:: json
71*61c4878aSAndroid Build Coastguard Worker
72*61c4878aSAndroid Build Coastguard Worker   {
73*61c4878aSAndroid Build Coastguard Worker     "my_subsystem" : {
74*61c4878aSAndroid Build Coastguard Worker       "successes" : 1000,
75*61c4878aSAndroid Build Coastguard Worker       "attempts" : 1200,
76*61c4878aSAndroid Build Coastguard Worker     }
77*61c4878aSAndroid Build Coastguard Worker   }
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard WorkerIn this case, every instance of ``MySubsystem`` will have unique counters.
80*61c4878aSAndroid Build Coastguard Worker
81*61c4878aSAndroid Build Coastguard WorkerExample: Instrumenting a legacy codebase
82*61c4878aSAndroid Build Coastguard Worker----------------------------------------
83*61c4878aSAndroid Build Coastguard WorkerA common situation in embedded development is **debugging legacy code** or code
84*61c4878aSAndroid Build Coastguard Workerwhich is hard to change; where it is perhaps impossible to plumb metrics
85*61c4878aSAndroid Build Coastguard Workerobjects around with dependency injection. The alternative to plumbing metrics
86*61c4878aSAndroid Build Coastguard Workeris to register the metrics through a global mechanism. ``pw_metric`` supports
87*61c4878aSAndroid Build Coastguard Workerthis use case. For example:
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker**Before instrumenting:**
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker   // This code was passed down from generations of developers before; no one
94*61c4878aSAndroid Build Coastguard Worker   // knows what it does or how it works. But it needs to be fixed!
95*61c4878aSAndroid Build Coastguard Worker   void OldCodeThatDoesntWorkButWeDontKnowWhy() {
96*61c4878aSAndroid Build Coastguard Worker     if (some_variable) {
97*61c4878aSAndroid Build Coastguard Worker       DoSomething();
98*61c4878aSAndroid Build Coastguard Worker     } else {
99*61c4878aSAndroid Build Coastguard Worker       DoSomethingElse();
100*61c4878aSAndroid Build Coastguard Worker     }
101*61c4878aSAndroid Build Coastguard Worker   }
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker**After instrumenting:**
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/global.h"
108*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GLOBAL(legacy_do_something, "legacy_do_something");
111*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GLOBAL(legacy_do_something_else, "legacy_do_something_else");
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker   // This code was passed down from generations of developers before; no one
114*61c4878aSAndroid Build Coastguard Worker   // knows what it does or how it works. But it needs to be fixed!
115*61c4878aSAndroid Build Coastguard Worker   void OldCodeThatDoesntWorkButWeDontKnowWhy() {
116*61c4878aSAndroid Build Coastguard Worker     if (some_variable) {
117*61c4878aSAndroid Build Coastguard Worker       legacy_do_something.Increment();
118*61c4878aSAndroid Build Coastguard Worker       DoSomething();
119*61c4878aSAndroid Build Coastguard Worker     } else {
120*61c4878aSAndroid Build Coastguard Worker       legacy_do_something_else.Increment();
121*61c4878aSAndroid Build Coastguard Worker       DoSomethingElse();
122*61c4878aSAndroid Build Coastguard Worker     }
123*61c4878aSAndroid Build Coastguard Worker   }
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard WorkerIn this case, the developer merely had to add the metrics header, define some
126*61c4878aSAndroid Build Coastguard Workermetrics, and then start incrementing them. These metrics will be available
127*61c4878aSAndroid Build Coastguard Workerglobally through the ``pw::metric::global_metrics`` object defined in
128*61c4878aSAndroid Build Coastguard Worker``pw_metric/global.h``.
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard WorkerWhy not just use simple counter variables?
131*61c4878aSAndroid Build Coastguard Worker------------------------------------------
132*61c4878aSAndroid Build Coastguard WorkerOne might wonder what the point of leveraging a metric library is when it is
133*61c4878aSAndroid Build Coastguard Workertrivial to make some global variables and print them out. There are a few
134*61c4878aSAndroid Build Coastguard Workerreasons:
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker- **Metrics offload** - To make it easy to get metrics off-device by sharing
137*61c4878aSAndroid Build Coastguard Worker  the infrastructure for offloading.
138*61c4878aSAndroid Build Coastguard Worker
139*61c4878aSAndroid Build Coastguard Worker- **Consistent format** - To get the metrics in a consistent format (e.g.
140*61c4878aSAndroid Build Coastguard Worker  protobuf or JSON) for analysis
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker- **Uncoordinated collection** - To provide a simple and reliable way for
143*61c4878aSAndroid Build Coastguard Worker  developers on a team to all collect metrics for their subsystems, without
144*61c4878aSAndroid Build Coastguard Worker  having to coordinate to offload. This could extend to code in libraries
145*61c4878aSAndroid Build Coastguard Worker  written by other teams.
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker- **Pre-boot or interrupt visibility** - Some of the most challenging bugs come
148*61c4878aSAndroid Build Coastguard Worker  from early system boot when not all system facilities are up (e.g. logging or
149*61c4878aSAndroid Build Coastguard Worker  UART). In those cases, metrics provide a low-overhead approach to understand
150*61c4878aSAndroid Build Coastguard Worker  what is happening. During early boot, metrics can be incremented, then after
151*61c4878aSAndroid Build Coastguard Worker  boot dumping the metrics provides insights into what happened. While basic
152*61c4878aSAndroid Build Coastguard Worker  counter variables can work in these contexts too, one still has to deal with
153*61c4878aSAndroid Build Coastguard Worker  the offloading problem; which the library handles.
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard Worker---------------------
156*61c4878aSAndroid Build Coastguard WorkerMetrics API reference
157*61c4878aSAndroid Build Coastguard Worker---------------------
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard WorkerThe metrics API consists of just a few components:
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker- The core data structures ``pw::metric::Metric`` and ``pw::metric::Group``
162*61c4878aSAndroid Build Coastguard Worker- The macros for scoped metrics and groups ``PW_METRIC`` and
163*61c4878aSAndroid Build Coastguard Worker  ``PW_METRIC_GROUP``
164*61c4878aSAndroid Build Coastguard Worker- The macros for globally registered metrics and groups
165*61c4878aSAndroid Build Coastguard Worker  ``PW_METRIC_GLOBAL`` and ``PW_METRIC_GROUP_GLOBAL``
166*61c4878aSAndroid Build Coastguard Worker- The global groups and metrics list: ``pw::metric::global_groups`` and
167*61c4878aSAndroid Build Coastguard Worker  ``pw::metric::global_metrics``.
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard WorkerMetric
170*61c4878aSAndroid Build Coastguard Worker------
171*61c4878aSAndroid Build Coastguard WorkerThe ``pw::metric::Metric`` provides:
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker- A 31-bit tokenized name
174*61c4878aSAndroid Build Coastguard Worker- A 1-bit discriminator for int or float
175*61c4878aSAndroid Build Coastguard Worker- A 32-bit payload (int or float)
176*61c4878aSAndroid Build Coastguard Worker- A 32-bit next pointer (intrusive list)
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard WorkerThe metric object is 12 bytes on 32-bit platforms.
179*61c4878aSAndroid Build Coastguard Worker
180*61c4878aSAndroid Build Coastguard Worker.. cpp:class:: pw::metric::Metric
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker   .. cpp:function:: Increment(uint32_t amount = 0)
183*61c4878aSAndroid Build Coastguard Worker
184*61c4878aSAndroid Build Coastguard Worker      Increment the metric by the given amount. Results in undefined behaviour if
185*61c4878aSAndroid Build Coastguard Worker      the metric is not of type int.
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker   .. cpp:function:: Set(uint32_t value)
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker      Set the metric to the given value. Results in undefined behaviour if the
190*61c4878aSAndroid Build Coastguard Worker      metric is not of type int.
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker   .. cpp:function:: Set(float value)
193*61c4878aSAndroid Build Coastguard Worker
194*61c4878aSAndroid Build Coastguard Worker      Set the metric to the given value. Results in undefined behaviour if the
195*61c4878aSAndroid Build Coastguard Worker      metric is not of type float.
196*61c4878aSAndroid Build Coastguard Worker
197*61c4878aSAndroid Build Coastguard Worker.. _module-pw_metric-group:
198*61c4878aSAndroid Build Coastguard Worker
199*61c4878aSAndroid Build Coastguard WorkerGroup
200*61c4878aSAndroid Build Coastguard Worker-----
201*61c4878aSAndroid Build Coastguard WorkerThe ``pw::metric::Group`` object is simply:
202*61c4878aSAndroid Build Coastguard Worker
203*61c4878aSAndroid Build Coastguard Worker- A name for the group
204*61c4878aSAndroid Build Coastguard Worker- A list of children groups
205*61c4878aSAndroid Build Coastguard Worker- A list of leaf metrics groups
206*61c4878aSAndroid Build Coastguard Worker- A 32-bit next pointer (intrusive list)
207*61c4878aSAndroid Build Coastguard Worker
208*61c4878aSAndroid Build Coastguard WorkerThe group object is 16 bytes on 32-bit platforms.
209*61c4878aSAndroid Build Coastguard Worker
210*61c4878aSAndroid Build Coastguard Worker.. cpp:class:: pw::metric::Group
211*61c4878aSAndroid Build Coastguard Worker
212*61c4878aSAndroid Build Coastguard Worker   .. cpp:function:: Dump(int indent_level = 0)
213*61c4878aSAndroid Build Coastguard Worker
214*61c4878aSAndroid Build Coastguard Worker      Recursively dump a metrics group to ``pw_log``. Produces output like:
215*61c4878aSAndroid Build Coastguard Worker
216*61c4878aSAndroid Build Coastguard Worker      .. code-block:: none
217*61c4878aSAndroid Build Coastguard Worker
218*61c4878aSAndroid Build Coastguard Worker         "$6doqFw==": {
219*61c4878aSAndroid Build Coastguard Worker           "$05OCZw==": {
220*61c4878aSAndroid Build Coastguard Worker             "$VpPfzg==": 1,
221*61c4878aSAndroid Build Coastguard Worker             "$LGPMBQ==": 1.000000,
222*61c4878aSAndroid Build Coastguard Worker             "$+iJvUg==": 5,
223*61c4878aSAndroid Build Coastguard Worker           }
224*61c4878aSAndroid Build Coastguard Worker           "$9hPNxw==": 65,
225*61c4878aSAndroid Build Coastguard Worker           "$oK7HmA==": 13,
226*61c4878aSAndroid Build Coastguard Worker           "$FCM4qQ==": 0,
227*61c4878aSAndroid Build Coastguard Worker         }
228*61c4878aSAndroid Build Coastguard Worker
229*61c4878aSAndroid Build Coastguard Worker      Note the metric names are tokenized with base64. Decoding requires using
230*61c4878aSAndroid Build Coastguard Worker      the Pigweed detokenizer. With a detokenizing-enabled logger, you could get
231*61c4878aSAndroid Build Coastguard Worker      something like:
232*61c4878aSAndroid Build Coastguard Worker
233*61c4878aSAndroid Build Coastguard Worker      .. code-block:: none
234*61c4878aSAndroid Build Coastguard Worker
235*61c4878aSAndroid Build Coastguard Worker         "i2c_1": {
236*61c4878aSAndroid Build Coastguard Worker           "gyro": {
237*61c4878aSAndroid Build Coastguard Worker             "num_sampleses": 1,
238*61c4878aSAndroid Build Coastguard Worker             "init_time_us": 1.000000,
239*61c4878aSAndroid Build Coastguard Worker             "initialized": 5,
240*61c4878aSAndroid Build Coastguard Worker           }
241*61c4878aSAndroid Build Coastguard Worker           "bus_errors": 65,
242*61c4878aSAndroid Build Coastguard Worker           "transactions": 13,
243*61c4878aSAndroid Build Coastguard Worker           "bytes_sent": 0,
244*61c4878aSAndroid Build Coastguard Worker         }
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard WorkerMacros
247*61c4878aSAndroid Build Coastguard Worker------
248*61c4878aSAndroid Build Coastguard WorkerThe **macros are the primary mechanism for creating metrics**, and should be
249*61c4878aSAndroid Build Coastguard Workerused instead of directly constructing metrics or groups. The macros handle
250*61c4878aSAndroid Build Coastguard Workertokenizing the metric and group names.
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC(identifier, name, value)
253*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC(group, identifier, name, value)
254*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_STATIC(identifier, name, value)
255*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_STATIC(group, identifier, name, value)
256*61c4878aSAndroid Build Coastguard Worker
257*61c4878aSAndroid Build Coastguard Worker   Declare a metric, optionally adding it to a group.
258*61c4878aSAndroid Build Coastguard Worker
259*61c4878aSAndroid Build Coastguard Worker   - **identifier** - An identifier name for the created variable or member.
260*61c4878aSAndroid Build Coastguard Worker     For example: ``i2c_transactions`` might be used as a local or global
261*61c4878aSAndroid Build Coastguard Worker     metric; inside a class, could be named according to members
262*61c4878aSAndroid Build Coastguard Worker     (``i2c_transactions_`` for Google's C++ style).
263*61c4878aSAndroid Build Coastguard Worker   - **name** - The string name for the metric. This will be tokenized. There
264*61c4878aSAndroid Build Coastguard Worker     are no restrictions on the contents of the name; however, consider
265*61c4878aSAndroid Build Coastguard Worker     restricting these to be valid C++ identifiers to ease integration with
266*61c4878aSAndroid Build Coastguard Worker     other systems.
267*61c4878aSAndroid Build Coastguard Worker   - **value** - The initial value for the metric. Must be either a floating
268*61c4878aSAndroid Build Coastguard Worker     point value (e.g. ``3.2f``) or unsigned int (e.g. ``21u``).
269*61c4878aSAndroid Build Coastguard Worker   - **group** - A ``pw::metric::Group`` instance. If provided, the metric is
270*61c4878aSAndroid Build Coastguard Worker     added to the given group.
271*61c4878aSAndroid Build Coastguard Worker
272*61c4878aSAndroid Build Coastguard Worker   The macro declares a variable or member named "name" with type
273*61c4878aSAndroid Build Coastguard Worker   ``pw::metric::Metric``, and works in three contexts: global, local, and
274*61c4878aSAndroid Build Coastguard Worker   member.
275*61c4878aSAndroid Build Coastguard Worker
276*61c4878aSAndroid Build Coastguard Worker   If the ``_STATIC`` variant is used, the macro declares a variable with static
277*61c4878aSAndroid Build Coastguard Worker   storage. These can be used in function scopes, but not in classes.
278*61c4878aSAndroid Build Coastguard Worker
279*61c4878aSAndroid Build Coastguard Worker   1. At global scope:
280*61c4878aSAndroid Build Coastguard Worker
281*61c4878aSAndroid Build Coastguard Worker      .. code-block:: cpp
282*61c4878aSAndroid Build Coastguard Worker
283*61c4878aSAndroid Build Coastguard Worker         PW_METRIC(foo, "foo", 15.5f);
284*61c4878aSAndroid Build Coastguard Worker
285*61c4878aSAndroid Build Coastguard Worker         void MyFunc() {
286*61c4878aSAndroid Build Coastguard Worker           foo.Increment();
287*61c4878aSAndroid Build Coastguard Worker         }
288*61c4878aSAndroid Build Coastguard Worker
289*61c4878aSAndroid Build Coastguard Worker   2. At local function or member function scope:
290*61c4878aSAndroid Build Coastguard Worker
291*61c4878aSAndroid Build Coastguard Worker      .. code-block:: cpp
292*61c4878aSAndroid Build Coastguard Worker
293*61c4878aSAndroid Build Coastguard Worker         void MyFunc() {
294*61c4878aSAndroid Build Coastguard Worker           PW_METRIC(foo, "foo", 15.5f);
295*61c4878aSAndroid Build Coastguard Worker           foo.Increment();
296*61c4878aSAndroid Build Coastguard Worker           // foo goes out of scope here; be careful!
297*61c4878aSAndroid Build Coastguard Worker         }
298*61c4878aSAndroid Build Coastguard Worker
299*61c4878aSAndroid Build Coastguard Worker   3. At member level inside a class or struct:
300*61c4878aSAndroid Build Coastguard Worker
301*61c4878aSAndroid Build Coastguard Worker      .. code-block:: cpp
302*61c4878aSAndroid Build Coastguard Worker
303*61c4878aSAndroid Build Coastguard Worker         struct MyStructy {
304*61c4878aSAndroid Build Coastguard Worker           void DoSomething() {
305*61c4878aSAndroid Build Coastguard Worker             somethings.Increment();
306*61c4878aSAndroid Build Coastguard Worker           }
307*61c4878aSAndroid Build Coastguard Worker           // Every instance of MyStructy will have a separate somethings counter.
308*61c4878aSAndroid Build Coastguard Worker           PW_METRIC(somethings, "somethings", 0u);
309*61c4878aSAndroid Build Coastguard Worker         }
310*61c4878aSAndroid Build Coastguard Worker
311*61c4878aSAndroid Build Coastguard Worker   You can also put a metric into a group with the macro. Metrics can belong to
312*61c4878aSAndroid Build Coastguard Worker   strictly one group, otherwise an assertion will fail. Example:
313*61c4878aSAndroid Build Coastguard Worker
314*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
315*61c4878aSAndroid Build Coastguard Worker
316*61c4878aSAndroid Build Coastguard Worker      PW_METRIC_GROUP(my_group, "my_group");
317*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, foo, "foo", 0.2f);
318*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, bar, "bar", 44000u);
319*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, zap, "zap", 3.14f);
320*61c4878aSAndroid Build Coastguard Worker
321*61c4878aSAndroid Build Coastguard Worker   .. tip::
322*61c4878aSAndroid Build Coastguard Worker      If you want a globally registered metric, see ``pw_metric/global.h``; in
323*61c4878aSAndroid Build Coastguard Worker      that context, metrics are globally registered without the need to
324*61c4878aSAndroid Build Coastguard Worker      centrally register in a single place.
325*61c4878aSAndroid Build Coastguard Worker
326*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GROUP(identifier, name)
327*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GROUP(parent_group, identifier, name)
328*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GROUP_STATIC(identifier, name)
329*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GROUP_STATIC(parent_group, identifier, name)
330*61c4878aSAndroid Build Coastguard Worker
331*61c4878aSAndroid Build Coastguard Worker   Declares a ``pw::metric::Group`` with name name; the name is tokenized.
332*61c4878aSAndroid Build Coastguard Worker   Works similar to ``PW_METRIC`` and can be used in the same contexts (global,
333*61c4878aSAndroid Build Coastguard Worker   local, and member). Optionally, the group can be added to a parent group.
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard Worker   If the ``_STATIC`` variant is used, the macro declares a variable with static
336*61c4878aSAndroid Build Coastguard Worker   storage. These can be used in function scopes, but not in classes.
337*61c4878aSAndroid Build Coastguard Worker
338*61c4878aSAndroid Build Coastguard Worker   Example:
339*61c4878aSAndroid Build Coastguard Worker
340*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
341*61c4878aSAndroid Build Coastguard Worker
342*61c4878aSAndroid Build Coastguard Worker      PW_METRIC_GROUP(my_group, "my_group");
343*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, foo, "foo", 0.2f);
344*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, bar, "bar", 44000u);
345*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(my_group, zap, "zap", 3.14f);
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GLOBAL(identifier, name, value)
348*61c4878aSAndroid Build Coastguard Worker
349*61c4878aSAndroid Build Coastguard Worker   Declare a ``pw::metric::Metric`` with name name, and register it in the
350*61c4878aSAndroid Build Coastguard Worker   global metrics list ``pw::metric::global_metrics``.
351*61c4878aSAndroid Build Coastguard Worker
352*61c4878aSAndroid Build Coastguard Worker   Example:
353*61c4878aSAndroid Build Coastguard Worker
354*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
355*61c4878aSAndroid Build Coastguard Worker
356*61c4878aSAndroid Build Coastguard Worker      #include "pw_metric/metric.h"
357*61c4878aSAndroid Build Coastguard Worker      #include "pw_metric/global.h"
358*61c4878aSAndroid Build Coastguard Worker
359*61c4878aSAndroid Build Coastguard Worker      // No need to coordinate collection of foo and bar; they're autoregistered.
360*61c4878aSAndroid Build Coastguard Worker      PW_METRIC_GLOBAL(foo, "foo", 0.2f);
361*61c4878aSAndroid Build Coastguard Worker      PW_METRIC_GLOBAL(bar, "bar", 44000u);
362*61c4878aSAndroid Build Coastguard Worker
363*61c4878aSAndroid Build Coastguard Worker   Note that metrics defined with ``PW_METRIC_GLOBAL`` should never be added to
364*61c4878aSAndroid Build Coastguard Worker   groups defined with ``PW_METRIC_GROUP_GLOBAL``. Each metric can only belong
365*61c4878aSAndroid Build Coastguard Worker   to one group, and metrics defined with ``PW_METRIC_GLOBAL`` are
366*61c4878aSAndroid Build Coastguard Worker   pre-registered with the global metrics list.
367*61c4878aSAndroid Build Coastguard Worker
368*61c4878aSAndroid Build Coastguard Worker   .. attention::
369*61c4878aSAndroid Build Coastguard Worker      Do not create ``PW_METRIC_GLOBAL`` instances anywhere other than global
370*61c4878aSAndroid Build Coastguard Worker      scope. Putting these on an instance (member context) would lead to dangling
371*61c4878aSAndroid Build Coastguard Worker      pointers and misery. Metrics are never deleted or unregistered!
372*61c4878aSAndroid Build Coastguard Worker
373*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_GROUP_GLOBAL(identifier, name, value)
374*61c4878aSAndroid Build Coastguard Worker
375*61c4878aSAndroid Build Coastguard Worker   Declare a ``pw::metric::Group`` with name name, and register it in the
376*61c4878aSAndroid Build Coastguard Worker   global metric groups list ``pw::metric::global_groups``.
377*61c4878aSAndroid Build Coastguard Worker
378*61c4878aSAndroid Build Coastguard Worker   Note that metrics created with ``PW_METRIC_GLOBAL`` should never be added to
379*61c4878aSAndroid Build Coastguard Worker   groups! Instead, just create a freestanding metric and register it into the
380*61c4878aSAndroid Build Coastguard Worker   global group (like in the example below).
381*61c4878aSAndroid Build Coastguard Worker
382*61c4878aSAndroid Build Coastguard Worker   Example:
383*61c4878aSAndroid Build Coastguard Worker
384*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
385*61c4878aSAndroid Build Coastguard Worker
386*61c4878aSAndroid Build Coastguard Worker      #include "pw_metric/metric.h"
387*61c4878aSAndroid Build Coastguard Worker      #include "pw_metric/global.h"
388*61c4878aSAndroid Build Coastguard Worker
389*61c4878aSAndroid Build Coastguard Worker      // No need to coordinate collection of this group; it's globally registered.
390*61c4878aSAndroid Build Coastguard Worker      PW_METRIC_GROUP_GLOBAL(leagcy_system, "legacy_system");
391*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(leagcy_system, foo, "foo",0.2f);
392*61c4878aSAndroid Build Coastguard Worker      PW_METRIC(leagcy_system, bar, "bar",44000u);
393*61c4878aSAndroid Build Coastguard Worker
394*61c4878aSAndroid Build Coastguard Worker   .. attention::
395*61c4878aSAndroid Build Coastguard Worker      Do not create ``PW_METRIC_GROUP_GLOBAL`` instances anywhere other than
396*61c4878aSAndroid Build Coastguard Worker      global scope. Putting these on an instance (member context) would lead to
397*61c4878aSAndroid Build Coastguard Worker      dangling pointers and misery. Metrics are never deleted or unregistered!
398*61c4878aSAndroid Build Coastguard Worker
399*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: PW_METRIC_TOKEN(name)
400*61c4878aSAndroid Build Coastguard Worker
401*61c4878aSAndroid Build Coastguard Worker   Declare a ``pw::metric::Token`` (``pw::tokenizer::Token``) for a metric with
402*61c4878aSAndroid Build Coastguard Worker   name ``name``. This token matches the ``.name()`` of a metric with the same
403*61c4878aSAndroid Build Coastguard Worker   name.
404*61c4878aSAndroid Build Coastguard Worker
405*61c4878aSAndroid Build Coastguard Worker   This is a wrapper around ``PW_TOKENIZE_STRING_MASK`` and carries the same
406*61c4878aSAndroid Build Coastguard Worker   semantics.
407*61c4878aSAndroid Build Coastguard Worker
408*61c4878aSAndroid Build Coastguard Worker   This is unlikely to be used by most pw_metric consumers.
409*61c4878aSAndroid Build Coastguard Worker
410*61c4878aSAndroid Build Coastguard Worker----------------------
411*61c4878aSAndroid Build Coastguard WorkerUsage & Best Practices
412*61c4878aSAndroid Build Coastguard Worker----------------------
413*61c4878aSAndroid Build Coastguard WorkerThis library makes several tradeoffs to enable low memory use per-metric, and
414*61c4878aSAndroid Build Coastguard Workerone of those tradeoffs results in requiring care in constructing the metric
415*61c4878aSAndroid Build Coastguard Workertrees.
416*61c4878aSAndroid Build Coastguard Worker
417*61c4878aSAndroid Build Coastguard WorkerUse the Init() pattern for static objects with metrics
418*61c4878aSAndroid Build Coastguard Worker------------------------------------------------------
419*61c4878aSAndroid Build Coastguard WorkerA common pattern in embedded systems is to allocate many objects globally, and
420*61c4878aSAndroid Build Coastguard Workerreduce reliance on dynamic allocation (or eschew malloc entirely). This leads
421*61c4878aSAndroid Build Coastguard Workerto a pattern where rich/large objects are statically constructed at global
422*61c4878aSAndroid Build Coastguard Workerscope, then interacted with via tasks or threads. For example, consider a
423*61c4878aSAndroid Build Coastguard Workerhypothetical global ``Uart`` object:
424*61c4878aSAndroid Build Coastguard Worker
425*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
426*61c4878aSAndroid Build Coastguard Worker
427*61c4878aSAndroid Build Coastguard Worker   class Uart {
428*61c4878aSAndroid Build Coastguard Worker    public:
429*61c4878aSAndroid Build Coastguard Worker     Uart(span<std::byte> rx_buffer, span<std::byte> tx_buffer)
430*61c4878aSAndroid Build Coastguard Worker       : rx_buffer_(rx_buffer), tx_buffer_(tx_buffer) {}
431*61c4878aSAndroid Build Coastguard Worker
432*61c4878aSAndroid Build Coastguard Worker     // Send/receive here...
433*61c4878aSAndroid Build Coastguard Worker
434*61c4878aSAndroid Build Coastguard Worker    private:
435*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> rx_buffer;
436*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> tx_buffer;
437*61c4878aSAndroid Build Coastguard Worker   };
438*61c4878aSAndroid Build Coastguard Worker
439*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_rx_buffer;
440*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_tx_buffer;
441*61c4878aSAndroid Build Coastguard Worker   Uart uart1(uart_rx_buffer, uart_tx_buffer);
442*61c4878aSAndroid Build Coastguard Worker
443*61c4878aSAndroid Build Coastguard WorkerThrough the course of building a product, the team may want to add metrics to
444*61c4878aSAndroid Build Coastguard Workerthe UART to for example gain insight into which operations are triggering lots
445*61c4878aSAndroid Build Coastguard Workerof data transfer. When adding metrics to the above imaginary UART object, one
446*61c4878aSAndroid Build Coastguard Workermight consider the following approach:
447*61c4878aSAndroid Build Coastguard Worker
448*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
449*61c4878aSAndroid Build Coastguard Worker
450*61c4878aSAndroid Build Coastguard Worker   class Uart {
451*61c4878aSAndroid Build Coastguard Worker    public:
452*61c4878aSAndroid Build Coastguard Worker     Uart(span<std::byte> rx_buffer,
453*61c4878aSAndroid Build Coastguard Worker          span<std::byte> tx_buffer,
454*61c4878aSAndroid Build Coastguard Worker          Group& parent_metrics)
455*61c4878aSAndroid Build Coastguard Worker       : rx_buffer_(rx_buffer),
456*61c4878aSAndroid Build Coastguard Worker         tx_buffer_(tx_buffer) {
457*61c4878aSAndroid Build Coastguard Worker         // PROBLEM! parent_metrics may not be constructed if it's a reference
458*61c4878aSAndroid Build Coastguard Worker         // to a static global.
459*61c4878aSAndroid Build Coastguard Worker         parent_metrics.Add(tx_bytes_);
460*61c4878aSAndroid Build Coastguard Worker         parent_metrics.Add(rx_bytes_);
461*61c4878aSAndroid Build Coastguard Worker      }
462*61c4878aSAndroid Build Coastguard Worker
463*61c4878aSAndroid Build Coastguard Worker     // Send/receive here which increment tx/rx_bytes.
464*61c4878aSAndroid Build Coastguard Worker
465*61c4878aSAndroid Build Coastguard Worker    private:
466*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> rx_buffer;
467*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> tx_buffer;
468*61c4878aSAndroid Build Coastguard Worker
469*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(tx_bytes_, "tx_bytes", 0);
470*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(rx_bytes_, "rx_bytes", 0);
471*61c4878aSAndroid Build Coastguard Worker   };
472*61c4878aSAndroid Build Coastguard Worker
473*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GROUP(global_metrics, "/");
474*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GROUP(global_metrics, uart1_metrics, "uart1");
475*61c4878aSAndroid Build Coastguard Worker
476*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_rx_buffer;
477*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_tx_buffer;
478*61c4878aSAndroid Build Coastguard Worker   Uart uart1(uart_rx_buffer,
479*61c4878aSAndroid Build Coastguard Worker              uart_tx_buffer,
480*61c4878aSAndroid Build Coastguard Worker              uart1_metrics);
481*61c4878aSAndroid Build Coastguard Worker
482*61c4878aSAndroid Build Coastguard WorkerHowever, this **is incorrect**, since the ``parent_metrics`` (pointing to
483*61c4878aSAndroid Build Coastguard Worker``uart1_metrics`` in this case) may not be constructed at the point of
484*61c4878aSAndroid Build Coastguard Worker``uart1`` getting constructed. Thankfully in the case of ``pw_metric`` this
485*61c4878aSAndroid Build Coastguard Workerwill result in an assertion failure (or it will work correctly if the
486*61c4878aSAndroid Build Coastguard Workerconstructors are called in a favorable order), so the problem will not go
487*61c4878aSAndroid Build Coastguard Workerunnoticed.  Instead, consider using the ``Init()`` pattern for static objects,
488*61c4878aSAndroid Build Coastguard Workerwhere references to dependencies may only be stored during construction, but no
489*61c4878aSAndroid Build Coastguard Workermethods on the dependencies are called.
490*61c4878aSAndroid Build Coastguard Worker
491*61c4878aSAndroid Build Coastguard WorkerInstead, the ``Init()`` approach separates global object construction into two
492*61c4878aSAndroid Build Coastguard Workerphases: The constructor where references are stored, and a ``Init()`` function
493*61c4878aSAndroid Build Coastguard Workerwhich is called after all static constructors have run. This approach works
494*61c4878aSAndroid Build Coastguard Workercorrectly, even when the objects are allocated globally:
495*61c4878aSAndroid Build Coastguard Worker
496*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
497*61c4878aSAndroid Build Coastguard Worker
498*61c4878aSAndroid Build Coastguard Worker   class Uart {
499*61c4878aSAndroid Build Coastguard Worker    public:
500*61c4878aSAndroid Build Coastguard Worker     // Note that metrics is not passed in here at all.
501*61c4878aSAndroid Build Coastguard Worker     Uart(span<std::byte> rx_buffer,
502*61c4878aSAndroid Build Coastguard Worker          span<std::byte> tx_buffer)
503*61c4878aSAndroid Build Coastguard Worker       : rx_buffer_(rx_buffer),
504*61c4878aSAndroid Build Coastguard Worker         tx_buffer_(tx_buffer) {}
505*61c4878aSAndroid Build Coastguard Worker
506*61c4878aSAndroid Build Coastguard Worker      // Precondition: parent_metrics is already constructed.
507*61c4878aSAndroid Build Coastguard Worker      void Init(Group& parent_metrics) {
508*61c4878aSAndroid Build Coastguard Worker         parent_metrics.Add(tx_bytes_);
509*61c4878aSAndroid Build Coastguard Worker         parent_metrics.Add(rx_bytes_);
510*61c4878aSAndroid Build Coastguard Worker      }
511*61c4878aSAndroid Build Coastguard Worker
512*61c4878aSAndroid Build Coastguard Worker     // Send/receive here which increment tx/rx_bytes.
513*61c4878aSAndroid Build Coastguard Worker
514*61c4878aSAndroid Build Coastguard Worker    private:
515*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> rx_buffer;
516*61c4878aSAndroid Build Coastguard Worker     pw::span<std::byte> tx_buffer;
517*61c4878aSAndroid Build Coastguard Worker
518*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(tx_bytes_, "tx_bytes", 0);
519*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(rx_bytes_, "rx_bytes", 0);
520*61c4878aSAndroid Build Coastguard Worker   };
521*61c4878aSAndroid Build Coastguard Worker
522*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GROUP(root_metrics, "/");
523*61c4878aSAndroid Build Coastguard Worker   PW_METRIC_GROUP(root_metrics, uart1_metrics, "uart1");
524*61c4878aSAndroid Build Coastguard Worker
525*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_rx_buffer;
526*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 512> uart_tx_buffer;
527*61c4878aSAndroid Build Coastguard Worker   Uart uart1(uart_rx_buffer,
528*61c4878aSAndroid Build Coastguard Worker              uart_tx_buffer);
529*61c4878aSAndroid Build Coastguard Worker
530*61c4878aSAndroid Build Coastguard Worker   void main() {
531*61c4878aSAndroid Build Coastguard Worker     // uart1_metrics is guaranteed to be initialized by this point, so it is
532*61c4878aSAndroid Build Coastguard Worker     safe to pass it to Init().
533*61c4878aSAndroid Build Coastguard Worker     uart1.Init(uart1_metrics);
534*61c4878aSAndroid Build Coastguard Worker   }
535*61c4878aSAndroid Build Coastguard Worker
536*61c4878aSAndroid Build Coastguard Worker.. attention::
537*61c4878aSAndroid Build Coastguard Worker   Be extra careful about **static global metric registration**. Consider using
538*61c4878aSAndroid Build Coastguard Worker   the ``Init()`` pattern.
539*61c4878aSAndroid Build Coastguard Worker
540*61c4878aSAndroid Build Coastguard WorkerMetric member order matters in objects
541*61c4878aSAndroid Build Coastguard Worker--------------------------------------
542*61c4878aSAndroid Build Coastguard WorkerThe order of declaring in-class groups and metrics matters if the metrics are
543*61c4878aSAndroid Build Coastguard Workerwithin a group declared inside the class. For example, the following class will
544*61c4878aSAndroid Build Coastguard Workerwork fine:
545*61c4878aSAndroid Build Coastguard Worker
546*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
547*61c4878aSAndroid Build Coastguard Worker
548*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
549*61c4878aSAndroid Build Coastguard Worker
550*61c4878aSAndroid Build Coastguard Worker   class PowerSubsystem {
551*61c4878aSAndroid Build Coastguard Worker    public:
552*61c4878aSAndroid Build Coastguard Worker      Group& metrics() { return metrics_; }
553*61c4878aSAndroid Build Coastguard Worker      const Group& metrics() const { return metrics_; }
554*61c4878aSAndroid Build Coastguard Worker
555*61c4878aSAndroid Build Coastguard Worker    private:
556*61c4878aSAndroid Build Coastguard Worker     PW_METRIC_GROUP(metrics_, "power");  // Note metrics_ declared first.
557*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, foo, "foo", 0.2f);
558*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, bar, "bar", 44000u);
559*61c4878aSAndroid Build Coastguard Worker   };
560*61c4878aSAndroid Build Coastguard Worker
561*61c4878aSAndroid Build Coastguard Workerbut the following one will not since the group is constructed after the metrics
562*61c4878aSAndroid Build Coastguard Worker(and will result in a compile error):
563*61c4878aSAndroid Build Coastguard Worker
564*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
565*61c4878aSAndroid Build Coastguard Worker
566*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
567*61c4878aSAndroid Build Coastguard Worker
568*61c4878aSAndroid Build Coastguard Worker   class PowerSubsystem {
569*61c4878aSAndroid Build Coastguard Worker    public:
570*61c4878aSAndroid Build Coastguard Worker      Group& metrics() { return metrics_; }
571*61c4878aSAndroid Build Coastguard Worker      const Group& metrics() const { return metrics_; }
572*61c4878aSAndroid Build Coastguard Worker
573*61c4878aSAndroid Build Coastguard Worker    private:
574*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, foo, "foo", 0.2f);
575*61c4878aSAndroid Build Coastguard Worker     PW_METRIC(metrics_, bar, "bar", 44000u);
576*61c4878aSAndroid Build Coastguard Worker     PW_METRIC_GROUP(metrics_, "power");  // Error: metrics_ must be first.
577*61c4878aSAndroid Build Coastguard Worker   };
578*61c4878aSAndroid Build Coastguard Worker
579*61c4878aSAndroid Build Coastguard Worker.. attention::
580*61c4878aSAndroid Build Coastguard Worker
581*61c4878aSAndroid Build Coastguard Worker   Put **groups before metrics** when declaring metrics members inside classes.
582*61c4878aSAndroid Build Coastguard Worker
583*61c4878aSAndroid Build Coastguard WorkerThread safety
584*61c4878aSAndroid Build Coastguard Worker-------------
585*61c4878aSAndroid Build Coastguard Worker``pw_metric`` has **no built-in synchronization for manipulating the tree**
586*61c4878aSAndroid Build Coastguard Workerstructure. Users are expected to either rely on shared global mutex when
587*61c4878aSAndroid Build Coastguard Workerconstructing the metric tree, or do the metric construction in a single thread
588*61c4878aSAndroid Build Coastguard Worker(e.g. a boot/init thread). The same applies for destruction, though we do not
589*61c4878aSAndroid Build Coastguard Workeradvise destructing metrics or groups.
590*61c4878aSAndroid Build Coastguard Worker
591*61c4878aSAndroid Build Coastguard WorkerIndividual metrics have atomic ``Increment()``, ``Set()``, and the value
592*61c4878aSAndroid Build Coastguard Workeraccessors ``as_float()`` and ``as_int()`` which don't require separate
593*61c4878aSAndroid Build Coastguard Workersynchronization, and can be used from ISRs.
594*61c4878aSAndroid Build Coastguard Worker
595*61c4878aSAndroid Build Coastguard Worker.. attention::
596*61c4878aSAndroid Build Coastguard Worker
597*61c4878aSAndroid Build Coastguard Worker   **You must synchronize access to metrics**. ``pw_metrics`` does not
598*61c4878aSAndroid Build Coastguard Worker   internally synchronize access during construction. Metric Set/Increment are
599*61c4878aSAndroid Build Coastguard Worker   safe.
600*61c4878aSAndroid Build Coastguard Worker
601*61c4878aSAndroid Build Coastguard WorkerLifecycle
602*61c4878aSAndroid Build Coastguard Worker---------
603*61c4878aSAndroid Build Coastguard WorkerMetric objects are not designed to be destructed, and are expected to live for
604*61c4878aSAndroid Build Coastguard Workerthe lifetime of the program or application. If you need dynamic
605*61c4878aSAndroid Build Coastguard Workercreation/destruction of metrics, ``pw_metric`` does not attempt to cover that
606*61c4878aSAndroid Build Coastguard Workeruse case. Instead, ``pw_metric`` covers the case of products with two execution
607*61c4878aSAndroid Build Coastguard Workerphases:
608*61c4878aSAndroid Build Coastguard Worker
609*61c4878aSAndroid Build Coastguard Worker1. A boot phase where the metric tree is created.
610*61c4878aSAndroid Build Coastguard Worker2. A run phase where metrics are collected. The tree structure is fixed.
611*61c4878aSAndroid Build Coastguard Worker
612*61c4878aSAndroid Build Coastguard WorkerTechnically, it is possible to destruct metrics provided care is taken to
613*61c4878aSAndroid Build Coastguard Workerremove the given metric (or group) from the list it's contained in. However,
614*61c4878aSAndroid Build Coastguard Workerthere are no helper functions for this, so be careful.
615*61c4878aSAndroid Build Coastguard Worker
616*61c4878aSAndroid Build Coastguard WorkerBelow is an example that **is incorrect**. Don't do what follows!
617*61c4878aSAndroid Build Coastguard Worker
618*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
619*61c4878aSAndroid Build Coastguard Worker
620*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
621*61c4878aSAndroid Build Coastguard Worker
622*61c4878aSAndroid Build Coastguard Worker   void main() {
623*61c4878aSAndroid Build Coastguard Worker     PW_METRIC_GROUP(root, "/");
624*61c4878aSAndroid Build Coastguard Worker     {
625*61c4878aSAndroid Build Coastguard Worker       // BAD! The metrics have a different lifetime than the group.
626*61c4878aSAndroid Build Coastguard Worker       PW_METRIC(root, temperature, "temperature_f", 72.3f);
627*61c4878aSAndroid Build Coastguard Worker       PW_METRIC(root, humidity, "humidity_relative_percent", 33.2f);
628*61c4878aSAndroid Build Coastguard Worker     }
629*61c4878aSAndroid Build Coastguard Worker     // OOPS! root now has a linked list that points to the destructed
630*61c4878aSAndroid Build Coastguard Worker     // "humidity" object.
631*61c4878aSAndroid Build Coastguard Worker   }
632*61c4878aSAndroid Build Coastguard Worker
633*61c4878aSAndroid Build Coastguard Worker.. attention::
634*61c4878aSAndroid Build Coastguard Worker   **Don't destruct metrics**. Metrics are designed to be registered /
635*61c4878aSAndroid Build Coastguard Worker   structured upfront, then manipulated during a device's active phase. They do
636*61c4878aSAndroid Build Coastguard Worker   not support destruction.
637*61c4878aSAndroid Build Coastguard Worker
638*61c4878aSAndroid Build Coastguard Worker.. _module-pw_metric-exporting:
639*61c4878aSAndroid Build Coastguard Worker
640*61c4878aSAndroid Build Coastguard Worker-----------------
641*61c4878aSAndroid Build Coastguard WorkerExporting metrics
642*61c4878aSAndroid Build Coastguard Worker-----------------
643*61c4878aSAndroid Build Coastguard WorkerCollecting metrics on a device is not useful without a mechanism to export
644*61c4878aSAndroid Build Coastguard Workerthose metrics for analysis and debugging. ``pw_metric`` offers optional RPC
645*61c4878aSAndroid Build Coastguard Workerservice libraries (``:metric_service_nanopb`` based on nanopb, and
646*61c4878aSAndroid Build Coastguard Worker``:metric_service_pwpb`` based on pw_protobuf) that enable exporting a
647*61c4878aSAndroid Build Coastguard Workeruser-supplied set of on-device metrics via RPC. This facility is intended to
648*61c4878aSAndroid Build Coastguard Workerfunction from the early stages of device bringup through production in the
649*61c4878aSAndroid Build Coastguard Workerfield.
650*61c4878aSAndroid Build Coastguard Worker
651*61c4878aSAndroid Build Coastguard WorkerThe metrics are fetched by calling the ``MetricService.Get`` RPC method, which
652*61c4878aSAndroid Build Coastguard Workerstreams all registered metrics to the caller in batches (server streaming RPC).
653*61c4878aSAndroid Build Coastguard WorkerBatching the returned metrics avoids requiring a large buffer or large RPC MTU.
654*61c4878aSAndroid Build Coastguard Worker
655*61c4878aSAndroid Build Coastguard WorkerThe returned metric objects have flattened paths to the root. For example, the
656*61c4878aSAndroid Build Coastguard Workerreturned metrics (post detokenization and jsonified) might look something like:
657*61c4878aSAndroid Build Coastguard Worker
658*61c4878aSAndroid Build Coastguard Worker.. code-block:: json
659*61c4878aSAndroid Build Coastguard Worker
660*61c4878aSAndroid Build Coastguard Worker   {
661*61c4878aSAndroid Build Coastguard Worker     "/i2c1/failed_txns": 17,
662*61c4878aSAndroid Build Coastguard Worker     "/i2c1/total_txns": 2013,
663*61c4878aSAndroid Build Coastguard Worker     "/i2c1/gyro/resets": 24,
664*61c4878aSAndroid Build Coastguard Worker     "/i2c1/gyro/hangs": 1,
665*61c4878aSAndroid Build Coastguard Worker     "/spi1/thermocouple/reads": 242,
666*61c4878aSAndroid Build Coastguard Worker     "/spi1/thermocouple/temp_celsius": 34.52,
667*61c4878aSAndroid Build Coastguard Worker   }
668*61c4878aSAndroid Build Coastguard Worker
669*61c4878aSAndroid Build Coastguard WorkerNote that there is no nesting of the groups; the nesting is implied from the
670*61c4878aSAndroid Build Coastguard Workerpath.
671*61c4878aSAndroid Build Coastguard Worker
672*61c4878aSAndroid Build Coastguard WorkerRPC service setup
673*61c4878aSAndroid Build Coastguard Worker-----------------
674*61c4878aSAndroid Build Coastguard WorkerTo expose a ``MetricService`` in your application, do the following:
675*61c4878aSAndroid Build Coastguard Worker
676*61c4878aSAndroid Build Coastguard Worker1. Define metrics around the system, and put them in a group or list of
677*61c4878aSAndroid Build Coastguard Worker   metrics. Easy choices include for example the ``global_groups`` and
678*61c4878aSAndroid Build Coastguard Worker   ``global_metrics`` variables; or creat your own.
679*61c4878aSAndroid Build Coastguard Worker2. Create an instance of ``pw::metric::MetricService``.
680*61c4878aSAndroid Build Coastguard Worker3. Register the service with your RPC server.
681*61c4878aSAndroid Build Coastguard Worker
682*61c4878aSAndroid Build Coastguard WorkerFor example:
683*61c4878aSAndroid Build Coastguard Worker
684*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
685*61c4878aSAndroid Build Coastguard Worker
686*61c4878aSAndroid Build Coastguard Worker   #include "pw_rpc/server.h"
687*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric.h"
688*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/global.h"
689*61c4878aSAndroid Build Coastguard Worker   #include "pw_metric/metric_service_nanopb.h"
690*61c4878aSAndroid Build Coastguard Worker
691*61c4878aSAndroid Build Coastguard Worker   // Note: You must customize the RPC server setup; see pw_rpc.
692*61c4878aSAndroid Build Coastguard Worker   Channel channels[] = {
693*61c4878aSAndroid Build Coastguard Worker    Channel::Create<1>(&uart_output),
694*61c4878aSAndroid Build Coastguard Worker   };
695*61c4878aSAndroid Build Coastguard Worker   Server server(channels);
696*61c4878aSAndroid Build Coastguard Worker
697*61c4878aSAndroid Build Coastguard Worker   // Metric service instance, pointing to the global metric objects.
698*61c4878aSAndroid Build Coastguard Worker   // This could also point to custom per-product or application objects.
699*61c4878aSAndroid Build Coastguard Worker   pw::metric::MetricService metric_service(
700*61c4878aSAndroid Build Coastguard Worker       pw::metric::global_metrics,
701*61c4878aSAndroid Build Coastguard Worker       pw::metric::global_groups);
702*61c4878aSAndroid Build Coastguard Worker
703*61c4878aSAndroid Build Coastguard Worker   void RegisterServices() {
704*61c4878aSAndroid Build Coastguard Worker     server.RegisterService(metric_service);
705*61c4878aSAndroid Build Coastguard Worker     // Register other services here.
706*61c4878aSAndroid Build Coastguard Worker   }
707*61c4878aSAndroid Build Coastguard Worker
708*61c4878aSAndroid Build Coastguard Worker   void main() {
709*61c4878aSAndroid Build Coastguard Worker     // ... system initialization ...
710*61c4878aSAndroid Build Coastguard Worker
711*61c4878aSAndroid Build Coastguard Worker     RegisterServices();
712*61c4878aSAndroid Build Coastguard Worker
713*61c4878aSAndroid Build Coastguard Worker     // ... start your applcation ...
714*61c4878aSAndroid Build Coastguard Worker   }
715*61c4878aSAndroid Build Coastguard Worker
716*61c4878aSAndroid Build Coastguard Worker.. attention::
717*61c4878aSAndroid Build Coastguard Worker   Take care when exporting metrics. Ensure **appropriate access control** is in
718*61c4878aSAndroid Build Coastguard Worker   place. In some cases it may make sense to entirely disable metrics export for
719*61c4878aSAndroid Build Coastguard Worker   production builds. Although reading metrics via RPC won't influence the
720*61c4878aSAndroid Build Coastguard Worker   device, in some cases the metrics could expose sensitive information if
721*61c4878aSAndroid Build Coastguard Worker   product owners are not careful.
722*61c4878aSAndroid Build Coastguard Worker
723*61c4878aSAndroid Build Coastguard Worker.. attention::
724*61c4878aSAndroid Build Coastguard Worker   **MetricService::Get is a synchronous RPC method**
725*61c4878aSAndroid Build Coastguard Worker
726*61c4878aSAndroid Build Coastguard Worker   Calls to is ``MetricService::Get`` are blocking and will send all metrics
727*61c4878aSAndroid Build Coastguard Worker   immediately, even though it is a server-streaming RPC. This will work fine if
728*61c4878aSAndroid Build Coastguard Worker   the device doesn't have too many metrics, or doesn't have concurrent RPCs
729*61c4878aSAndroid Build Coastguard Worker   like logging, but could be a problem in some cases.
730*61c4878aSAndroid Build Coastguard Worker
731*61c4878aSAndroid Build Coastguard Worker   We plan to offer an async version where the application is responsible for
732*61c4878aSAndroid Build Coastguard Worker   pumping the metrics into the streaming response. This gives flow control to
733*61c4878aSAndroid Build Coastguard Worker   the application.
734*61c4878aSAndroid Build Coastguard Worker
735*61c4878aSAndroid Build Coastguard Worker-----------
736*61c4878aSAndroid Build Coastguard WorkerSize report
737*61c4878aSAndroid Build Coastguard Worker-----------
738*61c4878aSAndroid Build Coastguard WorkerThe below size report shows the cost in code and memory for a few examples of
739*61c4878aSAndroid Build Coastguard Workermetrics. This does not include the RPC service.
740*61c4878aSAndroid Build Coastguard Worker
741*61c4878aSAndroid Build Coastguard Worker.. include:: metric_size_report
742*61c4878aSAndroid Build Coastguard Worker
743*61c4878aSAndroid Build Coastguard Worker.. attention::
744*61c4878aSAndroid Build Coastguard Worker   At time of writing, **the above sizes show an unexpectedly large flash
745*61c4878aSAndroid Build Coastguard Worker   impact**. We are investigating why GCC is inserting large global static
746*61c4878aSAndroid Build Coastguard Worker   constructors per group, when all the logic should be reused across objects.
747*61c4878aSAndroid Build Coastguard Worker
748*61c4878aSAndroid Build Coastguard Worker-------------
749*61c4878aSAndroid Build Coastguard WorkerMetric Parser
750*61c4878aSAndroid Build Coastguard Worker-------------
751*61c4878aSAndroid Build Coastguard WorkerThe metric_parser Python Module requests the system metrics via RPC, then parses the
752*61c4878aSAndroid Build Coastguard Workerresponse while detokenizing the group and metrics names, and returns the metrics
753*61c4878aSAndroid Build Coastguard Workerin a dictionary organized by group and value.
754*61c4878aSAndroid Build Coastguard Worker
755*61c4878aSAndroid Build Coastguard Worker----------------
756*61c4878aSAndroid Build Coastguard WorkerDesign tradeoffs
757*61c4878aSAndroid Build Coastguard Worker----------------
758*61c4878aSAndroid Build Coastguard WorkerThere are many possible approaches to metrics collection and aggregation. We've
759*61c4878aSAndroid Build Coastguard Workerchosen some points on the tradeoff curve:
760*61c4878aSAndroid Build Coastguard Worker
761*61c4878aSAndroid Build Coastguard Worker- **Atomic-sized metrics** - Using simple metric objects with just uint32/float
762*61c4878aSAndroid Build Coastguard Worker  enables atomic operations. While it might be nice to support larger types, it
763*61c4878aSAndroid Build Coastguard Worker  is more useful to have safe metrics increment from interrupt subroutines.
764*61c4878aSAndroid Build Coastguard Worker
765*61c4878aSAndroid Build Coastguard Worker- **No aggregate metrics (yet)** - Aggregate metrics (e.g. average, max, min,
766*61c4878aSAndroid Build Coastguard Worker  histograms) are not supported, and must be built on top of the simple base
767*61c4878aSAndroid Build Coastguard Worker  metrics. By taking this route, we can considerably simplify the core metrics
768*61c4878aSAndroid Build Coastguard Worker  system and have aggregation logic in separate modules. Those modules can then
769*61c4878aSAndroid Build Coastguard Worker  feed into the metrics system - for example by creating multiple metrics for a
770*61c4878aSAndroid Build Coastguard Worker  single underlying metric. For example: "foo", "foo_max", "foo_min" and so on.
771*61c4878aSAndroid Build Coastguard Worker
772*61c4878aSAndroid Build Coastguard Worker  The other problem with automatic aggregation is that what period the
773*61c4878aSAndroid Build Coastguard Worker  aggregation happens over is often important, and it can be hard to design
774*61c4878aSAndroid Build Coastguard Worker  this cleanly into the API. Instead, this responsibility is pushed to the user
775*61c4878aSAndroid Build Coastguard Worker  who must take more care.
776*61c4878aSAndroid Build Coastguard Worker
777*61c4878aSAndroid Build Coastguard Worker  Note that we will add helpers for aggregated metrics.
778*61c4878aSAndroid Build Coastguard Worker
779*61c4878aSAndroid Build Coastguard Worker- **No virtual metrics** - An alternate approach to the concrete Metric class
780*61c4878aSAndroid Build Coastguard Worker  in the current module is to have a virtual interface for metrics, and then
781*61c4878aSAndroid Build Coastguard Worker  allow those metrics to have their own storage. This is attractive but can
782*61c4878aSAndroid Build Coastguard Worker  lead to many vtables and excess memory use in simple one-metric use cases.
783*61c4878aSAndroid Build Coastguard Worker
784*61c4878aSAndroid Build Coastguard Worker- **Linked list registration** - Using linked lists for registration is a
785*61c4878aSAndroid Build Coastguard Worker  tradeoff, accepting some memory overhead in exchange for flexibility. Other
786*61c4878aSAndroid Build Coastguard Worker  alternatives include a global table of metrics, which has the disadvantage of
787*61c4878aSAndroid Build Coastguard Worker  requiring centralizing the metrics -- an impossibility for middleware like
788*61c4878aSAndroid Build Coastguard Worker  Pigweed.
789*61c4878aSAndroid Build Coastguard Worker
790*61c4878aSAndroid Build Coastguard Worker- **Synchronization** - The only synchronization guarantee provided by
791*61c4878aSAndroid Build Coastguard Worker  pw_metric is that increment and set are atomic. Other than that, users are on
792*61c4878aSAndroid Build Coastguard Worker  their own to synchonize metric collection and updating.
793*61c4878aSAndroid Build Coastguard Worker
794*61c4878aSAndroid Build Coastguard Worker- **No fast metric lookup** - The current design does not make it fast to
795*61c4878aSAndroid Build Coastguard Worker  lookup a metric at runtime; instead, one must run a linear search of the tree
796*61c4878aSAndroid Build Coastguard Worker  to find the matching metric. In most non-dynamic use cases, this is fine in
797*61c4878aSAndroid Build Coastguard Worker  practice, and saves having a more involved hash table. Metric updates will be
798*61c4878aSAndroid Build Coastguard Worker  through direct member or variable accesses.
799*61c4878aSAndroid Build Coastguard Worker
800*61c4878aSAndroid Build Coastguard Worker- **Relying on C++ static initialization** - In short, the convenience
801*61c4878aSAndroid Build Coastguard Worker  outweighs the cost and risk. Without static initializers, it would be
802*61c4878aSAndroid Build Coastguard Worker  impossible to automatically collect the metrics without post-processing the
803*61c4878aSAndroid Build Coastguard Worker  C++ code to find the metrics; a huge and debatably worthwhile approach. We
804*61c4878aSAndroid Build Coastguard Worker  have carefully analyzed the static initializer behaviour of Pigweed's
805*61c4878aSAndroid Build Coastguard Worker  IntrusiveList and are confident it is correct.
806*61c4878aSAndroid Build Coastguard Worker
807*61c4878aSAndroid Build Coastguard Worker- **Both local & global support** - Potentially just one approach (the local or
808*61c4878aSAndroid Build Coastguard Worker  global one) could be offered, making the module less complex. However, we
809*61c4878aSAndroid Build Coastguard Worker  feel the additional complexity is worthwhile since there are legimitate use
810*61c4878aSAndroid Build Coastguard Worker  cases for both e.g. ``PW_METRIC`` and ``PW_METRIC_GLOBAL``. We'd prefer to
811*61c4878aSAndroid Build Coastguard Worker  have a well-tested upstream solution for these use cases rather than have
812*61c4878aSAndroid Build Coastguard Worker  customers re-implement one of these.
813*61c4878aSAndroid Build Coastguard Worker
814*61c4878aSAndroid Build Coastguard Worker----------------
815*61c4878aSAndroid Build Coastguard WorkerRoadmap & Status
816*61c4878aSAndroid Build Coastguard Worker----------------
817*61c4878aSAndroid Build Coastguard Worker- **String metric names** - ``pw_metric`` stores metric names as tokens. On one
818*61c4878aSAndroid Build Coastguard Worker  hand, this is great for production where having a compact binary is often a
819*61c4878aSAndroid Build Coastguard Worker  requirement to fit the application in the given part. However, in early
820*61c4878aSAndroid Build Coastguard Worker  development before flash is a constraint, string names are more convenient to
821*61c4878aSAndroid Build Coastguard Worker  work with since there is no need for host-side detokenization. We plan to add
822*61c4878aSAndroid Build Coastguard Worker  optional support for using supporting strings.
823*61c4878aSAndroid Build Coastguard Worker
824*61c4878aSAndroid Build Coastguard Worker- **Aggregate metrics** - We plan to add support for aggregate metrics on top
825*61c4878aSAndroid Build Coastguard Worker  of the simple metric mechanism, either as another module or as additional
826*61c4878aSAndroid Build Coastguard Worker  functionality inside this one. Likely examples include min/max,
827*61c4878aSAndroid Build Coastguard Worker
828*61c4878aSAndroid Build Coastguard Worker- **Selectively enable or disable metrics** - Currently the metrics are always
829*61c4878aSAndroid Build Coastguard Worker  enabled once included. In practice this is not ideal since many times only a
830*61c4878aSAndroid Build Coastguard Worker  few metrics are wanted in production, but having to strip all the metrics
831*61c4878aSAndroid Build Coastguard Worker  code is error prone. Instead, we will add support for controlling what
832*61c4878aSAndroid Build Coastguard Worker  metrics are enabled or disabled at compile time. This may rely on of C++20's
833*61c4878aSAndroid Build Coastguard Worker  support for zero-sized members to fully remove the cost.
834*61c4878aSAndroid Build Coastguard Worker
835*61c4878aSAndroid Build Coastguard Worker- **Async RPC** - The current RPC service exports the metrics by streaming
836*61c4878aSAndroid Build Coastguard Worker  them to the client in batches. However, the current solution streams all the
837*61c4878aSAndroid Build Coastguard Worker  metrics to completion; this may block the RPC thread. In the future we will
838*61c4878aSAndroid Build Coastguard Worker  have an async solution where the user is in control of flow priority.
839*61c4878aSAndroid Build Coastguard Worker
840*61c4878aSAndroid Build Coastguard Worker- **Timer integration** - We would like to add a stopwatch type mechanism to
841*61c4878aSAndroid Build Coastguard Worker  time multiple in-flight events.
842*61c4878aSAndroid Build Coastguard Worker
843*61c4878aSAndroid Build Coastguard Worker- **C support** - In practice it's often useful or necessary to instrument
844*61c4878aSAndroid Build Coastguard Worker  C-only code. While it will be impossible to support the global registration
845*61c4878aSAndroid Build Coastguard Worker  system that the C++ version supports, we will figure out a solution to make
846*61c4878aSAndroid Build Coastguard Worker  instrumenting C code relatively smooth.
847*61c4878aSAndroid Build Coastguard Worker
848*61c4878aSAndroid Build Coastguard Worker- **Global counter** - We may add a global metric counter to help detect cases
849*61c4878aSAndroid Build Coastguard Worker  where post-initialization metrics manipulations are done.
850*61c4878aSAndroid Build Coastguard Worker
851*61c4878aSAndroid Build Coastguard Worker- **Proto structure** - It may be possible to directly map metrics to a custom
852*61c4878aSAndroid Build Coastguard Worker  proto structure, where instead of a name or token field, a tag field is
853*61c4878aSAndroid Build Coastguard Worker  provided. This could result in elegant export to an easily machine parsable
854*61c4878aSAndroid Build Coastguard Worker  and compact representation on the host. We may investigate this in the
855*61c4878aSAndroid Build Coastguard Worker  future.
856*61c4878aSAndroid Build Coastguard Worker
857*61c4878aSAndroid Build Coastguard Worker- **Safer data structures** - At a cost of 4B per metric and 4B per group, it
858*61c4878aSAndroid Build Coastguard Worker  may be possible to make metric structure instantiation safe even in static
859*61c4878aSAndroid Build Coastguard Worker  constructors, and also make it safe to remove metrics dynamically. We will
860*61c4878aSAndroid Build Coastguard Worker  consider whether this tradeoff is the right one, since a 4B cost per metric
861*61c4878aSAndroid Build Coastguard Worker  is substantial on projects with many metrics.
862