You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/learning-paths/laptops-and-desktops/win_profile_guided_optimisation/_index.md
+7-11Lines changed: 7 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,22 +1,18 @@
1
1
---
2
2
title: Optimize C++ applications on Windows on Arm using Profile-Guided Optimization
3
3
4
-
draft: true
5
-
cascade:
6
-
draft: true
7
-
8
4
minutes_to_complete: 30
9
5
10
-
who_is_this_for: This is an introductory topic for software developers who want to optimize C++ application performance on Windows on Arm using profile-guided optimization.
6
+
who_is_this_for: This is an introductory topic for software developers who want to optimize C++ application performance on Windows on Arm using Profile-Guided Optimization (PGO).
11
7
12
8
learning_objectives:
13
-
- Microbenchmark a function using Google Benchmark.
14
-
- Apply profile-guided optimization to build performance-tuned binaries for Windows on Arm.
15
-
- Measure and compare performance improvements from PGO-optimized builds.
9
+
- Microbenchmark a function using Google Benchmark
10
+
- Apply profile-guided optimization to build performance-tuned binaries for Windows on Arm
11
+
- Measure and compare performance improvements from PGO-optimized builds
16
12
17
13
prerequisites:
18
-
- Basic C++ understanding.
19
-
- A Windows on Arm machine with [Visual Studio](/install-guides/vs-woa/) and the C++ desktop development tools installed.
14
+
- Familiarity with C++ development and compiling programs from the command line
15
+
- A Windows on Arm machine with [Visual Studio](/install-guides/vs-woa/) and the C++ desktop development tools installed
Copy file name to clipboardExpand all lines: content/learning-paths/laptops-and-desktops/win_profile_guided_optimisation/how-to-1.md
+9-5Lines changed: 9 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,5 @@
1
1
---
2
-
title: Profile-Guided Optimization
2
+
title: Understand Profile-Guided Optimization
3
3
weight: 2
4
4
5
5
### FIXED, DO NOT MODIFY
@@ -14,17 +14,17 @@ First, you compile your program to produce an instrumented binary that collects
14
14
15
15
This approach identifies frequently executed paths (known as "hot" paths) and optimizes them more aggressively, while reducing emphasis on less critical code paths.
16
16
17
-
## How does PGO improve performance?
17
+
## How PGO improves performance on Windows on Arm
18
18
19
19
PGO enables several compiler optimizations that aren't possible with static analysis alone.
20
20
21
-
The compiler arranges frequently executed code together in memory through code layout optimization, which improves instruction cache utilization and reduces branch mispredictions. Instead of using heuristics for inlining decisions, the compiler inlines functions based on actual call frequency and execution patterns from your profiling data.
21
+
Code layout optimization arranges frequently executed code together in memory, improving instruction cache utilization and reducing branch mispredictions. Instead of using heuristics for inlining decisions, the compiler inlines functions based on actual call frequency and execution patterns from your profiling data.
22
22
23
23
For C++ virtual functions, PGO can identify the most common call targets and optimize or devirtualize those paths. The compiler can also eliminate dead code by optimizing differently or removing code paths that never execute in your profiling runs.
24
24
25
-
For example, if your application has an error handling path that rarely executes, PGO ensures the compiler doesn't optimize for that path at the expense of your main execution flow. The result is typically 5-15% performance improvement, though gains vary by application.
25
+
If your application has an error handling path that rarely executes, PGO ensures the compiler doesn't optimize for that path at the expense of your main execution flow. Performance improvements typically range from 5-15%, though results vary by workload and architecture.
26
26
27
-
## When should you use Profile-Guided Optimization?
27
+
## When to use PGO on Arm
28
28
29
29
You'll find PGO particularly beneficial in the later stages of development when real-world workloads are available. It's especially useful for applications where performance is critical and runtime behavior is complex or data-dependent.
30
30
@@ -39,3 +39,7 @@ Your profiling data must accurately represent typical usage scenarios. If it doe
39
39
Additionally, the process requires extra build steps, which can increase compile times for large codebases. Use PGO on performance-critical sections that are heavily influenced by actual runtime behavior.
40
40
41
41
PGO might not be ideal for early-stage development or applications with highly variable or unpredictable usage patterns.
42
+
43
+
## What you've accomplished and what's next
44
+
45
+
You now understand what PGO is, how it improves performance through code layout and inlining optimizations, and when to apply it. In the next section, you'll learn about Google Benchmark, the tool you'll use to measure these performance improvements.
Copy file name to clipboardExpand all lines: content/learning-paths/laptops-and-desktops/win_profile_guided_optimisation/how-to-2.md
+14-6Lines changed: 14 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,15 +6,21 @@ weight: 3
6
6
layout: learningpathall
7
7
---
8
8
9
+
## Overview
10
+
9
11
Before you start working with Profile-Guided Optimization, you need to understand how to measure performance. This section introduces Google Benchmark, the tool you'll use to measure the impact of your optimizations. Don't worry about installing anything yet. You'll set up your environment and run your first benchmark in the next section.
10
12
13
+
## What is Google Benchmark?
14
+
11
15
Google Benchmark is a C++ library specifically designed for microbenchmarking, which means measuring the performance of small code snippets with high accuracy. Microbenchmarking helps you identify bottlenecks and optimize critical sections, especially in performance-sensitive applications.
12
16
13
-
Google Benchmark simplifies this process by providing a framework that manages iterations, times execution, and performs statistical analysis. This lets you focus on the code being measured, rather than writing test code or trying to prevent unwanted compiler optimizations manually.
17
+
Google Benchmark simplifies this process by providing a framework that manages iterations, times execution, and performs statistical analysis. You can focus on the code being measured, rather than writing test code or trying to prevent unwanted compiler optimizations manually.
14
18
15
-
To use Google Benchmark, you define a function that accepts a `benchmark::State&` parameter and iterate over it to perform the benchmarking. You register the function using the `BENCHMARK` macro and include `BENCHMARK_MAIN()` to generate the benchmark's entry point.
19
+
## Write a simple benchmark
16
20
17
-
This example shows a basic benchmark that measures the time it takes to create an empty string:
21
+
To use Google Benchmark, define a function that accepts a benchmark::State& parameter and use it to run the benchmark in a loop. You register the function using the `BENCHMARK` macro and include `BENCHMARK_MAIN()` to generate the benchmark's entry point.
22
+
23
+
The following example shows a basic benchmark that measures the time it takes to create an empty string. A minimal benchmark looks like this:
18
24
19
25
```cpp
20
26
#include<benchmark/benchmark.h>
@@ -28,7 +34,7 @@ BENCHMARK(BM_StringCreation);
28
34
BENCHMARK_MAIN();
29
35
```
30
36
31
-
## Filter benchmarks and prevent compiler optimizations
37
+
## Control benchmark execution
32
38
33
39
Google Benchmark provides tools to ensure accurate measurements by preventing unintended compiler optimizations and allowing flexible benchmark selection.
34
40
@@ -40,6 +46,8 @@ When you have multiple benchmarks, you can run a specific subset using the `--be
40
46
.\benchmark_binary --benchmark_filter=BM_String.*
41
47
```
42
48
43
-
This approach eliminates the need to repeatedly comment out lines of source code when you want to focus on specific benchmarks.
49
+
Filtering eliminates the need to repeatedly comment out lines of source code when you want to focus on specific benchmarks.
50
+
51
+
## What you've accomplished and what's next
44
52
45
-
Now that you understand how Google Benchmark works, you're ready to install it and run your first benchmark. In the next section, you'll set up your environment and use Google Benchmark with Profile-Guided Optimization to measure and improve performance.
53
+
You now understand how to write basic benchmarks with Google Benchmark, use `benchmark::DoNotOptimize` to prevent unwanted compiler optimizations, and filter benchmark execution with command-line options. In the next section, you'll install Google Benchmark and create a baseline benchmark to measure division performance on Windows on Arm.
Copy file name to clipboardExpand all lines: content/learning-paths/laptops-and-desktops/win_profile_guided_optimisation/how-to-3.md
+19-9Lines changed: 19 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,17 +6,21 @@ weight: 4
6
6
layout: learningpathall
7
7
---
8
8
9
-
In this section, you'll create a baseline benchmark to measure the performance of a division operation. This baseline will help you see the improvement when you apply Profile-Guided Optimization in the next section. This example demonstrates how even seemingly straightforward operations can benefit from optimization techniques.
9
+
## Overview
10
+
11
+
In this section, you'll create a baseline benchmark to measure the performance of a division operation. This baseline allows you to measure the improvement when you apply profile-guided optimization in the next section.
10
12
11
13
Integer division is ideal for benchmarking because it's significantly more expensive than operations like addition, subtraction, or multiplication. On most CPU architectures, including Arm, division instructions have higher latency and lower throughput compared to other arithmetic operations. By applying Profile-Guided Optimization to code containing division operations, you can achieve significant performance improvements.
12
14
13
15
For this example, you'll use an Arm computer running Windows.
14
16
15
-
## Install the required tools
17
+
## Set up Google Benchmark on Windows on Arm
18
+
19
+
Before you can run benchmarks, you need to install vcpkg (a C++ package manager) and Google Benchmark. This is a one-time setup step.
16
20
17
21
### Install vcpkg and Google Benchmark
18
22
19
-
Run the following commands in PowerShell:
23
+
The following commands download and initialize vcpkg, create a project directory, and install Google Benchmark for Windows on Arm:
20
24
21
25
```console
22
26
iex (iwr -useb https://aka.ms/vcpkg-init.ps1)
@@ -54,27 +58,29 @@ BENCHMARK(baseDiv)->Arg(1500)->Unit(benchmark::kMicrosecond); // value of 1500 i
54
58
BENCHMARK_MAIN();
55
59
```
56
60
57
-
## Compile and run the baseline benchmark
61
+
## Compile the baseline benchmark with MSVC
58
62
59
63
Open an **ARM64 Native Tools Command Prompt** from the Windows Start menu and start PowerShell:
60
64
61
65
```console
62
66
powershell
63
67
```
64
68
65
-
Before compiling, set an environment variable to refer to the vcpkg installation directory:
69
+
Set an environment variable to refer to the vcpkg-installed package directory for the ARM64 Windows target. This simplifies the compiler commands that follow:
The baseline shows an average execution time of 7.90 microseconds. This gives you a clear starting point to measure improvement. Now that you have this baseline measurement, you're ready to apply Profile-Guided Optimization. In the next section, you'll use PGO to optimize this code and see how much faster it can run.
108
+
The warning appears because the Google Benchmark library was built in debug mode, but it doesn't affect the validity of the measurements for this example.
109
+
110
+
## What you've accomplished and what's next
111
+
112
+
You've set up Google Benchmark on Windows on Arm, created a division-heavy benchmark, and established a baseline performance measurement of 7.90 microseconds. This baseline gives you a clear reference point to measure the impact of Profile-Guided Optimization. In the next section, you'll apply PGO to this code and measure the performance improvement.
Copy file name to clipboardExpand all lines: content/learning-paths/laptops-and-desktops/win_profile_guided_optimisation/how-to-4.md
+21-7Lines changed: 21 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,11 +6,19 @@ weight: 5
6
6
layout: learningpathall
7
7
---
8
8
9
+
## Overview
10
+
9
11
Now that you have a baseline benchmark, you're ready to apply Profile-Guided Optimization. The PGO process involves three steps: build an instrumented binary, run it to collect profile data, and rebuild with optimizations based on that data.
10
12
11
-
## Build the instrumented binary
13
+
## Build instrumented binary with MSVC
14
+
15
+
Open an **ARM64 Native Tools Command Prompt** from the Windows Start menu and start PowerShell if it's not already open. If you're starting a new session, navigate to your project directory and set the `$VCPKG` environment variable again:
12
16
13
-
You should already have an ARM64 Native Tools Command Prompt open with PowerShell running from the previous section.
This command uses several important compiler and linker options. The `/O2` flag creates fast code, while `/GL` enables whole program optimization. The `/GENPROFILE` linker option generates a `.pgd` file for PGO, and `/LTCG` specifies link time code generation. The `/PGD` option specifies the database file where profile data will be stored.
22
30
23
-
## Collect profile data
31
+
## Collect PGO profile data on Windows on Arm
24
32
25
33
Run the instrumented binary to generate profile data:
26
34
@@ -30,7 +38,7 @@ Run the instrumented binary to generate profile data:
30
38
31
39
This execution creates profile data files (typically with a `.pgc` extension) in the same directory. The profile data captures information about which code paths execute most frequently and how the program behaves at runtime.
32
40
33
-
## Rebuild with optimizations
41
+
## Rebuild with PGO optimizations
34
42
35
43
Now recompile the program using the `/USEPROFILE` flag to apply optimizations based on the collected data:
The `/USEPROFILE` linker option instructs the linker to enable PGO with the profile generated during the previous run. The compiler can now make informed decisions about code layout, inlining, and other optimizations based on actual runtime behavior.
42
50
43
-
## Measure the improvement
51
+
## Measure PGO performance gains
44
52
45
53
Run the optimized binary to see the performance improvement:
46
54
@@ -66,6 +74,12 @@ Benchmark Time CPU Iterations
66
74
baseDiv/1500 2.86 us 2.86 us 244429
67
75
```
68
76
69
-
The average execution time is reduced from 7.90 to 2.86 microseconds, which is a 64% improvement. This significant gain occurs because the profile data informed the compiler that the input divisor was consistently 1500 during the profiled runs, allowing it to apply specific optimizations that wouldn't be possible with static analysis alone.
77
+
The warning appears because the Google Benchmark library was built in debug mode, but it doesn't affect the validity of the measurements.
78
+
79
+
The average execution time is reduced from 7.90 to 2.86 microseconds, which is a 64% improvement. This result was measured on a Windows on Arm device with Visual Studio 2022 (MSVC 17.0) using the division benchmark with a constant divisor of 1500. Your results may vary depending on your specific hardware and workload.
80
+
81
+
The compiler used the profile data to determine that the divisor was consistently 1500, enabling optimizations that wouldn't be possible with static analysis alone.
82
+
83
+
## What you've accomplished
70
84
71
-
You've successfully used Profile-Guided Optimization to improve performance on Windows on Arm. This same technique can be applied to your own performance-critical code to achieve similar improvements.
85
+
You've applied PGO to reduce execution time by 64% on a division-heavy benchmark. You completed the full PGO workflow: instrument, profile, and optimize. Apply this same technique to performance-critical sections of your own code to achieve similar gains on Windows on Arm.
0 commit comments