UNPKG

5.65 kBMarkdownView Raw
1## Understanding the analysis
2
3An unknown issue occurs when Clinic.js' analysis algorithms are unable to categorize the sampling results but nevertheless an issue *of some kind* has been detected.
4
5This outcome can be attributed to one of two scenarios:
6
71. Ambient noise – for instance, other applications using the CPU or memory – during the sampling period has polluted the results.
82. There is a genuine performance issue but `clinic doctor` doesn't recognize it.
9
10In the case of ambient noise, there may still be a specific, categorizable performance issue.
11
12We can make eliminate the possibility of ambient noise and make it easier for Clinic.js to definitively recognize the issue by:
13
14- Closing down as many applications as possible, especially applications that are CPU- or Memory- intensive.
15- Using the `--on-port` flag. This can reduce the chances of unknown issues because there is no time gap nor additional system activity between the server starting and the load test beginning.
16
17By way of example, instead of running `clinic -- node app.js` in one terminal and `autocannon localhost:3000` in another, it is preferable and recommended to trigger both in one command using the following command:
18
19<code class='snippet'>clinic doctor --on-port="autocannon localhost:3000" -- node app.js</code>
20
21An even simpler form of this is to use the `--autocannon` flag,
22
23<code class='snippet'>clinic doctor --autocannon / -- node app.js</code>
24
25If after taking these steps an unknown categorization continues to occur then we can instead attempt to infer the nature of the performance issue using specialist diagnostic tooling, such
26as `clinic flame`, `clinic bubble` or Node Inspector.
27
28## Next Steps
29
30- First eliminate the possibility of ambient noise
31 - Reduce noise by closing down as many other applications running on the system as possible - especially CPU or Memory intensive applications
32 - Ensure that the `--on-port` flag is being used to trigger load testing instead of initiating load testing independently
33- Use `clinic bubbleprof` to create a diagram of the application's asynchronous flow (see <code class='snippet'>clinic bubbleprof --help</code>)
34- Explore the Bubbleprof diagram. Look for long lines and large circles representing persistent delays, then drill down to reveal the lines of code responsible
35 - A common problem is the overuse or misuse of promises. `clinic bubbleprof` will visualize promise activity, make a point of looking out for it in the diagram.
36- Use `clinic flame` to generate a flamegraph
37 - Run <code class='snippet'>clinic flame --help</code> to get started
38- Look for "hot" blocks, these are functions that are observed (at a higher relative frequency) to be at the top the stack per CPU sample – in other words, such functions are blocking the event loop
39- For memory analysis use the [`--inspect`](https://nodejs.org/en/docs/inspector) flag with the Chrome Devtools *Memory* tab.
40 - Run <code class='snippet'>node --inspect <FILENAME></code>
41 - Open Chrome and navigate to [chrome://inspect](chrome://inspect)
42 - Under the **Remote Target** heading, there should be a target with the official Node.js icon
43 - Click the `inspect` link for that target – this will connect Chrome Devtools to the Node processes remote debug interface
44 - In Devtools, select the *Memory* tab
45 - Select the *Take heap snapshot* radio box, and then click *Take snapshot*
46 - Put the process under load (in the same way that the process was load tested for Clinic.js)
47 - Click *Profiles* in the left panel, then click *Take snapshot* again
48 - Under the *HEAP SNAPSHOTS* left panel, select the second Snapshot (it will be called *Snapshot 2*)
49 - Locate the dropdown box just above the "Constructor" column (most likely the dropdown box says *Summary*)
50 - Click the dropdown, and select *Comparison* – this compares the before and after snapshots of the heap
51 - Click the *# Delta* and/or *Size Delta* columns to sort by the difference in object counts
52 or object size, categorized by constructor type
53 - Use the interactive trees in the Constructor column to drill down into the specifics
54 - Use the *Retainers* panel to understand the chain of object references
55
56## Reference
57- [Clinic.js Flame](https://clinicjs.org/flame)
58- [Overview of blocking vs non-blocking](https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/)
59- [Concurrency model and Event Loop
60](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)
61- [Don't Block the Event Loop (or the Worker Pool)](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)
62- Understanding Flamegraphs and how to use 0x: [Tuning Node.js app performance with autocannon and 0x](https://www.nearform.com/blog/tuning-node-js-app-performance-with-autocannon-and-0x/)
63- [Clinic.js Bubbleprof](https://clinicjs.org/bubbleprof)
64- [Chrome Devtools Docs: Fix Memory Problems](https://developers.google.com/web/tools/chrome-devtools/memory-problems/)
65- [Chrome Devtools Docs: Memory Terminology](https://developers.google.com/web/tools/chrome-devtools/memory-problems/memory-101)
66- [Chrome Devtools Docs: How to record heap snapshots](https://developers.google.com/web/tools/chrome-devtools/memory-problems/heap-snapshots)
67- [Node Docs: Inspector](https://nodejs.org/en/docs/inspector/)
68- **Advanced**: [Core dump analysis tool for Linux: llnode](https://github.com/nodejs/llnode)
69- **Advanced**: [Core dump analysis tool for SmartOS: mdb_v8](https://github.com/joyent/mdb_v8)
70- **Advanced**: [Core dump analysis tool for Linux which wraps SmartOS mdb](https://www.npmjs.com/package/autopsy)