Skip to content

Commit 00733b2

Browse files
authored
Merge pull request #203 from vedantk/cherry
Cherry-pick profile runtime & lldb build fixes
2 parents bcd4c9c + 59c5392 commit 00733b2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1027
-81
lines changed

clang/docs/SourceBasedCodeCoverage.rst

+10
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ directory structure will be created. Additionally, the following special
8787
be between 1 and 9. The merge pool specifier can only occur once per filename
8888
pattern.
8989

90+
* "%c" expands out to nothing, but enables a mode in which profile counter
91+
updates are continuously synced to a file. This means that if the
92+
instrumented program crashes, or is killed by a signal, perfect coverage
93+
information can still be recovered. Continuous mode is not yet compatible with
94+
the "%Nm" merging mode described above, does not support value profiling for
95+
PGO, and is only supported on Darwin. Support for Linux may be mostly
96+
complete but requires testing, and support for Fuchsia/Windows may require
97+
more extensive changes: please get involved if you are interested in porting
98+
this feature.
99+
90100
.. code-block:: console
91101
92102
# Step 2: Run the program.

clang/lib/Driver/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(LLVM_LINK_COMPONENTS
22
BinaryFormat
33
Option
4+
ProfileData
45
Support
56
)
67

clang/lib/Driver/ToolChains/Darwin.cpp

+35-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/Driver/SanitizerArgs.h"
2020
#include "llvm/ADT/StringSwitch.h"
2121
#include "llvm/Option/ArgList.h"
22+
#include "llvm/ProfileData/InstrProf.h"
2223
#include "llvm/Support/Path.h"
2324
#include "llvm/Support/ScopedPrinter.h"
2425
#include "llvm/Support/TargetParser.h"
@@ -1114,28 +1115,60 @@ static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) {
11141115
CmdArgs.push_back(Symbol);
11151116
}
11161117

1118+
/// Add a sectalign directive for \p Segment and \p Section to the maximum
1119+
/// expected page size for Darwin.
1120+
///
1121+
/// On iPhone 6+ the max supported page size is 16K. On macOS, the max is 4K.
1122+
/// Use a common alignment constant (16K) for now, and reduce the alignment on
1123+
/// macOS if it proves important.
1124+
static void addSectalignToPage(const ArgList &Args, ArgStringList &CmdArgs,
1125+
StringRef Segment, StringRef Section) {
1126+
for (const char *A : {"-sectalign", Args.MakeArgString(Segment),
1127+
Args.MakeArgString(Section), "0x4000"})
1128+
CmdArgs.push_back(A);
1129+
}
1130+
11171131
void Darwin::addProfileRTLibs(const ArgList &Args,
11181132
ArgStringList &CmdArgs) const {
11191133
if (!needsProfileRT(Args)) return;
11201134

11211135
AddLinkRuntimeLib(Args, CmdArgs, "profile",
11221136
RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink));
11231137

1138+
bool ForGCOV = needsGCovInstrumentation(Args);
1139+
11241140
// If we have a symbol export directive and we're linking in the profile
11251141
// runtime, automatically export symbols necessary to implement some of the
11261142
// runtime's functionality.
11271143
if (hasExportSymbolDirective(Args)) {
1128-
if (needsGCovInstrumentation(Args)) {
1144+
if (ForGCOV) {
11291145
addExportedSymbol(CmdArgs, "___gcov_flush");
11301146
addExportedSymbol(CmdArgs, "_flush_fn_list");
11311147
addExportedSymbol(CmdArgs, "_writeout_fn_list");
11321148
} else {
11331149
addExportedSymbol(CmdArgs, "___llvm_profile_filename");
11341150
addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
1135-
addExportedSymbol(CmdArgs, "_lprofCurFilename");
11361151
}
11371152
addExportedSymbol(CmdArgs, "_lprofDirMode");
11381153
}
1154+
1155+
// Align __llvm_prf_{cnts,data} sections to the maximum expected page
1156+
// alignment. This allows profile counters to be mmap()'d to disk. Note that
1157+
// it's not enough to just page-align __llvm_prf_cnts: the following section
1158+
// must also be page-aligned so that its data is not clobbered by mmap().
1159+
//
1160+
// The section alignment is only needed when continuous profile sync is
1161+
// enabled, but this is expected to be the default in Xcode. Specifying the
1162+
// extra alignment also allows the same binary to be used with/without sync
1163+
// enabled.
1164+
if (!ForGCOV) {
1165+
for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) {
1166+
addSectalignToPage(
1167+
Args, CmdArgs, "__DATA",
1168+
llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO,
1169+
/*AddSegmentInfo=*/false));
1170+
}
1171+
}
11391172
}
11401173

