diff --git a/docs/performance/Benchmarking.md b/docs/performance/Benchmarking.md
index 279c68d424af1..cc1add10e9e1c 100644
--- a/docs/performance/Benchmarking.md
+++ b/docs/performance/Benchmarking.md
@@ -19,7 +19,7 @@ Add the following to your
[mozconfig](/setup/configuring_build_options.html#using-a-mozconfig-configuration-file)
in order to build with level 2:
-``` {.notranslate}
+```
ac_add_options RUSTC_OPT_LEVEL=2
```
@@ -32,7 +32,7 @@ all debug builds, and in optimized Nightly builds (but not opt Developer
Edition or Beta builds). The poisoning can be disabled by setting the
environment variable
-``` {.notranslate}
+```
JSGC_DISABLE_POISONING=1
```
diff --git a/docs/performance/bestpractices.md b/docs/performance/bestpractices.md
index 81014fa8512d6..26279171bc65a 100644
--- a/docs/performance/bestpractices.md
+++ b/docs/performance/bestpractices.md
@@ -524,7 +524,7 @@ The Gecko profiler is your best friend when diagnosing performance
problems and looking for bottlenecks. There’s plenty of excellent
documentation on MDN about the Gecko profiler:
-- [Basic instructions for gathering and sharing a performance profile](https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Reporting_a_Performance_Problem)
+- [Basic instructions for gathering and sharing a performance profile](reporting_a_performance_problem.md)
- [Advanced profile analysis](https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler)
diff --git a/docs/performance/call_tree.md b/docs/performance/call_tree.md
new file mode 100644
index 0000000000000..43d523ebda995
--- /dev/null
+++ b/docs/performance/call_tree.md
@@ -0,0 +1,185 @@
+# Call Tree
+
+The Call Tree tells you which JavaScript functions the browser spent the
+most time in. By analyzing its results, you can find bottlenecks in your
+code - places where the browser is spending a disproportionately large
+amount of time.
+
+These bottlenecks are the places where any optimizations you can make
+will have the biggest impact.
+
+The Call Tree is a sampling profiler. It periodically samples the state
+of the JavaScript engine and records the stack for the code executing at
+the time. Statistically, the number of samples taken in which we were
+executing a particular function corresponds to the amount of time the
+browser spent executing it.
+
+In this article, we'll use the output of a simple program as an
+example. If you want to get the program to experiment with your profile,
+you can find it
+[here](https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/).
+You can find the specific profile we discuss
+[here](https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/profile/call-tree.json)
+- just import it to the performance tool to follow along.
+
+There's a short page describing the structure of this program
+[here](sorting_algorithms_comparison.md).
+
+Note that we use the same program - the same profile, in fact - in the
+documentation page for the [Flame
+Chart](https://developer.mozilla.org/en-US/docs/Tools/Performance/Flame_Chart).
+
+The screenshot below shows the output of a program that compares three
+sorting algorithms - bubble sort, selection sort, and quicksort. To do
+this, it generates some arrays filled with random integers and sorts
+them using each algorithm in turn.
+
+We've [zoomed](https://developer.mozilla.org/en-US/docs/Tools/Performance/UI_Tour#zooming_in) into
+the part of the recording that shows a long JavaScript marker:
+
+![](img/perf-call-tree.png)
+
+The Call Tree presents the results in a table. Each row represents a
+function in which at least one sample was taken, and the rows are
+ordered by the number of samples taken while in that function, highest
+to lowest.
+
+*Samples* is the number of samples that were taken when we were
+executing this particular function, including its children (the other
+functions called by this particular function).
+
+*Total Time* is that number translated into milliseconds, based on the
+total amount of time covered by the selected portion of the recording.
+These numbers should roughly be the same as the number of samples.
+
+*Total Cost* is that number as a percentage of the total number of
+samples in the selected portion of the recording.
+
+*Self Time* is calculated as the time spent in that particular function,
+excluding its children. This comes from the captured stacks where this
+function is the leafmost function.
+
+*Self Cost* is calculated from *Self Time* as a percentage of the total
+number of samples in the selected portion of the recording.
+
+In the current version of the Call Tree, these are the most important
+columns. Functions with a relatively high *Self Cost* are good
+candidates for optimization, either because they take a long time to
+run, or because they are called very often.
+
+[The inverted call tree](#using_an_inverted_aka_bottom-up_call_tree) is
+a good way to focus on these *Self Cos*t values.
+
+This screenshot tells us something we probably already knew: Bubble sort
+is a very inefficient algorithm. We have about six times as many samples
+in bubble sort as in selection sort, and 13 times as many as in
+quicksort.
+
+## Walking up the call tree
+
+Next to each function name is a disclosure arrow: Click that, and you
+can see the path back up the call tree, from the function in which the
+sample was taken, to the root. For example, we can expand the entry for
+`bubbleSort()`:
+
+![](img/perf-call-tree-expanded-bubblesort.png)
+
+So we can see the call graph is like this:
+
+ sortAll()
+
+ -> sort()
+
+ -> bubbleSort()
+
+Note also that *Self Cost* for `sort()` here is 1.45%, and note that
+this is the same as for the separate entry for `sort()` later in the
+list. This is telling us that some samples were taken in `sort()`
+itself, rather than in the functions it calls.
+
+Sometimes there's more than one path back from an entry to the top
+level. Let's expand the entry for `swap()`:
+
+![](img/perf-call-tree-expanded-sawp.png)
+
+There were 253 samples taken inside `swap()`. But `swap()` was reached
+by two different paths: both `bubbleSort()` and `selectionSort()` use
+it. We can also see that 252 of the 253 samples in `swap() `were taken
+in the `bubbleSort()` branch, and only one in the `selectionSort()`
+branch.
+
+This result means that bubble sort is even less efficient than we had
+thought! It can shoulder the blame for another 252 samples, or almost
+another 10% of the total cost.
+
+With this kind of digging, we can figure out the whole call graph, with
+associated sample count:
+
+ sortAll() // 8
+
+ -> sort() // 37
+
+ -> bubbleSort() // 1345
+
+ -> swap() // 252
+
+ -> selectionSort() // 190
+
+ -> swap() // 1
+
+ -> quickSort() // 103
+
+ -> partition() // 12
+
+## Platform data
+
+You'll also see some rows labeled *Gecko*, *Input & Events*, and so on.
+These represent internal browser calls.
+
+This can be useful information too. If your site is making the browser
+work hard, this might not show up as samples recorded in your code, but
+it is still your problem.
+
+In our example, there are 679 samples assigned to *Gecko* - the
+second-largest group after `bubbleSort()`. Let's expand that:
+
+![](img/perf-call-tree-expanded-gecko.png)
+
+This result is telling us that 614 of those samples, or about 20% of the
+total cost, are coming from our `sort()` call. If we look at the code
+for `sort()`, it should be fairly obvious that the high platform data
+cost is coming from repeated calls to `console.log()`:
+
+``` {.brush: .js}
+function sort(unsorted) {
+ console.log(bubbleSort(unsorted));
+ console.log(selectionSort(unsorted));
+ console.log(quickSort(unsorted));
+}
+```
+
+It would certainly be worthwhile considering more efficient ways of
+implementing this.
+
+One thing to be aware of here is that idle time is classified as
+*Gecko*, so parts of your profile where your JavaScript isn't running
+will contribute *Gecko* samples. These aren't relevant to the
+performance of your site.
+
+By default, the Call Tree doesn't split platform data out into separate
+functions, because they add a great deal of noise, and the details are
+not likely to be useful to people not working on Firefox. If you want to
+see the details, check \"Show Gecko Platform Data\" in the
+[Settings](https://developer.mozilla.org/en-US/docs/Tools/Performance/UI_Tour#toolbar).
+
+## Using an inverted, aka Bottom-Up, Call Tree
+
+An inverted call tree reverses the order of all stacks, putting the
+leafmost function calls at the top. The direct consequence is that this
+is a view that focuses more on the function's *Self Time* information.
+This is a very useful view to find some hot spot in your code.
+
+To display this view, click the gear icon on the right-hand end of the
+performance tab and select **Invert Call Tree**.
+
+![](img/performance_menu_invert_call_tree.png)
diff --git a/docs/performance/img/dominators-1.png b/docs/performance/img/dominators-1.png
new file mode 100644
index 0000000000000..163a80016c7c0
Binary files /dev/null and b/docs/performance/img/dominators-1.png differ
diff --git a/docs/performance/img/dominators-10.png b/docs/performance/img/dominators-10.png
new file mode 100644
index 0000000000000..e6688060af40a
Binary files /dev/null and b/docs/performance/img/dominators-10.png differ
diff --git a/docs/performance/img/dominators-2.png b/docs/performance/img/dominators-2.png
new file mode 100644
index 0000000000000..99b7db7b0989b
Binary files /dev/null and b/docs/performance/img/dominators-2.png differ
diff --git a/docs/performance/img/dominators-3.png b/docs/performance/img/dominators-3.png
new file mode 100644
index 0000000000000..2d380f6e21080
Binary files /dev/null and b/docs/performance/img/dominators-3.png differ
diff --git a/docs/performance/img/dominators-4.png b/docs/performance/img/dominators-4.png
new file mode 100644
index 0000000000000..d3d5eef59c24a
Binary files /dev/null and b/docs/performance/img/dominators-4.png differ
diff --git a/docs/performance/img/dominators-5.png b/docs/performance/img/dominators-5.png
new file mode 100644
index 0000000000000..41a03488e92cf
Binary files /dev/null and b/docs/performance/img/dominators-5.png differ
diff --git a/docs/performance/img/dominators-6.png b/docs/performance/img/dominators-6.png
new file mode 100644
index 0000000000000..a3d3026eb2d5b
Binary files /dev/null and b/docs/performance/img/dominators-6.png differ
diff --git a/docs/performance/img/dominators-7.png b/docs/performance/img/dominators-7.png
new file mode 100644
index 0000000000000..160f205391410
Binary files /dev/null and b/docs/performance/img/dominators-7.png differ
diff --git a/docs/performance/img/dominators-8.png b/docs/performance/img/dominators-8.png
new file mode 100644
index 0000000000000..e9512b9b05a4f
Binary files /dev/null and b/docs/performance/img/dominators-8.png differ
diff --git a/docs/performance/img/dominators-9.png b/docs/performance/img/dominators-9.png
new file mode 100644
index 0000000000000..af396abc2124e
Binary files /dev/null and b/docs/performance/img/dominators-9.png differ
diff --git a/docs/performance/img/memory-1-small.png b/docs/performance/img/memory-1-small.png
new file mode 100644
index 0000000000000..a2076330b8737
Binary files /dev/null and b/docs/performance/img/memory-1-small.png differ
diff --git a/docs/performance/img/memory-2-small.png b/docs/performance/img/memory-2-small.png
new file mode 100644
index 0000000000000..569b0d9d66643
Binary files /dev/null and b/docs/performance/img/memory-2-small.png differ
diff --git a/docs/performance/img/memory-3-small.png b/docs/performance/img/memory-3-small.png
new file mode 100644
index 0000000000000..5d77bd7f60826
Binary files /dev/null and b/docs/performance/img/memory-3-small.png differ
diff --git a/docs/performance/img/memory-4-small.png b/docs/performance/img/memory-4-small.png
new file mode 100644
index 0000000000000..9a1e18da6fdce
Binary files /dev/null and b/docs/performance/img/memory-4-small.png differ
diff --git a/docs/performance/img/memory-5-small.png b/docs/performance/img/memory-5-small.png
new file mode 100644
index 0000000000000..e3277186dcdf6
Binary files /dev/null and b/docs/performance/img/memory-5-small.png differ
diff --git a/docs/performance/img/memory-6-small.png b/docs/performance/img/memory-6-small.png
new file mode 100644
index 0000000000000..da69b93e51c01
Binary files /dev/null and b/docs/performance/img/memory-6-small.png differ
diff --git a/docs/performance/img/memory-7-small.png b/docs/performance/img/memory-7-small.png
new file mode 100644
index 0000000000000..844565a8b4db1
Binary files /dev/null and b/docs/performance/img/memory-7-small.png differ
diff --git a/docs/performance/img/memory-graph-dominator-multiple-references.svg b/docs/performance/img/memory-graph-dominator-multiple-references.svg
new file mode 100644
index 0000000000000..b4740aaf2d7f3
--- /dev/null
+++ b/docs/performance/img/memory-graph-dominator-multiple-references.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/memory-graph-dominators.svg b/docs/performance/img/memory-graph-dominators.svg
new file mode 100644
index 0000000000000..051f41e800f0e
--- /dev/null
+++ b/docs/performance/img/memory-graph-dominators.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/memory-graph-immediate-dominator.svg b/docs/performance/img/memory-graph-immediate-dominator.svg
new file mode 100644
index 0000000000000..e5f952c302c79
--- /dev/null
+++ b/docs/performance/img/memory-graph-immediate-dominator.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/memory-graph-unreachable.svg b/docs/performance/img/memory-graph-unreachable.svg
new file mode 100644
index 0000000000000..f308c49a09652
--- /dev/null
+++ b/docs/performance/img/memory-graph-unreachable.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/memory-graph.svg b/docs/performance/img/memory-graph.svg
new file mode 100644
index 0000000000000..f7bb83cad100d
--- /dev/null
+++ b/docs/performance/img/memory-graph.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/memory-tool-aggregate-view.png b/docs/performance/img/memory-tool-aggregate-view.png
new file mode 100644
index 0000000000000..653710979f0be
Binary files /dev/null and b/docs/performance/img/memory-tool-aggregate-view.png differ
diff --git a/docs/performance/img/memory-tool-call-stack-expanded.png b/docs/performance/img/memory-tool-call-stack-expanded.png
new file mode 100644
index 0000000000000..fe2364da58505
Binary files /dev/null and b/docs/performance/img/memory-tool-call-stack-expanded.png differ
diff --git a/docs/performance/img/memory-tool-call-stack.png b/docs/performance/img/memory-tool-call-stack.png
new file mode 100644
index 0000000000000..52a96015da2c0
Binary files /dev/null and b/docs/performance/img/memory-tool-call-stack.png differ
diff --git a/docs/performance/img/memory-tool-in-group-icon.png b/docs/performance/img/memory-tool-in-group-icon.png
new file mode 100644
index 0000000000000..6354a3d3779e7
Binary files /dev/null and b/docs/performance/img/memory-tool-in-group-icon.png differ
diff --git a/docs/performance/img/memory-tool-in-group-retaining-paths.png b/docs/performance/img/memory-tool-in-group-retaining-paths.png
new file mode 100644
index 0000000000000..191115f041902
Binary files /dev/null and b/docs/performance/img/memory-tool-in-group-retaining-paths.png differ
diff --git a/docs/performance/img/memory-tool-in-group.png b/docs/performance/img/memory-tool-in-group.png
new file mode 100644
index 0000000000000..88aac55e9e6f2
Binary files /dev/null and b/docs/performance/img/memory-tool-in-group.png differ
diff --git a/docs/performance/img/memory-tool-inverted-call-stack.png b/docs/performance/img/memory-tool-inverted-call-stack.png
new file mode 100644
index 0000000000000..5a951c2e8c255
Binary files /dev/null and b/docs/performance/img/memory-tool-inverted-call-stack.png differ
diff --git a/docs/performance/img/memory-tool-switch-view.png b/docs/performance/img/memory-tool-switch-view.png
new file mode 100644
index 0000000000000..bb3cb0cdb3827
Binary files /dev/null and b/docs/performance/img/memory-tool-switch-view.png differ
diff --git a/docs/performance/img/monsters.svg b/docs/performance/img/monsters.svg
new file mode 100644
index 0000000000000..844744d3d13bc
--- /dev/null
+++ b/docs/performance/img/monsters.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/docs/performance/img/treemap-bbc.png b/docs/performance/img/treemap-bbc.png
new file mode 100644
index 0000000000000..55552b8382a63
Binary files /dev/null and b/docs/performance/img/treemap-bbc.png differ
diff --git a/docs/performance/img/treemap-domnodes.png b/docs/performance/img/treemap-domnodes.png
new file mode 100644
index 0000000000000..1192e390dabf5
Binary files /dev/null and b/docs/performance/img/treemap-domnodes.png differ
diff --git a/docs/performance/img/treemap-monsters.png b/docs/performance/img/treemap-monsters.png
new file mode 100644
index 0000000000000..513adab9239c7
Binary files /dev/null and b/docs/performance/img/treemap-monsters.png differ
diff --git a/docs/performance/index.md b/docs/performance/index.md
index 2cc1caceaae13..85f0f292947da 100644
--- a/docs/performance/index.md
+++ b/docs/performance/index.md
@@ -7,11 +7,22 @@ explains how to test for performance in Firefox.
The [profiler documentation](../../tools/profiler/)
explains how to use the Gecko profiler.
-```eval_rst
-.. toctree::
- :titlesonly:
- :maxdepth: 1
- :glob:
+## General Performance references
+* Tips on generating valid performance metrics by [benchmarking](benchmarking.md)
+* [GPU Performance](GPU_performance.md) Tips for reducing impacts on browser performance in front-end code.
+* [Automated Performance testing and Sheriffing](automated_performance_testing_and_sheriffing.md) Information on automated performance testing and sheriffing at Mozilla.
+* [Performance best practices for Firefox front-end engineers](bestpractices.md) Tips for reducing impacts on browser performance in front-end code.
+* [Reporting a performance problem](reporting_a_performance_problem.md) A user friendly guide to reporting a performance problem. A development environment is not required.
+* [Scroll Linked Effects](scroll-linked_effects.md) Information on scroll-linked effects, their effect on performance, related tools, and possible mitigation techniques.
- *
-```
+## Memory profiling and leak detection tools
+* The [Developer Tools Memory panel](memory/memory.md) supports taking heap snapshots, diffing them, computing dominator trees to surface "heavy retainers", and recording allocation stacks.
+* [About:memory](memory/about_colon_memory.md) about:memory is the easiest-to-use tool for measuring memory usage in Mozilla code, and is the best place to start. It also lets you do other memory-related operations like trigger GC and CC, dump GC & CC logs, and dump DMD reports. about:memory is built on top of Firefox's memory reporting infrastructure.
+* [DMD](memory/DMD.md) is a tool that identifies shortcomings in about:memory's measurements, and can also do multiple kinds of general heap profiling.
+* [AWSY](memory/awsy.md) (are we slim yet?) is a memory usage and regression tracker.
+* [Bloatview](memory/bloatview.md) prints per-class statistics on allocations and refcounts, and provides gross numbers on the amount of memory being leaked broken down by class. It is used as part of Mozilla's continuous integration testing.
+* [Refcount Tracing and Balancing](memory/refcount_tracing_and_balancing.md) are ways to track down leaks caused by incorrect uses of reference counting. They are slow and not particular easy to use, and thus most suitable for use by expert developers.
+* [GC and CC Logs](memory/GC_and_CC_logs.md)
+* [Leak Gauge](memory/leak_gauge.md) can be generated and analyzed to in various ways. In particular, they can help you understand why a particular object is being kept alive.
+* [LogAlloc](https://searchfox.org/mozilla-central/source/memory/replace/logalloc/README) is a tool that dumps a log of memory allocations in Gecko. That log can then be replayed against Firefox's default memory allocator independently or through another replace-malloc library, allowing the testing of other allocators under the exact same workload.
+* [See also the documentation on Leak-hunting strategies and tips.](leak_hunting_strategies_and_tips.md)
diff --git a/docs/performance/memory/DOM_allocation_example.md b/docs/performance/memory/DOM_allocation_example.md
new file mode 100644
index 0000000000000..11e7aad6769e8
--- /dev/null
+++ b/docs/performance/memory/DOM_allocation_example.md
@@ -0,0 +1,57 @@
+# DOM allocation example
+
+This article describes a very simple web page that we\'ll use to
+illustrate some features of the Memory tool.
+
+You can try out the site at
+.
+
+It just contains a script that creates a large number of DOM nodes:
+
+``` {.brush: .js}
+var toolbarButtonCount = 20;
+var toolbarCount = 200;
+
+function getRandomInt(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function createToolbarButton() {
+ var toolbarButton = document.createElement("span");
+ toolbarButton.classList.add("toolbarbutton");
+ // stop Spidermonkey from sharing instances
+ toolbarButton[getRandomInt(0,5000)] = "foo";
+ return toolbarButton;
+}
+
+function createToolbar() {
+ var toolbar = document.createElement("div");
+ // stop Spidermonkey from sharing instances
+ toolbar[getRandomInt(0,5000)] = "foo";
+ for (var i = 0; i < toolbarButtonCount; i++) {
+ var toolbarButton = createToolbarButton();
+ toolbar.appendChild(toolbarButton);
+ }
+ return toolbar;
+}
+
+function createToolbars() {
+ var container = document.getElementById("container");
+ for (var i = 0; i < toolbarCount; i++) {
+ var toolbar = createToolbar();
+ container.appendChild(toolbar);
+ }
+}
+
+createToolbars();
+```
+
+A simple pseudocode representation of how this code operates looks like
+this:
+
+ createToolbars()
+ -> createToolbar() // called 200 times, creates 1 DIV element each time
+ -> createToolbarButton() // called 20 times per toolbar, creates 1 SPAN element each time
+
+In total, then, it creates 200 `HTMLDivElement` objects, and 4000
+`HTMLSpanElement` objects.
diff --git a/docs/performance/memory/about_colon_memory.md b/docs/performance/memory/about_colon_memory.md
new file mode 100644
index 0000000000000..07d575a7f3905
--- /dev/null
+++ b/docs/performance/memory/about_colon_memory.md
@@ -0,0 +1,274 @@
+# about:memory
+
+about:memory is a special page within Firefox that lets you view, save,
+load, and diff detailed measurements of Firefox's memory usage. It also
+lets you do other memory-related operations like trigger GC and CC, dump
+GC & CC logs, and dump DMD reports. It is present in all builds and does
+not require any preparation to be used.
+
+## How to generate memory reports
+
+Let's assume that you want to measure Firefox's memory usage. Perhaps
+you want to investigate it yourself, or perhaps someone has asked you to
+use about:memory to generate "memory reports" so they can investigate
+a problem you are having. Follow these steps.
+
+- At the moment of interest (e.g. once Firefox's memory usage has
+ gotten high) open a new tab and type "about:memory" into the
+ address bar and hit "Enter".
+- If you are using a communication channel where files can be sent,
+ such as Bugzilla or email, click on the "Measure and save..."
+ button. This will open a file dialog that lets you save the memory
+ reports to a file of your choosing. (The filename will have a
+ `.json.gz` suffix.) You can then attach or upload the file
+ appropriately. The recipients will be able to view the contents of
+ this file within about:memory in their own Firefox instance.
+- If you are using a communication channel where only text can be
+ sent, such as a comment thread on a website, click on the
+ "Measure..." button. This will cause a tree-like structure to be
+ generated text within about:memory. This structure is just text, so
+ you can copy and paste some or all of this text into any kind of
+ text buffer. (You don't need to take a screenshot.) This text
+ contains fewer measurements than a memory reports file, but is often
+ good enough to diagnose problems. Don't click "Measure..."
+ repeatedly, because that will cause the memory usage of about:memory
+ itself to rise, due to it discarding and regenerating large numbers
+ of DOM nodes.
+
+Note that in both cases the generated data contains privacy-sensitive
+details such as the full list of the web pages you have open in other
+tabs. If you do not wish to share this information, you can select the
+"anonymize" checkbox before clicking on "Measure and save..." or
+"Measure...". This will cause the privacy-sensitive data to be
+stripped out, but it may also make it harder for others to investigate
+the memory usage.
+
+## Loading memory reports from file
+
+The easiest way to load memory reports from file is to use the
+"Load..." button. You can also use the "Load and diff..." button
+to get the difference between two memory report files.
+
+Single memory report files can also be loaded automatically when
+about:memory is loaded by appending a `file` query string, for example:
+
+ about:memory?file=/home/username/reports.json.gz
+
+This is most useful when loading memory reports files obtained from a
+Firefox OS device.
+
+Memory reports are saved to file as gzipped JSON. These files can be
+loaded as is, but they can also be loaded after unzipping.
+
+## Interpreting memory reports
+
+Almost everything you see in about:memory has an explanatory tool-tip.
+Hover over any button to see a description of what it does. Hover over
+any measurement to see a description of what it means.
+
+### [Measurement basics]
+
+Most measurements use bytes as their unit, but some are counts or
+percentages.
+
+Most measurements are presented within trees. For example:
+
+ 585 (100.0%) -- preference-service
+ └──585 (100.0%) -- referent
+ ├──493 (84.27%) ── strong
+ └───92 (15.73%) -- weak
+ ├──92 (15.73%) ── alive
+ └───0 (00.00%) ── dead
+
+Leaf nodes represent actual measurements; the value of each internal
+node is the sum of all its children.
+
+The use of trees allows measurements to be broken down into further
+categories, sub-categories, sub-sub-categories, etc., to arbitrary
+depth, as needed. All the measurements within a single tree are
+non-overlapping.
+
+Tree paths can be written using \'/\' as a separator. For example,
+`preference/referent/weak/dead` represents the path to the final leaf
+node in the example tree above.
+
+Sub-trees can be collapsed or expanded by clicking on them. If you find
+any particular tree overwhelming, it can be helpful to collapse all the
+sub-trees immediately below the root, and then gradually expand the
+sub-trees of interest.
+
+### [Sections]
+
+Memory reports are displayed on a per-process basis, with one process
+per section. Within each process's measurements, there are the
+following subsections.
+
+#### Explicit Allocations
+
+This section contains a single tree, called "explicit", that measures
+all the memory allocated via explicit calls to heap allocation functions
+(such as `malloc` and `new`) and to non-heap allocations functions (such
+as `mmap` and `VirtualAlloc`).
+
+Here is an example for a browser session where tabs were open to
+cnn.com, techcrunch.com, and arstechnica.com. Various sub-trees have
+been expanded and others collapsed for the sake of presentation.
+
+ 191.89 MB (100.0%) -- explicit
+ ├───63.15 MB (32.91%) -- window-objects
+ │ ├──24.57 MB (12.80%) -- top(http://edition.cnn.com/, id=8)
+ │ │ ├──20.18 MB (10.52%) -- active
+ │ │ │ ├──10.57 MB (05.51%) -- window(http://edition.cnn.com/)
+ │ │ │ │ ├───4.55 MB (02.37%) ++ js-compartment(http://edition.cnn.com/)
+ │ │ │ │ ├───2.60 MB (01.36%) ++ layout
+ │ │ │ │ ├───1.94 MB (01.01%) ── style-sheets
+ │ │ │ │ └───1.48 MB (00.77%) -- (2 tiny)
+ │ │ │ │ ├──1.43 MB (00.75%) ++ dom
+ │ │ │ │ └──0.05 MB (00.02%) ── property-tables
+ │ │ │ └───9.61 MB (05.01%) ++ (18 tiny)
+ │ │ └───4.39 MB (02.29%) -- js-zone(0x7f69425b5800)
+ │ ├──15.75 MB (08.21%) ++ top(http://techcrunch.com/, id=20)
+ │ ├──12.85 MB (06.69%) ++ top(http://arstechnica.com/, id=14)
+ │ ├───6.40 MB (03.33%) ++ top(chrome://browser/content/browser.xul, id=3)
+ │ └───3.59 MB (01.87%) ++ (4 tiny)
+ ├───45.74 MB (23.84%) ++ js-non-window
+ ├───33.73 MB (17.58%) ── heap-unclassified
+ ├───22.51 MB (11.73%) ++ heap-overhead
+ ├────6.62 MB (03.45%) ++ images
+ ├────5.82 MB (03.03%) ++ workers/workers(chrome)
+ ├────5.36 MB (02.80%) ++ (16 tiny)
+ ├────4.07 MB (02.12%) ++ storage
+ ├────2.74 MB (01.43%) ++ startup-cache
+ └────2.16 MB (01.12%) ++ xpconnect
+
+Some expertise is required to understand the full details here, but
+there are various things worth pointing out.
+
+- This "explicit" value at the root of the tree represents all the
+ memory allocated via explicit calls to allocation functions.
+- The "window-objects" sub-tree represents all JavaScript `window`
+ objects, which includes the browser tabs and UI windows. For
+ example, the "top(http://edition.cnn.com/, id=8)" sub-tree
+ represents the tab open to cnn.com, and
+ "top(chrome://browser/content/browser.xul, id=3)" represents the
+ main browser UI window.
+- Within each window's measurements are sub-trees for JavaScript
+ ("js-compartment(...)" and "js-zone(...)"), layout,
+ style-sheets, the DOM, and other things.
+- It's clear that the cnn.com tab is using more memory than the
+ techcrunch.com tab, which is using more than the arstechnica.com
+ tab.
+- Sub-trees with names like "(2 tiny)" are artificial nodes inserted
+ to allow insignificant sub-trees to be collapsed by default. If you
+ select the "verbose" checkbox before measuring, all trees will be
+ shown fully expanded and no artificial nodes will be inserted.
+- The "js-non-window" sub-tree represents JavaScript memory usage
+ that doesn't come from windows, but from the browser core.
+- The "heap-unclassified" value represents heap-allocated memory
+ that is not measured by any memory reporter. This is typically
+ 10--20% of "explicit". If it gets higher, it indicates that
+ additional memory reporters should be added.
+ [DMD](DMD.md")
+ can be used to determine where these memory reporters should be
+ added.
+- There are measurements for other content such as images and workers,
+ and for browser subsystems such as the startup cache and XPConnect.
+
+Some add-on memory usage is identified, as the following example shows.
+
+ ├───40,214,384 B (04.17%) -- add-ons
+ │ ├──21,184,320 B (02.20%) ++ {d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}/js-non-window/zones/zone(0x100496800)/compartment([System Principal], jar:file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7Bd10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d%7D.xpi!/bootstrap.js (from: resource://gre/modules/addons/XPIProvider.jsm:4307))
+ │ ├──11,583,312 B (01.20%) ++ jid1-xUfzOsOFlzSOXg@jetpack/js-non-window/zones/zone(0x100496800)
+ │ ├───5,574,608 B (00.58%) -- {59c81df5-4b7a-477b-912d-4e0fdf64e5f2}
+ │ │ ├──5,529,280 B (00.57%) -- window-objects
+ │ │ │ ├──4,175,584 B (00.43%) ++ top(chrome://chatzilla/content/chatzilla.xul, id=4293)
+ │ │ │ └──1,353,696 B (00.14%) ++ top(chrome://chatzilla/content/output-window.html, id=4298)
+ │ │ └─────45,328 B (00.00%) ++ js-non-window/zones/zone(0x100496800)/compartment([System Principal], file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7B59c81df5-4b7a-477b-912d-4e0fdf64e5f2%7D/components/chatzilla-service.js)
+ │ └───1,872,144 B (00.19%) ++ treestyletab@piro.sakura.ne.jp/js-non-window/zones/zone(0x100496800)
+
+More things worth pointing out are as follows.
+
+- Some add-ons are identified by a name, such as Tree Style Tab.
+ Others are identified only by a hexadecimal identifier. You can look
+ in about:support to see which add-on a particular identifier belongs
+ to. For example, `59c81df5-4b7a-477b-912d-4e0fdf64e5f2` is
+ Chatzilla.
+- All JavaScript memory usage for an add-on is measured separately and
+ shown in this sub-tree.
+- For add-ons that use separate windows, such as Chatzilla, the memory
+ usage of those windows will show up in this sub-tree.
+- For add-ons that use XUL overlays, such as AdBlock Plus, the memory
+ usage of those overlays will not show up in this sub-tree; it will
+ instead be in the non-add-on sub-trees and won't be identifiable as
+ being caused by the add-on.
+
+#### Other Measurements
+
+This section contains multiple trees, includes many that cross-cut the
+measurements in the "explicit" tree. For example, in the "explicit"
+tree all DOM and layout measurements are broken down by window by
+window, but in "Other Measurements" those measurements are aggregated
+into totals for the whole browser, as the following example shows.
+
+ 26.77 MB (100.0%) -- window-objects
+ ├──14.59 MB (54.52%) -- layout
+ │ ├───6.22 MB (23.24%) ── style-sets
+ │ ├───4.00 MB (14.95%) ── pres-shell
+ │ ├───1.79 MB (06.68%) ── frames
+ │ ├───0.89 MB (03.33%) ── style-contexts
+ │ ├───0.62 MB (02.33%) ── rule-nodes
+ │ ├───0.56 MB (02.10%) ── pres-contexts
+ │ ├───0.47 MB (01.75%) ── line-boxes
+ │ └───0.04 MB (00.14%) ── text-runs
+ ├───6.53 MB (24.39%) ── style-sheets
+ ├───5.59 MB (20.89%) -- dom
+ │ ├──3.39 MB (12.66%) ── element-nodes
+ │ ├──1.56 MB (05.84%) ── text-nodes
+ │ ├──0.54 MB (02.03%) ── other
+ │ └──0.10 MB (00.36%) ++ (4 tiny)
+ └───0.06 MB (00.21%) ── property-tables
+
+Some of the trees in this section measure things that do not cross-cut
+the measurements in the "explicit" tree, such as those in the
+"preference-service" example above.
+
+Finally, at the end of this section are individual measurements, as the
+following example shows.
+
+ 0.00 MB ── canvas-2d-pixels
+ 5.38 MB ── gfx-surface-xlib
+ 0.00 MB ── gfx-textures
+ 0.00 MB ── gfx-tiles-waste
+ 0 ── ghost-windows
+ 109.22 MB ── heap-allocated
+ 164 ── heap-chunks
+ 1.00 MB ── heap-chunksize
+ 114.51 MB ── heap-committed
+ 164.00 MB ── heap-mapped
+ 4.84% ── heap-overhead-ratio
+ 1 ── host-object-urls
+ 0.00 MB ── imagelib-surface-cache
+ 5.27 MB ── js-main-runtime-temporary-peak
+ 0 ── page-faults-hard
+ 203,349 ── page-faults-soft
+ 274.99 MB ── resident
+ 251.47 MB ── resident-unique
+ 1,103.64 MB ── vsize
+
+Some measurements of note are as follows.
+
+- "resident". Physical memory usage. If you want a single
+ measurement to summarize memory usage, this is probably the best
+ one.
+- "vsize". Virtual memory usage. This is often much higher than any
+ other measurement (particularly on Mac). It only really matters on
+ 32-bit platforms such as Win32. There is also
+ "vsize-max-contiguous" (not measured on all platforms, and not
+ shown in this example), which indicates the largest single chunk of
+ available virtual address space. If this number is low, it's likely
+ that memory allocations will fail due to lack of virtual address
+ space quite soon.
+- Various graphics-related measurements ("gfx-*"). The measurements
+ taken vary between platforms. Graphics is often a source of high
+ memory usage, and so these measurements can be helpful for detecting
+ such cases.
diff --git a/docs/performance/memory/aggregate_view.md b/docs/performance/memory/aggregate_view.md
new file mode 100644
index 0000000000000..0781805a8b23e
--- /dev/null
+++ b/docs/performance/memory/aggregate_view.md
@@ -0,0 +1,201 @@
+# Aggregate view
+
+Before Firefox 48, this was the default view of a heap snapshot. After
+Firefox 48, the default view is the [Tree map
+view](tree_map_view.md), and you can switch to the
+Aggregate view using the dropdown labeled \"View:\":
+
+![](../img/memory-tool-switch-view.png)
+
+The Aggregate view looks something like this:
+
+![](../img/memory-tool-aggregate-view.png)
+
+It presents a breakdown of the heap\'s contents, as a table. There are
+three main ways to group the data:
+
+- Type
+- Call Stack
+- Inverted Call Stack
+
+You can switch between them using the dropdown menu labeled \"Group
+by:\" located at the top of the panel:
+
+There\'s also a box labeled \"Filter\" at the top-right of the pane. You
+can use this to filter the contents of the snapshot that are displayed,
+so you can quickly see, for example, how many objects of a specific
+class were allocated.
+
+## Type
+
+This is the default view, which looks something like this:
+
+![](../img/memory-tool-aggregate-view.png)
+
+It groups the things on the heap into types, including:
+
+- **JavaScript objects:** such as `Function` or `Array`
+- **DOM elements:** such as `HTMLSpanElement` or `Window`
+- **Strings:** listed as `"strings"`
+- **JavaScript sources:** listed as \"`JSScript"`
+- **Internal objects:** such as \"`js::Shape`\". These are prefixed
+ with `"js::"`.
+
+Each type gets a row in the table, and rows are ordered by the amount of
+memory occupied by objects of that type. For example, in the screenshot
+above you can see that JavaScript `Object`s account for most memory,
+followed by strings.
+
+- The \"Total Count\" column shows you the number of objects of each
+ category that are currently allocated.
+- The \"Total Bytes\" column shows you the number of bytes occupied by
+ objects in each category, and that number as a percentage of the
+ whole heap size for that tab.
+
+The screenshots in this section are taken from a snapshot of the
+[monster example page](monster_example.md).
+
+For example, in the screenshot above, you can see that:
+
+- there are four `Array` objects
+- that account for 15% of the total heap.
+
+Next to the type\'s name, there\'s an icon that contains three stars
+arranged in a triangle:
+
+![](../img/memory-tool-in-group-icon.png)
+
+Click this to see every instance of that type. For example, the entry
+for `Array` tells us that there are four `Array` objects in the
+snapshot. If we click the star-triangle, we\'ll see all four `Array`
+instances:
+
+![](../img/memory-tool-in-group.png)
+
+For each instance, you can see the [retained size and shallow
+size](dominators.html#shallow_and_retained_size) of
+that instance. In this case, you can see that the first three arrays
+have a fairly large shallow size (5% of the total heap usage) and a much
+larger retained size (26% of the total).
+
+On the right-hand side is a pane that just says \"Select an item to view
+its retaining paths\". If you select an item, you\'ll see the [Retaining
+paths
+panel](/dominators_view.html#retaining_paths_panel)
+for that item:
+
+![](../img/memory-tool-in-group-retaining-paths.png)
+
+
+
+
+## Call Stack
+
+The Call Stack shows you exactly where in your code you are making heap
+allocations.
+
+Because tracing allocations has a runtime cost, it must be explicitly
+enabled by checking \"Record call stacks\" *before* you allocate the
+memory in the snapshot.
+
+You\'ll then see a list of all the functions that allocated objects,
+ordered by the size of the allocations they made:
+
+![](../img/memory-tool-call-stack.png)
+\
+The structure of this view is very much like the structure of the [Call
+Tree](call_tree.md), only it shows
+allocations rather than processor samples. So, for example, the first
+entry says that:
+
+- 4,832,592 bytes, comprising 93% of the total heap usage, were
+ allocated in a function at line 35 of \"alloc.js\", **or in
+ functions called by that function**
+
+We can use the disclosure triangle to drill down the call tree, to find
+the exact place your code made those allocations.
+
+It\'s easier to explain this with reference to a simple example. For
+this we\'ll use the [DOM allocation
+example](DOM_allocation_example.md). This page
+runs a script that creates a large number of DOM nodes (200
+`HTMLDivElement` objects and 4000 `HTMLSpanElement` objects).
+
+Let\'s get an allocation trace:
+
+1. open the Memory tool
+2. check \"Record call stacks\"
+3. load
+
+4. take a snapshot
+5. select \"View/Aggregate\"
+6. select \"Group by/Call Stack\"
+
+
+
+You should see something like this:
+
+![](../img/memory-tool-call-stack.png)
+
+This is telling us that 93% of the total heap snapshot was allocated in
+functions called from \"alloc.js\", line 35 (our initial
+`createToolbars()` call).
+
+We can use the disclosure arrow to expand the tree to find out exactly
+where we\'re allocating memory:
+
+![](../img/memory-tool-call-stack-expanded.png)
+
+This is where the \"Bytes\" and \"Count\" columns are useful: they show
+allocation size and number of allocations at that exact point.
+
+So in the example above, we can see that we made 4002 allocations,
+accounting for 89% of the total heap, in `createToolbarButton()`, at
+[alloc.js line 9, position
+23](https://github.com/mdn/performance-scenarios/blob/gh-pages/dom-allocs/scripts/alloc.js#L9):
+that is, the exact point where we create the span
+elements.
+
+The file name and line number is a link: if we click it, we go directly
+to that line in the debugger:
+
+
+
+
+## Inverted Call Stack
+
+The Call Stack view is top-down: it shows allocations that happen at
+that point **or points deeper in the call tree**. So it\'s good for
+getting an overview of where your program is memory-hungry. However,
+this view means you have to drill a long way down to find the exact
+place where the allocations are happening.
+
+The \"Inverted Call Stack\" view helps with that. It gives you the
+bottom-up view of the program showing the exact places where allocations
+are happening, ranked by the size of allocation at each place. The
+disclosure arrow then walks you back up the call tree towards the top
+level.
+
+Let\'s see what the example looks like when we select \"Inverted Call
+Stack\":
+
+![](../img/memory-tool-inverted-call-stack.png)
+
+Now at the top we can immediately see the `createToolbarButton()` call
+accounting for 89% of the heap usage in our page.
+
+## no stack available
+
+In the example above you\'ll note that 7% of the heap is marked \"(no
+stack available)\". This is because not all heap usage results from your
+JavaScript.
+
+For example:
+
+- any scripts the page loads occupy heap space
+- sometimes an object is allocated when there is no JavaScript on the
+ stack. For example, DOM Event objects are allocated
+ before the JavaScript is run and event handlers are called.
+
+Many real-world pages will have a much higher \"(no stack available)\"
+share than 7%.
diff --git a/docs/performance/memory/awsy.md b/docs/performance/memory/awsy.md
new file mode 100644
index 0000000000000..8004575740d8b
--- /dev/null
+++ b/docs/performance/memory/awsy.md
@@ -0,0 +1,22 @@
+# Are We Slim Yet (AWSY)
+
+The Are We Slim Yet project (commonly known as AWSY) for several years
+tracked memory usage across builds on the (now defunct) website.
+It used the same
+infrastructure as
+[about:memory](about_colon_memory.md) to measure
+memory usage on a predefined snapshot of Alexa top 100 pages known as
+tp5.
+
+Since Firefox transitioned to using multiple processes by default, we
+[moved AWSY into the
+TaskCluster](https://bugzilla.mozilla.org/show_bug.cgi?id=1272113)
+infrastructure. This allowed us to run measurements on all branches and
+platforms. The results are posted to
+[perfherder](https://treeherder.mozilla.org/perf.html) where we can
+track regressions automatically.
+
+As new processes are added to Firefox we want to make sure their memory
+usage is also tracked by AWSY. To this end we request that memory
+reporting be integrated into any new process before it is enabled on
+Nightly.
diff --git a/docs/performance/memory/basic_operations.md b/docs/performance/memory/basic_operations.md
new file mode 100644
index 0000000000000..e0d597e194382
--- /dev/null
+++ b/docs/performance/memory/basic_operations.md
@@ -0,0 +1,82 @@
+# Basic operations
+
+## Opening the Memory tool
+
+Before Firefox 50, the Memory tool is not enabled by default. To enable
+it, open the developer tool settings, and check the "Memory" box under
+"Default Firefox Developer Tools":
+
+
+
+From Firefox 50 onwards, the Memory tool is enabled by default.
+
+## Taking a heap snapshot
+
+To take a snapshot of the heap, click the "Take snapshot" button, or
+the camera icon on the left:
+
+![memoryimage1](../img/memory-1-small.png)
+
+The snapshot will occupy the large pane on the right-hand side. On the
+left, you'll see an entry for the new snapshot, including its
+timestamp, size, and controls to save or clear this snapshot:
+
+![memoryimage2](../img/memory-2-small.png)
+
+## Clearing a snapshot
+
+To remove a snapshot, click the "X" icon:
+
+![memoryimage3](../img/memory-3-small.png)
+
+## Saving and loading snapshots
+
+If you close the Memory tool, all unsaved snapshots will be discarded.
+To save a snapshot click "Save":
+
+![memoryimage4](../img/memory-4-small.png)
+
+You'll be prompted for a name and location, and the file will be saved
+with an `.fxsnapshot` extension.
+
+To load a snapshot from an existing `.fxsnapshot` file, click the import
+button, which looks like a rectangle with an arrow rising from it
+(before Firefox 49, this button was labeled with the text
+"Import\...\"):
+
+![memoryimage5](../img/memory-5-small.png)
+
+You'll be prompted to find a snapshot file on disk.
+
+## Comparing snapshots
+
+Starting in Firefox 45, you can diff two heap snapshots. The diff shows
+you where memory was allocated or freed between the two snapshots.
+
+To create a diff, click the button that looks like a Venn diagram next
+to the camera icon (before Firefox 47, this looked like a \"+/-\" icon):
+
+![memoryimage6](../img/memory-6-small.png)
+
+You'll be prompted to select the snapshot to use as a baseline, then
+the snapshot to compare. The tool then shows you the differences between
+the two snapshots:
+
+
+
+
+::: {.note}
+When you're looking at a comparison, you can't use the Dominators view
+or the Tree Map view.
+:::
+
+## Recording call stacks
+
+The Memory tool can tell you exactly where in your code you are
+allocating memory. However, recording this information has a run-time
+cost, so you must ask the tool to record memory calls *before* the
+memory is allocated, if you want to see memory call sites in the
+snapshot. To do this, check "Record call stacks" (before Firefox 49
+this was labeled "Record allocation stacks"):
+
+![memoryimage7](../img/memory-7-small.png)
diff --git a/docs/performance/memory/bloatview.md b/docs/performance/memory/bloatview.md
new file mode 100644
index 0000000000000..7d965dd9baf97
--- /dev/null
+++ b/docs/performance/memory/bloatview.md
@@ -0,0 +1,245 @@
+# Bloatview
+
+BloatView is a tool that shows information about cumulative memory usage
+and leaks. If it finds leaks, you can use [refcount tracing and balancing](refcount_tracing_and_balancing.md)
+to discover the root cause.
+
+## How to build with BloatView
+
+Build with `--enable-debug` or `--enable-logrefcnt`.
+
+## How to run with BloatView
+
+The are two environment variables that can be used.
+
+ XPCOM_MEM_BLOAT_LOG
+
+If set, this causes a *bloat log* to be printed on program exit, and
+each time `nsTraceRefcnt::DumpStatistics` is called. This log contains
+data on leaks and bloat (a.k.a. usage).
+
+ XPCOM_MEM_LEAK_LOG
+
+This is similar to `XPCOM_MEM_BLOAT_LOG`, but restricts the log to only
+show data on leaks.
+
+You can set these environment variables to any of the following values.
+
+- **1** - log to stdout.
+- **2** - log to stderr.
+- ***filename*** - write log to a file.
+
+## Reading individual bloat logs
+
+Full BloatView output contains per-class statistics on allocations and
+refcounts, and provides gross numbers on the amount of memory being
+leaked broken down by class. Here\'s a sample of the BloatView output.
+
+ == BloatView: ALL (cumulative) LEAK AND BLOAT STATISTICS, tab process 1862
+ |<----------------Class--------------->|<-----Bytes------>|<----Objects---->|
+ | | Per-Inst Leaked| Total Rem|
+ 0 |TOTAL | 17 2484|253953338 38|
+ 17 |AsyncTransactionTrackersHolder | 40 40| 10594 1|
+ 78 |CompositorChild | 472 472| 1 1|
+ 79 |CondVar | 24 48| 3086 2|
+ 279 |MessagePump | 8 8| 30 1|
+ 285 |Mutex | 20 60| 89987 3|
+ 302 |PCompositorChild | 412 412| 1 1|
+ 308 |PImageBridgeChild | 416 416| 1 1|
+
+The first line tells you the pid of the leaking process, along with the
+type of process.
+
+Here's how you interpret the columns.
+
+- The first, numerical column [is theindex](https://searchfox.org/mozilla-central/source/xpcom/base/nsTraceRefcnt.cpp#365)
+ of the leaking class.
+- **Class** - The name of the class in question (truncated to 20
+ characters).
+- **Bytes Per-Inst** - The number of bytes returned if you were to
+ write `sizeof(Class)`. Note that this number does not reflect any
+ memory held onto by the class, such as internal buffers, etc. (E.g.
+ for `nsString` you\'ll see the size of the header struct, not the
+ size of the string contents!)
+- **Bytes Leaked** - The number of bytes per instance times the number
+ of objects leaked: (Bytes Per-Inst) x (Objects Rem). Use this number
+ to look for the worst offenders. (Should be zero!)
+- **Objects Total** - The total count of objects allocated of a given
+ class.
+- **Objects Rem** - The number of objects allocated of a given class
+ that weren't deleted. (Should be zero!)
+
+Interesting things to look for:
+
+- **Are your classes in the list?** - Look! If they aren't, then
+ you're not using the `NS_IMPL_ADDREF` and `NS_IMPL_RELEASE` (or
+ `NS_IMPL_ISUPPORTS` which calls them) for xpcom objects, or
+ `MOZ_COUNT_CTOR` and `MOZ_COUNT_DTOR` for non-xpcom objects. Not
+ having your classes in the list is *not* ok. That means no one is
+ looking at them, and we won't be able to tell if someone introduces
+ a leak. (See
+ [How_to_instrument_your_objects_for_BloatView](bloatview.html#how-to-instrument-your-objects-for-bloatview)
+ for how to fix this.)
+- **The Bytes Leaked for your classes should be zero!** - Need I say
+ more? If it isn't, you should use the other tools to fix it.
+- **The number of objects remaining might not be equal to the total
+ number of objects.** This could indicate a hand-written Release
+ method (that doesn't use the `NS_LOG_RELEASE` macro from
+ nsTraceRefcnt.h), or perhaps you\'re just not freeing any of the
+ instances you've allocated. These sorts of leaks are easy to fix.
+- **The total number of objects might be 1.** This might indicate a
+ global variable or service. Usually this will have a large number of
+ refcounts.
+
+If you find leaks, you can use [refcount tracing and balancing](refcount_tracing_and_balancing.md)
+to discover the root cause.
+
+## Combining and sorting bloat logs
+
+You can view one or more bloat logs in your browser by running the
+following program.
+
+ perl tools/bloatview/bloattable.pl *log1* *log2* \... *logn* \>
+ *htmlfile*
+
+This will produce an HTML file that contains a table similar to the
+following (but with added JavaScript so you can sort the data by
+column).
+
+ Byte Bloats
+
+ ---------- ---------------- --------------------------
+ Name File Date
+ blank `blank.txt` Tue Aug 29 14:17:40 2000
+ mozilla `mozilla.txt` Tue Aug 29 14:18:42 2000
+ yahoo `yahoo.txt` Tue Aug 29 14:19:32 2000
+ netscape `netscape.txt` Tue Aug 29 14:20:14 2000
+ ---------- ---------------- --------------------------
+
+The numbers do not include malloc d data such as string contents.
+
+Click on a column heading to sort by that column. Click on a class name
+to see details for that class.
+
+ -------------------- --------------- ----------------- --------- --------- ---------- ---------- ------------------------------- --------- -------- ---------- ---------
+ Class Name Instance Size Bytes allocated Bytes allocated but not freed
+ blank mozilla yahoo netscape Total blank mozilla yahoo netscape Total
+ TOTAL 1754408 432556 179828 404184 2770976
+ nsStr 20 6261600 3781900 1120920 1791340 12955760 222760 48760 13280 76160 360960
+ nsHashKey 8 610568 1842400 2457872 1134592 6045432 32000 536 568 1216 34320
+ nsTextTransformer 548 8220 469088 1414936 1532756 3425000 0 0 0 0 0
+ nsStyleContextData 736 259808 325312 489440 338560 1413120 141312 220800 -11040 94944 446016
+ nsLineLayout 1100 2200 225500 402600 562100 1192400 0 0 0 0 0
+ nsLocalFile 424 558832 19928 1696 1272 581728 72080 1272 424 -424 73352
+ -------------------- --------------- ----------------- --------- --------- ---------- ---------- ------------------------------- --------- -------- ---------- ---------
+
+The first set of columns, **Bytes allocated**, shows the amount of
+memory allocated for the first log file (`blank.txt`), the difference
+between the first log file and the second (`mozilla.txt`), the
+difference between the second log file and the third (`yahoo.txt`), the
+difference between the third log file and the fourth (`netscape.txt`),
+and the total amount of memory allocated in the fourth log file. These
+columns provide an idea of how hard the memory allocator has to work,
+but they do not indicate the size of the working set.
+
+The second set of columns, **Bytes allocated but not freed**, shows the
+net memory gain or loss by subtracting the amount of memory freed from
+the amount allocated.
+
+The **Show Objects** and **Show References** buttons show the same
+statistics but counting objects or `AddRef`\'d references rather than
+bytes.
+
+## Comparing Bloat Logs
+
+You can also compare any two bloat logs (either those produced when the
+program shuts down, or written to the bloatlogs directory) by running
+the following program.
+
+ `perl tools/bloatview/bloatdiff.pl` \ \
+
+This will give you output of the form:
+
+ Bloat/Leak Delta Report
+ Current file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-22-133450.txt
+ Previous file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-16-010302.txt
+ --------------------------------------------------------------------------
+ CLASS LEAKS delta BLOAT delta
+ --------------------------------------------------------------------------
+ TOTAL 6113530 2.79% 67064808 9.18%
+ StyleContextImpl 265440 81.19% 283584 -26.99%
+ CToken 236500 17.32% 306676 20.64%
+ nsStr 217760 14.94% 5817060 7.63%
+ nsXULAttribute 113048 -70.92% 113568 -71.16%
+ LiteralImpl 53280 26.62% 75840 19.40%
+ nsXULElement 51648 0.00% 51648 0.00%
+ nsProfile 51224 0.00% 51224 0.00%
+ nsFrame 47568 -26.15% 48096 -50.49%
+ CSSDeclarationImpl 42984 0.67% 43488 0.67%
+
+This "delta report" shows the leak offenders, sorted from most leaks
+to fewest. The delta numbers show the percentage change between runs for
+the amount of leaks and amount of bloat (negative numbers are better!).
+The bloat number is a metric determined by multiplying the total number
+of objects allocated of a given class by the class size. Note that
+although this isn\'t necessarily the amount of memory consumed at any
+given time, it does give an indication of how much memory we\'re
+consuming. The more memory in general, the worse the performance and
+footprint. The percentage 99999.99% will show up indicating an
+"infinite" amount of leakage. This happens when something that didn't
+leak before is now leaking.
+
+## BloatView and continuous integration
+
+BloatView runs on debug builds for many of the test suites Mozilla has
+running under continuous integration. If a new leak occurs, it will
+trigger a test job failure.
+
+BloatView's output file can also show you where the leaked objects are
+allocated. To do so, the `XPCOM_MEM_LOG_CLASSES` environment variable
+should be set to the name of the class from the BloatView table:
+
+ XPCOM_MEM_LOG_CLASSES=MyClass mach mochitest [options]
+
+Multiple class names can be specified by setting `XPCOM_MEM_LOG_CLASSES`
+to a comma-separated list of names:
+
+ XPCOM_MEM_LOG_CLASSES=MyClass,MyOtherClass,DeliberatelyLeakedClass mach mochitest [options]
+
+Test harness scripts typically accept a `--setenv` option for specifying
+environment variables, which may be more convenient in some cases:
+
+ mach mochitest --setenv=XPCOM_MEM_LOG_CLASSES=MyClass [options]
+
+For getting allocation stacks in automation, you can add the appropriate
+`--setenv` options to the test configurations for the platforms you\'re
+interested in. Those configurations are located in
+`testing/mozharness/configs/`. The most likely configs you\'ll want to
+modify are listed below:
+
+- Linux: `unittests/linux_unittest.py`
+- Mac: `unittests/mac_unittest.py`
+- Windows: `unittests/win_unittest.py`
+- Android: `android/androidarm_4_3.py`
+
+## How to instrument your objects for BloatView
+
+First, if your object is an xpcom object and you use the
+`NS_IMPL_ADDREF` and `NS_IMPL_RELEASE` (or a variation thereof) macro to
+implement your `AddRef` and `Release` methods, then there is nothing you
+need do. By default, those macros support refcnt logging directly.
+
+If your object is not an xpcom object then some manual editing is in
+order. The following sample code shows what must be done:
+
+ MyType::MyType()
+ {
+ MOZ_COUNT_CTOR(MyType);
+ ...
+ }
+
+ MyType::~MyType()
+ {
+ MOZ_COUNT_DTOR(MyType);
+ ...
+ }
diff --git a/docs/performance/memory/dmd.md b/docs/performance/memory/dmd.md
new file mode 100644
index 0000000000000..a2b2f303397b1
--- /dev/null
+++ b/docs/performance/memory/dmd.md
@@ -0,0 +1,528 @@
+# DMD
+
+DMD (short for "dark matter detector") is a heap profiler within
+Firefox. It has four modes.
+
+- "Dark Matter" mode. In this mode, DMD tracks the contents of the
+ heap, including which heap blocks have been reported by memory
+ reporters. It helps us reduce the "heap-unclassified" value in
+ Firefox's about:memory page, and also detects if any heap blocks
+ are reported twice. Originally, this was the only mode that DMD had,
+ which explains DMD's name. This is the default mode.
+- "Live" mode. In this mode, DMD tracks the current contents of the
+ heap. You can dump that information to file, giving a profile of the
+ live heap blocks at that point in time. This is good for
+ understanding how memory is used at an interesting point in time,
+ such as peak memory usage.
+- "Cumulative" mode. In this mode, DMD tracks both the past and
+ current contents of the heap. You can dump that information to file,
+ giving a profile of the heap usage for the entire session. This is
+ good for finding parts of the code that cause high heap churn, e.g.
+ by allocating many short-lived allocations.
+- "Heap scanning" mode. This mode is like live mode, but it also
+ records the contents of every live block in the log. This can be
+ used to investigate leaks by figuring out which objects might be
+ holding references to other objects.
+
+## Building and Running
+
+### Nightly Firefox
+
+The easiest way to use DMD is with the normal Nightly Firefox build,
+which has DMD already enabled in the build. To have DMD active while
+running it, you just need to set the environment variable `DMD=1` when
+running. For instance, on OSX, you can run something like:
+
+ DMD=1 /Applications/Firefox\ Nightly.app/Contents/MacOS/firefox
+
+You can tell it is working by going to about:memory and looking for
+"Save DMD Output". If DMD has been properly enabled, the "Save"
+button won't be grayed out. Look at the "Trigger" section below to
+see the full list of ways to get a DMD report once you have it
+activated. Note that stack information you get will likely be less
+detailed, due to being unable to symbolicate. You will be able to get
+function names, but not line numbers.
+
+### Desktop Firefox (Linux)
+
+#### Build
+
+Build Firefox with these options:
+
+ ac_add_options --enable-dmd
+
+If building via try server, modify
+`browser/config/mozconfigs/linux64/common-opt` or a similar file before
+pushing.
+
+#### Launch
+
+Use `mach run --dmd`; use `--mode` to choose the mode. Add `--debug` to
+run under gdb.
+
+#### Trigger
+
+There are three ways to trigger a DMD snapshot.
+
+1. Visit about:memory and click the DMD button (depending on how old
+ your build is, it might be labelled "Save" or "Analyze reports"
+ or "DMD"). The button won't be present in non-DMD builds, and
+ will be grayed out in DMD builds if DMD isn't enabled at start-up.
+
+2. If you wish to trigger DMD dumps from within C++ or JavaScript code,
+ you can use `nsIMemoryInfoDumper.dumpMemoryToTempDir`. For example,
+ from JavaScript code you can do the following.
+
+ const Cc = Components.classes;
+ let mydumper = Cc["@mozilla.org/memory-info-dumper;1"]
+ .getService(Ci.nsIMemoryInfoDumper);
+ mydumper.dumpMemoryInfoToTempDir(identifier, anonymize, minimize);
+
+ This will dump memory reports and DMD output to the temporary
+ directory. `identifier` is a string that will be used for part of
+ the filename (or a timestamp will be used if it is an empty string);
+ `anonymize` is a boolean that indicates if the memory reports should
+ be anonymized; and `minimize` is a boolean that indicates if memory
+ usage should be minimized first.
+
+3. (Linux only) You can send signal 34 to the firefox process, e.g.
+ with the following command.
+
+ $ killall -34 firefox
+
+Each one of these steps triggers all the memory reporters and then DMD
+analyzes the reports, printing commentary like this:
+
+ DMD[5222] opened /tmp/dmd-1414556492-5222.json.gz for writing
+ DMD[5222] Dump 1 {
+ DMD[5222] Constructing the heap block list...
+ DMD[5222] Constructing the stack trace table...
+ DMD[5222] Constructing the stack frame table...
+ DMD[5222] }
+
+In an e10s-enabled build, you'll see separate output for each process.
+This step can take 10 or more seconds and may make Firefox freeze
+temporarily.
+
+If you see the "opened" line, it tells you where the file was saved.
+It's always in a temp directory, and the filenames are always of the
+form dmd-.
+
+### Desktop Firefox (Mac)
+
+#### Build
+
+Build with these options:
+
+ ac_add_options --enable-dmd
+
+If building via try server, modify
+`browser/config/mozconfigs/macosx64/common-opt` or a similar file before
+pushing.
+
+#### Launch
+
+Use `mach run --dmd; `use `--mode` to choose the mode. Add `--debug` to
+run under lldb.
+
+#### Trigger
+
+Follow the [Trigger instructions for Linux](#Trigger_7). Note that on
+Mac this step can take 30+ seconds.
+
+### Desktop Firefox (Windows)
+
+#### Build
+
+Build with these options:
+
+ ac_add_options --enable-dmd
+
+If building via try server, modify
+`browser/config/mozconfigs/win32/common-opt`. Also, add this line to
+`build/mozconfig.common`:
+
+ MOZ_CRASHREPORTER_UPLOAD_FULL_SYMBOLS=1
+
+#### Launch
+
+On a local build, use `mach run --dmd`; use `--mode` to choose the mode.
+
+On a build done by the try server, follow [these
+instructions](https://bugzilla.mozilla.org/show_bug.cgi?id=936784#c69){.external
+.text} instead.
+
+#### Trigger
+
+Follow the [Trigger instructions for Linux]
+
+### Fennec
+
+::: {.note}
+In order to use DMD on Fennec you will need root access on the Android
+device. Instructions on how to root your device is outside the scope of
+this document.
+:::
+
+#### Build
+
+Build with these options:
+
+ ac_add_options --enable-dmd
+
+#### Prep
+
+In order to prepare your device for running Fennec with DMD enabled, you
+will need to do a few things. First, you will need to push the libdmd.so
+library to the device so that it can by dynamically loaded by Fennec.
+You can do this by running:
+
+ adb push $OBJDIR/dist/bin/libdmd.so /sdcard/
+
+Second, you will need to make an executable wrapper for Fennec which
+sets an environment variable before launching it. (If you are familiar
+with the recommended "--es env0" method for setting environment
+variables when launching Fennec, note that you cannot use this method
+here because those are processed too late in the startup process. If you
+are not familiar with that method, you can ignore this parenthetical
+note.) First make the executable wrapper on your host machine using the
+editor of your choice. Name the file dmd_fennec and enter this as the
+contents:
+
+ #!/system/bin/sh
+ export MOZ_REPLACE_MALLOC_LIB=/sdcard/libdmd.so
+ exec "$@"
+
+If you want to use other DMD options, you can enter additional
+environment variables above. You will need to push this to the device
+and make it executable. Since you cannot mark files in /sdcard/ as
+executable, we will use /data/local/tmp for this purpose:
+
+ adb push dmd_fennec /data/local/tmp
+ adb shell
+ cd /data/local/tmp
+ chmod 755 dmd_fennec
+
+The final step is to make Android use the above wrapper script while
+launching Fennec, so that the environment variable is present when
+Fennec starts up. Assuming you have done a local build, the app
+identifier will be `org.mozilla.fennec_$USERNAME` (`$USERNAME` is your
+username on the host machine) and so we do this as shown below. If you
+are using a DMD-enabled try build, or build from other source, adjust
+the app identifier as necessary.
+
+ adb shell
+ su # You need root access for the setprop command to take effect
+ setprop wrap.org.mozilla.fennec_$USERNAME "/data/local/tmp/dmd_fennec"
+
+Once this is set up, starting the `org.mozilla.fennec_$USERNAME` app
+will use the wrapper script.
+
+#### Launch
+
+Launch Fennec either by tapping on the icon as usual, or from the
+command line (as before, be sure to replace
+`org.mozilla.fennec_$USERNAME` with the app identifier as appropriate).
+
+ adb shell am start -n org.mozilla.fennec_$USERNAME/.App
+
+#### Trigger
+
+Use the existing memory-report dumping hook:
+
+ adb shell am broadcast -a org.mozilla.gecko.MEMORY_DUMP
+
+In logcat, you should see output similar to this:
+
+ I/DMD (20731): opened /storage/emulated/0/Download/memory-reports/dmd-default-20731.json.gz for writing
+ ...
+ I/GeckoConsole(20731): nsIMemoryInfoDumper dumped reports to /storage/emulated/0/Download/memory-reports/unified-memory-report-default-20731.json.gz
+
+The path is where the memory reports and DMD reports get dumped to. You
+can pull them like so:
+
+ adb pull /sdcard/Download/memory-reports/dmd-default-20731.json.gz
+ adb pull /sdcard/Download/memory-reports/unified-memory-report-default-20731.json.gz
+
+## Processing the output
+
+DMD outputs one gzipped JSON file per process that contains a
+description of that process's heap. You can analyze these files (either
+gzipped or not) using `dmd.py`. On Nightly Firefox, `dmd.py` is included
+in the distribution. For instance on OS X, it is located in the
+directory `/Applications/Firefox Nightly.app/Contents/Resources/`. For
+Nightly, symbolication will fail, but you can at least get some
+information. In a local build, `dmd.py` will be located in the directory
+`$OBJDIR/dist/bin/`.
+
+Some platforms (Linux, Mac, Android) require stack fixing, which adds
+missing filename, function name and line number information. This will
+occur automatically the first time you run `dmd.py` on the output file.
+This can take 10s of seconds or more to complete. (This will fail if
+your build does not contain symbols. However, if you have crash reporter
+symbols for your build -- as tryserver builds do -- you can use [this
+script](https://github.com/mstange/analyze-tryserver-profiles/blob/master/resymbolicate_dmd.py)
+instead: clone the whole repo, edit the paths at the top of
+`resymbolicate_dmd.py` and run it.) The simplest way to do this is to
+just run the `dmd.py` script on your DMD report while your working
+directory is `$OBJDIR/dist/bin`. This will allow the local libraries to
+be found and used.
+
+If you invoke `dmd.py` without arguments you will get output appropriate
+for the mode in which DMD was invoked.
+
+### "Dark matter" mode output
+
+For "dark matter" mode, `dmd.py`'s output describes how the live heap
+blocks are covered by memory reports. This output is broken into
+multiple sections.
+
+1. "Invocation". This tells you how DMD was invoked, i.e. what
+ options were used.
+2. "Twice-reported stack trace records". This tells you which heap
+ blocks were reported twice or more. The presence of any such records
+ indicates bugs in one or more memory reporters.
+3. "Unreported stack trace records". This tells you which heap blocks
+ were not reported, which indicate where additional memory reporters
+ would be most helpful.
+4. "Once-reported stack trace records": like the "Unreported stack
+ trace records" section, but for blocks reported once.
+5. "Summary": gives measurements of the total heap, and the
+ unreported/once-reported/twice-reported portions of it.
+
+The "Twice-reported stack trace records" and "Unreported stack trace
+records" sections are the most important, because they indicate ways in
+which the memory reporters can be improved.
+
+Here's an example stack trace record from the "Unreported stack trace
+records" section.
+
+ Unreported {
+ 150 blocks in heap block record 283 of 5,495
+ 21,600 bytes (20,400 requested / 1,200 slop)
+ Individual block sizes: 144 x 150
+ 0.00% of the heap (16.85% cumulative)
+ 0.02% of unreported (94.68% cumulative)
+ Allocated at {
+ #01: replace_malloc (/home/njn/moz/mi5/go64dmd/memory/replace/dmd/../../../../memory/replace/dmd/DMD.cpp:1286)
+ #02: malloc (/home/njn/moz/mi5/go64dmd/memory/build/../../../memory/build/replace_malloc.c:153)
+ #03: moz_xmalloc (/home/njn/moz/mi5/memory/mozalloc/mozalloc.cpp:84)
+ #04: nsCycleCollectingAutoRefCnt::incr(void*, nsCycleCollectionParticipant*) (/home/njn/moz/mi5/go64dmd/dom/xul/../../dist/include/nsISupportsImpl.h:250)
+ #05: nsXULElement::Create(nsXULPrototypeElement*, nsIDocument*, bool, bool,mozilla::dom::Element**) (/home/njn/moz/mi5/dom/xul/nsXULElement.cpp:287)
+ #06: nsXBLContentSink::CreateElement(char16_t const**, unsigned int, mozilla::dom::NodeInfo*, unsigned int, nsIContent**, bool*, mozilla::dom::FromParser) (/home/njn/moz/mi5/dom/xbl/nsXBLContentSink.cpp:874)
+ #07: nsCOMPtr::StartAssignment() (/home/njn/moz/mi5/go64dmd/dom/xml/../../dist/include/nsCOMPtr.h:753)
+ #08: nsXMLContentSink::HandleStartElement(char16_t const*, char16_t const**, unsigned int, unsigned int, bool) (/home/njn/moz/mi5/dom/xml/nsXMLContentSink.cpp:1007)
+ }
+ }
+
+It tells you that there were 150 heap blocks that were allocated from
+the program point indicated by the "Allocated at" stack trace, that
+these blocks took up 21,600 bytes, that all 150 blocks had a size of 144
+bytes, and that 1,200 of those bytes were "slop" (wasted space caused
+by the heap allocator rounding up request sizes). It also indicates what
+percentage of the total heap size and the unreported portion of the heap
+these blocks represent.
+
+Within each section, records are listed from largest to smallest.
+
+Once-reported and twice-reported stack trace records also have stack
+traces for the report point(s). For example:
+
+ Reported at {
+ #01: mozilla::dmd::Report(void const*) (/home/njn/moz/mi2/memory/replace/dmd/DMD.cpp:1740) 0x7f68652581ca
+ #02: CycleCollectorMallocSizeOf(void const*) (/home/njn/moz/mi2/xpcom/base/nsCycleCollector.cpp:3008) 0x7f6860fdfe02
+ #03: nsPurpleBuffer::SizeOfExcludingThis(unsigned long (*)(void const*)) const (/home/njn/moz/mi2/xpcom/base/nsCycleCollector.cpp:933) 0x7f6860fdb7af
+ #04: nsCycleCollector::SizeOfIncludingThis(unsigned long (*)(void const*), unsigned long*, unsigned long*, unsigned long*, unsigned long*, unsigned long*) const (/home/njn/moz/mi2/xpcom/base/nsCycleCollector.cpp:3029) 0x7f6860fdb6b1
+ #05: CycleCollectorMultiReporter::CollectReports(nsIMemoryMultiReporterCallback*, nsISupports*) (/home/njn/moz/mi2/xpcom/base/nsCycleCollector.cpp:3075) 0x7f6860fde432
+ #06: nsMemoryInfoDumper::DumpMemoryReportsToFileImpl(nsAString_internal const&) (/home/njn/moz/mi2/xpcom/base/nsMemoryInfoDumper.cpp:626) 0x7f6860fece79
+ #07: nsMemoryInfoDumper::DumpMemoryReportsToFile(nsAString_internal const&, bool, bool) (/home/njn/moz/mi2/xpcom/base/nsMemoryInfoDumper.cpp:344) 0x7f6860febaf9
+ #08: mozilla::(anonymous namespace)::DumpMemoryReportsRunnable::Run() (/home/njn/moz/mi2/xpcom/base/nsMemoryInfoDumper.cpp:58) 0x7f6860fefe03
+ }
+
+You can tell which memory reporter made the report by the name of the
+`MallocSizeOf` function near the top of the stack trace. In this case it
+was the cycle collector's reporter.
+
+By default, DMD does not record an allocation stack trace for most
+blocks, to make it run faster. The decision on whether to record is done
+probabilistically, and larger blocks are more likely to have an
+allocation stack trace recorded. All unreported blocks that lack an
+allocation stack trace will end up in a single record. For example:
+
+ Unreported {
+ 420,010 blocks in heap block record 2 of 5,495
+ 29,203,408 bytes (27,777,288 requested / 1,426,120 slop)
+ Individual block sizes: 2,048 x 3; 1,024 x 103; 512 x 147; 496 x 7; 480 x 31; 464 x 6; 448 x 50; 432 x 41; 416 x 28; 400 x 53; 384 x 43; 368 x 216; 352 x 141; 336 x 58; 320 x 104; 304 x 5,130; 288 x 150; 272 x 591; 256 x 6,017; 240 x 1,372; 224 x 93; 208 x 488; 192 x 1,919; 176 x 18,903; 160 x 1,754; 144 x 5,041; 128 x 36,709; 112 x 5,571; 96 x 6,280; 80 x 40,738; 64 x 37,925; 48 x 78,392; 32 x 136,199; 16 x 31,001; 8 x 4,706
+ 3.78% of the heap (10.24% cumulative)
+ 21.24% of unreported (57.53% cumulative)
+ Allocated at {
+ #01: (no stack trace recorded due to --stacks=partial)
+ }
+ }
+
+In contrast, stack traces are always recorded when a block is reported,
+which means you can end up with records like this where the allocation
+point is unknown but the reporting point *is* known:
+
+ Once-reported {
+ 104,491 blocks in heap block record 13 of 4,689
+ 10,392,000 bytes (10,392,000 requested / 0 slop)
+ Individual block sizes: 512 x 124; 256 x 242; 192 x 813; 128 x 54,664; 64 x 48,648
+ 1.35% of the heap (48.65% cumulative)
+ 1.64% of once-reported (59.18% cumulative)
+ Allocated at {
+ #01: (no stack trace recorded due to --stacks=partial)
+ }
+ Reported at {
+ #01: mozilla::dmd::DMDFuncs::Report(void const*) (/home/njn/moz/mi5/go64dmd/memory/replace/dmd/../../../../memory/replace/dmd/DMD.cpp:1646)
+ #02: WindowsMallocSizeOf(void const*) (/home/njn/moz/mi5/dom/base/nsWindowMemoryReporter.cpp:189)
+ #03: nsAttrAndChildArray::SizeOfExcludingThis(unsigned long (*)(void const*)) const (/home/njn/moz/mi5/dom/base/nsAttrAndChildArray.cpp:880)
+ #04: mozilla::dom::FragmentOrElement::SizeOfExcludingThis(unsigned long (*)(void const*)) const (/home/njn/moz/mi5/dom/base/FragmentOrElement.cpp:2337)
+ #05: nsINode::SizeOfIncludingThis(unsigned long (*)(void const*)) const (/home/njn/moz/mi5/go64dmd/parser/html/../../../dom/base/nsINode.h:307)
+ #06: mozilla::dom::NodeInfo::NodeType() const (/home/njn/moz/mi5/go64dmd/dom/base/../../dist/include/mozilla/dom/NodeInfo.h:127)
+ #07: nsHTMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes*) const (/home/njn/moz/mi5/dom/html/nsHTMLDocument.cpp:3710)
+ #08: nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes*) const (/home/njn/moz/mi5/dom/base/nsDocument.cpp:12820)
+ }
+ }
+
+The choice of whether to record an allocation stack trace for all blocks
+is controlled by an option (see below).
+
+### "Live" mode output
+
+
+For "live" mode, dmd.py's output describes what live heap blocks are
+present. This output is broken into multiple sections.
+
+1. "Invocation". This tells you how DMD was invoked, i.e. what
+ options were used.
+2. "Live stack trace records". This tells you which heap blocks were
+ present.
+3. "Summary": gives measurements of the total heap.
+
+The individual records are similar to those output in "dark matter"
+mode.
+
+### "Cumulative" mode output
+
+For "cumulative" mode, dmd.py's output describes how the live heap
+blocks are covered by memory reports. This output is broken into
+multiple sections.
+
+1. "Invocation". This tells you how DMD was invoked, i.e. what
+ options were used.
+2. "Cumulative stack trace records". This tells you which heap blocks
+ were allocated during the session.
+3. "Summary": gives measurements of the total (cumulative) heap.
+
+The individual records are similar to those output in "dark matter"
+mode.
+
+### "Scan" mode output
+
+For "scan" mode, the output of `dmd.py` is the same as "live" mode.
+A separate script, `block_analyzer.py`, can be used to find out
+information about which blocks refer to a particular block.
+`dmd.py --clamp-contents` needs to be run on the log first. See [this
+other page](heap_scan_mode.md) for an
+overview of how to use heap scan mode to fix a leak involving refcounted
+objects.
+
+## Options
+
+### Runtime
+
+When you run `mach run --dmd` you can specify additional options to
+control how DMD runs. Run `mach help run` for documentation on these.
+
+The most interesting one is `--mode`. Acceptable values are
+`dark-matter` (the default), `live`, `cumulative`, and `scan`.
+
+Another interesting one is `--stacks`. Acceptable values are `partial`
+(the default) and `full`. In the former case most blocks will not have
+an allocation stack trace recorded. However, because larger blocks are
+more likely to have one recorded, most allocated bytes should have an
+allocation stack trace even though most allocated blocks do not. Use
+`--stacks=full` if you want complete information, but note that DMD will
+run substantially slower in that case.
+
+The options may also be put in the environment variable DMD, or set DMD
+to 1 to enable DMD with default options (dark-matter and partial
+stacks).
+
+The `MOZ_DMD_SHUTDOWN_LOG` environment variable, if set, triggers a DMD
+run at shutdown; its value must be a directory where the logs will be
+placed. Which processes get logged is controlled by the
+`MOZ_DMD_LOG_PROCESS` environment variable, which can take the following
+values.
+
+- Unset: log all processes.
+- "`default`": log the parent process only.
+- "`tab`": log content processes only.
+
+For example, if you have
+
+ MOZ_DMD_SHUTDOWN_LOG=~/dmdlogs/ MOZ_DMD_LOG_PROCESS=tab
+
+then DMD logs for content processes will be saved to `~/dmdlogs/`.
+
+**NOTE:**
+
+- To dump DMD data from Content processes, you'll need to disable the
+ sandbox
+- MOZ_DMD_SHUTDOWN_LOG must (currently) include the trailing separator
+ (\'\'/\")
+
+### Post-processing
+
+`dmd.py` also takes options that control how it works. Run `dmd.py -h`
+for documentation. The following options are the most interesting ones.
+
+- `-f` / `--max-frames`. By default, records show up to 8 stack
+ frames. You can choose a smaller number, in which case more
+ allocations will be aggregated into each record, but you'll have
+ less context. Or you can choose a larger number, in which cases
+ allocations will be split across more records, but you will have
+ more context. There is no single best value, but values in the range
+ 2..10 are often good. The maximum is 24.
+
+- `-a` / `--ignore-alloc-frames`. Many allocation stack traces start
+ with multiple frames that mention allocation wrapper functions, e.g.
+ `js_calloc()` calls `replace_calloc()`. This option filters these
+ out. It often helps improve the quality of the output when using a
+ small `--max-frames` value.
+
+- `-s` / `--sort-by`. This controls how records are sorted. Acceptable
+ values are `usable` (the default), `req`, `slop` and `num-blocks`.
+
+- `--clamp-contents`. For a heap scan log, this performs a
+ conservative pointer analysis on the contents of each block,
+ changing any value that is a pointer into the middle of a live block
+ into a pointer to the start of that block. All other values are
+ changes to null. In addition, all trailing nulls are removed from
+ the block contents.
+
+As an example that combines multiple options, if you apply the following
+command to a profile obtained in "live" mode:
+
+ dmd.py -r -f 2 -a -s slop
+
+it will give you a good idea of where the major sources of slop are.
+
+`dmd.py` can also compute the difference between two DMD output files,
+so long as those files were produced in the same mode. Simply pass it
+two filenames instead of one to get the difference.
+
+## Which heap blocks are reported?
+
+At this stage you might wonder how DMD knows, in "dark matter" mode,
+which allocations have been reported and which haven't. DMD only knows
+about heap blocks that are measured via a function created with one of
+the following two macros:
+
+ MOZ_DEFINE_MALLOC_SIZE_OF
+ MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
+
+Fortunately, most of the existing memory reporters do this. See
+[Performance/Memory_Reporting](https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Memory_reporting "Platform/Memory Reporting")
+for more details about how memory reporters are written.
diff --git a/docs/performance/memory/dominators.md b/docs/performance/memory/dominators.md
new file mode 100644
index 0000000000000..afee88d1a2634
--- /dev/null
+++ b/docs/performance/memory/dominators.md
@@ -0,0 +1,90 @@
+# Dominators
+
+This article provides an introduction to the concepts of *Reachability*,
+*Shallow* versus *Retained* size, and *Dominators*, as they apply in
+garbage-collected languages like JavaScript.
+
+These concepts matter in memory analysis, because often an object may
+itself be small, but may hold references to other much larger objects,
+and by doing this will prevent the garbage collector from freeing that
+extra memory.
+
+You can see the dominators in a page using the [Dominators
+view](dominators_view.md) in the Memory tool.
+
+With a garbage-collected language, like JavaScript, the programmer
+doesn\'t generally have to worry about deallocating memory. They can
+just create and use objects, and when the objects are no longer needed,
+the runtime takes care of cleaning up, and frees the memory the objects
+occupied.
+
+## Reachability
+
+In modern JavaScript implementations, the runtime decides whether an
+object is no longer needed based on *reachability*. In this system the
+heap is represented as one or more graphs. Each node in the graph
+represents an object, and each connection between nodes (edge)
+represents a reference from one object to another. The graph starts at a
+root node, indicated in these diagrams with \"R\".
+
+![](../img/memory-graph.svg)
+
+During garbage collection, the runtime traverses the graph, starting at
+the root, and marks every object it finds. Any objects it doesn\'t find
+are unreachable, and can be deallocated.
+
+So when an object becomes unreachable (for example, because it is only
+referenced by a single local variable which goes out of scope) then any
+objects it references also become unreachable, as long as no other
+objects reference them:
+
+![](../img/memory-graph-unreachable.svg)
+
+Conversely, this means that objects are kept alive as long as some other
+reachable object is holding a reference to them.
+
+## Shallow and retained size
+
+This gives rise to a distinction between two ways to look at the size of
+an object:
+
+- *shallow size*: the size of the object itself
+- *retained size*: the size of the object itself, plus the size of
+ other objects that are kept alive by this object
+
+Often, objects will have a small shallow size but a much larger retained
+size, through the references they contain to other objects. Retained
+size is an important concept in analyzing memory usage, because it
+answers the question \"if this object ceases to exist, what\'s the total
+amount of memory freed?\".
+
+## Dominators
+
+A related concept is that of the *dominator*. Node B is said to dominate
+node A if every path from the root to A passes through B:
+
+![](../img/memory-graph-dominators.svg)
+
+If any of node A\'s dominators are freed, then node A itself becomes
+eligible for garbage collection.
+
+[If node B dominates node A, but does not dominate any of A\'s other
+dominators, then B is the *immediate dominator* of
+A:]
+
+![](../img/memory-graph-immediate-dominator.svg)
+
+[One slight subtlety here is that if an object A is referenced by two
+other objects B and C, then neither object is its
+dominator], because you could remove either B or C from
+the graph, and A would still be retained by its other referrer. Instead,
+the immediate dominator of A would be its first common ancestor:\
+![](../img/memory-graph-dominator-multiple-references.svg)
+
+## See also
+
+[Dominators in graph
+theory](https://en.wikipedia.org/wiki/Dominator_%28graph_theory%29).
+
+[Tracing garbage
+collection](https://en.wikipedia.org/wiki/Tracing_garbage_collection).
diff --git a/docs/performance/memory/dominators_view.md b/docs/performance/memory/dominators_view.md
new file mode 100644
index 0000000000000..8ed57280efdce
--- /dev/null
+++ b/docs/performance/memory/dominators_view.md
@@ -0,0 +1,221 @@
+# Dominators view
+
+The Dominators view is new in Firefox 46.
+
+Starting in Firefox 46, the Memory tool includes a new view called the
+Dominators view. This is useful for understanding the \"retained size\"
+of objects allocated by your site: that is, the size of the objects
+themselves plus the size of the objects that they keep alive through
+references.
+
+If you already know what shallow size, retained size, and dominators
+are, skip to the Dominators UI section. Otherwise, you might want to
+review the article on [Dominators
+concepts](dominators.md).
+
+## Dominators UI
+
+To see the Dominators view for a snapshot, select \"Dominators\" in the
+\"View\" drop-down list. It looks something like this:
+
+![](../img/dominators-1.png)
+
+The Dominators view consists of two panels:
+
+- the [Dominators Tree
+ panel](dominators_view.html#dominators_tree_panel)
+ shows you which nodes in the snapshot are retaining the most memory
+- the [Retaining Paths
+ panel](dominators_view.html#retaining_paths_panel)
+ (new in Firefox 47) shows the 5 shortest retaining paths for a
+ single node.
+
+![](../img/dominators-2.png)
+
+### Dominators Tree panel {#Dominators_Tree_panel}
+
+The Dominators Tree tells you which objects in the snapshot are
+retaining the most memory.
+
+In the main part of the UI, the first row is labeled \"GC Roots\".
+Immediately underneath that is an entry for:
+
+- Every GC root node. In Gecko, there is more than one memory graph,
+ and therefore more than one root. There may be many (often
+ temporary) roots. For example: variables allocated on the stack need
+ to be rooted, or internal caches may need to root their elements.
+- Any other node that\'s referenced from two different roots (since in
+ this case, neither root dominates it).
+
+Each entry displays:
+
+- the retained size of the node, as bytes and as a percentage of the
+ total
+- the shallow size of the node, as bytes and as a percentage of the
+ total
+- the nodes\'s name and address in memory.
+
+Entries are ordered by the amount of memory that they retain. For
+example:
+
+![](../img/dominators-3.png)
+
+In this screenshot we can see five entries under \"GC Roots\". The first
+two are Call and Window objects, and retain about 21% and 8% of the
+total size of the memory snapshot, respectively. You can also see that
+these objects have a relatively tiny \"Shallow Size\", so almost all of
+the retained size is in the objects that they dominate.
+
+Immediately under each GC root, you\'ll see all the nodes for which this
+root is the [immediate
+dominator](/dominators.html#immediate_dominator).
+These nodes are also ordered by their retained size.
+
+For example, if we click on the first Window object:
+
+![](../img/dominators-4.png)
+
+We can see that this Window dominates a CSS2Properties object, whose
+retained size is 2% of the total snapshot size. Again the shallow size
+is very small: almost all of its retained size is in the nodes that it
+dominates. By clicking on the disclosure arrow next to the Function, we
+can see those nodes.
+
+In this way you can quickly get a sense of which objects retain the most
+memory in the snapshot.
+
+You can use [Alt]{.kbd} + click to expand the whole graph under a node.
+
+#### Call Stack {#Call_Stack}
+
+In the toolbar at the top of the tool is a dropdown called \"Label by\":
+
+![](../img/dominators-5.png)
+
+By default, this is set to \"Type\". However, you can set it instead to
+\"Call Stack\" to see exactly where in your code the objects are being
+allocated.
+
+::: {.note}
+This option is called \"Allocation Stack\" in Firefox 46.
+:::
+
+To enable this, you must check the box labeled \"Record call stacks\"
+*before* you run the code that allocates the objects. Then take a
+snapshot, then select \"Call Stack\" in the \"Label by\" drop-down.
+
+Now the node\'s name will contain the name of the function that
+allocated it, and the file, line number and character position of the
+exact spot where the function allocated it. Clicking the file name will
+take you to that spot in the Debugger.
+
+
+
+:::
+Sometimes you\'ll see \"(no stack available)\" here. In particular,
+allocation stacks are currently only recorded for objects, not for
+arrays, strings, or internal structures.
+:::
+
+### Retaining Paths panel {#Retaining_Paths_panel}
+
+::: {.geckoVersionNote}
+The Retaining Paths panel is new in Firefox 47.
+:::
+
+The Retaining Paths panel shows you, for a given node, the 5 shortest
+paths back from this node to a GC root. This enables you to see all the
+nodes that are keeping the given node from being garbage-collected. If
+you suspect that an object is being leaked, this will show you exactly
+which objects are holding a reference to it.
+
+To see the retaining paths for a node, you have to select the node in
+the Dominators Tree panel:
+
+![](../img/dominators-6.png)
+
+Here, we\'ve selected an object, and can see a single path back to a GC
+root.
+
+The `Window` GC root holds a reference to an `HTMLDivElement` object,
+and that holds a reference to an `Object`, and so on. If you look in the
+Dominators Tree panel, you can trace the same path there. If either of
+these references were removed, the items below them could be
+garbage-collected.
+
+Each connection in the graph is labeled with the variable name for the
+referenced object.
+
+Sometimes there\'s more than one retaining path back from a node:
+
+![](../img/dominators-7.png)
+
+Here there are three paths back from the `DocumentPrototype` node to a
+GC root. If one were removed, then the `DocumentPrototype` would still
+not be garbage-collected, because it\'s still retained by the other two
+path.
+
+## Example {#Example}
+
+Let\'s see how some simple code is reflected in the Dominators view.
+
+We\'ll use the [monster allocation
+example](monster_example.md), which creates three
+arrays, each containing 5000 monsters, each monster having a
+randomly-generated name.
+
+### Taking a snapshot
+
+To see what it looks like in the Dominators view:
+
+- load the page
+- enable the Memory tool in the
+ [Settings](https://developer.mozilla.org/en-US/docs/Tools/Tools_Toolbox#settings), if you
+ haven\'t already
+- open the Memory tool
+- check \"Record call stacks\"
+- press the button labeled \"Make monsters!\"
+- take a snapshot
+- switch to the \"Dominators\" view
+
+
+
+### Analyzing the Dominators Tree
+
+You\'ll see the three arrays as the top three GC roots, each retaining
+about 23% of the total memory usage:
+
+![](../img/dominators-8.png)
+
+If you expand an array, you\'ll see the objects (monsters) it contains.
+Each monster has a relatively small shallow size of 160 bytes. This
+includes the integer eye- and tentacle-counts. Each monster has a bigger
+retained size, which is accounted for by the string used for the
+monster\'s name:
+
+![](../img/dominators-9.png)
+
+All this maps closely to the [memory graph we were expecting to
+see](/monster_example.html#allocation-graph). One
+thing you might be wondering, though, is: where\'s the top-level object
+that retains all three arrays? If we look at the Retaining Paths panel
+for one of the arrays, we\'ll see it:
+
+![](../img/dominators-10.png)
+
+Here we can see the retaining object, and even that this particular
+array is the array of `fierce` monsters. But the array is also rooted
+directly, so if the object were to stop referencing the array, it would
+still not be eligible for garbage collection.
+
+This means that the object does not dominate the array, and is therefore
+not shown in the Dominators Tree view. [See the relevant section of the
+Dominators concepts
+article](dominators.html#multiple-paths).
+
+### Using the Call Stack view {#Using_the_Call_Stack_view}
+
+Finally, you can switch to the Call Stack view, see where the objects
+are being allocated, and jump to that point in the Debugger:
+
+
diff --git a/docs/performance/memory/gc_and_cc_logs.md b/docs/performance/memory/gc_and_cc_logs.md
new file mode 100644
index 0000000000000..8d909e05b27ab
--- /dev/null
+++ b/docs/performance/memory/gc_and_cc_logs.md
@@ -0,0 +1,112 @@
+## GC and CC logs
+
+Garbage collector (GC) and cycle collector (CC) logs give information
+about why various JS and C++ objects are alive in the heap. Garbage
+collector logs and cycle collector logs can be analyzed in various ways.
+In particular, CC logs can be used to understand why the cycle collector
+is keeping an object alive. These logs can either be manually or
+automatically generated, and they can be generated in both debug and
+non-debug builds.
+
+This logs the contents of the Javascript heap to a file named
+`gc-edges-NNNN.log`. It also creates a file named `cc-edges-NNNN.log` to
+which it dumps the parts of the heap visible to the cycle collector,
+which includes native C++ objects that participate in cycle collection,
+as well as JS objects being held alive by those C++ objects.
+
+## Generating logs
+
+### From within Firefox
+
+To manually generate GC and CC logs, navigate to `about:memory` and use
+the buttons under \"Save GC & CC logs.\" \"Save concise\" will generate
+a smaller CC log, \"Save verbose\" will provide a more detailed CC log.
+(The GC log will be the same size in either case.)
+
+With multiprocess Firefox, you can't record logs from the content
+process, due to sandboxing. You'll need to disable sandboxing by
+setting `MOZ_DISABLE_CONTENT_SANDBOX=t` when you run Firefox.
+
+### From the commandline
+
+TLDR: if you just want shutdown GC/CC logs to debug leaks that happen in
+our automated tests, you probably want something along the lines of:
+
+ MOZ_DISABLE_CONTENT_SANDBOX=t MOZ_CC_LOG_DIRECTORY=/full/path/to/log/directory/ MOZ_CC_LOG_SHUTDOWN=1 MOZ_CC_ALL_TRACES=shutdown ./mach ...
+
+As noted in the previous section, with multiprocess Firefox, you can't
+record logs from the content process, due to sandboxing. You'll need to
+disable sandboxing by setting `MOZ_DISABLE_CONTENT_SANDBOX=t` when you
+run Firefox.
+
+On desktop Firefox you can override the default location of the log
+files by setting the `MOZ_CC_LOG_DIRECTORY` environment variable. By
+default, they go to a temporary directory which differs per OS - it's
+`/tmp/` on Linux/BSD, `$LOCALAPPDATA\Temp\` on Windows, and somewhere in
+`/var/folders/` on Mac (whatever the directory service returns for
+`TmpD`/`NS_OS_TEMP_DIR`). Note that just `MOZ_CC_LOG_DIRECTORY=.` won't
+work - you need to specify a full path. On Firefox for Android you can
+use the cc-dump.xpi
+extension to save the files to `/sdcard`. By default, the file is
+created in some temp directory, and the path to the file is printed to
+the Error Console.
+
+To log every cycle collection, set the `MOZ_CC_LOG_ALL` environment
+variable. To log only shutdown collections, set `MOZ_CC_LOG_SHUTDOWN`.
+To make all CCs verbose, set `MOZ_CC_ALL_TRACES to "all`\", or to
+\"`shutdown`\" to make only shutdown CCs verbose.
+
+Live GC logging can be enabled with the pref
+`javascript.options.mem.log`. Output to a file can be controlled with
+the MOZ_GCTIMER environment variable. See the [Statistics
+API](https://developer.mozilla.org/en-US/docs/Tools/Tools_Toolbox#settings/en-US/docs/SpiderMonkey/Internals/GC/Statistics_API) page for
+details on values.
+
+Set the environment variable `MOZ_CC_LOG_THREAD` to `main` to only log
+main thread CCs, or to `worker` to only log worker CCs. The default
+value is `all`, which will log all CCs.
+
+To get cycle collector logs on Try server, set `MOZ_CC_LOG_DIRECTORY` to
+`MOZ_UPLOAD_DIR`, then set the other variables appropriately to generate
+CC logs. The way to set environment variables depends on the test
+harness, or you can modify the code in nsCycleCollector to set that
+directly. To find the CC logs once the try run has finished, click on
+the particular job, then click on \"Job Details\" in the bottom pane in
+TreeHerder, and you should see download links.
+
+To set the environment variable, find the `buildBrowserEnv` method in
+the Python file for the test suite you are interested in, and add
+something like this code to the file:
+
+ browserEnv["MOZ_CC_LOG_DIRECTORY"] = os.environ["MOZ_UPLOAD_DIR"]
+ browserEnv["MOZ_CC_LOG_SHUTDOWN"] = "1"
+
+## Analyzing GC and CC logs
+
+There are numerous scripts that analyze GC and CC logs on
+[GitHub](https://github.com/amccreight/heapgraph/tree/master/cc)
+
+
+To find out why an object is being kept alive, the relevant scripts are
+`find_roots.py` and `parse_cc_graph.py` (which is called by
+`find_roots.py`). Calling `find_roots.py` on a CC log with a specific
+object or kind of object will produce paths from rooting objects to the
+specified objects. Most big leaks include an `nsGlobalWindow`, so
+that's a good class to try if you don't have any better idea.
+
+To fix a leak, the next step is to figure out why the rooting object is
+alive. For a C++ object, you need to figure out where the missing
+references are from. For a JS object, you need to figure out why the JS
+object is reachable from a JS root. For the latter, you can use the
+corresponding [`find_roots.py` for
+JS](https://github.com/amccreight/heapgraph/tree/master/g)
+on the GC log.
+
+## Alternatives
+
+There are two add-ons that can be used to create and analyze CC graphs.
+
+- [about:cc](https://bugzilla.mozilla.org/show_bug.cgi?id=726346)
+ is simple, ugly, but rather powerful.
+- [about:ccdump](https://addons.mozilla.org/en-US/firefox/addon/cycle-collector-analyzer/?src=ss)
+ is prettier but a bit slower.
diff --git a/docs/performance/memory/heap_scan_mode.md b/docs/performance/memory/heap_scan_mode.md
new file mode 100644
index 0000000000000..331290478fa98
--- /dev/null
+++ b/docs/performance/memory/heap_scan_mode.md
@@ -0,0 +1,309 @@
+# DMD heap scan mode
+
+Firefox's DMD heap scan mode tracks the set of all live blocks of
+malloc-allocated memory and their allocation stacks, and allows you to
+log these blocks, and the values stored in them, to a file. When
+combined with cycle collector logging, this can be used to investigate
+leaks of refcounted cycle collected objects, by figuring out what holds
+a strong reference to a leaked object.
+
+**When should you use this?** DMD heap scan mode is intended to be used
+to investigate leaks of cycle collected (CCed) objects. DMD heap scan
+mode is a "tool of last resort" that should only be used when all
+other avenues have been tried and failed, except possibly [ref count
+logging](refcount_tracing_and_balancing.md).
+It is particularly useful if you have no idea what is causing the leak.
+If you have a patch that introduces a leak, you are probably better off
+auditing all of the strong references that your patch creates before
+trying this.
+
+The particular steps given below are intended for the case where the
+leaked object is alive all the way through shutdown. You could modify
+these steps for leaks that go away in shutdown by collecting a CC and
+DMD log prior to shutdown. However, in that case it may be easier to use
+refcount logging, or rr with a conditional breakpoint set on calls to
+`Release()` for the leaking object, to see what object actually does the
+release that causes the leaked object to go away.
+
+## Prerequisites
+
+- A debug DMD build of Firefox. [This
+ page](dmd.md)
+ describes how to do that. This should probably be an optimized
+ build. Non-optimized DMD builds will generate better stack traces,
+ but they can be so slow as to be useless.
+- The build is going to be very slow, so you may need to disable some
+ shutdown checks. First, in
+ `toolkit/components/terminator/nsTerminator.cpp`, delete everything
+ in `RunWatchDog` but the call to `NS_SetCurrentThreadName`. This
+ will keep the watch dog from killing the browser when shut down
+ takes multiple minutes. Secondly, you may need to comment out the
+ call to `MOZ_CRASH("NSS_Shutdown failed");` in
+ `xpcom/build/XPCOMInit.cpp`, as this also seems to trigger when
+ shutdown is extremely slow.
+- You need the cycle collector analysis script `find_roots.py`, which
+ can be downloaded as part of [this repo on
+ Github](https://github.com/amccreight/heapgraph).
+
+## Generating Logs
+
+The next step is to generate a number of log files. You need to get a
+shutdown CC log and a DMD log, for a single run.
+
+**Definitions** I'll write `$objdir` for the object directory for your
+Firefox DMD build, `$srcdir` for the top level of the Firefox source
+directory, and `$heapgraph` for the location of the heapgraph repo, and
+`$logdir` for the location you want logs to go to. `$logdir` should end
+in a path separator. For instance, `~/logs/leak/`.
+
+The command you need to run Firefox will look something like this:
+
+ XPCOM_MEM_BLOAT_LOG=1 MOZ_CC_LOG_SHUTDOWN=1 MOZ_DISABLE_CONTENT_SANDBOX=t MOZ_CC_LOG_DIRECTORY=$logdir
+ MOZ_CC_LOG_PROCESS=content MOZ_CC_LOG_THREAD=main MOZ_DMD_SHUTDOWN_LOG=$logdir MOZ_DMD_LOG_PROCESS=tab ./mach run --dmd --mode=scan
+
+Breaking this down:
+
+- `XPCOM_MEM_BLOAT_LOG=1`: This reports a list of the counts of every
+ object created and destroyed and tracked by the XPCOM leak tracking
+ system. From this chart, you can see how many objects of a
+ particular type were leaked through shutdown. This can come in handy
+ during the manual analysis phase later, to get evidence to support
+ your hunches. For instance, if you think that an `nsFoo` object
+ might be holding your leaking object alive, you can use this to
+ easily see if we leaked an `nsFoo` object.
+- `MOZ_CC_LOG_SHUTDOWN=1`: This generates a cycle collector log during
+ shutdown. Creating this log during shutdown is nice because there
+ are less things unrelated to the leak in the log, and various cycle
+ collector optimizations are disabled. A garbage collector log will
+ also be created, which you may not need.
+- `MOZ_DISABLE_CONTENT_SANDBOX=t`: This disables the content process
+ sandbox, which is needed because the DMD and CC log files are
+ created directly by the child processes.
+- `MOZ_CC_LOG_DIRECTORY=$logdir`: This selects the location for cycle
+ collector logs to be saved.
+- `MOZ_CC_LOG_PROCESS=content MOZ_CC_LOG_THREAD=main`: These options
+ specify that we only want CC logs for the main thread of content
+ processes, to make shutdown less slow. If your leak is happening in
+ a different process or thread, change the options, which are listed
+ in `xpcom/base/nsCycleCollector.cpp`.
+- `MOZ_DMD_SHUTDOWN_LOG=$logdir`: This option specifies that we want a
+ DMD log to be taken very late in XPCOM shutdown, and the location
+ for that log to be saved. Like with the CC log, we want this log
+ very late to avoid as many non-leaking things as possible.
+- `MOZ_DMD_LOG_PROCESS=tab`: As with the CC, this means that we only
+ want these logs in content processes, in order to make shutdown
+ faster. The allowed values here are the same as those returned by
+ `XRE_GetProcessType()`, so adjust as needed.
+- Finally, the `--dmd` option need to be passed in so that DMD will be
+ run. `--mode=scan` is needed so that when we get a DMD log the
+ entire contents of each block of memory is saved for later analysis.
+
+With that command line in hand, you can start Firefox. Be aware that
+this may take multiple minutes if you have optimization disabled.
+
+Once it has started, go through the steps you need to reproduce your
+leak. If your leak is a ghost window, it can be handy to get an
+`about:memory` report and write down the PID of the leaking process. You
+may want to wait 10 or so seconds after this to make sure as much as
+possible is cleaned up.
+
+Next, exit the browser. This will cause a lot of logs to be written out,
+so it can take a while.
+
+## Analyzing the Logs
+
+##### Getting the PID and address of the leaking object
+
+The first step is to figure out the **PID** of the leaking process. The
+second step is to figure out **the address of the leaking object**,
+usually a window. Conveniently, you can usually do both at once using
+the cycle collector log. If you are investigating a leak of
+`www.example.com`, then from `$logdir` you can do
+`"grep nsGlobalWindow cc-edges* | grep example.com"`. This looks through
+all of the windows in all of the CC logs (which may leaked, this late in
+shutdown), and then filters out windows where the URL contains
+`example.com`.
+
+The result of that grep will contain output that looks something like
+this:
+
+ cc-edges.15873.log:0x7f0897082c00 [rc=1285] nsGlobalWindowInner # 2147483662 inner https://www.example.com/
+
+cc-edges.15873.log: The first part is the file name where it was
+found. `15873` is the PID of the process that leaked. You'll want to
+write down the name of the file and the PID. Let's call the file
+`$cclog` and the pid `$pid`.
+
+0x7f0897082c00: This is the address of the leaking window. You'll
+also want to write that down. Let's call this `$winaddr`.
+
+If there are multiple files, you'll end up with one that looks like
+`cc-edges.$pid.log` and one or more that look like
+`cc-edges.$pid-$n.log` for various values of `$n`. You want the one with
+the largest `$n`, as this was recorded the latest, and so it will
+contain the least non-garbage.
+
+##### Identifying the root in the cycle collector log
+
+The next step is to figure out why the cycle collector could not collect
+the window, using the `find_roots.py` script from the heapgraph
+repository. The command to invoke this looks like this:
+
+ python $heapgraph/find_roots.py $cclog $winaddr
+
+This may take a few seconds. It will eventually produce some output.
+You'll want to save a copy of this output for later.
+
+The output will look something like this, after a message about loading
+progress:
+
+ 0x7f0882fe3230 [FragmentOrElement (xhtml) script https://www.example.com]
+ --[[via hash] mListenerManager]--> 0x7f0899b4e550 [EventListenerManager]
+ --[mListeners event=onload listenerType=3 [i]]--> 0x7f0882ff8f80 [CallbackObject]
+ --[mIncumbentGlobal]--> 0x7f0897082c00 [nsGlobalWindowInner # 2147483662 inner https://www.example.com]
+
+Root 0x7f0882fe3230 is a ref counted object with 1 unknown edge(s).
+ known edges:
+ 0x7f08975a24c0 [FragmentOrElement (xhtml) head https://www.example.com] --[mAttrsAndChildren[i]]--> 0x7f0882fe3230
+ 0x7f08967e7b20 [JS Object (HTMLScriptElement)] --[UnwrapDOMObject(obj)]--> 0x7f0882fe3230
+
+The first two lines mean that the script element `0x7f0882fe3230`
+contains a strong reference to the EventListenerManager
+`0x7f0899b4e550`. "[via hash] mListenerManager" is a description of
+that strong reference. Together, these lines show a chain of strong
+references from an object the cycle collector thinks needs to be kept
+alive, `0x7f0899b4e550`, to the object` 0x7f0897082c00` that you asked
+about. Most of the time, the actual chain is not important, because the
+cycle collector can only tell us about what went right. Let us call the
+address of the leaking object (`0x7f0882fe3230` in this case)
+`$leakaddr`.
+
+Besides `$leakaddr`, the other interesting part is the chunk at the
+bottom. It tells us that there is 1 unknown edge, and 2 known edges.
+What this means is that the leaking object has a refcount of 3, but the
+cycle collector was only told about these two references. In this case,
+a head element and a JS object (the JS reflector of the script element).
+We need to figure out what the unknown reference is from, as that is
+where our leak really is.
+
+##### Figure out what is holding the leaking object alive.
+
+Now we need to use the DMD heap scan logs. These contain the contents of
+every live block of memory.
+
+The first step to using the DMD heap scan logs is to do some
+pre-processing for the DMD log. Stacks need to be symbolicated, and we
+need to clamp the values contained in the heap. Clamping is the same
+kind of analysis that a conservative GC does: if a word-aligned value in
+a heap block points to somewhere within another heap block, replace that
+value with the address of the block.
+
+Both kinds of preprocessing are done by the `dmd.py` script, which can
+be invoked like this:
+
+ $objdir/dist/bin/dmd.py --clamp-contents dmd-$pid.log.gz
+
+This can take a few minutes due to symbolification, but you only need to
+run it once on a log file.
+
+After that is done, we can finally find out which objects (possibly)
+point to other objects, using the block_analyzer script:
+
+ python $srcdir/memory/replace/dmd/block_analyzer.py dmd-$pid.log.gz $leakaddr
+
+This will look through every block of memory in the log, and give some
+basic information about any block of memory that (possibly) contains a
+pointer to that object. You can pass some additional options to affect
+how the results are displayed. "-sfl 10000 -a" is useful. The -sfl 10000
+tells it to not truncate stack frames, and -a tells it to not display
+generic frames related to the allocator.
+
+Caveat: I think block_analyzer.py does not attempt to clamp the address
+you pass into it, so if it is an offset from the start of the block, it
+won't find it.
+
+ block_analyzer.py` will return a series of entries that look like this
+ with the [...] indicating where I have removed things):
+ 0x7f089306b000 size = 4096 bytes at byte offset 2168
+ nsAttrAndChildArray::GrowBy[...]
+ nsAttrAndChildArray::InsertChildAt[...]
+ [...]
+
+`0x7f089306b000` is the address of the block that contains `$leakaddr`.
+144 bytes is the size of that block. That can be useful for confirming
+your guess about what class the block actually is. The byte offset tells
+you were in the block the pointer is. This is mostly useful for larger
+objects, and you can potentially combine this with debugging information
+to figure out exactly what field this is. The rest of the entry is the
+stack trace for the allocation of the block, which is the most useful
+piece of information.
+
+What you need to do now is to go through every one of these entries and
+place it into three categories: strong reference known to the cycle
+collector, weak reference, or something else! The goal is to eventually
+shrink down the "something else" category until there are only as many
+things in it as there are unknown references to the leaking object, and
+then you have your leaker.
+
+To place an entry into one of the categories, you must look at the code
+locations given in the stack trace, and see if you can tell what the
+object is based on that, then compare that to what `find_roots.py` told
+you.
+
+For instance, one of the strong references in the CC log is from a head
+element to its child via `mAttrsAndChildren`, and that sounds a lot like
+this, so we can mark it as being a strong known reference.
+
+This is an iterative process, where you first go through and mark off
+the things that are easily categorizable, and repeat until you have a
+small list of things to analyze.
+
+##### Example analysis of block_analyzer.py results
+
+In one debugging session where I was investigating the leak from bug
+1451985, I eventually reduced the list of entries until this was the
+most suspicious looking entry:
+
+ 0x7f0892f29630 size = 392 bytes at byte offset 56
+ mozilla::dom::ScriptLoader::ProcessExternalScript[...]
+ [...]
+
+I went to that line of `ScriptLoader::ProcessExternalScript()`, and it
+contained a call to ScriptLoader::CreateLoadRequest(). Fortunately, this
+method mostly just contains two calls to `new`, one for
+`ScriptLoadRequest` and one for `ModuleLoadRequest`. (This is where an
+unoptimized build comes in handy, as it would have pointed out the exact
+line. Unfortunately, in this particular case, the unoptimized build was
+so slow I wasn't getting any logs.) I then looked through the list of
+leaked objects generated by `XPCOM_MEM_BLOAT_LOG` and saw that we were
+leaking a `ScriptLoadRequest`, so I went and looked at its class
+definition, where I noticed that `ScriptLoadRequest` had a strong
+reference to an element that it wasn't telling the cycle collector
+about, which seemed suspicious.
+
+The first thing I did to try to confirm that this was the source of the
+leak was pass the address of this object into the cycle collector
+analysis log, `find_roots.py`, that we used at an earlier step. That
+gave a result that contained this:
+
+ 0x7f0882fe3230 [FragmentOrElement (xhtml) script [...]
+ --[mNodeInfo]--> 0x7f0897431f00 [NodeInfo (xhtml) script]
+ [...]
+ --[mLoadingAsyncRequests]--> 0x7f0892f29630 [ScriptLoadRequest]
+
+This confirms that this block is actually a ScriptLoadRequest. Secondly,
+notice that the load request is being held alive by the very same script
+element that is causing the window leak! This strongly suggests that
+there is a cycle of strong references between the script element and the
+load request. I then added the missing field to the traverse and unlink
+methods of ScriptLoadRequest, and confirmed that I couldn't reproduce
+the leak.
+
+Keep in mind that you may need to run `block_analyzer.py` multiple
+times. For instance, if the script element was being held alive by some
+container being held alive by a runnable, we'd first need to figure out
+that the container was holding the element. If it isn't possible to
+figure out what is holding that alive, you'd have to run block_analyzer
+again. This isn't too bad, because unlike ref count logging, we have the
+full state of memory in our existing log, so we don't need to run the
+browser again.
diff --git a/docs/performance/memory/leak_gauge.md b/docs/performance/memory/leak_gauge.md
new file mode 100644
index 0000000000000..153303549eb26
--- /dev/null
+++ b/docs/performance/memory/leak_gauge.md
@@ -0,0 +1,45 @@
+# Leak Gauge
+
+Leak Gauge is a tool that can be used to detect certain kinds of leaks
+in Gecko, including those involving documents, window objects, and
+docshells. It has two parts: instrumentation in Gecko that produces a
+log file, and a script to post-process the log file.
+
+## Getting a log file
+
+To get a log file, run the browser with these settings:
+
+ NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
+ NSPR_LOG_FILE=nspr.log # or any other filename of your choice
+
+This overwrites any existing file named `nspr.log`. The browser runs
+with a negligible slowdown. For reliable results, exit the browser
+before post-processing the log file.
+
+## Post-processing the log file
+
+Post-process the log file with
+[tools/leak-gauge/leak-gauge.pl](https://searchfox.org/mozilla-central/source/tools/leak-gauge/leak-gauge.html)
+
+If there are no leaks, the output looks like this:
+
+ Results of processing log leak.log :
+ Summary:
+ Leaked 0 out of 11 DOM Windows
+ Leaked 0 out of 44 documents
+ Leaked 0 out of 3 docshells
+ Leaked content nodes in 0 out of 0 documents
+
+If there are leaks, the output looks like this:
+
+ Results of processing log leak2.log :
+ Leaked outer window 2c6e410 at address 2c6e410.
+ Leaked outer window 2c6ead0 at address 2c6ead0.
+ Leaked inner window 2c6ec80 (outer 2c6ead0) at address 2c6ec80.
+ Summary:
+ Leaked 13 out of 15 DOM Windows
+ Leaked 35 out of 46 documents
+ Leaked 4 out of 4 docshells
+ Leaked content nodes in 42 out of 53 documents
+
+If you find leaks, please file a bug report.
diff --git a/docs/performance/memory/leak_hunting_strategies_and_tips.md b/docs/performance/memory/leak_hunting_strategies_and_tips.md
new file mode 100644
index 0000000000000..549c406d85791
--- /dev/null
+++ b/docs/performance/memory/leak_hunting_strategies_and_tips.md
@@ -0,0 +1,218 @@
+This document is old and some of the information is out-of-date. Use
+with caution.
+
+## Strategy for finding leaks
+
+When trying to make a particular testcase not leak, I recommend focusing
+first on the largest object graphs (since these entrain many smaller
+objects), then on smaller reference-counted object graphs, and then on
+any remaining individual objects or small object graphs that don't
+entrain other objects.
+
+Because (1) large graphs of leaked objects tend to include some objects
+pointed to by global variables that confuse GC-based leak detectors,
+which can make leaks look smaller (as in [bug
+99180](https://bugzilla.mozilla.org/show_bug.cgi?id=99180){.external
+.text}) or hide them completely and (2) large graphs of leaked objects
+tend to hide smaller ones, it's much better to go after the large
+graphs of leaks first.
+
+A good general pattern for finding and fixing leaks is to start with a
+task that you want not to leak (for example, reading email). Start
+finding and fixing leaks by running part of the task under nsTraceRefcnt
+logging, gradually building up from as little as possible to the
+complete task, and fixing most of the leaks in the first steps before
+adding additional steps. (By most of the leaks, I mean the leaks of
+large numbers of different types of objects or leaks of objects that are
+known to entrain many non-logged objects such as JS objects. Seeing a
+leaked `GlobalWindowImpl`, `nsXULPDGlobalObject`,
+`nsXBLDocGlobalObject`, or `nsXPCWrappedJS` is a sign that there could
+be significant numbers of JS objects leaked.)
+
+For example, start with bringing up the mail window and closing the
+window without doing anything. Then go on to selecting a folder, then
+selecting a message, and then other activities one does while reading
+mail.
+
+Once you've done this, and it doesn't leak much, then try the action
+under trace-malloc or LSAN or Valgrind to find the leaks of smaller
+graphs of objects. (When I refer to the size of a graph of objects, I'm
+referring to the number of objects, not the size in bytes. Leaking many
+copies of a string could be a very large leak, but the object graphs are
+small and easy to identify using GC-based leak detection.)
+
+## What leak tools do we have?
+
+ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------------------------------------------------- ---------------------- -------------------------------------------------------
+ Tool Finds Platforms Requires
+ Leak tools for large object graphs
+ [Leak Gauge](leak_gauge.md) Windows, documents, and docshells only All platforms Any build
+ [GC and CC logs](GC_and_CC_logs.md) JS objects, DOM objects, many other kinds of objects All platforms Any build
+ Leak tools for medium-size object graphs
+ [BloatView](bloatview.md), [refcount tracing and balancing](refcount_tracing_and_balancing.md) Objects that implement `nsISupports` or use `MOZ_COUNT_{CTOR,DTOR}` All tier 1 platforms Debug build (or build opt with `--enable-logrefcnt`)
+ Leak tools for debugging memory growth that is cleaned up on shutdown
+ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------------------------------------------------- ---------------------- -------------------------------------------------------
+
+## Common leak patterns
+
+When trying to find a leak of reference-counted objects, there are a
+number of patterns that could cause the leak:
+
+1. Ownership cycles. The most common source of hard-to-fix leaks is
+ ownership cycles. If you can avoid creating cycles in the first
+ place, please do, since it's often hard to be sure to break the
+ cycle in every last case. Sometimes these cycles extend through JS
+ objects (discussed further below), and since JS is
+ garbage-collected, every pointer acts like an owning pointer and the
+ potential for fan-out is larger. See [bug
+ 106860](https://bugzilla.mozilla.org/show_bug.cgi?id=106860){.external
+ .text} and [bug
+ 84136](https://bugzilla.mozilla.org/show_bug.cgi?id=84136){.external
+ .text} for examples. (Is this advice still accurate now that we have
+ a cycle collector? \--Jesse)
+2. Dropping a reference on the floor by:
+ 1. Forgetting to release (because you weren't using `nsCOMPtr`
+ when you should have been): See [bug
+ 99180](https://bugzilla.mozilla.org/show_bug.cgi?id=99180){.external
+ .text} or [bug
+ 93087](https://bugzilla.mozilla.org/show_bug.cgi?id=93087){.external
+ .text} for an example or [bug
+ 28555](https://bugzilla.mozilla.org/show_bug.cgi?id=28555){.external
+ .text} for a slightly more interesting one. This is also a
+ frequent problem around early returns when not using `nsCOMPtr`.
+ 2. Double-AddRef: This happens most often when assigning the result
+ of a function that returns an AddRefed pointer (bad!) into an
+ `nsCOMPtr` without using `dont_AddRef()`. See [bug
+ 76091](https://bugzilla.mozilla.org/show_bug.cgi?id=76091){.external
+ .text} or [bug
+ 49648](https://bugzilla.mozilla.org/show_bug.cgi?id=49648){.external
+ .text} for an example.
+ 3. \[Obscure\] Double-assignment into the same variable: If you
+ release a member variable and then assign into it by calling
+ another function that does the same thing, you can leak the
+ object assigned into the variable by the inner function. (This
+ can happen equally with or without `nsCOMPtr`.) See [bug
+ 38586](https://bugzilla.mozilla.org/show_bug.cgi?id=38586){.external
+ .text} and [bug
+ 287847](https://bugzilla.mozilla.org/show_bug.cgi?id=287847){.external
+ .text} for examples.
+3. Dropping a non-refcounted object on the floor (especially one that
+ owns references to reference counted objects). See [bug
+ 109671](https://bugzilla.mozilla.org/show_bug.cgi?id=109671){.external
+ .text} for an example.
+4. Destructors that should have been virtual: If you expect to override
+ an object's destructor (which includes giving a derived class of it
+ an `nsCOMPtr` member variable) and delete that object through a
+ pointer to the base class using delete, its destructor better be
+ virtual. (But we have many virtual destructors in the codebase that
+ don't need to be -- don't do that.)
+
+## Debugging leaks that go through XPConnect
+
+Many large object graphs that leak go through
+[XPConnect](http://www.mozilla.org/scriptable/){.external .text}. This
+can mean there will be XPConnect wrapper objects showing up as owning
+the leaked objects, but it doesn't mean it's XPConnect's fault
+(although that [has been known to
+happen](https://bugzilla.mozilla.org/show_bug.cgi?id=76102){.external
+.text}, it's rare). Debugging leaks that go through XPConnect requires
+a basic understanding of what XPConnect does. XPConnect allows an XPCOM
+object to be exposed to JavaScript, and it allows certain JavaScript
+objects to be exposed to C++ code as normal XPCOM objects.
+
+When a C++ object is exposed to JavaScript (the more common of the two),
+an XPCWrappedNative object is created. This wrapper owns a reference to
+the native object until the corresponding JavaScript object is
+garbage-collected. This means that if there are leaked GC roots from
+which the wrapper is reachable, the wrapper will never release its
+reference on the native object. While this can be debugged in detail,
+the quickest way to solve these problems is often to simply debug the
+leaked JS roots. These roots are printed on shutdown in DEBUG builds,
+and the name of the root should give the type of object it is associated
+with.
+
+One of the most common ways one could leak a JS root is by leaking an
+`nsXPCWrappedJS` object. This is the wrapper object in the reverse
+direction \-- when a JS object is used to implement an XPCOM interface
+and be used transparently by native code. The `nsXPCWrappedJS` object
+creates a GC root that exists as long as the wrapper does. The wrapper
+itself is just a normal reference-counted object, so a leaked
+`nsXPCWrappedJS` can be debugged using the normal refcount-balancer
+tools.
+
+If you really need to debug leaks that involve JS objects closely, you
+can get detailed printouts of the paths JS uses to mark objects when it
+is determining the set of live objects by using the functions added in
+[bug
+378261](https://bugzilla.mozilla.org/show_bug.cgi?id=378261){.external
+.text} and [bug
+378255](https://bugzilla.mozilla.org/show_bug.cgi?id=378255){.external
+.text}. (More documentation of this replacement for GC_MARK_DEBUG, the
+old way of doing it, would be useful. It may just involve setting the
+`XPC_SHUTDOWN_HEAP_DUMP` environment variable to a file name, but I
+haven't tested that.)
+
+## Post-processing of stack traces
+
+On Mac and Linux, the stack traces generated by our internal debugging
+tools don't have very good symbol information (since they just show the
+results of `dladdr`). The stacks can be significantly improved (better
+symbols, and file name / line number information) by post-processing.
+Stacks can be piped through the script `tools/rb/fix_stacks.py` to do
+this. These scripts are designed to be run on balance trees in addition
+to raw stacks; since they are rather slow, it is often **much faster**
+to generate balance trees (e.g., using `make-tree.pl` for the refcount
+balancer or `diffbloatdump.pl --use-address` for trace-malloc) and*then*
+run the balance trees (which are much smaller) through the
+post-processing.
+
+## Getting symbol information for system libraries
+
+### Windows
+
+Setting the environment variable `_NT_SYMBOL_PATH` to something like
+`symsrv*symsrv.dll*f:\localsymbols*http://msdl.microsoft.com/download/symbols`
+as described in [Microsoft's
+article](http://support.microsoft.com/kb/311503){.external .text}. This
+needs to be done when running, since we do the address to symbol mapping
+at runtime.
+
+### Linux
+
+Many Linux distros provide packages containing external debugging
+symbols for system libraries. `fix_stacks.py` uses this debugging
+information (although it does not verify that they match the library
+versions on the system).
+
+For example, on Fedora, these are in \*-debuginfo RPMs (which are
+available in yum repositories that are disabled by default, but easily
+enabled by editing the system configuration).
+
+## Tips
+
+### Disabling Arena Allocation
+
+With many lower-level leak tools (particularly trace-malloc based ones,
+like leaksoup) it can be helpful to disable arena allocation of objects
+that you're interested in, when possible, so that each object is
+allocated with a separate call to malloc. Some places you can do this
+are:
+
+layout engine
+: Define `DEBUG_TRACEMALLOC_FRAMEARENA` where it is commented out in
+ `layout/base/nsPresShell.cpp`
+
+glib
+: Set the environment variable `G_SLICE=always-malloc`
+
+## Other References
+
+- [Performance
+ tools](https://wiki.mozilla.org/Performance:Tools "Performance:Tools")
+- [Leak Debugging Screencasts](https://dbaron.org/mozilla/leak-screencasts/){.external
+ .text}
+- [LeakingPages](https://wiki.mozilla.org/LeakingPages "LeakingPages") -
+ a list of pages known to leak
+- [mdc:Performance](https://developer.mozilla.org/en/Performance "mdc:Performance"){.extiw} -
+ contains documentation for all of our memory profiling and leak
+ detection tools
diff --git a/docs/performance/memory/memory.md b/docs/performance/memory/memory.md
new file mode 100644
index 0000000000000..c92375a394bbd
--- /dev/null
+++ b/docs/performance/memory/memory.md
@@ -0,0 +1,64 @@
+# Memory Tools
+
+The Memory tool lets you take a snapshot of the current tab's memory
+[heap](https://en.wikipedia.org/wiki/Memory_management#HEAP).
+It then provides a number of views of the heap that can
+show you which objects account for memory usage and exactly where in
+your code you are allocating memory.
+
+
+
+------------------------------------------------------------------------
+
+### The basics
+- Opening [the memory
+ tool](basic_operations.html#opening-the-memory-tool)
+- [Taking a heap
+ snapshot](basic_operations.html#saving-and-loading-snapshots)
+- [Comparing two
+ snapshots](basic_operations.html#comparing-snapshots)
+- [Deleting
+ snapshots](basic_operations.html#clearing-a-snapshot)
+- [Saving and loading
+ snapshots](basic_operations.html#saving-and-loading-snapshots)
+- [Recording call
+ stacks](basic_operations.html#recording-call-stacks)
+
+------------------------------------------------------------------------
+
+### Analyzing snapshots
+
+The Tree map view is new in Firefox 48, and the Dominators view is new
+in Firefox 46.
+
+Once you've taken a snapshot, there are three main views the Memory
+tool provides:
+
+- [the Tree map view](tree_map_view.md) shows
+ memory usage as a
+ [treemap](https://en.wikipedia.org/wiki/Treemapping).
+- [the Aggregate view](aggregate_view.md) shows
+ memory usage as a table of allocated types.
+- [the Dominators view](dominators_view.md)
+ shows the "retained size" of objects: that is, the size of objects
+ plus the size of other objects that they keep alive through
+ references.
+
+If you've opted to record allocation stacks for the snapshot, the
+Aggregate and Dominators views can show you exactly where in your code
+allocations are happening.
+
+------------------------------------------------------------------------
+
+### Concepts
+
+- What are [Dominators](dominators.md)?
+
+------------------------------------------------------------------------
+
+### Example pages
+
+Examples used in the Memory tool documentation.
+
+- The [Monster example](monster_example.md)
+- The [DOM allocation example](DOM_allocation_example.md)
diff --git a/docs/performance/memory/monster_example.md b/docs/performance/memory/monster_example.md
new file mode 100644
index 0000000000000..fd6b6e2f80a91
--- /dev/null
+++ b/docs/performance/memory/monster_example.md
@@ -0,0 +1,79 @@
+# Monster example slug
+
+This article describes a very simple web page that we'll use to
+illustrate some features of the Memory tool.
+
+You can try the site at
+.
+Heres the code:
+
+``` {.brush: .js}
+var MONSTER_COUNT = 5000;
+var MIN_NAME_LENGTH = 2;
+var MAX_NAME_LENGTH = 48;
+
+function Monster() {
+
+ function randomInt(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+ }
+
+ function randomName() {
+ var chars = "abcdefghijklmnopqrstuvwxyz";
+ var nameLength = randomInt(MIN_NAME_LENGTH, MAX_NAME_LENGTH);
+ var name = "";
+ for (var j = 0; j < nameLength; j++) {
+ name += chars[randomInt(0, chars.length-1)];
+ }
+ return name;
+ }
+
+ this.name = randomName();
+ this.eyeCount = randomInt(0, 25);
+ this.tentacleCount = randomInt(0, 250);
+}
+
+function makeMonsters() {
+ var monsters = {
+ "friendly": [],
+ "fierce": [],
+ "undecided": []
+ };
+
+ for (var i = 0; i < MONSTER_COUNT; i++) {
+ monsters.friendly.push(new Monster());
+ }
+
+ for (var i = 0; i < MONSTER_COUNT; i++) {
+ monsters.fierce.push(new Monster());
+ }
+
+ for (var i = 0; i < MONSTER_COUNT; i++) {
+ monsters.undecided.push(new Monster());
+ }
+
+ console.log(monsters);
+}
+
+var makeMonstersButton = document.getElementById("make-monsters");
+makeMonstersButton.addEventListener("click", makeMonsters);
+```
+
+The page contains a button: when you push the button, the code creates
+some monsters. Specifically:
+
+- the code creates an object with three properties, each an array:
+ - one for fierce monsters
+ - one for friendly monsters
+ - one for monsters who haven't decided yet.
+- for each array, the code creates and appends 5000
+ randomly-initialized monsters. Each monster has:
+ - a string, for the monster's name
+ - a number representing the number of eyes it has
+ - a number representing the number of tentacles it has.
+
+So the structure of the memory allocated on the JavaScript heap is an
+object containing three arrays, each containing 5000 objects (monsters),
+each object containing a string and two integers:
+
+[![](../img/monsters.svg)]
diff --git a/docs/performance/memory/refcount_tracing_and_balancing.md b/docs/performance/memory/refcount_tracing_and_balancing.md
new file mode 100644
index 0000000000000..6dfc691c4f380
--- /dev/null
+++ b/docs/performance/memory/refcount_tracing_and_balancing.md
@@ -0,0 +1,235 @@
+# Refcount Tracing and Balancing
+
+Refcount tracing and balancing are advanced techniques for tracking down
+leak of refcounted objects found with
+[BloatView](bloatview.md). The first step
+is to run Firefox with refcount tracing enabled, which produces one or
+more log files. Refcount tracing logs calls to `Addref` and `Release`,
+preferably for a particular set of classes, including call-stacks in
+symbolic form (on platforms that support this). Refcount balancing is a
+follow-up step that analyzes the resulting log to help a developer
+figure out where refcounting went wrong.
+
+## How to build for refcount tracing
+
+Build with `--enable-debug` or `--enable-logrefcnt`.
+
+## How to run with refcount tracing on
+
+There are several environment variables that can be used.
+
+First, you select one of three environment variables to choose what kind
+of logging you want. You almost certainly want `XPCOM_MEM_REFCNT_LOG`.
+
+NOTE: Due to an issue with the sandbox on Windows (bug
+[1345568](https://bugzilla.mozilla.org/show_bug.cgi?id=1345568)
+refcount logging currently requires the MOZ_DISABLE_CONTENT_SANDBOX
+environment variable to be set.
+
+`XPCOM_MEM_REFCNT_LOG`
+
+Setting this environment variable enables refcount tracing. If you set
+this environment variable to the name of a file, the log will be output
+to that file. You can also set it to 1 to log to stdout or 2 to log to
+stderr, but these logs are large and expensive to capture, so you
+probably don't want to do that. **WARNING**: you should never use this
+without `XPCOM_MEM_LOG_CLASSES` and/or `XPCOM_MEM_LOG_OBJECTS`, because
+without some filtering the logging will be completely useless due to how
+slow the browser will run and how large the logs it produces will be.
+
+`XPCOM_MEM_COMPTR_LOG`
+
+This environment variable enables logging of additions and releases of
+objects into `nsCOMPtr`s. This requires C++ dynamic casts, so it is not
+supported on all platforms. However, having an nsCOMPtr log and using it
+in the creation of the balance tree allows AddRef and Release calls that
+we know are matched to be eliminated from the tree, so it makes it much
+easier to debug reference count leaks of objects that have a large
+amount of reference counting traffic.
+
+`XPCOM_MEM_ALLOC_LOG`
+
+For platforms that don't have stack-crawl support, XPCOM supports
+logging at the call site to `AddRef`/`Release` using the usual cpp
+`__FILE__` and __LINE__ number macro expansion hackery. This results
+in slower code, but at least you get some data about where the leaks
+might be occurring from.
+
+You must also set one or two additional environment variables,
+`XPCOM_MEM_LOG_CLASSES` and `XPCOM_MEM_LOG_OBJECTS,` to reduce the set
+of objects being logged, in order to improve performance to something
+vaguely tolerable.
+
+`XPCOM_MEM_LOG_CLASSES`
+
+This variable should contain a comma-separated list of names which will
+be used to compare against the types of the objects being logged. For
+example:
+
+ env XPCOM_MEM_LOG_CLASSES=nsDocShell XPCOM_MEM_REFCNT_LOG=./refcounts.log ./mach run
+
+This will log the `AddRef` and `Release` calls only for instances of
+`nsDocShell` while running the browser using `mach`, to a file
+`refcounts.log`. Note that setting `XPCOM_MEM_LOG_CLASSES` will also
+list the *serial number* of each object that leaked in the "bloat log"
+(that is, the file specified by the `XPCOM_MEM_BLOAT_LOG` variable; see
+[the BloatView documentation](bloatview.md)
+for more details). An object's serial number is simply a unique number,
+starting at one, that is assigned to the object when it is allocated.
+
+You may use an object's serial number with the following variable to
+further restrict the reference count tracing:
+
+ XPCOM_MEM_LOG_OBJECTS
+
+Set this variable to a comma-separated list of object *serial number* or
+ranges of *serial number*, e.g., `1,37-42,73,165` (serial numbers start
+from 1, not 0). When this is set, along with `XPCOM_MEM_LOG_CLASSES` and
+`XPCOM_MEM_REFCNT_LOG`, a stack track will be generated for *only* the
+specific objects that you list. For example,
+
+ env XPCOM_MEM_LOG_CLASSES=nsDocShell XPCOM_MEM_LOG_OBJECTS=2 XPCOM_MEM_REFCNT_LOG=./refcounts.log ./mach run
+
+will log stack traces to `refcounts.log` for the 2nd `nsDocShell` object
+that gets allocated, and nothing else.
+
+## **Post-processing step 1: finding the leakers**
+
+First you have to figure out which objects leaked. The script
+`tools/rb/find_leakers.py` does this. It grovels through the log file,
+and figures out which objects got allocated (it knows because they were
+just allocated because they got `AddRef()`-ed and their refcount became
+1). It adds them to a list. When it finds an object that got freed (it
+knows because its refcount goes to 0), it removes it from the list.
+Anything left over is leaked.
+
+The scripts output looks like the following.
+
+ 0x00253ab0 (1)
+ 0x00253ae0 (2)
+ 0x00253bd0 (4)
+
+The number in parentheses indicates the order in which it was allocated,
+if you care. Pick one of these pointers for use with Step 2.
+
+## Post-processing step 2: filtering the log
+
+Once you've picked an object that leaked, you can use
+`tools/``rb``/filter-log.pl` to filter the log file to drop the call
+stack for other objects; This process reduces the size of the log file
+and also improves the performance.
+
+ perl -w tools/rb/filter-log.pl --object 0x00253ab0 < ./refcounts.log > my-leak.log
+
+#### Linux Users
+
+The log file generated on Linux system often lack function names, file
+names and line numbers. Linux users need to run a script to fix the call
+stack.
+
+ python tools/rb/fix_stacks.py < ./refcounts.log > fixed_stack.log
+
+## **Post-processing step 3: building the balance tree**
+
+Now that you've the log file fully prepared, you can build a *balance
+tree*. This process takes all the stack `AddRef()` and `Release()` stack
+traces and munges them into a call graph. Each node in the graph
+represents a call site. Each call site has a *balance factor*, which is
+positive if more `AddRef()`s than `Release()`es have happened at the
+site, zero if the number of `AddRef()`s and `Release()`es are equal, and
+negative if more `Release()`es than `AddRef()`s have happened at the
+site.
+
+To build the balance tree, run `tools/rb/make-tree.pl`, specifying the
+object of interest. For example:
+
+ perl -w tools/rb/make-tree.pl --object 0x00253ab0 < my-leak.log
+
+This will build an indented tree that looks something like this (except
+probably a lot larger and leafier):
+
+ .root: bal=1
+ main: bal=1
+ DoSomethingWithFooAndReturnItToo: bal=2
+ NS_NewFoo: bal=1
+
+Let's pretend in our toy example that `NS_NewFoo()` is a factory method
+that makes a new foo and returns it.
+`DoSomethingWithFooAndReturnItToo()` is a method that munges the foo
+before returning it to `main()`, the main program.
+
+What this little tree is telling you is that you leak *one refcount*
+overall on object `0x00253ab0`. But, more specifically, it shows you
+that:
+
+- `NS_NewFoo()` "leaks" a refcount. This is probably "okay"
+ because it's a factory method that creates an `AddRef()`-ed object.
+- `DoSomethingWithFooAndReturnItToo()` leaks *two* refcounts.
+ Hmm...this probably isn't okay, especially because...
+- `main()` is back down to leaking *one* refcount.
+
+So from this, we can deduce that `main()` is correctly releasing the
+refcount that it got on the object returned from
+`DoSomethingWithFooAndReturnItToo()`, so the leak *must* be somewhere in
+that function.
+
+So now say we go fix the leak in `DoSomethingWithFooAndReturnItToo()`,
+re-run our trace, grovel through the log by hand to find the object that
+corresponds to `0x00253ab0` in the new run, and run `make-tree.pl`. What
+we'd hope to see is a tree that looks like:
+
+ .root: bal=0
+ main: bal=0
+ DoSomethingWithFooAndReturnItToo: bal=1
+ NS_NewFoo: bal=1
+
+That is, `NS_NewFoo()` "leaks" a single reference count; this leak is
+"inherited" by `DoSomethingWithFooAndReturnItToo()`; but is finally
+balanced by a `Release()` in `main()`.
+
+## Hints
+
+Clearly, this is an iterative and analytical process. Here are some
+tricks that make it easier.
+
+**Check for leaks from smart pointers.** If the leak comes from a smart
+pointer that is logged in the XPCOM_MEM_COMPTR_LOG, then
+find-comptr-leakers.pl will find the exact stack for you, and you don't
+have to look at trees.
+
+**Ignore balanced trees**. The `make-tree.pl` script accepts an option
+`--ignore-balanced`, which tells it *not* to bother printing out the
+children of a node whose balance factor is zero. This can help remove
+some of the clutter from an otherwise noisy tree.
+
+**Ignore matched releases from smart pointers.** If you've checked (see
+above) that the leak wasn't from a smart pointer, you can ignore the
+references that came from smart pointers (where we can use the pointer
+identity of the smart pointer to match the AddRef and the Release). This
+requires using an XPCOM_MEM_REFCNT_LOG and an XPCOM_MEM_COMPTR_LOG that
+were collected at the same time. For more details, see the [old
+documentation](http://www-archive.mozilla.org/performance/leak-tutorial.html)
+(which should probably be incorporated here). This is best used with
+`--ignore-balanced`
+
+**Play Mah Jongg**. An unbalanced tree is not necessarily an evil thing.
+More likely, it indicates that one `AddRef()` is cancelled by another
+`Release()` somewhere else in the code. So the game is to try to match
+them with one another.
+
+**Exclude Functions.** To aid in this process, you can create an
+"excludes file", that lists the name of functions that you want to
+exclude from the tree building process (presumably because you've
+matched them). `make-tree.pl` has an option `--exclude [file]`, where
+`[file]` is a newline-separated list of function names that will be
+*excluded* from consideration while building the tree. Specifically, any
+call stack that contains that call site will not contribute to the
+computation of balance factors in the tree.
+
+## How to instrument your objects for refcount tracing and balancing
+
+The process is the same as [instrumenting them for
+[BloatView](bloatview.md]
+todo
+How_to_instrument_your_objects_for_BloatView,
+because BloatView and refcount tracing share underlying infrastructure.
diff --git a/docs/performance/memory/tree_map_view.md b/docs/performance/memory/tree_map_view.md
new file mode 100644
index 0000000000000..30d9968db626e
--- /dev/null
+++ b/docs/performance/memory/tree_map_view.md
@@ -0,0 +1,62 @@
+# Tree map view
+
+The Tree map view is new in Firefox 48.
+
+The Tree map view provides a visual representation of the snapshot, that
+helps you quickly get an idea of which objects are using the most
+memory.
+
+A treemap displays [\"hierarchical (tree-structured) data as a set of
+nested rectangles\"](https://en.wikipedia.org/wiki/Treemapping). The
+size of the rectangles corresponds to some quantitative aspect of the
+data.
+
+For the treemaps shown in the Memory tool, things on the heap are
+divided at the top level into four categories:
+
+- **objects**: JavaScript and DOM objects, such as `Function`,
+ `Object`, or `Array`, and DOM types like `Window` and
+ `HTMLDivElement`.
+- **scripts**: JavaScript sources loaded by the page.
+- **strings**
+- **other**: this includes internal
+ [SpiderMonkey](https://developer.mozilla.org/en-US/docs/Tools/Tools_Toolbox#settings/en-US/docs/Mozilla/Projects/SpiderMonkey) objects.
+
+Each category is represented with a rectangle, and the size of the
+rectangle corresponds to the proportion of the heap occupied by items in
+that category. This means you can quickly get an idea of roughly what
+sorts of things allocated by your site are using the most memory.
+
+Within top-level categories:
+
+- **objects** is further divided by the object's type.
+- **scripts** is further subdivided by the script's origin. It also
+ includes a separate rectangle for code that can't be correlated
+ with a file, such as JIT-optimized code.
+- **other** is further subdivided by the object's type.
+
+Here are some example snapshots, as they appear in the Tree map view:
+
+![](../img/treemap-domnodes.png)
+
+This treemap is from the [DOM allocation
+example](DOM_allocation_example.md), which runs a
+script that creates a large number of DOM nodes (200 `HTMLDivElement`
+objects and 4000 `HTMLSpanElement` objects). You can see how almost all
+the heap usage is from the `HTMLSpanElement` objects that it creates.
+
+![](../img/treemap-monsters.png)
+
+This treemap is from the [monster allocation
+example](monster_example.md), which creates three
+arrays, each containing 5000 monsters, each monster having a
+randomly-generated name. You can see that most of the heap is occupied
+by the strings used for the monsters' names, and the objects used to
+contain the monsters' other attributes.
+
+![](../img/treemap-bbc.png)
+
+This treemap is from , and is probably more
+representative of real life than the examples. You can see the much
+larger proportion of the heap occupied by scripts, that are loaded from
+a large number of origins.
diff --git a/docs/performance/reporting_a_performance_problem.md b/docs/performance/reporting_a_performance_problem.md
index 5717bb23ca64b..f1b7a28490906 100644
--- a/docs/performance/reporting_a_performance_problem.md
+++ b/docs/performance/reporting_a_performance_problem.md
@@ -21,7 +21,7 @@ These steps only work in Firefox 75+.
When enabled, the profiler toolbar button is not recording by default.
Recording can be done by clicking on the toolbar icon to open its panel.
-Make sure to choose an appropriate setting for the recording (if you\'re
+Make sure to choose an appropriate setting for the recording (if you're
not sure, choose Firefox Platform), and then choosing **Start
Recording**. The toolbar icon turns blue when it is recording.
@@ -58,7 +58,7 @@ mouse to interact with the UI:
will allow you to upload this profile and once completed will write
out a link. Before uploading, the publish button asks you what data
you'd like to publish to our servers.
-5. Note that while it\'s possible to strip profiles of potentially
+5. Note that while it's possible to strip profiles of potentially
privacy sensitive information, the less information a profile
contains, *the harder it is to analyze and turn into actionable
data.*
diff --git a/docs/performance/scroll-linked_effects.md b/docs/performance/scroll-linked_effects.md
index 102d90b5ea16d..d17740f20b549 100644
--- a/docs/performance/scroll-linked_effects.md
+++ b/docs/performance/scroll-linked_effects.md
@@ -12,15 +12,15 @@ techniques.
Often scrolling effects are implemented by listening for the `scroll`
event and then updating elements on the page in some way (usually the
CSS
-[`position`](/en-US/docs/Web/CSS/position "The position CSS property sets how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements.")
+[`position`]((https://developer.mozilla.org/en-US/docs/Web/CSS/position "The position CSS property sets how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements.")
or
-[`transform`](/en-US/docs/Web/CSS/transform "The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.")
+[`transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform "The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.")
property.) You can find a sampling of such effects at [CSS Scroll API:
Use
Cases](https://github.com/RByers/css-houdini-drafts/blob/master/css-scroll-api/UseCases.md).
These effects work well in browsers where the scrolling is done
-synchronously on the browser\'s main thread. However, most browsers now
+synchronously on the browser's main thread. However, most browsers now
support some sort of asynchronous scrolling in order to provide a
consistent 60 frames per second experience to the user. In the
asynchronous scrolling model, the visual scroll position is updated in
@@ -46,12 +46,12 @@ Here is an implementation of a sticky-positioning effect, where the
```
This implementation of sticky positioning relies on the scroll event
-listener to reposition the \"toolbar\" div. As the scroll event listener
-runs in the JavaScript on the browser\'s main thread, it will be
+listener to reposition the "toolbar" div. As the scroll event listener
+runs in the JavaScript on the browser's main thread, it will be
asynchronous relative to the user-visible scrolling. Therefore, with
asynchronous scrolling, the event handler will be delayed relative to
the user-visible scroll, and so the div will not stay visually fixed as
-intended. Instead, it will move with the user\'s scrolling, and then
+intended. Instead, it will move with the user's scrolling, and then
\"snap\" back into position when the scroll event handler runs. This
constant moving and snapping will result in a jittery visual effect. One
way to implement this without the scroll event listener is to use the
@@ -69,7 +69,7 @@ the \"toolbar\" div is updated by the browser as the user scrolls.
### Example 2: Scroll snapping
Below is an implementation of scroll snapping, where the scroll position
-snaps to a particular destination when the user\'s scrolling stops near
+snaps to a particular destination when the user's scrolling stops near
that destination.
``` {.brush: .html}
@@ -97,7 +97,7 @@ In this example, there is a scroll event listener which detects if the
scroll position is within 200 pixels of the top of the \"snaptarget\"
div. If it is, then it triggers an animation to \"snap\" the scroll
position to the top of the div. As this animation is driven by
-JavaScript on the browser\'s main thread, it can be interrupted by other
+JavaScript on the browser's main thread, it can be interrupted by other
JavaScript running in other tabs or other windows. Therefore, the
animation can end up looking janky and not as smooth as intended.
Instead, using the CSS snap-points property will allow the browser to
@@ -124,7 +124,7 @@ the user.
```
This version can work smoothly in the browser even if there is
-slow-running Javascript on the browser\'s main thread.
+slow-running Javascript on the browser's main thread.
### Other effects
@@ -157,7 +157,7 @@ consideration are:
animation.
- [CompositorWorker](https://docs.google.com/document/d/18GGuTRGnafai17PDWjCHHAvFRsCfYUDYsi720sVPkws/edit?pli=1#heading=h.iy9r1phg1ux4):
Allows JavaScript to be run on the compositor thread in small
- chunks, provided it doesn\'t cause the framerate to drop.
+ chunks, provided it doesn't cause the framerate to drop.
- [Scroll
Customization](https://docs.google.com/document/d/1VnvAqeWFG9JFZfgG5evBqrLGDZYRE5w6G5jEDORekPY/edit?pli=1):
Introduces a new API for content to dictate how a scroll delta is
diff --git a/docs/performance/sorting_algorithms_comparison.md b/docs/performance/sorting_algorithms_comparison.md
new file mode 100644
index 0000000000000..5841b3472d51d
--- /dev/null
+++ b/docs/performance/sorting_algorithms_comparison.md
@@ -0,0 +1,57 @@
+# Sorting algorithms comparision
+
+This article describes a simple example program that we use in two of
+the Performance guides: the guide to the [Call
+Tree](call_tree.md) and the guide to the
+[Flame Chart](https://developer.mozilla.org/en-US/docs/Tools/Performance/Flame_Chart).
+
+This program compares the performance of three different sorting
+algorithms:
+
+- bubble sort
+- selection sort
+- quicksort
+
+It consists of the following functions:
+
+ ----------------------- ---------------------------------------------------------------------------------------------------
+ **`sortAll()`** Top-level function. Iteratively (200 iterations) generates a randomized array and calls `sort()`.
+ **`sort()`** Calls each of `bubbleSort()`, `selectionSort()`, `quickSort()` in turn and logs the result.
+ **`bubbleSort()`** Implements a bubble sort, returning the sorted array.
+ **`selectionSort()`** Implements a selection sort, returning the sorted array.
+ **`quickSort()`** Implements quicksort, returning the sorted array.
+ `swap()` Helper function for `bubbleSort()` and `selectionSort()`.
+ `partition()` Helper function for `quickSort()`.
+ ----------------------- ---------------------------------------------------------------------------------------------------
+
+Its call graph looks like this:
+
+ sortAll() // (generate random array, then call sort) x 200
+
+ -> sort() // sort with each algorithm, log the result
+
+ -> bubbleSort()
+
+ -> swap()
+
+ -> selectionSort()
+
+ -> swap()
+
+ -> quickSort()
+
+ -> partition()
+
+The implementations of the sorting algorithms in the program are taken
+from and are
+used under the MIT license.
+
+You can try out the example program
+[here](https://mdn.github.io/performance-scenarios/js-call-tree-1/index.html)
+and clone the code [here](https://github.com/mdn/performance-scenarios)
+(be sure to check out the gh-pages branch). You can also [download the
+specific profile we
+discuss](https://github.com/mdn/performance-scenarios/tree/gh-pages/js-call-tree-1/profile)
+- just import it to the Performance tool if you want to follow along. Of
+course, you can generate your own profile, too, but the numbers will be
+a little different.