Test to check backtraces with machine function splitting.
authorSriraman Tallam <tmsriram@google.com>
Mon, 26 Oct 2020 20:42:18 +0000 (13:42 -0700)
committerSriraman Tallam <tmsriram@google.com>
Mon, 26 Oct 2020 21:08:42 +0000 (14:08 -0700)
clang supports option -fsplit-machine-functions and this test checks if the
backtraces are sane when functions are split.

With -fsplit-machine-functions, a function with profiles can get split into 2
parts, the original function containing hot code and a cold part as determined
by the profile info and the cold cutoff threshold.. The cold part gets the
".cold" suffix to disambiguate its symbol from the hot part and can be placed
arbitrarily in the address space.

This test checks if the back-trace looks correct when the cold part is executed.

Differential Revision: https://reviews.llvm.org/D90081

lldb/test/Shell/Unwind/Inputs/split-machine-functions.ll [new file with mode: 0644]
lldb/test/Shell/Unwind/split-machine-functions.test [new file with mode: 0644]

diff --git a/lldb/test/Shell/Unwind/Inputs/split-machine-functions.ll b/lldb/test/Shell/Unwind/Inputs/split-machine-functions.ll
new file mode 100644 (file)
index 0000000..415e1fd
--- /dev/null
@@ -0,0 +1,99 @@
+;; IR + Profile to split machine functions with -fsplit-machine-functions
+;; Source used to generate this file
+;; int k;
+
+;; int baz() {
+;;   return 0;
+;; }
+;;
+;; int bar() {
+;;   return 0;
+;; }
+;;
+;; int foo() {
+;;   if (k)
+;;     baz();
+;;   else
+;;     bar();
+;;   return 0;
+;; }
+;;
+;; int main() {
+;;   foo();
+;;   return 0;
+;; }
+
+;; Commands:
+;; clang -fprofile-generate -O0 source.cc
+;; ./a.out && llvm-profdata merge -o default.profdata *.profraw
+;; clang -fprofile-use -O0 source.cc -emit-llvm -S
+
+target triple = "x86_64-unknown-linux-gnu"
+
+@k = dso_local global i32 0, align 4
+
+define dso_local i32 @_Z3bazv() !prof !31 {
+  ret i32 0
+}
+
+define dso_local i32 @_Z3barv() !prof !32 {
+  ret i32 0
+}
+
+define dso_local i32 @_Z3foov() !prof !32 {
+  %1 = load i32, i32* @k, align 4
+  %2 = icmp ne i32 %1, 0
+  br i1 %2, label %3, label %5, !prof !33
+
+3:                                                ; preds = %0
+  %4 = call i32 @_Z3bazv()
+  br label %7
+
+5:                                                ; preds = %0
+  %6 = call i32 @_Z3barv()
+  br label %7
+
+7:                                                ; preds = %5, %3
+  ret i32 0
+}
+
+define dso_local i32 @main() !prof !32 {
+  %1 = call i32 @_Z3foov()
+  ret i32 0
+}
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10, !11, !12}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 3}
+!5 = !{!"MaxCount", i64 1}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1}
+!8 = !{!"NumCounts", i64 5}
+!9 = !{!"NumFunctions", i64 4}
+!10 = !{!"IsPartialProfile", i64 0}
+!11 = !{!"PartialProfileRatio", double 0.000000e+00}
+!12 = !{!"DetailedSummary", !13}
+!13 = !{!14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29}
+!14 = !{i32 10000, i64 0, i32 0}
+!15 = !{i32 100000, i64 0, i32 0}
+!16 = !{i32 200000, i64 0, i32 0}
+!17 = !{i32 300000, i64 0, i32 0}
+!18 = !{i32 400000, i64 1, i32 3}
+!19 = !{i32 500000, i64 1, i32 3}
+!20 = !{i32 600000, i64 1, i32 3}
+!21 = !{i32 700000, i64 1, i32 3}
+!22 = !{i32 800000, i64 1, i32 3}
+!23 = !{i32 900000, i64 1, i32 3}
+!24 = !{i32 950000, i64 1, i32 3}
+!25 = !{i32 990000, i64 1, i32 3}
+!26 = !{i32 999000, i64 1, i32 3}
+!27 = !{i32 999900, i64 1, i32 3}
+!28 = !{i32 999990, i64 1, i32 3}
+!29 = !{i32 999999, i64 1, i32 3}
+!31 = !{!"function_entry_count", i64 0}
+!32 = !{!"function_entry_count", i64 1}
+!33 = !{!"branch_weights", i32 1, i32 0}
diff --git a/lldb/test/Shell/Unwind/split-machine-functions.test b/lldb/test/Shell/Unwind/split-machine-functions.test
new file mode 100644 (file)
index 0000000..bc631b1
--- /dev/null
@@ -0,0 +1,46 @@
+# Test to check if machine function splitter still produces the right backtraces
+# with lldb when a function is split into a hot and cold part and the cold part
+# is executed.  The cold part has the same function symbol name but with a
+# ".cold" suffix and this test checks that the back trace is clear.
+
+# UNSUPPORTED: system-darwin, system-windows
+# REQUIRES: target-x86_64
+# REQUIRES: lld
+
+# RUN: split-file %s %t.split
+#
+# RUN: %clang_host %p/Inputs/split-machine-functions.ll -o %t
+# RUN: %lldb %t -s %t.split/commands -o exit | FileCheck  %s --check-prefix=DEFAULT
+#
+# RUN: %clang_host %p/Inputs/split-machine-functions.ll -fsplit-machine-functions -o %t
+# RUN: %lldb %t -s %t.split/commands -o exit | FileCheck  %s --check-prefix=SPLIT
+#
+# Test a permutation where foo.cold is very far from foo.  The default ordering does not
+# ensure that there will be a gap between foo and foo.cold.  Using a symbol ordering
+# file guarantees this
+# RUN: %clang_host %p/Inputs/split-machine-functions.ll -fsplit-machine-functions -o %t -fuse-ld=lld -Wl,--symbol-ordering-file,%t.split/sym_order_1.txt -Wl,--warn-symbol-ordering -Wl,--fatal-warnings
+# RUN: %lldb %t -s %t.split/commands -o exit | FileCheck  %s --check-prefix=SPLIT
+
+#--- commands
+breakpoint set -n bar
+# DEFAULT: Breakpoint 1: where = {{.*}}`bar
+# SPLIT: Breakpoint 1: where = {{.*}}`bar
+
+process launch
+# DEFAULT: stop reason = breakpoint 1.1
+# SPLIT: stop reason = breakpoint 1.1
+
+thread backtrace
+# DEFAULT: frame #0: {{.*}}`bar
+# DEFAULT: frame #1: {{.*}}`foo() +
+# DEFAULT: frame #2: {{.*}}`main +
+# SPLIT: frame #0: {{.*}}`bar
+# SPLIT: frame #1: {{.*}}`foo() (.cold) +
+# SPLIT: frame #2: {{.*}}`main +
+
+#--- sym_order_1.txt
+_Z3foov
+main
+_Z3barv
+_Z3bazv
+_Z3foov.cold