[compiler-rt] [llvm] Draft changes to trim the histogram raw profile format. (PR #147854)
Snehasish Kumar via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 12 14:26:46 PDT 2025
https://github.com/snehasish updated https://github.com/llvm/llvm-project/pull/147854
>From 3371ae262edf9baad35d5b566b4053e897396a3e Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 8 Jul 2025 23:07:26 -0700
Subject: [PATCH] Draft changes to trim the histogram raw profile format.
---
compiler-rt/include/profile/MemProfData.inc | 10 ++++--
compiler-rt/lib/memprof/memprof_allocator.cpp | 9 +++---
.../lib/memprof/memprof_rawprofile.cpp | 5 +--
.../TestCases/memprof_histogram_uint8.cpp | 32 +++++++++++++++++++
llvm/include/llvm/ProfileData/MemProfData.inc | 10 ++++--
5 files changed, 54 insertions(+), 12 deletions(-)
create mode 100644 compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp
diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc
index 3f785bd23fce3..4a43f72c2405d 100644
--- a/compiler-rt/include/profile/MemProfData.inc
+++ b/compiler-rt/include/profile/MemProfData.inc
@@ -33,11 +33,11 @@
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
-#define MEMPROF_RAW_VERSION 4ULL
+#define MEMPROF_RAW_VERSION 5ULL
// Currently supported versions.
#define MEMPROF_RAW_SUPPORTED_VERSIONS \
- { 3ULL, 4ULL }
+ { 3ULL, 4ULL, 5ULL }
#define MEMPROF_V3_MIB_SIZE 132ULL;
@@ -219,7 +219,11 @@ void Merge(const MemInfoBlock &newMIB) {
ShorterHistogramSize = newMIB.AccessHistogramSize;
}
for (size_t i = 0; i < ShorterHistogramSize; ++i) {
- ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];
+ // Cast to uint8_t* and cap the sum at 255 to prevent overflow
+ uint8_t *CurrentHistPtr = (uint8_t *)AccessHistogram;
+ uint8_t *ShorterHistPtr = (uint8_t *)ShorterHistogram;
+ uint32_t sum = CurrentHistPtr[i] + ShorterHistPtr[i];
+ CurrentHistPtr[i] = (sum > 255) ? 255 : (uint8_t)sum;
}
}
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
index 60f5c853f9d76..c5cef5cde9466 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -77,7 +77,7 @@ void Print(const MemInfoBlock &M, const u64 id, bool print_terse) {
? MAX_HISTOGRAM_PRINT_SIZE
: M.AccessHistogramSize;
for (size_t i = 0; i < PrintSize; ++i) {
- Printf("%llu ", ((uint64_t *)M.AccessHistogram)[i]);
+ Printf("%u ", ((uint8_t *)M.AccessHistogram)[i]);
}
Printf("\n");
}
@@ -327,12 +327,13 @@ struct Allocator {
uint32_t HistogramSize =
RoundUpTo(user_size, HISTOGRAM_GRANULARITY) / HISTOGRAM_GRANULARITY;
uintptr_t Histogram =
- (uintptr_t)InternalAlloc(HistogramSize * sizeof(uint64_t));
- memset((void *)Histogram, 0, HistogramSize * sizeof(uint64_t));
+ (uintptr_t)InternalAlloc(HistogramSize * sizeof(uint8_t));
+ memset((void *)Histogram, 0, HistogramSize * sizeof(uint8_t));
for (size_t i = 0; i < HistogramSize; ++i) {
u8 Counter =
*((u8 *)HISTOGRAM_MEM_TO_SHADOW(p + HISTOGRAM_GRANULARITY * i));
- ((uint64_t *)Histogram)[i] = (uint64_t)Counter;
+ // Cap the counter at HISTOGRAM_MAX_COUNTER (255) to prevent overflow
+ ((uint8_t *)Histogram)[i] = (Counter > HISTOGRAM_MAX_COUNTER) ? HISTOGRAM_MAX_COUNTER : Counter;
}
MemInfoBlock newMIB(user_size, c, m->timestamp_ms, curtime, m->cpu_id,
GetCpuId(), Histogram, HistogramSize);
diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
index a897648584828..95f22ffc5c42a 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
@@ -171,7 +171,8 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
// deserialization.
Ptr = WriteBytes((*h)->mib, Ptr);
for (u64 j = 0; j < (*h)->mib.AccessHistogramSize; ++j) {
- u64 HistogramEntry = ((u64 *)((*h)->mib.AccessHistogram))[j];
+ // Read as uint8_t and write as uint8_t
+ uint8_t HistogramEntry = ((uint8_t *)((*h)->mib.AccessHistogram))[j];
Ptr = WriteBytes(HistogramEntry, Ptr);
}
if ((*h)->mib.AccessHistogramSize > 0) {
@@ -249,7 +250,7 @@ u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef<LoadedModule> Modules,
},
reinterpret_cast<void *>(&TotalAccessHistogramEntries));
const u64 NumHistogramBytes =
- RoundUpTo(TotalAccessHistogramEntries * sizeof(uint64_t), 8);
+ RoundUpTo(TotalAccessHistogramEntries * sizeof(uint8_t), 8);
const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
diff --git a/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp b/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp
new file mode 100644
index 0000000000000..ec3e4494feaca
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx_memprof -O0 -mllvm -memprof-histogram -mllvm -memprof-use-callbacks=true %s -o %t && %env_memprof_opts=print_text=1:histogram=1:log_path=stdout %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ // Allocate memory that will create a histogram
+ char *buffer = (char *)malloc(1024);
+ if (!buffer) return 1;
+
+ for (int i = 0; i < 10; ++i) {
+ // Access every 8th byte (since shadow granularity is 8b.
+ buffer[i * 8] = 'A';
+ }
+
+ for (int j = 0; j < 200; ++j) {
+ buffer[8] = 'B'; // Count = previous count + 200
+ }
+
+ for (int j = 0; j < 400; ++j) {
+ buffer[16] = 'B'; // Count is saturated at 255
+ }
+
+ // Free the memory to trigger MIB creation with histogram
+ free(buffer);
+
+ printf("Test completed successfully\n");
+ return 0;
+}
+
+// CHECK: AccessCountHistogram[128]: 1 201 255 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+// CHECK: Test completed successfully
diff --git a/llvm/include/llvm/ProfileData/MemProfData.inc b/llvm/include/llvm/ProfileData/MemProfData.inc
index 3f785bd23fce3..4a43f72c2405d 100644
--- a/llvm/include/llvm/ProfileData/MemProfData.inc
+++ b/llvm/include/llvm/ProfileData/MemProfData.inc
@@ -33,11 +33,11 @@
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
-#define MEMPROF_RAW_VERSION 4ULL
+#define MEMPROF_RAW_VERSION 5ULL
// Currently supported versions.
#define MEMPROF_RAW_SUPPORTED_VERSIONS \
- { 3ULL, 4ULL }
+ { 3ULL, 4ULL, 5ULL }
#define MEMPROF_V3_MIB_SIZE 132ULL;
@@ -219,7 +219,11 @@ void Merge(const MemInfoBlock &newMIB) {
ShorterHistogramSize = newMIB.AccessHistogramSize;
}
for (size_t i = 0; i < ShorterHistogramSize; ++i) {
- ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];
+ // Cast to uint8_t* and cap the sum at 255 to prevent overflow
+ uint8_t *CurrentHistPtr = (uint8_t *)AccessHistogram;
+ uint8_t *ShorterHistPtr = (uint8_t *)ShorterHistogram;
+ uint32_t sum = CurrentHistPtr[i] + ShorterHistPtr[i];
+ CurrentHistPtr[i] = (sum > 255) ? 255 : (uint8_t)sum;
}
}
More information about the llvm-commits
mailing list