Skip to content

Commit 3d4bba3

Browse files
committed
[MemProf] Memory profiling runtime support
See RFC for background: http://lists.llvm.org/pipermail/llvm-dev/2020-June/142744.html Follow on companion to the clang/llvm instrumentation support in D85948 and committed earlier. This patch adds the compiler-rt runtime support for the memory profiling. Note that much of this support was cloned from asan (and then greatly simplified and renamed). For example the interactions with the sanitizer_common allocators, error handling, interception, etc. The bulk of the memory profiling specific code can be found in the MemInfoBlock, MemInfoBlockCache, and related classes defined and used in memprof_allocator.cpp. For now, the memory profile is dumped to text (stderr by default, but honors the sanitizer_common log_path flag). It is dumped in either a default verbose format, or an optional terse format. This patch also adds a set of tests for the core functionality. Differential Revision: https://reviews.llvm.org/D87120
1 parent 880fc4d commit 3d4bba3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+4816
-2
lines changed

compiler-rt/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON)
4545
mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER)
4646
option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON)
4747
mark_as_advanced(COMPILER_RT_BUILD_PROFILE)
48+
option(COMPILER_RT_BUILD_MEMPROF "Build memory profiling runtime" ON)
49+
mark_as_advanced(COMPILER_RT_BUILD_MEMPROF)
4850
option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF)
4951
mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT)
5052

compiler-rt/cmake/config-ix.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ else()
324324
endif()
325325
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X})
326326
set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
327+
set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
327328
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
328329
${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9})
329330
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
@@ -551,6 +552,9 @@ if(APPLE)
551552
list_intersect(HWASAN_SUPPORTED_ARCH
552553
ALL_HWASAN_SUPPORTED_ARCH
553554
SANITIZER_COMMON_SUPPORTED_ARCH)
555+
list_intersect(MEMPROF_SUPPORTED_ARCH
556+
ALL_MEMPROF_SUPPORTED_ARCH
557+
SANITIZER_COMMON_SUPPORTED_ARCH)
554558
list_intersect(PROFILE_SUPPORTED_ARCH
555559
ALL_PROFILE_SUPPORTED_ARCH
556560
SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -599,6 +603,7 @@ else()
599603
filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH})
600604
filter_available_targets(MSAN_SUPPORTED_ARCH ${ALL_MSAN_SUPPORTED_ARCH})
601605
filter_available_targets(HWASAN_SUPPORTED_ARCH ${ALL_HWASAN_SUPPORTED_ARCH})
606+
filter_available_targets(MEMPROF_SUPPORTED_ARCH ${ALL_MEMPROF_SUPPORTED_ARCH})
602607
filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
603608
filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
604609
filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
@@ -702,6 +707,13 @@ else()
702707
set(COMPILER_RT_HAS_HWASAN FALSE)
703708
endif()
704709

710+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND MEMPROF_SUPPORTED_ARCH AND
711+
OS_NAME MATCHES "Linux")
712+
set(COMPILER_RT_HAS_MEMPROF TRUE)
713+
else()
714+
set(COMPILER_RT_HAS_MEMPROF FALSE)
715+
endif()
716+
705717
if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
706718
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD")
707719
set(COMPILER_RT_HAS_PROFILE TRUE)