11411174
void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,

clang/test/Driver/darwin-ld.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@
345345
// RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log
346346
// LINK_PROFILE_FIRST: {{ld(.exe)?"}} "{{[^"]+}}libclang_rt.profile_{{[a-z]+}}.a"
347347

348+
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -### %t.o 2> %t.log
349+
// RUN: FileCheck -check-prefix=PROFILE_SECTALIGN %s < %t.log
350+
// RUN: %clang -target arm64-apple-ios12 -fprofile-instr-generate -### %t.o 2> %t.log
351+
// RUN: FileCheck -check-prefix=PROFILE_SECTALIGN %s < %t.log
352+
// PROFILE_SECTALIGN: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x4000" "-sectalign" "__DATA" "__llvm_prf_data" "0x4000"
353+
348354
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -exported_symbols_list /dev/null -### %t.o 2> %t.log
349355
// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
350356
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Wl,-exported_symbols_list,/dev/null -### %t.o 2> %t.log
@@ -355,7 +361,7 @@
355361
// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
356362
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Xlinker -exported_symbols_list -Xlinker /dev/null -### %t.o 2> %t.log
357363
// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
358-
// PROFILE_EXPORT: "-exported_symbol" "___llvm_profile_filename" "-exported_symbol" "___llvm_profile_raw_version" "-exported_symbol" "_lprofCurFilename"
364+
// PROFILE_EXPORT: "-exported_symbol" "___llvm_profile_filename" "-exported_symbol" "___llvm_profile_raw_version"
359365
//
360366
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate --coverage -### %t.o 2> %t.log
361367
// RUN: FileCheck -check-prefix=NO_PROFILE_EXPORT %s < %t.log

compiler-rt/lib/profile/InstrProfData.inc

+3-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \
130130
INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
131131
INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
132132
INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
133+
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters)
133134
INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
135+
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterCounters, PaddingBytesAfterCounters)
134136
INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
135137
INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
136138
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
@@ -628,7 +630,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
628630
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
629631

630632
/* Raw profile format version (start from 1). */
631-
#define INSTR_PROF_RAW_VERSION 4
633+
#define INSTR_PROF_RAW_VERSION 5
632634
/* Indexed profile format version (start from 1). */
633635
#define INSTR_PROF_INDEX_VERSION 5
634636
/* Coverage mapping format vresion (start from 0). */

compiler-rt/lib/profile/InstrProfiling.h

+80-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define PROFILE_INSTRPROFILING_H_
1111

1212
#include "InstrProfilingPort.h"
13+
#include <stdio.h>
1314

1415
#define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY
1516
#include "InstrProfData.inc"
@@ -37,6 +38,22 @@ typedef struct ValueProfNode {
3738
#include "InstrProfData.inc"
3839
} ValueProfNode;
3940

41+
/*!
42+
* \brief Return 1 if profile counters are continuously synced to the raw
43+
* profile via an mmap(). This is in contrast to the default mode, in which
44+
* the raw profile is written out at program exit time.
45+
*/
46+
int __llvm_profile_is_continuous_mode_enabled(void);
47+
48+
/*!
49+
* \brief Enable continuous mode.
50+
*
51+
* See \ref __llvm_profile_is_continuous_mode_enabled. The behavior is undefined
52+
* if continuous mode is already enabled, or if it cannot be enable due to
53+
* conflicting options.
54+
*/
55+
void __llvm_profile_enable_continuous_mode(void);
56+
4057
/*!
4158
* \brief Get number of bytes necessary to pad the argument to eight
4259
* byte boundary.
@@ -125,7 +142,7 @@ int __llvm_orderfile_write_file(void);
125142
/*!
126143
* \brief this is a wrapper interface to \c __llvm_profile_write_file.
127144
* After this interface is invoked, a arleady dumped flag will be set
128-
* so that profile won't be dumped again during program exit.
145+
* so that profile won't be dumped again during program exit.
129146
* Invocation of interface __llvm_profile_reset_counters will clear
130147
* the flag. This interface is designed to be used to collect profile
131148
* data from user selected hot regions. The use model is
@@ -154,9 +171,47 @@ int __llvm_orderfile_dump(void);
154171
*
155172
* \c Name is not copied, so it must remain valid. Passing NULL resets the
156173
* filename logic to the default behaviour.
174+
*
175+
* Note: There may be multiple copies of the profile runtime (one for each
176+
* instrumented image/DSO). This API only modifies the filename within the
177+
* copy of the runtime available to the calling image.
178+
*
179+
* Warning: This is a no-op if continuous mode (\ref
180+
* __llvm_profile_is_continuous_mode_enabled) is on. The reason for this is
181+
* that in continuous mode, profile counters are mmap()'d to the profile at
182+
* program initialization time. Support for transferring the mmap'd profile
183+
* counts to a new file has not been implemented.
157184
*/
158185
void __llvm_profile_set_filename(const char *Name);
159186

