Skip to content

[memprof] Use -memprof-default-options to set options during compile time #118874

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 6, 2024

Conversation

ellishg
Copy link
Contributor

@ellishg ellishg commented Dec 5, 2024

Add the __memprof_default_options_str variable, initialized via the -memprof-default-options LLVM flag, to hold the default options string for memprof. This allows us to set these options during compile time in the clang invocation.

Also update the docs to describe the various ways to set these options.

@llvmbot
Copy link
Member

llvmbot commented Dec 5, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Ellis Hoag (ellishg)

Changes

Add the __memprof_default_options_str variable, initialized via the -memprof-default-options LLVM flag, to hold the default options string for memprof. This allows us to set these options during compile time in the clang invocation.

Also update the docs to describe the various ways to set these options.


Full diff: https://github.com/llvm/llvm-project/pull/118874.diff

9 Files Affected:

  • (modified) compiler-rt/include/sanitizer/memprof_interface.h (+3-3)
  • (modified) compiler-rt/lib/memprof/memprof_flags.cpp (+1-1)
  • (modified) compiler-rt/lib/memprof/memprof_flags.h (+9-7)
  • (modified) compiler-rt/lib/memprof/memprof_interface_internal.h (+3)
  • (modified) compiler-rt/lib/memprof/memprof_rtl.cpp (+2)
  • (modified) compiler-rt/lib/memprof/weak_symbols.txt (+1-1)
  • (added) compiler-rt/test/memprof/TestCases/set_options.cpp (+16)
  • (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+21)
  • (added) llvm/test/Instrumentation/HeapProfiler/memprof-options.ll (+11)
diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h
index 4660a7818c92b3..cdb65084b50200 100644
--- a/compiler-rt/include/sanitizer/memprof_interface.h
+++ b/compiler-rt/include/sanitizer/memprof_interface.h
@@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void);
 
 /// User-provided default option settings.
 ///
-/// You can provide your own implementation of this function to return a string
-/// containing MemProf runtime options (for example,
-/// <c>verbosity=1:print_stats=1</c>).
+/// You can set these options via the -memprof-default-options LLVM flag or
+/// you can provide your own implementation of this function. See
+/// memprof_flags.h for more info.
 ///
 /// \returns Default options string.
 const char *SANITIZER_CDECL __memprof_default_options(void);
diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp
index b107ff8fa0a7ca..95fde9d9672d68 100644
--- a/compiler-rt/lib/memprof/memprof_flags.cpp
+++ b/compiler-rt/lib/memprof/memprof_flags.cpp
@@ -89,5 +89,5 @@ void InitializeFlags() {
 } // namespace __memprof
 
 SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) {
-  return "";
+  return __memprof_default_options_str;
 }
diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h
index 2f2b628653dc19..ee1b7b3bcad921 100644
--- a/compiler-rt/lib/memprof/memprof_flags.h
+++ b/compiler-rt/lib/memprof/memprof_flags.h
@@ -17,13 +17,15 @@
 #include "sanitizer_common/sanitizer_flag_parser.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
-// MemProf flag values can be defined in four ways:
-// 1) initialized with default values at startup.
-// 2) overriden during compilation of MemProf runtime by providing
-//    compile definition MEMPROF_DEFAULT_OPTIONS.
-// 3) overriden from string returned by user-specified function
-//    __memprof_default_options().
-// 4) overriden from env variable MEMPROF_OPTIONS.
+// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc.
+// These values can be overridded in a number of ways, each option overrides the
+// prior one:
+//  1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf
+//     runtime
+//  2) by setting the LLVM flag -memprof-default-options during the compilation
+//     of your binary
+//  3) by overriding the user-specified function __memprof_default_options()
+//  4) by setting the environment variable MEMPROF_OPTIONS during runtime
 
 namespace __memprof {
 
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 318bc410440562..7d3a937814a34b 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size);
 
 SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats();
 
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
+    __memprof_default_options_str[1];
+
 SANITIZER_INTERFACE_ATTRIBUTE
 const char *__memprof_default_options();
 
diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp
index 2cc6c2df5a6fe4..ef8884a7e56f40 100644
--- a/compiler-rt/lib/memprof/memprof_rtl.cpp
+++ b/compiler-rt/lib/memprof/memprof_rtl.cpp
@@ -27,6 +27,8 @@
 
 #include <time.h>
 
+SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1];
+
 uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol.
 
 // Allow the user to specify a profile output file via the binary.
diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt
index 271813612ab604..bfece89e2e1579 100644
--- a/compiler-rt/lib/memprof/weak_symbols.txt
+++ b/compiler-rt/lib/memprof/weak_symbols.txt
@@ -1 +1 @@
-___memprof_default_options __memprof_profile_filename
+___memprof_default_options_str ___memprof_default_options __memprof_profile_filename
diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp
new file mode 100644
index 00000000000000..00f3d606de911c
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/set_options.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx_memprof %s -o %t-default
+// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT
+
+// RUN: %clangxx_memprof %s -mllvm -memprof-default-options="print_text=true,log_path=stdout,atexit=false" -o %t
+// RUN: %run %t | FileCheck %s
+
+#include <sanitizer/memprof_interface.h>
+#include <stdio.h>
+
+int main() {
+  printf("Options: \"%s\"\n", __memprof_default_options());
+  return 0;
+}
+
+// DEFAULT: Options: ""
+// CHECK: Options: "print_text=true,log_path=stdout,atexit=false"
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index 33a7a37fa28e65..6e17a16a46a9e9 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -166,6 +166,11 @@ static cl::opt<bool>
                                      "context in this module's profiles"),
                             cl::Hidden, cl::init(false));
 
+static cl::opt<std::string>
+    MemprofDefaultOptions("memprof-default-options",
+                          cl::desc("The default memprof options"), cl::Hidden,
+                          cl::init(""));
+
 extern cl::opt<bool> MemProfReportHintedSizes;
 
 // Instrumentation statistics
@@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) {
   appendToCompilerUsed(M, MemprofHistogramFlag);
 }
 
+void createMemprofDefaultOptionsVar(Module &M) {
+  Constant *OptionsConst = ConstantDataArray::getString(
+      M.getContext(), MemprofDefaultOptions, /*AddNull=*/true);
+  GlobalVariable *OptionsVar =
+      new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,
+                         GlobalValue::WeakAnyLinkage, OptionsConst,
+                         "__memprof_default_options_str");
+  Triple TT(M.getTargetTriple());
+  if (TT.supportsCOMDAT()) {
+    OptionsVar->setLinkage(GlobalValue::ExternalLinkage);
+    OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
+  }
+}
+
 bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   // Create a module constructor.
@@ -566,6 +585,8 @@ bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   createMemprofHistogramFlagVar(M);
 
+  createMemprofDefaultOptionsVar(M);
+
   return true;
 }
 
diff --git a/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
new file mode 100644
index 00000000000000..589e04bb403c6f
--- /dev/null
+++ b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S | FileCheck %s --check-prefixes=CHECK,EMPTY
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S -memprof-default-options="verbose=1" | FileCheck %s --check-prefixes=CHECK,VERBOSE
+
+define i32 @main() {
+entry:
+  ret i32 0
+}
+
+; CHECK: $__memprof_default_options_str = comdat any
+; EMPTY: @__memprof_default_options_str = constant [1 x i8] zeroinitializer, comdat
+; VERBOSE: @__memprof_default_options_str = constant [10 x i8] c"verbose=1\00", comdat

@llvmbot
Copy link
Member

llvmbot commented Dec 5, 2024

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Ellis Hoag (ellishg)

Changes

Add the __memprof_default_options_str variable, initialized via the -memprof-default-options LLVM flag, to hold the default options string for memprof. This allows us to set these options during compile time in the clang invocation.

Also update the docs to describe the various ways to set these options.


Full diff: https://github.com/llvm/llvm-project/pull/118874.diff

9 Files Affected:

  • (modified) compiler-rt/include/sanitizer/memprof_interface.h (+3-3)
  • (modified) compiler-rt/lib/memprof/memprof_flags.cpp (+1-1)
  • (modified) compiler-rt/lib/memprof/memprof_flags.h (+9-7)
  • (modified) compiler-rt/lib/memprof/memprof_interface_internal.h (+3)
  • (modified) compiler-rt/lib/memprof/memprof_rtl.cpp (+2)
  • (modified) compiler-rt/lib/memprof/weak_symbols.txt (+1-1)
  • (added) compiler-rt/test/memprof/TestCases/set_options.cpp (+16)
  • (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+21)
  • (added) llvm/test/Instrumentation/HeapProfiler/memprof-options.ll (+11)
diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h
index 4660a7818c92b3..cdb65084b50200 100644
--- a/compiler-rt/include/sanitizer/memprof_interface.h
+++ b/compiler-rt/include/sanitizer/memprof_interface.h
@@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void);
 
 /// User-provided default option settings.
 ///
-/// You can provide your own implementation of this function to return a string
-/// containing MemProf runtime options (for example,
-/// <c>verbosity=1:print_stats=1</c>).
+/// You can set these options via the -memprof-default-options LLVM flag or
+/// you can provide your own implementation of this function. See
+/// memprof_flags.h for more info.
 ///
 /// \returns Default options string.
 const char *SANITIZER_CDECL __memprof_default_options(void);
diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp
index b107ff8fa0a7ca..95fde9d9672d68 100644
--- a/compiler-rt/lib/memprof/memprof_flags.cpp
+++ b/compiler-rt/lib/memprof/memprof_flags.cpp
@@ -89,5 +89,5 @@ void InitializeFlags() {
 } // namespace __memprof
 
 SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) {
-  return "";
+  return __memprof_default_options_str;
 }
diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h
index 2f2b628653dc19..ee1b7b3bcad921 100644
--- a/compiler-rt/lib/memprof/memprof_flags.h
+++ b/compiler-rt/lib/memprof/memprof_flags.h
@@ -17,13 +17,15 @@
 #include "sanitizer_common/sanitizer_flag_parser.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
-// MemProf flag values can be defined in four ways:
-// 1) initialized with default values at startup.
-// 2) overriden during compilation of MemProf runtime by providing
-//    compile definition MEMPROF_DEFAULT_OPTIONS.
-// 3) overriden from string returned by user-specified function
-//    __memprof_default_options().
-// 4) overriden from env variable MEMPROF_OPTIONS.
+// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc.
+// These values can be overridded in a number of ways, each option overrides the
+// prior one:
+//  1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf
+//     runtime
+//  2) by setting the LLVM flag -memprof-default-options during the compilation
+//     of your binary
+//  3) by overriding the user-specified function __memprof_default_options()
+//  4) by setting the environment variable MEMPROF_OPTIONS during runtime
 
 namespace __memprof {
 
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 318bc410440562..7d3a937814a34b 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size);
 
 SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats();
 
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
+    __memprof_default_options_str[1];
+
 SANITIZER_INTERFACE_ATTRIBUTE
 const char *__memprof_default_options();
 
diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp
index 2cc6c2df5a6fe4..ef8884a7e56f40 100644
--- a/compiler-rt/lib/memprof/memprof_rtl.cpp
+++ b/compiler-rt/lib/memprof/memprof_rtl.cpp
@@ -27,6 +27,8 @@
 
 #include <time.h>
 
+SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1];
+
 uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol.
 
 // Allow the user to specify a profile output file via the binary.
diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt
index 271813612ab604..bfece89e2e1579 100644
--- a/compiler-rt/lib/memprof/weak_symbols.txt
+++ b/compiler-rt/lib/memprof/weak_symbols.txt
@@ -1 +1 @@
-___memprof_default_options __memprof_profile_filename
+___memprof_default_options_str ___memprof_default_options __memprof_profile_filename
diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp
new file mode 100644
index 00000000000000..00f3d606de911c
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/set_options.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx_memprof %s -o %t-default
+// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT
+
+// RUN: %clangxx_memprof %s -mllvm -memprof-default-options="print_text=true,log_path=stdout,atexit=false" -o %t
+// RUN: %run %t | FileCheck %s
+
+#include <sanitizer/memprof_interface.h>
+#include <stdio.h>
+
+int main() {
+  printf("Options: \"%s\"\n", __memprof_default_options());
+  return 0;
+}
+
+// DEFAULT: Options: ""
+// CHECK: Options: "print_text=true,log_path=stdout,atexit=false"
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index 33a7a37fa28e65..6e17a16a46a9e9 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -166,6 +166,11 @@ static cl::opt<bool>
                                      "context in this module's profiles"),
                             cl::Hidden, cl::init(false));
 