compiler-rt/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)
55
sanitizer/common_interface_defs.h
66
sanitizer/coverage_interface.h
77
sanitizer/dfsan_interface.h
8+
sanitizer/memprof_interface.h
89
sanitizer/hwasan_interface.h
910
sanitizer/linux_syscall_hooks.h
1011
sanitizer/lsan_interface.h
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===-- sanitizer/memprof_interface.h --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of MemProfiler (MemProf).
10+
//
11+
// Public interface header.
12+
//===----------------------------------------------------------------------===//
13+
#ifndef SANITIZER_MEMPROF_INTERFACE_H
14+
#define SANITIZER_MEMPROF_INTERFACE_H
15+
16+
#include <sanitizer/common_interface_defs.h>
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
/// Records access to a memory region (<c>[addr, addr+size)</c>).
22+
///
23+
/// This memory must be previously allocated by your program.
24+
///
25+
/// \param addr Start of memory region.
26+
/// \param size Size of memory region.
27+
void __memprof_record_access_range(void const volatile *addr, size_t size);
28+
29+
/// Records access to a memory address <c><i>addr</i></c>.
30+
///
31+
/// This memory must be previously allocated by your program.
32+
///
33+
/// \param addr Accessed memory address
34+
void __memprof_record_access(void const volatile *addr);
35+
36+
/// User-provided callback on MemProf errors.
37+
///
38+
/// You can provide a function that would be called immediately when MemProf
39+
/// detects an error. This is useful in cases when MemProf detects an error but
40+
/// your program crashes before the MemProf report is printed.
41+
void __memprof_on_error(void);
42+
43+
/// Prints accumulated statistics to <c>stderr</c> (useful for calling from the
44+
/// debugger).
45+
void __memprof_print_accumulated_stats(void);
46+
47+
/// User-provided default option settings.
48+
///
49+
/// You can provide your own implementation of this function to return a string
50+
/// containing MemProf runtime options (for example,
51+
/// <c>verbosity=1:print_stats=1</c>).
52+
///
53+
/// \returns Default options string.
54+
const char *__memprof_default_options(void);
55+
56+
#ifdef __cplusplus
57+
} // extern "C"
58+
#endif
59+
60+
#endif // SANITIZER_MEMPROF_INTERFACE_H

compiler-rt/lib/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ if(COMPILER_RT_BUILD_LIBFUZZER)
6060
compiler_rt_build_runtime(fuzzer)
6161
endif()
6262

