As mentioned in Basic Concepts,
the main idea behind timeline profiling is collecting temporal call stack
and thread state data. Thus, it allows you not only evaluate the performance of certain methods but also get
detailed info about how performance flaws are distributed in time. This is extremely helpful in analyzing UI freezes,
sync delays, excessive garbage collections, file I/O, and other interval events.
Timeline Viewer UI is tailored for convenient work with the event timeline: It is a set of filters and
diagrams that allows you to filter and visualize temporal data.
Analysis workflow in Timeline Viewer is quite simple:
You select profiling data on input.
This can be either Time
data, Memory Allocation data, or data about raised Exceptions.
You slice and dice the data using filters (not only using Filters -
Timeline and Call Stack can also add filtering by time, thread, or particular method). The result of filters' work is always a set of time intervals or
point events selected by a specific condition.
For example, you can ask the viewer to "Select all time intervals where the Main thread is running"
or "Select all time intervals where blocking garbage collection is performed".
You view and analyze the filtered data.
Here we come to a couple of concepts you need to know for successful data analysis in Timeline Viewer.
Everything Is a Filter
Both steps 2 and 3 are performed using the same UI controls.
Thus, each control is used not only to set a specific filter but also to display a chunk of filtered information.
For example, the Thread State filter not only allows you to apply a filter by thread state
but also displays how long selected threads were in particular states.
Filters Are Chained Together
Filters can be grouped in chains.
Complex filter combinations allow you to analyze almost any aspect of your app.
For example, if you combine the "Select all time intervals where the Main thread is running"
and "Select all time intervals where blocking garbage collection is performed" filters,
you will get the resulting filter "Select all time intervals where the Main thread is running during garbage collections".
In other words, this filter combination will leave only the time intervals where the Main thread toggled GCs. The
Call Stack | Top Methods filter will show you the exact methods that toggled collections.
How This Works. Example
For example, you have an app running three threads: Main Thread, Thread#1, and Thread#2.
Your app extensively works with file system: it reads and writes to disk a lot, which results in poor app performance. You decide
to profile the app and find the methods that can be optimized.
How This Looks in Timeline Viewer
1. You run dotTrace and profile your app during the performance drop. For simplicity, let's take that
profiling lasted 100 ms.
The Threads diagram looks like follows:
It appears that most of the profiling time all three threads worked (blue intervals). There were also
time intervals where threads waited (pale blue).
2. You look at Interval Filters
in the Filters window to determine events that took place in the app.
show that File I/O
was quite significant and took 100 ms - 33.33% of the total analyzed
time interval (which is equal 300 ms = 3 threads * 100 ms profiling time).
3. You select
File I/O in Interval Filters
to apply filter by file I/O operations.
The filter you get is "Select all time intervals where Main Thread, Thread#1, and
Thread#2 performed file operations."
After you apply the filter, the values in all filters are recalculated related to the file I/O time.
For example, the
value of 95.00% says that almost all file operations were performed by your own code.
The Threads diagram also filters out the file I/O intervals:
It appears that the majority of file operations (80.00%) were performed by Thread#2.
4. You select Thread#2 in the
to apply the filter by this thread. The resulting filter you get is
"Select all time intervals where Thread#2 performed file I/O operations".
The Threads diagram filters out the thread:
Interval Filters are also recalculated related to Thread#2:
Thus, 100.00% of User Code
say that all Thread#2 file operations were performed by your own code.
5. You look at Top Methods
in the Call Stack window to determine methods that performed file operations.
The filter shows that 90.00% of file operations were performed by MyApp.SomeReadMethod.
It might also be worth to investigate
Call Tree and find out who calls MyApp.SomeReadMethod. This makes sense as
is probably a simple low level method that only reads from disk.
6. You optimize the MyApp.SomeReadMethod method or the methods that call it in order to reduce the amount of