Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / tools / profiler / docs / code-overview.rst
blob3ca662e14117941fd1aea7cceb8959a99f97cf62
1 Profiler Code Overview
2 ######################
4 This is an overview of the code that implements the Profiler inside Firefox
5 with dome details around tricky subjects, or pointers to more detailed
6 documentation and/or source code.
8 It assumes familiarity with Firefox development, including Mercurial (hg), mach,
9 moz.build files, Try, Phabricator, etc.
11 It also assumes knowledge of the user-visible part of the Firefox Profiler, that
12 is: How to use the Firefox Profiler, and what profiles contain that is shown
13 when capturing a profile. See the main website https://profiler.firefox.com, and
14 its `documentation <https://profiler.firefox.com/docs/>`_.
16 For just an "overview", it may look like a huge amount of information, but the
17 Profiler code is indeed quite expansive, so it takes a lot of words to explain
18 even just a high-level view of it! For on-the-spot needs, it should be possible
19 to search for some terms here and follow the clues. But for long-term
20 maintainers, it would be worth skimming this whole document to get a grasp of
21 the domain, and return to get some more detailed information before diving into
22 the code.
24 WIP note: This document should be correct at the time it is written, but the
25 profiler code constantly evolves to respond to bugs or to provide new exciting
26 features, so this document could become obsolete in parts! It should still be
27 useful as an overview, but its correctness should be verified by looking at the
28 actual code. If you notice any significant discrepancy or broken links, please
29 help by
30 `filing a bug <https://bugzilla.mozilla.org/enter_bug.cgi?product=Core&component=Gecko+Profiler>`_.
32 *****
33 Terms
34 *****
36 This is the common usage for some frequently-used terms, as understood by the
37 Dev Tools team. But incorrect usage can sometimes happen, context is key!
39 * **profiler** (a): Generic name for software that enables the profiling of
40   code. (`"Profiling" on Wikipedia <https://en.wikipedia.org/wiki/Profiling_(computer_programming)>`_)
41 * **Profiler** (the): All parts of the profiler code inside Firefox.
42 * **Base Profiler** (the): Parts of the Profiler that live in
43   mozglue/baseprofiler, and can be used from anywhere, but has limited
44   functionality.
45 * **Gecko Profiler** (the): Parts of the Profiler that live in tools/profiler,
46   and can only be used from other code in the XUL library.
47 * **Profilers** (the): Both the Base Profiler and the Gecko Profiler.
48 * **profiling session**: This is the time during which the profiler is running
49   and collecting data.
50 * **profile** (a): The output from a profiling session, either as a file, or a
51   shared viewable profile on https://profiler.firefox.com
52 * **Profiler back-end** (the): Other name for the Profiler code inside Firefox,
53   to distinguish it from...
54 * **Profiler front-end** (the): The website https://profiler.firefox.com that
55   displays profiles captured by the back-end.
56 * **Firefox Profiler** (the): The whole suite comprised of the back-end and front-end.
58 ******************
59 Guiding Principles
60 ******************
62 When working on the profiler, here are some guiding principles to keep in mind:
64 * Low profiling overhead in cpu and memory. For the Profiler to provide the best
65   value, it should stay out of the way and consume as few resources (in time and
66   memory) as possible, so as not to skew the actual Firefox code too much.
68 * Common data structures and code should be in the Base Profiler when possible.
70   WIP note: Deduplication is slowly happening, see
71   `meta bug 1557566 <https://bugzilla.mozilla.org/show_bug.cgi?id=1557566>`_.
72   This document focuses on the Profiler back-end, and mainly the Gecko Profiler
73   (because this is where most of the code lives, the Base Profiler is mostly a
74   subset, originally just a cut-down version of the Gecko Profiler); so unless
75   specified, descriptions below are about the Gecko Profiler, but know that
76   there may be some equivalent code in the Base Profiler as well.
78 * Use appropriate programming-language features where possible to reduce coding
79   errors in both our code, and our users' usage of it. In C++, this can be done
80   by using a specific class/struct types for a given usage, to avoid misuse
81   (e.g., an generic integer representing a **process** could be incorrectly
82   given to a function expecting a **thread**; we have specific types for these
83   instead, more below.)
85 * Follow the
86   `Coding Style <https://firefox-source-docs.mozilla.org/code-quality/coding-style/index.html>`_.
88 * Whenever possible, write tests (if not present already) for code you add or
89   modify -- but this may be too difficult in some case, use good judgement and
90   at least test manually instead.
92 ******************
93 Profiler Lifecycle
94 ******************
96 Here is a high-level view of the Base **or** Gecko Profiler lifecycle, as part
97 of a Firefox run. The following sections will go into much more details.
99 * Profiler initialization, preparing some common data.
100 * Threads de/register themselves as they start and stop.
101 * During each User/test-controlled profiling session:
103   * Profiler start, preparing data structures that will store the profiling data.
104   * Periodic sampling from a separate thread, happening at a user-selected
105     frequency (usually once every 1-2 ms), and recording snapshots of what
106     Firefox is doing:
108     * CPU sampling, measuring how much time each thread has spent actually
109       running on the CPU.
110     * Stack sampling, capturing a stack of functions calls from whichever leaf
111       function the program is in at this point in time, up to the top-most
112       caller (i.e., at least the ``main()`` function, or its callers if any).
113       Note that unlike most external profilers, the Firefox Profiler back-end
114       is capable or getting more useful information than just native functions
115       calls (compiled from C++ or Rust):
117       * Labels added by Firefox developers along the stack, usually to identify
118         regions of code that perform "interesting" operations (like layout, file
119         I/Os, etc.).
120       * JavaScript function calls, including the level of optimization applied.
121       * Java function calls.
122   * At any time, Markers may record more specific details of what is happening,
123     e.g.: User operations, page rendering steps, garbage collection, etc.
124   * Optional profiler pause, which stops most recording, usually near the end of
125     a session so that no data gets recorded past this point.
126   * Profile JSON output, generated from all the recorded profiling data.
127   * Profiler stop, tearing down profiling session objects.
128 * Profiler shutdown.
130 Note that the Base Profiler can start earlier, and then the data collected so
131 far, as well as the responsibility for periodic sampling, is handed over to the
132 Gecko Profiler:
134 #. (Firefox starts)
135 #. Base Profiler init
136 #. Base Profiler start
137 #. (Firefox loads the libxul library and initializes XPCOM)
138 #. Gecko Profiler init
139 #. Gecko Profiler start
140 #. Handover from Base to Gecko
141 #. Base Profiler stop
142 #. (Bulk of the profiling session)
143 #. JSON generation
144 #. Gecko Profiler stop
145 #. Gecko Profiler shutdown
146 #. (Firefox ends XPCOM)
147 #. Base Profiler shutdown
148 #. (Firefox exits)
150 Base Profiler functions that add data (mostly markers and labels) may be called
151 from anywhere, and will be recorded by either Profiler. The corresponding
152 functions in Gecko Profiler can only be called from other libxul code, and can
153 only be recorded by the Gecko Profiler.
155 Whenever possible, Gecko Profiler functions should be preferred if accessible,
156 as they may provide extended functionality (e.g., better stacks with JS in
157 markers). Otherwise fallback on Base Profiler functions.
159 ***********
160 Directories
161 ***********
163 * Non-Profiler supporting code
165   * `mfbt <https://searchfox.org/mozilla-central/source/mfbt>`_ - Mostly
166     replacements for C++ std library facilities.
168   * `mozglue/misc <https://searchfox.org/mozilla-central/source/mozglue/misc>`_
170     * `PlatformMutex.h <https://searchfox.org/mozilla-central/source/mozglue/misc/PlatformMutex.h>`_ -
171       Mutex base classes.
172     * `StackWalk.h <https://searchfox.org/mozilla-central/source/mozglue/misc/StackWalk.h>`_ -
173       Stack-walking functions.
174     * `TimeStamp.h <https://searchfox.org/mozilla-central/source/mozglue/misc/TimeStamp.h>`_ -
175       Timestamps and time durations.
177   * `xpcom <https://searchfox.org/mozilla-central/source/xpcom>`_
179     * `ds <https://searchfox.org/mozilla-central/source/xpcom/ds>`_ -
180       Data structures like arrays, strings.
182     * `threads <https://searchfox.org/mozilla-central/source/xpcom/threads>`_ -
183       Threading functions.
185 * Profiler back-end
187   * `mozglue/baseprofiler <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler>`_ -
188     Base Profiler code, usable from anywhere in Firefox. Because it lives in
189     mozglue, it's loaded right at the beginning, so it's possible to start the
190     profiler very early, even before Firefox loads its big&heavy "xul" library.
192     * `baseprofiler's public <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public>`_ -
193       Public headers, may be #included from anywhere.
194     * `baseprofiler's core <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/core>`_ -
195       Main implementation code.
196     * `baseprofiler's lul <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/lul>`_ -
197       Special stack-walking code for Linux.
198     * `../tests/TestBaseProfiler.cpp <https://searchfox.org/mozilla-central/source/mozglue/tests/TestBaseProfiler.cpp>`_ -
199       Unit tests.
201   * `tools/profiler <https://searchfox.org/mozilla-central/source/tools/profiler>`_ -
202     Gecko Profiler code, only usable from the xul library. That library is
203     loaded a short time after Firefox starts, so the Gecko Profiler is not able
204     to profile the early phase of the application, Base Profiler handles that,
205     and can pass its collected data to the Gecko Profiler when the latter
206     starts.
208     * `public <https://searchfox.org/mozilla-central/source/tools/profiler/public>`_ -
209       Public headers, may be #included from most libxul code.
210     * `core <https://searchfox.org/mozilla-central/source/tools/profiler/core>`_ -
211       Main implementation code.
212     * `gecko <https://searchfox.org/mozilla-central/source/tools/profiler/gecko>`_ -
213       Control from JS, and multi-process/IPC code.
214     * `lul <https://searchfox.org/mozilla-central/source/tools/profiler/lul>`_ -
215       Special stack-walking code for Linux.
216     * `rust-api <https://searchfox.org/mozilla-central/source/tools/profiler/rust-api>`_,
217       `rust-helper <https://searchfox.org/mozilla-central/source/tools/profiler/rust-helper>`_
218     * `tests <https://searchfox.org/mozilla-central/source/tools/profiler/tests>`_
220   * `devtools/client/performance-new <https://searchfox.org/mozilla-central/source/devtools/client/performance-new>`_,
221     `devtools/shared/performance-new <https://searchfox.org/mozilla-central/source/devtools/shared/performance-new>`_ -
222     Middleware code for about:profiling and devtools panel functionality.
224   * js, starting with
225     `js/src/vm/GeckoProfiler.h <https://searchfox.org/mozilla-central/source/js/src/vm/GeckoProfiler.h>`_ -
226     JavaScript engine support, mostly to capture JS stacks.
228   * `toolkit/components/extensions/schemas/geckoProfiler.json <https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/geckoProfiler.json>`_ -
229     File that needs to be updated when Profiler features change.
231 * Profiler front-end
233   * Out of scope for this document, but its code and bug repository can be found at:
234     https://github.com/firefox-devtools/profiler . Sometimes work needs to be
235     done on both the back-end of the front-end, especially when modifying the
236     back-end's JSON output format.
238 *******
239 Headers
240 *******
242 The most central public header is
243 `GeckoProfiler.h <https://searchfox.org/mozilla-central/source/tools/profiler/public/GeckoProfiler.h>`_,
244 from which almost everything else can be found, it can be a good starting point
245 for exploration.
246 It includes other headers, which together contain important top-level macros and
247 functions.
249 WIP note: GeckoProfiler.h used to be the header that contained everything!
250 To better separate areas of functionality, and to hopefully reduce compilation
251 times, parts of it have been split into smaller headers, and this work will
252 continue, see `bug 1681416 <https://bugzilla.mozilla.org/show_bug.cgi?id=1681416>`_.
254 MOZ_GECKO_PROFILER and Macros
255 =============================
257 Mozilla officially supports the Profiler on `tier-1 platforms
258 <https://firefox-source-docs.mozilla.org/contributing/build/supported.html>`_:
259 Windows, macos, Linux and Android.
260 There is also some code running on tier 2-3 platforms (e.g., for FreeBSD), but
261 the team at Mozilla is not obligated to maintain it; we do try to keep it
262 running, and some external contributors are keeping an eye on it and provide
263 patches when things do break.
265 To reduce the burden on unsupported platforms, a lot of the Profilers code is
266 only compiled when ``MOZ_GECKO_PROFILER`` is #defined. This means that some
267 public functions may not always be declared or implemented, and should be
268 surrounded by guards like ``#ifdef MOZ_GECKO_PROFILER``.
270 Some commonly-used functions offer an empty definition in the
271 non-``MOZ_GECKO_PROFILER`` case, so these functions may be called from anywhere
272 without guard.
274 Other functions have associated macros that can always be used, and resolve to
275 nothing on unsupported platforms. E.g.,
276 ``PROFILER_REGISTER_THREAD`` calls ``profiler_register_thread`` where supported,
277 otherwise does nothing.
279 WIP note: There is an effort to eventually get rid of ``MOZ_GECKO_PROFILER`` and
280 its associated macros, see
281 `bug 1635350 <https://bugzilla.mozilla.org/show_bug.cgi?id=1635350>`_.
283 RAII "Auto" macros and classes
284 ==============================
285 A number of functions are intended to be called in pairs, usually to start and
286 then end some operation. To ease their use, and ensure that both functions are
287 always called together, they usually have an associated class and/or macro that
288 may be called only once. This pattern of using an object's destructor to ensure
289 that some action always eventually happens, is called
290 `RAII <https://en.cppreference.com/w/cpp/language/raii>`_ in C++, with the
291 common prefix "auto".
293 E.g.: In ``MOZ_GECKO_PROFILER`` builds,
294 `AUTO_PROFILER_INIT <https://searchfox.org/mozilla-central/search?q=AUTO_PROFILER_INIT>`_
295 instantiates an
296 `AutoProfilerInit <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AAutoProfilerInit>`_
297 object, which calls ``profiler_init`` when constructed, and
298 ``profiler_shutdown`` when destroyed.
300 *********************
301 Platform Abstractions
302 *********************
304 This section describes some platform abstractions that are used throughout the
305 Profilers. (Other platform abstractions will be described where they are used.)
307 Process and Thread IDs
308 ======================
310 The Profiler back-end often uses process and thread IDs (aka "pid" and "tid"),
311 which are commonly just a number.
312 For better code correctness, and to hide specific platform details, they are
313 encapsulated in opaque types
314 `BaseProfilerProcessId <https://searchfox.org/mozilla-central/search?q=BaseProfilerProcessId>`_
316 `BaseProfilerThreadId <https://searchfox.org/mozilla-central/search?q=BaseProfilerThreadId>`_.
317 These types should be used wherever possible.
318 When interfacing with other code, they may be converted using the member
319 functions ``FromNumber`` and ``ToNumber``.
321 To find the current process or thread ID, use
322 `profiler_current_process_id <https://searchfox.org/mozilla-central/search?q=profiler_current_process_id>`_
324 `profiler_current_thread_id <https://searchfox.org/mozilla-central/search?q=profiler_current_thread_id>`_.
326 The main thread ID is available through
327 `profiler_main_thread_id <https://searchfox.org/mozilla-central/search?q=profiler_main_thread_id>`_
328 (assuming
329 `profiler_init_main_thread_id <https://searchfox.org/mozilla-central/search?q=profiler_init_main_thread_id>`_
330 was called when the application started -- especially important in stand-alone
331 test programs.)
333 `profiler_is_main_thread <https://searchfox.org/mozilla-central/search?q=profiler_is_main_thread>`_
334 is a quick way to find out if the current thread is the main thread.
336 Locking
337 =======
338 The locking primitives in PlatformMutex.h are not supposed to be used as-is, but
339 through a user-accessible implementation. For the Profilers, this is in
340 `BaseProfilerDetail.h <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/BaseProfilerDetail.h>`_.
342 In addition to the usual ``Lock``, ``TryLock``, and ``Unlock`` functions,
343 `BaseProfilerMutex <https://searchfox.org/mozilla-central/search?q=BaseProfilerMutex>`_
344 objects have a name (which may be helpful when debugging),
345 they record the thread on which they are locked (making it possible to know if
346 the mutex is locked on the current thread), and in ``DEBUG`` builds there are
347 assertions verifying that the mutex is not incorrectly used recursively, to
348 verify the correct ordering of different Profiler mutexes, and that it is
349 unlocked before destruction.
351 Mutexes should preferably be locked within C++ block scopes, or as class
352 members, by using
353 `BaseProfilerAutoLock <https://searchfox.org/mozilla-central/search?q=BaseProfilerAutoLock>`_.
355 Some classes give the option to use a mutex or not (so that single-threaded code
356 can more efficiently bypass locking operations), for these we have
357 `BaseProfilerMaybeMutex <https://searchfox.org/mozilla-central/search?q=BaseProfilerMaybeMutex>`_
359 `BaseProfilerMaybeAutoLock <https://searchfox.org/mozilla-central/search?q=BaseProfilerMaybeAutoLock>`_.
361 There is also a special type of shared lock (aka RWLock, see
362 `RWLock on wikipedia <https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock>`_),
363 which may be locked in multiple threads (through ``LockShared`` or preferably
364 `BaseProfilerAutoLockShared <https://searchfox.org/mozilla-central/search?q=BaseProfilerAutoLockShared>`_),
365 or locked exclusively, preventing any other locking (through ``LockExclusive`` or preferably
366 `BaseProfilerAutoLockExclusive <https://searchfox.org/mozilla-central/search?q=BaseProfilerAutoLockExclusive>`_).
368 *********************
369 Main Profiler Classes
370 *********************
372 Diagram showing the most important Profiler classes, see details in the
373 following sections:
375 (As noted, the "RegisteredThread" classes are now obsolete in the Gecko
376 Profiler, see the "Thread Registration" section below for an updated diagram and
377 description.)
379 .. image:: profilerclasses-20220913.png
381 ***********************
382 Profiler Initialization
383 ***********************
385 `profiler_init <https://searchfox.org/mozilla-central/search?q=symbol:_Z13profiler_initPv>`_
387 `baseprofiler::profiler_init <https://searchfox.org/mozilla-central/search?q=symbol:_ZN7mozilla12baseprofiler13profiler_initEPv>`_
388 must be called from the main thread, and are used to prepare important aspects
389 of the profiler, including:
391 * Making sure the main thread ID is recorded.
392 * Handling ``MOZ_PROFILER_HELP=1 ./mach run`` to display the command-line help.
393 * Creating the ``CorePS`` instance -- more details below.
394 * Registering the main thread.
395 * Initializing some platform-specific code.
396 * Handling other environment variables that are used to immediately start the
397   profiler, with optional settings provided in other env-vars.
399 CorePS
400 ======
402 The `CorePS class <https://searchfox.org/mozilla-central/search?q=symbol:T_CorePS>`_
403 has a single instance that should live for the duration of the Firefox
404 application, and contains important information that could be needed even when
405 the Profiler is not running.
407 It includes:
409 * A static pointer to its single instance.
410 * The process start time.
411 * JavaScript-specific data structures.
412 * A list of registered
413   `PageInformations <https://searchfox.org/mozilla-central/search?q=symbol:T_PageInformation>`_,
414   used to keep track of the tabs that this process handles.
415 * A list of
416   `BaseProfilerCounts <https://searchfox.org/mozilla-central/search?q=symbol:T_BaseProfilerCount>`_,
417   used to record things like the process memory usage.
418 * The process name, and optionally the "eTLD+1" (roughly sub-domain) that this
419   process handles.
420 * In the Base Profiler only, a list of
421   `RegisteredThreads <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%253A%253Abaseprofiler%253A%253ARegisteredThread>`_.
422   WIP note: This storage has been reworked in the Gecko Profiler (more below),
423   and in practice the Base Profiler only registers the main thread. This should
424   eventually disappear as part of the de-duplication work
425   (`bug 1557566 <https://bugzilla.mozilla.org/show_bug.cgi?id=1557566>`_).
427 *******************
428 Thread Registration
429 *******************
431 Threads need to register themselves in order to get fully profiled.
432 This section describes the main data structures that record the list of
433 registered threads and their data.
435 WIP note: There is some work happening to add limited profiling of unregistered
436 threads, with the hope that more and more functionality could be added to
437 eventually use the same registration data structures.
439 Diagram showing the relevant classes, see details in the following sub-sections:
441 .. image:: profilerthreadregistration-20220913.png
443 ProfilerThreadRegistry
444 ======================
447 `static ProfilerThreadRegistry object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Aprofiler%3A%3AThreadRegistry>`_
448 contains a list of ``OffThreadRef`` objects.
450 Each ``OffThreadRef`` points to a ``ProfilerThreadRegistration``, and restricts
451 access to a safe subset of the thread data, and forces a mutex lock if necessary
452 (more information under ProfilerThreadRegistrationData below).
454 ProfilerThreadRegistration
455 ==========================
458 `ProfilerThreadRegistration object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Aprofiler%3A%3AThreadRegistration>`_
459 contains a lot of information relevant to its thread, to help with profiling it.
461 This data is accessible from the thread itself through an ``OnThreadRef``
462 object, which points to the ``ThreadRegistration``, and restricts access to a
463 safe subset of thread data, and forces a mutex lock if necessary (more
464 information under ProfilerThreadRegistrationData below).
466 ThreadRegistrationData and accessors
467 ====================================
469 `The ProfilerThreadRegistrationData.h header <https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerThreadRegistrationData.h>`_
470 contains a hierarchy of classes that encapsulate all the thread-related data.
472 ``ThreadRegistrationData`` contains all the actual data members, including:
474 * Some long-lived
475   `ThreadRegistrationInfo <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%253A%253Aprofiler%253A%253AThreadRegistrationInfo>`_,
476   containing the thread name, its registration time, the thread ID, and whether
477   it's the main thread.
478 * A ``ProfilingStack`` that gathers developer-provided pseudo-frames, and JS
479   frames.
480 * Some platform-specific ``PlatformData`` (usually required to actually record
481   profiling measurements for that thread).
482 * A pointer to the top of the stack.
483 * A shared pointer to the thread's ``nsIThread``.
484 * A pointer to the ``JSContext``.
485 * An optional pre-allocated ``JsFrame`` buffer used during stack-sampling.
486 * Some JS flags.
487 * Sleep-related data (to avoid costly sampling while the thread is known to not
488   be doing anything).
489 * The current ``ThreadProfilingFeatures``, to know what kind of data to record.
490 * When profiling, a pointer to a ``ProfiledThreadData``, which contains some
491   more data needed during and just after profiling.
493 As described in their respective code comments, each data member is supposed to
494 be accessed in certain ways, e.g., the ``JSContext`` should only be "written
495 from thread, read from thread and suspended thread". To enforce these rules,
496 data members can only be accessed through certain classes, which themselves can
497 only be instantiated in the correct conditions.
499 The accessor classes are, from base to most-derived:
501 * ``ThreadRegistrationData``, not an accessor itself, but it's the base class
502   with all the ``protected`` data.
503 * ``ThreadRegistrationUnlockedConstReader``, giving unlocked ``const`` access to
504    the ``ThreadRegistrationInfo``, ``PlatformData``, and stack top.
505 * ``ThreadRegistrationUnlockedConstReaderAndAtomicRW``, giving unlocked
506   access to the atomic data members: ``ProfilingStack``, sleep-related data,
507   ``ThreadProfilingFeatures``.
508 * ``ThreadRegistrationUnlockedRWForLockedProfiler``, giving access that's
509   protected by the Profiler's main lock, but doesn't require a
510   ``ThreadRegistration`` lock, to the ``ProfiledThreadData``
511 * ``ThreadRegistrationUnlockedReaderAndAtomicRWOnThread``, giving unlocked
512   mutable access, but only on the thread itself, to the ``JSContext``.
513 * ``ThreadRegistrationLockedRWFromAnyThread``, giving locked access from any
514   thread to mutex-protected data: ``ThreadProfilingFeatures``, ``JsFrame``,
515   ``nsIThread``, and the JS flags.
516 * ``ThreadRegistrationLockedRWOnThread``, giving locked access, but only from
517   the thread itself, to the ``JSContext`` and a JS flag-related operation.
518 * ``ThreadRegistration::EmbeddedData``, containing all of the above, and stored
519   as a data member in each ``ThreadRegistration``.
521 To recapitulate, if some code needs some data on the thread, it can use
522 ``ThreadRegistration`` functions to request access (with the required rights,
523 like a mutex lock).
524 To access data about another thread, use similar functions from
525 ``ThreadRegistry`` instead.
526 You may find some examples in the implementations of the functions in
527 ProfilerThreadState.h (see the following section).
529 ProfilerThreadState.h functions
530 ===============================
533 `ProfilerThreadState.h <https://searchfox.org/mozilla-central/source/tools/profiler/public/ProfilerThreadState.h>`_
534 header provides a few helpful functions related to threads, including:
536 * ``profiler_is_active_and_thread_is_registered``
537 * ``profiler_thread_is_being_profiled`` (for the current thread or another
538   thread, and for a given set of features)
539 * ``profiler_thread_is_sleeping``
541 **************
542 Profiler Start
543 **************
545 There are multiple ways to start the profiler, through command line env-vars,
546 and programmatically in C++ and JS.
548 The main public C++ function is
549 `profiler_start <https://searchfox.org/mozilla-central/search?q=symbol:_Z14profiler_startN7mozilla10PowerOfTwoIjEEdjPPKcjyRKNS_5MaybeIdEE%2C_Z14profiler_startN7mozilla10PowerOfTwoIjEEdjPPKcjmRKNS_5MaybeIdEE>`_.
550 It takes all the features specifications, and returns a promise that gets
551 resolved when the Profiler has fully started in all processes (multi-process
552 profiling is described later in this document, for now the focus will be on each
553 process running its instance of the Profiler). It first calls ``profiler_init``
554 if needed, and also ``profiler_stop`` if the profiler was already running.
556 The main implementation, which can be called from multiple sources, is
557 `locked_profiler_start <https://searchfox.org/mozilla-central/search?q=locked_profiler_start>`_.
558 It performs a number of operations to start the profiling session, including:
560 * Record the session start time.
561 * Pre-allocate some work buffer to capture stacks for markers on the main thread.
562 * In the Gecko Profiler only: If the Base Profiler was running, take ownership
563   of the data collected so far, and stop the Base Profiler (we don't want both
564   trying to collect the same data at the same time!)
565 * Create the ActivePS, which keeps track of most of the profiling session
566   information, more about it below.
567 * For each registered thread found in the ``ThreadRegistry``, check if it's one
568   of the threads to profile, and if yes set the appropriate data into the
569   corresponding ``ThreadRegistrationData`` (including informing the JS engine to
570   start recording profiling data).
571 * On Android, start the Java sampler.
572 * If native allocations are to be profiled, setup the appropriate hooks.
573 * Start the audio callback tracing if requested.
574 * Set the public shared "active" state, used by many functions to quickly assess
575   whether to actually record profiling data.
577 ActivePS
578 ========
580 The `ActivePS class <https://searchfox.org/mozilla-central/search?q=symbol:T_ActivePS>`_
581 has a single instance at a time, that should live for the length of the
582 profiling session.
584 It includes:
586 * The session start time.
587 * A way to track "generations" (in case an old ActivePS still lives when the
588   next one starts, so that in-flight data goes to the correct place.)
589 * Requested features: Buffer capacity, periodic sampling interval, feature set,
590   list of threads to profile, optional: specific tab to profile.
591 * The profile data storage buffer and its chunk manager (see "Storage" section
592   below for details.)
593 * More data about live and dead profiled threads.
594 * Optional counters for per-process CPU usage, and power usage.
595 * A pointer to the ``SamplerThread`` object (see "Periodic Sampling" section
596   below for details.)
598 *******
599 Storage
600 *******
602 During a session, the profiling data is serialized into a buffer, which is made
603 of "chunks", each of which contains "blocks", which have a size and the "entry"
604 data.
606 During a profiling session, there is one main profile buffer, which may be
607 started by the Base Profiler, and then handed over to the Gecko Profiler when
608 the latter starts.
610 The buffer is divided in chunks of equal size, which are allocated before they
611 are needed. When the data reaches a user-set limit, the oldest chunk is
612 recycled. This means that for long-enough profiling sessions, only the most
613 recent data (that could fit under the limit) is kept.
615 Each chunk stores a sequence of blocks of variable length. The chunk itself
616 only knows where the first full block starts, and where the last block ends,
617 which is where the next block will be reserved.
619 To add an entry to the buffer, a block is reserved, the size is written first
620 (so that readers can find the start of the next block), and then the entry bytes
621 are written.
623 The following sessions give more technical details.
625 leb128iterator.h
626 ================
628 `This utility header <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/leb128iterator.h>`_
629 contains some functions to read and write unsigned "LEB128" numbers
630 (`LEB128 on wikipedia <https://en.wikipedia.org/wiki/LEB128>`_).
632 They are an efficient way to serialize numbers that are usually small, e.g.,
633 numbers up to 127 only take one byte, two bytes up to 16,383, etc.
635 ProfileBufferBlockIndex
636 =======================
638 `A ProfileBufferBlockIndex object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferBlockIndex>`_
639 encapsulates a block index that is known to be the valid start of a block. It is
640 created when a block is reserved, or when trusted code computes the start of a
641 block in a chunk.
643 The more generic
644 `ProfileBufferIndex <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferIndex>`_
645 type is used when working inside blocks.
647 ProfileBufferChunk
648 ==================
650 `A ProfileBufferChunk <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferChunk>`_
651 is a variable-sized object. It contains:
653 * A public copyable header, itself containing:
655   * The local offset to the first full block (a chunk may start with the end of
656     a block that was started at the end of the previous chunk). That offset in
657     the very first chunk is the natural start to read all the data in the
658     buffer.
659   * The local offset past the last reserved block. This is where the next block
660     should be reserved, unless it points past the end of this chunk size.
661   * The timestamp when the chunk was first used.
662   * The timestamp when the chunk became full.
663   * The number of bytes that may be stored in this chunk.
664   * The number of reserved blocks.
665   * The global index where this chunk starts.
666   * The process ID writing into this chunk.
668 * An owning unique pointer to the next chunk. It may be null for the last chunk
669   in a chain.
671 * In ``DEBUG`` builds, a state variable, which is used to ensure that the chunk
672   goes through a known sequence of states (e.g., Created, then InUse, then
673   Done, etc.) See the sequence diagram
674   `where the member variable is defined <https://searchfox.org/mozilla-central/search?q=symbol:F_%3CT_mozilla%3A%3AProfileBufferChunk%3A%3AInternalHeader%3E_mState>`_.
676 * The actual buffer data.
678 Because a ProfileBufferChunk is variable-size, it must be created through its
679 static ``Create`` function, which takes care of allocating the correct amount
680 of bytes, at the correct alignment.
682 Chunk Managers
683 ==============
685 ProfilerBufferChunkManager
686 --------------------------
688 `The ProfileBufferChunkManager abstract class <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferChunkManager>`_
689 defines the interface of classes that manage chunks.
691 Concrete implementations are responsible for:
692 * Creating chunks for their user, with a mechanism to pre-allocate chunks before they are actually needed.
693 * Taking back and owning chunks when they are "released" (usually when full).
694 * Automatically destroying or recycling the oldest released chunks.
695 * Giving temporary access to extant released chunks.
697 ProfileBufferChunkManagerSingle
698 -------------------------------
700 `A ProfileBufferChunkManagerSingle object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferChunkManagerSingle>`_
701 manages a single chunk.
703 That chunk is always the same, it is never destroyed. The user may use it and
704 optionally release it. The manager can then be reset, and that one chunk will
705 be available again for use.
707 A request for a second chunk would always fail.
709 This manager is short-lived and not thread-safe. It is useful when there is some
710 limited data that needs to be captured without blocking the global profiling
711 buffer, usually one stack sample. This data may then be extracted and quickly
712 added to the global buffer.
714 ProfileBufferChunkManagerWithLocalLimit
715 ---------------------------------------
717 `A ProfileBufferChunkManagerWithLocalLimit object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferChunkManagerSingle>`_
718 implements the ``ProfileBufferChunkManager`` interface fully, managing a number
719 of chunks, and making sure their total combined size stays under a given limit.
720 This is the main chunk manager user during a profiling session.
722 Note: It also implements the ``ProfileBufferControlledChunkManager`` interface,
723 this is explained in the later section "Multi-Process Profiling".
725 It is thread-safe, and one instance is shared by both Profilers.
727 ProfileChunkedBuffer
728 ====================
730 `A ProfileChunkedBuffer object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileChunkedBuffer>`_
731 uses a ``ProfilerBufferChunkManager`` to store data, and handles the different
732 C++ types of data that the Profilers want to read/write as entries in buffer
733 chunks.
735 Its main function is ``ReserveAndPut``:
737 * It takes an invocable object (like a lambda) that should return the size of
738   the entry to store, this is to potentially avoid costly operations just to
739   compute a size, when the profiler may not be running.
740 * It attempts to reserve the space in its chunks, requesting a new chunk if
741   necessary.
742 * It then calls a provided invocable object with a
743   `ProfileBufferEntryWriter <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferEntryWriter>`_,
744   which offers a range of functions to help serialize C++ objects. The
745   de/serialization functions are found in specializations of
746   `ProfileBufferEntryWriter::Serializer <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferEntryWriter%3A%3ASerializer>`_
747   and
748   `ProfileBufferEntryReader::Deserializer <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferEntryReader%3A%3ADeserializer>`_.
750 More "put" functions use ``ReserveAndPut`` to more easily serialize blocks of
751 memory, or C++ objects.
753 ``ProfileChunkedBuffer`` is optionally thread-safe, using a
754 ``BaseProfilerMaybeMutex``.
756 WIP note: Using a mutex makes this storage too noisy for profiling some
757 real-time (like audio processing).
758 `Bug 1697953 <https://bugzilla.mozilla.org/show_bug.cgi?id=1697953>`_ will look
759 at switching to using atomic variables instead.
760 An alternative would be to use a totally separate non-thread-safe buffers for
761 each real-time thread that requires it (see
762 `bug 1754889 <https://bugzilla.mozilla.org/show_bug.cgi?id=1754889>`_).
764 ProfileBuffer
765 =============
767 `A ProfileBuffer object <https://searchfox.org/mozilla-central/search?q=symbol:T_ProfileBuffer>`_
768 uses a ``ProfileChunkedBuffer`` to store data, and handles the different kinds
769 of entries that the Profilers want to read/write.
771 Each entry starts with a tag identifying a kind. These kinds can be found in
772 `ProfileBufferEntryKinds.h <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/ProfileBufferEntryKinds.h>`_.
774 There are "legacy" kinds, which are small fixed-length entries, such as:
775 Categories, labels, frame information, counters, etc. These can be stored in
776 `ProfileBufferEntry objects <https://searchfox.org/mozilla-central/search?q=symbol:T_ProfileBufferEntry>`_
778 And there are "modern" kinds, which have variable sizes, such as: Markers, CPU
779 running times, full stacks, etc. These are more directly handled by code that
780 can access the underlying ``ProfileChunkedBuffer``.
782 The other major responsibility of a ``ProfileChunkedBuffer`` is to read back all
783 this data, sometimes during profiling (e.g., to duplicate a stack), but mainly
784 at the end of a session when generating the output JSON profile.
786 *****************
787 Periodic Sampling
788 *****************
790 Probably the most important job of the Profiler is to sample stacks of a number
791 of running threads, to help developers know which functions get used a lot when
792 performing some operation on Firefox.
794 This is accomplished from a special thread, which regularly springs into action
795 and captures all this data.
797 SamplerThread
798 =============
800 `The SamplerThread object <https://searchfox.org/mozilla-central/search?q=symbol:T_SamplerThread>`_
801 manages the information needed during sampling. It is created when the profiler
802 starts, and is stored inside the ``ActivePS``, see above for details.
804 It includes:
806 * A ``Sampler`` object that contains platform-specific details, which are
807   implemented in separate files like platform-win32.cpp, etc.
808 * The same generation index as its owning ``ActivePS``.
809 * The requested interval between samples.
810 * A handle to the thread where the sampling happens, its main function is
811   `Run() function <https://searchfox.org/mozilla-central/search?q=symbol:_ZN13SamplerThread3RunEv>`_.
812 * A list of callbacks to invoke after the next sampling. These may be used by
813   tests to wait for sampling to actually happen.
814 * The unregistered-thread-spy data, and an optional handle on another thread
815   that takes care of "spying" on unregistered thread (on platforms where that
816   operation is too expensive to run directly on the sampling thread).
818 The ``Run()`` function takes care of performing the periodic sampling work:
819 (more details in the following sections)
821 * Retrieve the sampling parameters.
822 * Instantiate a ``ProfileBuffer`` on the stack, to capture samples from other threads.
823 * Loop until a ``break``:
825   * Lock the main profiler mutex, and do:
827     * Check if sampling should stop, and break from the loop.
828     * Clean-up exit profiles (these are profiles sent from dying sub-processes,
829       and are kept for as long as they overlap with this process' own buffer range).
830     * Record the CPU utilization of the whole process.
831     * Record the power consumption.
832     * Sample each registered counter, including the memory counter.
833     * For each registered thread to be profiled:
835       * Record the CPU utilization.
836       * If the thread is marked as "still sleeping", record a "same as before"
837         sample, otherwise suspend the thread and take a full stack sample.
838       * On some threads, record the event delay to compute the
839         (un)responsiveness. WIP note: This implementation may change.
841     * Record profiling overhead durations.
843   * Unlock the main profiler mutex.
844   * Invoke registered post-sampling callbacks.
845   * Spy on unregistered threads.
846   * Based on the requested sampling interval, and how much time this loop took,
847     compute when the next sampling loop should start, and make the thread sleep
848     for the appropriate amount of time. The goal is to be as regular as
849     possible, but if some/all loops take too much time, don't try too hard to
850     catch up, because the system is probably under stress already.
851   * Go back to the top of the loop.
853 * If we're here, we hit a loop ``break`` above.
854 * Invoke registered post-sampling callbacks, to let them know that sampling
855   stopped.
857 CPU Utilization
858 ===============
860 CPU Utilization is stored as a number of milliseconds that a thread or process
861 has spent running on the CPU since the previous sampling.
863 Implementations are platform-dependent, and can be found in
864 `the GetThreadRunningTimesDiff function <https://searchfox.org/mozilla-central/search?q=symbol:_ZL25GetThreadRunningTimesDiffRK10PSAutoLockRN7mozilla8profiler45ThreadRegistrationUnlockedRWForLockedProfilerE>`_
866 `the GetProcessRunningTimesDiff function <https://searchfox.org/mozilla-central/search?q=symbol:_ZL26GetProcessRunningTimesDiffRK10PSAutoLockR12RunningTimes>`_.
868 Power Consumption
869 =================
871 Energy probes added in 2022.
873 Stacks
874 ======
876 Stacks are the sequence of calls going from the entry point in the program
877 (generally ``main()`` and some OS-specific functions above), down to the
878 function where code is currently being executed.
880 Native Frames
881 -------------
883 Compiled code, from C++ and Rust source.
885 Label Frames
886 ------------
888 Pseudo-frames with arbitrary text, added from any language, mostly C++.
890 JS, Wasm Frames
891 ---------------
893 Frames corresponding to JavaScript functions.
895 Java Frames
896 -----------
898 Recorded by the JavaSampler.
900 Stack Merging
901 -------------
903 The above types of frames are all captured in different ways, and when finally
904 taking an actual stack sample (apart from Java), they get merged into one stack.
906 All frames have an associated address in the call stack, and can therefore be
907 merged mostly by ordering them by this stack address. See
908 `MergeStacks <https://searchfox.org/mozilla-central/search?q=symbol:_ZL11MergeStacksjbRKN7mozilla8profiler51ThreadRegistrationUnlockedReaderAndAtomicRWOnThreadERK9RegistersRK11NativeStackR22ProfilerStackCollectorPN2JS22ProfilingFrameIterator5FrameEj>`_
909 for the implementation details.
911 Counters
912 ========
914 Counters are a special kind of probe, which can be continuously updated during
915 profiling, and the ``SamplerThread`` will sample their value at every loop.
917 Memory Counter
918 --------------
920 This is the main counter. During a profiling session, hooks into the memory
921 manager keep track of each de/allocation, so at each sampling we know how many
922 operations were performed, and what is the current memory usage compared to the
923 previous sampling.
925 Profiling Overhead
926 ==================
928 The ``SamplerThread`` records timestamps between parts of its sampling loop, and
929 records this as the sampling overhead. This may be useful to determine if the
930 profiler itself may have used too much of the computer resources, which could
931 skew the profile and give wrong impressions.
933 Unregistered Thread Profiling
934 =============================
936 At some intervals (not necessarily every sampling loop, depending on the OS),
937 the profiler may attempt to find unregistered threads, and record some
938 information about them.
940 WIP note: This feature is experimental, and data is captured in markers on the
941 main thread. More work is needed to put this data in tracks like regular
942 registered threads, and capture more data like stack samples and markers.
944 *******
945 Markers
946 *******
948 Markers are events with a precise timestamp or time range, they have a name, a
949 category, options (out of a few choices), and optional marker-type-specific
950 payload data.
952 Before describing the implementation, it is useful to be familiar with how
953 markers are natively added from C++, because this drives how the implementation
954 takes all this information and eventually outputs it in the final JSON profile.
956 Adding Markers from C++
957 =======================
959 See https://firefox-source-docs.mozilla.org/tools/profiler/markers-guide.html
961 Implementation
962 ==============
964 The main function that records markers is
965 `profiler_add_marker <https://searchfox.org/mozilla-central/search?q=symbol:_Z19profiler_add_markerRKN7mozilla18ProfilerStringViewIcEERKNS_14MarkerCategoryEONS_13MarkerOptionsET_DpRKT0_>`_.
966 It's a variadic templated function that takes the different the expected
967 arguments, first checks if the marker should actually be recorded (the profiler
968 should be running, and the target thread should be profiled), and then calls
969 into the deeper implementation function ``AddMarkerToBuffer`` with a reference
970 to the main profiler buffer.
972 `AddMarkerToBuffer <https://searchfox.org/mozilla-central/search?q=symbol:_Z17AddMarkerToBufferRN7mozilla20ProfileChunkedBufferERKNS_18ProfilerStringViewIcEERKNS_14MarkerCategoryEONS_13MarkerOptionsET_DpRKT0_>`_
973 takes the marker type as an object, removes it from the function parameter list,
974 and calls the next function with the marker type as an explicit template
975 parameter, and also a pointer to the function that can capture the stack
976 (because it is different between Base and Gecko Profilers, in particular the
977 latter one knows about JS).
979 From here, we enter the land of
980 `BaseProfilerMarkersDetail.h <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/BaseProfilerMarkersDetail.h>`_,
981 which employs some heavy template techniques, in order to most efficiently
982 serialize the given marker payload arguments, in order to make them
983 deserializable when outputting the final JSON. In previous implementations, for
984 each new marker type, a new C++ class derived from a payload abstract class was
985 required, that had to implement all the constructors and virtual functions to:
987 * Create the payload object.
988 * Serialize the payload into the profile buffer.
989 * Deserialize from the profile buffer to a new payload object.
990 * Convert the payload into the final output JSON.
992 Now, the templated functions automatically take care of serializing all given
993 function call arguments directly (instead of storing them somewhere first), and
994 preparing a deserialization function that will recreate them on the stack and
995 directly call the user-provided JSONification function with these arguments.
997 Continuing from the public ``AddMarkerToBuffer``,
998 `mozilla::base_profiler_markers_detail::AddMarkerToBuffer <https://searchfox.org/mozilla-central/search?q=symbol:_ZN7mozilla28base_profiler_markers_detail17AddMarkerToBufferERNS_20ProfileChunkedBufferERKNS_18ProfilerStringViewIcEERKNS_14MarkerCategoryEONS_13MarkerOptionsEPFbS2_NS_19StackCaptureOptionsEEDpRKT0_>`_
999 sets some defaults if not specified by the caller: Target the current thread,
1000 use the current time.
1002 Then if a stack capture was requested, attempt to do it in
1003 the most efficient way, using a pre-allocated buffer if possible.
1005 WIP note: This potential allocation should be avoided in time-critical thread.
1006 There is already a buffer for the main thread (because it's the busiest thread),
1007 but there could be more pre-allocated threads, for specific real-time thread
1008 that need it, or picked from a pool of pre-allocated buffers. See
1009 `bug 1578792 <https://bugzilla.mozilla.org/show_bug.cgi?id=1578792>`_.
1011 From there, `AddMarkerWithOptionalStackToBuffer <https://searchfox.org/mozilla-central/search?q=AddMarkerWithOptionalStackToBuffer>`_
1012 handles ``NoPayload`` markers (usually added with ``PROFILER_MARKER_UNTYPED``)
1013 in a special way, mostly to avoid the extra work associated with handling
1014 payloads. Otherwise it continues with the following function.
1016 `MarkerTypeSerialization<MarkerType>::Serialize <symbol:_ZN7mozilla28base_profiler_markers_detail23MarkerTypeSerialization9SerializeERNS_20ProfileChunkedBufferERKNS_18ProfilerStringViewIcEERKNS_14MarkerCategoryEONS_13MarkerOptionsEDpRKTL0__>`_
1017 retrieves the deserialization tag associated with the marker type. If it's the
1018 first time this marker type is used,
1019 `Streaming::TagForMarkerTypeFunctions <symbol:_ZN7mozilla28base_profiler_markers_detail9Streaming25TagForMarkerTypeFunctionsEPFvRNS_24ProfileBufferEntryReaderERNS_12baseprofiler20SpliceableJSONWriterEEPFNS_4SpanIKcLy18446744073709551615EEEvEPFNS_12MarkerSchemaEvE,_ZN7mozilla28base_profiler_markers_detail9Streaming25TagForMarkerTypeFunctionsEPFvRNS_24ProfileBufferEntryReaderERNS_12baseprofiler20SpliceableJSONWriterEEPFNS_4SpanIKcLm18446744073709551615EEEvEPFNS_12MarkerSchemaEvE,_ZN7mozilla28base_profiler_markers_detail9Streaming25TagForMarkerTypeFunctionsEPFvRNS_24ProfileBufferEntryReaderERNS_12baseprofiler20SpliceableJSONWriterEEPFNS_4SpanIKcLj4294967295EEEvEPFNS_12MarkerSchemaEvE>`_
1020 adds it to the global list (which stores some function pointers used during
1021 deserialization).
1023 Then the main serialization happens in
1024 `StreamFunctionTypeHelper<decltype(MarkerType::StreamJSONMarkerData)>::Serialize <symbol:_ZN7mozilla28base_profiler_markers_detail24StreamFunctionTypeHelperIFT_RNS_12baseprofiler20SpliceableJSONWriterEDpT0_EE9SerializeERNS_20ProfileChunkedBufferERKNS_18ProfilerStringViewIcEERKNS_14MarkerCategoryEONS_13MarkerOptionsEhDpRKS6_>`_.
1025 Deconstructing this mouthful of an template:
1027 * ``MarkerType::StreamJSONMarkerData`` is the user-provided function that will
1028   eventually produce the final JSON, but here it's only used to know the
1029   parameter types that it expects.
1030 * ``StreamFunctionTypeHelper`` takes that function prototype, and can extract
1031   its argument by specializing on ```R(SpliceableJSONWriter&, As...)``, now
1032   ``As...`` is a parameter pack matching the function parameters.
1033 * Note that ``Serialize`` also takes a parameter pack, which contains all the
1034   referenced arguments given to the top ``AddBufferToMarker`` call. These two
1035   packs are supposed to match, at least the given arguments should be
1036   convertible to the target pack parameter types.
1037 * That specialization's ``Serialize`` function calls the buffer's ``PutObjects``
1038   variadic function to write all the marker data, that is:
1040   * The entry kind that must be at the beginning of every buffer entry, in this
1041     case `ProfileBufferEntryKind::Marker <https://searchfox.org/mozilla-central/source/mozglue/baseprofiler/public/ProfileBufferEntryKinds.h#78>`_.
1042   * The common marker data (options first, name, category, deserialization tag).
1043   * Then all the marker-type-specific arguments. Note that the C++ types
1044     are those extracted from the deserialization function, so we know that
1045     whatever is serialized here can be later deserialized using those same
1046     types.
1048 The deserialization side is described in the later section "JSON output of
1049 Markers".
1051 Adding Markers from Rust
1052 ========================
1054 See https://firefox-source-docs.mozilla.org/tools/profiler/instrumenting-rust.html#adding-markers
1056 Adding Markers from JS
1057 ======================
1059 See https://firefox-source-docs.mozilla.org/tools/profiler/instrumenting-javascript.html
1061 Adding Markers from Java
1062 ========================
1064 See https://searchfox.org/mozilla-central/source/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ProfilerController.java
1066 *************
1067 Profiling Log
1068 *************
1070 During a profiling session, some profiler-related events may be recorded using
1071 `ProfilingLog::Access <https://searchfox.org/mozilla-central/search?q=symbol:_ZN12ProfilingLog6AccessEOT_>`_.
1073 The resulting JSON object is added near the end of the process' JSON generation,
1074 in a top-level property named "profilingLog". This object is free-form, and is
1075 not intended to be displayed, or even read by most people. But it may include
1076 interesting information for advanced users, or could be an early temporary
1077 prototyping ground for new features.
1079 See "profileGatheringLog" for another log related to late events.
1081 WIP note: This was introduced shortly before this documentation, so at this time
1082 it doesn't do much at all.
1084 ***************
1085 Profile Capture
1086 ***************
1088 Usually at the end of a profiling session, a profile is "captured", and either
1089 saved to disk, or sent to the front-end https://profiler.firefox.com for
1090 analysis. This section describes how the captured data is converted to the
1091 Gecko Profiler JSON format.
1093 FailureLatch
1094 ============
1096 `The FailureLatch interface <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AFailureLatch>`_
1097 is used during the JSON generation, in order to catch any unrecoverable error
1098 (such as running Out Of Memory), to exit the process early, and to forward the
1099 error to callers.
1101 There are two main implementations, suffixed "source" as they are the one source
1102 of failure-handling, which is passed as ``FailureLatch&`` throughout the code:
1104 * `FailureLatchInfallibleSource <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AFailureLatchInfallibleSource>`_
1105   is an "infallible" latch, meaning that it doesn't expect any failure. So if
1106   a failure actually happened, the program would immediately terminate! (This
1107   was the default behavior prior to introducing these latches.)
1108 * `FailureLatchSource <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AFailureLatchSource>`_
1109   is a "fallible" latch, it will record the first failure that happens, and
1110   "latch" into the failure state. The code should regularly examine this state,
1111   and return early when possible. Eventually this failure state may be exposed
1112   to end users.
1114 ProgressLogger, ProportionValue
1115 ===============================
1117 `A ProgressLogger object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProgressLogger>`_
1118 is used to track the progress of a long operation, in this case the JSON
1119 generation process.
1121 To match how the JSON generation code works (as a tree of C++ functions calls),
1122 each ``ProgressLogger`` in a function usually records progress from 0 to 100%
1123 locally inside that function. If that function calls a sub-function, it gives it
1124 a sub-logger, which in the caller function is set to represent a local sub-range
1125 (like 20% to 40%), but to the called function it will look like its own local
1126 ``ProgressLogger`` that goes from 0 to 100%. The very top ``ProgressLogger``
1127 converts the deepest local progress value to the corresponding global progress.
1129 Progress values are recorded in
1130 `ProportionValue objects <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProportionValue>`_,
1131 which effectively record fractional value with no loss of precision.
1133 This progress is most useful when the parent process is waiting for child
1134 processes to do their work, to make sure progress does happen, otherwise to stop
1135 waiting for frozen processes. More about that in the "Multi-Process Profiling"
1136 section below.
1138 JSONWriter
1139 ==========
1141 `A JSONWriter object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AJSONWriter>`_
1142 offers a simple way to create a JSON stream (start/end collections, add
1143 elements, etc.), and calls back into a provided
1144 `JSONWriteFunc interface <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AJSONWriteFunc>`_
1145 to output characters.
1147 While these classes live outside of the Profiler directories, it may sometimes be
1148 worth maintaining and/or modifying them to better serve the Profiler's needs.
1149 But there are other users, so be careful not to break other things!
1151 SpliceableJSONWriter and SpliceableChunkedJSONWriter
1152 ====================================================
1154 Because the Profiler deals with large amounts of data (big profiles can take
1155 tens to hundreds of megabytes!), some specialized wrappers add better handling
1156 of these large JSON streams.
1158 `SpliceableJSONWriter <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Abaseprofiler%3A%3ASpliceableJSONWriter>`_
1159 is a subclass of ``JSONWriter``, and allows the "splicing" of JSON strings,
1160 i.e., being able to take a whole well-formed JSON string, and directly inserting
1161 it as a JSON object in the target JSON being streamed.
1163 It also offers some functions that are often useful for the Profiler, such as:
1164 * Converting a timestamp into a JSON object in the stream, taking care of keeping a nanosecond precision, without unwanted zeroes or nines at the end.
1165 * Adding a number of null elements.
1166 * Adding a unique string index, and add that string to a provided unique-string list if necessary. (More about UniqueStrings below.)
1168 `SpliceableChunkedJSONWriter <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Abaseprofiler%3A%3ASpliceableChunkedJSONWriter>`_
1169 is a subclass of ``SpliceableJSONWriter``. Its main attribute is that it provides its own writer
1170 (`ChunkedJSONWriteFunc <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Abaseprofiler%3A%3AChunkedJSONWriteFunc>`_),
1171 which stores the stream as a sequence of "chunks" (heap-allocated buffers).
1172 It starts with a chunk of a default size, and writes incoming data into it,
1173 later allocating more chunks as needed. This avoids having massive buffers being
1174 resized all the time.
1176 It also offers the same splicing abilities as its parent class, but in case an
1177 incoming JSON string comes from another ``SpliceableChunkedJSONWriter``, it's
1178 able to just steal the chunks and add them to its list, thereby avoiding
1179 expensive allocations and copies and destructions.
1181 UniqueStrings
1182 =============
1184 Because a lot of strings would be repeated in profiles (e.g., frequent marker
1185 names), such strings are stored in a separate JSON array of strings, and an
1186 index into this list is used instead of that full string object.
1188 Note that these unique-string indices are currently only located in specific
1189 spots in the JSON tree, they cannot be used just anywhere strings are accepted.
1191 `The UniqueJSONStrings class <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3Abaseprofiler%3A%3AUniqueJSONStrings>`_
1192 stores this list of unique strings in a ``SpliceableChunkedJSONWriter``.
1193 Given a string, it takes care of storing it if encountered for the first time,
1194 and inserts the index into a target ``SpliceableJSONWriter``.
1196 JSON Generation
1197 ===============
1199 The "Gecko Profile Format" can be found at
1200 https://github.com/firefox-devtools/profiler/blob/main/docs-developer/gecko-profile-format.md .
1202 The implementation in the back-end is
1203 `locked_profiler_stream_json_for_this_process <https://searchfox.org/mozilla-central/search?q=locked_profiler_stream_json_for_this_process>`_.
1204 It outputs each JSON top-level JSON object, mostly in sequence. See the code for
1205 how each object is output. Note that there is special handling for samples and
1206 markers, as explained in the following section.
1208 ProcessStreamingContext and ThreadStreamingContext
1209 --------------------------------------------------
1211 In JSON profiles, samples and markers are separated by thread and by
1212 samples/markers. Because there are potentially tens to a hundred threads, it
1213 would be very costly to read the full profile buffer once for each of these
1214 groups. So instead the buffer is read once, and all samples and markers are
1215 handled as they are read, and their JSON output is sent to separate JSON
1216 writers.
1218 `A ProcessStreamingContext object <https://searchfox.org/mozilla-central/search?q=symbol:T_ProcessStreamingContext>`_
1219 contains all the information to facilitate this output, including a list of
1220 `ThreadStreamingContext's <https://searchfox.org/mozilla-central/search?q=symbol:T_ThreadStreamingContext>`_,
1221 which each contain one ``SpliceableChunkedJSONWriter`` for the samples, and one
1222 for the markers in this thread.
1224 When reading entries from the profile buffer, samples and markers are found by
1225 their ``ProfileBufferEntryKind``, and as part of deserializing either kind (more
1226 about each below), the thread ID is read, and determines which
1227 ``ThreadStreamingContext`` will receive the JSON output.
1229 At the end of this process, all ``SpliceableChunkedJSONWriters`` are efficiently
1230 spliced (mainly a pointer move) into the final JSON output.
1232 JSON output of Samples
1233 ----------------------
1235 This work is done in
1236 `ProfileBuffer::DoStreamSamplesAndMarkersToJSON <https://searchfox.org/mozilla-central/search?q=DoStreamSamplesAndMarkersToJSON>`_.
1238 From the main ``ProfileChunkedBuffer``, each entry is visited, its
1239 ``ProfileBufferEntryKind`` is read first, and for samples all frames from
1240 captured stack are converted to the appropriate JSON.
1242 `A UniqueStacks object <https://searchfox.org/mozilla-central/search?q=symbol:T_UniqueStacks>`_
1243 is used to de-duplicate frames and even sub-stacks:
1245 * Each unique frame string is written into a JSON array inside a
1246   ``SpliceableChunkedJSONWriter``, and its index is the frame identifier.
1247 * Each stack level is also de-duplicated, and identifies the associated frame
1248   string, and points at the calling stack level (i.e., closer to the root).
1249 * Finally, the identifier for the top of the stack is stored, along with a
1250   timestamp (and potentially some more information) as the sample.
1252 For example, if we have collected the following samples:
1254 #. A -> B -> C
1255 #. A -> B
1256 #. A -> B -> D
1258 The frame table would contain each frame name, something like:
1259 ``["A", "B", "C", "D"]``. So the frame containing "A" has index 0, "B" is at 1,
1260 etc.
1262 The stack table would contain each stack level, something like:
1263 ``[[0, null], [1, 0], [2, 1], [3, 1]]``. ``[0, null]`` means the frame is 0
1264 ("A"), and it has no caller, it's the root frame. ``[1, 0]`` means the frame is
1265 1 ("B"), and its caller is stack 0, which is just the previous one in this
1266 example.
1268 And the three samples stored in the thread data would be therefore be: 2, 1, 3
1269 (E.g.: "2" points in the stack table at the frame [2,1] with "C", and from them
1270 down to "B", then "A").
1272 All this contains all the information needed to reconstruct all full stack
1273 samples.
1275 JSON output of Markers
1276 ----------------------
1278 This also happens
1279 `inside ProfileBuffer::DoStreamSamplesAndMarkersToJSON <https://searchfox.org/mozilla-central/search?q=DoStreamSamplesAndMarkersToJSON>`_.
1281 When a ``ProfileBufferEntryKind::Marker`` is encountered,
1282 `the DeserializeAfterKindAndStream function <https://searchfox.org/mozilla-central/search?q=DeserializeAfterKindAndStream>`_
1283 reads the ``MarkerOptions`` (stored as explained above), which include the
1284 thread ID, identifying which ``ThreadStreamingContext``'s
1285 ``SpliceableChunkedJSONWriter`` to use.
1287 After that, the common marker data (timing, category, etc.) is output.
1289 Then the ``Streaming::DeserializerTag`` identifies which type of marker this is.
1290 The special case of ``0`` (no payload) means nothing more is output.
1292 Otherwise some more common data is output as part of the payload if present, in
1293 particular the "inner window id" (used to match markers with specific html
1294 frames), and stack.
1296 WIP note: Some of these may move around in the future, see
1297 `bug 1774326 <https://bugzilla.mozilla.org/show_bug.cgi?id=1774326>`_,
1298 `bug 1774328 <https://bugzilla.mozilla.org/show_bug.cgi?id=1774328>`_, and
1299 others.
1301 In case of a C++-written payload, the ``DeserializerTag`` identifies the
1302 ``MarkerDataDeserializer`` function to use. This is part of the heavy templated
1303 code in BaseProfilerMarkersDetail.h, the function is defined as
1304 `MarkerTypeSerialization<MarkerType>::Deserialize <https://searchfox.org/mozilla-central/search?q=symbol:_ZN7mozilla28base_profiler_markers_detail23MarkerTypeSerialization11DeserializeERNS_24ProfileBufferEntryReaderERNS_12baseprofiler20SpliceableJSONWriterE>`_,
1305 which outputs the marker type name, and then each marker payload argument. The
1306 latter is done by using the user-defined ``MarkerType::StreamJSONMarkerData``
1307 parameter list, and recursively deserializing each parameter from the profile
1308 buffer into an on-stack variable of a corresponding type, at the end of which
1309 ``MarkerType::StreamJSONMarkerData`` can be called with all of these arguments
1310 at it expects, and that function does the actual JSON streaming as the user
1311 programmed.
1313 *************
1314 Profiler Stop
1315 *************
1317 See "Profiler Start" and do the reverse!
1319 There is some special handling of the ``SampleThread`` object, just to ensure
1320 that it gets deleted outside of the main profiler mutex being locked, otherwise
1321 this could result in a deadlock (because it needs to take the lock before being
1322 able to check the state variable indicating that the sampling loop and thread
1323 should end).
1325 *****************
1326 Profiler Shutdown
1327 *****************
1329 See "Profiler Initialization" and do the reverse!
1331 One additional action is handling the optional ``MOZ_PROFILER_SHUTDOWN``
1332 environment variable, to output a profile if the profiler was running.
1334 ***********************
1335 Multi-Process Profiling
1336 ***********************
1338 All of the above explanations focused on what the profiler is doing is each
1339 process: Starting, running and collecting samples, markers, and more data,
1340 outputting JSON profiles, and stopping.
1342 But Firefox is a multi-process program, since
1343 `Electrolysis aka e10s <https://wiki.mozilla.org/Electrolysis>`_ introduce child
1344 processes to handle web content and extensions, and especially since
1345 `Fission <https://wiki.mozilla.org/Project_Fission>`_ forced even parts of the
1346 same webpage to run in separate processes, mainly for added security. Since then
1347 Firefox can spawn many processes, sometimes 10 to 20 when visiting busy sites.
1349 The following sections explains how profiling Firefox as a whole works.
1351 IPC (Inter-Process Communication)
1352 =================================
1354 See https://firefox-source-docs.mozilla.org/ipc/.
1356 As a quick summary, some message-passing function-like declarations live in
1357 `PProfiler.ipdl <https://searchfox.org/mozilla-central/source/tools/profiler/gecko/PProfiler.ipdl>`_,
1358 and corresponding ``SendX`` and ``RecvX`` C++ functions are respectively
1359 generated in
1360 `PProfilerParent.h <https://searchfox.org/mozilla-central/source/__GENERATED__/ipc/ipdl/_ipdlheaders/mozilla/PProfilerParent.h>`_,
1361 and virtually declared (for user implementation) in
1362 `PProfilerChild.h <https://searchfox.org/mozilla-central/source/__GENERATED__/ipc/ipdl/_ipdlheaders/mozilla/PProfilerChild.h>`_.
1364 During Profiling
1365 ================
1367 Exit profiles
1368 -------------
1370 One IPC message that is not in PProfiler.ipdl, is
1371 `ShutdownProfile <https://searchfox.org/mozilla-central/search?q=ShutdownProfile%28&path=&case=false&regexp=false>`_
1373 `PContent.ipdl <https://searchfox.org/mozilla-central/source/dom/ipc/PContent.ipdl>`_.
1375 It's called from
1376 `ContentChild::ShutdownInternal <https://searchfox.org/mozilla-central/search?q=symbol:_ZN7mozilla3dom12ContentChild16ShutdownInternalEv>`_,
1377 just before a child process ends, and if the profiler was running, to ensure
1378 that the profile data is collected and sent to the parent, for storage in its
1379 ``ActivePS``.
1382 `ActivePS::AddExitProfile <https://searchfox.org/mozilla-central/search?q=symbol:_ZN8ActivePS14AddExitProfileERK10PSAutoLockRK12nsTSubstringIcE>`_
1383 for details. Note that the current "buffer position at gathering time" (which is
1384 effectively the largest ``ProfileBufferBlockIndex`` that is present in the
1385 global profile buffer) is recorded. Later,
1386 `ClearExpiredExitProfiles <https://searchfox.org/mozilla-central/search?q=ClearExpiredExitProfiles>`_
1387 looks at the **smallest** ``ProfileBufferBlockIndex`` still present in the
1388 buffer (because early chunks may have been discarded to limit memory usage), and
1389 discards exit profiles that were recorded before, because their data is now
1390 older than anything stored in the parent.
1392 Profile Buffer Global Memory Control
1393 ------------------------------------
1395 Each process runs its own profiler, with each its own profile chunked buffer. To
1396 keep the overall memory usage of all these buffers under the user-picked limit,
1397 processes work together, with the parent process overseeing things.
1399 Diagram showing the relevant classes, see details in the following sub-sections:
1401 .. image:: fissionprofiler-20200424.png
1403 ProfileBufferControlledChunkManager
1404 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1406 `The ProfileBufferControlledChunkManager interface <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferControlledChunkManager>`_
1407 allows a controller to get notified about all chunk updates, and to force the
1408 destruction/recycling of old chunks.
1409 `The ProfileBufferChunkManagerWithLocalLimit class <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferChunkManagerWithLocalLimit>`_
1410 implements it.
1412 `An Update object <https://searchfox.org/mozilla-central/search?q=symbol:T_mozilla%3A%3AProfileBufferControlledChunkManager%3A%3AUpdate>`_
1413 contains all information related to chunk changes: How much memory is currently
1414 used by the local chunk manager, how much has been "released" (and therefore
1415 could be destroyed/recycled), and a list of all chunks that were released since
1416 the previous update; it also has a special state meaning that the child is
1417 shutting down so there won't be updates anymore. An ``Update`` may be "folded"
1418 into a previous one, to create a combined update equivalent to the two separate
1419 ones one after the other.
1421 Update Handling in the ProfilerChild
1422 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1424 When the profiler starts in a child process, the ``ProfilerChild``
1425 `starts to listen for updates <https://searchfox.org/mozilla-central/search?q=symbol:_ZN7mozilla13ProfilerChild17SetupChunkManagerEv>`_.
1427 These updates are stored and folded into previous ones (if any). At some point,
1428 `an AwaitNextChunkManagerUpdate message <https://searchfox.org/mozilla-central/search?q=RecvAwaitNextChunkManagerUpdate>`_
1429 will be received, and any update can be forwarded to the parent. The local
1430 update is cleared, ready to store future updates.
1432 Update Handling in the ProfilerParent
1433 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1435 When the profiler starts AND when there are child processes, the
1436 `ProfilerParent's ProfilerParentTracker <https://searchfox.org/mozilla-central/search?q=ProfilerParentTracker>`_
1437 creates
1438 `a ProfileBufferGlobalController <https://searchfox.org/mozilla-central/search?q=ProfileBufferGlobalController>`_,
1439 which starts to listen for updates from the local chunk manager.
1441 The ``ProfilerParentTracker`` is also responsible for keeping track of child
1442 processes, and to regularly
1443 `send them AwaitNextChunkManagerUpdate messages <https://searchfox.org/mozilla-central/search?q=SendAwaitNextChunkManagerUpdate>`_,
1444 that the child's ``ProfilerChild`` answers to with updates. The update may
1445 indicate that the child is shutting down, in which case the tracker will stop
1446 tracking it.
1448 All these updates (from the local chunk manager, and from child processes' own
1449 chunk managers) are processed in
1450 `ProfileBufferGlobalController::HandleChunkManagerNonFinalUpdate <https://searchfox.org/mozilla-central/search?q=HandleChunkManagerNonFinalUpdate>`_.
1451 Based on this stream of updates, it is possible to calculate the total memory
1452 used by all profile buffers in all processes, and to keep track of all chunks
1453 that have been "released" (i.e., are full, and can be destroyed). When the total
1454 memory usage reaches the user-selected limit, the controller can lookup the
1455 oldest chunk, and get it destroyed (either a local call for parent chunks, or by
1456 sending
1457 `a DestroyReleasedChunksAtOrBefore message <https://searchfox.org/mozilla-central/search?q=DestroyReleasedChunksAtOrBefore>`_
1458 to the owning child).
1460 Historical note: Prior to Fission, the Profiler used to keep one fixed-size
1461 circular buffer in each process, but as Fission made the possible number of
1462 processes unlimited, the memory consumption grew too fast, and required the
1463 implementation of the above system. But there may still be mentions of
1464 "circular buffers" in the code or documents; these have effectively been
1465 replaced by chunked buffers, with centralized chunk control.
1467 Gathering Child Profiles
1468 ========================
1470 When it's time to capture a full profile, the parent process performs its own
1471 JSON generation (as described above), and sends
1472 `a GatherProfile message <https://searchfox.org/mozilla-central/search?q=GatherProfile%28>`_
1473 to all child processes, which will make them generate their JSON profile and
1474 send it back to the parent.
1476 All child profiles, including the exit profiles collected during profiling, are
1477 stored as elements of a top-level array with property name "processes".
1479 During the gathering phase, while the parent is waiting for child responses, it
1480 regularly sends
1481 `GetGatherProfileProgress messages <https://searchfox.org/mozilla-central/search?q=GetGatherProfileProgress>`_
1482 to all child processes that have not sent their profile yet, and the parent
1483 expects responses within a short timeframe. The response carries a progress
1484 value. If at some point two messages went with no progress was made anywhere
1485 (either there was no response, or the progress value didn't change), the parent
1486 assumes that remaining child processes may be frozen indefinitely, stops the
1487 gathering and considers the JSON generation complete.
1489 During all of the above work, events are logged (especially issues with child
1490 processes), and are added at the end of the JSON profile, in a top-level object
1491 with property name "profileGatheringLog". This object is free-form, and is not
1492 intended to be displayed, or even read by most people. But it may include
1493 interesting information for advanced users regarding the profile-gathering
1494 phase.