summaryrefslogtreecommitdiffstats
path: root/mozglue/baseprofiler/build
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /mozglue/baseprofiler/build
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mozglue/baseprofiler/build')
-rw-r--r--mozglue/baseprofiler/build/generate_profiling_categories.py350
-rw-r--r--mozglue/baseprofiler/build/profiling_categories.yaml301
2 files changed, 651 insertions, 0 deletions
diff --git a/mozglue/baseprofiler/build/generate_profiling_categories.py b/mozglue/baseprofiler/build/generate_profiling_categories.py
new file mode 100644
index 0000000000..64da056bbd
--- /dev/null
+++ b/mozglue/baseprofiler/build/generate_profiling_categories.py
@@ -0,0 +1,350 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This script generates ProfilingCategoryList.h and profiling_categories.rs
+# files from profiling_categories.yaml.
+
+from collections import OrderedDict
+
+import yaml
+
+CPP_HEADER_TEMPLATE = """\
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef {includeguard}
+#define {includeguard}
+
+/* This file is generated by generate_profiling_categories.py from
+ profiling_categories.yaml. DO NOT EDIT! */
+
+// Profiler sub-categories are applied to each sampled stack to describe the
+// type of workload that the CPU is busy with. Only one sub-category can be
+// assigned so be mindful that these are non-overlapping. The active category is
+// set by pushing a label to the profiling stack, or by the unwinder in cases
+// such as JITs. A profile sample in arbitrary C++/Rust will typically be
+// categorized based on the top of the label stack.
+//
+// The list of available color names for categories is:
+// transparent
+// blue
+// green
+// grey
+// lightblue
+// magenta
+// orange
+// purple
+// yellow
+
+// clang-format off
+
+{contents}
+
+// clang-format on
+
+#endif // {includeguard}
+"""
+
+CPP_MACRO_DEFINITION = """\
+#define MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY) \\
+"""
+
+RUST_TEMPLATE = """\
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This file is generated by generate_profiling_categories.py from
+ profiling_categories.yaml. DO NOT EDIT! */
+
+{contents}\
+"""
+
+RUST_ENUM_TEMPLATE = """\
+#[repr(u32)]
+#[derive(Debug, Copy, Clone)]
+pub enum {name} {{
+{fields}
+}}
+"""
+
+RUST_CONVERSION_IMPL_TEMPLATE = """\
+impl {name} {{
+ pub fn to_cpp_enum_value(&self) -> u32 {{
+{content}
+ }}
+}}
+"""
+
+RUST_DEFAULT_IMPL_TEMPLATE = """\
+impl Default for {name} {{
+ fn default() -> Self {{
+{content}
+ }}
+}}
+"""
+
+RUST_MATCH_SELF = """\
+ match *self {{
+{fields}
+ }}
+"""
+
+
+def generate_header(c_out, includeguard, contents):
+ c_out.write(
+ CPP_HEADER_TEMPLATE.format(includeguard=includeguard, contents=contents)
+ )
+
+
+def generate_rust_file(c_out, contents):
+ c_out.write(RUST_TEMPLATE.format(contents=contents))
+
+
+def load_yaml(yaml_path):
+ # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7+
+ # also preserves ordering for normal dictionaries.
+ # Code based on https://stackoverflow.com/a/21912744.
+ class OrderedLoader(yaml.Loader):
+ pass
+
+ def construct_mapping(loader, node):
+ loader.flatten_mapping(node)
+ return OrderedDict(loader.construct_pairs(node))
+
+ tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
+ OrderedLoader.add_constructor(tag, construct_mapping)
+
+ file_handler = open(yaml_path)
+ return yaml.load(file_handler, OrderedLoader)
+
+
+def generate_category_macro(name, label, color, subcategories):
+ contents = ' BEGIN_CATEGORY({name}, "{label}", "{color}") \\\n'.format(
+ name=name, label=label, color=color
+ )
+
+ subcategory_items = []
+
+ for subcategory in subcategories:
+ subcat_name = subcategory["name"]
+ assert isinstance(subcat_name, str)
+ subcat_label = subcategory["label"]
+ assert isinstance(subcat_label, str)
+
+ subcategory_items.append(
+ ' SUBCATEGORY({parent_cat}, {name}, "{label}") \\\n'.format(
+ parent_cat=name, name=subcat_name, label=subcat_label
+ )
+ )
+
+ contents += "".join(subcategory_items)
+ contents += " END_CATEGORY"
+
+ return contents
+
+
+def generate_macro_header(c_out, yaml_path):
+ """Generate ProfilingCategoryList.h from profiling_categories.yaml.
+ The generated file has a macro to generate the profiling category enums.
+ """
+
+ data = load_yaml(yaml_path)
+
+ # Stores the macro definition of each categories.
+ category_items = []
+
+ for category in data:
+ name = category["name"]
+ assert isinstance(name, str)
+ label = category["label"]
+ assert isinstance(label, str)
+ color = category["color"]
+ assert isinstance(color, str)
+ subcategories = category.get("subcategories", None)
+ assert (
+ isinstance(subcategories, list) and len(subcategories) > 0
+ ), "At least one subcategory expected as default in {}.".format(name)
+
+ category_items.append(
+ generate_category_macro(name, label, color, subcategories)
+ )
+
+ contents = CPP_MACRO_DEFINITION
+ contents += " \\\n".join(category_items)
+
+ generate_header(c_out, "baseprofiler_ProfilingCategoryList_h", contents)
+
+
+class RustEnum:
+ """Class that keeps the rust enum fields and impls.
+ This is used for generating the Rust ProfilingCategoryPair and ProfilingCategory
+ enums as well as ProfilingCategoryPair's sub category enums.
+ For example, this can either generate an enum with discrimant fields for sub
+ category enums and ProfilingCategory:
+ ```
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone)]
+ pub enum Graphics {
+ LayerBuilding = 0,
+ ...
+ }
+ ```
+ or can generate an enum with optional tuple values for ProfilingCategoryPair
+ to explicitly mention their sub categories:
+ ```
+ #[repr(u32)]
+ #[derive(Debug, Copy, Clone)]
+ pub enum ProfilingCategoryPair {
+ Network(Option<Network>),
+ ...
+ }
+ ```
+
+ And in addition to enums, it will generate impls for each enum. See one
+ example below:
+ ```
+ impl Default for Network {
+ fn default() -> Self {
+ Network::Other
+ }
+ }
+ ```
+ """
+
+ def __init__(self, name):
+ # Name of the Rust enum.
+ self.name = name
+ # Fields of the Rust enum. This list contains elements of
+ # (field_name, field_string) tuple for convenience.
+ self.fields = []
+ # Impls of the Rust enum. Each element is a string.
+ self.impls = []
+ # Default category of the Rust enum. Main enums won't have it, but all
+ # sub category enums must have one. This is being checked later.
+ self.default_category = None
+
+ def append_optional_tuple_field(self, field_name):
+ """Append the enum fields list with an optional tuple field."""
+ field = (field_name, " {name}(Option<{name}>),".format(name=field_name))
+ self.fields.append(field)
+
+ def append_discriminant_field(self, field_name, field_value):
+ """Append the enum fields list with a discriminant field."""
+ field = (
+ field_name,
+ " {name} = {value},".format(name=field_name, value=field_value),
+ )
+ self.fields.append(field)
+
+ def append_default_impl(self, default_category):
+ """Append the enum impls list with a default implementation."""
+ self.default_category = default_category
+
+ self.impls.append(
+ RUST_DEFAULT_IMPL_TEMPLATE.format(
+ name=self.name,
+ content=" {category}::{subcategory}".format(
+ category=self.name, subcategory=self.default_category
+ ),
+ )
+ )
+
+ def append_conversion_impl(self, content):
+ """Append the enum impls list with a conversion implementation for cpp values."""
+ self.impls.append(
+ RUST_CONVERSION_IMPL_TEMPLATE.format(name=self.name, content=content)
+ )
+
+ def to_rust_string(self):
+ """Serialize the enum with its impls as a string"""
+ joined_fields = "\n".join(map(lambda field: field[1], self.fields))
+ result = RUST_ENUM_TEMPLATE.format(name=self.name, fields=joined_fields)
+ result += "\n"
+ result += "\n".join(self.impls)
+ return result
+
+
+def generate_rust_enums(c_out, yaml_path):
+ """Generate profiling_categories.rs from profiling_categories.yaml.
+ The generated file has a profiling category enums and their impls.
+ """
+
+ data = load_yaml(yaml_path)
+
+ # Each category has its own enum for keeping its subcategories. We are
+ # keeping all of them here.
+ enums = []
+ # Parent enums for prifiling category and profiling category pair. They will
+ # be appended to the end of the `enums`.
+ profiling_category_pair_enum = RustEnum("ProfilingCategoryPair")
+ profiling_category_enum = RustEnum("ProfilingCategory")
+ profiling_category_pair_value = 0
+
+ for cat_index, category in enumerate(data):
+ cat_name = category["name"]
+ assert isinstance(cat_name, str)
+ cat_label = category["label"]
+ assert isinstance(cat_label, str)
+ # This will be used as our main enum field and sub category enum.
+ cat_label = "".join(filter(str.isalnum, cat_label))
+ cat_subcategories = category.get("subcategories", None)
+ assert (
+ isinstance(cat_subcategories, list) and len(cat_subcategories) > 0
+ ), "At least one subcategory expected as default in {}.".format(cat_name)
+
+ # Create a new enum for this sub category and append it to the enums list.
+ category_enum = RustEnum(cat_label)
+ enums.append(category_enum)
+
+ for subcategory in cat_subcategories:
+ subcat_name = subcategory["name"]
+ assert isinstance(subcat_name, str)
+ subcat_label = subcategory["label"]
+ assert isinstance(subcat_label, str)
+ friendly_subcat_name = None
+
+ if cat_name == subcat_name:
+ # This is the default sub-category. It should use the label as name.
+ friendly_subcat_name = subcat_label
+ category_enum.append_default_impl(subcat_label)
+ else:
+ # This is a non-default sub-category.
+ underscore_pos = subcat_name.find("_")
+ friendly_subcat_name = subcat_name[underscore_pos + 1 :]
+
+ friendly_subcat_name = "".join(filter(str.isalnum, friendly_subcat_name))
+ category_enum.append_discriminant_field(
+ friendly_subcat_name, profiling_category_pair_value
+ )
+ profiling_category_pair_value += 1
+
+ assert (
+ category_enum.default_category is not None
+ ), "There must be a default subcategory with the same name."
+
+ # Append the main enums.
+ profiling_category_pair_enum.append_optional_tuple_field(cat_label)
+ profiling_category_enum.append_discriminant_field(cat_label, cat_index)
+
+ # Add the main enums impls for conversion into cpp values.
+ profiling_category_pair_impl_fields = "\n".join(
+ " {enum_name}::{field_name}(val) => val.unwrap_or_default() as u32,".format(
+ enum_name="ProfilingCategoryPair", field_name=field
+ )
+ for field, _ in profiling_category_pair_enum.fields
+ )
+ profiling_category_pair_enum.append_conversion_impl(
+ RUST_MATCH_SELF.format(fields=profiling_category_pair_impl_fields)
+ )
+ profiling_category_enum.append_conversion_impl(" *self as u32")
+
+ # After adding all the sub category enums, we can add the main enums to the list.
+ enums.append(profiling_category_pair_enum)
+ enums.append(profiling_category_enum)
+
+ # Print all the enums and their impls.
+ contents = "\n".join(map(lambda enum: enum.to_rust_string(), enums))
+ generate_rust_file(c_out, contents)
diff --git a/mozglue/baseprofiler/build/profiling_categories.yaml b/mozglue/baseprofiler/build/profiling_categories.yaml
new file mode 100644
index 0000000000..62fd5d0617
--- /dev/null
+++ b/mozglue/baseprofiler/build/profiling_categories.yaml
@@ -0,0 +1,301 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Profiling categories
+# ====================
+# This file defines all profiling categories with their sub-categories. It is
+# parsed by generate_profiling_categories.py at build time to create
+# ProfilingCategoryList.h and profiling_categories.rs files.
+#
+# Profiling sub-categories are applied to each sampled stack to describe the
+# type of workload that the CPU is busy with. Only one sub-category can be
+# assigned so be mindful that these are non-overlapping. The active category is
+# set by pushing a label to the profiling stack, or by the unwinder in cases
+# such as JITs. A profile sample in arbitrary C++/Rust will typically be
+# categorized based on the top of the label stack.
+#
+# Each category consists of a name and a set of attributes that are described below:
+#
+# name [required]
+# ====
+# Name of the profiling category. This will be used in the C++ enum fields (not
+# by Rust).
+#
+# label [required]
+# =====
+# Label of the profiling category. This a more human readable string for the
+# category. Label will be displayed in the Firefox Profiler front-end. But also
+# this will be used as a Rust enum field (with non-alphanumeric characters
+# removed) because it's more idiomatic for Rust enums than name fields (which
+# are snake cased fields with all caps, which is not idiomatic to rust enum
+# field).
+#
+# color [required]
+# =====
+# Color that this category will show up as in the Firefox Profiler front-end.
+# The list of available color names for categories is:
+# - transparent
+# - blue
+# - green
+# - grey
+# - lightblue
+# - magenta
+# - orange
+# - purple
+# - yellow
+#
+# subcategories [required]
+# =============
+# A list of sub-categories that belong to this category.
+# There must be at least one sub-category for each category and there must be at
+# least one category with the same name as the category to indicate the default
+# sub-category. Each sub-category must have name and label attributes.
+#
+# name attribute should either be the same as the category (for default
+# sub-category) or should start with parent category name + underscore
+# (e.g. JS_Parsing).
+#
+# label attribute has the same purpose as parent category label attribute.
+#
+# For example:
+# - name: JS
+# subcategories:
+# - name: JS
+# label: Other
+# - name: JS_Parsing
+# label: Parsing
+#
+# Note that the first sub-category has the same name with the category. This is
+# the default sub-category. Also note the other sub-categories starting with the
+# category name + underscore.
+#
+
+- name: IDLE
+ label: Idle
+ color: transparent
+ subcategories:
+ - name: IDLE
+ label: Other
+
+- name: OTHER
+ label: Other
+ color: grey
+ subcategories:
+ - name: OTHER
+ label: Other
+ - name: OTHER_PreferenceRead
+ label: Preference Read
+ - name: OTHER_Profiling
+ label: Profiling
+
+- name: TEST
+ label: Test
+ color: darkgray
+ subcategories:
+ - name: TEST
+ label: Test
+
+- name: LAYOUT
+ label: Layout
+ color: purple
+ subcategories:
+ - name: LAYOUT
+ label: Other
+ - name: LAYOUT_FrameConstruction
+ label: Frame construction
+ - name: LAYOUT_Reflow
+ label: Reflow
+ - name: LAYOUT_CSSParsing
+ label: CSS parsing
+ - name: LAYOUT_SelectorQuery
+ label: Selector query
+ - name: LAYOUT_StyleComputation
+ label: Style computation
+ - name: LAYOUT_Destroy
+ label: Layout cleanup
+
+- name: JS
+ label: JavaScript
+ color: yellow
+ subcategories:
+ - name: JS
+ label: Other
+ - name: JS_Parsing
+ label: Parsing
+ - name: JS_BaselineCompilation
+ label: JIT Compile (baseline)
+ - name: JS_IonCompilation
+ label: JIT Compile (ion)
+ - name: JS_Interpreter
+ label: Interpreter
+ - name: JS_BaselineInterpret
+ label: JIT (baseline-interpreter)
+ - name: JS_Baseline
+ label: JIT (baseline)
+ - name: JS_IonMonkey
+ label: JIT (ion)
+ - name: JS_Builtin
+ label: Builtin API
+ - name: JS_Wasm
+ label: Wasm
+
+- name: GCCC
+ label: GC / CC
+ color: orange
+ subcategories:
+ - name: GCCC
+ label: Other
+ - name: GCCC_MinorGC
+ label: Minor GC
+ - name: GCCC_MajorGC
+ label: Major GC (Other)
+ - name: GCCC_MajorGC_Mark
+ label: Major GC (Mark)
+ - name: GCCC_MajorGC_Sweep
+ label: Major GC (Sweep)
+ - name: GCCC_MajorGC_Compact
+ label: Major GC (Compact)
+ - name: GCCC_UnmarkGray
+ label: Unmark Gray
+ - name: GCCC_Barrier
+ label: Barrier
+ - name: GCCC_FreeSnowWhite
+ label: CC (Free Snow White)
+ - name: GCCC_BuildGraph
+ label: CC (Build Graph)
+ - name: GCCC_ScanRoots
+ label: CC (Scan Roots)
+ - name: GCCC_CollectWhite
+ label: CC (Collect White)
+ - name: GCCC_Finalize
+ label: CC (Finalize)
+
+- name: NETWORK
+ label: Network
+ color: lightblue
+ subcategories:
+ - name: NETWORK
+ label: Other
+
+- name: GRAPHICS
+ label: Graphics
+ color: green
+ subcategories:
+ - name: GRAPHICS
+ label: Other
+ - name: GRAPHICS_DisplayListBuilding
+ label: DisplayList building
+ - name: GRAPHICS_DisplayListMerging
+ label: DisplayList merging
+ - name: GRAPHICS_LayerBuilding
+ label: Layer building
+ - name: GRAPHICS_TileAllocation
+ label: Tile allocation
+ - name: GRAPHICS_WRDisplayList
+ label: WebRender display list
+ - name: GRAPHICS_Rasterization
+ label: Rasterization
+ - name: GRAPHICS_FlushingAsyncPaints
+ label: Flushing async paints
+ - name: GRAPHICS_ImageDecoding
+ label: Image decoding
+
+- name: DOM
+ label: DOM
+ color: blue
+ subcategories:
+ - name: DOM
+ label: Other
+
+- name: JAVA_ANDROID
+ label: Android
+ color: yellow
+ subcategories:
+ - name: JAVA_ANDROID
+ label: Other
+
+- name: JAVA_ANDROIDX
+ label: AndroidX
+ color: orange
+ subcategories:
+ - name: JAVA_ANDROIDX
+ label: Other
+
+- name: JAVA_LANGUAGE
+ label: Java
+ color: blue
+ subcategories:
+ - name: JAVA_LANGUAGE
+ label: Other
+
+- name: JAVA_MOZILLA
+ label: Mozilla
+ color: green
+ subcategories:
+ - name: JAVA_MOZILLA
+ label: Other
+
+- name: JAVA_KOTLIN
+ label: Kotlin
+ color: purple
+ subcategories:
+ - name: JAVA_KOTLIN
+ label: Other
+
+- name: JAVA_BLOCKED
+ label: Blocked
+ color: lightblue
+ subcategories:
+ - name: JAVA_BLOCKED
+ label: Other
+
+- name: IPC
+ label: IPC
+ color: lightgreen
+ subcategories:
+ - name: IPC
+ label: Other
+
+- name: MEDIA
+ label: Media
+ color: orange
+ subcategories:
+ - name: MEDIA
+ label: Other
+ - name: MEDIA_CUBEB
+ label: Cubeb
+ - name: MEDIA_PLAYBACK
+ label: Playback
+ - name: MEDIA_RT
+ label: Real-time rendering
+
+# We don't name this category ACCESSIBILITY
+# because it's already defined as a macro.
+- name: A11Y
+ label: Accessibility
+ color: brown
+ subcategories:
+ - name: A11Y
+ label: Other
+
+- name: PROFILER
+ label: Profiler
+ color: lightred
+ subcategories:
+ - name: PROFILER
+ label: Other
+
+- name: TIMER
+ label: Timer
+ color: grey
+ subcategories:
+ - name: TIMER
+ label: Other
+
+- name: REMOTE_PROTOCOL
+ label: Remote-Protocol
+ color: grey
+ subcategories:
+ - name: REMOTE_PROTOCOL
+ label: Other