From 9aa7a721ce3dc84d0ad2d987af72cf14ff76d8a7 Mon Sep 17 00:00:00 2001 From: Sriraman Tallam Date: Mon, 26 Oct 2020 13:42:18 -0700 Subject: [PATCH] Test to check backtraces with machine function splitting. 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 --- .../Shell/Unwind/Inputs/split-machine-functions.ll | 99 ++++++++++++++++++++++ .../test/Shell/Unwind/split-machine-functions.test | 46 ++++++++++ 2 files changed, 145 insertions(+) create mode 100644 lldb/test/Shell/Unwind/Inputs/split-machine-functions.ll create mode 100644 lldb/test/Shell/Unwind/split-machine-functions.test 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 index 0000000..415e1fd --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/split-machine-functions.ll @@ -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 index 0000000..bc631b1 --- /dev/null +++ b/lldb/test/Shell/Unwind/split-machine-functions.test @@ -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 -- 2.7.4