Skip to content

Commit

Permalink
Make the Boehm GC a Git submodule. Simplify gc.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
fruffy committed Mar 20, 2023
1 parent ada3b00 commit 400d314
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 140 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@
[submodule "backends/p4tools/submodules/inja"]
path = backends/p4tools/submodules/inja
url = https://github.com/pantor/inja.git
[submodule "tools/bdwgc"]
path = tools/bdwgc
url = https://github.com/ivmai/bdwgc
78 changes: 63 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ OPTION (ENABLE_DPDK "Build the DPDK backend (required for the full test suite)"
OPTION (ENABLE_P4TEST "Build the P4Test backend (required for the full test suite)" ON)
OPTION (ENABLE_TEST_TOOLS "Build the P4Tools development platform" OFF)
OPTION (ENABLE_P4C_GRAPHS "Build the p4c-graphs backend" ON)
OPTION (ENABLE_PROTOBUF_STATIC "Link against Protobuf statically" ON)
OPTION (ENABLE_GC "Use libgc" ON)
OPTION (ENABLE_MULTITHREAD "Use multithreading" OFF)
OPTION (ENABLE_LTO "Enable Link Time Optimization (LTO)" OFF)
Expand Down Expand Up @@ -119,22 +118,19 @@ if (BUILD_STATIC_RELEASE)
# Set the static variable
set(P4C_STATIC_BUILD STATIC)
# Do not bring in dynamic libstdcc and libgcc
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ -Wl,-z,muldefs")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,-z,muldefs")
add_definitions(-DP4C_STATIC_BUILD)
endif ()

