Profile a Windows MinGW Program with gprof
You will build a small Windows executable with MinGW profiling enabled, run it on Windows to create gmon.out, then use the installed cross-target gprof on Linux to inspect the flat profile and call graph. Allow 20 to 30 minutes, plus time to run the executable through the workload you actually care about.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide was checked with GNU Binutils 2.41.90.20240122, from Debian package binutils-mingw-w64-x86-64 version 2.41.90.20240122-1ubuntu1+11.4. The alias x86_64-w64-mingw32ucrt-gprof refers to the same canonical manpage, so the commands below use x86_64-w64-mingw32-gprof.
1. Check the toolchain
Confirm that the cross-compiler and profiler are available. This check changes nothing and does not need elevated privileges:
$ command -v x86_64-w64-mingw32-gcc
$ command -v x86_64-w64-mingw32-gprof
$ x86_64-w64-mingw32-gprof --version
GNU gprof (GNU Binutils) 2.41.90.20240122
The executable and its profile must describe the same build. Keep the executable, its debugging information and the resulting gmon.out together. A profile is not useful if it came from a different binary.
2. Build with profiling enabled
Create a test program, or apply the same compiler option to your real source. The key option is -pg; it arranges for profiling support to be linked into the program as well as marking the compilation for profiling.
#include <stdio.h>
static long transform(long value)
{
long result = value;
for (long i = 0; i < 200000; ++i) {
result = (result * 33 + i) % 1000003;
}
return result;
}
int main(void)
{
long total = 0;
for (long i = 0; i < 40; ++i) {
total += transform(i);
}
printf("%ld\n", total);
return 0;
}
Save it as profile-demo.c, then compile it. The -g option keeps useful symbol and source information for reports; -O0 makes this small demonstration easier to map back to the source.
$ x86_64-w64-mingw32-gcc -g -O0 -pg -o profile-demo.exe profile-demo.c
$ file profile-demo.exe
profile-demo.exe: PE32+ executable (console) x86-64, for MS Windows
Checkpoint: if the compile fails, stop here and fix the toolchain or source first. Do not try to analyse a partially written executable.
3. Run the executable on Windows
Copy profile-demo.exe to a Windows machine, or run it in the Windows environment that will exercise the real program. Run it from a writable directory:
PS> .\profile-demo.exe
<one integer printed by the program>
PS> Get-Item .\gmon.out
The number printed by the example is workload output, not a profiling result. The important checkpoint is that the process exits normally and creates gmon.out beside the executable. The installed manpage notes that a profiled program must call exit for the profile data to be written; normal return from main satisfies that requirement.
Run the real workload repeatedly enough to make its hot paths representative, then copy gmon.out back to Linux without renaming it. Do not replace a useful profile accidentally: copy it to a separate directory before collecting another run.
4. Read the default report
From the directory containing the matching executable and gmon.out, run:
$ x86_64-w64-mingw32-gprof profile-demo.exe gmon.out > profile.txt
$ sed -n '1,80p' profile.txt
With no report-selection options, this version prints a flat profile and a call graph. The flat profile shows time and call counts attributed to functions. The call graph shows callers, children and propagated time. Redirecting to a text file makes a large report easier to search, and does not change the profile.
Use -b to remove the explanatory text around the tables, and -p or -q when you want one report form explicitly:
$ x86_64-w64-mingw32-gprof -b -p profile-demo.exe gmon.out > flat.txt
$ x86_64-w64-mingw32-gprof -b -q profile-demo.exe gmon.out > call-graph.txt
$ grep -n 'transform' flat.txt call-graph.txt
A function with a high percentage is a candidate for investigation, not automatic proof that it should be changed. Sampling is statistical, and call-graph time is estimated. Run a representative workload before drawing conclusions.
5. Narrow and verify the evidence
For C++ output, names are demangled by default. Use --no-demangle when comparing raw symbols. Use -Ctransform for an execution-count view restricted to a symbol specification, or -z when you need unused functions included in the flat profile.
$ x86_64-w64-mingw32-gprof --file-info profile-demo.exe gmon.out
$ x86_64-w64-mingw32-gprof -Ctransform profile-demo.exe gmon.out
The first command reports how many histogram, call-graph and basic-block records are present, then exits. It is a useful sanity check before interpreting an empty-looking report. If it says the executable is not in executable format, you passed the wrong image file, often a Linux binary or source file.
Source annotation is available with -A, but it needs source files that gprof can find. Pass their directories with -I /path/to/source. Without that, the profile can still be useful; do not treat missing annotated source as a failed profile.
6. Combine several runs carefully
To merge profile files from comparable runs, pass them together with -s. The command writes gmon.sum, which can then be analysed as the profile input:
$ x86_64-w64-mingw32-gprof -s profile-demo.exe run-1.out run-2.out
$ x86_64-w64-mingw32-gprof -b profile-demo.exe gmon.sum > combined.txt
Keep the runs comparable: the same executable, input shape and profiling environment. Do not merge profiles from unrelated builds. If you need to undo a merge, remove only the generated gmon.sum after checking that no later report depends on it. The original profile files are not changed by -s.
Common traps
- No
gmon.out: check that the Windows process was built with-pg, ran to normal exit, and had permission to write its working directory. - Wrong or empty symbols: confirm that the executable passed to gprof is the one that produced the profile. Keep
-gdata during investigation. - Unconvincing timings: increase the workload, avoid profiling startup-only behaviour, and remember that sampling and propagated child times have limits.
- Unexpected output files:
-swritesgmon.sum; annotated output with--separate-filescan write files next to the source names. Review destinations before using those options in a source tree.
Done means
- The MinGW executable was compiled with
-pgand retained its matching symbols. - The Windows workload exited normally and produced
gmon.out. --file-infoconfirmed that the profile contains records.- You inspected both the flat profile and call graph, treating their timings as evidence to investigate.
- Any merged
gmon.sumcontains only comparable runs, and the original profiles remain available.