63+
if(COMPILER_RT_BUILD_MEMPROF AND COMPILER_RT_HAS_SANITIZER_COMMON)
64+
compiler_rt_build_runtime(memprof)
65+
endif()
66+
6367
# It doesn't normally make sense to build runtimes when a sanitizer is enabled,
6468
# so we don't add_subdirectory the runtimes in that case. However, the opposite
6569
# is true for fuzzers that exercise parts of the runtime. So we add the fuzzer
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Build for the Memory Profiler runtime support library.
2+
3+
set(MEMPROF_SOURCES
4+
memprof_allocator.cpp
5+
memprof_descriptions.cpp
6+
memprof_flags.cpp
7+
memprof_interceptors.cpp
8+
memprof_interceptors_memintrinsics.cpp
9+
memprof_linux.cpp
10+
memprof_malloc_linux.cpp
11+
memprof_posix.cpp
12+
memprof_rtl.cpp
13+
memprof_shadow_setup.cpp
14+
memprof_stack.cpp
15+
memprof_stats.cpp
16+
memprof_thread.cpp
17+
)
18+
19+
set(MEMPROF_CXX_SOURCES
20+
memprof_new_delete.cpp
21+
)
22+
23+
set(MEMPROF_PREINIT_SOURCES
24+
memprof_preinit.cpp
25+
)
26+
27+
SET(MEMPROF_HEADERS
28+
memprof_allocator.h
29+
memprof_descriptions.h
30+
memprof_flags.h
31+
memprof_flags.inc
32+
memprof_init_version.h
33+
memprof_interceptors.h
34+
memprof_interceptors_memintrinsics.h
35+
memprof_interface_internal.h
36+
memprof_internal.h
37+
memprof_mapping.h
38+
memprof_stack.h
39+
memprof_stats.h
40+
memprof_thread.h
41+
)
42+
43+
include_directories(..)
44+
45+
set(MEMPROF_CFLAGS ${SANITIZER_COMMON_CFLAGS})
46+
set(MEMPROF_COMMON_DEFINITIONS "")
47+
48+
append_rtti_flag(OFF MEMPROF_CFLAGS)
49+
50+
set(MEMPROF_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
51+
52+
set(MEMPROF_DYNAMIC_DEFINITIONS
53+
${MEMPROF_COMMON_DEFINITIONS} MEMPROF_DYNAMIC=1)
54+
55+
set(MEMPROF_DYNAMIC_CFLAGS ${MEMPROF_CFLAGS})
56+
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
57+
-ftls-model=initial-exec MEMPROF_DYNAMIC_CFLAGS)
58+
59+
set(MEMPROF_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARIES} ${SANITIZER_COMMON_LINK_LIBS})
60+
61+
append_list_if(COMPILER_RT_HAS_LIBDL dl MEMPROF_DYNAMIC_LIBS)
62+
append_list_if(COMPILER_RT_HAS_LIBRT rt MEMPROF_DYNAMIC_LIBS)
63+
append_list_if(COMPILER_RT_HAS_LIBM m MEMPROF_DYNAMIC_LIBS)
64+
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread MEMPROF_DYNAMIC_LIBS)
65+
append_list_if(COMPILER_RT_HAS_LIBLOG log MEMPROF_DYNAMIC_LIBS)
66+
67+
if (TARGET cxx-headers OR HAVE_LIBCXX)
68+
set(MEMPROF_DEPS cxx-headers)
69+
endif()
70+
71+
# Compile MemProf sources into an object library.
72+
73+
add_compiler_rt_object_libraries(RTMemprof_dynamic
74+
OS ${SANITIZER_COMMON_SUPPORTED_OS}
75+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
76+
SOURCES ${MEMPROF_SOURCES} ${MEMPROF_CXX_SOURCES}
77+
ADDITIONAL_HEADERS ${MEMPROF_HEADERS}
78+
CFLAGS ${MEMPROF_DYNAMIC_CFLAGS}
79+
DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
80+
DEPS ${MEMPROF_DEPS})
81+
82+
add_compiler_rt_object_libraries(RTMemprof
83+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
84+
SOURCES ${MEMPROF_SOURCES}
85+
ADDITIONAL_HEADERS ${MEMPROF_HEADERS}
86+
CFLAGS ${MEMPROF_CFLAGS}
87+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
88+
DEPS ${MEMPROF_DEPS})
89+
add_compiler_rt_object_libraries(RTMemprof_cxx
90+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
91+
SOURCES ${MEMPROF_CXX_SOURCES}
92+
ADDITIONAL_HEADERS ${MEMPROF_HEADERS}
93+
CFLAGS ${MEMPROF_CFLAGS}
94+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
95+
DEPS ${MEMPROF_DEPS})
96+
add_compiler_rt_object_libraries(RTMemprof_preinit
97+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
98+
SOURCES ${MEMPROF_PREINIT_SOURCES}
99+
ADDITIONAL_HEADERS ${MEMPROF_HEADERS}
100+
CFLAGS ${MEMPROF_CFLAGS}
101+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
102+
DEPS ${MEMPROF_DEPS})
103+
104+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "")
105+
add_compiler_rt_object_libraries(RTMemprof_dynamic_version_script_dummy
106+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
107+
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
108+
CFLAGS ${MEMPROF_DYNAMIC_CFLAGS}
109+
DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
110+
DEPS ${MEMPROF_DEPS})
111+
112+
# Build MemProf runtimes shipped with Clang.
113+
add_compiler_rt_component(memprof)
114+
115+
# Build separate libraries for each target.
116+
117+
set(MEMPROF_COMMON_RUNTIME_OBJECT_LIBS
118+
RTInterception
119+
RTSanitizerCommon
120+
RTSanitizerCommonLibc
121+
RTSanitizerCommonCoverage
122+
RTSanitizerCommonSymbolizer)
123+
124+
add_compiler_rt_runtime(clang_rt.memprof
125+
STATIC
126+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
127+
OBJECT_LIBS RTMemprof_preinit
128+
RTMemprof
129+
${MEMPROF_COMMON_RUNTIME_OBJECT_LIBS}
130+
CFLAGS ${MEMPROF_CFLAGS}
131+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
132+
PARENT_TARGET memprof)
133+
134+
add_compiler_rt_runtime(clang_rt.memprof_cxx
135+
STATIC
136+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
137+
OBJECT_LIBS RTMemprof_cxx
138+
CFLAGS ${MEMPROF_CFLAGS}
139+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
140+
PARENT_TARGET memprof)
141+
142+
add_compiler_rt_runtime(clang_rt.memprof-preinit
143+
STATIC
144+
ARCHS ${MEMPROF_SUPPORTED_ARCH}
145+
OBJECT_LIBS RTMemprof_preinit
146+
CFLAGS ${MEMPROF_CFLAGS}
147+
DEFS ${MEMPROF_COMMON_DEFINITIONS}
148+
PARENT_TARGET memprof)
149+
150+
foreach(arch ${MEMPROF_SUPPORTED_ARCH})
151+
if (UNIX)
152+
add_sanitizer_rt_version_list(clang_rt.memprof-dynamic-${arch}
153+
LIBS clang_rt.memprof-${arch} clang_rt.memprof_cxx-${arch}
154+
EXTRA memprof.syms.extra)
155+
set(VERSION_SCRIPT_FLAG
156+
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.memprof-dynamic-${arch}.vers)
157+
set_property(SOURCE
158+
${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
159+
APPEND PROPERTY
160+
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.memprof-dynamic-${arch}.vers)
161+
else()
162+
set(VERSION_SCRIPT_FLAG)
163+
endif()
164+
165+
set(MEMPROF_DYNAMIC_WEAK_INTERCEPTION)
166+
167+
add_compiler_rt_runtime(clang_rt.memprof
168+
SHARED
169+
ARCHS ${arch}
170+
OBJECT_LIBS ${MEMPROF_COMMON_RUNTIME_OBJECT_LIBS}
171+
RTMemprof_dynamic
172+
# The only purpose of RTMemprof_dynamic_version_script_dummy is to
173+
# carry a dependency of the shared runtime on the version script.
174+
# Replacing it with a straightforward
175+
# add_dependencies(clang_rt.memprof-dynamic-${arch} clang_rt.memprof-dynamic-${arch}-version-list)
176+
# generates an order-only dependency in ninja.
177+
RTMemprof_dynamic_version_script_dummy
178+
${MEMPROF_DYNAMIC_WEAK_INTERCEPTION}
179+
CFLAGS ${MEMPROF_DYNAMIC_CFLAGS}
180+
LINK_FLAGS ${MEMPROF_DYNAMIC_LINK_FLAGS}
181+
${VERSION_SCRIPT_FLAG}
182+
LINK_LIBS ${MEMPROF_DYNAMIC_LIBS}
183+
DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
184+
PARENT_TARGET memprof)
185+
186+
if (SANITIZER_USE_SYMBOLS)
187+
add_sanitizer_rt_symbols(clang_rt.memprof_cxx
188+
ARCHS ${arch})
189+
add_dependencies(memprof clang_rt.memprof_cxx-${arch}-symbols)
190+
add_sanitizer_rt_symbols(clang_rt.memprof
191+
ARCHS ${arch}
192+
EXTRA memprof.syms.extra)
193+
add_dependencies(memprof clang_rt.memprof-${arch}-symbols)
194+
endif()
195+
endforeach()

compiler-rt/lib/memprof/README.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
MemProfiling RT
2+
================================
3+
This directory contains sources of the MemProfiling (MemProf) runtime library.
4+
5+
Directory structure:
6+
README.txt : This file.
7+
CMakeLists.txt : File for cmake-based build.
8+
memprof_*.{cc,h} : Sources of the memprof runtime library.
9+
10+
Also MemProf runtime needs the following libraries:
11+
lib/interception/ : Machinery used to intercept function calls.
12+
lib/sanitizer_common/ : Code shared between various sanitizers.
13+
14+
MemProf runtime can only be built by CMake. You can run MemProf tests
15+
from the root of your CMake build tree:
16+
17+
make check-memprof
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__memprof_*

0 commit comments

Comments
 (0)