Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / usecounters.py
blob0071be7dffc731ef8cc76cc621040e19e5ad0f1c
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 import re
8 def read_conf(conf_filename):
9 # Can't read/write from a single StringIO, so make a new one for reading.
10 stream = open(conf_filename, "r")
12 def parse_counters(stream):
13 for line_num, full_line in enumerate(stream):
14 line = full_line.rstrip("\n")
15 if not line or line.startswith("//"):
16 # empty line or comment
17 continue
18 m = re.match(r"method ([A-Za-z0-9]+)\.([A-Za-z0-9]+)$", line)
19 if m:
20 interface_name, method_name = m.groups()
21 yield {
22 "type": "method",
23 "interface_name": interface_name,
24 "method_name": method_name,
26 continue
27 m = re.match(r"attribute ([A-Za-z0-9]+)\.([A-Za-z0-9]+)$", line)
28 if m:
29 interface_name, attribute_name = m.groups()
30 yield {
31 "type": "attribute",
32 "interface_name": interface_name,
33 "attribute_name": attribute_name,
35 continue
36 m = re.match(r"custom ([A-Za-z0-9_]+) (.*)$", line)
37 if m:
38 name, desc = m.groups()
39 yield {"type": "custom", "name": name, "desc": desc}
40 continue
41 raise ValueError(
42 "error parsing %s at line %d" % (conf_filename, line_num + 1)
45 return parse_counters(stream)
48 YAML_HEADER = """\
49 # This file is AUTOGENERATED by usecounters.py. DO NOT EDIT.
50 # (instead, re-run ./mach gen-use-counter-metrics)
52 # This Source Code Form is subject to the terms of the Mozilla Public
53 # License, v. 2.0. If a copy of the MPL was not distributed with this
54 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
56 ---
57 $schema: moz://mozilla.org/schemas/glean/metrics/2-0-0
58 $tags:
59 - 'Core :: DOM: Core & HTML'
61 """
63 BASE_METRICS = """\
64 use.counter:
65 content_documents_destroyed:
66 type: counter
67 description: >
68 A count of how many content documents were destroyed.
69 Used to turn document use counters' counts into rates.
70 Excludes documents for which we do not count use counters
71 (See `Document::ShouldIncludeInTelemetry`).
72 bugs:
73 - https://bugzilla.mozilla.org/show_bug.cgi?id=1204994
74 - https://bugzilla.mozilla.org/show_bug.cgi?id=1569672
75 - https://bugzilla.mozilla.org/show_bug.cgi?id=1845779
76 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
77 data_reviews:
78 - https://bugzilla.mozilla.org/show_bug.cgi?id=1569672
79 notification_emails:
80 - dom-core@mozilla.com
81 - emilio@mozilla.com
82 expires: never
83 send_in_pings:
84 - use-counters
86 top_level_content_documents_destroyed:
87 type: counter
88 description: >
89 A count of how many "pages" were destroyed.
90 Used to turn page use counters' counts into rates.
91 Excludes pages that contain only documents for which we do not count use
92 counters (See `Document::ShouldIncludeInTelemetry`).
93 bugs:
94 - https://bugzilla.mozilla.org/show_bug.cgi?id=1204994
95 - https://bugzilla.mozilla.org/show_bug.cgi?id=1569672
96 - https://bugzilla.mozilla.org/show_bug.cgi?id=1845779
97 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
98 data_reviews:
99 - https://bugzilla.mozilla.org/show_bug.cgi?id=1569672
100 notification_emails:
101 - dom-core@mozilla.com
102 - emilio@mozilla.com
103 expires: never
104 send_in_pings:
105 - use-counters
107 dedicated_workers_destroyed:
108 type: counter
109 description: >
110 A count of how many `Dedicated`-kind workers were destroyed.
111 Used to turn dedicated worker use counters' counts into rates.
112 Excludes chrome workers.
113 bugs:
114 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
115 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
116 data_reviews:
117 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
118 notification_emails:
119 - dom-core@mozilla.com
120 - emilio@mozilla.com
121 expires: never
122 send_in_pings:
123 - use-counters
125 shared_workers_destroyed:
126 type: counter
127 description: >
128 A count of how many `Shared`-kind workers were destroyed.
129 Used to turn shared worker use counters' counts into rates.
130 Excludes chrome workers.
131 bugs:
132 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
133 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
134 data_reviews:
135 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
136 notification_emails:
137 - dom-core@mozilla.com
138 - emilio@mozilla.com
139 expires: never
140 send_in_pings:
141 - use-counters
143 service_workers_destroyed:
144 type: counter
145 description: >
146 A count of how many `Service`-kind workers were destroyed.
147 Used to turn service worker use counters' counts into rates.
148 Excludes chrome workers.
149 bugs:
150 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
151 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
152 data_reviews:
153 - https://bugzilla.mozilla.org/show_bug.cgi?id=1202706
154 notification_emails:
155 - dom-core@mozilla.com
156 - emilio@mozilla.com
157 expires: never
158 send_in_pings:
159 - use-counters
163 USE_COUNTER_TEMPLATE = """\
164 {name}:
165 type: counter
166 description: >
167 {desc}
168 Compare against `{denominator}`
169 to calculate the rate.
170 bugs:
171 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
172 data_reviews:
173 - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
174 notification_emails:
175 - dom-core@mozilla.com
176 - emilio@mozilla.com
177 expires: never
178 send_in_pings:
179 - use-counters
184 def gen_use_counter_metrics():
186 Finds use counters in:
187 * dom/base/UseCounters.conf
188 * dom/base/UseCountersWorker.conf
189 * dom/base/nsDeprecatedOperationsList.h
190 * !/layout/style/ServoCSSPropList.py
191 * servo/components/style/properties/counted_unknown_properties.py
192 and overwrites the Glean metrics definition file
193 `dom/base/use_counter_metrics.yaml` with definitions for each use counter found.
195 IF YOU CHANGE THIS FUNCTION:
196 * You should probably add your bug's number to USE_COUNTER_TEMPLATE, above.
198 Returns 0 on success.
201 page,
202 doc,
203 dedicated,
204 shared,
205 service,
206 ops_page,
207 ops_doc,
208 css_page,
209 css_doc,
210 ) = parse_use_counters()
211 import os
213 import buildconfig
214 from mozbuild.util import FileAvoidWrite
216 yaml_path = os.path.join(
217 buildconfig.topsrcdir, "dom", "base", "use_counter_metrics.yaml"
219 with FileAvoidWrite(yaml_path) as f:
220 f.write(YAML_HEADER)
221 f.write(BASE_METRICS)
223 total = (
224 len(page)
225 + len(doc)
226 + len(dedicated)
227 + len(shared)
228 + len(service)
229 + len(ops_page)
230 + len(ops_doc)
231 + len(css_page)
232 + len(css_doc)
234 f.write(f"# Total of {total} use counter metrics (excludes denominators).\n")
235 f.write(f"# Total of {len(page)} 'page' use counters.\n")
236 f.write("use.counter.page:\n")
237 for [_, name, desc] in page:
238 f.write(
239 USE_COUNTER_TEMPLATE.format(
240 name=name,
241 desc=desc,
242 denominator="use.counter.top_level_content_documents_destroyed",
246 f.write(f"# Total of {len(doc)} 'document' use counters.\n")
247 f.write("use.counter.doc:\n")
248 for [_, name, desc] in doc:
249 f.write(
250 USE_COUNTER_TEMPLATE.format(
251 name=name,
252 desc=desc,
253 denominator="use.counter.content_documents_destroyed",
257 f.write(f"# Total of {len(dedicated)} 'dedicated worker' use counters.\n")
258 f.write("use.counter.worker.dedicated:\n")
259 for [_, name, desc] in dedicated:
260 f.write(
261 USE_COUNTER_TEMPLATE.format(
262 name=name,
263 desc=desc,
264 denominator="use.counter.dedicated_workers_destroyed",
268 f.write(f"# Total of {len(shared)} 'shared worker' use counters.\n")
269 f.write("use.counter.worker.shared:\n")
270 for [_, name, desc] in shared:
271 f.write(
272 USE_COUNTER_TEMPLATE.format(
273 name=name,
274 desc=desc,
275 denominator="use.counter.shared_workers_destroyed",
279 f.write(f"# Total of {len(service)} 'service worker' use counters.\n")
280 f.write("use.counter.worker.service:\n")
281 for [_, name, desc] in service:
282 f.write(
283 USE_COUNTER_TEMPLATE.format(
284 name=name,
285 desc=desc,
286 denominator="use.counter.service_workers_destroyed",
290 f.write(
291 f"# Total of {len(ops_page)} 'deprecated operations (page)' use counters.\n"
293 f.write("use.counter.deprecated_ops.page:\n")
294 for [_, name, desc] in ops_page:
295 f.write(
296 USE_COUNTER_TEMPLATE.format(
297 name=name,
298 desc=desc,
299 denominator="use.counter.top_level_content_documents_destroyed",
303 f.write(
304 f"# Total of {len(ops_doc)} 'deprecated operations (document)' use counters.\n"
306 f.write("use.counter.deprecated_ops.doc:\n")
307 for [_, name, desc] in ops_doc:
308 f.write(
309 USE_COUNTER_TEMPLATE.format(
310 name=name,
311 desc=desc,
312 denominator="use.counter.content_documents_destroyed",
316 f.write(f"# Total of {len(css_page)} 'CSS (page)' use counters.\n")
317 f.write("use.counter.css.page:\n")
318 for [_, name, desc] in css_page:
319 f.write(
320 USE_COUNTER_TEMPLATE.format(
321 name=name,
322 desc=desc,
323 denominator="use.counter.top_level_content_documents_destroyed",
327 f.write(f"# Total of {len(css_doc)} 'CSS (document)' use counters.\n")
328 f.write("use.counter.css.doc:\n")
329 for [_, name, desc] in css_doc:
330 f.write(
331 USE_COUNTER_TEMPLATE.format(
332 name=name,
333 desc=desc,
334 denominator="use.counter.content_documents_destroyed",
338 return 0
341 def parse_use_counters():
343 Finds use counters in:
344 * dom/base/UseCounters.conf
345 * dom/base/UseCountersWorker.conf
346 * dom/base/nsDeprecatedOperationsList.h
347 * !/layout/style/ServoCSSPropList.py
348 * servo/components/style/properties/counted_unknown_properties.py
349 and returns them as a tuple of lists of tuples of the form:
350 (page, doc, dedicated, shared, service, ops_page, ops_doc, css_page, css_doc)
351 where each of the items is a List<Tuple<enum_name, glean_name, description>>
352 where `enum_name` is the name of the enum variant from UseCounter.h
353 (like `eUseCounter_custom_CustomizedBuiltin`), and
354 where `glean_name` is the name conjugated to Glean metric name safety.
357 # Note, this function contains a duplication of enum naming logic from UseCounter.h.
358 # If you change the enum name format, you'll need to do it twice.
360 # There are 3 kinds of Use Counters in conf files: method, attribute, custom.
361 # `method` and `attribute` are presumed label-safe and are taken as-is.
362 # `custom` can be any case, so are coerced to snake_case.
363 import os
365 import buildconfig
367 uc_path = os.path.join(buildconfig.topsrcdir, "dom", "base", "UseCounters.conf")
368 page = []
369 doc = []
370 for counter in read_conf(uc_path):
371 if counter["type"] == "method":
372 enum_name = (
373 f"eUseCounter_{counter['interface_name']}_{counter['method_name']}"
375 glean_name = f"{counter['interface_name']}_{counter['method_name']}".lower()
376 method = f"called {counter['interface_name']}.{counter['method_name']}"
377 page.append((enum_name, glean_name, f"Whether a page called {method}."))
378 doc.append((enum_name, glean_name, f"Whether a document called {method}."))
379 elif counter["type"] == "attribute":
380 enum_root = (
381 f"eUseCounter_{counter['interface_name']}_{counter['attribute_name']}"
383 name = f"{counter['interface_name']}_{counter['attribute_name']}".lower()
384 attr = f"{counter['interface_name']}.{counter['attribute_name']}"
385 page.append(
386 (f"{enum_root}_getter", f"{name}_getter", f"Whether a page got {attr}.")
388 page.append(
389 (f"{enum_root}_setter", f"{name}_setter", f"Whether a page set {attr}.")
391 doc.append(
393 f"{enum_root}_getter",
394 f"{name}_getter",
395 f"Whether a document got {attr}.",
398 doc.append(
400 f"{enum_root}_setter",
401 f"{name}_setter",
402 f"Whether a document set {attr}.",
405 elif counter["type"] == "custom":
406 enum_name = f"eUseCounter_custom_{counter['name']}"
407 page.append(
409 enum_name,
410 to_snake_case(counter["name"]),
411 f"Whether a page {counter['desc']}.",
414 doc.append(
416 enum_name,
417 to_snake_case(counter["name"]),
418 f"Whether a document {counter['desc']}.",
421 else:
422 print(f"Found unexpected use counter type {counter['type']}. Returning 1.")
423 return 1
425 worker_uc_path = os.path.join(
426 buildconfig.topsrcdir, "dom", "base", "UseCountersWorker.conf"
428 dedicated = []
429 shared = []
430 service = []
431 for counter in read_conf(worker_uc_path):
432 if counter["type"] == "method":
433 enum_name = f"{counter['interface_name']}_{counter['method_name']}"
434 name = f"{counter['interface_name']}_{counter['method_name']}".lower()
435 method = f"called {counter['interface_name']}.{counter['method_name']}"
436 dedicated.append(
437 (enum_name, name, f"Whether a dedicated worker called {method}.")
439 shared.append(
440 (enum_name, name, f"Whether a shared worker called {method}.")
442 service.append(
443 (enum_name, name, f"Whether a service worker called {method}.")
445 elif counter["type"] == "attribute":
446 enum_root = f"{counter['interface_name']}_{counter['attribute_name']}"
447 name = f"{counter['interface_name']}_{counter['attribute_name']}".lower()
448 attr = f"{counter['interface_name']}.{counter['attribute_name']}"
449 dedicated.append(
451 f"{enum_root}_getter",
452 f"{name}_getter",
453 f"Whether a dedicated worker got {attr}.",
456 dedicated.append(
458 f"{enum_root}_setter",
459 f"{name}_setter",
460 f"Whether a dedicated worker set {attr}.",
463 shared.append(
465 f"{enum_root}_getter",
466 f"{name}_getter",
467 f"Whether a shared worker got {attr}.",
470 shared.append(
472 f"{enum_root}_setter",
473 f"{name}_setter",
474 f"Whether a shared worker set {attr}.",
477 service.append(
479 f"{enum_root}_getter",
480 f"{name}_getter",
481 f"Whether a service worker got {attr}.",
484 service.append(
486 f"{enum_root}_setter",
487 f"{name}_setter",
488 f"Whether a service worker set {attr}.",
491 elif counter["type"] == "custom":
492 enum_name = f"Custom_{counter['name']}"
493 dedicated.append(
495 enum_name,
496 to_snake_case(counter["name"]),
497 f"Whether a dedicated worker {counter['desc']}.",
500 shared.append(
502 enum_name,
503 to_snake_case(counter["name"]),
504 f"Whether a shared worker {counter['desc']}.",
507 service.append(
509 enum_name,
510 to_snake_case(counter["name"]),
511 f"Whether a service worker {counter['desc']}.",
514 else:
515 print(
516 f"Found unexpected worker use counter type {counter['type']}. Returning 1."
518 return 1
520 # nsDeprecatedOperationsList.h parsing is adapted from parse_histograms.py.
521 operation_list_path = os.path.join(
522 buildconfig.topsrcdir, "dom", "base", "nsDeprecatedOperationList.h"
524 operation_regex = re.compile("^DEPRECATED_OPERATION\\(([^)]+)\\)")
525 ops_page = []
526 ops_doc = []
527 with open(operation_list_path) as f:
528 for line in f:
529 match = operation_regex.search(line)
530 if not match:
531 # No macro, probably whitespace or comment.
532 continue
534 op = match.group(1)
535 op_name = to_snake_case(op)
536 enum_name = f"eUseCounter_{op}"
537 ops_page.append((enum_name, op_name, f"Whether a page used {op}."))
538 ops_doc.append((enum_name, op_name, f"Whether a document used {op}."))
540 # Theoretically, we could do this without a completed build
541 # (ie, without the generated ServoCSSPropList.py) by sourcing direct from
542 # servo/components/style/properties/data.py:PropertiesData(engine=gecko).
544 # ...but parse_histograms.py doesn't do this the hard way. Should we?
546 import runpy
548 proplist_path = os.path.join(
549 buildconfig.topobjdir, "layout", "style", "ServoCSSPropList.py"
551 css_properties = runpy.run_path(proplist_path)["data"]
552 css_page = []
553 css_doc = []
554 for prop in css_properties.values():
555 # We prefix `prop_name` with `css_` to avoid colliding with C++ keywords
556 # like `float`.
557 prop_name = "css_" + to_snake_case(prop.name)
559 # Dependency keywords: CSS_PROP_PUBLIC_OR_PRIVATE, GenerateServoCSSPropList.py.
560 method = "Float" if prop.method == "CssFloat" else prop.method
561 # Dependency keywords: CSS_PROP_DOMPROP_PREFIXED, GenerateServoCSSPropList.py.
562 if method.startswith("Moz") and prop.type() != "alias":
563 method = method[3:] # remove the moz prefix
565 enum_name = f"eUseCounter_property_{method}"
566 css_page.append(
567 (enum_name, prop_name, f"Whether a page used the CSS property {prop.name}.")
569 css_doc.append(
571 enum_name,
572 prop_name,
573 f"Whether a document used the CSS property {prop.name}.",
577 # Counted unknown properties: AKA - stuff that doesn't exist, but we want
578 # to count uses of anyway.
579 # We _might_ decide to implement these in the future, though, so we just add
580 # them to the css_page, css_doc lists directly for continuity.
581 # (We do give them a different description, though)
583 import sys
585 sys.path.append(os.path.join(buildconfig.topsrcdir, "layout", "style"))
586 from GenerateCountedUnknownProperties import to_camel_case
588 unknown_proplist_path = os.path.join(
589 buildconfig.topsrcdir,
590 "servo",
591 "components",
592 "style",
593 "properties",
594 "counted_unknown_properties.py",
596 unknown_properties = runpy.run_path(unknown_proplist_path)[
597 "COUNTED_UNKNOWN_PROPERTIES"
599 for prop in unknown_properties:
600 enum_name = f"eUseCounter_unknown_property_{to_camel_case(prop)}"
601 prop_name = to_snake_case(prop)
602 css_page.append(
604 enum_name,
605 prop_name,
606 f"Whether a page used the (unknown, counted) CSS property {prop}.",
609 css_doc.append(
611 enum_name,
612 prop_name,
613 f"Whether a document used the (unknown, counted) CSS property {prop}.",
617 return (page, doc, dedicated, shared, service, ops_page, ops_doc, css_page, css_doc)
620 def to_snake_case(kebab_or_pascal):
622 Takes `kebab_or_pascal` which is in PascalCase or kebab-case
623 and conjugates it to "snake_case" (all lowercase, "_"-delimited).
625 return (
626 re.sub("([A-Z]+)", r"_\1", kebab_or_pascal).replace("-", "_").lower().strip("_")
630 def metric_map(f, *inputs):
632 Parses all use counters and outputs UseCounter.cpp which contains implementations
633 for two functions defined in UseCounter.h:
634 * const char* IncrementUseCounter(UseCounter aUseCounter, bool aIsPage)
635 * const char* IncrementWorkerUseCounter(UseCounterWorker aUseCounter, dom::WorkerKind aKind)
637 (Basically big switch statements mapping from enums to glean metrics, calling Add())
641 page,
642 doc,
643 dedicated,
644 shared,
645 service,
646 ops_page,
647 ops_doc,
648 css_page,
649 css_doc,
650 ) = parse_use_counters()
652 f.write(
653 """\
654 /* AUTOGENERATED by usecounters.py. DO NOT EDIT */
655 /* This Source Code Form is subject to the terms of the Mozilla Public
656 * License, v. 2.0. If a copy of the MPL was not distributed with this
657 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
659 #include "mozilla/dom/UseCounterMetrics.h"
661 #include "mozilla/dom/WorkerPrivate.h"
662 #include "mozilla/glean/GleanMetrics.h"
664 namespace mozilla::dom {
666 const char* IncrementUseCounter(UseCounter aUseCounter, bool aIsPage) {
667 static constexpr struct {
668 const char* name;
669 glean::impl::CounterMetric doc_metric;
670 glean::impl::CounterMetric page_metric;
671 } kEntries[] = {
675 # This order must match the order UseCounter is defined,
676 # (and we guarantee it via the MOZ_ASSERT below at runtime).
677 assert len(page) == len(doc)
678 assert len(ops_page) == len(ops_doc)
679 assert len(css_page) == len(css_doc)
681 index = 0
682 static_asserts = []
683 for pc, dc in zip(page, doc):
684 assert pc[0] == dc[0]
685 assert pc[1] == dc[1]
686 static_asserts.append(f"static_assert({index} == size_t(UseCounter::{pc[0]}));")
687 f.write(
688 f"""\
690 "{pc[1]}",
691 glean::use_counter_doc::{pc[1]},
692 glean::use_counter_page::{pc[1]},
696 index += 1
698 for pc, dc in zip(ops_page, ops_doc):
699 assert pc[0] == dc[0]
700 assert pc[1] == dc[1]
701 static_asserts.append(f"static_assert({index} == size_t(UseCounter::{pc[0]}));")
702 f.write(
703 f"""\
705 "deprecated_ops.{pc[1]}",
706 glean::use_counter_deprecated_ops_doc::{pc[1]},
707 glean::use_counter_deprecated_ops_page::{pc[1]},
711 index += 1
713 for pc, dc in zip(css_page, css_doc):
714 assert pc[0] == dc[0]
715 assert pc[1] == dc[1]
716 static_asserts.append(f"static_assert({index} == size_t(UseCounter::{pc[0]}));")
717 f.write(
718 f"""\
720 "css.{pc[1]}",
721 glean::use_counter_css_doc::{pc[1]},
722 glean::use_counter_css_page::{pc[1]},
726 index += 1
728 f.write("};\n")
729 f.write("\n".join(static_asserts))
730 f.write(
731 """\
732 MOZ_ASSERT(size_t(aUseCounter) < ArrayLength(kEntries));
733 const auto& entry = kEntries[size_t(aUseCounter)];
734 (aIsPage ? entry.page_metric : entry.doc_metric).Add();
735 return entry.name;
738 const char* IncrementWorkerUseCounter(UseCounterWorker aUseCounter, WorkerKind aKind) {
739 static constexpr struct {
740 const char* name;
741 glean::impl::CounterMetric dedicated_metric;
742 glean::impl::CounterMetric shared_metric;
743 glean::impl::CounterMetric service_metric;
744 } kEntries[] = {
747 assert len(dedicated) == len(shared)
748 assert len(dedicated) == len(service)
749 index = 0
750 static_asserts = []
751 for dc, sc, servicec in zip(dedicated, shared, service):
752 assert dc[0] == sc[0]
753 assert dc[1] == sc[1]
754 assert dc[0] == servicec[0]
755 assert dc[1] == servicec[1]
756 static_asserts.append(
757 f"static_assert({index} == size_t(UseCounterWorker::{dc[0]}));"
759 f.write(
760 f"""\
762 "{dc[1]}",
763 glean::use_counter_worker_dedicated::{dc[1]},
764 glean::use_counter_worker_shared::{dc[1]},
765 glean::use_counter_worker_service::{dc[1]},
769 index += 1
770 f.write("};\n")
771 f.write("\n".join(static_asserts))
772 f.write(
773 """\
774 MOZ_ASSERT(size_t(aUseCounter) < ArrayLength(kEntries));
775 const auto& entry = kEntries[size_t(aUseCounter)];
776 switch (aKind) {
777 case WorkerKind::WorkerKindDedicated:
778 entry.dedicated_metric.Add();
779 break;
780 case WorkerKind::WorkerKindShared:
781 entry.shared_metric.Add();
782 break;
783 case WorkerKind::WorkerKindService:
784 entry.service_metric.Add();
785 break;
787 return entry.name;
790 } // namespace mozilla