diff --git a/llvm/test/tools/llvm-profgen/Inputs/coroutine.perfbin b/llvm/test/tools/llvm-profgen/Inputs/coroutine.perfbin new file mode 100755 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ +#include +#include +#include +#include + +struct task { + struct promise_type { + task get_return_object() { return {}; } + std::experimental::suspend_never initial_suspend() { return {}; } + std::experimental::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +template +struct generator { + struct promise_type; + using handle = std::experimental::coroutine_handle; + struct promise_type { + int current_value; + static auto get_return_object_on_allocation_failure() { return generator{nullptr}; } + auto get_return_object() { return generator{handle::from_promise(*this)}; } + auto initial_suspend() { return std::experimental::suspend_always{}; } + auto final_suspend() { return std::experimental::suspend_always{}; } + void unhandled_exception() { std::terminate(); } + void return_void() {} + auto yield_value(int value) { + current_value = value; + return std::experimental::suspend_always{}; + } + }; + bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; } + int current_value() { return coro.promise().current_value; } + generator(generator const &) = delete; + generator(generator &&rhs) : coro(rhs.coro) { rhs.coro = nullptr; } + ~generator() { + if (coro) + coro.destroy(); + } + +private: + generator(handle h) : coro(h) {} + handle coro; +}; + +generator ticker(int count) { + for (int i = 0; i < count; ++i) { + srand(time(NULL)); + uint32_t a = rand() % 10 + 1; + uint32_t b = rand() % 10 + 1; + uint64_t c = 0; + for (int i = 0; i < 1500; ++i) { + c = ((uint64_t)a) + b; + a = b; + b = c % 2147483648ULL; + } + co_yield a; + } +} + +int main() { + auto g = ticker(500000); + uint64_t ans = 0; + while (g.move_next()) { + ans += g.current_value(); + } + std::cout << ans << "\n"; +} diff --git a/llvm/test/tools/llvm-profgen/func-split.test b/llvm/test/tools/llvm-profgen/func-split.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profgen/func-split.test @@ -0,0 +1,69 @@ +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/func-split.perfscript --binary=%S/Inputs/func-split.perfbin --output=%t +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/func-split.perfscript --binary=%S/Inputs/func-split.perfbin --output=%t --ignore-stack-samples +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-STRIP-CTX + +;CHECK: [foo]:408:0 +;CHECK: 2.1: 27 +;CHECK: 3: 27 +;CHECK: 3.1: 2 bar:2 +;CHECK: 3.2: 26 +;CHECK: [foo:3.1 @ bar]:8:0 +;CHECK: 1: 1 +;CHECK: 5: 1 +;CHECK: [bar]:0:1 + +;CHECK-NOT: foo.cold + +;CHECK-STRIP-CTX: foo:408:0 +;CHECK-STRIP-CTX: 0: 0 +;CHECK-STRIP-CTX: 2.1: 27 +;CHECK-STRIP-CTX: 3: 27 +;CHECK-STRIP-CTX: 3.1: 1 bar:1 +;CHECK-STRIP-CTX: 3.2: 26 +;CHECK-STRIP-CTX: 4: 0 +;CHECK-STRIP-CTX: bar:8:1 +;CHECK-STRIP-CTX: 1: 1 +;CHECK-STRIP-CTX: 5: 1 + +;CHECK-STRIP-CTX-NOT: foo.cold + + +; clang -g -O3 -fdebug-info-for-profiling func-split.c -mllvm -mfs-count-threshold=0 +; -fprofile-sample-use=profile.txt -fno-inline -mllvm --enable-split-machine-functions=1 + +#include + +int bar(int x, int y) { + if (x % 3) { + return x - y; + } + return x + y; +} + +void foo() { + int s, i = 0; + while (i++ < 4000 * 4000) + if (i % 91 == 0) s = bar(i, s); else s += 30; + printf("sum is %d\n", s); +} + +int main() { + foo(); + return 0; +} + +; profile.txt: + +foo:106269:0 + 2.1: 2268 + 2.2: 2217 + 3: 2268 + 3.1: 1 bar:1 + 3.2: 2192 +bar:1032:1 + 0: 24 + 1: 24 + 2: 16 + 4: 8 + 5: 24 diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.h b/llvm/tools/llvm-profgen/ProfileGenerator.h --- a/llvm/tools/llvm-profgen/ProfileGenerator.h +++ b/llvm/tools/llvm-profgen/ProfileGenerator.h @@ -74,7 +74,7 @@ void updateBodySamplesforFunctionProfile(FunctionSamples &FunctionProfile, const SampleContextFrame &LeafLoc, uint64_t Count); - + StringRef getCalleeNameForOffset(uint64_t TargetOffset); // Used by SampleProfileWriter SampleProfileMap ProfileMap; diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/llvm/tools/llvm-profgen/ProfileGenerator.cpp --- a/llvm/tools/llvm-profgen/ProfileGenerator.cpp +++ b/llvm/tools/llvm-profgen/ProfileGenerator.cpp @@ -397,6 +397,24 @@ } } +static bool isOutlinedFunction(StringRef CalleeName) { + // Check whether it's from hot-cold func split or coro split. + return CalleeName.find(".resume") != StringRef::npos || + CalleeName.find(".cold") != StringRef::npos; +} + +StringRef ProfileGeneratorBase::getCalleeNameForOffset(uint64_t TargetOffset) { + // Get the callee name by branch target if it's a call branch. + StringRef CalleeName = FunctionSamples::getCanonicalFnName( + Binary->getFuncFromStartOffset(TargetOffset)); + + // We won't accumulate sample count againt outlined function. + if (CalleeName.size() == 0 || isOutlinedFunction(CalleeName)) + return StringRef(); + + return CalleeName; +} + void ProfileGenerator::populateBoundarySamplesForAllFunctions( const BranchSample &BranchCounters) { for (auto Entry : BranchCounters) { @@ -405,9 +423,7 @@ uint64_t Count = Entry.second; assert(Count != 0 && "Unexpected zero weight branch"); - // Get the callee name by branch target if it's a call branch. - StringRef CalleeName = FunctionSamples::getCanonicalFnName( - Binary->getFuncFromStartOffset(TargetOffset)); + StringRef CalleeName = getCalleeNameForOffset(TargetOffset); if (CalleeName.size() == 0) continue; // Record called target sample and its count. @@ -551,9 +567,7 @@ uint64_t Count = Entry.second; assert(Count != 0 && "Unexpected zero weight branch"); - // Get the callee name by branch target if it's a call branch - StringRef CalleeName = FunctionSamples::getCanonicalFnName( - Binary->getFuncFromStartOffset(TargetOffset)); + StringRef CalleeName = getCalleeNameForOffset(TargetOffset); if (CalleeName.size() == 0) continue; @@ -804,8 +818,7 @@ getFunctionProfileForLeafProbe(ContextStack, CallProbe); FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count); FunctionProfile.addTotalSamples(Count); - StringRef CalleeName = FunctionSamples::getCanonicalFnName( - Binary->getFuncFromStartOffset(TargetOffset)); + StringRef CalleeName = getCalleeNameForOffset(TargetOffset); if (CalleeName.size() == 0) continue; FunctionProfile.addCalledTargetSamples(CallProbe->getIndex(), 0, CalleeName,