187+
/*!
188+
* \brief Set the FILE object for writing instrumentation data.
189+
*
190+
* Sets the FILE object to be used for subsequent calls to
191+
* \a __llvm_profile_write_file(). The profile file name set by environment
192+
* variable, command-line option, or calls to \a __llvm_profile_set_filename
193+
* will be ignored.
194+
*
195+
* \c File will not be closed after a call to \a __llvm_profile_write_file() but
196+
* it may be flushed. Passing NULL restores default behavior.
197+
*
198+
* If \c EnableMerge is nonzero, the runtime will always merge profiling data
199+
* with the contents of the profiling file. If EnableMerge is zero, the runtime
200+
* may still merge the data if it would have merged for another reason (for
201+
* example, because of a %m specifier in the file name).
202+
*
203+
* Note: There may be multiple copies of the profile runtime (one for each
204+
* instrumented image/DSO). This API only modifies the file object within the
205+
* copy of the runtime available to the calling image.
206+
*
207+
* Warning: This is a no-op if continuous mode (\ref
208+
* __llvm_profile_is_continuous_mode_enabled) is on. The reason for this is
209+
* that in continuous mode, profile counters are mmap()'d to the profile at
210+
* program initialization time. Support for transferring the mmap'd profile
211+
* counts to a new file has not been implemented.
212+
*/
213+
void __llvm_profile_set_file_object(FILE *File, int EnableMerge);
214+
160215
/*! \brief Register to write instrumentation data to file at exit. */
161216
int __llvm_profile_register_write_file_atexit(void);
162217

@@ -177,7 +232,12 @@ const char *__llvm_profile_get_path_prefix();
177232
* \brief Return filename (including path) of the profile data. Note that if the
178233
* user calls __llvm_profile_set_filename later after invoking this interface,
179234
* the actual file name may differ from what is returned here.
180-
* Side-effect: this API call will invoke malloc with dynamic memory allocation.
235+
* Side-effect: this API call will invoke malloc with dynamic memory allocation
236+
* (the returned pointer must be passed to `free` to avoid a leak).
237+
*
238+
* Note: There may be multiple copies of the profile runtime (one for each
239+
* instrumented image/DSO). This API only retrieves the filename from the copy
240+
* of the runtime available to the calling image.
181241
*/
182242
const char *__llvm_profile_get_filename();
183243

@@ -191,6 +251,24 @@ uint64_t __llvm_profile_get_version(void);
191251
uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
192252
const __llvm_profile_data *End);
193253

