diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -646,7 +646,7 @@ // Mark all functions with registered events as having a valid profile. for (auto &BFI : BC.getBinaryFunctions()) { BinaryFunction &BF = BFI.second; - if (getBranchData(BF)) { + if (getBranchData(BF) || getFuncSampleData(BF.getNames())) { const auto Flags = opts::BasicAggregation ? BinaryFunction::PF_SAMPLE : BinaryFunction::PF_LBR; BF.markProfiled(Flags); diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -1331,7 +1331,8 @@ if (getBranchData(Function) || getMemData(Function)) return true; - if (getBranchDataForNames(Function.getNames()) || + if (getFuncSampleData(Function.getNames()) || + getBranchDataForNames(Function.getNames()) || getMemDataForNames(Function.getNames())) return true; diff --git a/bolt/test/X86/nolbr.s b/bolt/test/X86/nolbr.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/nolbr.s @@ -0,0 +1,39 @@ +# This reproduces a bug where profile collected from perf without LBRs and +# converted into fdata-no-lbr format is reported to not contain profile for any +# functions. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ +# RUN: %s -o %t.o +# RUN: link_fdata --no-lbr %s %t.o %t.fdata +# RUN: FileCheck %s --input-file %t.fdata --check-prefix=CHECK-FDATA +# RUN: llvm-strip --strip-unneeded %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata --dyno-stats -nl \ +# RUN: --print-only=_start 2>&1 | FileCheck %s --check-prefix=CHECK-BOLT + +# CHECK-FDATA: no_lbr +# CHECK-FDATA-NEXT: 1 _start [[#]] 1 + +# CHECK-BOLT: BOLT-INFO: pre-processing profile using branch profile reader +# CHECK-BOLT: BOLT-INFO: operating with basic samples profiling data (no LBR). +# CHECK-BOLT: BOLT-INFO: 1 out of 1 functions in the binary (100.0%) have non-empty execution profile + + .globl _start + .type _start, %function +_start: + pushq %rbp + movq %rsp, %rbp + cmpl $0x0, %eax +a: +# FDATA: 1 _start #a# 1 + je b + movl $0x0, %eax + jmp c +b: + movl $0x1, %eax +c: + popq %rbp + retq +.size _start, .-_start diff --git a/bolt/test/link_fdata.py b/bolt/test/link_fdata.py --- a/bolt/test/link_fdata.py +++ b/bolt/test/link_fdata.py @@ -18,6 +18,7 @@ parser.add_argument("output") parser.add_argument("prefix", nargs="?", default="FDATA", help="Custom FDATA prefix") parser.add_argument("--nmtool", default="nm", help="Path to nm tool") +parser.add_argument("--no-lbr", action='store_true') args = parser.parse_args() @@ -36,6 +37,10 @@ # [] preagg_pat = re.compile(r"(?P[BFf]) (?P.*)") +# No-LBR profile: +# +nolbr_pat = re.compile(r"([01].*) (?P\d+)") + # Replacement symbol: #symname# replace_pat = re.compile(r"#(?P[^#]+)#") @@ -51,6 +56,7 @@ profile_line = prefix_match.group(1) fdata_match = fdata_pat.match(profile_line) preagg_match = preagg_pat.match(profile_line) + nolbr_match = nolbr_pat.match(profile_line) if fdata_match: src_dst, execnt, mispred = fdata_match.groups() # Split by whitespaces not preceded by a backslash (negative lookbehind) @@ -59,6 +65,14 @@ # exactly matches the format. assert len(chunks) == 6, f"ERROR: wrong format/whitespaces must be escaped:\n{line}" exprs.append(('FDATA', (*chunks, execnt, mispred))) + elif nolbr_match: + loc, count = nolbr_match.groups() + # Split by whitespaces not preceded by a backslash (negative lookbehind) + chunks = re.split(r'(?