From 2e33ed9ecc52fcec27eac2efb2615d1efcf6fd32 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 6 Dec 2024 09:22:16 -0800 Subject: [PATCH] [memprof] Use -memprof-runtime-default-options to set options during compile time (#118874) Add the `__memprof_default_options_str` variable, initialized via the `-memprof-runtime-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. --- .../include/sanitizer/memprof_interface.h | 6 +++--- compiler-rt/lib/memprof/memprof_flags.cpp | 2 +- compiler-rt/lib/memprof/memprof_flags.h | 16 +++++++------- .../lib/memprof/memprof_interface_internal.h | 3 +++ compiler-rt/lib/memprof/memprof_rtl.cpp | 2 ++ compiler-rt/lib/memprof/weak_symbols.txt | 2 +- .../memprof/TestCases/default_options.cpp | 3 +++ .../test/memprof/TestCases/set_options.cpp | 16 ++++++++++++++ .../Instrumentation/MemProfiler.cpp | 21 +++++++++++++++++++ .../HeapProfiler/memprof-options.ll | 11 ++++++++++ 10 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 compiler-rt/test/memprof/TestCases/set_options.cpp create mode 100644 llvm/test/Instrumentation/HeapProfiler/memprof-options.ll diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h index 4660a7818c92..6d9b2a2394f4 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, -/// verbosity=1:print_stats=1). +/// You can set these options via the -memprof-runtime-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 b107ff8fa0a7..95fde9d9672d 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 2f2b628653dc..4dd395a6be94 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-runtime-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 318bc4104405..7d3a937814a3 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 2cc6c2df5a6f..ef8884a7e56f 100644 --- a/compiler-rt/lib/memprof/memprof_rtl.cpp +++ b/compiler-rt/lib/memprof/memprof_rtl.cpp @@ -27,6 +27,8 @@ #include +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 271813612ab6..bfece89e2e15 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/default_options.cpp b/compiler-rt/test/memprof/TestCases/default_options.cpp index 1b6b61fc048b..4042a7df588b 100644 --- a/compiler-rt/test/memprof/TestCases/default_options.cpp +++ b/compiler-rt/test/memprof/TestCases/default_options.cpp @@ -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() { 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 000000000000..dddcfcf98c5c --- /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-runtime-default-options="print_text=true,log_path=stdout,atexit=false" -o %t +// RUN: %run %t | FileCheck %s + +#include +#include + +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 33a7a37fa28e..ab7d3c700299 100644 --- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp @@ -166,6 +166,11 @@ static cl::opt "context in this module's profiles"), cl::Hidden, cl::init(false)); +static cl::opt + MemprofRuntimeDefaultOptions("memprof-runtime-default-options", + cl::desc("The default memprof options"), + cl::Hidden, cl::init("")); + extern cl::opt MemProfReportHintedSizes; // Instrumentation statistics @@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) { appendToCompilerUsed(M, MemprofHistogramFlag); } +void createMemprofDefaultOptionsVar(Module &M) { + Constant *OptionsConst = ConstantDataArray::getString( + M.getContext(), MemprofRuntimeDefaultOptions, /*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 000000000000..8e82d524952d --- /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-runtime-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