I'm trying to analyze the performance of a Rust executable on Windows, but cannot seem to instrument the executable image using the VSInstr.exe tool.
To get started I set up a binary cargo package (cargo new --bin sample), and enabled generation of a PDB by adding
[profile.release]
debug = true
to the standard Cargo.toml file. Executing cargo build --release produces both sample.exe and sample.pdb. Navigating to target/release and executing vsinstr sample.exe produces the following diagnostic (VS2017 and VS2019, respectively):
Error VSP1011: Unable to obtain debug information. Link with the /Profile linker switch.
Unable to obtain debug information. Link with the /PROFILE linker switch.
Fair enough, so let's add the following .cargo/config file:
[build]
rustflags = ["-C", "link-args=/PROFILE"]
to pass the required flag to the linker. Running cargo build --release again produces the same artifacts, sample.exe and sample.pdb. Attempting to instrument the image using vsinstr sample.exe now produces the following diagnostic (VS2017 and VS2019, respectively):
Error VSP1033: The file '<path>\sample.exe' does not contain a recognized executable image.
The file does not contain a recognized executable image.
I'm not sure how to proceed from here, or how to further diagnose the core issue.
- Is there something wrong with what I'm doing?
- Am I running into a limitation of rustc/Clang?
- Most importantly, how do I fix the issue?
Notes:
The /PROFILE linker option is documented to be "available only in Enterprise (team development) versions". That information seems outdated. Using the option on a C++ application in Visual Studio 2019 Community had the desired effect.
I've verified, that the /PROFILE flag gets passed to the linker by adding the -Z print-link-args flag to the rustflags in .cargo/config to see the actual linker command line.
Profiling any given Rust application in sample mode (CPU Usage) from the Visual Studio IDE works as long as the respective PDB is available. That's helpful, but I'd really like to get accurate call graphs, so instrumentation is required.
Alongside VSInstr.exe, Visual Studio also ships a binary called vsinstr.legacy.exe, that apparently dumps out more information. Running this against the Rust executable produces a list of warnings that have the following shape:
Warning VSP2005: Internal instrumentation warning: Block start at 1400016D9 is inside instruction at 1400016D8. Removed.
The addresses in all messages differ exactly by 1, which looks an awful lot like an off-by-one error, presumably in the code that produces the PDBs.