Hello everyone! In the last report I said that just a little bit of work on the heap snapshot portion of the UI should result in a useful tool.
Here's my report for the first useful pieces of the Heap Snapshot UI!
Last time you already saw the graphs showing how the number of instances of a given type or frame grow and shrink over the course of multiple snapshots, and how new snapshots can be requested from the UI.
The latter now looks a little bit different:
Each snapshot now has a little button for itself, they are in one line instead of each snapshot having its own line, and the progress bar has been replaced with a percentage and a little "spinner".
Navigating the heap
There are multiple ways to get started navigating the heap snapshot. Everything is reachable from the "Root" object (this is the norm for reachability-based garbage collection schemes). You can just click through from there and see what you can find.
Another way is to look at the
Type & Frame Lists, which show every type or frame along with the number of instances that exist in the heap snapshot, and the total size taken up by those objects.
Type & Frame Lists
Clicking on a type, or the name or filename of a frame leads you to a list of all objects of that type, all frames with the given name, or all frames from the given file. They are grouped by size, and each object shows up as a little button with the ID:
Clicking any of these buttons leads you to the Explorer.
Here's a screenshot of the explorer to give you an idea of how the parts go together that I explain next:
The explorer is split into two identical panels, which allows you to compare two objects, or to explore in multiple directions from one given object.
There's an "Arrow to the Right" button on the left pane and an "Arrow to the Left" button on the right pane. These buttons make the other pane show the same object that the one pane currently shows.
On the left of each pane there's a "Path" display. Clicking the "Path" button in the explorer will calculate the shortest path to reach the object from the root. This is useful when you've got an object that you would expect to have already been deleted by the garbage collector, but for some reason is still around. The path can give the critical hint to figure out why it's still around. Maybe one phase of the program has ended, but something is still holding on to a cache that was put in as an optimization, and that still has your object in it? That cache in question would be on the path for your object.
The other half of each panel shows information about the object: Displayed at the very top is whether it is an object, a type object, an STable, or a frame.
Below that there is an input field where you can enter any ID belonging to a Collectable (the general term encompassing types, type objects, stables, and frames) to have a look.
The "Kind" field needs to have the number values replaced with human-readable text, but it's not the most interesting thing anyway.
The "Size" of the Collectable is split into two parts. One is the fixed size that every instance of the given type has. The other is any extra data an instance of this type may have attached to it, that's not a Collectable itself. This would be the case for arrays and hashes, as well as buffers and many "internal" objects.
Finally, the "References" field shows how many Collectables are referred to by the Collectable in question (outgoing references) and how many Collectables reference this object in question.
Below that there are two buttons,
Network. The former was explained further above, and the latter will get its own little section in this blog post.
Finally, the bottom of the panel is dedicated to a list of all references - outgoing or incoming - grouped by what the reference means, and what type it references.
In this example you see that the frame of the function
elementary2d.p6 on line 87 references a couple of variables (
&inv), the frame that called this frame (
step), an outer frame (
MAIN), and a code object. The right pane shows the incoming references. For incoming references, the name of the reference isn't available (yet), but you can see that 7 different objects are holding a reference to this frame.
The newest part of the heap snapshot UI is the Network View. It allows the user to get a "bird's eye" view of many objects and their relations to each other.
Here's a screenshot of the network view in action:
The network view is split into two panes. The pane on the left lists all types present in the network currently. It allows you to give every type a different symbol, a different color, or optionally make it invisible. In addition, it shows how many of each type are currently in the network display.
The right pane shows the objects, sorted by how far they are from the root (object 0, the one in Layer 0, with the frog icon).
Each object has one three-piece button. On the left of the button is the icon representing the type, in the middle is the object ID for this particular object, and on the right is an icon for the "relation" this object has to the "selected" object:
This view was generated for object 46011 (in layer 4, with a hamburger as the icon). This object gets the little "map marker pin" icon to show that it's the "center" of the network. In layers for distances 3, 2, and 1 there is one object each with a little icon showing two map marker pins connected with a squiggly line. This means that the object is part of the shortest path to the root. The third kind of icon is an arrow pointing from the left into a square that's on the right. Those are objects that refer to the selected object.
There is also an icon that's the same but the arrow goes outwards from the square instead of inwards. Those are objects that are referenced by the selected object. However, there is currently no button to have every object referenced by the selected object put into the network view. This is one of the next steps I'll be working on.
Customizing the colors and visibility of different types can give you a view like this:
And here's a view with more objects in it:
Interesting observations from this image:
- Most objects referencing the central object (the stroopwafel in layer 8) are actually farther from the root (layers for distance 9 through 15).
- Not every layer has objects in it; in this case layers for distances 12 and 14 are empty.
You have no doubt noticed that the buttons for collectables are very different between the network view and the type/frame lists and the explorer. The reason for that is that I only just started with the network view and wanted to display more info for each collectable (namely the icons to the left and right) and wanted them to look nicer. In the explorer there are sometimes thousands of objects in the reference list, and having big buttons like in the network view could be difficult to work with. There'll probably have to be a solution for that, or maybe it'll just work out fine in real-world use cases.
On the other hand, I want the colors and icons for types to be available everywhere, so that it's easier to spot common patterns across different views and to mark things you're interested in so they stand out in lists of many objects. I was also thinking of a "bookmark this object" feature for similar purposes.
Before most of that, the network viewer will have to become "navigable", i.e. clicking on an object should put it in the center, grab the path to the root, grab incoming references, etc.
There also need to be ways to handle references you're not (or no longer) interested in, especially when you come across an object that has thousands of them.
But until then, all of this should already be very useful!
Here's the section about the heap snapshot profiler from the original grant proposal:
- A web frontend for the heap snapshot analyzer
- Refactor how the analyzer gives data to the shell
- Result sets now have information about what each column means, for example "a number of bytes".
- Draft a concept for how the user will interact with the analyzer
- This refers mainly to how the navigator works
- UI for Per-Snapshot Summary: total heap size, total object count, etc.
- This is the "front page" with the graphs.
- UI for Top Lists for objects sorted by count or memory usage
- This is the "Type and Frame Lists".
- UI for Details of individual objects: size, pointers to other objects
- This is part of the explorer.
- UI for the shortest path that keeps an object alive
- This is also part of the explorer.
- UI for Across-Snapshot comparisons: object counts over time, etc.
- I think I will allow the left and right pane of the explorer to refer to different snapshots, which will allow comparing similar objects. Additionally, the user can open as many windows or tabs with the heap snapshot UI in it and switch freely between them in their regular web browser.
- UI for Heap Exploration: Find all objects of a specific type, etc.
- This is reachable from the "Type and Frame Lists".
- Functionality for finding paths from one object to all roots that reach it.
- The network view will allow getting the path to every object with a reference to the given object, which will fulfill this purpose.
- UI for whole parts of the network, like multiple paths to a single object.
- This is the network view.
- If an instrumented profile is also loaded
(this is currently not supported by moarperf)
- Links from types to routines allocating the type
- Links from frames (closures for example) to the call graph
- Refactor how the analyzer gives data to the shell
Looking at the list, it seems like the majority of intended features are already available or will be very soon!
Until now the user had to download
You can now visit the releases page on github to grab a tarball with all the files you need! Just install all backend dependencies with
zef install --deps-only . and run
And with that I'm already done for this report!
It looks like the heap snapshot portion of the grant is quite a bit smaller than the profiler part, although a lot of work happened in moarvm rather than the UI. I'm glad to see rapid progress on this.
I hope you enjoyed this quick look at the newest pieces of moarperf!