{"id":5068,"date":"2020-10-22T15:36:45","date_gmt":"2020-10-22T22:36:45","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/pix\/?page_id=5068"},"modified":"2020-10-28T11:16:35","modified_gmt":"2020-10-28T18:16:35","slug":"analyzing-memory-usage-and-performance-in-timing-captures","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/pix\/analyzing-memory-usage-and-performance-in-timing-captures\/","title":{"rendered":"Analyzing Memory usage and performance in Timing Captures"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/timing-captures-new\/\">PIX Timing Captures<\/a> include options to record information on the memory allocations and frees made while the capture is running. This memory data is used to compute a set of memory-related counters that can be graphed in the Metrics View and to build an allocation stack tree and virtual memory allocations list in the Range Details view.<\/p>\n<p>The combination of the memory counters and the allocation tree can help you analyze your title\u2019s memory usage and to find memory leaks. A typical usage pattern is to use the counters in the Metrics View to find periods of time where something unexpected is occurring, then use the Metrics View\u2019s context menu to navigate to that period in the Timeline to view the allocation stack tree.<\/p>\n<h3>Collecting memory allocation data<\/h3>\n<p>The Timing Capture options pane contains checkboxes you can use to select whether to collect memory data for calls to VirtualAlloc and HeapAlloc.<\/p>\n<p>To collect memory allocation data, select the allocators you\u2019d like to track and start the capture.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_options.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5072\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_options.png\" alt=\"Image pix timing capture memory options\" width=\"388\" height=\"463\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_options.png 388w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_options-251x300.png 251w\" sizes=\"(max-width: 388px) 100vw, 388px\" \/><\/a><\/p>\n<h3>Memory counters in the Metrics view<\/h3>\n<p>When one or more of the memory collection options are enabled, PIX gathers and computes several memory-related counters and adds them to the Metrics View. Three sets of counters are computed:<\/p>\n<ul>\n<li>Event Rate<\/li>\n<li>Memory Usage<\/li>\n<li>Unfreed allocations<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>All of these counters are separated by allocator and can be found in the CPU Memory section of the Metrics View Selector panel as shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_metrics.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5073\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_metrics.png\" alt=\"Image pix timing capture memory metrics\" width=\"244\" height=\"361\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_metrics.png 244w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_capture_memory_metrics-203x300.png 203w\" sizes=\"(max-width: 244px) 100vw, 244px\" \/><\/a><\/p>\n<p>The <strong>Event Rate<\/strong> counters show the rate of memory allocations over the duration of the capture for each allocator. For example, the following figure shows there are numerous points in the time where the HeapAlloc allocator makes bursts of memory allocations.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_event_rate_metric.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5075\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_event_rate_metric.png\" alt=\"Image pix timing memory event rate metric\" width=\"684\" height=\"518\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_event_rate_metric.png 684w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_event_rate_metric-300x227.png 300w\" sizes=\"(max-width: 684px) 100vw, 684px\" \/><\/a><\/p>\n<p>The <strong>Memory Usage<\/strong> counters shows the amount of memory used over the duration of the capture for each allocator. For example, the following figure shows a steady stair step pattern of growth for allocations made using VirtualAlloc.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_memory_usage_metric.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5076\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_memory_usage_metric.png\" alt=\"Image pix timing memory memory usage metric\" width=\"993\" height=\"500\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_memory_usage_metric.png 993w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_memory_usage_metric-300x151.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_memory_usage_metric-768x387.png 768w\" sizes=\"(max-width: 993px) 100vw, 993px\" \/><\/a><\/p>\n<p>The <strong>Unfreed allocations<\/strong> counter displays the number of unfreed allocations in the capture, shown by the time at which the allocation was made. For example, the following figure shows several points in time where allocations were made but were not freed before the end of the capture.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_unfreed_allocations_metric.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5097\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_unfreed_allocations_metric.png\" alt=\"Image pix timing memory unfreed allocations metric\" width=\"898\" height=\"696\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_unfreed_allocations_metric.png 898w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_unfreed_allocations_metric-300x233.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_unfreed_allocations_metric-768x595.png 768w\" sizes=\"(max-width: 898px) 100vw, 898px\" \/><\/a><\/p>\n<p>After using the <strong>Metrics View<\/strong> to identify periods of time that may be interesting from a memory perspective, the context menu can be used to navigate to that period of time in the <strong>Timeline<\/strong>. In the following figure, a period of time in which unfreed allocations occurred is selected in the <strong>Metrics View<\/strong> and then synchronized with the <strong>Timeline<\/strong>. When in the <strong>Timeline<\/strong>, the <strong>Range Details<\/strong> view can be used to view the <strong>Allocation Stack Tree<\/strong>. In this example, <strong>Range Details<\/strong> shows a non-zero Unfree Size for VirtualAlloc as expected. Expand the <strong>Allocation Stack Tree<\/strong> to find the callstacks responsible for the unfreed memory.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5098\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view.png\" alt=\"Image pix timing memory timeline and metrics view\" width=\"1653\" height=\"791\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view.png 1653w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view-300x144.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view-1024x490.png 1024w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view-768x368.png 768w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_timeline_and_metrics_view-1536x735.png 1536w\" sizes=\"(max-width: 1653px) 100vw, 1653px\" \/><\/a><\/p>\n<h3>Analyzing memory allocations in the Range Details view<\/h3>\n<p>When collecting memory data, PIX records the callstack for each memory allocation and free. The callstacks are then aggregated into an overall allocation tree. The allocation tree can be viewed in <strong>Range Details<\/strong> view in Timing Captures. To view the tree, select a range of time in the <strong>Timeline<\/strong>, then select <strong>Allocation Stack Tree<\/strong> from the Items to show dropdown. The allocation tree displayed in <strong>Range Details<\/strong> will include all allocations that occurred within the selected time range.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_items_to_show_view.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5101\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_items_to_show_view.png\" alt=\"Image pix timing memory items to show view\" width=\"838\" height=\"429\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_items_to_show_view.png 838w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_items_to_show_view-300x154.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_items_to_show_view-768x393.png 768w\" sizes=\"(max-width: 838px) 100vw, 838px\" \/><\/a><\/p>\n<p>The stacks displayed in <strong>Range Details<\/strong> are grouped first by allocator. This grouping keeps allocations and frees made with HeapAlloc separate from those made using VirtualAlloc. Each allocator is a top level node in the allocation stack tree. Use the <strong>Selector<\/strong> panel on the left hand side of the view to specify which allocators should be displayed in the tree.<\/p>\n<p>The HeapAlloc node is further grouped by heap handle, making it easy to analyze memory usage on a per-heap basis.<\/p>\n<p>The following figure shows the organization of the <strong>Allocation Stack Tree<\/strong>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5102\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization.png\" alt=\"Image pix timing memory allocation tree organization\" width=\"1091\" height=\"332\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization.png 1091w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization-300x91.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization-1024x312.png 1024w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_organization-768x234.png 768w\" sizes=\"(max-width: 1091px) 100vw, 1091px\" \/><\/a><\/p>\n<p>Expanding the tree displays the aggregated stacks for all allocations attributed to that allocator for the selected time range. The values for the <strong>Unfreed Size<\/strong>, <strong>Allocated Size<\/strong>, and <strong>Allocation Count<\/strong> columns are always relative to the node in the tree that is currently selected. The following picture shows that the function <strong>LeakMemorySometimes<\/strong> made 289memory allocations, and that 1,468,006,400 bytes from those allocations were not freed by the end of the capture. Furthermore, the stack tree indicates that <strong>LeakMemorySomtimes<\/strong> was called as part of two distinct callstacks. The first callstack goes through the <strong>Process<\/strong> function, while the second callstack goes through <strong>UpdateEnemyPositions<\/strong>. Looking at the <strong>Unfreed Size<\/strong> column for those two functions indicates that all of the unfreed memory came from the first callstack, the one that includes <strong>Process<\/strong>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5107\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2.png\" alt=\"Image pix timing memory allocation tree with leaks2\" width=\"1108\" height=\"325\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2.png 1108w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2-300x88.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2-1024x300.png 1024w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_allocation_tree_with_leaks2-768x225.png 768w\" sizes=\"(max-width: 1108px) 100vw, 1108px\" \/><\/a><\/p>\n<p>The <strong>Range Details<\/strong> view includes a filter bar that can be used to filter the contents of the view to only stacks that contain a specific string. In addition to string searching, the filter bar also includes a <strong>!Freed<\/strong> button that will filter the view to only those callstacks that have a non-zero value for <strong>Unfreed Size<\/strong>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5109\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter.png\" alt=\"Image pix timing memory not freed filter\" width=\"1103\" height=\"235\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter.png 1103w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter-300x64.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter-1024x218.png 1024w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_not_freed_filter-768x164.png 768w\" sizes=\"(max-width: 1103px) 100vw, 1103px\" \/><\/a><\/p>\n<p>The <strong>Display Options<\/strong> pane on the right hand side of the view enables you to customize some aspects of how the <strong>Range Details<\/strong> view displays the allocation tree. The set of columns to display can be changed, and the tree can be inverted such that the callee is shown at the top of the stack instead of at the bottom.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_range_details_display_options.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5111\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_range_details_display_options.png\" alt=\"Image pix timing memory range details display options\" width=\"645\" height=\"296\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_range_details_display_options.png 645w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_range_details_display_options-300x138.png 300w\" sizes=\"(max-width: 645px) 100vw, 645px\" \/><\/a><\/p>\n<p>In addition to the <strong>Allocation Stack Tree<\/strong>, the <strong>Range Details<\/strong> view can also be used to look at a flat list of all allocations made using VirtualAlloc. Select the <strong>Virtual Memory Allocations<\/strong> entry in <strong>Items to Show<\/strong> dropdown to view the flat list of all allocations. The list is organized by time by default and includes columns such as the allocation <strong>Size<\/strong>, the <strong>Unfreed Size<\/strong>, the <strong>Flags<\/strong> and so on as shown in the following figure.\u00a0 Selecting an allocation in the <strong>Range Details<\/strong> view populates the <strong>Element Details<\/strong> view with the callstack of the allocation.\u00a0 A link to the corresponding calls to VirtualFree are also provided, if applicable.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-5113\" src=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations.png\" alt=\"Image pix timing memory virtual memory allocations\" width=\"1513\" height=\"539\" srcset=\"https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations.png 1513w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations-300x107.png 300w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations-1024x365.png 1024w, https:\/\/devblogs.microsoft.com\/pix\/wp-content\/uploads\/sites\/41\/2020\/10\/pix_timing_memory_virtual_memory_allocations-768x274.png 768w\" sizes=\"(max-width: 1513px) 100vw, 1513px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PIX Timing Captures include options to record information on the memory allocations and frees made while the capture is running. This memory data is used to compute a set of memory-related counters that can be graphed in the Metrics View and to build an allocation stack tree and virtual memory allocations list in the Range [&hellip;]<\/p>\n","protected":false},"author":1915,"featured_media":4769,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[],"tags":[],"class_list":["post-5068","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry"],"acf":[],"blog_post_summary":"<p>PIX Timing Captures include options to record information on the memory allocations and frees made while the capture is running. This memory data is used to compute a set of memory-related counters that can be graphed in the Metrics View and to build an allocation stack tree and virtual memory allocations list in the Range [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/posts\/5068","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/users\/1915"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/comments?post=5068"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/posts\/5068\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/media\/4769"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/media?parent=5068"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/categories?post=5068"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/pix\/wp-json\/wp\/v2\/tags?post=5068"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}