diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b624d240..6417722df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,7 +232,6 @@ if (ENABLE_JEMALLOC_GLIBC_ALLOC) # The glibc jemalloc subproject which hooks the glibc allocator. # Required for thunks to work. # All host native libraries will use this allocator, while *most* other FEX internal allocations will use the other jemalloc allocator. - add_definitions(-DENABLE_JEMALLOC_GLIBC=1) add_subdirectory(External/jemalloc_glibc/) elseif (NOT MINGW_BUILD) message (STATUS @@ -244,9 +243,7 @@ endif() if (ENABLE_JEMALLOC) # The jemalloc subproject that all FEXCore fextl objects allocate through. - add_definitions(-DENABLE_JEMALLOC=1) add_subdirectory(External/jemalloc/) - include_directories(External/jemalloc/pregen/include/) elseif (NOT MINGW_BUILD) message (STATUS " jemalloc disabled!\n" diff --git a/FEXCore/Source/CMakeLists.txt b/FEXCore/Source/CMakeLists.txt index 3a56e03b8..3b33283c7 100644 --- a/FEXCore/Source/CMakeLists.txt +++ b/FEXCore/Source/CMakeLists.txt @@ -193,14 +193,6 @@ else() endif() endif() -if (ENABLE_JEMALLOC) - list (APPEND LIBS FEX_jemalloc) -endif() - -if (ENABLE_JEMALLOC_GLIBC_ALLOC) - list (APPEND LIBS FEX_jemalloc_glibc) -endif() - # Generate config configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Interface/Config/Config.json.in @@ -375,3 +367,25 @@ if (NOT MINGW_BUILD) DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Libraries) endif() + +# Meta-library to link jemalloc libraries enabled in the build configuration. +# Only needed for targets that run emulation. For others, use JemallocDummy. +add_library(JemallocLibs STATIC Utils/AllocatorHooks.cpp) +if (ENABLE_JEMALLOC) + target_compile_definitions(JemallocLibs PRIVATE ENABLE_JEMALLOC=1 JEMALLOC_NO_RENAME=1) + target_link_libraries(JemallocLibs PUBLIC FEX_jemalloc) +endif() +if (ENABLE_JEMALLOC_GLIBC_ALLOC) + set_source_files_properties(Interface/HLE/Thunks/Thunks.cpp PROPERTIES COMPILE_DEFINITIONS ENABLE_JEMALLOC_GLIBC=1) + target_link_libraries(JemallocLibs INTERFACE FEX_jemalloc_glibc) +endif() + +if (NOT MINGW_BUILD) + # Dummy project to use for host tools. + # This overrides use of jemalloc in FEXCore with the normal glibc allocator. + add_library(JemallocDummy STATIC Utils/AllocatorHooks.cpp) + target_include_directories(JemallocDummy PRIVATE "${PROJECT_SOURCE_DIR}/include/") +endif() + +# The shared library should always link enabled jemalloc libraries +target_link_libraries(${PROJECT_NAME}_shared JemallocLibs) diff --git a/FEXCore/Source/Utils/Allocator.cpp b/FEXCore/Source/Utils/Allocator.cpp index 2fb74d138..58311a374 100644 --- a/FEXCore/Source/Utils/Allocator.cpp +++ b/FEXCore/Source/Utils/Allocator.cpp @@ -19,24 +19,11 @@ #include #endif -#ifdef ENABLE_JEMALLOC -#include -#endif #include #include #include #include -extern "C" { -typedef void* (*mmap_hook_type)(void* addr, size_t length, int prot, int flags, int fd, off_t offset); -typedef int (*munmap_hook_type)(void* addr, size_t length); - -#ifdef ENABLE_JEMALLOC -extern mmap_hook_type je___mmap_hook; -extern munmap_hook_type je___munmap_hook; -#endif -} - namespace fextl::pmr { static fextl::pmr::default_resource FEXDefaultResource; std::pmr::memory_resource* get_default_resource() { @@ -127,19 +114,15 @@ void ReenableSBRKAllocations(void* Ptr) { #pragma GCC diagnostic ignored "-Wdeprecated-declarations" void SetupHooks() { Alloc64 = Alloc::OSAllocator::Create64BitAllocator(); -#ifdef ENABLE_JEMALLOC - je___mmap_hook = FEX_mmap; - je___munmap_hook = FEX_munmap; -#endif + SetJemallocMmapHook(FEX_mmap); + SetJemallocMunmapHook(FEX_munmap); FEXCore::Allocator::mmap = FEX_mmap; FEXCore::Allocator::munmap = FEX_munmap; } void ClearHooks() { -#ifdef ENABLE_JEMALLOC - je___mmap_hook = ::mmap; - je___munmap_hook = ::munmap; -#endif + SetJemallocMmapHook(::mmap); + SetJemallocMunmapHook(::munmap); FEXCore::Allocator::mmap = ::mmap; FEXCore::Allocator::munmap = ::munmap; diff --git a/FEXCore/Source/Utils/AllocatorHooks.cpp b/FEXCore/Source/Utils/AllocatorHooks.cpp new file mode 100644 index 000000000..60bfabf87 --- /dev/null +++ b/FEXCore/Source/Utils/AllocatorHooks.cpp @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +#ifdef ENABLE_JEMALLOC +#include +#endif + +#include +#include + +namespace FEXCore::Allocator { + +#ifndef _WIN32 +using mmap_hook_type = void* (*)(void* addr, size_t length, int prot, int flags, int fd, off_t offset); +using munmap_hook_type = int (*)(void* addr, size_t length); +#endif + +#ifdef ENABLE_JEMALLOC +void* malloc(size_t size) { + return ::je_malloc(size); +} +void* calloc(size_t n, size_t size) { + return ::je_calloc(n, size); +} +void* memalign(size_t align, size_t s) { + return ::je_memalign(align, s); +} +void* valloc(size_t size) { + return ::je_valloc(size); +} +int posix_memalign(void** r, size_t a, size_t s) { + return ::je_posix_memalign(r, a, s); +} +void* realloc(void* ptr, size_t size) { + return ::je_realloc(ptr, size); +} +void free(void* ptr) { + return ::je_free(ptr); +} +size_t malloc_usable_size(void* ptr) { + return ::je_malloc_usable_size(ptr); +} +void* aligned_alloc(size_t a, size_t s) { + return ::je_aligned_alloc(a, s); +} +void aligned_free(void* ptr) { + return ::je_free(ptr); +} + +#ifndef _WIN32 +extern "C" mmap_hook_type je___mmap_hook; +extern "C" munmap_hook_type je___munmap_hook; + +void SetJemallocMmapHook(mmap_hook_type Hook) { + je___mmap_hook = Hook; +} +void SetJemallocMunmapHook(munmap_hook_type Hook) { + je___munmap_hook = Hook; +} +#endif + +#elif defined(_WIN32) +#error "Tried building _WIN32 without jemalloc" + +#else +void* malloc(size_t size) { + return ::malloc(size); +} +void* calloc(size_t n, size_t size) { + return ::calloc(n, size); +} +void* memalign(size_t align, size_t s) { + return ::memalign(align, s); +} +void* valloc(size_t size) { + return ::valloc(size); +} +int posix_memalign(void** r, size_t a, size_t s) { + return ::posix_memalign(r, a, s); +} +void* realloc(void* ptr, size_t size) { + return ::realloc(ptr, size); +} +void free(void* ptr) { + return ::free(ptr); +} +size_t malloc_usable_size(void* ptr) { + return ::malloc_usable_size(ptr); +} +void* aligned_alloc(size_t a, size_t s) { + return ::aligned_alloc(a, s); +} +void aligned_free(void* ptr) { + return ::free(ptr); +} + +void SetJemallocMmapHook(mmap_hook_type) {} +void SetJemallocMunmapHook(munmap_hook_type) {} + +#endif +} // namespace FEXCore::Allocator diff --git a/FEXCore/include/FEXCore/Utils/AllocatorHooks.h b/FEXCore/include/FEXCore/Utils/AllocatorHooks.h index 58f28f826..e70f26224 100644 --- a/FEXCore/include/FEXCore/Utils/AllocatorHooks.h +++ b/FEXCore/include/FEXCore/Utils/AllocatorHooks.h @@ -4,16 +4,13 @@ #include #include -#ifndef ENABLE_JEMALLOC +#ifndef _WIN32 #include #include -#endif - -#ifdef _WIN32 +#include +#else #define NTDDI_VERSION 0x0A000005 #include -#else -#include #endif #include @@ -21,24 +18,6 @@ #include #include -extern "C" { -// jemalloc defines nothrow on its internal C function signatures. -#ifdef ENABLE_JEMALLOC -#define JEMALLOC_NOTHROW __attribute__((nothrow)) -// Forward declare jemalloc functions so we don't need to pull in the jemalloc header in to the public API. -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_malloc(size_t size); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_calloc(size_t n, size_t size); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_memalign(size_t align, size_t s); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_valloc(size_t size); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int je_posix_memalign(void** r, size_t a, size_t s); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_realloc(void* ptr, size_t size); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void je_free(void* ptr); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern size_t je_malloc_usable_size(void* ptr); -FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern void* je_aligned_alloc(size_t a, size_t s); -#undef JEMALLOC_NOTHROW -#endif -} - namespace FEXCore::Allocator { enum class ProtectOptions : uint32_t { None = 0, @@ -143,108 +122,23 @@ inline bool VirtualProtect(void* Ptr, size_t Size, ProtectOptions options) { #endif -// Memory allocation routines aliased to jemalloc functions. -#ifdef ENABLE_JEMALLOC -inline void* malloc(size_t size) { - return ::je_malloc(size); -} -inline void* calloc(size_t n, size_t size) { - return ::je_calloc(n, size); -} -inline void* memalign(size_t align, size_t s) { - return ::je_memalign(align, s); -} -inline void* valloc(size_t size) { - return ::je_valloc(size); -} -inline int posix_memalign(void** r, size_t a, size_t s) { - return ::je_posix_memalign(r, a, s); -} -inline void* realloc(void* ptr, size_t size) { - return ::je_realloc(ptr, size); -} -inline void free(void* ptr) { - return ::je_free(ptr); -} -inline size_t malloc_usable_size(void* ptr) { - return ::je_malloc_usable_size(ptr); -} -inline void* aligned_alloc(size_t a, size_t s) { - return ::je_aligned_alloc(a, s); -} -inline void aligned_free(void* ptr) { - return ::je_free(ptr); -} -#elif defined(_WIN32) -inline void* malloc(size_t size) { - return ::malloc(size); -} -inline void* calloc(size_t n, size_t size) { - return ::calloc(n, size); -} -inline void* memalign(size_t align, size_t s) { - return ::_aligned_malloc(s, align); -} -inline void* valloc(size_t size) { - return ::_aligned_malloc(size, 4096); -} -inline int posix_memalign(void** r, size_t a, size_t s) { - void* ptr = _aligned_malloc(s, a); - if (ptr) { - *r = ptr; - } - return errno; -} -inline void* realloc(void* ptr, size_t size) { - return ::realloc(ptr, size); -} -inline void free(void* ptr) { - return ::free(ptr); -} -inline size_t malloc_usable_size(void* ptr) { - return ::_msize(ptr); -} -inline void* aligned_alloc(size_t a, size_t s) { - return ::_aligned_malloc(s, a); -} -inline void aligned_free(void* ptr) { - return ::_aligned_free(ptr); -} -#else -inline void* malloc(size_t size) { - return ::malloc(size); -} -inline void* calloc(size_t n, size_t size) { - return ::calloc(n, size); -} -inline void* memalign(size_t align, size_t s) { - return ::memalign(align, s); -} -inline void* valloc(size_t size) { -#ifdef __ANDROID__ - return ::aligned_alloc(4096, size); -#else - return ::valloc(size); -#endif -} -inline int posix_memalign(void** r, size_t a, size_t s) { - return ::posix_memalign(r, a, s); -} -inline void* realloc(void* ptr, size_t size) { - return ::realloc(ptr, size); -} -inline void free(void* ptr) { - return ::free(ptr); -} -inline size_t malloc_usable_size(void* ptr) { - return ::malloc_usable_size(ptr); -} -inline void* aligned_alloc(size_t a, size_t s) { - return ::aligned_alloc(a, s); -} -inline void aligned_free(void* ptr) { - return ::free(ptr); -} +// Memory allocation routines to be defined externally. +// This allows to use jemalloc for emulation while using the normal allocator +// for host tools without building FEXCore twice. +void* malloc(size_t size); +void* calloc(size_t n, size_t size); +void* memalign(size_t align, size_t s); +void* valloc(size_t size); +int posix_memalign(void** r, size_t a, size_t s); +void* realloc(void* ptr, size_t size); +void free(void* ptr); +size_t malloc_usable_size(void* ptr); +void* aligned_alloc(size_t a, size_t s); +void aligned_free(void* ptr); + +#ifndef _WIN32 +void SetJemallocMmapHook(void* (*)(void* addr, size_t length, int prot, int flags, int fd, off_t offset)); +void SetJemallocMunmapHook(int (*)(void* addr, size_t length)); #endif struct FEXAllocOperators { diff --git a/FEXCore/unittests/APITests/CMakeLists.txt b/FEXCore/unittests/APITests/CMakeLists.txt index 52ffd0509..d6a670e21 100644 --- a/FEXCore/unittests/APITests/CMakeLists.txt +++ b/FEXCore/unittests/APITests/CMakeLists.txt @@ -1,6 +1,6 @@ file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS *.cpp) -set (LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base) +set (LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs) foreach(TEST ${TESTS}) get_filename_component(TEST_NAME ${TEST} NAME_WLE) add_executable(FEXCore_Tests_${TEST_NAME} ${TEST}) diff --git a/FEXCore/unittests/Emitter/CMakeLists.txt b/FEXCore/unittests/Emitter/CMakeLists.txt index 408c4b5fb..164cc62fb 100644 --- a/FEXCore/unittests/Emitter/CMakeLists.txt +++ b/FEXCore/unittests/Emitter/CMakeLists.txt @@ -1,7 +1,7 @@ if (COMPILE_VIXL_DISASSEMBLER) file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS *.cpp) - set (LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base) + set (LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs) foreach(TEST ${TESTS}) get_filename_component(TEST_NAME ${TEST} NAME_WLE) add_executable(Emitter_${TEST_NAME} ${TEST}) diff --git a/Source/Tools/CodeSizeValidation/CMakeLists.txt b/Source/Tools/CodeSizeValidation/CMakeLists.txt index 9f1ef665c..dd5158b56 100644 --- a/Source/Tools/CodeSizeValidation/CMakeLists.txt +++ b/Source/Tools/CodeSizeValidation/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND LIBS FEXCore Common CommonTools) +list(APPEND LIBS FEXCore Common CommonTools JemallocLibs) set (SRCS Main.cpp) add_executable(CodeSizeValidation ${SRCS}) diff --git a/Source/Tools/FEXBash/CMakeLists.txt b/Source/Tools/FEXBash/CMakeLists.txt index a07e78e15..389a08ffe 100644 --- a/Source/Tools/FEXBash/CMakeLists.txt +++ b/Source/Tools/FEXBash/CMakeLists.txt @@ -9,6 +9,7 @@ target_link_libraries(FEXBash PRIVATE FEXCore Common + JemallocLibs LinuxEmulation ${PTHREAD_LIB} ) diff --git a/Source/Tools/FEXConfig/CMakeLists.txt b/Source/Tools/FEXConfig/CMakeLists.txt index 145a01634..01c920767 100644 --- a/Source/Tools/FEXConfig/CMakeLists.txt +++ b/Source/Tools/FEXConfig/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_AUTOMOC ON) add_executable(FEXConfig) target_sources(FEXConfig PRIVATE Main.cpp Main.h) target_include_directories(FEXConfig PRIVATE ${CMAKE_SOURCE_DIR}/Source/) -target_link_libraries(FEXConfig PRIVATE Common) +target_link_libraries(FEXConfig PRIVATE Common JemallocDummy) if (Qt6_FOUND) qt_add_resources(QT_RESOURCES qml6.qrc) target_link_libraries(FEXConfig PRIVATE Qt6::Qml Qt6::Quick Qt6::Widgets) diff --git a/Source/Tools/FEXGetConfig/CMakeLists.txt b/Source/Tools/FEXGetConfig/CMakeLists.txt index c858bd956..6a35649dd 100644 --- a/Source/Tools/FEXGetConfig/CMakeLists.txt +++ b/Source/Tools/FEXGetConfig/CMakeLists.txt @@ -3,7 +3,7 @@ set(SRCS Main.cpp) add_executable(${NAME} ${SRCS}) -list(APPEND LIBS Common) +list(APPEND LIBS Common JemallocDummy) if (CMAKE_BUILD_TYPE MATCHES "RELEASE") target_link_options(${NAME} diff --git a/Source/Tools/FEXLoader/CMakeLists.txt b/Source/Tools/FEXLoader/CMakeLists.txt index 8d5a0805f..5715c7b09 100644 --- a/Source/Tools/FEXLoader/CMakeLists.txt +++ b/Source/Tools/FEXLoader/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND LIBS FEXCore Common) +list(APPEND LIBS FEXCore Common JemallocLibs) set (DEFINES) if (ENABLE_VIXL_SIMULATOR) diff --git a/Source/Tools/FEXRootFSFetcher/CMakeLists.txt b/Source/Tools/FEXRootFSFetcher/CMakeLists.txt index 69fdf8418..20446ccc0 100644 --- a/Source/Tools/FEXRootFSFetcher/CMakeLists.txt +++ b/Source/Tools/FEXRootFSFetcher/CMakeLists.txt @@ -3,7 +3,7 @@ set(SRCS Main.cpp XXFileHash.cpp) add_executable(${NAME} ${SRCS}) -list(APPEND LIBS FEXCore Common xxHash::xxhash) +list(APPEND LIBS FEXCore Common JemallocDummy xxHash::xxhash) target_include_directories(${NAME} PRIVATE ${CMAKE_SOURCE_DIR}/Source/) diff --git a/Source/Tools/FEXServer/CMakeLists.txt b/Source/Tools/FEXServer/CMakeLists.txt index 1190618d1..dc3e8de13 100644 --- a/Source/Tools/FEXServer/CMakeLists.txt +++ b/Source/Tools/FEXServer/CMakeLists.txt @@ -12,7 +12,7 @@ target_include_directories(${NAME} PRIVATE ${CMAKE_BINARY_DIR}/generated ${CMAKE_SOURCE_DIR}/Source/) -target_link_libraries(${NAME} PRIVATE FEXCore Common ${PTHREAD_LIB}) +target_link_libraries(${NAME} PRIVATE FEXCore Common JemallocDummy ${PTHREAD_LIB}) if (CMAKE_BUILD_TYPE MATCHES "RELEASE") target_link_options(${NAME} diff --git a/Source/Tools/TestHarnessRunner/CMakeLists.txt b/Source/Tools/TestHarnessRunner/CMakeLists.txt index da29e6e80..a2f82848c 100644 --- a/Source/Tools/TestHarnessRunner/CMakeLists.txt +++ b/Source/Tools/TestHarnessRunner/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND LIBS FEXCore Common) +list(APPEND LIBS FEXCore Common JemallocLibs) set (SRCS TestHarnessRunner.cpp) if (NOT MINGW_BUILD) diff --git a/Source/Tools/pidof/CMakeLists.txt b/Source/Tools/pidof/CMakeLists.txt index 8a5f79426..6c68725de 100644 --- a/Source/Tools/pidof/CMakeLists.txt +++ b/Source/Tools/pidof/CMakeLists.txt @@ -6,6 +6,7 @@ target_include_directories(FEXpidof target_link_libraries(FEXpidof PRIVATE cpp-optparse + JemallocDummy fmt::fmt ) diff --git a/Source/Windows/Common/CMakeLists.txt b/Source/Windows/Common/CMakeLists.txt index 6c2026a34..8d92d8f18 100644 --- a/Source/Windows/Common/CMakeLists.txt +++ b/Source/Windows/Common/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(CommonWindows STATIC CPUFeatures.cpp InvalidationTracker.cpp Logging.cpp LoadConfig.S) add_subdirectory(CRT) add_subdirectory(WinAPI) -target_link_libraries(CommonWindows FEXCore_Base) +target_link_libraries(CommonWindows FEXCore_Base JemallocLibs) target_compile_options(CommonWindows PRIVATE -Wno-inconsistent-dllimport) target_include_directories(CommonWindows PRIVATE "${CMAKE_SOURCE_DIR}/Source/Windows/include/" diff --git a/unittests/APITests/CMakeLists.txt b/unittests/APITests/CMakeLists.txt index 4a56cd5b3..23cf1077d 100644 --- a/unittests/APITests/CMakeLists.txt +++ b/unittests/APITests/CMakeLists.txt @@ -4,7 +4,7 @@ set (TESTS Filesystem ) -list(APPEND LIBS FEXCore) +list(APPEND LIBS FEXCore JemallocLibs) foreach(API_TEST ${TESTS}) add_executable(${API_TEST} ${API_TEST}.cpp)