Skip to content
Permalink
Browse files

PGO: Add a run-make test that makes sure that PGO profiling data is u…

…sed by the compiler during optimizations.
  • Loading branch information...
michaelwoerister committed Apr 25, 2019
1 parent 68b6924 commit 4dc3b99b27623dc142998d9009f64bcf48b9c7b2
@@ -0,0 +1,43 @@
# needs-profiler-support

-include ../tools.mk

# This test makes sure that PGO profiling data leads to cold functions being
# marked as `cold` and hot functions with `inlinehint`.
# The test program contains an `if` were actual execution only ever takes the
# `else` branch. Accordingly, we expect the function that is never called to
# be marked as cold.
#
# The program is compiled with `-Copt-level=s` because this setting disables
# LLVM's pre-inlining pass (i.e. a pass that does some inlining before it adds
# the profiling instrumentation). Disabling this pass leads to rather
# predictable IR which we need for this test to be stable.

COMMON_FLAGS=-Copt-level=s -Ccodegen-units=1

# LLVM doesn't support instrumenting binaries that use SEH:
# https://bugs.llvm.org/show_bug.cgi?id=41279
#
# Things work fine with -Cpanic=abort though.
ifdef IS_MSVC
COMMON_FLAGS+= -Cpanic=abort
endif

all:
# Compile the test program with instrumentation
$(RUSTC) $(COMMON_FLAGS) -Z pgo-gen="$(TMPDIR)" main.rs
# Run it in order to generate some profiling data
$(call RUN,main some-argument) || exit 1
# Postprocess the profiling data so it can be used by the compiler
$(LD_LIB_PATH_ENVVAR)=$(REAL_LD_LIBRARY_PATH) llvm-profdata merge \
-o "$(TMPDIR)"/merged.profdata \
"$(TMPDIR)"/default_*.profraw
# Compile the test program again, making use of the profiling data
$(RUSTC) $(COMMON_FLAGS) -Z pgo-use="$(TMPDIR)"/merged.profdata --emit=llvm-ir main.rs
# Check that the generate IR contains some things that we expect
#
# We feed the file into LLVM FileCheck tool *in reverse* so that we see the
# line with the function name before the line with the function attributes.
# FileCheck only supports checking that something matches on the next line,
# but not if something matches on the previous line.
tac "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt
@@ -0,0 +1,11 @@
# Add a check that the IR contains some expected metadata
CHECK: !{!"ProfileFormat", !"InstrProf"}
CHECK: !"ProfileSummary"

# Make sure that the hot function is marked with `inlinehint`
CHECK: define {{.*}} @hot_function
CHECK-NEXT: Function Attrs:{{.*}}inlinehint

# Make sure that the cold function is marked with `cold`
CHECK: define {{.*}} @cold_function
CHECK-NEXT: Function Attrs:{{.*}}cold
@@ -0,0 +1,23 @@
#[no_mangle]
pub fn cold_function(c: u8) {
println!("cold {}", c);
}

#[no_mangle]
pub fn hot_function(c: u8) {
std::env::set_var(format!("var{}", c), format!("hot {}", c));
}

fn main() {
let arg = std::env::args().skip(1).next().unwrap();

for i in 0 .. 1000_000 {
let some_value = arg.as_bytes()[i % arg.len()];
if some_value == b'!' {
// This branch is never taken at runtime
cold_function(some_value);
} else {
hot_function(some_value);
}
}
}

0 comments on commit 4dc3b99

Please sign in to comment.
You can’t perform that action at this time.