+static cl::opt<std::string>
+    MemprofDefaultOptions("memprof-default-options",
+                          cl::desc("The default memprof options"), cl::Hidden,
+                          cl::init(""));
+
 extern cl::opt<bool> MemProfReportHintedSizes;
 
 // Instrumentation statistics
@@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) {
   appendToCompilerUsed(M, MemprofHistogramFlag);
 }
 
+void createMemprofDefaultOptionsVar(Module &M) {
+  Constant *OptionsConst = ConstantDataArray::getString(
+      M.getContext(), MemprofDefaultOptions, /*AddNull=*/true);
+  GlobalVariable *OptionsVar =
+      new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,
+                         GlobalValue::WeakAnyLinkage, OptionsConst,
+                         "__memprof_default_options_str");
+  Triple TT(M.getTargetTriple());
+  if (TT.supportsCOMDAT()) {
+    OptionsVar->setLinkage(GlobalValue::ExternalLinkage);
+    OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
+  }
+}
+
 bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   // Create a module constructor.
@@ -566,6 +585,8 @@ bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   createMemprofHistogramFlagVar(M);
 
+  createMemprofDefaultOptionsVar(M);
+
   return true;
 }
 
diff --git a/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
new file mode 100644
index 00000000000000..589e04bb403c6f
--- /dev/null
+++ b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S | FileCheck %s --check-prefixes=CHECK,EMPTY
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S -memprof-default-options="verbose=1" | FileCheck %s --check-prefixes=CHECK,VERBOSE
+
+define i32 @main() {
+entry:
+  ret i32 0
+}
+
+; CHECK: $__memprof_default_options_str = comdat any
+; EMPTY: @__memprof_default_options_str = constant [1 x i8] zeroinitializer, comdat
+; VERBOSE: @__memprof_default_options_str = constant [10 x i8] c"verbose=1\00", comdat

@llvmbot
Copy link
Member

llvmbot commented Dec 5, 2024

@llvm/pr-subscribers-pgo

Author: Ellis Hoag (ellishg)

Changes

Add the __memprof_default_options_str variable, initialized via the -memprof-default-options LLVM flag, to hold the default options string for memprof. This allows us to set these options during compile time in the clang invocation.

Also update the docs to describe the various ways to set these options.


Full diff: https://github.com/llvm/llvm-project/pull/118874.diff

9 Files Affected:

  • (modified) compiler-rt/include/sanitizer/memprof_interface.h (+3-3)
  • (modified) compiler-rt/lib/memprof/memprof_flags.cpp (+1-1)
  • (modified) compiler-rt/lib/memprof/memprof_flags.h (+9-7)
  • (modified) compiler-rt/lib/memprof/memprof_interface_internal.h (+3)
  • (modified) compiler-rt/lib/memprof/memprof_rtl.cpp (+2)
  • (modified) compiler-rt/lib/memprof/weak_symbols.txt (+1-1)
  • (added) compiler-rt/test/memprof/TestCases/set_options.cpp (+16)
  • (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+21)
  • (added) llvm/test/Instrumentation/HeapProfiler/memprof-options.ll (+11)
diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h
index 4660a7818c92b3..cdb65084b50200 100644
--- a/compiler-rt/include/sanitizer/memprof_interface.h
+++ b/compiler-rt/include/sanitizer/memprof_interface.h
@@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void);
 
 /// User-provided default option settings.
 ///
-/// You can provide your own implementation of this function to return a string
-/// containing MemProf runtime options (for example,
-/// <c>verbosity=1:print_stats=1</c>).
+/// You can set these options via the -memprof-default-options LLVM flag or
+/// you can provide your own implementation of this function. See
+/// memprof_flags.h for more info.
 ///
 /// \returns Default options string.
 const char *SANITIZER_CDECL __memprof_default_options(void);
diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp
index b107ff8fa0a7ca..95fde9d9672d68 100644
--- a/compiler-rt/lib/memprof/memprof_flags.cpp
+++ b/compiler-rt/lib/memprof/memprof_flags.cpp
@@ -89,5 +89,5 @@ void InitializeFlags() {
 } // namespace __memprof
 
 SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) {
-  return "";
+  return __memprof_default_options_str;
 }
diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h
index 2f2b628653dc19..ee1b7b3bcad921 100644
--- a/compiler-rt/lib/memprof/memprof_flags.h
+++ b/compiler-rt/lib/memprof/memprof_flags.h
@@ -17,13 +17,15 @@
 #include "sanitizer_common/sanitizer_flag_parser.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
-// MemProf flag values can be defined in four ways:
-// 1) initialized with default values at startup.
-// 2) overriden during compilation of MemProf runtime by providing
-//    compile definition MEMPROF_DEFAULT_OPTIONS.
-// 3) overriden from string returned by user-specified function
-//    __memprof_default_options().
-// 4) overriden from env variable MEMPROF_OPTIONS.
+// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc.
+// These values can be overridded in a number of ways, each option overrides the
+// prior one:
+//  1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf
+//     runtime
+//  2) by setting the LLVM flag -memprof-default-options during the compilation
+//     of your binary
+//  3) by overriding the user-specified function __memprof_default_options()
+//  4) by setting the environment variable MEMPROF_OPTIONS during runtime
 
 namespace __memprof {
 
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 318bc410440562..7d3a937814a34b 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size);
 
 SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats();
 
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
+    __memprof_default_options_str[1];
+
 SANITIZER_INTERFACE_ATTRIBUTE
 const char *__memprof_default_options();
 
diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp
index 2cc6c2df5a6fe4..ef8884a7e56f40 100644
--- a/compiler-rt/lib/memprof/memprof_rtl.cpp
+++ b/compiler-rt/lib/memprof/memprof_rtl.cpp
@@ -27,6 +27,8 @@
 
 #include <time.h>
 
+SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1];
+
 uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol.
 
 // Allow the user to specify a profile output file via the binary.
diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt
index 271813612ab604..bfece89e2e1579 100644
--- a/compiler-rt/lib/memprof/weak_symbols.txt
+++ b/compiler-rt/lib/memprof/weak_symbols.txt
@@ -1 +1 @@
-___memprof_default_options __memprof_profile_filename
+___memprof_default_options_str ___memprof_default_options __memprof_profile_filename
diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp
new file mode 100644
index 00000000000000..00f3d606de911c
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/set_options.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx_memprof %s -o %t-default
+// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT
+
+// RUN: %clangxx_memprof %s -mllvm -memprof-default-options="print_text=true,log_path=stdout,atexit=false" -o %t
+// RUN: %run %t | FileCheck %s
+
+#include <sanitizer/memprof_interface.h>
+#include <stdio.h>
+
+int main() {
+  printf("Options: \"%s\"\n", __memprof_default_options());
+  return 0;
+}
+
+// DEFAULT: Options: ""
+// CHECK: Options: "print_text=true,log_path=stdout,atexit=false"
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index 33a7a37fa28e65..6e17a16a46a9e9 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -166,6 +166,11 @@ static cl::opt<bool>
                                      "context in this module's profiles"),
                             cl::Hidden, cl::init(false));
 
+static cl::opt<std::string>
+    MemprofDefaultOptions("memprof-default-options",
+                          cl::desc("The default memprof options"), cl::Hidden,
+                          cl::init(""));
+
 extern cl::opt<bool> MemProfReportHintedSizes;
 
 // Instrumentation statistics
@@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) {
   appendToCompilerUsed(M, MemprofHistogramFlag);
 }
 
+void createMemprofDefaultOptionsVar(Module &M) {
+  Constant *OptionsConst = ConstantDataArray::getString(
+      M.getContext(), MemprofDefaultOptions, /*AddNull=*/true);
+  GlobalVariable *OptionsVar =
+      new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,
+                         GlobalValue::WeakAnyLinkage, OptionsConst,
+                         "__memprof_default_options_str");
+  Triple TT(M.getTargetTriple());
+  if (TT.supportsCOMDAT()) {
+    OptionsVar->setLinkage(GlobalValue::ExternalLinkage);
+    OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
+  }
+}
+
 bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   // Create a module constructor.
@@ -566,6 +585,8 @@ bool ModuleMemProfiler::instrumentModule(Module &M) {
 
   createMemprofHistogramFlagVar(M);
 
+  createMemprofDefaultOptionsVar(M);
+
   return true;
 }
 
