Skip to content

Commit 6ad22c8

Browse files
authored
[compiler-rt][ctx_instr] Add ctx_profile component (#89304)
Add the component structure for contextual instrumented PGO and the bump allocator + test. (Tracking Issue: #89287, RFC referenced there)
1 parent 7c581b5 commit 6ad22c8

10 files changed

+247
-0
lines changed

compiler-rt/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON)
5050
mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER)
5151
option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON)
5252
mark_as_advanced(COMPILER_RT_BUILD_PROFILE)
53+
option(COMPILER_RT_BUILD_CTX_PROFILE "Build ctx profile runtime" ON)
54+
mark_as_advanced(COMPILER_RT_BUILD_CTX_PROFILE)
5355
option(COMPILER_RT_BUILD_MEMPROF "Build memory profiling runtime" ON)
5456
mark_as_advanced(COMPILER_RT_BUILD_MEMPROF)
5557
option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF)

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
6666
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}
6767
${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
6868
${RISCV32} ${RISCV64} ${LOONGARCH64})
69+
set(ALL_CTX_PROFILE_SUPPORTED_ARCH ${X86_64})
6970
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
7071
${LOONGARCH64} ${RISCV64})
7172
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}

compiler-rt/cmake/config-ix.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,9 @@ if(APPLE)
632632
list_intersect(PROFILE_SUPPORTED_ARCH
633633
ALL_PROFILE_SUPPORTED_ARCH
634634
SANITIZER_COMMON_SUPPORTED_ARCH)
635+
list_intersect(CTX_PROFILE_SUPPORTED_ARCH
636+
ALL_CTX_PROFILE_SUPPORTED_ARCH
637+
SANITIZER_COMMON_SUPPORTED_ARCH)
635638
list_intersect(TSAN_SUPPORTED_ARCH
636639
ALL_TSAN_SUPPORTED_ARCH
637640
SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -678,6 +681,7 @@ else()
678681
filter_available_targets(HWASAN_SUPPORTED_ARCH ${ALL_HWASAN_SUPPORTED_ARCH})
679682
filter_available_targets(MEMPROF_SUPPORTED_ARCH ${ALL_MEMPROF_SUPPORTED_ARCH})
680683
filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
684+
filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH ${ALL_CTX_PROFILE_SUPPORTED_ARCH})
681685
filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
682686
filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
683687
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
@@ -803,6 +807,13 @@ else()
803807
set(COMPILER_RT_HAS_PROFILE FALSE)
804808
endif()
805809

810+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND CTX_PROFILE_SUPPORTED_ARCH AND
811+
OS_NAME MATCHES "Linux")
812+
set(COMPILER_RT_HAS_CTX_PROFILE TRUE)
813+
else()
814+
set(COMPILER_RT_HAS_CTX_PROFILE FALSE)
815+
endif()
816+
806817
if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH)
807818
if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD")
808819
set(COMPILER_RT_HAS_TSAN TRUE)

compiler-rt/lib/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE)
5151
compiler_rt_build_runtime(profile)
5252
endif()
5353

