Skip to content

Commit

Permalink
[profile] Create only prof header when no counters
Browse files Browse the repository at this point in the history
When we use selective instrumentation and instrument a file
that is not in the selected files list provided via -fprofile-list,
we generate an empty raw profile. This leads to empty_raw_profile
error when we try to read that profile. This patch fixes the issue by
generating a raw profile that contains only a profile header when
there are no counters and profile data.

A small reproducer for the above issue:
echo "src:other.cc" > code.list
clang++ -O2 -fprofile-instr-generate -fcoverage-mapping
-fprofile-list=code.list code.cc -o code
./code
llvm-profdata show default.profraw

Differential Revision: https://reviews.llvm.org/D132094
  • Loading branch information
gulfemsavrun committed Aug 30, 2022
1 parent 7973346 commit 9998863
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 4 deletions.
3 changes: 0 additions & 3 deletions compiler-rt/lib/profile/InstrProfilingWriter.c
Expand Up @@ -276,9 +276,6 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
/* Create the header. */
__llvm_profile_header Header;

if (!NumData && (!DebugInfoCorrelate || !NumCounters))
return 0;

/* Determine how much padding is needed before/after the counters and after
* the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
Expand Down
23 changes: 23 additions & 0 deletions compiler-rt/test/profile/Posix/instrprof-empty-profile.c
@@ -0,0 +1,23 @@
// Test a profile with only a header is generated when a src file is not in the
// selected files list provided via -fprofile-list.

// RUN: mkdir -p %t.d
// RUN: echo "src:other.c" > %t-file.list
// RUN: %clang_profgen -fprofile-list=%t-file.list -o %t %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata show %t.profraw | FileCheck %s --check-prefix=RAW-PROFILE-HEADER-ONLY

// RUN: llvm-profdata merge -o %t.profdata %t.profraw
// RUN: llvm-profdata show %t.profdata | FileCheck %s --check-prefix=INDEXED-PROFILE-HEADER-ONLY

int main() { return 0; }

// RAW-PROFILE-HEADER-ONLY: Instrumentation level: Front-end
// RAW-PROFILE-HEADER-ONLY-NEXT: Total functions: 0
// RAW-PROFILE-HEADER-ONLY-NEXT: Maximum function count: 0
// RAW-PROFILE-HEADER-ONLY-NEXT: Maximum internal block count: 0

// INDEXED-PROFILE-HEADER-ONLY: Instrumentation level: Front-end
// INDEXED-PROFILE-HEADER-ONLY-NEXT: Total functions: 0
// INDEXED-PROFILE-HEADER-ONLY-NEXT: Maximum function count: 0
// INDEXED-PROFILE-HEADER-ONLY-NEXT: Maximum internal block count: 0
42 changes: 42 additions & 0 deletions compiler-rt/test/profile/Posix/instrprof-shared-empty-profile.test
@@ -0,0 +1,42 @@
"""
This test produces two shared libraries:

1. libt-instr.so is instrumented
2. libt-no-instr.so is built with profile rt linked in (via -u<hook>), but the object file is built
with instrumentation turned off.

The test verifies concatenating profiles with only headers and no profile data and counters.
"""

RUN: mkdir -p %t.d
RUN: %clang_profgen -o %t.d/libt-instr.so -fPIC -shared %S/../Inputs/instrprof-shared-lib.c
RUN: %clang -c -o %t.d/instrprof-shared-lib-no-instr.o -fPIC %S/../Inputs/instrprof-shared-lib.c
RUN: %clang_profgen -o %t.d/libt-no-instr.so -fPIC -shared %t.d/instrprof-shared-lib-no-instr.o

# Header + Header
RUN: echo "src:other.c" > %t-file.list
RUN: %clang_profgen -fprofile-list=%t-file.list -o %t-no-instr-no-instr -L%t.d -rpath %t.d -lt-no-instr %S/../Inputs/instrprof-shared-main.c
RUN: env LLVM_PROFILE_FILE=%t-no-instr-no-instr.profraw %run %t-no-instr-no-instr
RUN: llvm-profdata show %t-no-instr-no-instr.profraw | FileCheck %s --check-prefix=HEADER-HEADER
// HEADER-HEADER: Instrumentation level: Front-end
// HEADER-HEADER-NEXT: Total functions: 0
// HEADER-HEADER-NEXT: Maximum function count: 0
// HEADER-HEADER-NEXT: Maximum internal block count: 0

# Header + Profile
RUN: %clang_profgen -fprofile-list=%t-file.list -o %t-no-instr-instr -L%t.d -rpath %t.d -lt-instr %S/../Inputs/instrprof-shared-main.c
RUN: env LLVM_PROFILE_FILE=%t-no-instr-instr.profraw %run %t-no-instr-instr
RUN: llvm-profdata show %t-no-instr-instr.profraw | FileCheck %s --check-prefix=HEADER-PROFILE
// HEADER-PROFILE: Instrumentation level: Front-end
// HEADER-PROFILE-NEXT: Total functions: 1
// HEADER-PROFILE-NEXT: Maximum function count: 1000000
// HEADER-PROFILE-NEXT: Maximum internal block count: 360000

# Profile + Header
RUN: %clang_profgen -o %t-instr-no-instr -L%t.d -rpath %t.d -lt-no-instr %S/../Inputs/instrprof-shared-main.c
RUN: env LLVM_PROFILE_FILE=%t-instr-no-instr.profraw %run %t-instr-no-instr
RUN: llvm-profdata show %t-instr-no-instr.profraw | FileCheck %s --check-prefix=PROFILE-HEADER
// PROFILE-HEADER: Instrumentation level: Front-end
// PROFILE-HEADER-NEXT: Total functions: 1
// PROFILE-HEADER-NEXT: Maximum function count: 1
// PROFILE-HEADER-NEXT: Maximum internal block count: 1000000
4 changes: 3 additions & 1 deletion llvm/lib/ProfileData/InstrProfReader.cpp
Expand Up @@ -545,7 +545,9 @@ Error RawInstrProfReader<IntPtrT>::readValueProfilingData(

template <class IntPtrT>
Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record) {
if (atEnd())
// Keep reading profiles that consist of only headers and no profile data and
// counters.
while (atEnd())
// At this point, ValueDataStart field points to the next header.
if (Error E = readNextHeader(getNextHeaderPos()))
return error(std::move(E));
Expand Down

0 comments on commit 9998863

Please sign in to comment.