[llvm] 3a4d373 - [memprof] Align each rawprofile section to 8b.
Snehasish Kumar via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 30 20:19:08 PST 2021
Author: Snehasish Kumar
Date: 2021-11-30T20:12:43-08:00
New Revision: 3a4d373ec2ba676dc91fba06631a776785f8a6eb
URL: https://github.com/llvm/llvm-project/commit/3a4d373ec2ba676dc91fba06631a776785f8a6eb
DIFF: https://github.com/llvm/llvm-project/commit/3a4d373ec2ba676dc91fba06631a776785f8a6eb.diff
LOG: [memprof] Align each rawprofile section to 8b.
The first 8b of each raw profile section need to be aligned to 8b since
the first item in each section is a u64 count of the number of items in
the section.
Summary of changes:
* Assert alignment when reading counts.
* Update test to check alignment, relax some size checks to allow padding.
* Update raw binary inputs for llvm-profdata tests.
Differential Revision: https://reviews.llvm.org/D114826
Added:
Modified:
compiler-rt/lib/memprof/memprof_rawprofile.cpp
compiler-rt/lib/memprof/tests/rawprofile.cpp
llvm/lib/ProfileData/RawMemProfReader.cpp
llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
llvm/test/tools/llvm-profdata/memprof-basic.test
Removed:
################################################################################
diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
index 48e579cdab260..c4800a6df34c2 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
@@ -6,6 +6,7 @@
#include "memprof_rawprofile.h"
#include "profile/MemProfData.inc"
#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -77,7 +78,7 @@ void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
// Store the number of segments we recorded in the space we reserved.
*((u64 *)Buffer) = NumSegmentsRecorded;
- CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+ CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
"Expected num bytes != actual bytes written");
}
@@ -132,7 +133,7 @@ void SerializeStackToBuffer(const Vector<u64> &StackIds,
*(u64 *)(Ptr - (Count + 1) * sizeof(u64)) = Count;
}
- CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+ CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
"Expected num bytes != actual bytes written");
}
@@ -160,7 +161,7 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
Ptr = WriteBytes((*h)->mib, Ptr);
}
- CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+ CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
"Expected num bytes != actual bytes written");
}
@@ -181,11 +182,15 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
// BuildID 32B
// ----------
// ...
+// ----------
+// Optional Padding Bytes
// ---------- MIB Info
// Num Entries
// ---------- MIB Entry
// Alloc Count
// ...
+// ----------
+// Optional Padding Bytes
// ---------- Stack Info
// Num Entries
// ---------- Stack Entry
@@ -194,23 +199,29 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
// PC2
// ...
// ----------
+// Optional Padding Bytes
// ...
u64 SerializeToRawProfile(MIBMapTy &MIBMap, MemoryMappingLayoutBase &Layout,
char *&Buffer) {
- const u64 NumSegmentBytes = SegmentSizeBytes(Layout);
+ // Each section size is rounded up to 8b since the first entry in each section
+ // is a u64 which holds the number of entries in the section by convention.
+ const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Layout), 8);
Vector<u64> StackIds;
MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
// The first 8b are for the total number of MIB records. Each MIB record is
// preceded by a 8b stack id which is associated with stack frames in the next
// section.
- const u64 NumMIBInfoBytes =
- sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock));
+ const u64 NumMIBInfoBytes = RoundUpTo(
+ sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8);
- const u64 NumStackBytes = StackSizeBytes(StackIds);
+ const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
- const u64 TotalSizeBytes =
- sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes;
+ // Ensure that the profile is 8b aligned. We allow for some optional padding
+ // at the end so that any subsequent profile serialized to the same file does
+ // not incur unaligned accesses.
+ const u64 TotalSizeBytes = RoundUpTo(
+ sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8);
// Allocate the memory for the entire buffer incl. info blocks.
Buffer = (char *)InternalAlloc(TotalSizeBytes);
diff --git a/compiler-rt/lib/memprof/tests/rawprofile.cpp b/compiler-rt/lib/memprof/tests/rawprofile.cpp
index 29bc3b5f5ba80..829e183707376 100644
--- a/compiler-rt/lib/memprof/tests/rawprofile.cpp
+++ b/compiler-rt/lib/memprof/tests/rawprofile.cpp
@@ -49,6 +49,8 @@ u64 PopulateFakeMap(const MemInfoBlock &FakeMIB, uptr StackPCBegin,
template <class T = u64> T Read(char *&Buffer) {
static_assert(std::is_pod<T>::value, "Must be a POD type.");
+ assert(reinterpret_cast<size_t>(Buffer) % sizeof(T) == 0 &&
+ "Unaligned read!");
T t = *reinterpret_cast<T *>(Buffer);
Buffer += sizeof(T);
return t;
@@ -103,8 +105,9 @@ TEST(MemProf, Basic) {
const u64 MIBOffset = Read(Ptr);
const u64 StackOffset = Read(Ptr);
- // ============= Check sizes.
+ // ============= Check sizes and padding.
EXPECT_EQ(TotalSize, NumBytes);
+ EXPECT_EQ(TotalSize % 8, 0ULL);
// Should be equal to the size of the raw profile header.
EXPECT_EQ(SegmentOffset, 48ULL);
@@ -120,8 +123,10 @@ TEST(MemProf, Basic) {
EXPECT_EQ(StackOffset, 336ULL);
// We expect 2 stack entries, with 5 frames - 8b for total count,
- // 2 * (8b for id, 8b for frame count and 5*8b for fake frames)
- EXPECT_EQ(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));
+ // 2 * (8b for id, 8b for frame count and 5*8b for fake frames).
+ // Since this is the last section, there may be additional padding at the end
+ // to make the total profile size 8b aligned.
+ EXPECT_GE(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));
// ============= Check contents.
unsigned char ExpectedSegmentBytes[64] = {
diff --git a/llvm/lib/ProfileData/RawMemProfReader.cpp b/llvm/lib/ProfileData/RawMemProfReader.cpp
index 07c218aa97466..f8d13c74fac39 100644
--- a/llvm/lib/ProfileData/RawMemProfReader.cpp
+++ b/llvm/lib/ProfileData/RawMemProfReader.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include <cstdint>
+#include <type_traits>
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/ProfileData/MemProfData.inc"
@@ -28,15 +29,22 @@ struct Summary {
uint64_t NumStackOffsets;
};
+template <class T = uint64_t> inline T alignedRead(const char *Ptr) {
+ static_assert(std::is_pod<T>::value, "Not a pod type.");
+ assert(reinterpret_cast<size_t>(Ptr) % sizeof(T) == 0 && "Unaligned Read");
+ return *reinterpret_cast<const T *>(Ptr);
+}
+
Summary computeSummary(const char *Start) {
auto *H = reinterpret_cast<const Header *>(Start);
+ // Check alignment while reading the number of items in each section.
return Summary{
H->Version,
H->TotalSize,
- *reinterpret_cast<const uint64_t *>(Start + H->SegmentOffset),
- *reinterpret_cast<const uint64_t *>(Start + H->MIBOffset),
- *reinterpret_cast<const uint64_t *>(Start + H->StackOffset),
+ alignedRead(Start + H->SegmentOffset),
+ alignedRead(Start + H->MIBOffset),
+ alignedRead(Start + H->StackOffset),
};
}
@@ -84,7 +92,9 @@ RawMemProfReader::create(const Twine &Path) {
bool RawMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
if (Buffer.getBufferSize() < sizeof(uint64_t))
return false;
- uint64_t Magic = *reinterpret_cast<const uint64_t *>(Buffer.getBufferStart());
+ // Aligned read to sanity check that the buffer was allocated with at least 8b
+ // alignment.
+ const uint64_t Magic = alignedRead(Buffer.getBufferStart());
return Magic == MEMPROF_RAW_MAGIC_64;
}
diff --git a/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw b/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
index b0be02ade8da6..42bd6e72140ca 100644
Binary files a/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw and b/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
diff er
diff --git a/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw b/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
index e740903344cac..fd8f4129e6094 100644
Binary files a/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw and b/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
diff er
diff --git a/llvm/test/tools/llvm-profdata/memprof-basic.test b/llvm/test/tools/llvm-profdata/memprof-basic.test
index 1ef7c712abcc4..321119ba566ae 100644
--- a/llvm/test/tools/llvm-profdata/memprof-basic.test
+++ b/llvm/test/tools/llvm-profdata/memprof-basic.test
@@ -36,7 +36,7 @@ additional entry from a realloc in glibc/libio/vasprintf.c.
CHECK: MemProf Profile 1
CHECK: Version: 1
-CHECK: TotalSizeBytes: 1012
+CHECK: TotalSizeBytes: 1016
CHECK: NumSegments: 9
CHECK: NumMIBInfo: 3
CHECK: NumStackOffsets: 3
More information about the llvm-commits
mailing list