54+
if(COMPILER_RT_BUILD_CTX_PROFILE AND COMPILER_RT_HAS_CTX_PROFILE)
55+
compiler_rt_build_runtime(ctx_profile)
56+
endif()
57+
5458
if(COMPILER_RT_BUILD_XRAY)
5559
compiler_rt_build_runtime(xray)
5660
endif()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
add_compiler_rt_component(ctx_profile)
2+
3+
set(CTX_PROFILE_SOURCES
4+
CtxInstrProfiling.cpp
5+
)
6+
7+
set(CTX_PROFILE_HEADERS
8+
CtxInstrProfiling.h
9+
)
10+
11+
include_directories(..)
12+
include_directories(../../include)
13+
14+
# We don't use the C++ Standard Library here, so avoid including it by mistake.
15+
append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ EXTRA_FLAGS)
16+
17+
add_compiler_rt_runtime(clang_rt.ctx_profile
18+
STATIC
19+
ARCHS ${CTX_PROFILE_SUPPORTED_ARCH}
20+
OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc
21+
CFLAGS ${EXTRA_FLAGS}
22+
SOURCES ${CTX_PROFILE_SOURCES}
23+
ADDITIONAL_HEADERS ${CTX_PROFILE_HEADERS}
24+
PARENT_TARGET ctx_profile)
25+
26+
if(COMPILER_RT_INCLUDE_TESTS)
27+
add_subdirectory(tests)
28+
endif()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===- CtxInstrProfiling.cpp - contextual instrumented PGO ----------------===//
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+
#include "CtxInstrProfiling.h"
10+
#include "sanitizer_common/sanitizer_allocator_internal.h"
11+
#include "sanitizer_common/sanitizer_common.h"
12+
#include "sanitizer_common/sanitizer_dense_map.h"
13+
#include "sanitizer_common/sanitizer_mutex.h"
14+
#include "sanitizer_common/sanitizer_placement_new.h"
15+
#include "sanitizer_common/sanitizer_thread_safety.h"
16+
17+
#include <assert.h>
18+
19+
using namespace __ctx_profile;
20+
21+
// FIXME(mtrofin): use malloc / mmap instead of sanitizer common APIs to reduce
22+
// the dependency on the latter.
23+
Arena *Arena::allocateNewArena(size_t Size, Arena *Prev) {
24+
assert(!Prev || Prev->Next == nullptr);
25+
Arena *NewArena =
26+
new (__sanitizer::InternalAlloc(Size + sizeof(Arena))) Arena(Size);
27+
if (Prev)
28+
Prev->Next = NewArena;
29+
return NewArena;
30+
}
31+
32+
void Arena::freeArenaList(Arena *&A) {
33+
assert(A);
34+
for (auto *I = A; I != nullptr;) {
35+
auto *Current = I;
36+
I = I->Next;
37+
__sanitizer::InternalFree(Current);
38+
}
39+
A = nullptr;
40+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*===- CtxInstrProfiling.h- Contextual instrumentation-based PGO ---------===*\
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+
#ifndef CTX_PROFILE_CTXINSTRPROFILING_H_
10+
#define CTX_PROFILE_CTXINSTRPROFILING_H_
11+
12+
#include <sanitizer/common_interface_defs.h>
13+
14+
namespace __ctx_profile {
15+
16+
/// Arena (bump allocator) forming a linked list. Intentionally not thread safe.
17+
/// Allocation and de-allocation happen using sanitizer APIs. We make that
18+
/// explicit.
19+
class Arena final {
20+
public:
21+
// When allocating a new Arena, optionally specify an existing one to append
22+
// to, assumed to be the last in the Arena list. We only need to support
23+
// appending to the arena list.
24+
static Arena *allocateNewArena(size_t Size, Arena *Prev = nullptr);
25+
static void freeArenaList(Arena *&A);
26+
27+
uint64_t size() const { return Size; }
28+
29+
// Allocate S bytes or return nullptr if we don't have that many available.
30+
char *tryBumpAllocate(size_t S) {
31+
if (Pos + S > Size)
32+
return nullptr;
33+
Pos += S;
34+
return start() + (Pos - S);
35+
}
36+
37+
Arena *next() const { return Next; }
38+
39+
// the beginning of allocatable memory.
40+
const char *start() const { return const_cast<Arena *>(this)->start(); }
41+
const char *pos() const { return start() + Pos; }
42+
43+
private:
44+
explicit Arena(uint32_t Size) : Size(Size) {}
45+
~Arena() = delete;
46+
47+
char *start() { return reinterpret_cast<char *>(&this[1]); }
48+
49+
Arena *Next = nullptr;
50+
uint64_t Pos = 0;
51+
const uint64_t Size;
52+
};
53+
54+
} // namespace __ctx_profile
55+
#endif // CTX_PROFILE_CTXINSTRPROFILING_H_
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
include(CheckCXXCompilerFlag)
2+
include(CompilerRTCompile)
3+
include(CompilerRTLink)
4+
5+
set(CTX_PROFILE_UNITTEST_CFLAGS
6+
${COMPILER_RT_UNITTEST_CFLAGS}
7+
${COMPILER_RT_GTEST_CFLAGS}
8+
${COMPILER_RT_GMOCK_CFLAGS}
9+
${SANITIZER_TEST_CXX_CFLAGS}
10+
-I${COMPILER_RT_SOURCE_DIR}/lib/
11+
-DSANITIZER_COMMON_NO_REDEFINE_BUILTINS
12+
-O2
13+
-g
14+
-fno-rtti
15+
-Wno-pedantic
16+
-fno-omit-frame-pointer)
17+
18+
# Suppress warnings for gmock variadic macros for clang and gcc respectively.
19+
append_list_if(SUPPORTS_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS_FLAG -Wno-gnu-zero-variadic-macro-arguments CTX_PROFILE_UNITTEST_CFLAGS)
20+
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros CTX_PROFILE_UNITTEST_CFLAGS)
21+
22+
file(GLOB PROFILE_HEADERS ../*.h)
23+
24+
set(CTX_PROFILE_SOURCES
25+
../CtxInstrProfiling.cpp)
26+
27+
set(CTX_PROFILE_UNITTESTS
28+
CtxInstrProfilingTest.cpp
29+
driver.cpp)
30+
31+
include_directories(../../../include)
32+
33+
set(CTX_PROFILE_UNIT_TEST_HEADERS
34+
${CTX_PROFILE_HEADERS})
35+
36+
set(CTX_PROFILE_UNITTEST_LINK_FLAGS
37+
${COMPILER_RT_UNITTEST_LINK_FLAGS})
38+
39+
list(APPEND CTX_PROFILE_UNITTEST_LINK_FLAGS -pthread)
40+
41+
set(CTX_PROFILE_UNITTEST_LINK_LIBRARIES
42+
${COMPILER_RT_UNWINDER_LINK_LIBS}
43+
${SANITIZER_TEST_CXX_LIBRARIES})
44+
list(APPEND CTX_PROFILE_UNITTEST_LINK_LIBRARIES "dl")
45+
46+
if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST CTX_PROFILE_SUPPORTED_ARCH)
47+
# Profile unit tests are only run on the host machine.
48+
set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
49+
50+
add_executable(CtxProfileUnitTests
51+
${CTX_PROFILE_UNITTESTS}
52+
${COMPILER_RT_GTEST_SOURCE}
53+
${COMPILER_RT_GMOCK_SOURCE}
54+
${CTX_PROFILE_SOURCES}
55+
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
56+
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
57+
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
58+
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
59+
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>)
60+
set_target_compile_flags(CtxProfileUnitTests ${CTX_PROFILE_UNITTEST_CFLAGS})
61+
set_target_link_flags(CtxProfileUnitTests ${CTX_PROFILE_UNITTEST_LINK_FLAGS})
62+
target_link_libraries(CtxProfileUnitTests ${CTX_PROFILE_UNITTEST_LINK_LIBRARIES})
63+
64+
if (TARGET cxx-headers OR HAVE_LIBCXX)
65+
add_dependencies(CtxProfileUnitTests cxx-headers)
66+
endif()
67+
68+
set_target_properties(CtxProfileUnitTests PROPERTIES
69+
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
70+
endif()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "../CtxInstrProfiling.h"
2+
#include "gtest/gtest.h"
3+
4+
using namespace __ctx_profile;
5+
6+
TEST(ArenaTest, Basic) {
7+
Arena *A = Arena::allocateNewArena(1024);
8+
EXPECT_EQ(A->size(), 1024U);
9+
EXPECT_EQ(A->next(), nullptr);
10+
11+
auto *M1 = A->tryBumpAllocate(1020);
12+
EXPECT_NE(M1, nullptr);
13+
auto *M2 = A->tryBumpAllocate(4);
14+
EXPECT_NE(M2, nullptr);
15+
EXPECT_EQ(M1 + 1020, M2);
16+
EXPECT_EQ(A->tryBumpAllocate(1), nullptr);
17+
Arena *A2 = Arena::allocateNewArena(2024, A);
18+
EXPECT_EQ(A->next(), A2);
19+
EXPECT_EQ(A2->next(), nullptr);
20+
Arena::freeArenaList(A);
21+
EXPECT_EQ(A, nullptr);
22+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//===-- driver.cpp ----------------------------------------------*- 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+
#include "gtest/gtest.h"
10+
11+
int main(int argc, char **argv) {
12+
testing::InitGoogleTest(&argc, argv);
13+
return RUN_ALL_TESTS();
14+
}

0 commit comments

Comments
 (0)