diff --git a/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
new file mode 100644
index 00000000000000..589e04bb403c6f
--- /dev/null
+++ b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S | FileCheck %s --check-prefixes=CHECK,EMPTY
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S -memprof-default-options="verbose=1" | FileCheck %s --check-prefixes=CHECK,VERBOSE
+
+define i32 @main() {
+entry:
+  ret i32 0
+}
+
+; CHECK: $__memprof_default_options_str = comdat any
+; EMPTY: @__memprof_default_options_str = constant [1 x i8] zeroinitializer, comdat
+; VERBOSE: @__memprof_default_options_str = constant [10 x i8] c"verbose=1\00", comdat

Copy link
Contributor

@snehasish snehasish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downstream we override with own __memprof_default_options method. Can you add a test case to /memprof/TestCases/default_options.cpp which uses this option and ensures that the override approach takes precedence?

@@ -166,6 +166,11 @@ static cl::opt<bool>
"context in this module's profiles"),
cl::Hidden, cl::init(false));

static cl::opt<std::string>
MemprofDefaultOptions("memprof-default-options",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps "memprof-runtime-default-options" to make it clear that it affects the compiler-rt runtime?

@@ -1,5 +1,8 @@
// RUN: %clangxx_memprof -O2 %s -o %t && %run %t 2>&1 | FileCheck %s

// Check that overriding __memprof_default_options() takes precedence over the LLVM flag
// RUN: %clangxx_memprof -O2 %s -o %t-flag -mllvm -memprof-runtime-default-options="verbosity=0 help=0" && %run %t-flag 2>&1 | FileCheck %s

const char *kMemProfDefaultOptions = "verbosity=1 help=1";

extern "C" const char *__memprof_default_options() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the CHECK statement below will need to be updated to check verbosity=1 help=1 to verify the behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Available flags for MemProfiler: will only output if help=1, which is checked on line 6. So this indeed verifies the expected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out.

Copy link
Contributor

@snehasish snehasish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -1,5 +1,8 @@
// RUN: %clangxx_memprof -O2 %s -o %t && %run %t 2>&1 | FileCheck %s

// Check that overriding __memprof_default_options() takes precedence over the LLVM flag
// RUN: %clangxx_memprof -O2 %s -o %t-flag -mllvm -memprof-runtime-default-options="verbosity=0 help=0" && %run %t-flag 2>&1 | FileCheck %s

const char *kMemProfDefaultOptions = "verbosity=1 help=1";

extern "C" const char *__memprof_default_options() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out.

@ellishg ellishg merged commit 2e33ed9 into llvm:main Dec 6, 2024
8 checks passed
@ellishg ellishg deleted the memprof-options branch December 6, 2024 18:37
ellishg added a commit that referenced this pull request Mar 3, 2025
The `-memprof-runtime-default-options` LLVM flag introduced in
#118874 creates the
`__memprof_default_options_str` symbol with `WeakAnyLinkage` on Darwin.


https://github.com/ellishg/llvm-project/blob/fa0202169af23419c4bcbf66eabd1beb6b6e8e34/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp#L573-L576

This ensures Darwin passes `-exported_symbol
___memprof_default_options_str` to the linker so that the runtime
library has visibility into this symbol.

This will replace the earlier PR
#128615
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Mar 3, 2025
…#128920)

The `-memprof-runtime-default-options` LLVM flag introduced in
llvm/llvm-project#118874 creates the
`__memprof_default_options_str` symbol with `WeakAnyLinkage` on Darwin.

https://github.com/ellishg/llvm-project/blob/fa0202169af23419c4bcbf66eabd1beb6b6e8e34/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp#L573-L576

This ensures Darwin passes `-exported_symbol
___memprof_default_options_str` to the linker so that the runtime
library has visibility into this symbol.

This will replace the earlier PR
llvm/llvm-project#128615
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
The `-memprof-runtime-default-options` LLVM flag introduced in
llvm#118874 creates the
`__memprof_default_options_str` symbol with `WeakAnyLinkage` on Darwin.


https://github.com/ellishg/llvm-project/blob/fa0202169af23419c4bcbf66eabd1beb6b6e8e34/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp#L573-L576

This ensures Darwin passes `-exported_symbol
___memprof_default_options_str` to the linker so that the runtime
library has visibility into this symbol.

This will replace the earlier PR
llvm#128615
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants