Analyze CPU samples in Timing Captures

PIX includes a CPU sampling profiler that you can optionally run when you take a Timing Capture. CPU samples help you find what code runs during a Timing Capture, including code that isn't surrounded by PIX events. Use samples to inspect individual call stacks, aggregate hot functions over a selected time range, restrict the analysis to one or more PIX events, and map sampled functions back to source lines.

CPU samples are useful in several scenarios:

  • Find what code runs on a thread or core during parts of your title that have sparse or no PIX event instrumentation. Diagnosing these regions with samples is faster than adding more instrumentation and then rebuilding and redeploying your title.
  • Aggregate the samples from a relatively long capture to find which functions run most frequently and which take the longest to execute.
  • Use the C++ source view to attribute samples to individual source lines and find the hot spots within a function.

Before collecting samples, make sure PIX can find the PDBs for your title. PIX uses symbol information to resolve function names and source locations. For setup instructions, see Configure PIX to access PDBs for Timing Captures.

Collect CPU samples

To collect CPU samples, enable CPU Samples in the CPU section of the Timing Capture options pane, and then choose a sampling rate. PIX shows the PC sampling rates as:

  • 1 k/sec: low impact.
  • 4 k/sec: balanced.
  • 8 k/sec: maximum data.

Higher sampling rates provide more data, but they also add more capture overhead. Choose the lowest rate that gives enough detail for the question you're investigating.

After you open a capture that contains CPU samples, PIX shows sample data in:

  • The Timeline view.
  • The Element Details view.
  • The Range Details view.

Inspect individual samples in the Timeline

PIX shows individual CPU samples as short vertical lines on Core and Thread lanes in the Timeline view. Select a sample to populate Element Details with the sample time, thread, core, and call stack.

Individual samples are useful when a long PIX event has little or no child instrumentation. For example, if a RunSimulation event covers several milliseconds but doesn't contain more detailed PIX events, select samples inside that event to see which functions were executing during that time. The call stack of one such sample might show that a function named UpdateEnemyPositions is running and is allocating memory with operator new.

You can customize sample display from the gear icon next to a Thread or Core lane or from the Lane Configuration panel:

  • Show Samples shows or hides individual sample markers.
  • Sample Height changes the marker height.
  • Show Sampled Functions shows aggregated sampled-function fragments on Thread lanes when enough samples are present.

Analyze sampled functions over a time range

To aggregate samples over a time range:

  1. In the Timeline view, drag to select the time range you want to analyze.
  2. In Range Details, set Item Type: to Sampled Functions.
  3. Use the Display Options panel to choose how PIX organizes the sampled functions.

PIX aggregates all samples that occurred in the selected range across all threads and cores. You can view the aggregated samples either as a stack tree or as a flat function list, and you can change which samples are included and how they're organized:

The default Stack Tree view shows which sampled call stacks occurred most often in the selected range. For each function, PIX shows the number of samples that landed in the function, both inclusive and exclusive, along with the inclusive and exclusive percentages. The main columns include:

  • Inc. % and Inc. #: samples that occurred in the function or its callees.
  • Exc. % and Exc. #: samples that occurred directly in the function.
  • Threads: the number of threads represented by the function entry.
  • Module: the module that contains the function.

For example, an Inc. % value of 33.33% on UpdateEnemyPositions means that a third of the samples in the selected range occurred in UpdateEnemyPositions or in functions it called.

To see a flat list of functions rather than a call tree, open the Display Options panel and switch the slider from Stack Tree to Function List. You can also show or hide columns; for details, see The Range Details view.

Group by thread or core

By default, Sampled Functions aggregates samples from all included threads and cores. When you want to focus on the samples from only a subset of threads or cores, use Group By: in Display Options to split the stack tree by:

  • None.
  • Cores.
  • Threads.
  • Cores, Threads.

When you select a grouping option, PIX reorganizes the stack tree so that there's one root node per thread or core. For example, when you group by Threads, each root node contains the samples collected on a single thread.

Grouping is useful when the same hot function appears on multiple worker threads or when you need to understand whether work is concentrated on specific cores.

Focus on one function

Use a focus function when you want the selected function to become the root of the sampled stack tree. PIX rebuilds the stack tree from all calls to that function and shows the function's entire call tree as its children. Use this view to find the call paths below the function that are called most frequently or take the longest to execute.

  1. In Range Details, right-click a function.
  2. Select Set Focus Function.
  3. Inspect the call paths below the focused function.

PIX keeps the other sampled-function options available after you set a focus function. You can still change Group By: or filter by PIX events. Use Clear Focus Function or the clear button next to the focus display to return to the normal tree.

If a capture includes heterogeneous-core information, the selected function details also show performance-core and efficiency-core percentages for inclusive and exclusive samples.

Filter sampled functions by PIX events

The PIX Events: filter in Display Options restricts sampled-function analysis to samples that occurred while any selected PIX event was running. This lets you analyze the functions that ran between calls to PIXBeginEvent and PIXEndEvent.

To filter sampled functions by PIX events:

  1. Select a time range in the Timeline view.
  2. In Range Details, set Item Type: to Sampled Functions.
  3. Open Display Options.
  4. In PIX Events:, type part of an event name to filter the list, and then select one or more event names. The search is case-insensitive and matches any part of the name. For example, type Update to list only the events whose names contain Update.
  5. Select Apply to rebuild the sampled-function tree or function list. Select Clear to remove the selection.

If your title emits many distinct PIX event names, the list initially shows Too many items, use filter to narrow search instead of event names. Type a more specific search string to narrow the list.

The filter uses every instance of the selected event names that overlaps the selected time range. If you select more than one event name, samples from any selected event are included.

Use this filter when a PIX event identifies the scenario you care about, but the event doesn't contain enough child instrumentation to explain its cost. For example, filter to a Physics::Process event to analyze only the samples that occurred while instances of that event were executing, and then inspect the stack tree for hot call paths such as allocation or container work.

Tip

If the selected PIX event can run on multiple threads or cores, also use Group By: to split the filtered results by Threads, Cores, or Cores, Threads.

Open source analysis for a sampled function

The Source Analysis tab maps sampled-function data back to C++ source lines so you can find a function's hot spots: the lines of code on which most samples landed.

To open source analysis:

  1. In Range Details, select a function in Sampled Functions.
  2. In Element Details, switch from the Details tab to the Source Analysis tab.

PIX uses the source file path stored in your title's PDB to load the matching source file, and then highlights lines that contributed samples. The highlight opacity is based on the percentage of samples attributed to the line, so the bolder the highlight, the more often that line was executing when a sample was taken. The gutter shows either sample counts or percentages. By default, it shows percentages.

To change the source-analysis value display:

  1. Open the Element Details Display Options panel.
  2. Under Source Analysis Options, switch between Value and Percentage.

If PIX can't find the source file that matches the checksum stored in the PDB, Source Analysis shows a message like Could not find file Foo.cpp with matching checksum. Add source directories to Source Paths in Source Analysis Options or on the PIX Settings page, and then reopen or refresh the source analysis.