summaryrefslogtreecommitdiff
path: root/gnu/llvm/compiler-rt/lib/profile
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/compiler-rt/lib/profile')
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/CMakeLists.txt8
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/GCDAProfiling.c192
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfiling.c14
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfiling.h10
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingBiasVar.c15
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c3
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingFile.c121
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.c33
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.h8
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c194
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingPort.h6
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingRuntime.cpp4
-rw-r--r--gnu/llvm/compiler-rt/lib/profile/InstrProfilingUtil.h4
13 files changed, 390 insertions, 222 deletions
diff --git a/gnu/llvm/compiler-rt/lib/profile/CMakeLists.txt b/gnu/llvm/compiler-rt/lib/profile/CMakeLists.txt
index 955d0bf7293..29c6c02f2d0 100644
--- a/gnu/llvm/compiler-rt/lib/profile/CMakeLists.txt
+++ b/gnu/llvm/compiler-rt/lib/profile/CMakeLists.txt
@@ -1,11 +1,11 @@
CHECK_CXX_SOURCE_COMPILES("
-#ifdef _MSC_VER
-#include <Intrin.h> /* Workaround for PR19898. */
+#ifdef _WIN32
+#include <intrin.h> /* Workaround for PR19898. */
#include <windows.h>
#endif
int main() {
-#ifdef _MSC_VER
+#ifdef _WIN32
volatile LONG val = 1;
MemoryBarrier();
InterlockedCompareExchange(&val, 0, 1);
@@ -51,7 +51,9 @@ add_compiler_rt_component(profile)
set(PROFILE_SOURCES
GCDAProfiling.c
InstrProfiling.c
+ InstrProfilingInternal.c
InstrProfilingValue.c
+ InstrProfilingBiasVar.c
InstrProfilingBuffer.c
InstrProfilingFile.c
InstrProfilingMerge.c
diff --git a/gnu/llvm/compiler-rt/lib/profile/GCDAProfiling.c b/gnu/llvm/compiler-rt/lib/profile/GCDAProfiling.c
index 124be3c13af..82369357e98 100644
--- a/gnu/llvm/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/gnu/llvm/compiler-rt/lib/profile/GCDAProfiling.c
@@ -66,6 +66,16 @@ typedef unsigned long long uint64_t;
/* #define DEBUG_GCDAPROFILING */
+enum {
+ GCOV_DATA_MAGIC = 0x67636461, // "gcda"
+
+ GCOV_TAG_FUNCTION = 0x01000000,
+ GCOV_TAG_COUNTER_ARCS = 0x01a10000,
+ // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
+ GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
+ GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
+};
+
/*
* --- GCOV file format I/O primitives ---
*/
@@ -89,6 +99,7 @@ static uint64_t cur_buffer_size = 0;
static uint64_t cur_pos = 0;
static uint64_t file_size = 0;
static int new_file = 0;
+static int gcov_version;
#if defined(_WIN32)
static HANDLE mmap_handle = NULL;
#endif
@@ -199,17 +210,6 @@ static void write_64bit_value(uint64_t i) {
write_32bit_value(hi);
}
-static uint32_t length_of_string(const char *s) {
- return (strlen(s) / 4) + 1;
-}
-
-static void write_string(const char *s) {
- uint32_t len = length_of_string(s);
- write_32bit_value(len);
- write_bytes(s, strlen(s));
- write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
-}
-
static uint32_t read_32bit_value() {
uint32_t val;
@@ -221,18 +221,6 @@ static uint32_t read_32bit_value() {
return val;
}
-static uint32_t read_le_32bit_value() {
- uint32_t val = 0;
- int i;
-
- if (new_file)
- return (uint32_t)-1;
-
- for (i = 0; i < 4; i++)
- val |= write_buffer[cur_pos++] << (8*i);
- return val;
-}
-
static uint64_t read_64bit_value() {
// GCOV uses a lo-/hi-word format even on big-endian systems.
// See also GCOVBuffer::readInt64 in LLVM.
@@ -261,8 +249,8 @@ static int map_file() {
fseek(output_file, 0L, SEEK_END);
file_size = ftell(output_file);
- /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an
- * error message because it should "just work" for the user. */
+ /* A size of 0 means the file has been created just now (possibly by another
+ * process in lock-after-open race condition). No need to mmap. */
if (file_size == 0)
return -1;
@@ -345,30 +333,36 @@ static void unmap_file() {
* started at a time.
*/
COMPILER_RT_VISIBILITY
-void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+void llvm_gcda_start_file(const char *orig_filename, uint32_t version,
uint32_t checksum) {
const char *mode = "r+b";
filename = mangle_filename(orig_filename);
/* Try just opening the file. */
- new_file = 0;
fd = open(filename, O_RDWR | O_BINARY);
if (fd == -1) {
- /* Try opening the file, creating it if necessary. */
- new_file = 1;
- mode = "w+b";
- fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
- if (fd == -1) {
+ /* Try creating the file. */
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644);
+ if (fd != -1) {
+ mode = "w+b";
+ } else {
/* Try creating the directories first then opening the file. */
__llvm_profile_recursive_mkdir(filename);
- fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
- if (fd == -1) {
- /* Bah! It's hopeless. */
- int errnum = errno;
- fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
- strerror(errnum));
- return;
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644);
+ if (fd != -1) {
+ mode = "w+b";
+ } else {
+ /* Another process may have created the file just now.
+ * Try opening it without O_CREAT and O_EXCL. */
+ fd = open(filename, O_RDWR | O_BINARY);
+ if (fd == -1) {
+ /* Bah! It's hopeless. */
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+ strerror(errnum));
+ return;
+ }
}
}
}
@@ -381,27 +375,30 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
output_file = fdopen(fd, mode);
/* Initialize the write buffer. */
+ new_file = 0;
write_buffer = NULL;
cur_buffer_size = 0;
cur_pos = 0;
- if (new_file) {
+ if (map_file() == -1) {
+ /* The file has been created just now (file_size == 0) or mmap failed
+ * unexpectedly. In the latter case, try to recover by clobbering. */
+ new_file = 1;
+ write_buffer = NULL;
resize_write_buffer(WRITE_BUFFER_SIZE);
memset(write_buffer, 0, WRITE_BUFFER_SIZE);
- } else {
- if (map_file() == -1) {
- /* mmap failed, try to recover by clobbering */
- new_file = 1;
- write_buffer = NULL;
- cur_buffer_size = 0;
- resize_write_buffer(WRITE_BUFFER_SIZE);
- memset(write_buffer, 0, WRITE_BUFFER_SIZE);
- }
}
/* gcda file, version, stamp checksum. */
- write_bytes("adcg", 4);
- write_bytes(version, 4);
+ {
+ uint8_t c3 = version >> 24;
+ uint8_t c2 = (version >> 16) & 255;
+ uint8_t c1 = (version >> 8) & 255;
+ gcov_version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0'
+ : (c3 - '0') * 10 + c1 - '0';
+ }
+ write_32bit_value(GCOV_DATA_MAGIC);
+ write_32bit_value(version);
write_32bit_value(checksum);
#ifdef DEBUG_GCDAPROFILING
@@ -436,30 +433,25 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
}
COMPILER_RT_VISIBILITY
-void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
- uint32_t func_checksum, uint8_t use_extra_checksum,
+void llvm_gcda_emit_function(uint32_t ident, uint32_t func_checksum,
uint32_t cfg_checksum) {
uint32_t len = 2;
+ int use_extra_checksum = gcov_version >= 47;
if (use_extra_checksum)
len++;
#ifdef DEBUG_GCDAPROFILING
- fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident,
- function_name ? function_name : "NULL");
+ fprintf(stderr, "llvmgcda: function id=0x%08x\n", ident);
#endif
if (!output_file) return;
/* function tag */
- write_bytes("\0\0\0\1", 4);
- if (function_name)
- len += 1 + length_of_string(function_name);
+ write_32bit_value(GCOV_TAG_FUNCTION);
write_32bit_value(len);
write_32bit_value(ident);
write_32bit_value(func_checksum);
if (use_extra_checksum)
write_32bit_value(cfg_checksum);
- if (function_name)
- write_string(function_name);
}
COMPILER_RT_VISIBILITY
@@ -471,11 +463,11 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
if (!output_file) return;
- val = read_le_32bit_value();
+ val = read_32bit_value();
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
- if (val != 0x01a10000) {
+ if (val != GCOV_TAG_COUNTER_ARCS) {
fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
"corrupt arc tag (0x%08x)\n",
filename, val);
@@ -498,7 +490,7 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
cur_pos = save_cur_pos;
/* Counter #1 (arcs) tag */
- write_bytes("\0\0\xa1\1", 4);
+ write_32bit_value(GCOV_TAG_COUNTER_ARCS);
write_32bit_value(num_counters * 2);
for (i = 0; i < num_counters; ++i) {
counters[i] += (old_ctrs ? old_ctrs[i] : 0);
@@ -516,8 +508,6 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
COMPILER_RT_VISIBILITY
void llvm_gcda_summary_info() {
- const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
- uint32_t i;
uint32_t runs = 1;
static uint32_t run_counted = 0; // We only want to increase the run count once.
uint32_t val = 0;
@@ -525,46 +515,52 @@ void llvm_gcda_summary_info() {
if (!output_file) return;
- val = read_le_32bit_value();
+ val = read_32bit_value();
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
- if (val != 0xa1000000) {
- fprintf(stderr, "profiling: %s: cannot merge previous run count: "
- "corrupt object tag (0x%08x)\n",
+ if (val != (gcov_version >= 90 ? GCOV_TAG_OBJECT_SUMMARY
+ : GCOV_TAG_PROGRAM_SUMMARY)) {
+ fprintf(stderr,
+ "profiling: %s: cannot merge previous run count: "
+ "corrupt object tag (0x%08x)\n",
filename, val);
return;
}
val = read_32bit_value(); /* length */
- if (val != obj_summary_len) {
- fprintf(stderr, "profiling: %s: cannot merge previous run count: "
- "mismatched object length (%d)\n",
- filename, val);
- return;
+ uint32_t prev_runs;
+ if (gcov_version < 90) {
+ read_32bit_value();
+ read_32bit_value();
+ prev_runs = read_32bit_value();
+ } else {
+ prev_runs = read_32bit_value();
+ read_32bit_value();
}
-
- read_32bit_value(); /* checksum, unused */
- read_32bit_value(); /* num, unused */
- uint32_t prev_runs = read_32bit_value();
+ for (uint32_t i = gcov_version < 90 ? 3 : 2; i < val; ++i)
+ read_32bit_value();
/* Add previous run count to new counter, if not already counted before. */
runs = run_counted ? prev_runs : prev_runs + 1;
}
cur_pos = save_cur_pos;
- /* Object summary tag */
- write_bytes("\0\0\0\xa1", 4);
- write_32bit_value(obj_summary_len);
- write_32bit_value(0); /* checksum, unused */
- write_32bit_value(0); /* num, unused */
- write_32bit_value(runs);
- for (i = 3; i < obj_summary_len; ++i)
+ if (gcov_version >= 90) {
+ write_32bit_value(GCOV_TAG_OBJECT_SUMMARY);
+ write_32bit_value(2);
+ write_32bit_value(runs);
+ write_32bit_value(0); // sum_max
+ } else {
+ // Before gcov 4.8 (r190952), GCOV_TAG_SUMMARY_LENGTH was 9. r190952 set
+ // GCOV_TAG_SUMMARY_LENGTH to 22. We simply use the smallest length which
+ // can make gcov read "Runs:".
+ write_32bit_value(GCOV_TAG_PROGRAM_SUMMARY);
+ write_32bit_value(3);
write_32bit_value(0);
-
- /* Program summary tag */
- write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
- write_32bit_value(0); /* 0 length */
+ write_32bit_value(0);
+ write_32bit_value(runs);
+ }
run_counted = 1;
@@ -616,8 +612,17 @@ void llvm_writeout_files(void) {
}
}
-COMPILER_RT_VISIBILITY
-void llvm_delete_writeout_function_list(void) {
+#ifndef _WIN32
+// __attribute__((destructor)) and destructors whose priorities are greater than
+// 100 run before this function and can thus be tracked. The priority is
+// compatible with GCC 7 onwards.
+#if __GNUC__ >= 9
+#pragma GCC diagnostic ignored "-Wprio-ctor-dtor"
+#endif
+__attribute__((destructor(100)))
+#endif
+static void llvm_writeout_and_clear(void) {
+ llvm_writeout_files();
fn_list_remove(&writeout_fn_list);
}
@@ -698,8 +703,9 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn, fn_ptr rfn) {
/* Make sure we write out the data and delete the data structures. */
atexit(llvm_delete_reset_function_list);
atexit(llvm_delete_flush_function_list);
- atexit(llvm_delete_writeout_function_list);
- atexit(llvm_writeout_files);
+#ifdef _WIN32
+ atexit(llvm_writeout_and_clear);
+#endif
}
}
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.c
index 087d1cdd2ef..31a9fe99629 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.c
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.c
@@ -25,18 +25,8 @@ COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
: (INSTR_PROF_RAW_MAGIC_32);
}
-static unsigned ProfileDumped = 0;
-
-COMPILER_RT_VISIBILITY unsigned lprofProfileDumped() {
- return ProfileDumped;
-}
-
-COMPILER_RT_VISIBILITY void lprofSetProfileDumped() {
- ProfileDumped = 1;
-}
-
COMPILER_RT_VISIBILITY void __llvm_profile_set_dumped() {
- lprofSetProfileDumped();
+ lprofSetProfileDumped(1);
}
/* Return the number of bytes needed to add to SizeInBytes to make it
@@ -80,5 +70,5 @@ COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
}
}
}
- ProfileDumped = 0;
+ lprofSetProfileDumped(0);
}
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.h b/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.h
index 3a3bab3d0b4..d7a7c32332c 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.h
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfiling.h
@@ -218,6 +218,9 @@ int __llvm_profile_register_write_file_atexit(void);
/*! \brief Initialize file handling. */
void __llvm_profile_initialize_file(void);
+/*! \brief Initialize the profile runtime. */
+void __llvm_profile_initialize(void);
+
/*!
* \brief Return path prefix (excluding the base filename) of the profile data.
* This is useful for users using \c -fprofile-generate=./path_prefix who do
@@ -307,4 +310,11 @@ extern uint64_t INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */
*/
extern char INSTR_PROF_PROFILE_NAME_VAR[1]; /* __llvm_profile_filename. */
+/*!
+ * This variable is a weak symbol defined in InstrProfilingBiasVar.c. It
+ * allows compiler instrumentation to provide overriding definition with
+ * value from compiler command line. This variable has hidden visibility.
+ */
+COMPILER_RT_VISIBILITY extern intptr_t __llvm_profile_counter_bias;
+
#endif /* PROFILE_INSTRPROFILING_H_ */
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBiasVar.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBiasVar.c
new file mode 100644
index 00000000000..05745fd858d
--- /dev/null
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBiasVar.c
@@ -0,0 +1,15 @@
+/*===- InstrProfilingBiasVar.c - profile counter bias variable setup ------===*\
+|*
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+|* See https://llvm.org/LICENSE.txt for license information.
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfiling.h"
+
+/* The runtime should only provide its own definition of this symbol when the
+ * user has not specified one. Set this up by moving the runtime's copy of this
+ * symbol to an object file within the archive.
+ */
+COMPILER_RT_WEAK intptr_t __llvm_profile_counter_bias = -1;
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c
index 174280fd4b5..5ee44785a7a 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -62,7 +62,8 @@ void __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t *PaddingBytesAfterNames) {
- if (!__llvm_profile_is_continuous_mode_enabled()) {
+ if (!__llvm_profile_is_continuous_mode_enabled() ||
+ lprofRuntimeCounterRelocation()) {
*PaddingBytesBeforeCounters = 0;
*PaddingBytesAfterCounters = 0;
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingFile.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingFile.c
index 7f3727eed92..9e1a54a0c37 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingFile.c
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -448,6 +448,99 @@ static void unlockProfile(int *ProfileRequiresUnlock, FILE *File) {
}
#endif // !defined(__Fuchsia__) && !defined(_WIN32)
+static int writeMMappedFile(FILE *OutputFile, char **Profile) {
+ if (!OutputFile)
+ return -1;
+
+ /* Write the data into a file. */
+ setupIOBuffer();
+ ProfDataWriter fileWriter;
+ initFileWriter(&fileWriter, OutputFile);
+ if (lprofWriteData(&fileWriter, NULL, 0)) {
+ PROF_ERR("Failed to write profile: %s\n", strerror(errno));
+ return -1;
+ }
+ fflush(OutputFile);
+
+ /* Get the file size. */
+ uint64_t FileSize = ftell(OutputFile);
+
+ /* Map the profile. */
+ *Profile = (char *)mmap(
+ NULL, FileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(OutputFile), 0);
+ if (*Profile == MAP_FAILED) {
+ PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void relocateCounters(void) {
+ if (!__llvm_profile_is_continuous_mode_enabled() ||
+ !lprofRuntimeCounterRelocation())
+ return;
+
+ /* Get the sizes of various profile data sections. Taken from
+ * __llvm_profile_get_size_for_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
+ const uint64_t CountersOffset = sizeof(__llvm_profile_header) +
+ (DataSize * sizeof(__llvm_profile_data));
+
+ int Length = getCurFilenameLength();
+ char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
+ const char *Filename = getCurFilename(FilenameBuf, 0);
+ if (!Filename)
+ return;
+
+ FILE *File = NULL;
+ char *Profile = NULL;
+
+ if (!doMerging()) {
+ File = fopen(Filename, "w+b");
+ if (!File)
+ return;
+
+ if (writeMMappedFile(File, &Profile) == -1) {
+ fclose(File);
+ return;
+ }
+ } else {
+ File = lprofOpenFileEx(Filename);
+ if (!File)
+ return;
+
+ uint64_t ProfileFileSize = 0;
+ if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
+ lprofUnlockFileHandle(File);
+ fclose(File);
+ return;
+ }
+
+ if (!ProfileFileSize) {
+ if (writeMMappedFile(File, &Profile) == -1) {
+ fclose(File);
+ return;
+ }
+ } else {
+ /* The merged profile has a non-zero length. Check that it is compatible
+ * with the data in this process. */
+ if (mmapProfileForMerging(File, ProfileFileSize, &Profile) == -1) {
+ fclose(File);
+ return;
+ }
+ }
+
+ lprofUnlockFileHandle(File);
+ }
+
+ /* Update the profile fields based on the current mapping. */
+ __llvm_profile_counter_bias = (intptr_t)Profile -
+ (uintptr_t)__llvm_profile_begin_counters() + CountersOffset;
+}
+
static void initializeProfileForContinuousMode(void) {
if (!__llvm_profile_is_continuous_mode_enabled())
return;
@@ -715,7 +808,12 @@ static void parseAndSetFilename(const char *FilenamePat,
}
truncateCurrentFile();
- initializeProfileForContinuousMode();
+ if (__llvm_profile_is_continuous_mode_enabled()) {
+ if (lprofRuntimeCounterRelocation())
+ relocateCounters();
+ else
+ initializeProfileForContinuousMode();
+ }
}
/* Return buffer length that is required to store the current profile
@@ -854,10 +952,10 @@ const char *__llvm_profile_get_filename(void) {
return FilenameBuf;
}
-/* This method is invoked by the runtime initialization hook
- * InstrProfilingRuntime.o if it is linked in. Both user specified
+/* This API initializes the file handling, both user specified
* profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
- * environment variable can override this default value. */
+ * environment variable can override this default value.
+ */
COMPILER_RT_VISIBILITY
void __llvm_profile_initialize_file(void) {
const char *EnvFilenamePat;
@@ -865,6 +963,9 @@ void __llvm_profile_initialize_file(void) {
ProfileNameSpecifier PNS = PNS_unknown;
int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
+ if (__llvm_profile_counter_bias != -1)
+ lprofSetRuntimeCounterRelocation(1);
+
EnvFilenamePat = getFilenamePatFromEnv();
if (EnvFilenamePat) {
/* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
@@ -882,6 +983,16 @@ void __llvm_profile_initialize_file(void) {
parseAndSetFilename(SelectedPat, PNS, 0);
}
+/* This method is invoked by the runtime initialization hook
+ * InstrProfilingRuntime.o if it is linked in.
+ */
+COMPILER_RT_VISIBILITY
+void __llvm_profile_initialize(void) {
+ __llvm_profile_initialize_file();
+ if (!__llvm_profile_is_continuous_mode_enabled())
+ __llvm_profile_register_write_file_atexit();
+}
+
/* This API is directly called by the user application code. It has the
* highest precedence compared with LLVM_PROFILE_FILE environment variable
* and command line option -fprofile-instr-generate=<profile_name>.
@@ -951,7 +1062,7 @@ int __llvm_profile_dump(void) {
"in profile name or change profile name before dumping.\n",
"online profile merging is not on");
int rc = __llvm_profile_write_file();
- lprofSetProfileDumped();
+ lprofSetProfileDumped(1);
return rc;
}
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.c
new file mode 100644
index 00000000000..d58bc19ad11
--- /dev/null
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.c
@@ -0,0 +1,33 @@
+/*===- InstrProfilingInternal.c - Support library for PGO instrumentation -===*\
+|*
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+|* See https://llvm.org/LICENSE.txt for license information.
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+|*
+\*===----------------------------------------------------------------------===*/
+
+#if !defined(__Fuchsia__)
+
+#include "InstrProfilingInternal.h"
+
+static unsigned ProfileDumped = 0;
+
+COMPILER_RT_VISIBILITY unsigned lprofProfileDumped() {
+ return ProfileDumped;
+}
+
+COMPILER_RT_VISIBILITY void lprofSetProfileDumped(unsigned Value) {
+ ProfileDumped = Value;
+}
+
+static unsigned RuntimeCounterRelocation = 0;
+
+COMPILER_RT_VISIBILITY unsigned lprofRuntimeCounterRelocation(void) {
+ return RuntimeCounterRelocation;
+}
+
+COMPILER_RT_VISIBILITY void lprofSetRuntimeCounterRelocation(unsigned Value) {
+ RuntimeCounterRelocation = Value;
+}
+
+#endif
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.h b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.h
index 0cea4876f0a..904bd394592 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.h
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingInternal.h
@@ -181,8 +181,12 @@ uint64_t lprofGetLoadModuleSignature();
* Return non zero value if the profile data has already been
* dumped to the file.
*/
-unsigned lprofProfileDumped();
-void lprofSetProfileDumped();
+unsigned lprofProfileDumped(void);
+void lprofSetProfileDumped(unsigned);
+
+/* Return non zero value if counters are being relocated at runtime. */
+unsigned lprofRuntimeCounterRelocation(void);
+void lprofSetRuntimeCounterRelocation(unsigned);
COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *);
COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer;
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c
index 23b7efbe672..d8b7fa21d25 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c
@@ -34,16 +34,15 @@
#include "InstrProfilingInternal.h"
#include "InstrProfilingUtil.h"
-/* VMO that contains the coverage data shared across all modules. This symbol
- * has default visibility and is exported in each module (executable or DSO)
- * that statically links in the profiling runtime.
- */
-zx_handle_t __llvm_profile_vmo;
-/* Current offset within the VMO where data should be written next. This symbol
- * has default visibility and is exported in each module (executable or DSO)
- * that statically links in the profiling runtime.
- */
-uint64_t __llvm_profile_offset;
+COMPILER_RT_VISIBILITY unsigned lprofProfileDumped() {
+ return 1;
+}
+COMPILER_RT_VISIBILITY void lprofSetProfileDumped(unsigned Value) {}
+
+COMPILER_RT_VISIBILITY unsigned lprofRuntimeCounterRelocation(void) {
+ return 1;
+}
+COMPILER_RT_VISIBILITY void lprofSetRuntimeCounterRelocation(unsigned Value) {}
static const char ProfileSinkName[] = "llvm-profile";
@@ -58,65 +57,24 @@ static inline void lprofWrite(const char *fmt, ...) {
__sanitizer_log_write(s, ret + 1);
}
-static void createVMO() {
- /* Don't create VMO if it has been alread created. */
- if (__llvm_profile_vmo != ZX_HANDLE_INVALID)
- return;
-
- /* Get information about the current process. */
- zx_info_handle_basic_t Info;
- zx_status_t Status =
- _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
- sizeof(Info), NULL, NULL);
- if (Status != ZX_OK) {
- lprofWrite("LLVM Profile: cannot get info about current process: %s\n",
- _zx_status_get_string(Status));
- return;
- }
-
- /* Create VMO to hold the profile data. */
- Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &__llvm_profile_vmo);
- if (Status != ZX_OK) {
- lprofWrite("LLVM Profile: cannot create VMO: %s\n",
- _zx_status_get_string(Status));
- return;
- }
-
- /* Give the VMO a name including our process KOID so it's easy to spot. */
- char VmoName[ZX_MAX_NAME_LEN];
- snprintf(VmoName, sizeof(VmoName), "%s.%" PRIu64, ProfileSinkName, Info.koid);
- _zx_object_set_property(__llvm_profile_vmo, ZX_PROP_NAME, VmoName,
- strlen(VmoName));
-
- /* Duplicate the handle since __sanitizer_publish_data consumes it. */
- zx_handle_t Handle;
- Status =
- _zx_handle_duplicate(__llvm_profile_vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);
- if (Status != ZX_OK) {
- lprofWrite("LLVM Profile: cannot duplicate VMO handle: %s\n",
- _zx_status_get_string(Status));
- _zx_handle_close(__llvm_profile_vmo);
- __llvm_profile_vmo = ZX_HANDLE_INVALID;
- return;
- }
-
- /* Publish the VMO which contains profile data to the system. */
- __sanitizer_publish_data(ProfileSinkName, Handle);
-
- /* Use the dumpfile symbolizer markup element to write the name of VMO. */
- lprofWrite("LLVM Profile: {{{dumpfile:%s:%s}}}\n", ProfileSinkName, VmoName);
-}
+struct lprofVMOWriterCtx {
+ /* VMO that contains the profile data for this module. */
+ zx_handle_t Vmo;
+ /* Current offset within the VMO where data should be written next. */
+ uint64_t Offset;
+};
static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
uint32_t NumIOVecs) {
+ struct lprofVMOWriterCtx *Ctx = (struct lprofVMOWriterCtx *)This->WriterCtx;
+
/* Compute the total length of data to be written. */
size_t Length = 0;
for (uint32_t I = 0; I < NumIOVecs; I++)
Length += IOVecs[I].ElmSize * IOVecs[I].NumElm;
/* Resize the VMO to ensure there's sufficient space for the data. */
- zx_status_t Status =
- _zx_vmo_set_size(__llvm_profile_vmo, __llvm_profile_offset + Length);
+ zx_status_t Status = _zx_vmo_set_size(Ctx->Vmo, Ctx->Offset + Length);
if (Status != ZX_OK)
return -1;
@@ -124,74 +82,112 @@ static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
for (uint32_t I = 0; I < NumIOVecs; I++) {
size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
if (IOVecs[I].Data) {
- Status = _zx_vmo_write(__llvm_profile_vmo, IOVecs[I].Data,
- __llvm_profile_offset, Length);
+ Status = _zx_vmo_write(Ctx->Vmo, IOVecs[I].Data, Ctx->Offset, Length);
if (Status != ZX_OK)
return -1;
} else if (IOVecs[I].UseZeroPadding) {
/* Resizing the VMO should zero fill. */
}
- __llvm_profile_offset += Length;
+ Ctx->Offset += Length;
}
+ /* Record the profile size as a property of the VMO. */
+ _zx_object_set_property(Ctx->Vmo, ZX_PROP_VMO_CONTENT_SIZE, &Ctx->Offset,
+ sizeof(Ctx->Offset));
+
return 0;
}
-static void initVMOWriter(ProfDataWriter *This) {
+static void initVMOWriter(ProfDataWriter *This, struct lprofVMOWriterCtx *Ctx) {
This->Write = lprofVMOWriter;
- This->WriterCtx = NULL;
+ This->WriterCtx = Ctx;
}
-static int dump(void) {
- if (lprofProfileDumped()) {
- lprofWrite("LLVM Profile: data not published: already written.\n");
- return 0;
- }
-
+/* This method is invoked by the runtime initialization hook
+ * InstrProfilingRuntime.o if it is linked in. */
+COMPILER_RT_VISIBILITY
+void __llvm_profile_initialize(void) {
/* Check if there is llvm/runtime version mismatch. */
if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
lprofWrite("LLVM Profile: runtime and instrumentation version mismatch: "
"expected %d, but got %d\n",
INSTR_PROF_RAW_VERSION,
(int)GET_VERSION(__llvm_profile_get_version()));
- return -1;
+ return;
}
- /* Write the profile data into the mapped region. */
- ProfDataWriter VMOWriter;
- initVMOWriter(&VMOWriter);
- if (lprofWriteData(&VMOWriter, lprofGetVPDataReader(), 0) != 0)
- return -1;
+ /* This symbol is defined as weak and initialized to -1 by the runtimer, but
+ * compiler will generate a strong definition initialized to 0 when runtime
+ * counter relocation is used. */
+ if (__llvm_profile_counter_bias == -1) {
+ lprofWrite("LLVM Profile: counter relocation at runtime is required\n");
+ return;
+ }
- return 0;
-}
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
+ const uint64_t CountersOffset =
+ sizeof(__llvm_profile_header) + (DataSize * sizeof(__llvm_profile_data));
-COMPILER_RT_VISIBILITY
-int __llvm_profile_dump(void) {
- int rc = dump();
- lprofSetProfileDumped();
- return rc;
-}
+ zx_status_t Status;
-static void dumpWithoutReturn(void) { dump(); }
+ /* Create VMO to hold the profile data. */
+ zx_handle_t Vmo = ZX_HANDLE_INVALID;
+ Status = _zx_vmo_create(0, ZX_VMO_RESIZABLE, &Vmo);
+ if (Status != ZX_OK) {
+ lprofWrite("LLVM Profile: cannot create VMO: %s\n",
+ _zx_status_get_string(Status));
+ return;
+ }
-/* This method is invoked by the runtime initialization hook
- * InstrProfilingRuntime.o if it is linked in.
- */
-COMPILER_RT_VISIBILITY
-void __llvm_profile_initialize_file(void) { createVMO(); }
+ /* Give the VMO a name that includes the module signature. */
+ char VmoName[ZX_MAX_NAME_LEN];
+ snprintf(VmoName, sizeof(VmoName), "%" PRIu64 ".profraw",
+ lprofGetLoadModuleSignature());
+ _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));
-COMPILER_RT_VISIBILITY
-int __llvm_profile_register_write_file_atexit(void) {
- static bool HasBeenRegistered = false;
+ /* Write the profile data into the mapped region. */
+ ProfDataWriter VMOWriter;
+ struct lprofVMOWriterCtx Ctx = {.Vmo = Vmo, .Offset = 0};
+ initVMOWriter(&VMOWriter, &Ctx);
+ if (lprofWriteData(&VMOWriter, 0, 0) != 0) {
+ lprofWrite("LLVM Profile: failed to write data\n");
+ _zx_handle_close(Vmo);
+ return;
+ }
- if (HasBeenRegistered)
- return 0;
+ uint64_t Len = 0;
+ Status = _zx_vmo_get_size(Vmo, &Len);
+ if (Status != ZX_OK) {
+ lprofWrite("LLVM Profile: failed to get the VMO size: %s\n",
+ _zx_status_get_string(Status));
+ _zx_handle_close(Vmo);
+ return;
+ }
- lprofSetupValueProfiler();
+ uintptr_t Mapping;
+ Status =
+ _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
+ Vmo, 0, Len, &Mapping);
+ if (Status != ZX_OK) {
+ lprofWrite("LLVM Profile: failed to map the VMO: %s\n",
+ _zx_status_get_string(Status));
+ _zx_handle_close(Vmo);
+ return;
+ }
+
+ /* Publish the VMO which contains profile data to the system. Note that this
+ * also consumes the VMO handle. */
+ __sanitizer_publish_data(ProfileSinkName, Vmo);
+
+ /* Use the dumpfile symbolizer markup element to write the name of VMO. */
+ lprofWrite("LLVM Profile: {{{dumpfile:%s:%s}}}\n", ProfileSinkName, VmoName);
- HasBeenRegistered = true;
- return atexit(dumpWithoutReturn);
+ /* Update the profile fields based on the current mapping. */
+ __llvm_profile_counter_bias = (intptr_t)Mapping -
+ (uintptr_t)__llvm_profile_begin_counters() +
+ CountersOffset;
}
#endif
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPort.h b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPort.h
index 20cf5d660c6..4493dd512ff 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPort.h
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingPort.h
@@ -53,9 +53,9 @@
#endif
#if COMPILER_RT_HAS_ATOMICS == 1
-#ifdef _MSC_VER
+#ifdef _WIN32
#include <windows.h>
-#if _MSC_VER < 1900
+#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
#if defined(_WIN64)
@@ -73,7 +73,7 @@
(DomType *)InterlockedExchangeAdd((LONG volatile *)&PtrVar, \
(LONG)sizeof(DomType) * PtrIncr)
#endif
-#else /* !defined(_MSC_VER) */
+#else /* !defined(_WIN32) */
#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
__sync_bool_compare_and_swap(Ptr, OldV, NewV)
#define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingRuntime.cpp b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingRuntime.cpp
index 5dff09d7063..4ea2bb263f5 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingRuntime.cpp
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingRuntime.cpp
@@ -19,9 +19,7 @@ namespace {
class RegisterRuntime {
public:
RegisterRuntime() {
- __llvm_profile_initialize_file();
- if (!__llvm_profile_is_continuous_mode_enabled())
- __llvm_profile_register_write_file_atexit();
+ __llvm_profile_initialize();
}
};
diff --git a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingUtil.h b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingUtil.h
index f0e29a8803a..5f5c85091fe 100644
--- a/gnu/llvm/compiler-rt/lib/profile/InstrProfilingUtil.h
+++ b/gnu/llvm/compiler-rt/lib/profile/InstrProfilingUtil.h
@@ -30,11 +30,13 @@ int lprofUnlockFileHandle(FILE *F);
* lock for exclusive access. The caller will block
* if the lock is already held by another process. */
FILE *lprofOpenFileEx(const char *Filename);
-/* PS4 doesn't have setenv/getenv. Define a shim. */
+/* PS4 doesn't have setenv/getenv/fork. Define a shim. */
#if __ORBIS__
+#include <sys/types.h>
static inline char *getenv(const char *name) { return NULL; }
static inline int setenv(const char *name, const char *value, int overwrite)
{ return 0; }
+static pid_t fork() { return -1; }
#endif /* #if __ORBIS__ */
/* GCOV_PREFIX and GCOV_PREFIX_STRIP support */