summaryrefslogtreecommitdiffstats
path: root/tools/profiler/docs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /tools/profiler/docs
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--tools/profiler/docs/buffer.rst70
-rw-r--r--tools/profiler/docs/index.rst36
-rw-r--r--tools/profiler/docs/instrumenting-javascript.rst55
-rw-r--r--tools/profiler/docs/markers-guide.rst477
-rw-r--r--tools/profiler/docs/memory.rst46
5 files changed, 684 insertions, 0 deletions
diff --git a/tools/profiler/docs/buffer.rst b/tools/profiler/docs/buffer.rst
new file mode 100644
index 0000000000..dd7ef30dfd
--- /dev/null
+++ b/tools/profiler/docs/buffer.rst
@@ -0,0 +1,70 @@
+Buffers and Memory Management
+=============================
+
+In a post-Fission world, precise memory management across many threads and processes is
+especially important. In order for the profiler to achieve this, it uses a chunked buffer
+strategy.
+
+The `ProfileBuffer`_ is the overall buffer class that controls the memory and storage
+for the profile, it allows allocating objects into it. This can be used freely
+by things like markers and samples to store data as entries, without needing to know
+about the general strategy for how the memory is managed.
+
+The `ProfileBuffer`_ is then backed by the `ProfileChunkedBuffer`_. This specialized
+buffer grows incrementally, by allocating additional `ProfileBufferChunk`_ objects.
+More and more chunks will be allocated until a memory limit is reached, where they will
+be released. After releasing, the chunk will either be recycled or freed.
+
+The limiting of memory usage is coordinated by the `ProfilerParent`_ in the parent
+process. The `ProfilerParent`_ and `ProfilerChild`_ exchange IPC messages with information
+about how much memory is being used. When the maximum byte threshold is passed,
+the ProfileChunkManager in the parent process removes the oldest chunk, and then the
+`ProfilerParent`_ sends a `DestroyReleasedChunksAtOrBefore`_ message to all of child
+processes so that the oldest chunks in the profile are released. This helps long profiles
+to keep having data in a similar time frame.
+
+Profile Buffer Terminology
+##########################
+
+ProfilerParent
+ The main profiler machinery is installed in the parent process. It uses IPC to
+ communicate to the child processes. The PProfiler is the actor which is used
+ to communicate across processes to coordinate things. See `ProfilerParent.h`_. The
+ ProfilerParent uses the DestroyReleasedChunksAtOrBefore meessage to control the
+ overall chunk limit.
+
+ProfilerChild
+ ProfilerChild is installed in every child process, it will receive requests from
+ DestroyReleasedChunksAtOrBefore.
+
+Entry
+ This is an individual entry in the `ProfileBuffer.h`_,. These entry sizes are not
+ related to the chunks sizes. An individual entry can straddle two different chunks.
+ An entry can contain various pieces of data, like markers, samples, and stacks.
+
+Chunk
+ An arbitrary sized chunk of memory, managed by the `ProfileChunkedBuffer`_, and
+ IPC calls from the ProfilerParent.
+
+Unreleased Chunk
+ This chunk is currently being used to write entries into.
+
+Released chunk
+ This chunk is full of data. When memory limits happen, it can either be recycled
+ or freed.
+
+Recycled chunk
+ This is a chunk that was previously written into, and full. When memory limits occur,
+ rather than freeing the memory, it is re-used as the next chunk.
+
+.. _ProfileChunkedBuffer: https://searchfox.org/mozilla-central/search?q=ProfileChunkedBuffer&path=&case=true&regexp=false
+.. _ProfileChunkManager: https://searchfox.org/mozilla-central/search?q=ProfileBufferChunkManager.h&path=&case=true&regexp=false
+.. _ProfileBufferChunk: https://searchfox.org/mozilla-central/search?q=ProfileBufferChunk&path=&case=true&regexp=false
+.. _ProfileBufferChunkManagerWithLocalLimit: https://searchfox.org/mozilla-central/search?q=ProfileBufferChunkManagerWithLocalLimit&case=true&path=
+.. _ProfilerParent.h: https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerParent.h
+.. _ProfilerChild.h: https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerChild.h
+.. _ProfileBuffer.h: https://searchfox.org/mozilla-central/source/tools/profiler/core/ProfileBuffer.h
+.. _ProfileBuffer: https://searchfox.org/mozilla-central/search?q=ProfileBuffer&path=&case=true&regexp=false
+.. _ProfilerParent: https://searchfox.org/mozilla-central/search?q=ProfilerParent&path=&case=true&regexp=false
+.. _ProfilerChild: https://searchfox.org/mozilla-central/search?q=ProfilerChild&path=&case=true&regexp=false
+.. _DestroyReleasedChunksAtOrBefore: https://searchfox.org/mozilla-central/search?q=DestroyReleasedChunksAtOrBefore&path=&case=true&regexp=false
diff --git a/tools/profiler/docs/index.rst b/tools/profiler/docs/index.rst
new file mode 100644
index 0000000000..e7a99f2df7
--- /dev/null
+++ b/tools/profiler/docs/index.rst
@@ -0,0 +1,36 @@
+Gecko Profiler
+==============
+
+The Firefox Profiler is the collection of tools used to profile Firefox. This is backed
+by the Gecko Profiler, which is the primarily C++ component that instruments Gecko. It
+is configurable, and supports a variety of data sources and recording modes. Primarily,
+it is used as a stastical profiler, where the execution of threads that have been
+registered with the profile is paused, and a sample is taken. Generally, this includes
+a stackwalk with combined native stack frame, JavaScript stack frames, and custom stack
+frame labels.
+
+In addition to the sampling, the profiler can collect markers, which are collected
+deterministically (as opposed to statistically, like samples). These include some
+kind of text description, and optionally a payload with more information.
+
+This documentation serves to document the Gecko Profiler and Base Profiler components,
+while the profiler.firefox.com interface is documented at `profiler.firefox.com/docs/ <https://profiler.firefox.com/docs/>`_
+
+.. toctree::
+ :maxdepth: 1
+
+ buffer
+ instrumenting-javascript
+ markers-guide
+ memory
+
+The following areas still need documentation:
+
+ * LUL
+ * Instrumenting Java
+ * Instrumenting Rust
+ * Registering Threads
+ * Samples and Stack Walking
+ * Triggering Gecko Profiles in Automation
+ * JS Tracer
+ * Serialization
diff --git a/tools/profiler/docs/instrumenting-javascript.rst b/tools/profiler/docs/instrumenting-javascript.rst
new file mode 100644
index 0000000000..91575b9198
--- /dev/null
+++ b/tools/profiler/docs/instrumenting-javascript.rst
@@ -0,0 +1,55 @@
+Instrumenting JavaScript
+========================
+
+There are multiple ways to use the profiler with JavaScript. There is the "JavaScript"
+profiler feature (via about:profiling), which enables stack walking for JavaScript code.
+This is most likely turned on already for every profiler preset.
+
+In addition, markers can be created to specifically marker an instant in time, or a
+duration. This can be helpful to make sense of a particular piece of the front-end,
+or record events that normally wouldn't show up in samples.
+
+Markers in Browser Chrome
+*************************
+
+If you have access to ChromeUtils, then adding a marker is relatively easily.
+
+.. code-block:: javascript
+
+ // Add an instant marker, representing a single point in time
+ ChromeUtils.addProfilerMarker("MarkerName");
+
+ // Add a duration marker, representing a span of time.
+ const startTime = Cu.now();
+ doWork();
+ ChromeUtils.addProfilerMarker("MarkerName", startTime);
+
+ // Add a duration marker, representing a span of time, with some additional tex
+ const startTime = Cu.now();
+ doWork();
+ ChromeUtils.addProfilerMarker("MarkerName", startTime, "Details about this event");
+
+ // Add an instant marker, with some additional tex
+ const startTime = Cu.now();
+ doWork();
+ ChromeUtils.addProfilerMarker("MarkerName", undefined, "Details about this event");
+
+Markers in Content Code
+***********************
+
+If instrumenting content code, then the `UserTiming`_ API is the best bet.
+:code:`performance.mark` will create an instant marker, and a :code:`performance.measure`
+will create a duration marker. These markers will show up under UserTiming in
+the profiler UI.
+
+.. code-block:: javascript
+
+ // Create an instant marker.
+ performance.mark("InstantMarkerName");
+
+ doWork();
+
+ // Measuring with the performance API will also create duration markers.
+ performance.measure("DurationMarkerName", "InstantMarkerName");
+
+.. _UserTiming: https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API
diff --git a/tools/profiler/docs/markers-guide.rst b/tools/profiler/docs/markers-guide.rst
new file mode 100644
index 0000000000..a4d431fa48
--- /dev/null
+++ b/tools/profiler/docs/markers-guide.rst
@@ -0,0 +1,477 @@
+Markers
+=======
+
+Markers are packets of arbitrary data that are added to a profile by the Firefox code, usually to
+indicate something important happening at a point in time, or during an interval of time.
+
+Each marker has a name, a category, some common optional information (timing, backtrace, etc.),
+and an optional payload of a specific type (containing arbitrary data relevant to that type).
+
+
+Example
+-------
+
+Short example, details below.
+
+Note: Most marker-related identifiers are in the ``mozilla`` namespace, to be added where necessary.
+
+.. code-block:: c++
+
+ // Record a simple marker with the category of DOM.
+ PROFILER_MARKER_UNTYPED("Marker Name", DOM);
+
+ // Create a marker with some additional text information. (Be wary of printf!)
+ PROFILER_MARKER_TEXT("Marker Name", JS, MarkerOptions{}, "Additional text information.");
+
+ // Record a custom marker of type `ExampleNumberMarker` (see definition below).
+ PROFILER_MARKER("Number", OTHER, MarkerOptions{}, ExampleNumberMarker, 42);
+
+.. code-block:: c++
+
+ // Marker type definition.
+ struct ExampleNumberMarker {
+ // Unique marker type name.
+ static constexpr Span<const char> MarkerTypeName() { return MakeStringSpan("number"); }
+ // Data specific to this marker type, serialized to JSON for profiler.firefox.com.
+ static void StreamJSONMarkerData(SpliceableJSONWriter& aWriter, int aNumber) {
+ aWriter.IntProperty("number", aNumber);
+ }
+ // Where and how to display the marker and its data.
+ static MarkerSchema MarkerTypeDisplay() {
+ using MS = MarkerSchema;
+ MS schema(MS::Location::markerChart, MS::Location::markerTable);
+ schema.SetChartLabel("Number: {marker.data.number}");
+ schema.AddKeyLabelFormat("number", "Number", MS::Format::number);
+ return schema;
+ }
+ };
+
+
+How to Record Markers
+---------------------
+
+Header to Include
+^^^^^^^^^^^^^^^^^
+
+If the compilation unit only defines and records untyped, text, and/or its own markers, include
+`the main profiler markers header <https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerMarkers.h>`_:
+
+.. code-block:: c++
+
+ #include "mozilla/ProfilerMarkers.h"
+
+If it also records one of the other common markers defined in
+`ProfilerMarkerTypes.h <https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerMarkerTypes.h>`_,
+include that one instead:
+
+.. code-block:: c++
+
+ #include "mozilla/ProfilerMarkerTypes.h"
+
+And if it uses any other profiler functions (e.g., labels), use
+`the main Gecko Profiler header <https://searchfox.org/mozilla-central/source/tools/profiler/public/GeckoProfiler.h>`_
+instead:
+
+.. code-block:: c++
+
+ #include "GeckoProfiler.h"
+
+The above works from source files that end up in libxul, which is true for the majority
+of Firefox source code. But some files live outside of libxul, such as mfbt, in which
+case the advice is the same but the equivalent headers are from the Base Profiler instead:
+
+.. code-block:: c++
+
+ #include "mozilla/BaseProfilerMarkers.h" // Only own/untyped/text markers
+ #include "mozilla/BaseProfilerMarkerTypes.h" // Only common markers
+ #include "BaseProfiler.h" // Markers and other profiler functions
+
+Untyped Markers
+^^^^^^^^^^^^^^^
+
+Untyped markers don't carry any information apart from common marker data:
+Name, category, options.
+
+.. code-block:: c++
+
+ PROFILER_MARKER_UNTYPED(
+ // Name, and category pair.
+ "Marker Name", OTHER,
+ // Marker options, may be omitted if all defaults are acceptable.
+ MarkerOptions(MarkerStack::Capture(), ...));
+
+``PROFILER_MARKER_UNTYPED`` is a macro that simplifies the use of the main
+``profiler_add_marker`` function, by adding the appropriate namespaces, and a surrounding
+``#ifdef MOZ_GECKO_PROFILER`` guard.
+
+1. Marker name
+ The first argument is the name of this marker. This will be displayed in most places
+ the marker is shown. It can be a literal C string, or any dynamic string object.
+2. `Category pair name <https://searchfox.org/mozilla-central/define?q=M_174bb0de187ee7d9>`_
+ Choose a category + subcategory from the `the list of categories <https://searchfox.org/mozilla-central/define?q=M_174bb0de187ee7d9>`_.
+ This is the second parameter of each ``SUBCATEGORY`` line, for instance ``LAYOUT_Reflow``.
+ (Internally, this is really a `MarkerCategory <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerCategory>`_
+ object, in case you need to construct it elsewhere.)
+3. `MarkerOptions <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerOptions>`_
+ See the options below. It can be omitted if there are no other arguments, ``{}``, or
+ ``MarkerOptions()`` (no specified options); only one of the following option types
+ alone; or ``MarkerOptions(...)`` with one or more of the following options types:
+
+ * `MarkerThreadId <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerThreadId>`_
+ Rarely used, as it defaults to the current thread. Otherwise it specifies the target
+ "thread id" (aka "track") where the marker should appear; This may be useful when
+ referring to something that happened on another thread (use ``profiler_current_thread_id()``
+ from the original thread to get its id); or for some important markers, they may be
+ sent to the "main thread", which can be specified with ``MarkerThreadId::MainThread()``.
+ * `MarkerTiming <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerTiming>`_
+ This specifies an instant or interval of time. It defaults to the current instant if
+ left unspecified. Otherwise use ``MarkerTiming::InstantAt(timestamp)`` or
+ ``MarkerTiming::Interval(ts1, ts2)``; timestamps are usually captured with
+ ``TimeStamp::Now()``. It is also possible to record only the start or the end of an
+ interval, pairs of start/end markers will be matched by their name. *Note: The
+ upcoming "marker sets" feature will make this pairing more reliable, and also
+ allow more than two markers to be connected*.
+ * `MarkerStack <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerStack>`_
+ By default, markers do not record a "stack" (or "backtrace"). To record a stack at
+ this point, in the most efficient manner, specify ``MarkerStack::Capture()``. To
+ record a previously captured stack, first store a stack into a
+ ``UniquePtr<ProfileChunkedBuffer>`` with ``profiler_capture_backtrace()``, then pass
+ it to the marker with ``MarkerStack::TakeBacktrace(std::move(stack))``.
+ * `MarkerInnerWindowId <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerInnerWindowId>`_
+ If you have access to an "inner window id", consider specifying it as an option, to
+ help profiler.firefox.com to classify them by tab.
+
+Text Markers
+^^^^^^^^^^^^
+
+Text markers are very common, they carry an extra text as a fourth argument, in addition to
+the marker name. Use the following macro:
+
+.. code-block:: c++
+
+ PROFILER_MARKER_TEXT(
+ // Name, category pair, options.
+ "Marker Name", OTHER, {},
+ // Text string.
+ "Here are some more details."
+ );
+
+As useful as it is, using an expensive ``printf`` operation to generate a complex text
+comes with a variety of issues string. It can leak potentially sensitive information
+such as URLs can be leaked during the profile sharing step. profiler.firefox.com cannot
+access the information programmatically. It won't get the formatting benefits of the
+built-in marker schema. Please consider using a custom marker type to separate and
+better present the data.
+
+Other Typed Markers
+^^^^^^^^^^^^^^^^^^^
+
+From C++ code, a marker of some type ``YourMarker`` (details about type definition follow) can be
+recorded like this:
+
+.. code-block:: c++
+
+ PROFILER_MARKER(
+ "YourMarker name", OTHER,
+ MarkerOptions(MarkerTiming::IntervalUntilNowFrom(someStartTimestamp),
+ MarkerInnerWindowId(innerWindowId))),
+ YourMarker, "some string", 12345, "http://example.com", someTimeStamp);
+
+After the first three common arguments (like in ``PROFILER_MARKER_UNTYPED``), there are:
+
+4. The marker type, which is the name of the C++ ``struct`` that defines that type.
+5. A variadic list of type-specific argument. They must match the number of, and must
+ be convertible to, ``StreamJSONMarkerData`` parameters as specified in the marker type definition.
+
+"Auto" Scoped Interval Markers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To capture time intervals around some important operations, it is common to store a timestamp, do the work,
+and then record a marker, e.g.:
+
+.. code-block:: c++
+
+ void DoTimedWork() {
+ TimeStamp start = TimeStamp::Now();
+ DoWork();
+ PROFILER_MARKER_TEXT("Timed work", OTHER, MarkerTiming::IntervalUntilNowFrom(start), "Details");
+ }
+
+`RAII <https://en.cppreference.com/w/cpp/language/raii>`_ objects automate this, by recording the time
+when the object is constructed, and later recording the marker when the object is destroyed at the end
+of its C++ scope.
+This is especially useful if there are multiple scope exit points.
+
+``AUTO_PROFILER_MARKER_TEXT`` is `the only one implemented <https://searchfox.org/mozilla-central/define?q=M_ac7b392646edf5a5>`_ at this time.
+
+.. code-block:: c++
+
+ void MaybeDoTimedWork(bool aDoIt) {
+ AUTO_PROFILER_MARKER_TEXT("Timed work", OTHER, "Details");
+ if (!aDoIt) { /* Marker recorded here... */ return; }
+ DoWork();
+ /* ... or here. */
+ }
+
+Note that these RAII objects only record one marker. In some situation, a very long
+operation could be missed if it hasn't completed by the end of the profiling session.
+In this case, consider recording two distinct markers, using
+``MarkerTiming::IntervalStart()`` and ``MarkerTiming::IntervalEnd()``.
+
+Where to Define New Marker Types
+--------------------------------
+
+The first step is to determine the location of the marker type definition:
+
+* If this type is only used in one function, or a component, it can be defined in a
+ local common place relative to its use.
+* For a more common type that could be used from multiple locations:
+
+ * If there is no dependency on XUL, it can be defined in the Base Profiler, which can
+ be used in most locations in the codebase:
+ `mozglue/baseprofiler/public/BaseProfilerMarkerTypes.h <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/BaseProfilerMarkerTypes.h>`__
+
+ * However, if there is a XUL dependency, then it needs to be defined in the Gecko Profiler:
+ `tools/profiler/public/ProfilerMarkerTypes.h <https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerMarkerTypes.h>`__
+
+How to Define New Marker Types
+------------------------------
+
+Each marker type must be defined once and only once.
+The definition is a C++ ``struct``, its identifier is used when recording
+markers of that type in C++.
+By convention, the suffix "Marker" is recommended to better distinguish them
+from non-profiler entities in the source.
+
+.. code-block:: c++
+
+ struct YourMarker {
+
+Marker Type Name
+^^^^^^^^^^^^^^^^
+
+A marker type must have a unique name, it is used to keep track of the type of
+markers in the profiler storage, and to identify them uniquely on profiler.firefox.com.
+(It does not need to be the same as the ``struct``'s name.)
+
+This name is defined in a special static member function ``MarkerTypeName``:
+
+.. code-block:: c++
+
+ // …
+ static constexpr Span<const char> MarkerTypeName() {
+ return MakeStringSpan("YourMarker");
+ }
+
+Marker Type Data
+^^^^^^^^^^^^^^^^
+
+All markers of any type have some common data: A name, a category, options like
+timing, etc. as previously explained.
+
+In addition, a certain marker type may carry zero of more arbitrary pieces of
+information, and they are always the same for all markers of that type.
+
+These are defined in a special static member function ``StreamJSONMarkerData``.
+
+The first function parameters is always ``SpliceableJSONWriter& aWriter``,
+it will be used to stream the data as JSON, to later be read by
+profiler.firefox.com.
+
+.. code-block:: c++
+
+ // …
+ static void StreamJSONMarkerData(SpliceableJSONWriter& aWriter,
+
+The following function parameters is how the data is received as C++ objects
+from the call sites.
+
+* Most C/C++ `POD (Plain Old Data) <https://en.cppreference.com/w/cpp/named_req/PODType>`_
+ and `trivially-copyable <https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable>`_
+ types should work as-is, including ``TimeStamp``.
+* Character strings should be passed using ``const ProfilerString8View&`` (this handles
+ literal strings, and various ``std::string`` and ``nsCString`` types, and spans with or
+ without null terminator). Use ``const ProfilerString16View&`` for 16-bit strings such as
+ ``nsString``.
+* Other types can be used if they define specializations for ``ProfileBufferEntryWriter::Serializer``
+ and ``ProfileBufferEntryReader::Deserializer``. You should rarely need to define new
+ ones, but if needed see how existing specializations are written, or contact the
+ `perf-tools team for help <https://chat.mozilla.org/#/room/#profiler:mozilla.org>`_.
+
+Passing by value or by reference-to-const is recommended, because arguments are serialized
+in binary form (i.e., there are no optimizable ``move`` operations).
+
+For example, here's how to handle a string, a 64-bit number, another string, and
+a timestamp:
+
+.. code-block:: c++
+
+ // …
+ const ProfilerString8View& aString,
+ const int64_t aBytes,
+ const ProfilerString8View& aURL,
+ const TimeStamp& aTime) {
+
+Then the body of the function turns these parameters into a JSON stream.
+
+When this function is called, the writer has just started a JSON object, so
+everything that is written should be a named object property. Use
+``SpliceableJSONWriter`` functions, in most cases ``...Property`` functions
+from its parent class ``JSONWriter``: ``NullProperty``, ``BoolProperty``,
+``IntProperty``, ``DoubleProperty``, ``StringProperty``. (Other nested JSON
+types like arrays or objects are not supported by the profiler.)
+
+As a special case, ``TimeStamps`` must be streamed using ``aWriter.TimeProperty(timestamp)``.
+
+The property names will be used to identify where each piece of data is stored and
+how it should be displayed on profiler.firefox.com (see next section).
+
+Here's how the above functions parameters could be streamed:
+
+.. code-block:: c++
+
+ // …
+ aWriter.StringProperty("myString", aString);
+ aWriter.IntProperty("myBytes", aBytes);
+ aWriter.StringProperty("myURL", aURL);
+ aWriter.TimeProperty("myTime", aTime);
+ }
+
+Marker Type Display Schema
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now that we have defined how to stream type-specific data (from Firefox to
+profiler.firefox.com), we need to describe where and how this data will be
+displayed on profiler.firefox.com.
+
+The static member function ``MarkerTypeDisplay`` returns an opaque ``MarkerSchema``
+object, which will be forwarded to profiler.firefox.com.
+
+.. code-block:: c++
+
+ // …
+ static MarkerSchema MarkerTypeDisplay() {
+
+The ``MarkerSchema`` type will be used repeatedly, so for convenience we can define
+a local type alias:
+
+.. code-block:: c++
+
+ // …
+ using MS = MarkerSchema;
+
+First, we construct the ``MarkerSchema`` object to be returned at the end.
+
+One or more constructor arguments determine where this marker will be displayed in
+the profiler.firefox.com UI. See the `MarkerSchema::Location enumeration for the
+full list <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerSchema%3A%3ALocation>`_.
+
+Here is the most common set of locations, showing markers of that type in both the
+Marker Chart and the Marker Table panels:
+
+.. code-block:: c++
+
+ // …
+ MS schema(MS::Location::markerChart, MS::Location::markerTable);
+
+Some labels can optionally be specified, to display certain information in different
+locations: ``SetChartLabel``, ``SetTooltipLabel``, and ``SetTableLabel``; or
+``SetAllLabels`` to define all of them the same way.
+
+The arguments is a string that may refer to marker data within braces:
+
+* ``{marker.name}``: Marker name.
+* ``{marker.data.X}``: Type-specific data, as streamed with property name "X" from ``StreamJSONMarkerData`` (e.g., ``aWriter.IntProperty("X", aNumber);``
+
+For example, here's how to set the Marker Chart label to show the marker name and the
+``myBytes`` number of bytes:
+
+.. code-block:: c++
+
+ // …
+ schema.SetChartLabel("{marker.name} – {marker.data.myBytes}");
+
+profiler.firefox.com will apply the label with the data in a consistent manner. For
+example, with this label definition, it could display marker information like the
+following in the Firefox Profiler's Marker Chart:
+
+ * "Marker Name – 10B"
+ * "Marker Name – 25.204KB"
+ * "Marker Name – 512.54MB"
+
+For implementation details on this processing, see `src/profiler-logic/marker-schema.js <https://github.com/firefox-devtools/profiler/blob/main/src/profile-logic/marker-schema.js>`_
+in the profiler's front-end.
+
+Next, define the main display of marker data, which will appear in the Marker
+Chart tooltips and the Marker Table sidebar.
+
+Each row may either be:
+
+* A dynamic key-value pair, using one of the ``MarkerSchema::AddKey...`` functions. Each function is given:
+
+ * Key: Element property name as streamed in ``StreamJSONMarkerData``.
+ * Label: Optional prefix. Defaults to the key name.
+ * Format: How to format the data element value, see `MarkerSchema::Format for details <https://searchfox.org/mozilla-central/define?q=T_mozilla%3A%3AMarkerSchema%3A%3AFormat>`_.
+ * Searchable: Optional boolean, indicates if the value is used in searches, defaults to false.
+
+* Or a fixed label and value strings, using ``MarkerSchema::AddStaticLabelValue``.
+
+.. code-block:: c++
+
+ // …
+ schema.AddKeyLabelFormatSearchable(
+ "myString", "My String", MS::Format::string, true);
+ schema.AddKeyLabelFormat(
+ "myBytes", "My Bytes", MS::Format::bytes);
+ schema.AddKeyLabelFormat(
+ "myUrl", "My URL", MS::Format::url);
+ schema.AddKeyLabelFormat(
+ "myTime", "Event time", MS::Format::time);
+
+Finally the ``schema`` object is returned from the function:
+
+.. code-block:: c++
+
+ // …
+ return schema;
+ }
+
+Any other ``struct`` member function is ignored. There could be utility functions used by the above
+compulsory functions, to make the code clearer.
+
+And that is the end of the marker definition ``struct``.
+
+.. code-block:: c++
+
+ // …
+ };
+
+Performance Considerations
+--------------------------
+
+During profiling, it is best to reduce the amount of work spent doing profiler
+operations, as they can influence the performance of the code that you want to profile.
+
+Whenever possible, consider passing simple types to marker functions, such that
+``StreamJSONMarkerData`` will do the minimum amount of work necessary to serialize
+the marker type-specific arguments to its internal buffer representation. POD types
+(numbers) and strings are the easiest and cheapest to serialize. Look at the
+corresponding ``ProfileBufferEntryWriter::Serializer`` specializations if you
+want to better understand the work done.
+
+Avoid doing expensive operations when recording markers. E.g.: ``printf`` of
+different things into a string, or complex computations; instead pass the
+``printf``/computation arguments straight through to the marker function, so that
+``StreamJSONMarkerData`` can do the expensive work at the end of the profiling session.
+
+Marker Architecture Description
+-------------------------------
+
+The above sections should give all the information needed for adding your own marker
+types. However, if you are wanting to work on the marker architecture itself, this
+section will describe how the system works.
+
+TODO:
+ * Briefly describe the buffer and serialization.
+ * Describe the template strategy for generating marker types
+ * Describe the serialization and link to profiler front-end docs on marker processing (if they exist)
diff --git a/tools/profiler/docs/memory.rst b/tools/profiler/docs/memory.rst
new file mode 100644
index 0000000000..347a91f9e7
--- /dev/null
+++ b/tools/profiler/docs/memory.rst
@@ -0,0 +1,46 @@
+Profiling Memory
+================
+
+Sampling stacks from native allocations
+---------------------------------------
+
+The profiler can sample allocations and de-allocations from malloc using the
+"Native Allocations" feature. This can be enabled by going to `about:profiling` and
+enabling the "Native Allocations" checkbox. It is only available in Nightly, as it
+uses a technique of hooking into malloc that could be a little more risky to apply to
+the broader population of Firefox users.
+
+This implementation is located in: `tools/profiler/core/memory_hooks.cpp
+<https://searchfox.org/mozilla-central/source/tools/profiler/core/memory_hooks.cpp>`_
+
+It works by hooking into all of the malloc calls. When the profiler is running, it
+performs a `Bernoulli trial`_, that will pass for a given probability of per-byte
+allocated. What this means is that larger allocations have a higher chance of being
+recorded compared to smaller allocations. Currently, there is no way to configure
+the per-byte probability. This means that sampled allocation sizes will be closer
+to the actual allocated bytes.
+
+This infrastructure is quite similar to DMD, but with the additional motiviations of
+making it easy to turn on and use with the profiler. The overhead is quite high,
+especially on systems with more expensive stack walking, like Linux. Turning off
+thee "Native Stacks" feature can help lower overhead, but will give less information.
+
+For more information on analyzing these profiles, see the `Firefox Profiler docs`_.
+
+Memory counters
+---------------
+
+Similar to the Native Allocations feature, memory counters use the malloc memory hook
+that is only available in Nightly. When it's available, the memory counters are always
+turned on. This is a lightweight way to count in a very granular fashion how much
+memory is being allocated and deallocated during the profiling session.
+
+This information is then visualized in the `Firefox Profiler memory track`_.
+
+This feature uses the `Profiler Counters`_, which can be used to create other types
+of cheap counting instrumentation.
+
+.. _Bernoulli trial: https://en.wikipedia.org/wiki/Bernoulli_trial
+.. _Firefox Profiler docs: https://profiler.firefox.com/docs/#/./memory-allocations
+.. _Firefox Profiler memory track: https://profiler.firefox.com/docs/#/./memory-allocations?id=memory-track
+.. _Profiler Counters: https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerCounts.h