254+
/* ! \brief Given the sizes of the data and counter information, return the
255+
* number of padding bytes before and after the counters, and after the names,
256+
* in the raw profile.
257+
*
258+
* Note: In this context, "size" means "number of entries", i.e. the first two
259+
* arguments must be the result of __llvm_profile_get_data_size() and of
260+
* (__llvm_profile_end_counters() - __llvm_profile_begin_counters()) resp.
261+
*
262+
* Note: When mmap() mode is disabled, no padding bytes before/after counters
263+
* are needed. However, in mmap() mode, the counter section in the raw profile
264+
* must be page-aligned: this API computes the number of padding bytes
265+
* needed to achieve that.
266+
*/
267+
void __llvm_profile_get_padding_sizes_for_counters(
268+
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
269+
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
270+
uint64_t *PaddingBytesAfterNames);
271+
194272
/*!
195273
* \brief Set the flag that profile data has been dumped to the file.
196274
* This is useful for users to disable dumping profile data to the file for

compiler-rt/lib/profile/InstrProfilingBuffer.c

+70-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@
88

99
#include "InstrProfiling.h"
1010
#include "InstrProfilingInternal.h"
11+
#include "InstrProfilingPort.h"
12+
13+
/* When continuous mode is enabled (%c), this parameter is set to 1. This is
14+
* incompatible with the in-process merging mode. Lifting this restriction
15+
* may be complicated, as merging mode requires a lock on the profile, and
16+
* mmap() mode would require that lock to be held for the entire process
17+
* lifetime.
18+
*
19+
* This parameter is defined here in InstrProfilingBuffer.o, instead of in
20+
* InstrProfilingFile.o, to sequester all libc-dependent code in
21+
* InstrProfilingFile.o. The test `instrprof-without-libc` will break if this
22+
* layering is violated. */
23+
static int ContinuouslySyncProfile = 0;
24+
25+
COMPILER_RT_VISIBILITY int __llvm_profile_is_continuous_mode_enabled(void) {
26+
return ContinuouslySyncProfile;
27+
}
28+
29+
COMPILER_RT_VISIBILITY void __llvm_profile_enable_continuous_mode(void) {
30+
ContinuouslySyncProfile = 1;
31+
}
1132

1233
COMPILER_RT_VISIBILITY
1334
uint64_t __llvm_profile_get_size_for_buffer(void) {
@@ -30,18 +51,63 @@ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
3051
sizeof(__llvm_profile_data);
3152
}
3253

54+
/// Calculate the number of padding bytes needed to add to \p Offset in order
55+
/// for (\p Offset + Padding) to be page-aligned.
56+
static uint64_t calculateBytesNeededToPageAlign(uint64_t Offset,
57+
unsigned PageSize) {
58+
uint64_t OffsetModPage = Offset % PageSize;
59+
if (OffsetModPage > 0)
60+
return PageSize - OffsetModPage;
61+
return 0;
62+
}
63+
64+
COMPILER_RT_VISIBILITY
65+
void __llvm_profile_get_padding_sizes_for_counters(
66+
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
67+
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
68+
uint64_t *PaddingBytesAfterNames) {
69+
if (!__llvm_profile_is_continuous_mode_enabled()) {
70+
*PaddingBytesBeforeCounters = 0;
71+
*PaddingBytesAfterCounters = 0;
72+
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
73+
return;
74+
}
75+
76+
// In continuous mode, the file offsets for headers and for the start of
77+
// counter sections need to be page-aligned.
78+
unsigned PageSize = getpagesize();
79+
uint64_t DataSizeInBytes = DataSize * sizeof(__llvm_profile_data);
80+
uint64_t CountersSizeInBytes = CountersSize * sizeof(uint64_t);
81+
*PaddingBytesBeforeCounters = calculateBytesNeededToPageAlign(
82+
sizeof(__llvm_profile_header) + DataSizeInBytes, PageSize);
83+
*PaddingBytesAfterCounters =
84+
calculateBytesNeededToPageAlign(CountersSizeInBytes, PageSize);
85+
*PaddingBytesAfterNames =
86+
calculateBytesNeededToPageAlign(NamesSize, PageSize);
87+
}
88+
3389
COMPILER_RT_VISIBILITY
3490
uint64_t __llvm_profile_get_size_for_buffer_internal(
3591
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
3692
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
3793
const char *NamesBegin, const char *NamesEnd) {
3894
/* Match logic in __llvm_profile_write_buffer(). */
3995
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
40-
const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
96+
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
97+
uint64_t CountersSize = CountersEnd - CountersBegin;
98+
99+
/* Determine how much padding is needed before/after the counters and after
100+
* the names. */
101+
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
102+
PaddingBytesAfterNames;
103+
__llvm_profile_get_padding_sizes_for_counters(
104+
DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
105+
&PaddingBytesAfterCounters, &PaddingBytesAfterNames);
106+
41107
return sizeof(__llvm_profile_header) +
42-
(__llvm_profile_get_data_size(DataBegin, DataEnd) *
43-
sizeof(__llvm_profile_data)) +
44-
(CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding;
108+
(DataSize * sizeof(__llvm_profile_data)) + PaddingBytesBeforeCounters +
109+
(CountersSize * sizeof(uint64_t)) + PaddingBytesAfterCounters +
110+
NamesSize + PaddingBytesAfterNames;
45111
}
46112

47113
COMPILER_RT_VISIBILITY

0 commit comments

Comments
 (0)