summaryrefslogtreecommitdiffstats
path: root/devtools/docs/contributor/contributing/performance.md
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/docs/contributor/contributing/performance.md')
-rw-r--r--devtools/docs/contributor/contributing/performance.md152
1 files changed, 152 insertions, 0 deletions
diff --git a/devtools/docs/contributor/contributing/performance.md b/devtools/docs/contributor/contributing/performance.md
new file mode 100644
index 0000000000..4c6728d326
--- /dev/null
+++ b/devtools/docs/contributor/contributing/performance.md
@@ -0,0 +1,152 @@
+# Writing efficient code
+
+When debugging a page, tools get to slow down the website because of the added instrumentation.
+While working on Developer Tools we should strive to be the less impactful.
+First, because it is painful to work with laggy UI, but also because some tools record timings.
+For example, the network monitor records HTTP request timings.
+If the tools are slowing down Firefox significantly, it will make these measurements be wrong.
+
+To be efficient while working on performance, you should always focus on one precise user scenario.
+It could be:
+* a bug report where someone reports a precise interaction being slow,
+* or you could be trying to improve overall tools performance by looking at the most common usages.
+The important point here is to have some steps to reproduce, that you can redo manually in order to record a profile.
+And also, it is even better if you can replay via a test script. Test script that you can save as a new performance test.
+
+## Don't guess — profile.
+
+The very first thing to do is to record a profile while reproducing the scenario.
+
+Here's the Firefox documentation for [how to install the profiler and record a profile](https://developer.mozilla.org/docs/Mozilla/Performance/Reporting_a_Performance_Problem) and also [how to interpret the profiles](https://developer.mozilla.org/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler#Understanding_Profiles)
+
+There are some peculiarities about DevTools architecture that are worth knowing about when looking at a profile:
+
+### Tweak profiler default settings
+
+The default buffer size (9MB) is too small. If you don't increase it, you may easily miss data and only see last couple of seconds of your recording.
+To increase the buffer size, click on the profiler add-on icon, in the Firefox toolbar, and set it to 360MB, like this:
+
+ <img src="performance/profiler-buffer-size.png" alt="Profiler buffer size" style="width: 300px" />
+
+The other setting worth mentioning for DevTools debugging is the `Interval`
+The profiler records only samples, based on this `Interval`.
+If you want to see more fine-grained stack traces, you may reduce this interval to 0.1ms,
+but do that only if you really need it, as it will make Firefox much even slower when recording,
+and the measured times will be even slower.
+
+### The DevTools UI runs on the parent process
+
+When you are debugging tool front-ends (e.g. panels), always ensure you select the `Main Thread` line.
+It should have a light blue background like this:
+
+ <img src="performance/profiler-main-thread.png" alt="Select main process" style="width: 300px" />
+
+Otherwise, the vast majority of DevTools backend (DevToolsServer, actors, ...) lives in content processes.
+So if you are debugging them, you should select one of the `Content` lines.
+
+### Most of the DevTools codebase is in Javascript
+
+In the call tree, it is easier to filter by `JS`, via this menu list:
+ <img src="performance/profiler-filter-js.png" alt="JS Filtering" style="width: 200px" />
+
+But note that you may have to switch back to `Combined` in order to understand why some particular Javascript method is slow.
+
+### Handy filter strings for DevTools:
+
+ * `require`
+ Helps highlighting the cost of module loading
+ ![modules](performance/profiler-filter-require.png)
+ * DevTools uses two kind of URLs:
+ * `chrome://devtools/` for all panel documents. Filter with this to see the cost of all panel documents:
+ ![panels documents](performance/profiler-chrome-url.png)
+ * `resource://devtools/` for all javascript modules. Filter with this to see the cost of all modules:
+ ![modules](performance/profiler-resource-url.png)
+
+### Record durations manually
+
+Sometimes it is handy to focus on a very precise piece of code and record its time manually.
+For example when you identified one slow running method and think you can speed it up.
+It saves your from having to: record the profile, wait for the profiler to display and search for the precise method durations.
+
+#### Print durations in your Terminal and in the Browser Console
+
+You can use the [`Performance`](https://developer.mozilla.org/docs/Web/API/Performance) API, like this:
+```
+let start = window.performance.now();
+
+// Run the code you want to measure
+
+// Once it is done, do:
+console.log("my function took", window.performance.now() - start, "ms");
+```
+
+#### Use markers
+
+The Performance API also allows recording markers, like this:
+```
+window.performance.mark("my-function-start");
+
+// Run the code you want to measure
+
+// Once it is done, do:
+window.performance.measure("my-function", "my-function-start");
+```
+
+This marker will appear in the `Marker Chart` section in [profiler.firefox.com](https://profiler.firefox.com), in the `UserTiming` lines:
+ ![custom markers](performance/profiler-custom-markers.png)
+
+You can double click on it to make [profiler.firefox.com](https://profiler.firefox.com) display the record during this precise moment in time,
+and the call tree will only display what was executed during this measurement.
+
+### Prototype quickly
+
+Sometimes the best way to find what is slow is to comment blocks of code out
+and uncomment them one by one until you identify the culprit. And then focus on it.
+
+There are few things worse than spending a long time refactoring the piece of code that was not slow to begin with!
+
+## Assess your improvement.
+
+Once you have a patch that you think improves the performance, you have to assess whether it actually improves it.
+
+### Record another profile
+
+Compare the two profiles, without and with your patch.
+Then see if the call tree reports a significant difference:
+* A function call completely disappears in the new profile, with your fix.
+ For example you were loading a big module, and you got a frame for `require("my/big/module")` call, and no longer see it.
+* The same function call takes xxx ms less with your patch.
+
+This [lazy loading of modules in netmonitor](https://bugzilla.mozilla.org/show_bug.cgi?id=1420289) is a good example.
+Without this patch, App.js was loading in 91ms and was loading MonitorPanel.js and StatisticsPanel.js as dependencies:
+ ![netmonitor without patch](performance/profiler-netmonitor-open.png)
+
+With the patch, App.js loads in 47ms and only loads MonitorPanel.js:
+ ![netmonitor with patch](performance/profiler-netmon-open-fixed.png)
+
+It highlights that:
+ * we no longer load StatisticsPanel,
+ * App is faster to load.
+
+### Run performance tests
+
+See if any subtest reports a improvement. Ensure that the improvement makes any sense.
+For example, if the test is 50% faster, maybe you broke the performance test.
+This might happen if the test no longer waits for all the operations to finish executing before completing.
+
+To push your current patch to try, execute:
+```bash
+./mach try fuzzy --query "'linux 'damp" --rebuild 5
+```
+It will print in your Terminal a link to perfherder like this one:
+[https://treeherder.mozilla.org/perf.html#/comparechooser?newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db](https://treeherder.mozilla.org/perf.html#/comparechooser?newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db)
+Running performance tests takes time, so you should open it 30 minutes up to 2 hours later to see your results.
+See [DAMP Performance tests](../tests/performance-tests-damp.md) for more information about PerfHerder/try.
+
+Let's look at how to interpret an actual real-life [set of perfherder results](https://treeherder.mozilla.org/perf.html#/comparesubtest?originalProject=mozilla-central&newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db&originalSignature=edaec66500db21d37602c99daa61ac983f21a6ac&newSignature=edaec66500db21d37602c99daa61ac983f21a6ac&showOnlyImportant=1&framework=1&selectedTimeRange=172800):
+
+![perfherder results](performance/perfherder-results.png)
+
+These results are related to [lazy loading of modules in netmonitor](https://bugzilla.mozilla.org/show_bug.cgi?id=1420289).
+It is interesting to see that this patch is a trade-off. It makes netmonitor opening significantly faster, by preventing loading many modules during its opening.
+But it makes the page reload a bit slower as some modules that used to be loaded during netmonitor open, now have to be loaded during page reload.