diff options
author | Vedant Kumar <vsk@apple.com> | 2017-11-14 23:56:53 +0000 |
---|---|---|
committer | Vedant Kumar <vsk@apple.com> | 2017-11-14 23:56:53 +0000 |
commit | 2e3617c081e4b57c42cd37068cefe7aae8dcbbdc (patch) | |
tree | 97c9d81f4b6fafa008c7cd57a282a4efc7c087d0 /test/Profile | |
parent | 008c6263c4cd4098d3241b193e01894d959e00c0 (diff) |
[PGO] Detect more structural changes with the stable hash
Lifting from Bob Wilson's notes: The hash value that we compute and
store in PGO profile data to detect out-of-date profiles does not
include enough information. This means that many significant changes to
the source will not cause compiler warnings about the profile being out
of date, and worse, we may continue to use the outdated profile data to
make bad optimization decisions. There is some tension here because
some source changes won't affect PGO and we don't want to invalidate the
profile unnecessarily.
This patch adds a new hashing scheme which is more sensitive to loop
nesting, conditions, and out-of-order control flow. Here are examples
which show snippets which get the same hash under the current scheme,
and different hashes under the new scheme:
Loop Nesting Example
--------------------
// Snippet 1
while (foo()) {
while (bar()) {}
}
// Snippet 2
while (foo()) {}
while (bar()) {}
Condition Example
-----------------
// Snippet 1
if (foo())
bar();
baz();
// Snippet 2
if (foo())
bar();
else
baz();
Out-of-order Control Flow Example
---------------------------------
// Snippet 1
while (foo()) {
if (bar()) {}
baz();
}
// Snippet 2
while (foo()) {
if (bar())
continue;
baz();
}
In each of these cases, it's useful to differentiate between the
snippets because swapping their profiles gives bad optimization hints.
The new hashing scheme considers some logical operators in an effort to
detect more changes in conditions. This isn't a perfect scheme. E.g, it
does not produce the same hash for these equivalent snippets:
// Snippet 1
bool c = !a || b;
if (d && e) {}
// Snippet 2
bool f = d && e;
bool c = !a || b;
if (f) {}
This would require an expensive data flow analysis. Short of that, the
new hashing scheme looks reasonably complete, based on a scan over the
statements we place counters on.
Profiles which use the old version of the PGO hash remain valid and can
be used without issue (there are tests in tree which check this).
rdar://17068282
Differential Revision: https://reviews.llvm.org/D39446
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@318229 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Profile')
-rw-r--r-- | test/Profile/Inputs/c-captured.proftext | 8 | ||||
-rw-r--r-- | test/Profile/Inputs/c-counter-overflows.proftext | 2 | ||||
-rw-r--r-- | test/Profile/Inputs/c-general.proftext | 24 | ||||
-rw-r--r-- | test/Profile/Inputs/c-unprofiled-blocks.proftext | 6 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-class.proftext | 18 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-hash-v2.profdata.v5 | bin | 0 -> 3280 bytes | |||
-rw-r--r-- | test/Profile/Inputs/cxx-hash-v2.proftext | 239 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-lambda.proftext | 6 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-rangefor.proftext | 4 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-templates.proftext | 6 | ||||
-rw-r--r-- | test/Profile/Inputs/cxx-throws.proftext | 6 | ||||
-rw-r--r-- | test/Profile/Inputs/func-entry.proftext | 4 | ||||
-rw-r--r-- | test/Profile/Inputs/gcc-flag-compatibility.proftext | 2 | ||||
-rw-r--r-- | test/Profile/Inputs/objc-general.proftext | 19 | ||||
-rw-r--r-- | test/Profile/c-outdated-data.c | 4 | ||||
-rw-r--r-- | test/Profile/cxx-hash-v2.cpp | 177 | ||||
-rw-r--r-- | test/Profile/objc-general.m | 18 |
17 files changed, 494 insertions, 49 deletions
diff --git a/test/Profile/Inputs/c-captured.proftext b/test/Profile/Inputs/c-captured.proftext index a35e67b7a4..e82d4f544f 100644 --- a/test/Profile/Inputs/c-captured.proftext +++ b/test/Profile/Inputs/c-captured.proftext @@ -1,23 +1,23 @@ c-captured.c:__captured_stmt -10 +42129 2 1 1 c-captured.c:__captured_stmt.1 -266 +4752450705 3 1 10 1 main -0 +24 1 1 debug_captured -650 +11043906705 3 1 1 diff --git a/test/Profile/Inputs/c-counter-overflows.proftext b/test/Profile/Inputs/c-counter-overflows.proftext index 5a3633ecfc..b2e5dd1d77 100644 --- a/test/Profile/Inputs/c-counter-overflows.proftext +++ b/test/Profile/Inputs/c-counter-overflows.proftext @@ -1,5 +1,5 @@ main -285734896137 +10111551811706059223 8 1 68719476720 diff --git a/test/Profile/Inputs/c-general.proftext b/test/Profile/Inputs/c-general.proftext index 19e5bd3db4..c0d03b4b75 100644 --- a/test/Profile/Inputs/c-general.proftext +++ b/test/Profile/Inputs/c-general.proftext @@ -1,5 +1,5 @@ simple_loops -16515 +1245818015463121 4 1 100 @@ -7,7 +7,7 @@ simple_loops 75 conditionals -74917022372782735 +4190663230902537370 11 1 100 @@ -22,7 +22,7 @@ conditionals 100 early_exits -44128811889290 +8265526549255474475 9 1 0 @@ -35,7 +35,7 @@ early_exits 0 jumps -2016037664281362839 +15872630527555456493 22 1 1 @@ -61,7 +61,7 @@ jumps 9 switches -2745195701975551402 +11892326508727782373 19 1 1 @@ -84,7 +84,7 @@ switches 0 big_switch -10218718452081869619 +16933280399284440835 17 1 32 @@ -105,7 +105,7 @@ big_switch 2 boolean_operators -291222909838 +1245693242827665 8 1 100 @@ -117,7 +117,7 @@ boolean_operators 50 boolop_loops -9760565944591 +11270260636676715317 9 1 50 @@ -130,14 +130,14 @@ boolop_loops 26 conditional_operator -848 +54992 3 1 0 1 do_fallthrough -16586 +6898770640283947069 4 1 10 @@ -145,12 +145,12 @@ do_fallthrough 8 main -0 +24 1 1 c-general.c:static_func -4 +18129 2 1 10 diff --git a/test/Profile/Inputs/c-unprofiled-blocks.proftext b/test/Profile/Inputs/c-unprofiled-blocks.proftext index 87b48e13fb..ef7f653811 100644 --- a/test/Profile/Inputs/c-unprofiled-blocks.proftext +++ b/test/Profile/Inputs/c-unprofiled-blocks.proftext @@ -1,5 +1,5 @@ never_called -44257542701577 +5644096560937528444 9 0 0 @@ -12,12 +12,12 @@ never_called 0 main -1 +24 1 1 dead_code -2859007309808137 +9636018207904213947 10 1 0 diff --git a/test/Profile/Inputs/cxx-class.proftext b/test/Profile/Inputs/cxx-class.proftext index 77645fbc20..112200681a 100644 --- a/test/Profile/Inputs/cxx-class.proftext +++ b/test/Profile/Inputs/cxx-class.proftext @@ -1,52 +1,52 @@ _Z14simple_wrapperv -4 +18129 2 1 100 main -0 +24 1 1 _ZN6SimpleD1Ev -10 +42129 2 0 0 _ZN6SimpleD2Ev -10 +42129 2 100 99 _ZN6Simple6methodEv -10 +42129 2 100 99 _ZN6SimpleC1Ei -10 +42129 2 0 0 _ZN6SimpleC2Ei -10 +42129 2 100 99 _ZN7DerivedC1Ev -10 +42129 2 100 99 _ZN7DerivedD2Ev -10 +42129 2 100 99 diff --git a/test/Profile/Inputs/cxx-hash-v2.profdata.v5 b/test/Profile/Inputs/cxx-hash-v2.profdata.v5 Binary files differnew file mode 100644 index 0000000000..5d7fb1f369 --- /dev/null +++ b/test/Profile/Inputs/cxx-hash-v2.profdata.v5 diff --git a/test/Profile/Inputs/cxx-hash-v2.proftext b/test/Profile/Inputs/cxx-hash-v2.proftext new file mode 100644 index 0000000000..65c564524a --- /dev/null +++ b/test/Profile/Inputs/cxx-hash-v2.proftext @@ -0,0 +1,239 @@ +_Z11loop_returnv +# Func Hash: +1160721 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z10loop_breakv +# Func Hash: +1160593 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z8no_gotosv +# Func Hash: +1 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z13loop_continuev +# Func Hash: +1160657 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z18loop_after_if_elsev +# Func Hash: +11044458641 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z21consecutive_try_catchv +# Func Hash: +49221687100497 +# Num Counters: +5 +# Counter Values: +0 +0 +0 +0 +0 + +_Z16nested_try_catchv +# Func Hash: +49147600487505 +# Num Counters: +5 +# Counter Values: +0 +0 +0 +0 +0 + +_Z13indirect_gotov +# Func Hash: +1345 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z17nested_for_rangesv +# Func Hash: +1332305 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z18loop_in_then_blockv +# Func Hash: +11040003281 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z22consecutive_for_rangesv +# Func Hash: +1380689 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z15consecutive_dosv +# Func Hash: +856273 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z11direct_gotov +# Func Hash: +1281 +# Num Counters: +2 +# Counter Values: +0 +0 + +main +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +1 + +_Z11double_lnotv +# Func Hash: +174695569 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z18if_inside_of_whilev +# Func Hash: +36250705 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z11single_lnotv +# Func Hash: +2729105 +# Num Counters: +2 +# Counter Values: +0 +0 + +_Z19if_outside_of_whilev +# Func Hash: +38053009 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z8no_throwv +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +_Z9has_throwv +# Func Hash: +25 +# Num Counters: +1 +# Counter Values: +0 + +_Z10nested_dosv +# Func Hash: +799825 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z16if_inside_of_forv +# Func Hash: +4750648401 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z18loop_in_else_blockv +# Func Hash: +11044398161 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z17if_outside_of_forv +# Func Hash: +4752450705 +# Num Counters: +3 +# Counter Values: +0 +0 +0 + +_Z10loop_emptyv +# Func Hash: +18129 +# Num Counters: +2 +# Counter Values: +0 +0 + diff --git a/test/Profile/Inputs/cxx-lambda.proftext b/test/Profile/Inputs/cxx-lambda.proftext index 36646b5ab3..e49cd8d6ec 100644 --- a/test/Profile/Inputs/cxx-lambda.proftext +++ b/test/Profile/Inputs/cxx-lambda.proftext @@ -1,17 +1,17 @@ cxx-lambda.cpp:_ZZ7lambdasvENK3$_0clEi -654 +11211970062 3 10 9 9 main -0 +24 1 1 _Z7lambdasv -41226 +2895087587861649 4 1 1 diff --git a/test/Profile/Inputs/cxx-rangefor.proftext b/test/Profile/Inputs/cxx-rangefor.proftext index 7d2d1ef58d..b597292078 100644 --- a/test/Profile/Inputs/cxx-rangefor.proftext +++ b/test/Profile/Inputs/cxx-rangefor.proftext @@ -1,5 +1,5 @@ _Z9range_forv -0x000000000014a28a +6169071350249721981 5 1 4 @@ -8,6 +8,6 @@ _Z9range_forv 1 main -0 +24 1 1 diff --git a/test/Profile/Inputs/cxx-templates.proftext b/test/Profile/Inputs/cxx-templates.proftext index 5ea840038d..5b9d8e4569 100644 --- a/test/Profile/Inputs/cxx-templates.proftext +++ b/test/Profile/Inputs/cxx-templates.proftext @@ -1,16 +1,16 @@ main -0 +24 1 1 _Z4loopILj0EEvv -4 +18129 2 1 0 _Z4loopILj100EEvv -4 +18129 2 1 100 diff --git a/test/Profile/Inputs/cxx-throws.proftext b/test/Profile/Inputs/cxx-throws.proftext index 1d197b9eae..32fcf5d50c 100644 --- a/test/Profile/Inputs/cxx-throws.proftext +++ b/test/Profile/Inputs/cxx-throws.proftext @@ -1,5 +1,5 @@ _Z6throwsv -18359008150154 +340120998528097520 9 1 100 @@ -12,14 +12,14 @@ _Z6throwsv 100 _Z11unreachablei -0x28a +706946049169 3 1 1 0 main -0x2cc +187765848 3 1 1 diff --git a/test/Profile/Inputs/func-entry.proftext b/test/Profile/Inputs/func-entry.proftext index f7c2052035..1548c2d7f3 100644 --- a/test/Profile/Inputs/func-entry.proftext +++ b/test/Profile/Inputs/func-entry.proftext @@ -1,10 +1,10 @@ foo -0 +24 1 1000 main -4 +1160280 2 1 10000 diff --git a/test/Profile/Inputs/gcc-flag-compatibility.proftext b/test/Profile/Inputs/gcc-flag-compatibility.proftext index 99d41bb03f..38eb9e5dc5 100644 --- a/test/Profile/Inputs/gcc-flag-compatibility.proftext +++ b/test/Profile/Inputs/gcc-flag-compatibility.proftext @@ -1,5 +1,5 @@ main -4 +1160280 2 1 100 diff --git a/test/Profile/Inputs/objc-general.proftext b/test/Profile/Inputs/objc-general.proftext index 8d6771f9b3..f0034ae8cd 100644 --- a/test/Profile/Inputs/objc-general.proftext +++ b/test/Profile/Inputs/objc-general.proftext @@ -1,17 +1,30 @@ objc-general.m:__13+[A foreach:]_block_invoke -10 +42129 2 2 1 objc-general.m:+[A foreach:] -6 +401 2 1 2 main -0 +24 1 1 +consecutive_objc_for_ranges +1642897 +3 +0 +0 +0 + +nested_objc_for_ranges +1598545 +3 +0 +0 +0 diff --git a/test/Profile/c-outdated-data.c b/test/Profile/c-outdated-data.c index b686f94d80..2b97734789 100644 --- a/test/Profile/c-outdated-data.c +++ b/test/Profile/c-outdated-data.c @@ -7,10 +7,10 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING -// NO_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored +// NO_MISSING: warning: profile data may be out of date: of 3 functions, 2 have mismatched data that will be ignored // NO_MISSING-NOT: 1 has no data -// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored +// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 2 have mismatched data that will be ignored // WITH_MISSING: warning: profile data may be incomplete: of 3 functions, 1 has no data void no_usable_data() { diff --git a/test/Profile/cxx-hash-v2.cpp b/test/Profile/cxx-hash-v2.cpp new file mode 100644 index 0000000000..995fe008f5 --- /dev/null +++ b/test/Profile/cxx-hash-v2.cpp @@ -0,0 +1,177 @@ +// REQUIRES: shell + +// Check that all of the hashes in this file are unique (i.e, that none of the +// profiles for these functions are mutually interchangeable). +// +// RUN: llvm-profdata show -all-functions %S/Inputs/cxx-hash-v2.profdata.v5 | grep "Hash: 0x" | sort > %t.hashes +// RUN: uniq %t.hashes > %t.hashes.unique +// RUN: diff %t.hashes %t.hashes.unique + +// RUN: llvm-profdata merge %S/Inputs/cxx-hash-v2.proftext -o %t.profdata +// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -allow-empty +// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%S/Inputs/cxx-hash-v2.profdata.v5 2>&1 | FileCheck %s -allow-empty + +// CHECK-NOT: warning: profile data may be out of date + +int x; +int arr[1] = {0}; + +void loop_after_if_else() { + if (1) + x = 1; + else + x = 2; + while (0) + ++x; +} + +void loop_in_then_block() { + if (1) { + while (0) + ++x; + } else { + x = 2; + } +} + +void loop_in_else_block() { + if (1) { + x = 1; + } else { + while (0) + ++x; + } +} + +void if_inside_of_for() { + for (x = 0; x < 0; ++x) { + x = 1; + if (1) + x = 2; + } +} + +void if_outside_of_for() { + for (x = 0; x < 0; ++x) + x = 1; + if (1) + x = 2; +} + +void if_inside_of_while() { + while (0) { + x = 1; + if (1) + x = 2; + } +} + +void if_outside_of_while() { + while (0) + x = 1; + if (1) + x = 2; +} + +void nested_dos() { + do { + do { + ++x; + } while (0); + } while (0); +} + +void consecutive_dos() { + do { + } while (0); + do { + ++x; + } while (0); +} + +void loop_empty() { + for (x = 0; x < 5; ++x) {} +} + +void loop_return() { + for (x = 0; x < 5; ++x) + return; +} + +void loop_continue() { + for (x = 0; x < 5; ++x) + continue; +} + +void loop_break() { + for (x = 0; x < 5; ++x) + break; +} + +void no_gotos() { + static void *dispatch[] = {&&done}; + x = 0; +done: + ++x; +} + +void direct_goto() { + static void *dispatch[] = {&&done}; + x = 0; + goto done; +done: + ++x; +} + +void indirect_goto() { + static void *dispatch[] = {&&done}; + x = 0; + goto *dispatch[x]; +done: + ++x; +} + +void nested_for_ranges() { + for (int a : arr) + for (int b : arr) + ++x; +} + +void consecutive_for_ranges() { + for (int a : arr) {} + for (int b : arr) + ++x; +} + +void nested_try_catch() { + try { + try { + ++x; + } catch (...) {} + } catch (...) {} +} + +void consecutive_try_catch() { + try {} catch (...) {} + try { + ++x; + } catch (...) {} +} + +void no_throw() {} + +void has_throw() { + throw 0; +} + +void single_lnot() { + if (!x) {} +} + +void double_lnot() { + if (!!x) {} +} + +int main() { + return 0; +} diff --git a/test/Profile/objc-general.m b/test/Profile/objc-general.m index b679627a48..7a4cac9412 100644 --- a/test/Profile/objc-general.m +++ b/test/Profile/objc-general.m @@ -3,7 +3,9 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument=clang | FileCheck -check-prefix=PGOGEN %s // RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s + +// PGOUSE-NOT: warning: profile data may be out of date #ifdef HAVE_FOUNDATION @@ -63,6 +65,20 @@ struct NSFastEnumerationState; } @end +void nested_objc_for_ranges(NSArray *arr) { + int x = 0; + for (id a in arr) + for (id b in arr) + ++x; +} + +void consecutive_objc_for_ranges(NSArray *arr) { + int x = 0; + for (id a in arr) {} + for (id b in arr) + ++x; +} + // PGOUSE-DAG: ![[FR1]] = !{!"branch_weights", i32 2, i32 3} // PGOUSE-DAG: ![[FR2]] = !{!"branch_weights", i32 3, i32 2} // PGOUSE-DAG: ![[BL1]] = !{!"branch_weights", i32 2, i32 2} |