aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-08-02 17:33:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-08-02 17:33:19 +0000
commit005b7ed8f76756d94ef6266ded755ab7863cb936 (patch)
treede2aa8f0c2f604d3b4f81a94dd20ea0c50bf1e68 /lib
parent93c1b73a09a52d4a265f683bf1954b08bb430049 (diff)
downloadsrc-005b7ed8f76756d94ef6266ded755ab7863cb936.tar.gz
src-005b7ed8f76756d94ef6266ded755ab7863cb936.zip
Vendor import of compiler-rt trunk r338536:vendor/compiler-rt/compiler-rt-trunk-r338536
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=337141 svn path=/vendor/compiler-rt/compiler-rt-trunk-r338536/; revision=337142; tag=vendor/compiler-rt/compiler-rt-trunk-r338536
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_mapping.h2
-rw-r--r--lib/asan/tests/asan_test.cc2
-rw-r--r--lib/builtins/CMakeLists.txt9
-rw-r--r--lib/profile/InstrProfilingUtil.c11
-rw-r--r--lib/profile/InstrProfilingUtil.h6
-rw-r--r--lib/sanitizer_common/sanitizer_mutex.h7
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc35
-rw-r--r--lib/ubsan/ubsan_checks.inc2
-rw-r--r--lib/ubsan/ubsan_diag.h2
-rw-r--r--lib/ubsan/ubsan_handlers.cc43
-rw-r--r--lib/ubsan/ubsan_handlers.h17
-rw-r--r--lib/ubsan/ubsan_interface.inc2
-rw-r--r--lib/ubsan_minimal/ubsan_minimal_handlers.cc1
-rw-r--r--lib/xray/tests/unit/profile_collector_test.cc36
-rw-r--r--lib/xray/xray_buffer_queue.cc55
-rw-r--r--lib/xray/xray_profile_collector.cc30
-rw-r--r--lib/xray/xray_profiling.cc19
17 files changed, 209 insertions, 70 deletions
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 3f8cc004b95f..f3696da62b30 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -122,7 +122,7 @@
// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
//
-// Shadow mapping on NerBSD/i386 with SHADOW_OFFSET == 0x40000000:
+// Shadow mapping on NetBSD/i386 with SHADOW_OFFSET == 0x40000000:
// || `[0x60000000, 0xfffff000]` || HighMem ||
// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 11a3506a4853..25d6a2083450 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -963,7 +963,7 @@ TEST(AddressSanitizer, ThreadNamesTest) {
#if ASAN_NEEDS_SEGV
TEST(AddressSanitizer, ShadowGapTest) {
#if SANITIZER_WORDSIZE == 32
- char *addr = (char*)0x22000000;
+ char *addr = (char*)0x23000000;
#else
# if defined(__powerpc64__)
char *addr = (char*)0x024000800000;
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 75ff66405649..82332967b104 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -567,6 +567,15 @@ else ()
set(_arch "arm")
endif()
+ # For ARM archs, exclude any VFP builtins if VFP is not supported
+ if (${arch} MATCHES "^(arm|armhf|armv7|armv7s|armv7k|armv7m|armv7em)$")
+ string(REPLACE ";" " " _TARGET_${arch}_CFLAGS "${TARGET_${arch}_CFLAGS}")
+ check_compile_definition(__VFP_FP__ "${CMAKE_C_FLAGS} ${_TARGET_${arch}_CFLAGS}" COMPILER_RT_HAS_${arch}_VFP)
+ if(NOT COMPILER_RT_HAS_${arch}_VFP)
+ list(REMOVE_ITEM ${arch}_SOURCES ${arm_Thumb1_VFPv2_SOURCES} ${arm_Thumb1_SjLj_EH_SOURCES})
+ endif()
+ endif()
+
# Filter out generic versions of routines that are re-implemented in
# architecture specific manner. This prevents multiple definitions of the
# same symbols, making the symbol selection non-deterministic.
diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c
index d053ab160ca7..083bf14a3260 100644
--- a/lib/profile/InstrProfilingUtil.c
+++ b/lib/profile/InstrProfilingUtil.c
@@ -35,6 +35,8 @@
#include "InstrProfiling.h"
#include "InstrProfilingUtil.h"
+COMPILER_RT_WEAK unsigned lprofDirMode = 0755;
+
COMPILER_RT_VISIBILITY
void __llvm_profile_recursive_mkdir(char *path) {
int i;
@@ -47,12 +49,19 @@ void __llvm_profile_recursive_mkdir(char *path) {
#ifdef _WIN32
_mkdir(path);
#else
- mkdir(path, 0755); /* Some of these will fail, ignore it. */
+ /* Some of these will fail, ignore it. */
+ mkdir(path, __llvm_profile_get_dir_mode());
#endif
path[i] = save;
}
}
+COMPILER_RT_VISIBILITY
+void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; }
+
+COMPILER_RT_VISIBILITY
+unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; }
+
#if COMPILER_RT_HAS_ATOMICS != 1
COMPILER_RT_VISIBILITY
uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h
index 2f2ea1b876a8..147677fc8700 100644
--- a/lib/profile/InstrProfilingUtil.h
+++ b/lib/profile/InstrProfilingUtil.h
@@ -16,6 +16,12 @@
/*! \brief Create a directory tree. */
void __llvm_profile_recursive_mkdir(char *Pathname);
+/*! Set the mode used when creating profile directories. */
+void __llvm_profile_set_dir_mode(unsigned Mode);
+
+/*! Return the directory creation mode. */
+unsigned __llvm_profile_get_dir_mode(void);
+
int lprofLockFd(int fd);
int lprofUnlockFd(int fd);
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index 4bb878ee19dc..a93705be6918 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -73,13 +73,8 @@ class SpinMutex : public StaticSpinMutex {
class BlockingMutex {
public:
-#if SANITIZER_WINDOWS
- // Windows does not currently support LinkerInitialized
- explicit BlockingMutex(LinkerInitialized);
-#else
explicit constexpr BlockingMutex(LinkerInitialized)
- : opaque_storage_ {0, }, owner_(0) {}
-#endif
+ : opaque_storage_ {0, }, owner_ {0} {}
BlockingMutex();
void Lock();
void Unlock();
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index b8060b2e640c..38e567d9a732 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -767,43 +767,22 @@ void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
void internal_join_thread(void *th) { }
// ---------------------- BlockingMutex ---------------- {{{1
-const uptr LOCK_UNINITIALIZED = 0;
-const uptr LOCK_READY = (uptr)-1;
-
-BlockingMutex::BlockingMutex(LinkerInitialized li) {
- // FIXME: see comments in BlockingMutex::Lock() for the details.
- CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
-
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
-}
BlockingMutex::BlockingMutex() {
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
+ CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_));
+ internal_memset(this, 0, sizeof(*this));
}
void BlockingMutex::Lock() {
- if (owner_ == LOCK_UNINITIALIZED) {
- // FIXME: hm, global BlockingMutex objects are not initialized?!?
- // This might be a side effect of the clang+cl+link Frankenbuild...
- new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
-
- // FIXME: If it turns out the linker doesn't invoke our
- // constructors, we should probably manually Lock/Unlock all the global
- // locks while we're starting in one thread to avoid double-init races.
- }
- EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- CHECK_EQ(owner_, LOCK_READY);
+ AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_);
+ CHECK_EQ(owner_, 0);
owner_ = GetThreadSelf();
}
void BlockingMutex::Unlock() {
- CHECK_EQ(owner_, GetThreadSelf());
- owner_ = LOCK_READY;
- LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+ CheckLocked();
+ owner_ = 0;
+ ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_);
}
void BlockingMutex::CheckLocked() {
diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc
index 73c69363215a..5a7bdec2df12 100644
--- a/lib/ubsan/ubsan_checks.inc
+++ b/lib/ubsan/ubsan_checks.inc
@@ -30,6 +30,8 @@ UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
"integer-divide-by-zero")
UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use")
+UBSAN_CHECK(ImplicitIntegerTruncation, "implicit-integer-truncation",
+ "implicit-integer-truncation")
UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h
index d9ea410c358c..bde749684c65 100644
--- a/lib/ubsan/ubsan_diag.h
+++ b/lib/ubsan/ubsan_diag.h
@@ -178,7 +178,7 @@ public:
};
private:
- static const unsigned MaxArgs = 5;
+ static const unsigned MaxArgs = 8;
static const unsigned MaxRanges = 1;
/// The arguments which have been added to this diagnostic so far.
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 49c6bcacbe27..e72a32cf32c2 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -451,6 +451,49 @@ void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
Die();
}
+static void handleImplicitConversion(ImplicitConversionData *Data,
+ ReportOptions Opts, ValueHandle Src,
+ ValueHandle Dst) {
+ SourceLocation Loc = Data->Loc.acquire();
+ ErrorType ET = ErrorType::GenericUB;
+
+ switch (Data->Kind) {
+ case ICCK_IntegerTruncation:
+ ET = ErrorType::ImplicitIntegerTruncation;
+ break;
+ }
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ const TypeDescriptor &SrcTy = Data->FromType;
+ const TypeDescriptor &DstTy = Data->ToType;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ // FIXME: is it possible to dump the values as hex with fixed width?
+
+ Diag(Loc, DL_Error, ET,
+ "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
+ "type %4 changed the value to %5 (%6-bit, %7signed)")
+ << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
+ << (SrcTy.isSignedIntegerTy() ? "" : "un") << DstTy << Value(DstTy, Dst)
+ << DstTy.getIntegerBitWidth() << (DstTy.isSignedIntegerTy() ? "" : "un");
+}
+
+void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,
+ ValueHandle Src,
+ ValueHandle Dst) {
+ GET_REPORT_OPTIONS(false);
+ handleImplicitConversion(Data, Opts, Src, Dst);
+}
+void __ubsan::__ubsan_handle_implicit_conversion_abort(
+ ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) {
+ GET_REPORT_OPTIONS(true);
+ handleImplicitConversion(Data, Opts, Src, Dst);
+ Die();
+}
+
static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::InvalidBuiltin;
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index ed3c8f0b1b0e..07644b7ea15d 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -122,6 +122,23 @@ struct InvalidValueData {
/// \brief Handle a load of an invalid value for the type.
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
+/// Known implicit conversion check kinds.
+/// Keep in sync with the enum of the same name in CGExprScalar.cpp
+enum ImplicitConversionCheckKind : unsigned char {
+ ICCK_IntegerTruncation = 0,
+};
+
+struct ImplicitConversionData {
+ SourceLocation Loc;
+ const TypeDescriptor &FromType;
+ const TypeDescriptor &ToType;
+ /* ImplicitConversionCheckKind */ unsigned char Kind;
+};
+
+/// \brief Implict conversion that changed the value.
+RECOVERABLE(implicit_conversion, ImplicitConversionData *Data, ValueHandle Src,
+ ValueHandle Dst)
+
/// Known builtin check kinds.
/// Keep in sync with the enum of the same name in CodeGenFunction.h
enum BuiltinCheckKind : unsigned char {
diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc
index 782c621a2b47..0be6010ad27b 100644
--- a/lib/ubsan/ubsan_interface.inc
+++ b/lib/ubsan/ubsan_interface.inc
@@ -22,6 +22,8 @@ INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow)
INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch)
INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_abort)
+INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion)
+INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion_abort)
INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin)
INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort)
INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value)
diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc
index f25a75a863c4..e8fc3a8499b5 100644
--- a/lib/ubsan_minimal/ubsan_minimal_handlers.cc
+++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc
@@ -109,6 +109,7 @@ HANDLER(float_cast_overflow, "float-cast-overflow")
HANDLER(load_invalid_value, "load-invalid-value")
HANDLER(invalid_builtin, "invalid-builtin")
HANDLER(function_type_mismatch, "function-type-mismatch")
+HANDLER(implicit_conversion, "implicit-conversion")
HANDLER(nonnull_arg, "nonnull-arg")
HANDLER(nonnull_return, "nonnull-return")
HANDLER(nullability_arg, "nullability-arg")
diff --git a/lib/xray/tests/unit/profile_collector_test.cc b/lib/xray/tests/unit/profile_collector_test.cc
index b7dbe567312a..67049af2cd5f 100644
--- a/lib/xray/tests/unit/profile_collector_test.cc
+++ b/lib/xray/tests/unit/profile_collector_test.cc
@@ -15,6 +15,8 @@
#include "xray_profile_collector.h"
#include "xray_profiling_flags.h"
#include <cstdint>
+#include <cstring>
+#include <memory>
#include <thread>
#include <utility>
#include <vector>
@@ -24,6 +26,29 @@ namespace {
static constexpr auto kHeaderSize = 16u;
+constexpr uptr ExpectedProfilingVersion = 0x20180424;
+
+struct ExpectedProfilingFileHeader {
+ const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling
+ // files 'xrayprof' in hex.
+ const u64 Version = ExpectedProfilingVersion;
+ u64 Timestamp = 0;
+ u64 PID = 0;
+};
+
+void ValidateFileHeaderBlock(XRayBuffer B) {
+ ASSERT_NE(static_cast<const void *>(B.Data), nullptr);
+ ASSERT_EQ(B.Size, sizeof(ExpectedProfilingFileHeader));
+ typename std::aligned_storage<sizeof(ExpectedProfilingFileHeader)>::type
+ FileHeaderStorage;
+ ExpectedProfilingFileHeader ExpectedHeader;
+ std::memcpy(&FileHeaderStorage, B.Data, B.Size);
+ auto &FileHeader =
+ *reinterpret_cast<ExpectedProfilingFileHeader *>(&FileHeaderStorage);
+ ASSERT_EQ(ExpectedHeader.MagicBytes, FileHeader.MagicBytes);
+ ASSERT_EQ(ExpectedHeader.Version, FileHeader.Version);
+}
+
void ValidateBlock(XRayBuffer B) {
profilingFlags()->setDefaults();
ASSERT_NE(static_cast<const void *>(B.Data), nullptr);
@@ -107,9 +132,13 @@ TEST(profileCollectorServiceTest, PostSerializeCollect) {
// Then we serialize the data.
profileCollectorService::serialize();
- // Then we go through a single buffer to see whether we're getting the data we
- // expect.
+ // Then we go through two buffers to see whether we're getting the data we
+ // expect. The first block must always be as large as a file header, which
+ // will have a fixed size.
auto B = profileCollectorService::nextBuffer({nullptr, 0});
+ ValidateFileHeaderBlock(B);
+
+ B = profileCollectorService::nextBuffer(B);
ValidateBlock(B);
u32 BlockSize;
u32 BlockNum;
@@ -169,6 +198,9 @@ TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) {
// Ensure that we see two buffers.
auto B = profileCollectorService::nextBuffer({nullptr, 0});
+ ValidateFileHeaderBlock(B);
+
+ B = profileCollectorService::nextBuffer(B);
ValidateBlock(B);
B = profileCollectorService::nextBuffer(B);
diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc
index 8dfcc23540b1..3ce728900787 100644
--- a/lib/xray/xray_buffer_queue.cc
+++ b/lib/xray/xray_buffer_queue.cc
@@ -13,17 +13,50 @@
//
//===----------------------------------------------------------------------===//
#include "xray_buffer_queue.h"
-#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include <memory>
+#include <sys/mman.h>
+
+#ifndef MAP_NORESERVE
+// no-op on NetBSD (at least), unsupported flag on FreeBSD
+#define MAP_NORESERVE 0
+#endif
using namespace __xray;
using namespace __sanitizer;
+template <class T> static T *allocRaw(size_t N) {
+ // TODO: Report errors?
+ // We use MAP_NORESERVE on platforms where it's supported to ensure that the
+ // pages we're allocating for XRay never end up in pages that can be swapped
+ // in/out. We're doing this because for FDR mode, we want to ensure that
+ // writes to the buffers stay resident in memory to prevent XRay itself from
+ // causing swapping/thrashing.
+ //
+ // In the case when XRay pages cannot be swapped in/out or there's not enough
+ // RAM to back these pages, we're willing to cause a segmentation fault
+ // instead of introducing latency in the measurement. We assume here that
+ // there are enough pages that are swappable in/out outside of the buffers
+ // being used by FDR mode (which are bounded and configurable anyway) to allow
+ // us to keep using always-resident memory.
+ //
+ // TODO: Make this configurable?
+ void *A = reinterpret_cast<void *>(
+ internal_mmap(NULL, N * sizeof(T), PROT_WRITE | PROT_READ,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0));
+ return (A == MAP_FAILED) ? nullptr : reinterpret_cast<T *>(A);
+}
+
+template <class T> static void deallocRaw(T *ptr, size_t N) {
+ // TODO: Report errors?
+ if (ptr != nullptr)
+ internal_munmap(ptr, N);
+}
+
template <class T> static T *initArray(size_t N) {
- auto A = reinterpret_cast<T *>(
- InternalAlloc(N * sizeof(T), nullptr, kCacheLineSize));
+ auto A = allocRaw<T>(N);
if (A != nullptr)
while (N > 0)
new (A + (--N)) T();
@@ -42,19 +75,19 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success)
// Clean up the buffers we've already allocated.
for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B)
B->~BufferRep();
- InternalFree(Buffers);
+ deallocRaw(Buffers, N);
Success = false;
return;
};
for (size_t i = 0; i < N; ++i) {
auto &T = Buffers[i];
- void *Tmp = InternalAlloc(BufferSize, nullptr, 64);
+ void *Tmp = allocRaw<char>(BufferSize);
if (Tmp == nullptr) {
Success = false;
return;
}
- void *Extents = InternalAlloc(sizeof(BufferExtents), nullptr, 64);
+ auto *Extents = allocRaw<BufferExtents>(1);
if (Extents == nullptr) {
Success = false;
return;
@@ -62,7 +95,7 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success)
auto &Buf = T.Buff;
Buf.Data = Tmp;
Buf.Size = B;
- Buf.Extents = reinterpret_cast<BufferExtents *>(Extents);
+ Buf.Extents = Extents;
OwnedBuffers[i] = Tmp;
}
Success = true;
@@ -128,11 +161,11 @@ BufferQueue::~BufferQueue() {
for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) {
auto &T = *I;
auto &Buf = T.Buff;
- InternalFree(Buf.Data);
- InternalFree(Buf.Extents);
+ deallocRaw(Buf.Data, Buf.Size);
+ deallocRaw(Buf.Extents, 1);
}
for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B)
B->~BufferRep();
- InternalFree(Buffers);
- InternalFree(OwnedBuffers);
+ deallocRaw(Buffers, BufferCount);
+ deallocRaw(OwnedBuffers, BufferCount);
}
diff --git a/lib/xray/xray_profile_collector.cc b/lib/xray/xray_profile_collector.cc
index a43744d9a0cb..17a611eeacb8 100644
--- a/lib/xray/xray_profile_collector.cc
+++ b/lib/xray/xray_profile_collector.cc
@@ -37,6 +37,19 @@ struct ProfileBuffer {
size_t Size;
};
+// Current version of the profile format.
+constexpr u64 XRayProfilingVersion = 0x20180424;
+
+// Identifier for XRay profiling files 'xrayprof' in hex.
+constexpr u64 XRayMagicBytes = 0x7872617970726f66;
+
+struct XRayProfilingFileHeader {
+ const u64 MagicBytes = XRayMagicBytes;
+ const u64 Version = XRayProfilingVersion;
+ u64 Timestamp = 0; // System time in nanoseconds.
+ u64 PID = 0; // Process ID.
+};
+
struct BlockHeader {
u32 BlockSize;
u32 BlockNum;
@@ -302,7 +315,22 @@ XRayBuffer nextBuffer(XRayBuffer B) {
if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0)
return {nullptr, 0};
- if (B.Data == nullptr)
+ static pthread_once_t Once = PTHREAD_ONCE_INIT;
+ static typename std::aligned_storage<sizeof(XRayProfilingFileHeader)>::type
+ FileHeaderStorage;
+ pthread_once(&Once,
+ +[] { new (&FileHeaderStorage) XRayProfilingFileHeader{}; });
+
+ if (UNLIKELY(B.Data == nullptr)) {
+ // The first buffer should always contain the file header information.
+ auto &FileHeader =
+ *reinterpret_cast<XRayProfilingFileHeader *>(&FileHeaderStorage);
+ FileHeader.Timestamp = NanoTime();
+ FileHeader.PID = internal_getpid();
+ return {&FileHeaderStorage, sizeof(XRayProfilingFileHeader)};
+ }
+
+ if (UNLIKELY(B.Data == &FileHeaderStorage))
return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size};
BlockHeader Header;
diff --git a/lib/xray/xray_profiling.cc b/lib/xray/xray_profiling.cc
index 786084c77226..d4b4345d764a 100644
--- a/lib/xray/xray_profiling.cc
+++ b/lib/xray/xray_profiling.cc
@@ -32,16 +32,6 @@ namespace __xray {
namespace {
-constexpr uptr XRayProfilingVersion = 0x20180424;
-
-struct XRayProfilingFileHeader {
- const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling
- // files 'xrayprof' in hex.
- const uptr Version = XRayProfilingVersion;
- uptr Timestamp = 0; // System time in nanoseconds.
- uptr PID = 0; // Process ID.
-};
-
atomic_sint32_t ProfilerLogFlushStatus = {
XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING};
@@ -144,14 +134,7 @@ XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT {
if (Verbosity())
Report("profiling: Failed to flush to file, dropping data.\n");
} else {
- XRayProfilingFileHeader Header;
- Header.Timestamp = NanoTime();
- Header.PID = internal_getpid();
- retryingWriteAll(Fd, reinterpret_cast<const char *>(&Header),
- reinterpret_cast<const char *>(&Header) +
- sizeof(Header));
-
- // Now for each of the threads, write out the profile data as we would
+ // Now for each of the buffers, write out the profile data as we would
// see it in memory, verbatim.
while (B.Data != nullptr && B.Size != 0) {
retryingWriteAll(Fd, reinterpret_cast<const char *>(B.Data),