# required tools and libraries
find_package (PythonInterp 3 REQUIRED)
find_package (FLEX 2.0 REQUIRED)
find_package (BISON 3.0 REQUIRED)
if (ENABLE_PROTOBUF_STATIC)
set(SAVED_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif ()
find_package (Protobuf 3.0.0 REQUIRED)
if (ENABLE_PROTOBUF_STATIC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${SAVED_CMAKE_FIND_LIBRARY_SUFFIXES})
endif ()
# we require -pthread to make std::call_once work, even if we're not using threads...
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

# The boost graph headers are optional and only required by the graphs backend
find_package (Boost QUIET COMPONENTS graph)
if (Boost_FOUND)
Expand All @@ -145,20 +141,71 @@ endif ()
find_package (Boost REQUIRED COMPONENTS iostreams)
# otherwise ordered_map code tries to use boost::get (graph)
add_definitions ("-DBOOST_NO_ARGUMENT_DEPENDENT_LOOKUP")

# Compile with the Boehm garbage collector (https://github.com/ivmai/bdwgc) if requested.
if (ENABLE_GC)
find_package (LibGc 7.4.2 REQUIRED)
set(enable_cplusplus ON CACHE BOOL "C++ support")
# set(enable_threads OFF CACHE BOOL "Support threads")
# We redirect all malloc calls in the program.
set(enable_redirect_malloc ON CACHE BOOL "Redirect malloc and friends to GC routines.")
set(install_headers OFF CACHE BOOL "Install header and pkg-config metadata files.")
set(enable_docs OFF CACHE BOOL "Build and install documentation.")
set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set.")
add_definitions("-DREDIRECT_REALLOC=GC_REALLOC")
add_definitions("-DREDIRECT_FREE=GC_FREE")
add_definitions("-DNO_EXECUTE_PERMISSION")
add_definitions("-D_REENTRANT")
if(APPLE)
add_definitions("-DGC_PTHREAD_SIGMASK_NEEDED")
endif()
# We need to enable position independent code to make the malloc redirect work.
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if (BUILD_STATIC_RELEASE)
set(LIBGC_LIBRARIES
${CMAKE_BINARY_DIR}/tools/bdwgc/libgc.a
${CMAKE_BINARY_DIR}/tools/bdwgc/libgccpp.a
${CMAKE_BINARY_DIR}/tools/bdwgc/libcord.a
)
set(BUILD_SHARED_LIBS OFF CACHE STRING " " FORCE)
set(enable_threads OFF CACHE BOOL "Support threads.")
else()
add_definitions("-DUSE_COMPILER_TLS")
add_definitions("-DPARALLEL_MARK")
set(LIBGC_LIBRARIES gc gccpp cord)
endif()
add_subdirectory(tools/bdwgc)
include_directories(SYSTEM ${CMAKE_CURRENT_LIST_DIR}/tools/bdwgc/include)
set (HAVE_LIBGC 1)
add_custom_target(pre_bdwgc_patch ALL)
add_dependencies(gc pre_bdwgc_patch)
add_custom_target(post_bdwgc_patch ALL DEPENDS gc)
add_custom_command(
TARGET pre_bdwgc_patch
PRE_BUILD
COMMAND git apply ${CMAKE_SOURCE_DIR}/tools/silence_gc_warnings.patch
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tools/bdwgc/
MAIN_DEPENDENCY pre_bdwgc_patch
COMMENT "Patching bdwgc."
)
add_custom_command(
TARGET post_bdwgc_patch
POST_BUILD
COMMAND git apply --reverse ${CMAKE_SOURCE_DIR}/tools/silence_gc_warnings.patch
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tools/bdwgc/
MAIN_DEPENDENCY gc
COMMENT "Reverting bdwgc patch."
)
endif ()
if (ENABLE_MULTITHREAD)
add_definitions(-DMULTITHREAD)
add_definitions("-DMULTITHREAD")
add_definitions("-DGC_THREADS=1")
add_definitions("-DGC_NO_THREAD_REDIRECTS=1")
endif()
# we require -pthread to make std::call_once work, even if we're not using threads...
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${CMAKE_THREAD_LIBS_INIT}")

include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIRS})
include_directories(SYSTEM ${LIBGC_INCLUDE_DIR})
set (HAVE_LIBBOOST_IOSTREAMS 1)
set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${Boost_LIBRARIES}")
if (ENABLE_GC)
Expand Down Expand Up @@ -530,6 +577,7 @@ file(
list(FILTER P4C_LINT_LIST EXCLUDE REGEX "backends/p4tools/submodules")
list(FILTER P4C_LINT_LIST EXCLUDE REGEX "backends/ebpf/runtime")
list(FILTER P4C_LINT_LIST EXCLUDE REGEX "backends/ubpf/runtime")
list(FILTER P4C_LINT_LIST EXCLUDE REGEX "tools/bdwgc")
list(FILTER P4C_LINT_LIST EXCLUDE REGEX "control-plane/p4runtime")

# cpplint
Expand Down
3 changes: 0 additions & 3 deletions backends/p4tools/cmake/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ if(CCACHE_PROGRAM)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
endif()

# Use libgc.
find_package(LibGc 7.2.0 REQUIRED)

# Helper for defining a p4tools executable target.
function(add_p4tools_executable target source)
add_executable(${target} ${source} ${ARGN})
Expand Down
4 changes: 2 additions & 2 deletions backends/p4tools/common/core/z3_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
namespace P4Tools {

/// Converts a Z3 expression to a string.
const char *toString(z3::expr e) { return Z3_ast_to_string(e.ctx(), e); }
const char *toString(const z3::expr &e) { return Z3_ast_to_string(e.ctx(), e); }

#ifndef NDEBUG
template <typename... Args>
Expand All @@ -46,7 +46,7 @@ std::string stringFormat(const char *format, Args... args) {
__VA_ARGS__))

/// Converts a Z3 model to a string.
const char *toString(z3::model m) { return Z3_model_to_string(m.ctx(), m); }
const char *toString(const z3::model &m) { return Z3_model_to_string(m.ctx(), m); }
#else
#define Z3_LOG(...)
#endif // NDEBUG
Expand Down
5 changes: 2 additions & 3 deletions backends/p4tools/modules/testgen/targets/bmv2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ set(
execute_process(COMMAND ln -sfn ${P4C_SOURCE_DIR}/backends/bmv2/run-bmv2-test.py ${CMAKE_BINARY_DIR}/run-bmv2-test.py)

set(
TESTGEN_LIBS ${TESTGEN_LIBS}
TESTGEN_LIBS
${P4C_LIBRARIES}
${P4C_LIB_DEPS}
${CMAKE_THREAD_LIBS_INIT}
${TESTGEN_LIBS}
PARENT_SCOPE
)
5 changes: 3 additions & 2 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ set (LIBP4CTOOLKIT_HDRS
timer.h
)


add_library(p4ctoolkit STATIC ${LIBP4CTOOLKIT_SRCS})

# Disable libcall (realloc, malloc) optimizations which may cause infinite loops.
set_target_properties(p4ctoolkit PROPERTIES COMPILE_FLAGS -fno-builtin)
if (ENABLE_GC)
set_target_properties(p4ctoolkit PROPERTIES COMPILE_FLAGS -fno-builtin)
endif()
136 changes: 23 additions & 113 deletions lib/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

#include "config.h"
#if HAVE_LIBGC
#include <gc/gc.h>
#include <gc/gc_cpp.h>
#include <gc/gc_mark.h>
#endif /* HAVE_LIBGC */
Expand All @@ -31,146 +32,49 @@ limitations under the License.
#include "log.h"
#include "n4.h"

/* glibc++ requires defining global delete with this exception spec to avoid warnings.
* If it's not defined, probably not using glibc++ and don't need anything */
#ifndef _GLIBCXX_USE_NOEXCEPT
#define _GLIBCXX_USE_NOEXCEPT _NOEXCEPT
#endif

// One can disable the GC, e.g., to run under Valgrind, by editing config.h
#if HAVE_LIBGC
static bool done_init, started_init;
// emergency pool to allow a few extra allocations after a bad_alloc is thrown so we
// can generate reasonable errors, a stack trace, etc
static char emergency_pool[16 * 1024];
static char *emergency_ptr;

// One can disable the GC, e.g., to run under Valgrind, by editing config.h
void *operator new(std::size_t size) {
/* DANGER -- on OSX, can't safely call the garbage collector allocation
* routines from a static global constructor without manually initializing
* it first. Since we have global constructors that want to allocate
* memory, we need to force initialization */
if (!done_init) {
started_init = true;
GC_INIT();
done_init = true;
}
auto *rv = ::operator new(size, UseGC, 0, 0);
if (!rv && emergency_ptr && emergency_ptr + size < emergency_pool + sizeof(emergency_pool)) {
auto *rv = gc::operator new(size);
if ((rv == nullptr) && (emergency_ptr != nullptr) &&
emergency_ptr + size < emergency_pool + sizeof(emergency_pool)) {
rv = emergency_ptr;
size += -size & 0xf; // align to 16 bytes
emergency_ptr += size;
}
if (!rv) {
if (!emergency_ptr) emergency_ptr = emergency_pool;
if (rv == nullptr) {
if (emergency_ptr == nullptr) emergency_ptr = emergency_pool;
throw backtrace_exception<std::bad_alloc>();
}
return rv;
}

// clang-format off
void operator delete(void* p) _GLIBCXX_USE_NOEXCEPT {
void operator delete(void *p) noexcept {
if (p >= emergency_pool && p < emergency_pool + sizeof(emergency_pool)) {
return;
}
gc::operator delete(p);
}

void operator delete(void* p, std::size_t /*size*/) _GLIBCXX_USE_NOEXCEPT {
void operator delete(void *p, std::size_t /*size*/) noexcept {
if (p >= emergency_pool && p < emergency_pool + sizeof(emergency_pool)) {
return;
}
gc::operator delete(p);
}
// clang-format on

void *operator new[](std::size_t size) { return ::operator new(size); }
void operator delete[](void *p) _GLIBCXX_USE_NOEXCEPT { ::operator delete(p); }
void operator delete[](void *p, std::size_t) _GLIBCXX_USE_NOEXCEPT { ::operator delete(p); }

namespace {

constexpr size_t headerSize = 16;
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56019
// p4c requires gcc 4.9+, but there is no harm in adding this; maybe it wil help someone.
#if __GNUC__ == 4 && __GNUC_MINOR__ <= 8
using max_align_t = ::max_align_t;
#else
using max_align_t = std::max_align_t;
#endif
static_assert(headerSize >= alignof(max_align_t), "mmap header size not large enough");
static_assert(headerSize >= sizeof(size_t), "mmap header size not large enough");

void *data_to_header(void *ptr) { return static_cast<char *>(ptr) - headerSize; }

void *header_to_data(void *ptr) { return static_cast<char *>(ptr) + headerSize; }

size_t raw_size(void *ptr) {
size_t size;
memcpy(static_cast<void *>(&size), data_to_header(ptr), sizeof(size));
return size;
}

void *raw_alloc(size_t size) {
void *ptr =
mmap(0, size + headerSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
memcpy(ptr, static_cast<void *>(&size), sizeof(size));
return header_to_data(ptr);
}

void raw_free(void *ptr) {
size_t size = raw_size(ptr);
munmap(data_to_header(ptr), size + headerSize);
}

} // namespace

void *realloc(void *ptr, size_t size) {
if (!done_init) {
if (started_init) {
// called from within GC_INIT, so we can't call it again. Fall back to using
// mmap.
void *rv = raw_alloc(size);
if (ptr) {
size_t max = raw_size(ptr);
memcpy(rv, ptr, max < size ? max : size);
raw_free(ptr);
}
return rv;
} else {
started_init = true;
GC_INIT();
done_init = true;
}
}
if (ptr) {
if (GC_is_heap_ptr(ptr)) return GC_realloc(ptr, size);
size_t max = raw_size(ptr);
void *rv = GC_malloc(size);
memcpy(rv, ptr, max < size ? max : size);
raw_free(ptr);
return rv;
} else {
return GC_malloc(size);
}
}
// IMPORTANT: do not simplify this to realloc(nullptr, size)
// As it could be optimized to malloc(size) call causing
// infinite loops
void *malloc(size_t size) {
if (!done_init) return realloc(nullptr, size);

return GC_malloc(size);
}
void free(void *ptr) {
if (done_init && GC_is_heap_ptr(ptr)) GC_free(ptr);
}
void *calloc(size_t size, size_t elsize) {
size *= elsize;
void *rv = malloc(size);
if (rv) memset(rv, 0, size);
return rv;
}
void *operator new[](std::size_t size) { return gc::operator new(size); }
void operator delete[](void *p) noexcept { gc::operator delete(p); }
void operator delete[](void *p, std::size_t /*size*/) noexcept { ::operator delete(p); }

#if HAVE_GC_PRINT_STATS
/* GC_print_stats is not exported as an API symbol and cannot be used on some systems */
Expand All @@ -182,7 +86,8 @@ static int gc_logging_level;
static void gc_callback() {
if (gc_logging_level >= 1) {
std::clog << "****** GC called ****** (heap size " << n4(GC_get_heap_size()) << ")";
size_t count, size = cstring::cache_size(count);
size_t count = 0;
size_t size = cstring::cache_size(count);
std::clog << " cstring cache size " << n4(size) << " (count " << n4(count) << ")"
<< std::endl;
}
Expand Down Expand Up @@ -210,13 +115,18 @@ void setup_gc_logging() {

size_t gc_mem_inuse(size_t *max) {
#if HAVE_LIBGC
GC_word heapsize, heapfree;
GC_word heapsize = 0;
GC_word heapfree = 0;
GC_gcollect();
GC_get_heap_usage_safe(&heapsize, &heapfree, 0, 0, 0);
if (max) *max = heapsize;
GC_get_heap_usage_safe(&heapsize, &heapfree, nullptr, nullptr, nullptr);
if (max != nullptr) {
*max = heapsize;
}
return heapsize - heapfree;
#else
if (max) *max = 0;
if (max) {
*max = 0;
}
return 0;
#endif
}
1 change: 1 addition & 0 deletions tools/bdwgc
Submodule bdwgc added at b41a29
2 changes: 0 additions & 2 deletions tools/ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ P4C_DEPS="bison \
libboost-graph-dev \
libboost-iostreams-dev \
libfl-dev \
libgc-dev \
pkg-config \
python3 \
python3-pip \
Expand Down Expand Up @@ -89,7 +88,6 @@ fi

P4C_RUNTIME_DEPS="cpp \
${P4C_RUNTIME_DEPS_BOOST} \
libgc1* \
libgmp-dev \
python3"

Expand Down
Loading

0 comments on commit 400d314

Please sign in to comment.