///< linker.
CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants.
CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled.
-CODEGENOPT(MemProf , 1, 0) ///< Set when -fmemory-profile is enabled.
CODEGENOPT(MSVolatile , 1, 0) ///< Set when /volatile:ms is enabled.
CODEGENOPT(NoCommon , 1, 0) ///< Set when -fno-common or C++ is enabled.
CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is
/// Name of the profile file to use with -fprofile-sample-use.
std::string SampleProfileFile;
+ /// Name of the profile file to use as output for with -fmemory-profile.
+ std::string MemoryProfileOutput;
+
/// Name of the profile file to use as input for -fprofile-instr-use
std::string ProfileInstrumentUsePath;
Flags<[CC1Option]>;
defm memory_profile : OptInFFlag<"memory-profile", "Enable", "Disable", " heap memory profiling">;
+def fmemory_profile_EQ : Joined<["-"], "fmemory-profile=">,
+ Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<directory>">,
+ HelpText<"Enable heap memory profiling and dump results into <directory>">;
// Begin sanitizer flags. These should all be core options exposed in all driver
// modes.
if (LangOpts.Coroutines)
addCoroutinePassesToExtensionPoints(PMBuilder);
- if (CodeGenOpts.MemProf) {
+ if (!CodeGenOpts.MemoryProfileOutput.empty()) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addMemProfilerPasses);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
if (CodeGenOpts.UniqueInternalLinkageNames)
MPM.addPass(UniqueInternalLinkageNamesPass());
- if (CodeGenOpts.MemProf) {
+ if (!CodeGenOpts.MemoryProfileOutput.empty()) {
MPM.addPass(createModuleToFunctionPassAdaptor(MemProfilerPass()));
MPM.addPass(ModuleMemProfilerPass());
}
!LangOpts.isSignReturnAddressWithAKey());
}
+ if (!CodeGenOpts.MemoryProfileOutput.empty()) {
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ getModule().addModuleFlag(
+ llvm::Module::Error, "MemProfProfileFilename",
+ llvm::MDString::get(Ctx, CodeGenOpts.MemoryProfileOutput));
+ }
+
if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) {
// Indicate whether __nvvm_reflect should be configured to flush denormal
// floating point values to 0. (This corresponds to its "__CUDA_FTZ"
D.CCCIsCXX();
NeedsMemProfRt = Args.hasFlag(options::OPT_fmemory_profile,
+ options::OPT_fmemory_profile_EQ,
options::OPT_fno_memory_profile, false);
// Finally, initialize the set of available and recoverable sanitizers.
if (Args.getLastArg(options::OPT_save_temps_EQ))
Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
- if (Args.hasFlag(options::OPT_fmemory_profile,
- options::OPT_fno_memory_profile, false))
- Args.AddLastArg(CmdArgs, options::OPT_fmemory_profile);
+ auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile,
+ options::OPT_fmemory_profile_EQ,
+ options::OPT_fno_memory_profile);
+ if (MemProfArg &&
+ !MemProfArg->getOption().matches(options::OPT_fno_memory_profile))
+ MemProfArg->render(Args, CmdArgs);
// Embed-bitcode option.
// Only white-listed flags below are allowed to be embedded.
Opts.ThinLinkBitcodeFile =
std::string(Args.getLastArgValue(OPT_fthin_link_bitcode_EQ));
- Opts.MemProf = Args.hasArg(OPT_fmemory_profile);
+ // The memory profile runtime appends the pid to make this name more unique.
+ const char *MemProfileBasename = "memprof.profraw";
+ if (Args.hasArg(OPT_fmemory_profile_EQ)) {
+ SmallString<128> Path(
+ std::string(Args.getLastArgValue(OPT_fmemory_profile_EQ)));
+ llvm::sys::path::append(Path, MemProfileBasename);
+ Opts.MemoryProfileOutput = std::string(Path);
+ } else if (Args.hasArg(OPT_fmemory_profile))
+ Opts.MemoryProfileOutput = MemProfileBasename;
Opts.MSVolatile = Args.hasArg(OPT_fms_volatile);
--- /dev/null
+// Test that we get the expected module flag metadata for the memory profile
+// filename.
+// RUN: %clang -target x86_64-linux-gnu -S -emit-llvm -o - %s | FileCheck %s --check-prefix=NONE
+// RUN: %clang -target x86_64-linux-gnu -fmemory-profile -S -emit-llvm -o - %s | FileCheck %s --check-prefix=DEFAULTNAME
+// RUN: %clang -target x86_64-linux-gnu -fmemory-profile=/tmp -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CUSTOMNAME
+int main(void) {
+ return 0;
+}
+
+// NONE-NOT: MemProfProfileFilename
+// DEFAULTNAME: !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
+// CUSTOMNAME: !{i32 1, !"MemProfProfileFilename", !"/tmp/memprof.profraw"}
// RUN: %clangxx -target x86_64-linux-gnu -fmemory-profile %s -### 2>&1 | FileCheck %s
+// RUN: %clangxx -target x86_64-linux-gnu -fmemory-profile=foo %s -### 2>&1 | FileCheck %s --check-prefix=DIR
// RUN: %clangxx -target x86_64-linux-gnu -fmemory-profile -fno-memory-profile %s -### 2>&1 | FileCheck %s --check-prefix=OFF
+// RUN: %clangxx -target x86_64-linux-gnu -fmemory-profile=foo -fno-memory-profile %s -### 2>&1 | FileCheck %s --check-prefix=OFF
// CHECK: "-cc1" {{.*}} "-fmemory-profile"
// CHECK: ld{{.*}}libclang_rt.memprof{{.*}}libclang_rt.memprof_cxx
+// DIR: "-cc1" {{.*}} "-fmemory-profile=foo"
+// DIR: ld{{.*}}libclang_rt.memprof{{.*}}libclang_rt.memprof_cxx
// OFF-NOT: "-fmemory-profile"
// OFF-NOT: libclang_rt.memprof
// Check atexit option.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts=atexit=1 %run %t 2>&1 | FileCheck %s
-// RUN: %env_memprof_opts=atexit=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOATEXIT
+// RUN: %env_memprof_opts=log_path=stderr:atexit=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:atexit=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOATEXIT
// CHECK: MemProfiler exit stats:
// CHECK: Stats: {{[0-9]+}}M malloced ({{[0-9]+}}M for overhead) by {{[0-9]+}} calls
// Check print_module_map option.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts=print_module_map=1 %run %t 2>&1 | FileCheck %s
-// RUN: %env_memprof_opts=print_module_map=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOMAP
+// RUN: %env_memprof_opts=log_path=stderr:print_module_map=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:print_module_map=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOMAP
// CHECK: Process memory map follows:
// CHECK: dump_process_map.cpp.tmp
//
// RUN: %clangxx_memprof %s -o %t
-// Regular run.
-// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-GOOD --dump-input=always
+// stderr log_path
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-GOOD --dump-input=always
// Good log_path.
// RUN: rm -f %t.log.*
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SUMMARY
-// RUN: %env_memprof_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
+// RUN: %env_memprof_opts=log_path=stderr:allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SUMMARY
+// RUN: %env_memprof_opts=log_path=stderr:allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
// Test print_summary
-// RUN: %env_memprof_opts=allocator_may_return_null=0:print_summary=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOSUMMARY
+// RUN: %env_memprof_opts=log_path=stderr:allocator_may_return_null=0:print_summary=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOSUMMARY
#include <stdio.h>
#include <stdlib.h>
// Check mem_info_cache_entries option.
-// RUN: %clangxx_memprof -O0 %s -o %t && %env_memprof_opts=mem_info_cache_entries=15:print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_memprof -O0 %s -o %t && %env_memprof_opts=log_path=stderr:mem_info_cache_entries=15:print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s
// CHECK: Set 14 miss rate: 0 / {{.*}} = 0.00%
// CHECK-NOT: Set
// print_mem_info_cache_miss_rate_details options.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts=print_mem_info_cache_miss_rate=1 %run %t 2>&1 | FileCheck %s
-// RUN: %env_memprof_opts=print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s --check-prefix=DETAILS
+// RUN: %env_memprof_opts=log_path=stderr:print_mem_info_cache_miss_rate=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s --check-prefix=DETAILS
// CHECK: Overall miss rate: 0 / {{.*}} = 0.00%
// DETAILS: Set 0 miss rate: 0 / {{.*}} = 0.00%
// RUN: %clangxx_memprof %s -ldl -pthread -o %t
// RUN: %run %t 0 3
// RUN: %run %t 2 3
-// RUN: %env_memprof_opts=verbosity=2 %run %t 10 2 2>&1 | FileCheck %s
-// RUN: %env_memprof_opts=verbosity=2:intercept_tls_get_addr=1 %run %t 10 2 2>&1 | FileCheck %s
-// RUN: %env_memprof_opts=verbosity=2:intercept_tls_get_addr=0 %run %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0
+// RUN: %env_memprof_opts=log_path=stderr:verbosity=2 %run %t 10 2 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:verbosity=2:intercept_tls_get_addr=1 %run %t 10 2 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:verbosity=2:intercept_tls_get_addr=0 %run %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0
// CHECK: __tls_get_addr
// CHECK: Creating thread 0
// CHECK: __tls_get_addr
// before exit.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts= %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_memprof -DFREE -O0 %s -o %t
-// RUN: %env_memprof_opts= %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// This is actually:
// Memory allocation stack id = STACKID
// Check profile with calls to memory intrinsics.
-// RUN: %clangxx_memprof -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_memprof -O0 %s -o %t && %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// This is actually:
// Memory allocation stack id = STACKIDP
// before exit.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts= %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_memprof -DFREE -O0 %s -o %t
-// RUN: %env_memprof_opts= %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// Try again with callbacks instead of inline sequences
// RUN: %clangxx_memprof -mllvm -memprof-use-callbacks -O0 %s -o %t
-// RUN: %env_memprof_opts= %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// This is actually:
// Memory allocation stack id = STACKID
// deallocated before exit.
// RUN: %clangxx_memprof -O0 %s -o %t
-// RUN: %env_memprof_opts=print_terse=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:print_terse=1 %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_memprof -DFREE -O0 %s -o %t
-// RUN: %env_memprof_opts=print_terse=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_memprof_opts=log_path=stderr:print_terse=1 %run %t 2>&1 | FileCheck %s
// CHECK: MIB:[[STACKID:[0-9]+]]/1/40.00/40/40/20.00/20/20/[[AVELIFETIME:[0-9]+]].00/[[AVELIFETIME]]/[[AVELIFETIME]]/0/0/0/0
// CHECK: Stack for id [[STACKID]]:
-// RUN: %clangxx_memprof -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_memprof -O0 %s -o %t && %env_memprof_opts=log_path=stderr %run %t 2>&1 | FileCheck %s
// This is actually:
// Memory allocation stack id = STACKID
constexpr char MemProfShadowMemoryDynamicAddress[] =
"__memprof_shadow_memory_dynamic_address";
+constexpr char MemProfFilenameVar[] = "__memprof_profile_filename";
+
// Command-line flags.
static cl::opt<bool> ClInsertVersionCheck(
IRB.CreateStore(ShadowValue, ShadowAddr);
}
+// Create the variable for the profile file name.
+void createProfileFileNameVar(Module &M) {
+ const MDString *MemProfFilename =
+ dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename"));
+ if (!MemProfFilename)
+ return;
+ assert(!MemProfFilename->getString().empty() &&
+ "Unexpected MemProfProfileFilename metadata with empty string");
+ Constant *ProfileNameConst = ConstantDataArray::getString(
+ M.getContext(), MemProfFilename->getString(), true);
+ GlobalVariable *ProfileNameVar = new GlobalVariable(
+ M, ProfileNameConst->getType(), /*isConstant=*/true,
+ GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar);
+ Triple TT(M.getTargetTriple());
+ if (TT.supportsCOMDAT()) {
+ ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);
+ ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar));
+ }
+}
+
bool ModuleMemProfiler::instrumentModule(Module &M) {
// Create a module constructor.
std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION);
const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);
appendToGlobalCtors(M, MemProfCtorFunction, Priority);
+ createProfileFileNameVar(M);
+
return true;
}
--- /dev/null
+; Test to ensure that the filename provided by clang in the module flags
+; metadata results in the expected __memprof_profile_filename insertion.
+
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -memprof -memprof-module -S | FileCheck --check-prefixes=CHECK %s
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"MemProfProfileFilename", !"/tmp/memprof.profraw"}
+
+; CHECK: $__memprof_profile_filename = comdat any
+; CHECK: @__memprof_profile_filename = constant [21 x i8] c"/tmp/memprof.profraw\00", comdat