[llvm] [gsymutil] Add parameter into `GsymReader` to disable readahead (PR #199230)
Roy Shi via llvm-commits
llvm-commits at lists.llvm.org
Fri May 22 09:29:54 PDT 2026
https://github.com/royitaqi updated https://github.com/llvm/llvm-project/pull/199230
>From 61d8c091dd33e15b00b9be9ca93e1f340bffb601 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 21 May 2026 11:16:32 -0700
Subject: [PATCH 1/6] Disable readahead
---
llvm/lib/DebugInfo/GSYM/GsymReader.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index b68588fb24f75..06252b86623b2 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -12,6 +12,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/mman.h>
#include "llvm/DebugInfo/GSYM/GsymReaderV1.h"
#include "llvm/DebugInfo/GSYM/GsymReaderV2.h"
@@ -71,7 +72,12 @@ GsymReader::openFile(StringRef Filename) {
auto Err = BuffOrErr.getError();
if (Err)
return llvm::errorCodeToError(Err);
- return create(BuffOrErr.get());
+ // Disable readahead for benchmarking random access patterns.
+ auto &Buf = BuffOrErr.get();
+ madvise(const_cast<void *>(
+ static_cast<const void *>(Buf->getBufferStart())),
+ Buf->getBufferSize(), MADV_RANDOM);
+ return create(Buf);
}
llvm::Expected<std::unique_ptr<GsymReader>>
>From f926f77b87b7f9573bbda5abed364c5017af1818 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Thu, 21 May 2026 12:58:12 -0700
Subject: [PATCH 2/6] Add --benchmark-reader=start,stride parameters
---
llvm/tools/llvm-gsymutil/Opts.td | 8 +++-
llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp | 50 +++++++++++++++++++---
2 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/llvm/tools/llvm-gsymutil/Opts.td b/llvm/tools/llvm-gsymutil/Opts.td
index f2bf5e0783671..2b211eec9a96d 100644
--- a/llvm/tools/llvm-gsymutil/Opts.td
+++ b/llvm/tools/llvm-gsymutil/Opts.td
@@ -60,6 +60,10 @@ defm output_version :
Eq<"output-version",
"Set the GSYM output version (1 or 2). Default: 1.">;
def benchmark_reader :
- FF<"benchmark-reader",
- "Open a GSYM file and perform a lookup for every function start address to benchmark the reader performance">,
+ Joined<["--"], "benchmark-reader=">,
+ HelpText<"Benchmark reader with start,stride (default: 0,1 = every address)">,
+ Flags<[HelpHidden]>;
+def benchmark_reader_all :
+ Flag<["--"], "benchmark-reader">,
+ HelpText<"Benchmark reader by looking up every address">,
Flags<[HelpHidden]>;
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 33a5a2224e3f9..6dd5ea8569e72 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -98,6 +98,8 @@ static std::string OutputFilename;
static std::string JsonSummaryFile;
static bool Verify;
static bool BenchmarkReader;
+static uint32_t BenchmarkStart;
+static uint32_t BenchmarkStride;
static unsigned NumThreads;
static uint64_t SegmentSize;
static bool Quiet;
@@ -161,7 +163,37 @@ static void parseArgs(int argc, char **argv) {
JsonSummaryFile = A->getValue();
Verify = Args.hasArg(OPT_verify);
- BenchmarkReader = Args.hasArg(OPT_benchmark_reader);
+ BenchmarkStart = 0;
+ BenchmarkStride = 1;
+ if (Args.hasArg(OPT_benchmark_reader_all)) {
+ BenchmarkReader = true;
+ } else if (const llvm::opt::Arg *A =
+ Args.getLastArg(OPT_benchmark_reader)) {
+ BenchmarkReader = true;
+ StringRef S{A->getValue()};
+ if (!S.empty()) {
+ auto [StartStr, StrideStr] = S.split(',');
+ if (!llvm::to_integer(StartStr, BenchmarkStart, 0)) {
+ llvm::errs() << ToolName
+ << ": for the --benchmark-reader option: invalid start '"
+ << StartStr << "'\n";
+ std::exit(1);
+ }
+ if (!StrideStr.empty() &&
+ !llvm::to_integer(StrideStr, BenchmarkStride, 0)) {
+ llvm::errs() << ToolName
+ << ": for the --benchmark-reader option: invalid stride '"
+ << StrideStr << "'\n";
+ std::exit(1);
+ }
+ if (BenchmarkStride == 0) {
+ llvm::errs() << ToolName
+ << ": for the --benchmark-reader option: stride must be "
+ "positive\n";
+ std::exit(1);
+ }
+ }
+ }
if (const llvm::opt::Arg *A = Args.getLastArg(OPT_num_threads_EQ)) {
StringRef S{A->getValue()};
@@ -731,12 +763,14 @@ static void doLookup(GsymReader &Gsym, uint64_t Addr, raw_ostream &OS) {
}
}
-static llvm::Error benchmarkReader(StringRef GSYMPath) {
+static llvm::Error benchmarkReader(StringRef GSYMPath, uint32_t Start,
+ uint32_t Stride) {
auto Gsym = GsymReader::openFile(GSYMPath);
if (!Gsym)
return Gsym.takeError();
- auto NumAddrs = (*Gsym)->getNumAddresses();
- for (uint32_t I = 0; I < NumAddrs; ++I) {
+ uint32_t N = (*Gsym)->getNumAddresses();
+ uint32_t NumLookups = 0;
+ for (uint32_t I = Start; I < N; I += Stride) {
auto Addr = (*Gsym)->getAddress(I);
if (!Addr)
return createStringError(std::errc::invalid_argument,
@@ -744,9 +778,10 @@ static llvm::Error benchmarkReader(StringRef GSYMPath) {
auto LR = (*Gsym)->lookup(*Addr);
if (!LR)
return LR.takeError();
+ ++NumLookups;
}
- outs() << "Benchmarked " << NumAddrs << " lookups in \"" << GSYMPath
- << "\"\n";
+ outs() << "Benchmarked " << NumLookups << " lookups (out of " << N
+ << " addresses) in \"" << GSYMPath << "\"\n";
return Error::success();
}
@@ -764,7 +799,8 @@ int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
if (BenchmarkReader) {
for (const auto &GSYMPath : InputFilenames)
- if (auto Err = benchmarkReader(GSYMPath))
+ if (auto Err =
+ benchmarkReader(GSYMPath, BenchmarkStart, BenchmarkStride))
error("Benchmark failed: ", std::move(Err));
return EXIT_SUCCESS;
}
>From ff56ad776fcff540799dd19aef652ba44054b79b Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 22 May 2026 08:27:21 -0700
Subject: [PATCH 3/6] Move MADV_RANDOM into LLVM's mapped_file_region
abstraction
Replace the direct madvise() call in GsymReader with a proper
OS-independent API through mapped_file_region and MemoryBuffer,
following the existing dontNeed()/willNeed() pattern.
---
llvm/include/llvm/Support/FileSystem.h | 2 ++
llvm/include/llvm/Support/MemoryBuffer.h | 4 ++++
llvm/lib/DebugInfo/GSYM/GsymReader.cpp | 6 +-----
llvm/lib/Support/MemoryBuffer.cpp | 1 +
llvm/lib/Support/Unix/Path.inc | 13 +++++++++++++
llvm/lib/Support/Windows/Path.inc | 2 ++
6 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h
index 8dd5bb86949fa..6fe795042c6a4 100644
--- a/llvm/include/llvm/Support/FileSystem.h
+++ b/llvm/include/llvm/Support/FileSystem.h
@@ -1333,6 +1333,7 @@ class mapped_file_region {
LLVM_ABI void unmapImpl();
LLVM_ABI void dontNeedImpl();
LLVM_ABI void willNeedImpl();
+ LLVM_ABI void randomAccessImpl();
LLVM_ABI std::error_code init(sys::fs::file_t FD, uint64_t Offset,
mapmode Mode, const char *Name);
@@ -1366,6 +1367,7 @@ class mapped_file_region {
}
void dontNeed() { dontNeedImpl(); }
void willNeed() { willNeedImpl(); }
+ void randomAccess() { randomAccessImpl(); }
LLVM_ABI size_t size() const;
LLVM_ABI char *data() const;
diff --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h
index 9b0f1f0f7d34e..77efb49725631 100644
--- a/llvm/include/llvm/Support/MemoryBuffer.h
+++ b/llvm/include/llvm/Support/MemoryBuffer.h
@@ -88,6 +88,10 @@ class LLVM_ABI MemoryBuffer {
/// This should be use purely as an read optimization.
virtual void willNeedIfMmap() {}
+ /// For read-only MemoryBuffer_MMap, advise the kernel that accesses will be
+ /// random, disabling readahead. This calls madvise(MADV_RANDOM) on *NIX.
+ virtual void randomAccessIfMmap() {}
+
/// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
/// if successful, otherwise returning null.
///
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 06252b86623b2..92efd66566445 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -12,7 +12,6 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/mman.h>
#include "llvm/DebugInfo/GSYM/GsymReaderV1.h"
#include "llvm/DebugInfo/GSYM/GsymReaderV2.h"
@@ -72,11 +71,8 @@ GsymReader::openFile(StringRef Filename) {
auto Err = BuffOrErr.getError();
if (Err)
return llvm::errorCodeToError(Err);
- // Disable readahead for benchmarking random access patterns.
auto &Buf = BuffOrErr.get();
- madvise(const_cast<void *>(
- static_cast<const void *>(Buf->getBufferStart())),
- Buf->getBufferSize(), MADV_RANDOM);
+ Buf->randomAccessIfMmap();
return create(Buf);
}
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index 8491421762d1d..9c49c143cf01c 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -249,6 +249,7 @@ class MemoryBufferMMapFile : public MB {
void dontNeedIfMmap() override { MFR.dontNeed(); }
void willNeedIfMmap() override { MFR.willNeed(); }
+ void randomAccessIfMmap() override { MFR.randomAccess(); }
};
} // namespace
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index bde8cf1255025..98c210a5d31f7 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -944,6 +944,19 @@ void mapped_file_region::willNeedImpl() {
#endif
}
+void mapped_file_region::randomAccessImpl() {
+ assert(Mode == mapped_file_region::readonly);
+ if (!Mapping)
+ return;
+#if defined(__MVS__) || defined(_AIX)
+ // If we don't have madvise, or it isn't beneficial, treat this as a no-op.
+#elif defined(POSIX_MADV_RANDOM)
+ ::posix_madvise(Mapping, Size, POSIX_MADV_RANDOM);
+#else
+ ::madvise(Mapping, Size, MADV_RANDOM);
+#endif
+}
+
int mapped_file_region::alignment() { return Process::getPageSizeEstimate(); }
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index 7161af15046ab..19897242a9638 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -1183,6 +1183,8 @@ void mapped_file_region::unmapImpl() {
void mapped_file_region::dontNeedImpl() {}
+void mapped_file_region::randomAccessImpl() {}
+
void mapped_file_region::willNeedImpl() {
struct MEMORY_RANGE_ENTRY {
PVOID VirtualAddress;
>From def54918cb146b6d8016111e651d7aa23587365e Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 22 May 2026 08:40:28 -0700
Subject: [PATCH 4/6] Add RandomAccess parameter to GsymReader::openFile
Allow callers to opt in to MADV_RANDOM on the memory-mapped file
by passing RandomAccess=true. Default is false (no behavior change).
---
llvm/include/llvm/DebugInfo/GSYM/GsymReader.h | 4 +++-
llvm/lib/DebugInfo/GSYM/GsymReader.cpp | 5 +++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
index b44f895ed9634..3bf2d8a08b3d5 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
@@ -87,10 +87,12 @@ class GsymReader {
/// Construct a GsymReader from a file on disk.
///
/// \param Path The file path the GSYM file to read.
+ /// \param RandomAccess If true, advise the kernel that accesses will be
+ /// random, disabling readahead on the memory-mapped file.
/// \returns An expected GsymReader that contains the object or an error
/// object that indicates reason for failing to read the GSYM.
LLVM_ABI static llvm::Expected<std::unique_ptr<GsymReader>>
- openFile(StringRef Path);
+ openFile(StringRef Path, bool RandomAccess = false);
/// Construct a GsymReader from a buffer.
///
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 92efd66566445..835b275e28a7e 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -64,7 +64,7 @@ checkMagicAndDetectVersionEndian(StringRef Bytes) {
}
llvm::Expected<std::unique_ptr<GsymReader>>
-GsymReader::openFile(StringRef Filename) {
+GsymReader::openFile(StringRef Filename, bool RandomAccess) {
// Open the input file and return an appropriate error if needed.
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
@@ -72,7 +72,8 @@ GsymReader::openFile(StringRef Filename) {
if (Err)
return llvm::errorCodeToError(Err);
auto &Buf = BuffOrErr.get();
- Buf->randomAccessIfMmap();
+ if (RandomAccess)
+ Buf->randomAccessIfMmap();
return create(Buf);
}
>From 94a24da9db4e73176606066eeb3bcc558e0e831d Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 22 May 2026 09:13:50 -0700
Subject: [PATCH 5/6] Fix format
---
llvm/lib/Support/Unix/Path.inc | 2 +-
llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp | 6 ++----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 98c210a5d31f7..3c8d4c7c28013 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -949,7 +949,7 @@ void mapped_file_region::randomAccessImpl() {
if (!Mapping)
return;
#if defined(__MVS__) || defined(_AIX)
- // If we don't have madvise, or it isn't beneficial, treat this as a no-op.
+ // If we don't have madvise, or it isn't beneficial, treat this as a no-op.
#elif defined(POSIX_MADV_RANDOM)
::posix_madvise(Mapping, Size, POSIX_MADV_RANDOM);
#else
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 6dd5ea8569e72..7bbb8cf198f75 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -167,8 +167,7 @@ static void parseArgs(int argc, char **argv) {
BenchmarkStride = 1;
if (Args.hasArg(OPT_benchmark_reader_all)) {
BenchmarkReader = true;
- } else if (const llvm::opt::Arg *A =
- Args.getLastArg(OPT_benchmark_reader)) {
+ } else if (const llvm::opt::Arg *A = Args.getLastArg(OPT_benchmark_reader)) {
BenchmarkReader = true;
StringRef S{A->getValue()};
if (!S.empty()) {
@@ -799,8 +798,7 @@ int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
if (BenchmarkReader) {
for (const auto &GSYMPath : InputFilenames)
- if (auto Err =
- benchmarkReader(GSYMPath, BenchmarkStart, BenchmarkStride))
+ if (auto Err = benchmarkReader(GSYMPath, BenchmarkStart, BenchmarkStride))
error("Benchmark failed: ", std::move(Err));
return EXIT_SUCCESS;
}
>From 22bce1a011fb3dcaf45c3c60ccd7eb5ed27c8fc3 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 22 May 2026 09:29:36 -0700
Subject: [PATCH 6/6] Manually fix format
---
llvm/lib/Support/Unix/Path.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 3c8d4c7c28013..98c210a5d31f7 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -949,7 +949,7 @@ void mapped_file_region::randomAccessImpl() {
if (!Mapping)
return;
#if defined(__MVS__) || defined(_AIX)
- // If we don't have madvise, or it isn't beneficial, treat this as a no-op.
+ // If we don't have madvise, or it isn't beneficial, treat this as a no-op.
#elif defined(POSIX_MADV_RANDOM)
::posix_madvise(Mapping, Size, POSIX_MADV_RANDOM);
#else
More information about the llvm-commits
mailing list