diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..d42f217 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,10 @@ +ignore: + - "autohbw/.*" + - "examples/autohbw*" + - "examples/*example*" + - "examples/memkind*" + - "test/.*" +comment: + layout: "diff" + behaviour: default + require_changes: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b581c84 --- /dev/null +++ b/.gitignore @@ -0,0 +1,126 @@ +*.a +*.la +*.lo +*.o +*.so +.cproject +.deps/ +.dirstamp +.libs/ +.project +/Makefile +/Makefile.in +/VERSION +/aclocal.m4 +/ar-lib +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.status +/config.sub +/config_tls.h +/configure +/depcomp +/examples/*.la +/examples/*.lo +/examples/*.o +/examples/.deps/ +/examples/.dirstamp +/examples/.libs/ +/examples/autohbw_candidates +/examples/filter_memkind +/examples/hello_hbw +/examples/hello_memkind +/examples/hello_memkind_debug +/examples/memkind_allocated +/examples/memkind_cpp_allocator +/examples/memkind_get_stat +/examples/pmem_alignment +/examples/pmem_and_dax_kmem_kind +/examples/pmem_and_default_kind +/examples/pmem_config +/examples/pmem_cpp_allocator +/examples/pmem_detect_kind +/examples/pmem_free_with_unknown_kind +/examples/pmem_kinds +/examples/pmem_malloc +/examples/pmem_malloc_unlimited +/examples/pmem_multithreads +/examples/pmem_multithreads_onekind +/examples/pmem_usable_size +/install-sh +/jemalloc/configure +/jemalloc/obj/ +/libtool +/ltmain.sh +/m4/ +/memkind-*.spec +/memkind-*.tar.gz +/memkind-auto-dax-kmem-nodes +/memkind-hbw-nodes +/missing +/src/memkind_defines.h.in +/stamp-h1 +/stamp-h2 +/test-driver +/test-suite.log +/test/*.o +/test/*.pyc +/test/*.so +/test/.deps/ +/test/.dirstamp +/test/.libs/ +/test/all_tests +/test/alloc_benchmark_glibc +/test/alloc_benchmark_hbw +/test/alloc_benchmark_pmem +/test/alloc_benchmark_tbb +/test/allocator_perf_tool_tests +/test/autohbw_candidates +/test/autohbw_test_helper +/test/check.sh.log +/test/check.sh.trs +/test/dax_kmem_test +/test/decorator_test +/test/environ_err_dax_kmem_malloc_positive_test +/test/environ_err_dax_kmem_malloc_test +/test/environ_err_hbw_malloc_test +/test/environerr_hbw_malloc_test +/test/environerr_test +/test/filter_memkind +/test/fragmentation_benchmark_pmem +/test/freeing_memory_segfault_test +/test/gb_page_tests_bind_policy +/test/hello_hbw +/test/hello_memkind +/test/hello_memkind_debug +/test/locality_test +/test/mallocerr_test +/test/memkind_allocated +/test/memkind_cpp_allocator +/test/memkind_get_stat +/test/memkind_stat_test +/test/perf_tool +/test/performance_test +/test/performance/.deps/ +/test/pmem_alignment +/test/pmem_and_dax_kmem_kind +/test/pmem_and_default_kind +/test/pmem_config +/test/pmem_cpp_allocator +/test/pmem_detect_kind +/test/pmem_free_with_unknown_kind +/test/pmem_kinds +/test/pmem_malloc +/test/pmem_malloc_unlimited +/test/pmem_multithreads +/test/pmem_multithreads_onekind +/test/pmem_test +/test/pmem_usable_size +/test/trace_mechanism_test_helper +/test/defrag_reallocate +/vs +autom4te.cache/ +memkind.pc diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3899848 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,65 @@ +dist: bionic +sudo: required +language: cpp +cache: ccache +git: + depth: false +matrix: + fast_finish: true + include: + + - name: "Astyle" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - astyle + script: + - ./astyle.sh + + - name: "GCC 4.8" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 + - libnuma-dev + env: + - MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8" + install: + script: + - ./build.sh + + - name: "GCC 8.0" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-8 + - libnuma-dev + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + install: + script: + - ./build.sh + + - name: "Clang 8" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-bionic-8 + packages: + - clang-8 + - libnuma-dev + env: + - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" + install: + script: + - ./build.sh + +before_install: + - eval "${MATRIX_EVAL}" diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ea4ca98 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,26 @@ +Christopher Cantalupo +Vishwanath Venkatesan +Steven Hampson +Krzysztof Czurylo +Leobardo Rountree +Hector Barajas Villalobos +Ruchira Sasanka +Krzysztof Kulakowski +Rafael Aquini +Alexandr Konovalov +Grzegorz Ozanski +Artur Koziej +Jakub Dlugolecki +Lukasz Anaczkowski +Agata Wozniak +Grzegorz Andrejczuk +Kamil Patelczyk +Jeff Hammond +Aleksandra Hernik +Pawel Kochanek +Katarzyna Wasiuta +Krzysztof Filipek +Michal Biesek +Adam Borowski +Yuan Zhou +Harald Servat diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 0000000..ca0039b --- /dev/null +++ b/CONTRIBUTING @@ -0,0 +1,134 @@ +CONTRIBUTING +============ + +This file is intended to help those interested in contributing to the +memkind library. + + +COMMUNICATION +============= + +Please participate in the memkind mailing list: + + https://lists.01.org/mailman/listinfo/memkind + +There is also the option of opening an issue through github: + + https://github.com/memkind/memkind/issues + +The mailing list is intended for discussion and the issues are useful +for tracking progress on tasks. The TODO file lists out a number of +topics, and in order to prioritize one of them please open a github +issue with a related subject. + + +TESTING +======= + +The tests require a Linux kernel newer than 3.11 (the details are +documented in the memkind README), and the reservation of 3000 huge +pages. The huge pages can be reserved with the following command: + + $ sudo echo 3000 > /proc/sys/vm/nr_hugepages + +Only in the case where gigabyte pages have been reserved will the +tests associated with gigabyte pages be executed. Reserving gigabyte +pages may require a modification to the kernel command line unless the +kernel is quite recent. + +To test memkind simply execute the "make check" target after building. +This target calls memkind/test/test.sh with parameters +depending on the environment. + +Most of the tests are written within the gtest framework, however, as +part of testing the example programs are also executed and the return +code of the executable determines pass or fail. The autotools test +infrastructure is used as a high level executor, but it does not track +individual tests. The consequence of this is that the autotools +output records only one high level test which passes in the case where +every underlying test was successful and fails if any underlying test +fails. The individual test results are recorded in the directory +called "gtest_output." Here you will find the log of the tests in +gtest_output/test.out and a set of junit style xml results: one for +each test. Note that a side effect of having only one autotools test +is that autotools parallel testing is disabled. We have +multi-threaded tests that use the OpenMP run-time which enables more +purposeful and deterministic testing of threading issues. Note that +the OpenMP run-time is only required for testing, it is not used by +the memkind library internally. + + +CODING STYLE +============ + +Before submitting a patch for inclusion, please run the modified +source code files through astyle with the following options + + $ astyle --style=linux --indent=spaces=4 -S --max-continuation-indent=80 \ + --max-code-length=80 --break-after-logical --indent-namespaces -z2 \ + --align-pointer=name + +More information about astyle can be found here: + + http://astyle.sourceforge.net/ + +In C, source code constants are in all caps and everything else is in +all lower case. Underscores are used to separate words within a +symbol name. No camel case shall be used in C code. The test code is +largely written in C++. Here camel-case should be used for class +names and should always have a capitalized first letter. Other +symbols in C++ should generally follow the C style. + +Most symbols with global scope shall be prefixed with "memkind_" or +"hbw_" depending on which interface they are a part of. + +Any global variable shall have _g appended to the variable name and in +most cases shall be statically scoped within a single compilation +unit. The exception to that rule are static memory kinds that are +declared as extern within the associated interface header and are +constant after initialization. Global variables should be used in a +very narrow set of circumstances and in most cases modifications +should be guarded with pthread_once(3). + +Functions not used outside of the compilation unit shall be declared +as static. All functions which are not declared as static shall be +documented in a man page and have an associated interface header file. + +Preprocessor mark-up is discouraged when other options are possible. +Please use enum in place of #define when value control at configure or +build time is not required. + + +TESTS +===== + +The current state of the tests is not nearly as well organized as it +could be. That being said, it is quite simple to add a new test. +Most C++ files in the test directory are associated with a single +gtest testing::Test class. These classes usually have several +associated test fixtures in the same file. If a new test can be added +as a fixture to an existing class, simply add the fixture to the file +and the test will be incorporated into the test infrastructure. +If a new class is required, create a new file and add it to the list +of "test_all_tests_SOURCES" in memkind/test/Makfile.mk and it will +be incorporated into the test infrastructure. + +There are a few files which define classes which are not google test +classes. These are check.cpp, trial_generator.cpp and main.cpp. The +check.cpp file defines a class Check that can be used to validate +fundamental memkind features like NUMA node location, and page size. +The trial_generator.cpp file is used to abstract a sequence of +allocation and deallocation calls while performing checks on the +results of each call; this can be used to apply similar tests to all +of the different allocation APIs. The main.cpp file is a simple +wrapper around testing::InitGoogleTest and RUN_ALL_TESTS(). + + +SUBMITTING A PATCH +================== + +Please be sure that all tests pass before submission and that the +style conforms to the specifications given here. If a new feature is +implemented in the patch, please also include unit tests and an +example which exercises this feature. Once these requirements have +been met, please submit a pull request through github. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..cc1c9cc --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Unless otherwise specified, files in the memkind source distribution are +subject to the following license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..d887e18 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,242 @@ +* Mon Dec 16 2019 Michal Biesek v1.10.0 +- Provided another way to use Persistent Memory in memkind (MEMKIND_DAX_KMEM_* kinds) +- Added C++ allocator for static kinds (including MEMKIND_DAX_KMEM_* kinds) +- Provided an interface to get memkind allocation statistics +- Provided a method to reduce fragmentation - memkind_defrag_reallocate() +- Added support for background thread +- Updated internally used jemalloc to upstream version 5.2.1 +- Extended hbw interface with hbw_malloc_usable_size() +- Simplified building process + +* Wed Apr 3 2019 Michal Biesek v1.9.0 +- Provided a second function to create PMEM kind memkind_create_pmem_with_config() +- Provided the memkind_detect_kind() function to recognize a kind from memory allocation +- Provided memkind_config_set_memory_usage_policy() function + that modifies the default memory usage policy behavior +- Provided the ability to pass a NULL kind to memkind_malloc_usable_size() and memkind_realloc() +- Unified the memkind_realloc() behavior for all kinds +- Added the support for the pool_msize() function to TBB +- Extended build arch to ppc64, ppc64le, s390x +- Removed disable-stats from used jemalloc +- Fixed compilation under the Clang and rpm build configuration +- Provided the support for Dockerfile + +* Mon Dec 10 2018 Michal Biesek v1.8.0 +- Fixed error with realloc/free method with passing thread-specific cache flag +- Fixed error with memkind_create_pmem(), if other PMEM kind was destroyed before +- Fixed error with zeroing large allocations in PMEM kind +- Added support to create kind without maximum size limit of PMEM kind (max_size=0) +- Extended memkind API with memkind_malloc_usable_size() +- Removed EXPERIMENTAL from most methods in memkind API +- Added MEMKIND_ERROR_ARENAS_CREATE code +- Added C++ allocator for PMEM kind +- Extended PMEM examples +- Fixed integration with Travis CI +- Extended Travis CI configuration with Astyle and Coverage +- Added PMEM kind tests + +* Wed Jan 24 2018 Pawel Kochanek v1.7.0 +- Updated internally used jemalloc to upstream version 5.0. +- Fixed error that has been occurring while memkind was dynamically loaded. +- Fixed MEMKIND_HBW_NODES behavior for single NUMA node system. +- Removed licenses other than BSD 3-clause from COPYING. +- Changed build instructions. +- Added configurable jemalloc prefix in build scripts. +- Upgraded gtest to version 1.8.0. +- Added memory footprint tests. +- Added locality test for MEMKIND_PREFERRED. +- Applied test parametrization in BATests. +- Fixed problems with pytest testing in Travis. +- Added huge page configuration in several tests. +- Removed several symbols that are no longer exposed in public API from man pages. +- Fixed HBW_POLICY_BIND_ALL documentation. + +* Tue Jun 13 2017 Artur Koziej v1.6.0 +- Introduced new policy HBW_POLICY_BIND_ALL. +- Introduced MEMKIND_HBW_ALL, MEMKIND_HBW_ALL_HUGETLB and MEMKIND_REGULAR kinds. +- Fixed hbw_posix_memalign_psize() return value in case of unsupported policy and + page size combination. +- Documented supported policy and page size combination for + hbw_posix_memalign_psize(). +- Merged libmemkind.a and libjemalloc_pic.a into a single static library. +- Fixed OOM during tcache acquisition. +- Tuned huge pages configuration in memkind tests. +- Added stress tests for allocations with large random sizes. +- Added stress tests for allocations with random kinds. +- Extended policy and NUMA node binding tests. +- Fixed several Travis build problems. +- Removed gb_page_tests_preferred_policy tests. + +* Tue Feb 21 2017 Krzysztof Kulakowski v1.5.0 +- Intel(R) TBB scalable_allocator can be used as heap management alternative + to jemalloc (requires installed Intel (R) TBB package and environment variable + MEMKIND_HEAP_MANAGER=TBB) +- Updated internally used jemalloc to upstream version 4.3.1 (previously modified 3.5.1) +- Introduced new environment option MEMKIND_HOG_MEMORY. Setting it to "1" will prevent + memkind from releasing memory to OS. +- Introduced support for KNM processor from Intel(R) Xeon Phi(TM) family +- General cleanup of build scripts (e.g. fixed issues found on Ubuntu, + introduced simple build.sh script) +- Deprecated support for gigabyte-pages +- Removed number of previously deprecated symbols + +* Thu Nov 17 2016 Krzysztof Kulakowski v1.4.0 +- Introduced hbw_verify_memory_region() for verifying if provided memory + region fully falls into high-bandwidth memory (for details please take a look + at man/hbwmalloc.3). +- New API for creating kinds using set of predefined attributes: + memkind_create_kind(), memkind_destroy_kind() (for details please take a look + at man/memkind.3). +- Fixed issue in autohbw where it was reporting limit error regardless of + value provided. +- Added logging on error paths. +- Test base fixes and improvements. + +* Tue Sep 27 2016 Krzysztof Kulakowski v1.3.0 +- Introduced logging mechanism (for details please take a look at + man/memkind.3). +- Deprecated symbols: memkind_finalize(), memkind_get_num_kind(), + memkind_get_kind_by_partition(), memkind_get_kind_by_name(), + memkind_partition_mmap(), memkind_get_size(), MEMKIND_ERROR_MEMALIGN, + MEMKIND_ERROR_MALLCTL, MEMKIND_ERROR_GETCPU, MEMKIND_ERROR_PMTT, + MEMKIND_ERROR_TIEDISTANCE, MEMKIND_ERROR_ALIGNMENT, MEMKIND_ERROR_MALLOCX, + MEMKIND_ERROR_REPNAME, MEMKIND_ERROR_PTHREAD, MEMKIND_ERROR_BADPOLICY, + MEMKIND_ERROR_REPPOLICY. +- Added integration with hwloc (turned on with --with-hwloc). +- Cleanup of symbols exposed by libmemkind.so (e.g. no longer exposing libnuma + and jemalloc symbols). +- AutoHBW files have been moved to "memkind/autohbw" directory, code has + been refactored and tests have been added to appropriate scenarios. +- Library is now built with flags improving security (can be turned off + with --disable-secure configure time option). +- Changed configuration of jemalloc to turn off unused features. + +* Thu Aug 18 2016 Krzysztof Kulakowski v1.2.0 +- memkind_create() and memkind_ops have been deprecated (moved to + memkind_deprecated.h). +- Deprecated the headers from memkind/internal and added compile-time + warnings to them (plan is to remove those from rpm packages). +- autohbw files have been moved to memkind/autohbw directory. +- API decorators (memkind_malloc_pre, memkind_malloc_post etc.) now + need to be enabled with configure-time option --enable-decorators. +- Allocation time optimizations with up to 20% improvement. + +* Wed Jul 13 2016 Krzysztof Kulakowski v1.1.1 +- Performance improvement for memkind_free() in scenario where NULL + was passed as kind (reduced by 60%). +- Introduced integration with Travis CI. +- Fixed issue where memory returned from calloc was not filled with zeroes + when using memkind_pmem kinds. +- Fixed issue where interleave kinds was failing on systems without + Transparent Huge Pages module configured. +- Resolved several issues that was causing compilation errors on some systems. +- test/test.sh is now able to detect system configuration, and run only those + tests which requirements are meet. +- Added gtest to repo to avoid downloading it during build proecess. + +* Mon May 23 2016 Krzysztof Kulakowski v1.1.0 +- Implemented algorithm for detecting high-bandwidth memory on Intel Xeon Phi X200 + without parsing PMTT. +- PMTT-parsing service has been removed. +- memkind struct definition from memkind.h has been replaced by forward + declaration. Definition has been moved to /internal/memkind_private.h and + shouldn't be considered as part of library interface anymore. +- Performance improvement for hugetlb kinds (check_available() is no longer + parsing sysfs every time). +- Performance fix by removing --enable-safe from jemmaloc build flags. +- New tests for validating high-bandwidth memory detection has been added. +- AFTS has been split into two groups: memkind-afts.ts and memkind-afts-ext.ts, + based on amount of required memory (for details view test/README). + +* Thu Mar 03 2016 Artur Koziej v1.0.0 +- hbwmalloc.h released as stable API. +- Introduce API standards: STANDARD API, NON-STANDARD API, EXPERIMENTAL API. +- Introduce memkind versioning API. +- Fix type names in hbwmalloc API. +- Change error codes to POSIX standard ones in hbwmalloc API. +- Move API headers to include directory. +- Move NON-STANDARD API, or EXPERIMENTAL API to include/memkind/internal directory. +- New man page (memkind_interleave.3) describing interleave kind. +- Significant documentation improvement. +- Performance fix for jemalloc - significantly decrease of library initialization time. +- Enforce 2MB alignment in jemalloc due to the Linux kernel bug (munmap() fails for + huge pages, when the size is not aligned). +- Move to systemd defined service (memkind.service), drop init.d script. +- New rpm layout (memkind and memkind-devel). +- Remove false dependency on OpenMP. +- Extend test base for stress, longevity and initialization performance tests. +- Fix memory leak in ctl_growk(). +- Rename namespace: hbwmalloc -> hbw. +- Rename class: hbwmalloc_allocator -> allocator. + +* Thu Oct 15 2015 Krzysztof Kulakowski v0.3.0 +- Added two new kinds: MEMKIND_INTERLEAVE and MEMKIND_HBW_INTERLEAVE + (for details please take a look at man/memkind.3) +- Added support for file-backed memory heaps + (for details please take a look at man/memkind_pmem.3) +- Added autohbw library, that intercepts the standard heap allocations, + which let use high-bandwidth memory without modifying existing codebase + (for details please take a look at examples/autohbw_README) +- jemalloc is now, statically linked, internal component of memkind RPM + instead of rpm dependency. +- Added memkind_allocated example which demonstrates usage of memkind + with alignas() alignment specifier introduced in C++11 + (for details please take a look at examples/README) +- Added support for using thread local storage to improve performance in + multithreaded applications (enabled by configure time option: --enable-tls) +- Added possibility to set number of jemalloc arenas per kind by + configure time parameter or environmental variable + (for details please take a look at MEMKIND_ARENA_NUM_PER_KIND section + of man/memkind.3). +- Added decorators to the memkind allocation APIs. + These are weak symbols (pre and post for each API) which can modify + the input and output of each of the calls. +- Significantly extended test base (new groups of tests: performance, + multithreaded, PMTT, nagtive, stress). + +* Fri Jan 9 2015 Christopher Cantalupo v0.2.0 +- Bumped memkind ABI version to 0:1:0. +- Removed memkind_get_kind_for_free() from externally facing API's. Instead if + memkind_free() is called with zero passed for the kind then + memkind_get_kind_for_free() is called internally. +- Moved to single callback memkind_partition_mmap() to simplify + jemalloc modifications. +- Added hooks for setting file descriptor and offset for mmap enabling + file-backed memory kinds. +- Added a void pointer called "priv" to memkind structure for storing data for + user-defined kinds. +- Removed call to sched_getcpu(), now thread id is hashed to determine the arena + index. +- Added weak symbol hooks for decorating the heap management functions. +- Fixed several issues with init.d/memkind script and spec file scriptlets that + are exposed by SLES-12. +- Introduced an example library called numakind. + The numakind library will allocate from the closest NUMA node to a thread as + measured when that thread makes its first allocation call. +- Fixed error handling in memkind_gbtlb_mmap() that could cause a segfault when + gigabyte pages are not available. +- Added tests for PMTT parser. +- Removed binary mock PMTT table from source code, replaced it with a hexdump. +- Fixed a number of issues in test scripts which were suppressing errors. +- Removed unnecessary includes from header files. +- Better error checking in example code. +- Documentation update and clean up. + +* Thu Nov 13 2014 Christopher Cantalupo v0.1.0 +- Increased test code coverage significantly. +- Fixed bug in memkind_error_message() for MEMKIND_ERROR_TOOMANY. +- Removed memkind_arena_free() API since it was redundant with memkind_default_free(). +- Static memkind structs are now declared as extern in the headers and defined in the + source files files rather than being statically defined in the headers. + +* Thu Oct 30 2014 Christopher Cantalupo v0.0.9 +- Now building with autotools. +- Updated documentation. +- Fixed typo in copyright. +- Fixed test scripts to properly handle return code of each test. +- Added C++03 standard allocator that uses hbw_malloc and hbw_free. +* Tue Sep 30 2014 Christopher Cantalupo v0.0.8 +- Added GBTLB functionality, code clean up, documentation updates, + examples directory. Examples includes stream modified to use + memkind interface. Code coverage still lacking, and documentation + incomplete. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..f5aa3e4 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,552 @@ +.codecov.yml +.travis.yml +AUTHORS +CONTRIBUTING +COPYING +ChangeLog +Makefile.am +NEWS +PULL_REQUEST_TEMPLATE.md +README +astyle.sh +autogen.sh +autohbw/Makefile.mk +autohbw/autohbw.c +autohbw/autohbw_README +autohbw/autohbw_get_src_lines.pl +autohbw/autohbw_test.sh +build.sh +configure.ac +examples/Makefile.mk +examples/README +examples/autohbw_candidates.c +examples/filter_example.c +examples/hello_hbw_example.c +examples/hello_memkind_example.c +examples/memkind_allocated.hpp +examples/memkind_allocated_example.cpp +examples/memkind_cpp_allocator.cpp +examples/memkind_decorator_debug.c +examples/memkind_get_stat.c +examples/pmem_alignment.c +examples/pmem_and_default_kind.c +examples/pmem_and_dax_kmem.c +examples/pmem_config.c +examples/pmem_cpp_allocator.cpp +examples/pmem_detect_kind.c +examples/pmem_free_with_unknown_kind.c +examples/pmem_kinds.c +examples/pmem_malloc.c +examples/pmem_malloc_unlimited.c +examples/pmem_multithreads.c +examples/pmem_multithreads_onekind.c +examples/pmem_usable_size.c +include/hbw_allocator.h +include/hbwmalloc.h +include/memkind.h +include/memkind/internal/heap_manager.h +include/memkind/internal/memkind_arena.h +include/memkind/internal/memkind_bandwidth.h +include/memkind/internal/memkind_dax_kmem.h +include/memkind/internal/memkind_default.h +include/memkind/internal/memkind_gbtlb.h +include/memkind/internal/memkind_hbw.h +include/memkind/internal/memkind_hugetlb.h +include/memkind/internal/memkind_interleave.h +include/memkind/internal/memkind_log.h +include/memkind/internal/memkind_pmem.h +include/memkind/internal/memkind_private.h +include/memkind/internal/memkind_regular.h +include/memkind/internal/tbb_mem_pool_policy.h +include/memkind/internal/tbb_wrapper.h +include/memkind/internal/vec.h +include/memkind_allocator.h +include/memkind_deprecated.h +include/pmem_allocator.h +install_astyle.sh +jemalloc/.appveyor.yml +jemalloc/.autom4te.cfg +jemalloc/.gitattributes +jemalloc/.gitignore +jemalloc/.travis.yml +jemalloc/autogen.sh +jemalloc/bin/jemalloc-config.in +jemalloc/bin/jemalloc.sh.in +jemalloc/bin/jeprof.in +jemalloc/build-aux/config.guess +jemalloc/build-aux/config.sub +jemalloc/build-aux/install-sh +jemalloc/ChangeLog +jemalloc/config.stamp.in +jemalloc/configure.ac +jemalloc/COPYING +jemalloc/doc/html.xsl.in +jemalloc/doc/jemalloc.xml.in +jemalloc/doc/manpages.xsl.in +jemalloc/doc/stylesheet.xsl +jemalloc/include/jemalloc/internal/arena_externs.h +jemalloc/include/jemalloc/internal/arena_inlines_a.h +jemalloc/include/jemalloc/internal/arena_inlines_b.h +jemalloc/include/jemalloc/internal/arena_stats.h +jemalloc/include/jemalloc/internal/arena_structs_a.h +jemalloc/include/jemalloc/internal/arena_structs_b.h +jemalloc/include/jemalloc/internal/arena_types.h +jemalloc/include/jemalloc/internal/assert.h +jemalloc/include/jemalloc/internal/atomic.h +jemalloc/include/jemalloc/internal/atomic_c11.h +jemalloc/include/jemalloc/internal/atomic_gcc_atomic.h +jemalloc/include/jemalloc/internal/atomic_gcc_sync.h +jemalloc/include/jemalloc/internal/atomic_msvc.h +jemalloc/include/jemalloc/internal/background_thread_externs.h +jemalloc/include/jemalloc/internal/background_thread_inlines.h +jemalloc/include/jemalloc/internal/background_thread_structs.h +jemalloc/include/jemalloc/internal/base_externs.h +jemalloc/include/jemalloc/internal/base_inlines.h +jemalloc/include/jemalloc/internal/base_structs.h +jemalloc/include/jemalloc/internal/base_types.h +jemalloc/include/jemalloc/internal/bin.h +jemalloc/include/jemalloc/internal/bin_stats.h +jemalloc/include/jemalloc/internal/bin_types.h +jemalloc/include/jemalloc/internal/bitmap.h +jemalloc/include/jemalloc/internal/bit_util.h +jemalloc/include/jemalloc/internal/cache_bin.h +jemalloc/include/jemalloc/internal/ckh.h +jemalloc/include/jemalloc/internal/ctl.h +jemalloc/include/jemalloc/internal/div.h +jemalloc/include/jemalloc/internal/emitter.h +jemalloc/include/jemalloc/internal/extent_dss.h +jemalloc/include/jemalloc/internal/extent_externs.h +jemalloc/include/jemalloc/internal/extent_inlines.h +jemalloc/include/jemalloc/internal/extent_mmap.h +jemalloc/include/jemalloc/internal/extent_structs.h +jemalloc/include/jemalloc/internal/extent_types.h +jemalloc/include/jemalloc/internal/hash.h +jemalloc/include/jemalloc/internal/hook.h +jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h +jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in +jemalloc/include/jemalloc/internal/jemalloc_internal_externs.h +jemalloc/include/jemalloc/internal/jemalloc_internal_includes.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_a.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_b.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_c.h +jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h +jemalloc/include/jemalloc/internal/jemalloc_internal_types.h +jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in +jemalloc/include/jemalloc/internal/large_externs.h +jemalloc/include/jemalloc/internal/log.h +jemalloc/include/jemalloc/internal/malloc_io.h +jemalloc/include/jemalloc/internal/mutex.h +jemalloc/include/jemalloc/internal/mutex_pool.h +jemalloc/include/jemalloc/internal/mutex_prof.h +jemalloc/include/jemalloc/internal/nstime.h +jemalloc/include/jemalloc/internal/pages.h +jemalloc/include/jemalloc/internal/ph.h +jemalloc/include/jemalloc/internal/private_namespace.sh +jemalloc/include/jemalloc/internal/private_symbols.sh +jemalloc/include/jemalloc/internal/prng.h +jemalloc/include/jemalloc/internal/prof_externs.h +jemalloc/include/jemalloc/internal/prof_inlines_a.h +jemalloc/include/jemalloc/internal/prof_inlines_b.h +jemalloc/include/jemalloc/internal/prof_structs.h +jemalloc/include/jemalloc/internal/prof_types.h +jemalloc/include/jemalloc/internal/public_namespace.sh +jemalloc/include/jemalloc/internal/public_unnamespace.sh +jemalloc/include/jemalloc/internal/ql.h +jemalloc/include/jemalloc/internal/qr.h +jemalloc/include/jemalloc/internal/quantum.h +jemalloc/include/jemalloc/internal/rb.h +jemalloc/include/jemalloc/internal/rtree.h +jemalloc/include/jemalloc/internal/rtree_tsd.h +jemalloc/include/jemalloc/internal/safety_check.h +jemalloc/include/jemalloc/internal/sc.h +jemalloc/include/jemalloc/internal/seq.h +jemalloc/include/jemalloc/internal/smoothstep.h +jemalloc/include/jemalloc/internal/smoothstep.sh +jemalloc/include/jemalloc/internal/spin.h +jemalloc/include/jemalloc/internal/stats.h +jemalloc/include/jemalloc/internal/sz.h +jemalloc/include/jemalloc/internal/tcache_externs.h +jemalloc/include/jemalloc/internal/tcache_inlines.h +jemalloc/include/jemalloc/internal/tcache_structs.h +jemalloc/include/jemalloc/internal/tcache_types.h +jemalloc/include/jemalloc/internal/test_hooks.h +jemalloc/include/jemalloc/internal/ticker.h +jemalloc/include/jemalloc/internal/tsd.h +jemalloc/include/jemalloc/internal/tsd_generic.h +jemalloc/include/jemalloc/internal/tsd_malloc_thread_cleanup.h +jemalloc/include/jemalloc/internal/tsd_tls.h +jemalloc/include/jemalloc/internal/tsd_types.h +jemalloc/include/jemalloc/internal/tsd_win.h +jemalloc/include/jemalloc/internal/util.h +jemalloc/include/jemalloc/internal/witness.h +jemalloc/include/jemalloc/jemalloc.sh +jemalloc/include/jemalloc/jemalloc_defs.h.in +jemalloc/include/jemalloc/jemalloc_macros.h.in +jemalloc/include/jemalloc/jemalloc_mangle.sh +jemalloc/include/jemalloc/jemalloc_protos.h.in +jemalloc/include/jemalloc/jemalloc_rename.sh +jemalloc/include/jemalloc/jemalloc_typedefs.h.in +jemalloc/include/msvc_compat/C99/stdbool.h +jemalloc/include/msvc_compat/C99/stdint.h +jemalloc/include/msvc_compat/strings.h +jemalloc/include/msvc_compat/windows_extra.h +jemalloc/INSTALL.md +jemalloc/jemalloc.pc.in +jemalloc/m4/ax_cxx_compile_stdcxx.m4 +jemalloc/Makefile.in +jemalloc/msvc/jemalloc_vc2015.sln +jemalloc/msvc/jemalloc_vc2017.sln +jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj +jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj.filters +jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj +jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters +jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj +jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj.filters +jemalloc/msvc/ReadMe.txt +jemalloc/msvc/test_threads/test_threads.cpp +jemalloc/msvc/test_threads/test_threads.h +jemalloc/msvc/test_threads/test_threads_main.cpp +jemalloc/README +jemalloc/run_tests.sh +jemalloc/scripts/gen_run_tests.py +jemalloc/scripts/gen_travis.py +jemalloc/src/arena.c +jemalloc/src/background_thread.c +jemalloc/src/base.c +jemalloc/src/bin.c +jemalloc/src/bitmap.c +jemalloc/src/ckh.c +jemalloc/src/ctl.c +jemalloc/src/div.c +jemalloc/src/extent.c +jemalloc/src/extent_dss.c +jemalloc/src/extent_mmap.c +jemalloc/src/hash.c +jemalloc/src/hook.c +jemalloc/src/jemalloc.c +jemalloc/src/jemalloc_cpp.cpp +jemalloc/src/large.c +jemalloc/src/log.c +jemalloc/src/malloc_io.c +jemalloc/src/mutex.c +jemalloc/src/mutex_pool.c +jemalloc/src/nstime.c +jemalloc/src/pages.c +jemalloc/src/prng.c +jemalloc/src/prof.c +jemalloc/src/rtree.c +jemalloc/src/safety_check.c +jemalloc/src/sc.c +jemalloc/src/stats.c +jemalloc/src/sz.c +jemalloc/src/tcache.c +jemalloc/src/test_hooks.c +jemalloc/src/ticker.c +jemalloc/src/tsd.c +jemalloc/src/witness.c +jemalloc/src/zone.c +jemalloc/test/include/test/btalloc.h +jemalloc/test/include/test/extent_hooks.h +jemalloc/test/include/test/jemalloc_test.h.in +jemalloc/test/include/test/jemalloc_test_defs.h.in +jemalloc/test/include/test/math.h +jemalloc/test/include/test/mq.h +jemalloc/test/include/test/mtx.h +jemalloc/test/include/test/SFMT-alti.h +jemalloc/test/include/test/SFMT-params.h +jemalloc/test/include/test/SFMT-params607.h +jemalloc/test/include/test/SFMT-params1279.h +jemalloc/test/include/test/SFMT-params2281.h +jemalloc/test/include/test/SFMT-params4253.h +jemalloc/test/include/test/SFMT-params11213.h +jemalloc/test/include/test/SFMT-params19937.h +jemalloc/test/include/test/SFMT-params44497.h +jemalloc/test/include/test/SFMT-params86243.h +jemalloc/test/include/test/SFMT-params132049.h +jemalloc/test/include/test/SFMT-params216091.h +jemalloc/test/include/test/SFMT-sse2.h +jemalloc/test/include/test/SFMT.h +jemalloc/test/include/test/test.h +jemalloc/test/include/test/thd.h +jemalloc/test/include/test/timer.h +jemalloc/test/integration/aligned_alloc.c +jemalloc/test/integration/allocated.c +jemalloc/test/integration/extent.c +jemalloc/test/integration/extent.sh +jemalloc/test/integration/malloc.c +jemalloc/test/integration/mallocx.c +jemalloc/test/integration/mallocx.sh +jemalloc/test/integration/MALLOCX_ARENA.c +jemalloc/test/integration/overflow.c +jemalloc/test/integration/posix_memalign.c +jemalloc/test/integration/rallocx.c +jemalloc/test/integration/sdallocx.c +jemalloc/test/integration/slab_sizes.c +jemalloc/test/integration/slab_sizes.sh +jemalloc/test/integration/smallocx.c +jemalloc/test/integration/smallocx.sh +jemalloc/test/integration/thread_arena.c +jemalloc/test/integration/thread_tcache_enabled.c +jemalloc/test/integration/xallocx.c +jemalloc/test/integration/xallocx.sh +jemalloc/test/src/btalloc.c +jemalloc/test/src/btalloc_0.c +jemalloc/test/src/btalloc_1.c +jemalloc/test/src/math.c +jemalloc/test/src/mq.c +jemalloc/test/src/mtx.c +jemalloc/test/src/SFMT.c +jemalloc/test/src/test.c +jemalloc/test/src/thd.c +jemalloc/test/src/timer.c +jemalloc/test/stress/hookbench.c +jemalloc/test/stress/microbench.c +jemalloc/test/test.sh.in +jemalloc/test/unit/a0.c +jemalloc/test/unit/arena_reset.c +jemalloc/test/unit/arena_reset_prof.c +jemalloc/test/unit/arena_reset_prof.sh +jemalloc/test/unit/atomic.c +jemalloc/test/unit/background_thread.c +jemalloc/test/unit/background_thread_enable.c +jemalloc/test/unit/base.c +jemalloc/test/unit/binshard.c +jemalloc/test/unit/binshard.sh +jemalloc/test/unit/bitmap.c +jemalloc/test/unit/bit_util.c +jemalloc/test/unit/ckh.c +jemalloc/test/unit/decay.c +jemalloc/test/unit/decay.sh +jemalloc/test/unit/div.c +jemalloc/test/unit/emitter.c +jemalloc/test/unit/extent_quantize.c +jemalloc/test/unit/extent_util.c +jemalloc/test/unit/fork.c +jemalloc/test/unit/hash.c +jemalloc/test/unit/hook.c +jemalloc/test/unit/huge.c +jemalloc/test/unit/junk.c +jemalloc/test/unit/junk.sh +jemalloc/test/unit/junk_alloc.c +jemalloc/test/unit/junk_alloc.sh +jemalloc/test/unit/junk_free.c +jemalloc/test/unit/junk_free.sh +jemalloc/test/unit/log.c +jemalloc/test/unit/mallctl.c +jemalloc/test/unit/malloc_io.c +jemalloc/test/unit/math.c +jemalloc/test/unit/mq.c +jemalloc/test/unit/mtx.c +jemalloc/test/unit/nstime.c +jemalloc/test/unit/pack.c +jemalloc/test/unit/pack.sh +jemalloc/test/unit/pages.c +jemalloc/test/unit/ph.c +jemalloc/test/unit/prng.c +jemalloc/test/unit/prof_accum.c +jemalloc/test/unit/prof_accum.sh +jemalloc/test/unit/prof_active.c +jemalloc/test/unit/prof_active.sh +jemalloc/test/unit/prof_gdump.c +jemalloc/test/unit/prof_gdump.sh +jemalloc/test/unit/prof_idump.c +jemalloc/test/unit/prof_idump.sh +jemalloc/test/unit/prof_log.c +jemalloc/test/unit/prof_log.sh +jemalloc/test/unit/prof_reset.c +jemalloc/test/unit/prof_reset.sh +jemalloc/test/unit/prof_tctx.c +jemalloc/test/unit/prof_tctx.sh +jemalloc/test/unit/prof_thread_name.c +jemalloc/test/unit/prof_thread_name.sh +jemalloc/test/unit/ql.c +jemalloc/test/unit/qr.c +jemalloc/test/unit/rb.c +jemalloc/test/unit/retained.c +jemalloc/test/unit/rtree.c +jemalloc/test/unit/safety_check.c +jemalloc/test/unit/safety_check.sh +jemalloc/test/unit/sc.c +jemalloc/test/unit/seq.c +jemalloc/test/unit/SFMT.c +jemalloc/test/unit/size_classes.c +jemalloc/test/unit/slab.c +jemalloc/test/unit/smoothstep.c +jemalloc/test/unit/spin.c +jemalloc/test/unit/stats.c +jemalloc/test/unit/stats_print.c +jemalloc/test/unit/test_hooks.c +jemalloc/test/unit/ticker.c +jemalloc/test/unit/tsd.c +jemalloc/test/unit/witness.c +jemalloc/test/unit/zero.c +jemalloc/test/unit/zero.sh +jemalloc/TUNING.md +m4/ax_cxx_compile_stdcxx.m4 +m4/ax_cxx_compile_stdcxx_11.m4 +m4/ax_pthread.m4 +man/autohbw.7 +man/hbwallocator.3 +man/hbwmalloc.3 +man/memkind-auto-dax-kmem-nodes.1 +man/memkind-hbw-nodes.1 +man/memkind.3 +man/memkind_arena.3 +man/memkind_dax_kmem.3 +man/memkind_default.3 +man/memkind_hbw.3 +man/memkind_hugetlb.3 +man/memkind_pmem.3 +man/memkindallocator.3 +man/pmemallocator.3 +memkind.pc.in +memkind.spec.mk +src/Makefile.mk +src/hbwmalloc.c +src/heap_manager.c +man/memkind-auto-dax-kmem-nodes.c +src/memkind-hbw-nodes.c +src/memkind.c +src/memkind_arena.c +src/memkind_bandwidth.c +src/memkind_dax_kmem.c +src/memkind_default.c +src/memkind_gbtlb.c +src/memkind_hbw.c +src/memkind_hugetlb.c +src/memkind_interleave.c +src/memkind_log.c +src/memkind_pmem.c +src/memkind_regular.c +src/tbb_wrapper.c +test/Allocator.hpp +test/Makefile.mk +test/TestPolicy.hpp +test/alloc_benchmark.c +test/alloc_performance_tests.cpp +test/allocate_to_max_stress_test.cpp +test/allocator_perf_tool/AllocationSizes.hpp +test/allocator_perf_tool/Allocation_info.cpp +test/allocator_perf_tool/Allocation_info.hpp +test/allocator_perf_tool/Allocator.hpp +test/allocator_perf_tool/AllocatorFactory.hpp +test/allocator_perf_tool/CSVLogger.hpp +test/allocator_perf_tool/CommandLine.hpp +test/allocator_perf_tool/Configuration.hpp +test/allocator_perf_tool/ConsoleLog.hpp +test/allocator_perf_tool/FunctionCalls.hpp +test/allocator_perf_tool/FunctionCallsPerformanceTask.cpp +test/allocator_perf_tool/FunctionCallsPerformanceTask.h +test/allocator_perf_tool/GTestAdapter.hpp +test/allocator_perf_tool/HBWmallocAllocatorWithTimer.hpp +test/allocator_perf_tool/HugePageOrganizer.hpp +test/allocator_perf_tool/HugePageUnmap.hpp +test/allocator_perf_tool/Iterator.hpp +test/allocator_perf_tool/JemallocAllocatorWithTimer.hpp +test/allocator_perf_tool/Makefile +test/allocator_perf_tool/MemkindAllocatorWithTimer.hpp +test/allocator_perf_tool/Numastat.hpp +test/allocator_perf_tool/PmemMockup.cpp +test/allocator_perf_tool/PmemMockup.hpp +test/allocator_perf_tool/Runnable.hpp +test/allocator_perf_tool/ScenarioWorkload.cpp +test/allocator_perf_tool/ScenarioWorkload.h +test/allocator_perf_tool/StandardAllocatorWithTimer.hpp +test/allocator_perf_tool/Stats.hpp +test/allocator_perf_tool/StressIncreaseToMax.cpp +test/allocator_perf_tool/StressIncreaseToMax.h +test/allocator_perf_tool/Task.hpp +test/allocator_perf_tool/TaskFactory.hpp +test/allocator_perf_tool/Tests.hpp +test/allocator_perf_tool/Thread.hpp +test/allocator_perf_tool/TimerSysTime.hpp +test/allocator_perf_tool/VectorIterator.hpp +test/allocator_perf_tool/Workload.hpp +test/allocator_perf_tool/WrappersMacros.hpp +test/allocator_perf_tool/main.cpp +test/autohbw_test.py +test/autohbw_test_helper.c +test/bat_tests.cpp +test/check.cpp +test/check.h +test/common.h +test/dax_kmem_nodes.cpp +test/dax_kmem_nodes.h +test/dax_kmem_env_var_test.py +test/decorator_test.cpp +test/decorator_test.h +test/dlopen_test.cpp +test/draw_plots.py +test/environ_err_dax_kmem_malloc_positive_test.cpp +test/environ_err_dax_kmem_malloc_test.cpp +test/environ_err_hbw_malloc_test.cpp +test/error_message_tests.cpp +test/fragmentation_benchmark_pmem.cpp +test/freeing_memory_segfault_test.cpp +test/gb_page_tests_bind_policy.cpp +test/get_arena_test.cpp +test/gtest_fused/gtest/gtest-all.cc +test/gtest_fused/gtest/gtest.h +test/hbw_allocator_performance_tests.cpp +test/hbw_allocator_tests.cpp +test/hbw_detection_test.py +test/hbw_verify_function_test.cpp +test/heap_manager_init_perf_test.cpp +test/huge_page_test.cpp +test/load_tbbmalloc_symbols.c +test/locality_test.cpp +test/main.cpp +test/memkind_allocator_tests.cpp +test/memkind-afts-ext.ts +test/memkind-afts.ts +test/memkind-perf-ext.ts +test/memkind-perf.ts +test/memkind-pytests.ts +test/memkind-slts.ts +test/memkind_dax_kmem_test.cpp +test/memkind_detect_kind_tests.cpp +test/memkind_null_kind_test.cpp +test/memkind_pmem_config_tests.cpp +test/memkind_pmem_long_time_tests.cpp +test/memkind_pmem_tests.cpp +test/memkind_stat_test.cpp +test/memkind_defrag_reallocate.cpp +test/memkind_versioning_tests.cpp +test/memory_footprint_test.cpp +test/memory_manager.h +test/multithreaded_tests.cpp +test/negative_tests.cpp +test/performance/framework.cpp +test/performance/framework.hpp +test/performance/operations.hpp +test/performance/perf_tests.cpp +test/performance/perf_tests.hpp +test/pmem_alloc_performance_tests.cpp +test/pmem_allocator_tests.cpp +test/proc_stat.h +test/python_framework/__init__.py +test/python_framework/cmd_helper.py +test/python_framework/huge_page_organizer.py +test/random_sizes_allocator.h +test/run_alloc_benchmark.sh +test/static_kinds_list.h +test/static_kinds_tests.cpp +test/tbbmalloc.h +test/test.sh +test/test_dax_kmem.sh +test/trace_mechanism_test.py +test/trace_mechanism_test_helper.c +test/trial_generator.cpp +test/trial_generator.h +utils/docker/Dockerfile.fedora-31 +utils/docker/Dockerfile.ubuntu-18.04 +utils/docker/README.md +utils/docker/docker_install_ndctl.sh +utils/docker/docker_install_tbb.sh +utils/docker/docker_run_build.sh +utils/docker/docker_run_coverage.sh +utils/docker/docker_run_test.sh +utils/docker/run_local.sh +utils/docker/set_host_configuration.sh diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..d3b2039 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,526 @@ +# +# Copyright (C) 2014 - 2019 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +ACLOCAL_AMFLAGS = -I m4 +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/jemalloc/include +MAN2HTML = groff -mandoc -Thtml + +lib_LTLIBRARIES = libmemkind.la + +libmemkind_la_SOURCES = src/hbwmalloc.c \ + src/heap_manager.c \ + src/memkind.c \ + src/memkind_arena.c \ + src/memkind_bandwidth.c \ + src/memkind_dax_kmem.c \ + src/memkind_default.c \ + src/memkind_gbtlb.c \ + src/memkind_hbw.c \ + src/memkind_hugetlb.c \ + src/memkind_interleave.c \ + src/memkind_log.c \ + src/memkind_pmem.c \ + src/memkind_regular.c \ + src/tbb_wrapper.c \ + # end + + +libmemkind_la_LIBADD = jemalloc/lib/libjemalloc_pic.a +libmemkind_la_LDFLAGS = -version-info 0:1:0 -ldl -lrt +include_HEADERS = include/hbw_allocator.h \ + include/hbwmalloc.h \ + include/memkind.h \ + include/memkind_allocator.h \ + include/memkind_deprecated.h \ + include/pmem_allocator.h \ + # end + +noinst_HEADERS = include/memkind/internal/heap_manager.h \ + include/memkind/internal/memkind_arena.h \ + include/memkind/internal/memkind_bandwidth.h \ + include/memkind/internal/memkind_dax_kmem.h \ + include/memkind/internal/memkind_default.h \ + include/memkind/internal/memkind_gbtlb.h \ + include/memkind/internal/memkind_hbw.h \ + include/memkind/internal/memkind_hugetlb.h \ + include/memkind/internal/memkind_interleave.h \ + include/memkind/internal/memkind_log.h \ + include/memkind/internal/memkind_pmem.h \ + include/memkind/internal/memkind_private.h \ + include/memkind/internal/memkind_regular.h \ + include/memkind/internal/tbb_mem_pool_policy.h \ + include/memkind/internal/tbb_wrapper.h \ + include/memkind/internal/vec.h \ + # end + +EXTRA_DIST = CONTRIBUTING \ + VERSION \ + astyle.sh \ + autogen.sh \ + build.sh \ + examples/README \ + jemalloc/.appveyor.yml \ + jemalloc/.autom4te.cfg \ + jemalloc/.gitattributes\ + jemalloc/.gitignore \ + jemalloc/.travis.yml \ + jemalloc/autogen.sh \ + jemalloc/bin/jemalloc-config.in \ + jemalloc/bin/jemalloc.sh.in \ + jemalloc/bin/jeprof.in \ + jemalloc/build-aux/config.guess \ + jemalloc/build-aux/config.sub \ + jemalloc/build-aux/install-sh \ + jemalloc/ChangeLog \ + jemalloc/config.stamp.in \ + jemalloc/configure.ac \ + jemalloc/COPYING \ + jemalloc/doc/html.xsl.in \ + jemalloc/doc/jemalloc.xml.in \ + jemalloc/doc/manpages.xsl.in \ + jemalloc/doc/stylesheet.xsl \ + jemalloc/include/jemalloc/internal/arena_externs.h \ + jemalloc/include/jemalloc/internal/arena_inlines_a.h \ + jemalloc/include/jemalloc/internal/arena_inlines_b.h \ + jemalloc/include/jemalloc/internal/arena_stats.h \ + jemalloc/include/jemalloc/internal/arena_structs_a.h \ + jemalloc/include/jemalloc/internal/arena_structs_b.h \ + jemalloc/include/jemalloc/internal/arena_types.h \ + jemalloc/include/jemalloc/internal/assert.h \ + jemalloc/include/jemalloc/internal/atomic.h \ + jemalloc/include/jemalloc/internal/atomic_c11.h \ + jemalloc/include/jemalloc/internal/atomic_gcc_atomic.h \ + jemalloc/include/jemalloc/internal/atomic_gcc_sync.h \ + jemalloc/include/jemalloc/internal/atomic_msvc.h \ + jemalloc/include/jemalloc/internal/background_thread_externs.h \ + jemalloc/include/jemalloc/internal/background_thread_inlines.h \ + jemalloc/include/jemalloc/internal/background_thread_structs.h \ + jemalloc/include/jemalloc/internal/base_externs.h \ + jemalloc/include/jemalloc/internal/base_inlines.h \ + jemalloc/include/jemalloc/internal/base_structs.h \ + jemalloc/include/jemalloc/internal/base_types.h \ + jemalloc/include/jemalloc/internal/bin.h \ + jemalloc/include/jemalloc/internal/bin_stats.h \ + jemalloc/include/jemalloc/internal/bin_types.h \ + jemalloc/include/jemalloc/internal/bitmap.h \ + jemalloc/include/jemalloc/internal/bit_util.h \ + jemalloc/include/jemalloc/internal/cache_bin.h \ + jemalloc/include/jemalloc/internal/ckh.h \ + jemalloc/include/jemalloc/internal/ctl.h \ + jemalloc/include/jemalloc/internal/div.h \ + jemalloc/include/jemalloc/internal/emitter.h \ + jemalloc/include/jemalloc/internal/extent_dss.h \ + jemalloc/include/jemalloc/internal/extent_externs.h \ + jemalloc/include/jemalloc/internal/extent_inlines.h \ + jemalloc/include/jemalloc/internal/extent_mmap.h \ + jemalloc/include/jemalloc/internal/extent_structs.h \ + jemalloc/include/jemalloc/internal/extent_types.h \ + jemalloc/include/jemalloc/internal/hash.h \ + jemalloc/include/jemalloc/internal/hook.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in \ + jemalloc/include/jemalloc/internal/jemalloc_internal_externs.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_includes.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_a.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_b.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_c.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h \ + jemalloc/include/jemalloc/internal/jemalloc_internal_types.h \ + jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in \ + jemalloc/include/jemalloc/internal/large_externs.h \ + jemalloc/include/jemalloc/internal/log.h \ + jemalloc/include/jemalloc/internal/malloc_io.h \ + jemalloc/include/jemalloc/internal/mutex.h \ + jemalloc/include/jemalloc/internal/mutex_pool.h \ + jemalloc/include/jemalloc/internal/mutex_prof.h \ + jemalloc/include/jemalloc/internal/nstime.h \ + jemalloc/include/jemalloc/internal/pages.h \ + jemalloc/include/jemalloc/internal/ph.h \ + jemalloc/include/jemalloc/internal/private_namespace.sh \ + jemalloc/include/jemalloc/internal/private_symbols.sh \ + jemalloc/include/jemalloc/internal/prng.h \ + jemalloc/include/jemalloc/internal/prof_externs.h \ + jemalloc/include/jemalloc/internal/prof_inlines_a.h \ + jemalloc/include/jemalloc/internal/prof_inlines_b.h \ + jemalloc/include/jemalloc/internal/prof_structs.h \ + jemalloc/include/jemalloc/internal/prof_types.h \ + jemalloc/include/jemalloc/internal/public_namespace.sh \ + jemalloc/include/jemalloc/internal/public_unnamespace.sh \ + jemalloc/include/jemalloc/internal/ql.h \ + jemalloc/include/jemalloc/internal/qr.h \ + jemalloc/include/jemalloc/internal/quantum.h \ + jemalloc/include/jemalloc/internal/rb.h \ + jemalloc/include/jemalloc/internal/rtree.h \ + jemalloc/include/jemalloc/internal/rtree_tsd.h \ + jemalloc/include/jemalloc/internal/safety_check.h \ + jemalloc/include/jemalloc/internal/sc.h \ + jemalloc/include/jemalloc/internal/seq.h \ + jemalloc/include/jemalloc/internal/smoothstep.h \ + jemalloc/include/jemalloc/internal/smoothstep.sh \ + jemalloc/include/jemalloc/internal/spin.h \ + jemalloc/include/jemalloc/internal/stats.h \ + jemalloc/include/jemalloc/internal/sz.h \ + jemalloc/include/jemalloc/internal/tcache_externs.h \ + jemalloc/include/jemalloc/internal/tcache_inlines.h \ + jemalloc/include/jemalloc/internal/tcache_structs.h \ + jemalloc/include/jemalloc/internal/tcache_types.h \ + jemalloc/include/jemalloc/internal/test_hooks.h \ + jemalloc/include/jemalloc/internal/ticker.h \ + jemalloc/include/jemalloc/internal/tsd.h \ + jemalloc/include/jemalloc/internal/tsd_generic.h \ + jemalloc/include/jemalloc/internal/tsd_malloc_thread_cleanup.h \ + jemalloc/include/jemalloc/internal/tsd_tls.h \ + jemalloc/include/jemalloc/internal/tsd_types.h \ + jemalloc/include/jemalloc/internal/tsd_win.h \ + jemalloc/include/jemalloc/internal/util.h \ + jemalloc/include/jemalloc/internal/witness.h \ + jemalloc/include/jemalloc/jemalloc.sh \ + jemalloc/include/jemalloc/jemalloc_defs.h.in \ + jemalloc/include/jemalloc/jemalloc_macros.h.in \ + jemalloc/include/jemalloc/jemalloc_mangle.sh \ + jemalloc/include/jemalloc/jemalloc_protos.h.in \ + jemalloc/include/jemalloc/jemalloc_rename.sh \ + jemalloc/include/jemalloc/jemalloc_typedefs.h.in \ + jemalloc/include/msvc_compat/C99/stdbool.h \ + jemalloc/include/msvc_compat/C99/stdint.h \ + jemalloc/include/msvc_compat/strings.h \ + jemalloc/include/msvc_compat/windows_extra.h \ + jemalloc/INSTALL.md \ + jemalloc/jemalloc.pc.in \ + jemalloc/m4/ax_cxx_compile_stdcxx.m4 \ + jemalloc/Makefile.in \ + jemalloc/msvc/jemalloc_vc2015.sln \ + jemalloc/msvc/jemalloc_vc2017.sln \ + jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj \ + jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters \ + jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj \ + jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj.filters \ + jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj \ + jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters \ + jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj \ + jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj.filters \ + jemalloc/msvc/ReadMe.txt \ + jemalloc/msvc/test_threads/test_threads.cpp \ + jemalloc/msvc/test_threads/test_threads.h \ + jemalloc/msvc/test_threads/test_threads_main.cpp \ + jemalloc/README \ + jemalloc/run_tests.sh \ + jemalloc/scripts/gen_run_tests.py \ + jemalloc/scripts/gen_travis.py \ + jemalloc/src/arena.c \ + jemalloc/src/background_thread.c \ + jemalloc/src/base.c \ + jemalloc/src/bin.c \ + jemalloc/src/bitmap.c \ + jemalloc/src/ckh.c \ + jemalloc/src/ctl.c \ + jemalloc/src/div.c \ + jemalloc/src/extent.c \ + jemalloc/src/extent_dss.c \ + jemalloc/src/extent_mmap.c \ + jemalloc/src/hash.c \ + jemalloc/src/hook.c \ + jemalloc/src/jemalloc.c \ + jemalloc/src/jemalloc_cpp.cpp \ + jemalloc/src/large.c \ + jemalloc/src/log.c \ + jemalloc/src/malloc_io.c \ + jemalloc/src/mutex.c \ + jemalloc/src/mutex_pool.c \ + jemalloc/src/nstime.c \ + jemalloc/src/pages.c \ + jemalloc/src/prng.c \ + jemalloc/src/prof.c \ + jemalloc/src/rtree.c \ + jemalloc/src/safety_check.c \ + jemalloc/src/sc.c \ + jemalloc/src/stats.c \ + jemalloc/src/sz.c \ + jemalloc/src/tcache.c \ + jemalloc/src/test_hooks.c \ + jemalloc/src/ticker.c \ + jemalloc/src/tsd.c \ + jemalloc/src/witness.c \ + jemalloc/src/zone.c \ + jemalloc/test/include/test/btalloc.h \ + jemalloc/test/include/test/extent_hooks.h \ + jemalloc/test/include/test/jemalloc_test.h.in \ + jemalloc/test/include/test/jemalloc_test_defs.h.in \ + jemalloc/test/include/test/math.h \ + jemalloc/test/include/test/mq.h \ + jemalloc/test/include/test/mtx.h \ + jemalloc/test/include/test/SFMT-alti.h \ + jemalloc/test/include/test/SFMT-params.h \ + jemalloc/test/include/test/SFMT-params607.h \ + jemalloc/test/include/test/SFMT-params1279.h \ + jemalloc/test/include/test/SFMT-params2281.h \ + jemalloc/test/include/test/SFMT-params4253.h \ + jemalloc/test/include/test/SFMT-params11213.h \ + jemalloc/test/include/test/SFMT-params19937.h \ + jemalloc/test/include/test/SFMT-params44497.h \ + jemalloc/test/include/test/SFMT-params86243.h \ + jemalloc/test/include/test/SFMT-params132049.h \ + jemalloc/test/include/test/SFMT-params216091.h \ + jemalloc/test/include/test/SFMT-sse2.h \ + jemalloc/test/include/test/SFMT.h \ + jemalloc/test/include/test/test.h \ + jemalloc/test/include/test/thd.h \ + jemalloc/test/include/test/timer.h \ + jemalloc/test/integration/aligned_alloc.c \ + jemalloc/test/integration/allocated.c \ + jemalloc/test/integration/extent.c \ + jemalloc/test/integration/extent.sh \ + jemalloc/test/integration/malloc.c \ + jemalloc/test/integration/mallocx.c \ + jemalloc/test/integration/mallocx.sh \ + jemalloc/test/integration/MALLOCX_ARENA.c \ + jemalloc/test/integration/overflow.c \ + jemalloc/test/integration/posix_memalign.c \ + jemalloc/test/integration/rallocx.c \ + jemalloc/test/integration/sdallocx.c \ + jemalloc/test/integration/slab_sizes.c \ + jemalloc/test/integration/slab_sizes.sh \ + jemalloc/test/integration/smallocx.c \ + jemalloc/test/integration/smallocx.sh \ + jemalloc/test/integration/thread_arena.c \ + jemalloc/test/integration/thread_tcache_enabled.c \ + jemalloc/test/integration/xallocx.c \ + jemalloc/test/integration/xallocx.sh \ + jemalloc/test/src/btalloc.c \ + jemalloc/test/src/btalloc_0.c \ + jemalloc/test/src/btalloc_1.c \ + jemalloc/test/src/math.c \ + jemalloc/test/src/mq.c \ + jemalloc/test/src/mtx.c \ + jemalloc/test/src/SFMT.c \ + jemalloc/test/src/test.c \ + jemalloc/test/src/thd.c \ + jemalloc/test/src/timer.c \ + jemalloc/test/stress/hookbench.c \ + jemalloc/test/stress/microbench.c \ + jemalloc/test/test.sh.in \ + jemalloc/test/unit/a0.c \ + jemalloc/test/unit/arena_reset.c \ + jemalloc/test/unit/arena_reset_prof.c \ + jemalloc/test/unit/arena_reset_prof.sh \ + jemalloc/test/unit/atomic.c \ + jemalloc/test/unit/background_thread.c \ + jemalloc/test/unit/background_thread_enable.c \ + jemalloc/test/unit/base.c \ + jemalloc/test/unit/binshard.c \ + jemalloc/test/unit/binshard.sh \ + jemalloc/test/unit/bitmap.c \ + jemalloc/test/unit/bit_util.c \ + jemalloc/test/unit/ckh.c \ + jemalloc/test/unit/decay.c \ + jemalloc/test/unit/decay.sh \ + jemalloc/test/unit/div.c \ + jemalloc/test/unit/emitter.c \ + jemalloc/test/unit/extent_quantize.c\ + jemalloc/test/unit/extent_util.c \ + jemalloc/test/unit/fork.c \ + jemalloc/test/unit/hash.c \ + jemalloc/test/unit/hook.c \ + jemalloc/test/unit/huge.c \ + jemalloc/test/unit/junk.c \ + jemalloc/test/unit/junk.sh \ + jemalloc/test/unit/junk_alloc.c \ + jemalloc/test/unit/junk_alloc.sh \ + jemalloc/test/unit/junk_free.c \ + jemalloc/test/unit/junk_free.sh \ + jemalloc/test/unit/log.c \ + jemalloc/test/unit/mallctl.c \ + jemalloc/test/unit/malloc_io.c \ + jemalloc/test/unit/math.c \ + jemalloc/test/unit/mq.c \ + jemalloc/test/unit/mtx.c \ + jemalloc/test/unit/nstime.c \ + jemalloc/test/unit/pack.c \ + jemalloc/test/unit/pack.sh \ + jemalloc/test/unit/pages.c \ + jemalloc/test/unit/ph.c \ + jemalloc/test/unit/prng.c \ + jemalloc/test/unit/prof_accum.c \ + jemalloc/test/unit/prof_accum.sh \ + jemalloc/test/unit/prof_active.c \ + jemalloc/test/unit/prof_active.sh \ + jemalloc/test/unit/prof_gdump.c \ + jemalloc/test/unit/prof_gdump.sh \ + jemalloc/test/unit/prof_idump.c \ + jemalloc/test/unit/prof_idump.sh \ + jemalloc/test/unit/prof_log.c \ + jemalloc/test/unit/prof_log.sh \ + jemalloc/test/unit/prof_reset.c \ + jemalloc/test/unit/prof_reset.sh \ + jemalloc/test/unit/prof_tctx.c \ + jemalloc/test/unit/prof_tctx.sh \ + jemalloc/test/unit/prof_thread_name.c \ + jemalloc/test/unit/prof_thread_name.sh\ + jemalloc/test/unit/ql.c \ + jemalloc/test/unit/qr.c \ + jemalloc/test/unit/rb.c \ + jemalloc/test/unit/retained.c \ + jemalloc/test/unit/rtree.c \ + jemalloc/test/unit/safety_check.c \ + jemalloc/test/unit/safety_check.sh \ + jemalloc/test/unit/sc.c \ + jemalloc/test/unit/seq.c \ + jemalloc/test/unit/SFMT.c \ + jemalloc/test/unit/size_classes.c \ + jemalloc/test/unit/slab.c \ + jemalloc/test/unit/smoothstep.c \ + jemalloc/test/unit/spin.c \ + jemalloc/test/unit/stats.c \ + jemalloc/test/unit/stats_print.c \ + jemalloc/test/unit/test_hooks.c \ + jemalloc/test/unit/ticker.c \ + jemalloc/test/unit/tsd.c \ + jemalloc/test/unit/witness.c \ + jemalloc/test/unit/zero.c \ + jemalloc/test/unit/zero.sh \ + jemalloc/TUNING.md \ + memkind-$(VERSION).spec \ + memkind.pc.in \ + memkind.spec.mk \ + test/test.sh \ + test/test_dax_kmem.sh \ + utils/docker/Dockerfile.fedora-31 \ + utils/docker/Dockerfile.ubuntu-18.04 \ + utils/docker/README.md \ + utils/docker/docker_install_ndctl.sh \ + utils/docker/docker_install_tbb.sh \ + utils/docker/docker_run_build.sh \ + utils/docker/docker_run_coverage.sh \ + utils/docker/docker_run_test.sh \ + utils/docker/run_local.sh \ + utils/docker/set_host_configuration.sh \ + # end + +dist_doc_DATA = COPYING README VERSION +dist_man_MANS = man/autohbw.7 \ + man/hbwallocator.3 \ + man/hbwmalloc.3 \ + man/memkind-auto-dax-kmem-nodes.1 \ + man/memkind-hbw-nodes.1 \ + man/memkind.3 \ + man/memkind_arena.3 \ + man/memkind_dax_kmem.3 \ + man/memkind_default.3 \ + man/memkind_hbw.3 \ + man/memkind_hugetlb.3 \ + man/memkind_pmem.3 \ + man/memkindallocator.3 \ + man/pmemallocator.3 \ + # end + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = memkind.pc + +CLEANFILES = memkind-$(VERSION).spec $(libmemkind_la_LIBADD) +DISTCLEANFILES = VERSION configure pkgconfig_DATA + +bin_PROGRAMS = memkind-auto-dax-kmem-nodes memkind-hbw-nodes + +memkind_auto_dax_kmem_nodes_SOURCES = src/memkind-auto-dax-kmem-nodes.c +memkind_auto_dax_kmem_nodes_LDADD = libmemkind.la +memkind_auto_dax_kmem_nodes_LDFLAGS = $(DAXCTL_LIBS) + +memkind_hbw_nodes_SOURCES = src/memkind-hbw-nodes.c +memkind_hbw_nodes_LDADD = libmemkind.la + +bin_SCRIPTS = +check_PROGRAMS = +noinst_PROGRAMS = +noinst_LTLIBRARIES = +TESTS = + +req_flags = -fvisibility=hidden -Wall -Werror -D_GNU_SOURCE -DJE_PREFIX=@memkind_prefix@ + +AM_CFLAGS = $(req_flags) +AM_CXXFLAGS = $(req_flags) + +clean-local: clean-jemalloc_deps + +html-local: + $(MAN2HTML) man/hbwmalloc.3 > man/hbwmalloc.html + $(MAN2HTML) man/memkind.3 > man/memkind.html + $(MAN2HTML) man/memkindallocator.3 > man/memkindallocator.html + $(MAN2HTML) man/pmemallocator.3 > man/pmemallocator.html + +clean-jemalloc_deps: + [ -e jemalloc/configure ] && (cd jemalloc && $(MAKE) clean) || exit 0 + [ -e jemalloc/configure ] && (cd jemalloc && rm configure) || exit 0 + +.PHONY: jemalloc_deps checkprogs clean-jemalloc_deps html-local +.NOTPARALLEL: static_lib + +# build check programs without running tests +checkprogs: libmemkind.la $(check_PROGRAMS) + +memkind-$(VERSION).spec: + $(MAKE) version="$(VERSION)" -f memkind.spec.mk $@ + +rpm: dist + $(MAKE) version="$(VERSION)" -f memkind.spec.mk $@ + +all: jemalloc_deps static_lib + +# the script merge memkind and jemalloc libraries into one static library. +define ar_prog +create libmemkind.a\n\ +addlib .libs/libmemkind.a\n\ +addlib $(libmemkind_la_LIBADD)\n\ +save\n\ +end +endef + +static_lib: libmemkind.la + bash -c "ar -M < <(echo -e '$(ar_prog)')" + cp libmemkind.a .libs/ + rm libmemkind.a + +JEMALLOC_CONFIG = --enable-autogen --without-export --with-version=5.2.1-0-gea6b3e973b477b8061e0076bb257dbd7f3faa756 \ + --disable-fill --disable-initial-exec-tls --with-jemalloc-prefix=@memkind_prefix@ \ + --with-malloc-conf="narenas:@auto_arenas@,lg_tcache_max:@tcache_max_size_class@" \ + #end + +jemalloc_deps: + [ ! -e jemalloc/configure ] && (cd jemalloc && autoconf) || exit 0 + [ ! -e $(libmemkind_la_LIBADD) ] && (cd jemalloc && ./configure $(JEMALLOC_CONFIG) && $(MAKE)) || exit 0 + +unit_tests: checkprogs + test/all_tests --gtest_filter=*free_with_NULL_kind_4096_bytes:NegativeTest.*:ErrorMessage.*:GetArenaTest.*:MemkindVersioningTests.* + test/decorator_test + +PMEM_PATH=/tmp/ +unit_tests_pmem: checkprogs + test/pmem_test -d $(PMEM_PATH) + +unit_tests_dax_kmem: checkprogs + test/test_dax_kmem.sh + +include autohbw/Makefile.mk +include test/Makefile.mk +include examples/Makefile.mk +include src/Makefile.mk diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..c72d191 --- /dev/null +++ b/NEWS @@ -0,0 +1,42 @@ +OPEN DEVELOPMENT +================ + +We are moving to a more open development model with memkind. + +- The memkind github organization: + https://github.com/memkind + +- Rather than posting bulk patches at time of tag, we are posting more + incremental patches with finer grain commit details. + +- There is now a "dev" branch in the memkind repository and a + "memkind-dev" branch in the memkind fork of the jemalloc repository. + These will be used for open development work. + +- There is a memkind web page here: + http://memkind.github.io/memkind + +- We have posted an architecture document here: + http://memkind.github.io/memkind/memkind_arch_20150318.pdf + +- We invite you to join the memkind mailing list: + https://lists.01.org/mailman/listinfo/memkind + +- Feel free to open a github issue, especially if there is a TODO item + that you would like to prioritize. + +- We have posted source and binary RPMs for several distributions here: + http://download.opensuse.org/repositories/home:/cmcantalupo/ + +- memkind is also available in Fedora package repository (devel, EPEL7): + https://admin.fedoraproject.org/pkgdb/package/memkind/ + +- Pull requests are welcome. + +- White space formatting generally conforms to + $ astyle --style=linux --indent=spaces=4 -S --max-continuation-indent=80 \ + --max-code-length=80 --break-after-logical --indent-namespaces -z2 \ + --align-pointer=name + +- For more information about astyle: + http://astyle.sourceforge.net/ diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..41b7945 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ + + +### Description + + + +### Types of changes + + +- [ ] Bugfix (non-breaking change which fixes issue linked in Description above) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation (correction or otherwise) +- [ ] Cosmetics (whitespace, appearance) +- [ ] Other + +### Checklist + + +- [ ] Code compiles without errors +- [ ] All tests pass locally with my changes (see TESTING section in CONTRIBUTING file) +- [ ] Created tests which will fail without the change (if possible) +- [ ] Extended the README/documentation (if necessary) +- [ ] All newly added files have proprietary license (if necessary) +- [ ] All newly added files are referenced in MANIFEST files (if necessary) + +## Further comments + + diff --git a/README b/README new file mode 100644 index 0000000..f76195a --- /dev/null +++ b/README @@ -0,0 +1,390 @@ +# **MEMKIND** + +[![Build Status](https://travis-ci.org/memkind/memkind.svg)](https://travis-ci.org/memkind/memkind) +[![MEMKIND version](https://img.shields.io/github/tag/memkind/memkind.svg)](https://github.com/memkind/memkind/releases/latest) +[![Coverage Status](http://codecov.io/github/memkind/memkind/coverage.svg?branch=master)](http://codecov.io/gh/memkind/memkind?branch=master) +[![Packaging status](https://repology.org/badge/tiny-repos/memkind.svg)](https://repology.org/project/memkind/versions) + +The memkind library is a user extensible heap manager built on top of +jemalloc which enables control of memory characteristics and a +partitioning of the heap between kinds of memory. The kinds of memory +are defined by operating system memory policies that have been applied +to virtual address ranges. Memory characteristics supported by +memkind without user extension include control of NUMA and page size +features. The jemalloc non-standard interface has been extended to +enable specialized arenas to make requests for virtual memory from the +operating system through the memkind partition interface. Through the +other memkind interfaces the user can control and extend memory +partition features and allocate memory while selecting enabled +features. Memkind interface allows to create and control file-backed memory +(PMEM kind) on specified device. + +## Contents + +1. [Interfaces](#interfaces) +2. [Dependencies](#dependencies) +3. [Building and Installing](#building-and-installing) + * [jemalloc](#jemalloc) +4. [Run Requirements](#run-requirements) +5. [Kind Requirements](#kind-requirements) +6. [Kernel](#kernel) +7. [NVDIMM volatile usage](#nvdimm-volatile-usage) + * [DAX device](#dax-device) + * [DAX filesystem](#dax-filesystem) +8. [The Detection Mechanism of the Kind](#the-detection-mechanism-of-the-kind) +9. [Setting Logging Mechanism](#setting-logging-mechanism) +10. [Setting Heap Manager](#setting-heap-manager) +11. [Testing](#testing) +12. [Simulating High Bandwidth Memory](#simulating-high-bandwidth-memory) +13. [Notes](#notes) +14. [Status](#status) +15. [Disclaimer](#disclaimer) + +## Interfaces +The memkind library delivers four interfaces: + * hbwmalloc.h - recommended for high-bandwidth memory use cases (stable) + * memkind.h - generic interface for more complex use cases (stable) + * pmem_allocator.h - the C++ allocator that satisfies the C++ Allocator + [requirements](https://en.cppreference.com/w/cpp/named_req/Allocator) + used for PMEM memory use cases (stable) + * memkind_allocator.h - the C++ allocator that satisfies the C++ Allocator + [requirements](https://en.cppreference.com/w/cpp/named_req/Allocator) + used for static kinds (stable) + +For more detailed information about those interfaces see +corresponding manpages (located in man/ subdir): + + man memkind + + man hbwmalloc + + man pmemallocator + + man memkindallocator + +## Dependencies + +You will need to install required packages on the build system: + +* **autoconf** +* **automake** +* **gcc-c++** +* **libnuma-devel** +* **libtool** +* **numactl-devel** +* **unzip** + +For using automatic recognition of PMEM NUMA in MEMKIND_DAX_KMEM: + +* **libdaxctl-devel** (v66 or later) + +## Building and Installing + +The memkind library has a dependency on a related fork of jemalloc. +The configure scripts and gtest source code are distributed with the +source tarball included in the source RPM, and this tarball is created +with the memkind "make dist" target. In contrast to the distributed source +tarball, the git repository does not include any generated files. +For this reason some additional steps are required when building +from a checkout of the git repo. Those steps include running +the bash script called "autogen.sh" prior to configure. This script +will populate a VERSION file based on "git describe", and use +autoreconf to generate a configure script. + +Building and installing memkind in standard system location can be as simple as +typing the following while in the root directory of the source tree: + + ./autogen.sh + ./configure + make + make install + +To install this library into **other locations**, you can use the prefix variable, e.g.: + + ./autogen.sh + ./configure --prefix=/usr + make + make install + +This will install files to /usr/lib, /usr/include, /usr/share/doc/, usr/share/man. + +See the output of: + + ./configure --help + +for more information about either the memkind or the jemalloc configuration options. + +## jemalloc +The jemalloc source was forked from jemalloc version 5.2.1. This source tree +is located within the jemalloc subdirectory of the memkind source. The jemalloc +source code has been kept close to the original form, and in particular +the build system has been lightly modified. + +## Run Requirements + +You will need to install required packages for applications, +which are using the memkind library for dynamic linking at run time: + +* **libnuma** +* **numactl** +* **pthread** + +## Kind Requirements + +| Memory kind | NUMA | HBW Memory | Hugepages | Device DAX | Filesystem supporting hole punching | +| ----------------------------- |:-----:|:-----------:|:---------:|:----------:|:-----------------------------------:| +| MEMKIND_DEFAULT | | | | | | +| MEMKIND_HUGETLB | X | X | X | | | +| MEMKIND_HBW | X | X | | | | +| MEMKIND_HBW_ALL | X | X | | | | +| MEMKIND_HBW_HUGETLB | X | X | X | | | +| MEMKIND_HBW_ALL_HUGETLB | X | X | X | | | +| MEMKIND_HBW_PREFERRED | X | X | | | | +| MEMKIND_HBW_PREFERRED_HUGETLB | X | X | X | | | +| MEMKIND_HBW_INTERLEAVE | X | X | | | | +| MEMKIND_REGULAR | X | | | | | +| MEMKIND_DAX_KMEM | X | | | X | | +| MEMKIND_DAX_KMEM_ALL | X | | | X | | +| MEMKIND_DAX_KMEM_PREFERRED | X | | | X | | +| PMEM kind | | | | | X | + +## Kernel +To correctly control of NUMA, huge pages and file-backed memory following +requirements regarding Linux kernel must be satisfied: + +* **NUMA** + +Requires kernel +[patch](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3964acd0dbec123aa0a621973a2a0580034b4788) +introduced in Linux v3.11 that impacts +functionality of the NUMA system calls. Red Hat has back-ported this patch to the +v3.10 kernel in the RHEL 7.0 GA release, so RHEL 7.0 onward supports +memkind even though this kernel version predates v3.11. + +* **Hugepages** + +Functionality related to hugepages allocation require patches +[patch1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e0ec90ee7e6f6cbaa6d59ffb48d2a7af5e80e61d) and +[patch2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=099730d67417dfee273e9b10ac2560ca7fac7eb9) +Without them physical memory may end up being located on incorrect NUMA node. + +* **2MB Pages** + +To use the interfaces for obtaining 2MB pages please be sure to follow the instructions +[here](https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt) and pay particular +attention to the use of the procfs files: + + /proc/sys/vm/nr_hugepages + /proc/sys/vm/nr_overcommit_hugepages + +for enabling the kernel's huge page pool. + +* **Filesystem supporting hole punching** + +To use the PMEM kind, please be sure that filesystem which is used for PMEM creation supports +[FALLOC_FL_PUNCH_HOLE](http://man7.org/linux/man-pages/man2/fallocate.2.html) flag. + +* **Device DAX** + +To use MEMKIND_DAX_KMEM_* kinds you need at least Linux Kernel 5.1 (with enabled DEV_DAX_KMEM Kernel option) and created DAX device. +If you have loaded dax_pmem_compat module instead of dax_pmem, please read +[this](https://pmem.io/ndctl/daxctl-migrate-device-model.html) article and migrate device model +to use alternative device dax drivers, e.g. kmem. + +If you want to migrate device model type: + + daxctl migrate-device-model + +To create a new DAX device you can type: + + ndctl create-namespace --mode=devdax --map=mem + +To display a list of created devices: + + ndctl list + +If you have already created device in another mode, you can reconfigure the device using: + + ndctl create-namespace --mode=devdax --map=mem --force -e namespaceX.Y + +Where namespaceX.Y means namespace you want to reconfigure. + +For more details about creating new namespace read [this](https://pmem.io/ndctl/ndctl-create-namespace.html). + +Conversion from device dax to NUMA node can be performed using following commands: + + daxctl reconfigure-device daxX.Y --mode=system-ram + +Where daxX.Y is DAX device you want to reconfigure. + +This will migrate device from device_dax to kmem driver. After this step daxctl should be able to +see devices in system-ram mode: + + daxctl list + +Example output after reconfigure dax2.0 as system-ram: + + [ + { + "chardev":"dax1.0", + "size":263182090240, + "target_node":3, + "mode":"devdax" + }, + { + "chardev":"dax2.0", + "size":263182090240, + "target_node":4, + "mode":"system-ram" + } + ] + +Also you should be able to check new NUMA node configuration by: + + numactl -H + +Example output, where NUMA node 4 is NUMA node created from persistent memory: + + available: 3 nodes (0-1,4) + node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 + node 0 size: 192112 MB + node 0 free: 185575 MB + node 1 cpus: 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 + node 1 size: 193522 MB + node 1 free: 193107 MB + node 4 cpus: + node 4 size: 250880 MB + node 4 free: 250879 MB + node distances: + node 0 1 4 + 0: 10 21 17 + 1: 21 10 28 + 4: 17 28 10 + +## NVDIMM volatile usage + +Memkind supports using persistent memory as an extension of DRAM. +This volatile memory solution is provided by the library with two separate ways described below. + +## DAX device + +NVDIMM memory as DAX device is supported by MEMKIND_DAX_KMEM_* kinds. With this solution +persistent memory will be seen in OS as separate NUMA nodes. + +Memkind allows two ways to use this kind: + +- first implicitly, by allowing memkind library for automatic recognition of NUMA nodes +created from persistent memory using [libdaxctl-devel](#dependencies) +- secondary explicitly, by using MEMKIND_DAX_KMEM_NODES environment variable set to +comma separated list of NUMA nodes which will be treated as NUMA nodes created from persistent memory, +this solution overrides the first one + +## DAX filesystem +PMEM kind supports the traditional malloc/free interfaces on a memory mapped file. +This allows the use of [persistent memory](https://pmem.io/) +as volatile memory, for cases where the region of persistent memory +is useful to an application, but when the application doesn't need it to be persistent. +PMEM kind is most useful when used with Direct Access storage +[DAX](https://www.kernel.org/doc/Documentation/filesystems/dax.txt), which is +memory-addressable persistent storage that supports load/store access without being paged via the system page cache. + +Application using memkind library supports managing a data placement: + +| Data placement | Memory kind | +|----------------|---------------------------| +| PMEM (fsdax) | PMEM kind | +| PMEM (devdax) | MEMKIND_DAX_KMEM kind | +| DRAM | e.g. MEMKIND_DEFAULT kind | + +Currently, the PMEM kind is supported only by the jemalloc heap manager. + +## The Detection Mechanism of the Kind +One of the notable features of the memkind is to detect the correct kind of previously allocated memory. + +| Operations | Memkind API function | +|---------------------------------------------|----------------------------------------| +| Freeing memory | memkind_free(kind, ptr) | +| Reallocating memory | memkind_realloc(kind, ptr, size) | +| Obtaining the size of allocated memory | memkind_malloc_usable_size(kind, ptr) | +| Reallocating memory to reduce fragmentation | memkind_defrag_reallocate(kind, ptr) | + +Operations above could be unified for all used memory kinds +by passing a NULL value as a kind to the functions mentioned above. + +For more details, please see the following +[example](https://github.com/memkind/memkind/blob/master/examples/pmem_free_with_unknown_kind.c). + +**Important Notes:** +The look up for correct kind could result in serious performance penalty, +which can be avoided by specifying a correct kind explicitly. + +## Setting Logging Mechanism +In memkind library logging mechanism could be enabled by setting MEMKIND_DEBUG +environment variable. Setting MEMKIND_DEBUG to "1" enables printing messages +like errors and general information about environment to stderr. + +## Setting Heap Manager +In memkind library heap management can be adjusted with MEMKIND_HEAP_MANAGER +environment variable, which allows for switching to one of the available +heap managers. +Values: +- JEMALLOC - sets the jemalloc heap manager +- TBB - sets Intel Threading Building Blocks heap manager. This option requires installed +Intel Threading Building Blocks library. + +If the MEMKIND_HEAP_MANAGER is not set then the jemalloc heap manager will be used by default. + +## Testing +All existing tests pass. For more information on how to execute tests +see the [CONTRIBUTING](CONTRIBUTING) file. + +When tests are run on a NUMA platform without high bandwidth memory +the MEMKIND_HBW_NODES environment variable is used in conjunction with +"numactl --membind" to force standard allocations to one NUMA node and +high bandwidth allocations through a different NUMA node. See next +section for more details. + + +## Simulating High Bandwidth Memory +A method for testing for the benefit of high bandwidth memory on a +dual socket Intel(R) Xeon(TM) system is to use the QPI bus to simulate +slow memory. This is not an accurate model of the bandwidth and +latency characteristics of the Intel's 2nd generation Intel(R) Xeon Phi(TM) +Product Family on package memory, but is a reasonable way to determine +which data structures rely critically on bandwidth. + +If the application a.out has been modified to use high bandwidth +memory with the memkind library then this can be done with numactl as +follows with the bash shell: + + export MEMKIND_HBW_NODES=0 + numactl --membind=1 --cpunodebind=0 a.out + +or with csh: + + setenv MEMKIND_HBW_NODES 0 + numactl --membind=1 --cpunodebind=0 a.out + +The MEMKIND_HBW_NODES environment variable set to zero will bind high +bandwidth allocations to NUMA node 0. The --membind=1 flag to numactl +will bind standard allocations, static and stack variables to NUMA +node 1. The --cpunodebind=0 option to numactl will bind the process +threads to CPUs associated with NUMA node 0. With this configuration +standard allocations will be fetched across the QPI bus, and high +bandwidth allocations will be local to the process CPU. + +## Notes +* Using memkind with Transparent Huge Pages enabled may result in + undesirably high memory footprint. To avoid that disable THP using following + [instruction](https://www.kernel.org/doc/Documentation/vm/transhuge.txt) + +## Status +Different interfaces can represent different maturity level +(as described in corresponding man pages). +Feedback on design and implementation is greatly appreciated. + +## Disclaimer +SEE [COPYING](COPYING) FILE FOR LICENSE INFORMATION. + +THIS SOFTWARE IS PROVIDED AS A DEVELOPMENT SNAPSHOT TO AID +COLLABORATION AND WAS NOT ISSUED AS A RELEASED PRODUCT BY INTEL. diff --git a/README.md b/README.md new file mode 120000 index 0000000..100b938 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/astyle.sh b/astyle.sh new file mode 100755 index 0000000..96b801b --- /dev/null +++ b/astyle.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Copyright (C) 2018 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ASTYLE_MIN_VER="3.1" +ASTYLE_OPT="--style=linux --indent=spaces=4 -S -r --max-continuation-indent=80 " +ASTYLE_OPT+="--max-code-length=80 --break-after-logical --indent-namespaces -z2 " +ASTYLE_OPT+="--align-pointer=name" +if ! ASTYLE=$(which astyle) +then + echo "Package astyle was not found. Unable to check source files format policy." >&2 + exit 1 +fi +ASTYLE_VER=$(astyle --version 2>&1 | awk '{print $NF}') +if (( $(echo "$ASTYLE_VER < $ASTYLE_MIN_VER" | bc -l) )); +then + echo "Minimal required version of astyle is $ASTYLE_MIN_VER. Detected version is $ASTYLE_VER" >&2 + echo "Unable to check source files format policy." >&2 + exit 1 +fi +$ASTYLE $ASTYLE_OPT ./*.c,*.cpp,*.h,*.hpp --exclude=jemalloc > astyle.out +if TEST=$(cat astyle.out | grep -c Formatted) +then + cat astyle.out + git --no-pager diff + echo "Please fix style issues as shown above" + exit 1 +else + echo "Source code is compliant with format policy. No style issues were found." + exit 0 +fi diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..8949097 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Copyright (C) 2014 - 2019 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +set -e + +# If the VERSION file does not exist, then create it based on git +# describe or if not in a git repo just set VERSION to 0.0.0. +# Determine VERSION scheme, based on git: +# -if HEAD is tag annotated - it is official release e.g. setting VERSION to "1.9.0" +# -if HEAD is not tag annotated - it is snapshot e.g. setting VERSION to "1.8.0+dev19+g1c93b2d" + +if [ ! -f VERSION ]; then + if [ -f .git/config ]; then + sha=$(git describe --long | awk -F- '{print $(NF)}') + release=$(git describe --long | awk -F- '{print $(NF-1)}') + version=$(git describe --long | sed -e "s|\(.*\)-$release-$sha|\1|" -e "s|-|+|g" -e "s|^v||") + if [ ${release} != "0" ]; then + echo "WARNING: No annotated tag referring to this commit was found, setting version to development build " 2>&1 + version=${version}+dev${release}+${sha} + else + echo "Annotated tag referring to this commit was found, setting version as an official release" 2>&1 + version=${version} + fi + else + echo "WARNING: VERSION file does not exist and working directory is not a git repository, setting version to 0.0.0" 2>&1 + version=0.0.0 + fi + echo $version > VERSION +fi + +autoreconf --install + diff --git a/autohbw/Makefile.mk b/autohbw/Makefile.mk new file mode 100644 index 0000000..9d2fd12 --- /dev/null +++ b/autohbw/Makefile.mk @@ -0,0 +1,37 @@ +# +# Copyright (C) 2014 - 2016 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +lib_LTLIBRARIES += autohbw/libautohbw.la \ + # end + +EXTRA_DIST += autohbw/autohbw_get_src_lines.pl + +autohbw_libautohbw_la_LIBADD = libmemkind.la + +autohbw_libautohbw_la_SOURCES = autohbw/autohbw.c + +clean-local: autohbw-clean + +autohbw-clean: + rm -f autohbw/*.gcno diff --git a/autohbw/autohbw.c b/autohbw/autohbw.c new file mode 100644 index 0000000..4bff27b --- /dev/null +++ b/autohbw/autohbw.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2015 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////////////////////////////////////////////////////////////////////////// +// File : autohbw.c +// Purpose: Library to automatically allocate HBW (MCDRAM) +// Author : Ruchira Sasanka (ruchira DOT sasanka AT intel DOT com) +// Date : Jan 30, 2015 +/////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AUTOHBW_EXPORT __attribute__((visibility("default"))) +#define AUTOHBW_INIT __attribute__((constructor)) + +//-2 = nothing is printed +//-1 = critical messages are printed +// 0 = no log messages for allocations are printed but INFO messages are printed +// 1 = a log message is printed for each allocation (Default) +// 2 = a log message is printed for each allocation with a backtrace +enum { + ALWAYS = -1, + INFO, + ALLOC, + VERBOSE +}; + +// Default is to print allocations +static int LogLevel = ALLOC; + +// Allocations of size greater than low limit promoted to HBW memory. +// If there is a high limit specified, allocations larger than this limit +// will not be allocated in HBW. +static size_t HBWLowLimit = 1 * 1024 * 1024; +static size_t HBWHighLimit = -1ull; + +// Whether we have initialized HBW arena of memkind library -- by making +// a dummy call to it. HBW arena (and hence any memkind_* call with kind +// HBW) must NOT be used until this flag is set true. +static bool MemkindInitDone = false; + +// Following is the type of HBW memory that is allocated using memkind. +// By changing this type, this library can be used to allocate other +// types of memory types (e.g., MEMKIND_HUGETLB, MEMKIND_GBTLB, +// MEMKIND_HBW_HUGETLB etc.) +static memkind_t hbw_kind; + +// API control for HBW allocations. +static bool isAutoHBWEnabled = true; + +#define LOG(level, ...) \ + do { \ + if (LogLevel >= level) { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + } while (0) + +static bool isAllocInHBW(size_t size) +{ + if (!MemkindInitDone) + return false; + + if (!isAutoHBWEnabled) + return false; + + if (size < HBWLowLimit) + return false; + + if (size > HBWHighLimit) + return false; + + return true; +} + +// Returns the limit in bytes using a limit value and a multiplier +// character like K, M, G +static size_t getLimit(size_t limit, char lchar) +{ + // Now read the trailing character (e.g., K, M, G) + // Based on the character, determine the multiplier + if ((limit > 0) && isalpha(lchar)) { + long mult = 1; + + switch (toupper(lchar)) { + case 'G': + mult *= 1024; + case 'M': + mult *= 1024; + case 'K': + mult *= 1024; + } + + // check for overflow, saturate at max + if (limit >= -1ull / mult) + return -1ull; + + return limit * mult; + } + + return limit; +} + +// Once HBWLowLimit (and HBWHighLimit) are set, call this method to +// inform the user about the size range of arrays that will be allocated +// in HBW +static void printLimits() +{ + // Inform according to the limits set + if ((HBWLowLimit > 0) && (HBWHighLimit < -1ull)) { + // if both high and low limits are specified, we use a range + LOG(INFO, "INFO: Allocations between %ldK - %ldK will be allocated in " + "HBW. Set AUTO_HBW_SIZE=X:Y to change this limit.\n", + HBWLowLimit / 1024, HBWHighLimit / 1024); + } else if (HBWLowLimit > 0) { + // if only a low limit is provided, use that + LOG(INFO, "INFO: Allocations greater than %ldK will be allocated in HBW." + " Set AUTO_HBW_SIZE=X:Y to change this limit.\n", + HBWLowLimit / 1024); + } else if (HBWHighLimit < -1ull) { + // if only a high limit is provided, use that + LOG(INFO, "INFO: Allocations smaller than %ldK will be allocated in HBW. " + "Set AUTO_HBW_SIZE=X:Y to change this limit.\n", + HBWHighLimit / 1024); + } else { + // none of limits is set to non-edge value, everything goes to HBW + LOG(INFO, "INFO: All allocation will be done in HBW."); + } +} + +struct kind_name_t { + memkind_t *kind; + const char *name; +}; + +static struct kind_name_t named_kinds[] = { + { &MEMKIND_DEFAULT, "memkind_default" }, + { &MEMKIND_HUGETLB, "memkind_hugetlb" }, + { &MEMKIND_INTERLEAVE, "memkind_interleave" }, + { &MEMKIND_HBW, "memkind_hbw" }, + { &MEMKIND_HBW_PREFERRED, "memkind_hbw_preferred" }, + { &MEMKIND_HBW_HUGETLB, "memkind_hbw_hugetlb" }, + { &MEMKIND_HBW_PREFERRED_HUGETLB, "memkind_hbw_preferred_hugetlb" }, + { &MEMKIND_HBW_GBTLB, "memkind_hbw_gbtlb" }, + { &MEMKIND_HBW_PREFERRED_GBTLB, "memkind_hbw_preferred_gbtlb" }, + { &MEMKIND_GBTLB, "memkind_gbtlb" }, + { &MEMKIND_HBW_INTERLEAVE, "memkind_hbw_interleave" }, +}; + +static memkind_t get_kind_by_name(const char *name) +{ + int i; + for (i = 0; i < sizeof(named_kinds) / sizeof(named_kinds[0]); ++i) + if (strcasecmp(named_kinds[i].name, name) == 0) + return *named_kinds[i].kind; + + return 0; +} + +// Read from the environment and sets global variables +// Env variables are: +// AUTO_HBW_SIZE = gives the size for auto HBW allocation +// AUTO_HBW_LOG = gives logging level +static void setEnvValues() +{ + // STEP: Read the log level from the env variable. Do this early because + // printing depends on this + char *log_str = secure_getenv("AUTO_HBW_LOG"); + if (log_str && strlen(log_str)) { + int level = atoi(log_str); + LogLevel = level; + LOG(ALWAYS, "INFO: Setting log level to %d\n", LogLevel); + } + + if (LogLevel == INFO) { + LOG(INFO, "INFO: HBW allocation stats will not be printed. " + "Set AUTO_HBW_LOG to enable.\n"); + } else if (LogLevel == ALLOC) { + LOG(INFO, "INFO: Only HBW allocations will be printed. " + "Set AUTO_HBW_LOG to disable/enable.\n"); + } else if (LogLevel == VERBOSE) { + LOG(INFO, "INFO: HBW allocation with backtrace info will be printed. " + "Set AUTO_HBW_LOG to disable.\n"); + } + + // Set the memory type allocated by this library. By default, it is + // MEMKIND_HBW, but we can use this library to allocate other memory + // types + const char *memtype_str = secure_getenv("AUTO_HBW_MEM_TYPE"); + if (memtype_str && strlen(memtype_str)) { + // Find the memkind_t using the name the user has provided in the env variable + memkind_t mty = get_kind_by_name(memtype_str); + if (mty != 0) { + hbw_kind = mty; + LOG(INFO, "INFO: Setting HBW memory type to %s\n", memtype_str); + } else { + LOG(ALWAYS, "WARN: Memory type %s not recognized. Using default type\n", + memtype_str); + } + } + + // STEP: Set the size limits (thresholds) for HBW allocation + // + // Reads the environment variable + const char *size_str = secure_getenv("AUTO_HBW_SIZE"); + if (size_str) { + size_t lowlim = HBWLowLimit / 1024; + size_t highlim = HBWHighLimit / 1024; + char lowC = 'K', highC = 'K'; + + if (size_str) { + char *ptr = (char *)size_str; + lowlim = strtoll(ptr, &ptr, 10); + if (*ptr != 0 && *ptr != ':') + lowC = *ptr++; + else + lowC = ' '; + + if (*ptr++ == ':') { + highlim = strtoll(ptr, &ptr, 10); + if (*ptr) + highC = *ptr; + else + highC = ' '; + } + + LOG(INFO, "INFO: lowlim=%zu(%c), highlim=%zu(%c)\n", lowlim, lowC, highlim, + highC); + } + + HBWLowLimit = getLimit(lowlim, lowC); + HBWHighLimit = getLimit(highlim, highC); + + if (HBWLowLimit >= HBWHighLimit) { + LOG(ALWAYS, "WARN: In AUTO_HBW_SIZE=X:Y, X cannot be greater or equal to Y. " + "None of allocations will use HBW memory.\n"); + } + } else { + // if the user did not specify any limits, inform that we are using + // default limits + LOG(INFO, "INFO: Using default values for array size thresholds. " + "Set AUTO_HBW_SIZE=X:Y to change.\n"); + } + + // inform the user about limits + printLimits(); +} + +// This function is executed at library load time. +// Initialize HBW arena by making a dummy allocation/free at library load +// time. Until HBW initialization is complete, we must not call any +// allocation routines with HBW as kind. +static void AUTOHBW_INIT autohbw_load(void) +{ + // First set the default memory type this library allocates. This can + // be overridden by env variable + // Note: 'memkind_hbw_preferred' will allow falling back to DDR but + // 'memkind_hbw will not' + // Note: If HBM is not installed on a system, memkind_hbw_preferred call + // would fail. Therefore, we need to check for availability first. + if (memkind_check_available(MEMKIND_HBW) != 0) { + LOG(ALWAYS, "WARN: *** No HBM found in system. Will use default (DDR) " + "OR user specified type ***\n"); + hbw_kind = MEMKIND_DEFAULT; + } else { + hbw_kind = MEMKIND_HBW_PREFERRED; + } + + // Read any env variables. This has to be done first because DbgLevel + // is set using env variables and debug printing is used below + setEnvValues(); // read any env variables + + LOG(INFO, "INFO: autohbw.so loaded!\n"); + + // dummy HBW call to initialize HBW arena + void *pp = memkind_malloc(hbw_kind, 16); + if (pp == 0) { + LOG(ALWAYS, "\t-HBW init call FAILED. " + "Is required memory type present on your system?\n"); + abort(); + } + + LOG(ALWAYS, "\t-HBW int call succeeded\n"); + memkind_free(hbw_kind, pp); + + MemkindInitDone = true; // enable HBW allocation +} + +static void *MemkindMalloc(size_t size) +{ + LOG(VERBOSE, "In my memkind malloc sz:%ld ... ", size); + + bool useHbw = isAllocInHBW(size); + memkind_t kind = useHbw ? hbw_kind : MEMKIND_DEFAULT; + + if (useHbw) + LOG(VERBOSE, "\tHBW"); + + void *ptr = memkind_malloc(kind, size); + + LOG(VERBOSE, "\tptr:%p\n", ptr); + return ptr; +} + +static void *MemkindCalloc(size_t nmemb, size_t size) +{ + LOG(VERBOSE, "In my memkind calloc sz:%ld ..", size * nmemb); + + bool useHbw = isAllocInHBW(size); + memkind_t kind = useHbw ? hbw_kind : MEMKIND_DEFAULT; + + if (useHbw) + LOG(VERBOSE, "\tHBW"); + + void *ptr = memkind_calloc(kind, nmemb, size); + + LOG(VERBOSE, "\tptr:%p\n", ptr); + return ptr; +} + +static void *MemkindRealloc(void *ptr, size_t size) +{ + LOG(VERBOSE, "In my memkind realloc sz:%ld, p1:%p ..", size, ptr); + + bool useHbw = isAllocInHBW(size); + memkind_t kind = useHbw ? hbw_kind : MEMKIND_DEFAULT; + + if (useHbw) + LOG(VERBOSE, "\tHBW"); + + void *nptr = memkind_realloc(kind, ptr, size); + + LOG(VERBOSE, "\tptr=%p\n", nptr); + return nptr; +} + +static int MemkindAlign(void **memptr, size_t alignment, size_t size) +{ + LOG(VERBOSE, "In my memkind align sz:%ld .. ", size); + + bool useHbw = isAllocInHBW(size); + memkind_t kind = useHbw ? hbw_kind : MEMKIND_DEFAULT; + + if (useHbw) + LOG(VERBOSE, "\tHBW"); + + int ret = memkind_posix_memalign(kind, memptr, alignment, size); + + LOG(VERBOSE, "\tptr:%p\n", *memptr); + return ret; +} + +// memkind_free does not need the exact kind, if kind is 0. Then +// the library can figure out the proper kind itself. +static void MemkindFree(void *ptr) +{ + // avoid to many useless logs + if (ptr) + LOG(VERBOSE, "In my memkind free, ptr:%p\n", ptr); + memkind_free(0, ptr); +} + +//-------------------------------------------------------------------------- +// ------------------ Public API of autohbw ---------------------- +//-------------------------------------------------------------------------- + +AUTOHBW_EXPORT void enableAutoHBW() +{ + isAutoHBWEnabled = true; + LOG(INFO, "INFO: HBW allocations enabled by application (for this rank)\n"); +} + +AUTOHBW_EXPORT void disableAutoHBW() +{ + isAutoHBWEnabled = false; + LOG(INFO, "INFO: HBW allocations disabled by application (for this rank)\n"); +} + +AUTOHBW_EXPORT void *malloc(size_t size) +{ + return MemkindMalloc(size); +} + +AUTOHBW_EXPORT void *calloc(size_t nmemb, size_t size) +{ + return MemkindCalloc(nmemb, size); +} + +AUTOHBW_EXPORT void *realloc(void *ptr, size_t size) +{ + return MemkindRealloc(ptr, size); +} + +AUTOHBW_EXPORT int posix_memalign(void **memptr, size_t alignment, size_t size) +{ + return MemkindAlign(memptr, alignment, size); +} + +// Warn about deprecated function usage. +AUTOHBW_EXPORT void *valloc(size_t size) +{ + LOG(ALWAYS, "use of deprecated valloc. Use posix_memalign instead\n"); + void *memptr = 0; + size_t boundary = sysconf(_SC_PAGESIZE); + int status = MemkindAlign(&memptr, boundary, size); + if (status == 0 && memptr != 0) + return memptr; + + return 0; +} + +// Warn about deprecated function usage. +AUTOHBW_EXPORT void *memalign(size_t boundary, size_t size) +{ + LOG(ALWAYS, "use of deprecated memalign. Use posix_memalign instead\n"); + void *memptr = 0; + int status = MemkindAlign(&memptr, boundary, size); + if (status == 0 && memptr != 0) + return memptr; + + return 0; +} + +AUTOHBW_EXPORT void free(void *ptr) +{ + return MemkindFree(ptr); +} diff --git a/autohbw/autohbw_README b/autohbw/autohbw_README new file mode 100644 index 0000000..cf23a0f --- /dev/null +++ b/autohbw/autohbw_README @@ -0,0 +1,92 @@ +README for auothbw library +Ruchira Sasanka (ruchira DOT sasanka AT intel DOT com) +2015 April 8 + +PURPOSE +------- +The autohbw library is used to automatically allocate high-bandwidth (HBW) +memory without any modifications to source code of your application. +This library intercepts the standard heap allocations (e.g., malloc, calloc) +in your program so that it can serve those allocations out of HBW memory. + +There are two libraries installed at the same location as memkind library: + 1) libautohbw.so -- dynamic library + 2) libautohbw.a -- static library (provided for static linking) + +USAGE +----- +To use the dynamic library, insert LD_PRELOAD=libautohbw.so and libmekind.so +before your commandline. For instance, + + LD_PRELOAD=libautohbw.so /bin/ls + +executes Unix ls utility with autohbw library. You can execute the +above command on the prompt or put it in a shell script. An example of +the latter approach is given in ./autohbw_test.sh. Make sure that +LD_LIBRARY_PATH environment variable contains the path to libautohbw.so +and libmekind.so before you exeute the above command. + +To use the statically linked library, insert -lautohbw -lmemkind +on your link line. You will have to provide the library path with -L to +point to the above libraries. If you are linking your program statically +(e.g., with -static or -fast flags in ifort/icc), you must use the static +version of autohbw library (libautohbw.a). + +It is possible to temporarily disable/enable automatic HBM allocations by +calling disableAutoHBW() and enableAutoHBW() in your source code. To call +these routines, please include autohbw_api.h header file and link with +-lautohbw. + + +Usage with MPI programs +----------------------- +To use with MPI programs, you need to create a shell script to do the +LD_PRELOAD. E.g., + mpirun -n 2 ./autohbw_test.sh + +ENVIRONMENT VARIABLES +--------------------- +The following environment variables control the behavior of the autohbw +library: + + AUTO_HBW_SIZE=x[:y] + Indicates that any allocation larger than x and smaller than y should be + allocated in HBW memory. x and y can be followed by a K, M, or G to + indicate the size in Kilo/Memga/Giga bytes (e.g., 4K, 3M, 2G). + Examples: + AUTO_HBW_SIZE=4K # all allocation larger than 4K allocated in HBW + AUTO_HBW_SIZE=1M:5M # allocations between 1M and 5M allocated in HBW + + + AUTO_HBW_LOG=level + Sets the value of logging (printing) level. If level is: + -1 = no messages are printed + 0 = no log messages for allocations are printed but INFO messages + are printed + 1 = a log message is printed for each allocation (Default) + 2 = a log message is printed for each allocation with a backtrace + Redirect this output and use autohbw_get_src_lines.pl to find + source lines for each allocation. Your application must be compiled + with -g to see source lines. + Notes: + 1. Logging adds extra overhead. Therefore, performance critical runs, + logging level should be 0 + 2. The amount of free memory printed with log messages is only + approximate -- e.g. pages that are not touched yet are excluded + Examples: + AUTO_HBW_LOG=1 + + + AUTO_HBW_MEM_TYPE=memory_type + Sets the type of memory type that should be automatically allocated. By + default, this type is MEMKIND_HBW_PREFERRED, if MCDRAM is found in your + system; otherwise, the default is MEMKIND_DEFAULT. The names of memory + types are definedin memkind(3) man page. If you are requesting any huge + TLB pages, pleasemake sure that the requested type is currently enabled + in your OS. + Examples: + AUTO_HBW_MEM_TYPE=MEMKIND_HBW_PREFERRED (default, if MCDRAM present) + AUTO_HBW_MEM_TYPE=MEMKIND_DEFAULT (default, if MCDRAM absent) + AUTO_HBW_MEM_TYPE=MEMKIND_HBW_HUGETLB + AUTO_HBW_MEM_TYPE=MEMKIND_HUGETLB + diff --git a/autohbw/autohbw_api.h b/autohbw/autohbw_api.h new file mode 100644 index 0000000..45f666a --- /dev/null +++ b/autohbw/autohbw_api.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 - 2016 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////////////////////////////////////////////////////////////////////////// +// File : autohbw_api.h +// Purpose: Header file to include, to use API calls to AutoHBW +// Author : Ruchira Sasanka (ruchira.sasanka AT intel.com) +// Date : Jan 30, 2015 +/////////////////////////////////////////////////////////////////////////// + +#ifndef AUTOHBW_API_H +#define AUTOHBW_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Temporarily enable HBM allocations +void enableAutoHBW(); + +// Temporarily disable HBM allocations +void disableAutoHBW(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/autohbw/autohbw_get_src_lines.pl b/autohbw/autohbw_get_src_lines.pl new file mode 100644 index 0000000..81ccb67 --- /dev/null +++ b/autohbw/autohbw_get_src_lines.pl @@ -0,0 +1,106 @@ +#!/usr/bin/perl +# +# Copyright (C) 2015 - 2016 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +use strict; + +my $usage = "Usage: get_autohbw_srclines.pl output_log_of_AutoHBW executable"; + +# Check for 2 arguments +# +if (@ARGV != 2) { + print $usage, "\n"; + exit; +} + +# Read the command line arguments +# +my $LogF = shift @ARGV; +my $BinaryF = shift @ARGV; + +&main(); + +sub main { + + + print("Info: Reading AutoHBW log from: $LogF\n"); + print("Info: Binary file: $BinaryF\n"); + + # open the log file produced by AutoHBM and look at lines starting + # with Log + open LOGF, "grep Log $LogF |" or die "Can't open log file $LogF"; + + my $line; + + # Read each log line + # + while ($line = ) { + + # if the line contain 3 backtrace addresses, try to find the source + # lines for them + # + if ($line =~ /^(Log:.*)Backtrace:.*0x([0-9a-f]+).*0x([0-9a-f]+).*0x([0-9a-f]+)/ ) { + + # Read the pointers + # + my @ptrs; + + my $pre = $1; + + $ptrs[0] = $2; + $ptrs[1] = $3; + $ptrs[2] = $4; + + # prints the first portion of the line + # + print $pre, "\n"; + + # for each of the pointers, lookup its source line using + # addr2line and print the src line(s) if found + # + my $i=0; + for ($i=0; $i < @ptrs; $i++) { + + my $addr = $ptrs[$i]; + + open SRCL, "addr2line -e $BinaryF 0x$addr |" + or die "addr2line fail"; + + + my $srcl = ; + + if ($srcl =~ /^\?/) { + + } else { + + print "\t- Src: $srcl"; + } + + } + + } + + } + +} diff --git a/autohbw/autohbw_test.sh b/autohbw/autohbw_test.sh new file mode 100755 index 0000000..52cf313 --- /dev/null +++ b/autohbw/autohbw_test.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Copyright (C) 2015 - 2016 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# The following is needed if your system does not really have HBW nodes. +# Please see 'man memkind' for a description of this variable +# +# export MEMKIND_HBW_NODES=0 + +# Set any autohbw env variables +# +export AUTO_HBW_SIZE=4K + +# Make sure you have set LD_LIBRARY_PATH to lib directory with libautohbw.so +# and libmemkind.so +# +LD_PRELOAD=libautohbw.so:libmemkind.so /bin/ls diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..6dfd578 --- /dev/null +++ b/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Copyright (C) 2016 - 2019 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -e + +cd $(dirname $0) +EXTRA_CONF=$@ + +./autogen.sh +./configure $EXTRA_CONF + +#use V=1 for full cmdlines of build +make all -j`nproc` +make checkprogs -j`nproc` diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..95116a1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,234 @@ +# +# Copyright (C) 2014 - 2019 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.63]) +AC_INIT([memkind],m4_esyscmd([tr -d '\n' < VERSION])) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR([memkind.spec.mk]) + +AM_INIT_AUTOMAKE([-Wall -Werror foreign 1.11 silent-rules subdir-objects parallel-tests tar-pax]) +AM_SILENT_RULES([yes]) + +# Checks for programs and libraries. +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +AC_PROG_CXX +AC_PROG_CC +AC_OPENMP +AC_CHECK_LIB(numa, numa_available, [], [AC_MSG_ERROR([libnuma is required dependency])]) +AX_PTHREAD([LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC"], + [AC_MSG_ERROR([pthreads are required dependency])]) + +AM_PROG_CC_C_O + +#============================tls=============================================== +# Check for thread local storage support +AC_ARG_ENABLE([tls], + [AS_HELP_STRING([--enable-tls], [Enable thread-local storage (__thread keyword)])], +[if test "x$enable_tls" = "xyes" ; then + enable_tls="1" +else + enable_tls="0" +fi +], +[enable_tls="0"] +) +if test "x${enable_tls}" = "x1" ; then +AC_MSG_CHECKING([for TLS support]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[ + __thread int x; +]], [[ + x = 1234; +]])], + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no]) + enable_tls="0") +fi +if test "x${enable_tls}" = "x1" ; then + AC_DEFINE([MEMKIND_TLS], [ ], [Enables TLS usage for mapping arenas to threads]) +fi +AC_SUBST([enable_tls]) + +#============================decorators======================================== +AC_ARG_ENABLE([decorators], + [AS_HELP_STRING([--enable-decorators], [Enable decorators])], +[if test "x$enable_decorators" = "xyes" ; then + enable_decorators="1" +else + enable_decorators="0" +fi +], +[enable_decorators="0"] +) +if test "x${enable_decorators}" = "x1" ; then + AC_DEFINE([MEMKIND_DECORATION_ENABLED], [ ], [Enables decorators]) +fi +AC_SUBST([enable_decorators]) + +#============================debug============================================= +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], [Build debugging code and compile with -O0 -g])], +[if test "x$enable_debug" = "xno" ; then + enable_debug="0" +else + enable_debug="1" +fi +], +[enable_debug="0"] +) +if test "x$enable_debug" = "x1" ; then + AC_DEFINE([MEMKIND_DEBUG], [ ], [Enables code for debugging]) + CFLAGS="$CFLAGS -O0 -g" + CXXFLAGS="$CXXFLAGS -O0 -g" +fi +AC_SUBST([enable_debug]) + +#============================gcov============================================== +AC_ARG_ENABLE([gcov], + [AS_HELP_STRING([--enable-gcov], [Build code with gcov instructions])], +[if test "x$enable_gcov" = "xno" ; then + enable_gcov="0" +else + enable_gcov="1" +fi +], +[enable_gcov="0"] +) +if test "x$enable_gcov" = "x1" ; then + CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage" + CXXFLAGS="$CXXFLAGS -O0 -fprofile-arcs -ftest-coverage" +fi +AC_SUBST([enable_gcov]) + +#============================secure_flags====================================== +AC_ARG_ENABLE([secure], + [AS_HELP_STRING([--enable-secure], [Build library with security enchantments])], +[if test "x$enable_secure" = "xno" ; then + enable_secure="0" +else + enable_secure="1" +fi +], +[enable_secure="1"] +) +if test "x$enable_secure" = "x1" ; then + CFLAGS="$CFLAGS -fstack-protector" + LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" + + if test "$CFLAGS" != "${CFLAGS%-O0*}" ; then # if CFLAGS contains -O0 + echo "WARNING: Could not apply FORTIFY_SOURCE=2 due to lack of optimization (-O0)" + else + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" #FORTITFY_SOURCE does not work with -O0 (ex. if enable_debug=1 or enable_gcov=1) + fi +fi + +AC_SUBST([enable_secure]) + +#============================tcache_max_size_class====================== + +tcache_max_size_class=12; +AC_DEFINE_UNQUOTED([JEMALLOC_TCACHE_CLASS], $tcache_max_size_class, + [Maximum size class (log base 2) to cache in jemalloc tcache]) + +AC_SUBST(tcache_max_size_class) + +#============================auto_arenas================================ +auto_arenas=256; +AC_DEFINE_UNQUOTED([ARENA_LIMIT_DEFAULT_KIND], $auto_arenas, + [Maximum number of automatic managed arenas by jemalloc (used by MEMKIND_DEFAULT)]) + +AC_SUBST(auto_arenas) + +#============================arena_limit======================================= +arena_limit=256; +AC_ARG_VAR(ARENA_LIMIT, + [Upper bound for number of arenas per kind, if set to 0 then no limit] +) +if test "$ARENA_LIMIT" != "" ; then + arena_limit=$ARENA_LIMIT; +fi + +AC_DEFINE_UNQUOTED([ARENA_LIMIT_PER_KIND], $arena_limit, [Upper bound for number of arenas per kind]) + +#============================memkind_prefix======================================= +memkind_prefix=jemk_; +AC_ARG_VAR(MEMKIND_PREFIX, + [Prefix used for all jemalloc public API under memkind, default value jemk_] +) +if test "$MEMKIND_PREFIX" != "" ; then + memkind_prefix=$MEMKIND_PREFIX; +fi + +AC_SUBST(memkind_prefix) + +#===============================daxctl========================================= +AC_ARG_ENABLE([daxctl], + [AS_HELP_STRING([--enable-daxctl], [Build library with daxctl support])], +[if test "x$enable_daxctl" = "xno" ; then + enable_daxctl="0" +else + enable_daxctl="1" +fi +], +[enable_daxctl="1"] +) +if test "x$enable_daxctl" = "x1" ; then + AC_CHECK_LIB(daxctl, daxctl_dev_get_memory, [daxctl_kmem=yes], [daxctl_kmem=no]) +fi +if test $daxctl_kmem = "yes" ; then + AC_DEFINE([MEMKIND_DAXCTL_KMEM], [1], [Automatic recognition of PMEM as system memory in MEMKIND_DAX_KMEM]) + AC_SUBST(DAXCTL_LIBS, [-ldaxctl]) + LDFLAGS="$LDFLAGS -ldaxctl" +fi +AC_SUBST([enable_daxctl]) + +#============================cxx11============================================= + +AX_CXX_COMPILE_STDCXX_11([noext], [optional]) +AM_CONDITIONAL([HAVE_CXX11], [test "x$HAVE_CXX11" = x1]) + +LT_PREREQ([2.2]) +LT_INIT + +AC_CONFIG_FILES([Makefile memkind.pc]) + +AC_OUTPUT +AC_MSG_RESULT([=================================================================================]) +AC_MSG_RESULT([ + Memkind version $VERSION]) +if test $daxctl_kmem = "yes" ; then +AC_MSG_RESULT([ + Automatic recognition of PMEM NUMA in MEMKIND_DAX_KMEM is enabled]) +else +AC_MSG_RESULT([ + Automatic recognition of PMEM NUMA in MEMKIND_DAX_KMEM is disabled + To enable this feature please install libdaxctl-devel v66 or later + and run configure again]) +fi +AC_MSG_RESULT([=================================================================================]) diff --git a/copying_headers/MANIFEST.EXEMPT b/copying_headers/MANIFEST.EXEMPT new file mode 100644 index 0000000..0e6326d --- /dev/null +++ b/copying_headers/MANIFEST.EXEMPT @@ -0,0 +1,347 @@ +.codecov.yml +.gitignore +.travis.yml +AUTHORS +CONTRIBUTING +COPYING +ChangeLog +NEWS +PULL_REQUEST_TEMPLATE.md +README +VERSION +autohbw/autohbw_README +examples/README +include/memkind/internal/tbb_mem_pool_policy.h +jemalloc/.appveyor.yml +jemalloc/.autom4te.cfg +jemalloc/.gitattributes +jemalloc/.gitignore +jemalloc/.travis.yml +jemalloc/autogen.sh +jemalloc/bin/jemalloc-config.in +jemalloc/bin/jemalloc.sh.in +jemalloc/bin/jeprof.in +jemalloc/build-aux/config.guess +jemalloc/build-aux/config.sub +jemalloc/build-aux/install-sh +jemalloc/ChangeLog +jemalloc/config.stamp.in +jemalloc/configure.ac +jemalloc/COPYING +jemalloc/doc/html.xsl.in +jemalloc/doc/jemalloc.xml.in +jemalloc/doc/manpages.xsl.in +jemalloc/doc/stylesheet.xsl +jemalloc/include/jemalloc/internal/arena_externs.h +jemalloc/include/jemalloc/internal/arena_inlines_a.h +jemalloc/include/jemalloc/internal/arena_inlines_b.h +jemalloc/include/jemalloc/internal/arena_stats.h +jemalloc/include/jemalloc/internal/arena_structs_a.h +jemalloc/include/jemalloc/internal/arena_structs_b.h +jemalloc/include/jemalloc/internal/arena_types.h +jemalloc/include/jemalloc/internal/assert.h +jemalloc/include/jemalloc/internal/atomic.h +jemalloc/include/jemalloc/internal/atomic_c11.h +jemalloc/include/jemalloc/internal/atomic_gcc_atomic.h +jemalloc/include/jemalloc/internal/atomic_gcc_sync.h +jemalloc/include/jemalloc/internal/atomic_msvc.h +jemalloc/include/jemalloc/internal/background_thread_externs.h +jemalloc/include/jemalloc/internal/background_thread_inlines.h +jemalloc/include/jemalloc/internal/background_thread_structs.h +jemalloc/include/jemalloc/internal/base_externs.h +jemalloc/include/jemalloc/internal/base_inlines.h +jemalloc/include/jemalloc/internal/base_structs.h +jemalloc/include/jemalloc/internal/base_types.h +jemalloc/include/jemalloc/internal/bin.h +jemalloc/include/jemalloc/internal/bin_stats.h +jemalloc/include/jemalloc/internal/bin_types.h +jemalloc/include/jemalloc/internal/bitmap.h +jemalloc/include/jemalloc/internal/bit_util.h +jemalloc/include/jemalloc/internal/cache_bin.h +jemalloc/include/jemalloc/internal/ckh.h +jemalloc/include/jemalloc/internal/ctl.h +jemalloc/include/jemalloc/internal/div.h +jemalloc/include/jemalloc/internal/emitter.h +jemalloc/include/jemalloc/internal/extent_dss.h +jemalloc/include/jemalloc/internal/extent_externs.h +jemalloc/include/jemalloc/internal/extent_inlines.h +jemalloc/include/jemalloc/internal/extent_mmap.h +jemalloc/include/jemalloc/internal/extent_structs.h +jemalloc/include/jemalloc/internal/extent_types.h +jemalloc/include/jemalloc/internal/hash.h +jemalloc/include/jemalloc/internal/hook.h +jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h +jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in +jemalloc/include/jemalloc/internal/jemalloc_internal_externs.h +jemalloc/include/jemalloc/internal/jemalloc_internal_includes.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_a.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_b.h +jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_c.h +jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h +jemalloc/include/jemalloc/internal/jemalloc_internal_types.h +jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in +jemalloc/include/jemalloc/internal/large_externs.h +jemalloc/include/jemalloc/internal/log.h +jemalloc/include/jemalloc/internal/malloc_io.h +jemalloc/include/jemalloc/internal/mutex.h +jemalloc/include/jemalloc/internal/mutex_pool.h +jemalloc/include/jemalloc/internal/mutex_prof.h +jemalloc/include/jemalloc/internal/nstime.h +jemalloc/include/jemalloc/internal/pages.h +jemalloc/include/jemalloc/internal/ph.h +jemalloc/include/jemalloc/internal/private_namespace.sh +jemalloc/include/jemalloc/internal/private_symbols.sh +jemalloc/include/jemalloc/internal/prng.h +jemalloc/include/jemalloc/internal/prof_externs.h +jemalloc/include/jemalloc/internal/prof_inlines_a.h +jemalloc/include/jemalloc/internal/prof_inlines_b.h +jemalloc/include/jemalloc/internal/prof_structs.h +jemalloc/include/jemalloc/internal/prof_types.h +jemalloc/include/jemalloc/internal/public_namespace.sh +jemalloc/include/jemalloc/internal/public_unnamespace.sh +jemalloc/include/jemalloc/internal/ql.h +jemalloc/include/jemalloc/internal/qr.h +jemalloc/include/jemalloc/internal/quantum.h +jemalloc/include/jemalloc/internal/rb.h +jemalloc/include/jemalloc/internal/rtree.h +jemalloc/include/jemalloc/internal/rtree_tsd.h +jemalloc/include/jemalloc/internal/safety_check.h +jemalloc/include/jemalloc/internal/sc.h +jemalloc/include/jemalloc/internal/seq.h +jemalloc/include/jemalloc/internal/smoothstep.h +jemalloc/include/jemalloc/internal/smoothstep.sh +jemalloc/include/jemalloc/internal/spin.h +jemalloc/include/jemalloc/internal/stats.h +jemalloc/include/jemalloc/internal/sz.h +jemalloc/include/jemalloc/internal/tcache_externs.h +jemalloc/include/jemalloc/internal/tcache_inlines.h +jemalloc/include/jemalloc/internal/tcache_structs.h +jemalloc/include/jemalloc/internal/tcache_types.h +jemalloc/include/jemalloc/internal/test_hooks.h +jemalloc/include/jemalloc/internal/ticker.h +jemalloc/include/jemalloc/internal/tsd.h +jemalloc/include/jemalloc/internal/tsd_generic.h +jemalloc/include/jemalloc/internal/tsd_malloc_thread_cleanup.h +jemalloc/include/jemalloc/internal/tsd_tls.h +jemalloc/include/jemalloc/internal/tsd_types.h +jemalloc/include/jemalloc/internal/tsd_win.h +jemalloc/include/jemalloc/internal/util.h +jemalloc/include/jemalloc/internal/witness.h +jemalloc/include/jemalloc/jemalloc.sh +jemalloc/include/jemalloc/jemalloc_defs.h.in +jemalloc/include/jemalloc/jemalloc_macros.h.in +jemalloc/include/jemalloc/jemalloc_mangle.sh +jemalloc/include/jemalloc/jemalloc_protos.h.in +jemalloc/include/jemalloc/jemalloc_rename.sh +jemalloc/include/jemalloc/jemalloc_typedefs.h.in +jemalloc/include/msvc_compat/C99/stdbool.h +jemalloc/include/msvc_compat/C99/stdint.h +jemalloc/include/msvc_compat/strings.h +jemalloc/include/msvc_compat/windows_extra.h +jemalloc/INSTALL.md +jemalloc/jemalloc.pc.in +jemalloc/m4/ax_cxx_compile_stdcxx.m4 +jemalloc/Makefile.in +jemalloc/msvc/jemalloc_vc2015.sln +jemalloc/msvc/jemalloc_vc2017.sln +jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +jemalloc/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj +jemalloc/msvc/projects/vc2015/test_threads/test_threads.vcxproj.filters +jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj +jemalloc/msvc/projects/vc2017/jemalloc/jemalloc.vcxproj.filters +jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj +jemalloc/msvc/projects/vc2017/test_threads/test_threads.vcxproj.filters +jemalloc/msvc/ReadMe.txt +jemalloc/msvc/test_threads/test_threads.cpp +jemalloc/msvc/test_threads/test_threads.h +jemalloc/msvc/test_threads/test_threads_main.cpp +jemalloc/README +jemalloc/run_tests.sh +jemalloc/scripts/gen_run_tests.py +jemalloc/scripts/gen_travis.py +jemalloc/src/arena.c +jemalloc/src/background_thread.c +jemalloc/src/base.c +jemalloc/src/bin.c +jemalloc/src/bitmap.c +jemalloc/src/ckh.c +jemalloc/src/ctl.c +jemalloc/src/div.c +jemalloc/src/extent.c +jemalloc/src/extent_dss.c +jemalloc/src/extent_mmap.c +jemalloc/src/hash.c +jemalloc/src/hook.c +jemalloc/src/jemalloc.c +jemalloc/src/jemalloc_cpp.cpp +jemalloc/src/large.c +jemalloc/src/log.c +jemalloc/src/malloc_io.c +jemalloc/src/mutex.c +jemalloc/src/mutex_pool.c +jemalloc/src/nstime.c +jemalloc/src/pages.c +jemalloc/src/prng.c +jemalloc/src/prof.c +jemalloc/src/rtree.c +jemalloc/src/safety_check.c +jemalloc/src/sc.c +jemalloc/src/stats.c +jemalloc/src/sz.c +jemalloc/src/tcache.c +jemalloc/src/test_hooks.c +jemalloc/src/ticker.c +jemalloc/src/tsd.c +jemalloc/src/witness.c +jemalloc/src/zone.c +jemalloc/test/include/test/btalloc.h +jemalloc/test/include/test/extent_hooks.h +jemalloc/test/include/test/jemalloc_test.h.in +jemalloc/test/include/test/jemalloc_test_defs.h.in +jemalloc/test/include/test/math.h +jemalloc/test/include/test/mq.h +jemalloc/test/include/test/mtx.h +jemalloc/test/include/test/SFMT-alti.h +jemalloc/test/include/test/SFMT-params.h +jemalloc/test/include/test/SFMT-params607.h +jemalloc/test/include/test/SFMT-params1279.h +jemalloc/test/include/test/SFMT-params2281.h +jemalloc/test/include/test/SFMT-params4253.h +jemalloc/test/include/test/SFMT-params11213.h +jemalloc/test/include/test/SFMT-params19937.h +jemalloc/test/include/test/SFMT-params44497.h +jemalloc/test/include/test/SFMT-params86243.h +jemalloc/test/include/test/SFMT-params132049.h +jemalloc/test/include/test/SFMT-params216091.h +jemalloc/test/include/test/SFMT-sse2.h +jemalloc/test/include/test/SFMT.h +jemalloc/test/include/test/test.h +jemalloc/test/include/test/thd.h +jemalloc/test/include/test/timer.h +jemalloc/test/integration/aligned_alloc.c +jemalloc/test/integration/allocated.c +jemalloc/test/integration/extent.c +jemalloc/test/integration/extent.sh +jemalloc/test/integration/malloc.c +jemalloc/test/integration/mallocx.c +jemalloc/test/integration/mallocx.sh +jemalloc/test/integration/MALLOCX_ARENA.c +jemalloc/test/integration/overflow.c +jemalloc/test/integration/posix_memalign.c +jemalloc/test/integration/rallocx.c +jemalloc/test/integration/sdallocx.c +jemalloc/test/integration/slab_sizes.c +jemalloc/test/integration/slab_sizes.sh +jemalloc/test/integration/smallocx.c +jemalloc/test/integration/smallocx.sh +jemalloc/test/integration/thread_arena.c +jemalloc/test/integration/thread_tcache_enabled.c +jemalloc/test/integration/xallocx.c +jemalloc/test/integration/xallocx.sh +jemalloc/test/src/btalloc.c +jemalloc/test/src/btalloc_0.c +jemalloc/test/src/btalloc_1.c +jemalloc/test/src/math.c +jemalloc/test/src/mq.c +jemalloc/test/src/mtx.c +jemalloc/test/src/SFMT.c +jemalloc/test/src/test.c +jemalloc/test/src/thd.c +jemalloc/test/src/timer.c +jemalloc/test/stress/hookbench.c +jemalloc/test/stress/microbench.c +jemalloc/test/test.sh.in +jemalloc/test/unit/a0.c +jemalloc/test/unit/arena_reset.c +jemalloc/test/unit/arena_reset_prof.c +jemalloc/test/unit/arena_reset_prof.sh +jemalloc/test/unit/atomic.c +jemalloc/test/unit/background_thread.c +jemalloc/test/unit/background_thread_enable.c +jemalloc/test/unit/base.c +jemalloc/test/unit/binshard.c +jemalloc/test/unit/binshard.sh +jemalloc/test/unit/bitmap.c +jemalloc/test/unit/bit_util.c +jemalloc/test/unit/ckh.c +jemalloc/test/unit/decay.c +jemalloc/test/unit/decay.sh +jemalloc/test/unit/div.c +jemalloc/test/unit/emitter.c +jemalloc/test/unit/extent_quantize.c +jemalloc/test/unit/extent_util.c +jemalloc/test/unit/fork.c +jemalloc/test/unit/hash.c +jemalloc/test/unit/hook.c +jemalloc/test/unit/huge.c +jemalloc/test/unit/junk.c +jemalloc/test/unit/junk.sh +jemalloc/test/unit/junk_alloc.c +jemalloc/test/unit/junk_alloc.sh +jemalloc/test/unit/junk_free.c +jemalloc/test/unit/junk_free.sh +jemalloc/test/unit/log.c +jemalloc/test/unit/mallctl.c +jemalloc/test/unit/malloc_io.c +jemalloc/test/unit/math.c +jemalloc/test/unit/mq.c +jemalloc/test/unit/mtx.c +jemalloc/test/unit/nstime.c +jemalloc/test/unit/pack.c +jemalloc/test/unit/pack.sh +jemalloc/test/unit/pages.c +jemalloc/test/unit/ph.c +jemalloc/test/unit/prng.c +jemalloc/test/unit/prof_accum.c +jemalloc/test/unit/prof_accum.sh +jemalloc/test/unit/prof_active.c +jemalloc/test/unit/prof_active.sh +jemalloc/test/unit/prof_gdump.c +jemalloc/test/unit/prof_gdump.sh +jemalloc/test/unit/prof_idump.c +jemalloc/test/unit/prof_idump.sh +jemalloc/test/unit/prof_log.c +jemalloc/test/unit/prof_log.sh +jemalloc/test/unit/prof_reset.c +jemalloc/test/unit/prof_reset.sh +jemalloc/test/unit/prof_tctx.c +jemalloc/test/unit/prof_tctx.sh +jemalloc/test/unit/prof_thread_name.c +jemalloc/test/unit/prof_thread_name.sh +jemalloc/test/unit/ql.c +jemalloc/test/unit/qr.c +jemalloc/test/unit/rb.c +jemalloc/test/unit/retained.c +jemalloc/test/unit/rtree.c +jemalloc/test/unit/safety_check.c +jemalloc/test/unit/safety_check.sh +jemalloc/test/unit/sc.c +jemalloc/test/unit/seq.c +jemalloc/test/unit/SFMT.c +jemalloc/test/unit/size_classes.c +jemalloc/test/unit/slab.c +jemalloc/test/unit/smoothstep.c +jemalloc/test/unit/spin.c +jemalloc/test/unit/stats.c +jemalloc/test/unit/stats_print.c +jemalloc/test/unit/test_hooks.c +jemalloc/test/unit/ticker.c +jemalloc/test/unit/tsd.c +jemalloc/test/unit/witness.c +jemalloc/test/unit/zero.c +jemalloc/test/unit/zero.sh +jemalloc/TUNING.md +m4/ax_cxx_compile_stdcxx.m4 +m4/ax_cxx_compile_stdcxx_11.m4 +m4/ax_pthread.m4 +memkind.pc.in +test/gtest_fused/gtest/gtest-all.cc +test/gtest_fused/gtest/gtest.h +test/memkind-afts-ext.ts +test/memkind-afts.ts +test/memkind-perf-ext.ts +test/memkind-perf.ts +test/memkind-pytests.ts +test/memkind-slts.ts +utils/docker/README.md diff --git a/copying_headers/MANIFEST.freeBSD b/copying_headers/MANIFEST.freeBSD new file mode 100644 index 0000000..56798ed --- /dev/null +++ b/copying_headers/MANIFEST.freeBSD @@ -0,0 +1,193 @@ +Makefile.am +astyle.sh +autogen.sh +autohbw/Makefile.mk +autohbw/autohbw.c +autohbw/autohbw_get_src_lines.pl +autohbw/autohbw_test.sh +build.sh +configure.ac +examples/Makefile.mk +examples/autohbw_candidates.c +examples/filter_example.c +examples/hello_hbw_example.c +examples/hello_memkind_example.c +examples/memkind_allocated.hpp +examples/memkind_allocated_example.cpp +examples/memkind_decorator_debug.c +examples/memkind_get_stat.c +include/hbw_allocator.h +include/hbwmalloc.h +include/memkind.h +include/memkind/internal/heap_manager.h +include/memkind/internal/memkind_arena.h +include/memkind/internal/memkind_bandwidth.h +include/memkind/internal/memkind_dax_kmem.h +include/memkind/internal/memkind_default.h +include/memkind/internal/memkind_gbtlb.h +include/memkind/internal/memkind_hbw.h +include/memkind/internal/memkind_hugetlb.h +include/memkind/internal/memkind_interleave.h +include/memkind/internal/memkind_log.h +include/memkind/internal/memkind_pmem.h +include/memkind/internal/memkind_private.h +include/memkind/internal/memkind_regular.h +include/memkind/internal/tbb_wrapper.h +include/memkind/internal/vec.h +include/memkind_allocator.h +include/memkind_deprecated.h +include/pmem_allocator.h +install_astyle.sh +man/autohbw.7 +man/hbwallocator.3 +man/hbwmalloc.3 +mna/memkind-auto-dax-kmem-nodes.1 +man/memkind-hbw-nodes.1 +man/memkind.3 +man/memkind_arena.3 +man/memkind_dax_kmem.3 +man/memkind_default.3 +man/memkind_hbw.3 +man/memkind_hugetlb.3 +man/memkind_pmem.3 +man/memkindallocator.3 +man/pmemallocator.3 +memkind.spec.mk +src/Makefile.mk +src/hbwmalloc.c +src/heap_manager.c +src/memkind-auto-dax-kmem-nodes.c +src/memkind-hbw-nodes.c +src/memkind.c +src/memkind_arena.c +src/memkind_bandwidth.c +src/memkind_dax_kmem.c +src/memkind_default.c +src/memkind_gbtlb.c +src/memkind_hbw.c +src/memkind_hugetlb.c +src/memkind_interleave.c +src/memkind_log.c +src/memkind_pmem.c +src/memkind_regular.c +src/tbb_wrapper.c +test/Allocator.hpp +test/Makefile.mk +test/TestPolicy.hpp +test/alloc_benchmark.c +test/alloc_performance_tests.cpp +test/allocate_to_max_stress_test.cpp +test/allocator_perf_tool/AllocationSizes.hpp +test/allocator_perf_tool/Allocation_info.cpp +test/allocator_perf_tool/Allocation_info.hpp +test/allocator_perf_tool/Allocator.hpp +test/allocator_perf_tool/AllocatorFactory.hpp +test/allocator_perf_tool/CSVLogger.hpp +test/allocator_perf_tool/CommandLine.hpp +test/allocator_perf_tool/Configuration.hpp +test/allocator_perf_tool/ConsoleLog.hpp +test/allocator_perf_tool/FunctionCalls.hpp +test/allocator_perf_tool/FunctionCallsPerformanceTask.cpp +test/allocator_perf_tool/FunctionCallsPerformanceTask.h +test/allocator_perf_tool/GTestAdapter.hpp +test/allocator_perf_tool/HBWmallocAllocatorWithTimer.hpp +test/allocator_perf_tool/HugePageOrganizer.hpp +test/allocator_perf_tool/HugePageUnmap.hpp +test/allocator_perf_tool/Iterator.hpp +test/allocator_perf_tool/JemallocAllocatorWithTimer.hpp +test/allocator_perf_tool/Makefile +test/allocator_perf_tool/MemkindAllocatorWithTimer.hpp +test/allocator_perf_tool/Numastat.hpp +test/allocator_perf_tool/PmemMockup.cpp +test/allocator_perf_tool/PmemMockup.hpp +test/allocator_perf_tool/Runnable.hpp +test/allocator_perf_tool/ScenarioWorkload.cpp +test/allocator_perf_tool/ScenarioWorkload.h +test/allocator_perf_tool/StandardAllocatorWithTimer.hpp +test/allocator_perf_tool/Stats.hpp +test/allocator_perf_tool/StressIncreaseToMax.cpp +test/allocator_perf_tool/StressIncreaseToMax.h +test/allocator_perf_tool/Task.hpp +test/allocator_perf_tool/TaskFactory.hpp +test/allocator_perf_tool/Tests.hpp +test/allocator_perf_tool/Thread.hpp +test/allocator_perf_tool/TimerSysTime.hpp +test/allocator_perf_tool/VectorIterator.hpp +test/allocator_perf_tool/Workload.hpp +test/allocator_perf_tool/WrappersMacros.hpp +test/allocator_perf_tool/main.cpp +test/autohbw_test.py +test/autohbw_test_helper.c +test/bat_tests.cpp +test/check.cpp +test/check.h +test/common.h +test/dax_kmem_nodes.cpp +test/dax_kmem_nodes.h +test/dax_kmem_env_var_test.py +test/decorator_test.cpp +test/decorator_test.h +test/dlopen_test.cpp +test/draw_plots.py +test/environ_err_dax_kmem_malloc_positive_test.cpp +test/environ_err_dax_kmem_malloc_test.cpp +test/environ_err_hbw_malloc_test.cpp +test/error_message_tests.cpp +test/fragmentation_benchmark_pmem.cpp +test/freeing_memory_segfault_test.cpp +test/gb_page_tests_bind_policy.cpp +test/get_arena_test.cpp +test/hbw_allocator_performance_tests.cpp +test/hbw_allocator_tests.cpp +test/hbw_detection_test.py +test/hbw_verify_function_test.cpp +test/heap_manager_init_perf_test.cpp +test/huge_page_test.cpp +test/load_tbbmalloc_symbols.c +test/locality_test.cpp +test/main.cpp +test/memkind_allocator_tests.cpp +test/memkind_dax_kmem_test.cpp +test/memkind_detect_kind_tests.cpp +test/memkind_null_kind_test.cpp +test/memkind_pmem_config_tests.cpp +test/memkind_pmem_long_time_tests.cpp +test/memkind_pmem_tests.cpp +test/memkind_stat_test.cpp +test/memkind_defrag_reallocate.cpp +test/memkind_versioning_tests.cpp +test/memory_footprint_test.cpp +test/memory_manager.h +test/multithreaded_tests.cpp +test/negative_tests.cpp +test/performance/framework.cpp +test/performance/framework.hpp +test/performance/operations.hpp +test/performance/perf_tests.cpp +test/performance/perf_tests.hpp +test/pmem_alloc_performance_tests.cpp +test/pmem_allocator_tests.cpp +test/proc_stat.h +test/python_framework/__init__.py +test/python_framework/cmd_helper.py +test/python_framework/huge_page_organizer.py +test/random_sizes_allocator.h +test/run_alloc_benchmark.sh +test/static_kinds_list.h +test/static_kinds_tests.cpp +test/tbbmalloc.h +test/test.sh +test/test_dax_kmem.sh +test/trace_mechanism_test.py +test/trace_mechanism_test_helper.c +test/trial_generator.cpp +test/trial_generator.h +utils/docker/Dockerfile.fedora-31 +utils/docker/Dockerfile.ubuntu-18.04 +utils/docker/docker_install_ndctl.sh +utils/docker/docker_install_tbb.sh +utils/docker/docker_run_build.sh +utils/docker/docker_run_coverage.sh +utils/docker/docker_run_test.sh +utils/docker/run_local.sh +utils/docker/set_host_configuration.sh diff --git a/copying_headers/MANIFEST.freeBSD3 b/copying_headers/MANIFEST.freeBSD3 new file mode 100644 index 0000000..553a45e --- /dev/null +++ b/copying_headers/MANIFEST.freeBSD3 @@ -0,0 +1,14 @@ +examples/memkind_cpp_allocator.cpp +examples/pmem_alignment.c +examples/pmem_and_dax_kmem_kind.c +examples/pmem_and_default_kind.c +examples/pmem_config.c +examples/pmem_cpp_allocator.cpp +examples/pmem_detect_kind.c +examples/pmem_free_with_unknown_kind.c +examples/pmem_kinds.c +examples/pmem_malloc.c +examples/pmem_malloc_unlimited.c +examples/pmem_multithreads.c +examples/pmem_multithreads_onekind.c +examples/pmem_usable_size.c diff --git a/copying_headers/header.freeBSD b/copying_headers/header.freeBSD new file mode 100644 index 0000000..db5a089 --- /dev/null +++ b/copying_headers/header.freeBSD @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ \ No newline at end of file diff --git a/copying_headers/header.freeBSD3 b/copying_headers/header.freeBSD3 new file mode 100644 index 0000000..9119412 --- /dev/null +++ b/copying_headers/header.freeBSD3 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/copying_headers/header.intel-acpi b/copying_headers/header.intel-acpi new file mode 100644 index 0000000..c4603f8 --- /dev/null +++ b/copying_headers/header.intel-acpi @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ \ No newline at end of file diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..8d118a4 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +memkind (0.0.0) UNRELEASED; urgency=low + + * See ChangeLog for more details + + -- Krzysztof Kulakowski Mon, 12 Dec 2016 15:53:31 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..5a13b16 --- /dev/null +++ b/debian/control @@ -0,0 +1,25 @@ +Source: memkind +Section: utils +Priority: optional +Maintainer: Krzysztof Kulakowski +Build-Depends: debhelper (>= 8.0.0) +Standards-Version: 3.9.4 +Homepage: https://github.com/memkind/memkind + +Package: memkind +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: + The memkind library is an user extensible heap manager built on top of + jemalloc which enables control of memory characteristics and a + partitioning of the heap between kinds of memory. The kinds of memory + are defined by operating system memory policies that have been applied + to virtual address ranges. Memory characteristics supported by + memkind without user extension include control of NUMA and page size + features. The jemalloc non-standard interface has been extended to + enable specialized arenas to make requests for virtual memory from the + operating system through the memkind partition interface. Through the + other memkind interfaces the user can control and extend memory + partition features and allocate memory while selecting enabled + features. This software is being made available for early evaluation. + Feedback on design or implementation is greatly appreciated. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..5e7f167 --- /dev/null +++ b/debian/rules @@ -0,0 +1,21 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# ignore tests during build +override_dh_auto_test: + +override_dh_auto_configure: + ./build_jemalloc.sh + ./autogen.sh + dh_auto_configure -- --prefix=/usr --libdir=/usr/lib \ + --includedir=/usr/include --sbindir=/usr/sbin --enable-cxx11 \ + --mandir=/usr/share/man --docdir=/usr/share/doc/memkind + +override_dh_auto_build: + dh_auto_build -- checkprogs + +%: + dh $@ diff --git a/examples/Makefile.mk b/examples/Makefile.mk new file mode 100644 index 0000000..bcc8ba2 --- /dev/null +++ b/examples/Makefile.mk @@ -0,0 +1,99 @@ +# +# Copyright (C) 2014 - 2019 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +noinst_PROGRAMS += examples/autohbw_candidates \ + examples/filter_memkind \ + examples/hello_hbw \ + examples/hello_memkind \ + examples/hello_memkind_debug \ + examples/memkind_get_stat \ + examples/pmem_alignment \ + examples/pmem_and_dax_kmem_kind \ + examples/pmem_and_default_kind \ + examples/pmem_config \ + examples/pmem_detect_kind \ + examples/pmem_free_with_unknown_kind \ + examples/pmem_kinds \ + examples/pmem_malloc \ + examples/pmem_malloc_unlimited \ + examples/pmem_multithreads \ + examples/pmem_multithreads_onekind \ + examples/pmem_usable_size \ + # end +if HAVE_CXX11 +noinst_PROGRAMS += examples/memkind_allocated +noinst_PROGRAMS += examples/memkind_cpp_allocator +noinst_PROGRAMS += examples/pmem_cpp_allocator +endif + +examples_autohbw_candidates_LDADD = libmemkind.la +examples_filter_memkind_LDADD = libmemkind.la +examples_hello_hbw_LDADD = libmemkind.la +examples_hello_memkind_LDADD = libmemkind.la +examples_hello_memkind_debug_LDADD = libmemkind.la +examples_memkind_get_stat_LDADD = libmemkind.la +examples_pmem_alignment_LDADD = libmemkind.la +examples_pmem_and_dax_kmem_kind_LDADD = libmemkind.la +examples_pmem_and_default_kind_LDADD = libmemkind.la +examples_pmem_config_LDADD = libmemkind.la +examples_pmem_detect_kind_LDADD = libmemkind.la +examples_pmem_free_with_unknown_kind_LDADD = libmemkind.la +examples_pmem_kinds_LDADD = libmemkind.la +examples_pmem_malloc_LDADD = libmemkind.la +examples_pmem_malloc_unlimited_LDADD = libmemkind.la +examples_pmem_multithreads_LDADD = libmemkind.la +examples_pmem_multithreads_onekind_LDADD = libmemkind.la +examples_pmem_usable_size_LDADD = libmemkind.la + +if HAVE_CXX11 +examples_memkind_allocated_LDADD = libmemkind.la +examples_memkind_cpp_allocator_LDADD = libmemkind.la +examples_pmem_cpp_allocator_LDADD = libmemkind.la +endif + +examples_autohbw_candidates_SOURCES = examples/autohbw_candidates.c +examples_filter_memkind_SOURCES = examples/filter_example.c +examples_hello_hbw_SOURCES = examples/hello_hbw_example.c +examples_hello_memkind_SOURCES = examples/hello_memkind_example.c +examples_hello_memkind_debug_SOURCES = examples/hello_memkind_example.c examples/memkind_decorator_debug.c +examples_pmem_alignment_SOURCES = examples/pmem_alignment.c +examples_pmem_and_dax_kmem_kind_SOURCES = examples/pmem_and_dax_kmem_kind.c +examples_pmem_and_default_kind_SOURCES = examples/pmem_and_default_kind.c +examples_pmem_config_SOURCES = examples/pmem_config.c +examples_pmem_detect_kind_SOURCES = examples/pmem_detect_kind.c +examples_pmem_free_with_unknown_kind_SOURCES = examples/pmem_free_with_unknown_kind.c +examples_pmem_kinds_SOURCES = examples/pmem_kinds.c +examples_pmem_malloc_SOURCES = examples/pmem_malloc.c +examples_pmem_malloc_unlimited_SOURCES = examples/pmem_malloc_unlimited.c +examples_pmem_multithreads_SOURCES = examples/pmem_multithreads.c +examples_pmem_multithreads_onekind_SOURCES = examples/pmem_multithreads_onekind.c +examples_pmem_usable_size_SOURCES = examples/pmem_usable_size.c +if HAVE_CXX11 +examples_memkind_allocated_SOURCES = examples/memkind_allocated_example.cpp examples/memkind_allocated.hpp +examples_memkind_cpp_allocator_SOURCES = examples/memkind_cpp_allocator.cpp +examples_pmem_cpp_allocator_SOURCES = examples/pmem_cpp_allocator.cpp +endif + +clean-local: + rm -f examples/*.gcno examples/*.gcda diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..79e4408 --- /dev/null +++ b/examples/README @@ -0,0 +1,104 @@ +# Memkind examples + +The example directory contains example codes that use the memkind +interface. + +## PMEM + +The pmem_*.c(pp) demonstrates how to create and use a file-backed memory kind. +The default pmem path is "/tmp/". +Custom directory is pass as first argument to all of PMEM example programs, +e.g. to execute pmem_malloc example in /mnt/pmem location, call: + + ./pmem_malloc /mnt/pmem/ + +### pmem_kinds.c + +This example shows how to create and destroy pmem kind with defined or unlimited size. + +### pmem_malloc.c + +This example shows how to allocate memory and possibility to exceed pmem kind size. + +### pmem_malloc_unlimited.c + +This example shows how to allocate memory with unlimited kind size. + +### pmem_usable_size.c + +This example shows difference between the expected and the actual allocation size. + +### pmem_alignment.c + +This example shows how to use memkind alignment and how it affects allocations. + +### pmem_multithreads.c + +This example shows how to use multithreading with independent pmem kinds. + +### pmem_multithreads_onekind.c + +This example shows how to use multithreading with one main pmem kind. + +### pmem_and_dax_kmem_kind.c + +This example shows how to allocate to PMEM memory using file-backed memory (pmem kind) +and persistent memory NUMA node (MEMKIND_DAX_KMEM). + +### pmem_and_default_kind.c + +This example shows how to allocate in standard memory and file-backed memory (pmem kind). + +### pmem_detect_kind.c + +This example shows how to distinguish allocation from different kinds using detect kind function. + +### pmem_config.c + +This example shows how to use custom configuration to create pmem kind. + +### pmem_free_with_unknown_kind.c + +This example shows how to allocate in standard memory and file-backed memory (pmem kind) +and free memory without a need to remember which kind it belongs to. + +### pmem_cpp_allocator.cpp + +This example shows usage of C++ allocator mechanism designed for file-backed memory +kind with different data structures like: vector, list and map. + +## Other memkind examples + +### memkind_get_stat.c + +This example shows how to get information about allocator and kind statistics. + +### other + +The simplest example is the hello_example.c which is a hello world +variant. The filter_example.c shows how you would use high bandwidth +memory to store a reduction of a larger data set stored in DDR. There is +also an example of how to create user defined kinds. This example +creates kinds which isolate allocations to a single NUMA node each +backed by a single arena. + +### memkind_cpp_allocator.cpp + +This example shows usage of C++ allocator mechanism designed for static +kinds with different data structures like: forward list, deque and multiset. + +The memkind_allocated example is simple usage of memkind in C++11 which +shows how memkind can be used to allocate objects, and consists of two files: +memkind_allocated.hpp - which is definition of template class that should be +inherited and parametrized by derived type (curiously recurring template +pattern), to let deriving class allocate their objects using specified kind. +memkind_allocated_example.cpp - which is usage example of this approach. +Logic of memkind_allocated is based on overriding operator new() in template, +and allocating memory on kind specified in new() parameter, or by overridable +static method getClassKind(). This implementation also supports alignment +specifier's (alignas() - new feature in C++11). +The downside of this approach is that it will work properly only if +memkind_allocated template is inherited once in inheritance chain (which +probably makes that not very useful for most scenarios). Other thing is that it +overriding class new() operator which can cause various problems if used +unwisely. diff --git a/examples/autohbw_candidates.c b/examples/autohbw_candidates.c new file mode 100644 index 0000000..f4844ce --- /dev/null +++ b/examples/autohbw_candidates.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2015 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////////////////////////////////////////////////////////////////////////// +// File : autohbw_candidates.c +// Purpose: Shows which functions are interposed by AutoHBW library. +// : These functions can be used for testing purposes +// Author : Ruchira Sasanka (ruchira.sasanka AT intel.com) +// Date : Sept 10, 2015 +/////////////////////////////////////////////////////////////////////////// + + +#include + +#include +#include + + +/////////////////////////////////////////////////////////////////////////// +// This function contains an example case for each heap allocation function +// intercepted by the AutoHBW library +/////////////////////////////////////////////////////////////////////////// + +//volatile is needed to prevent optimizing out below hooks +volatile int memkind_called_g; + +void memkind_malloc_post(struct memkind *kind, size_t size, void **result) +{ + memkind_called_g = 1; +} +void memkind_calloc_post(struct memkind *kind, size_t nmemb, size_t size, + void **result) +{ + memkind_called_g = 1; +} +void memkind_posix_memalign_post(struct memkind *kind, void **memptr, + size_t alignment, size_t size, int *err) +{ + memkind_called_g = 1; +} +void memkind_realloc_post(struct memkind *kind, void *ptr, size_t size, + void **result) +{ + memkind_called_g = 1; +} +void memkind_free_pre(struct memkind **kind, void **ptr) +{ + memkind_called_g = 1; +} + +void finish_testcase(int fail_condition, const char *fail_message, int *err) +{ + + if(memkind_called_g != 1 || fail_condition) { + printf("%s\n", fail_message); + *err= -1; + } + memkind_called_g = 0; +} + +int main() +{ + int err = 0; + const size_t size = 1024 * 1024; // 1M of data + + void *buf = NULL; + memkind_called_g = 0; + + // Test 1: Test malloc and free + buf = malloc(size); + finish_testcase(buf==NULL, "Malloc failed!", &err); + + free(buf); + finish_testcase(0, "Free after malloc failed!", &err); + + // Test 2: Test calloc and free + buf = calloc(size, 1); + finish_testcase(buf==NULL, "Calloc failed!", &err); + + free(buf); + finish_testcase(0, "Free after calloc failed!", &err); + + // Test 3: Test realloc and free + buf = malloc(size); + finish_testcase(buf==NULL, "Malloc before realloc failed!", &err); + + buf = realloc(buf, size * 2); + finish_testcase(buf==NULL, "Realloc failed!", &err); + + free(buf); + finish_testcase(0, "Free after realloc failed!", &err); + buf = NULL; + + // Test 4: Test posix_memalign and free + int ret = posix_memalign(&buf, 64, size); + finish_testcase(ret, "Posix_memalign failed!", &err); + + free(buf); + finish_testcase(0, "Free after posix_memalign failed!", &err); + + return err; +} diff --git a/examples/filter_example.c b/examples/filter_example.c new file mode 100644 index 0000000..f128d71 --- /dev/null +++ b/examples/filter_example.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 - 2016 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + const size_t stream_len = 1024 * 1024; + const size_t filter_len = 1024; + const size_t num_filter = stream_len / filter_len; + size_t i, j; + double *stream = NULL; + double *filter = NULL; + double *result = NULL; + + srandom(0); + + stream = (double *)memkind_malloc(MEMKIND_DEFAULT, stream_len * sizeof(double)); + if (stream == NULL) { + perror(""); + fprintf(stderr, "Unable to allocate stream\n"); + return errno ? -errno : 1; + } + + filter = (double *)memkind_malloc(MEMKIND_HBW, filter_len * sizeof(double)); + if (filter == NULL) { + perror(""); + fprintf(stderr, "Unable to allocate filter\n"); + return errno ? -errno : 1; + } + + result = (double *)memkind_calloc(MEMKIND_HBW, filter_len, sizeof(double)); + if (result == NULL) { + perror(""); + fprintf(stderr, "Unable to allocate result\n"); + return errno ? -errno : 1; + } + + for (i = 0; i < stream_len; i++) { + stream[i] = (double)(random())/(double)(RAND_MAX); + } + + for (i = 0; i < filter_len; i++) { + filter[i] = (double)(i)/(double)(filter_len); + } + + for (i = 0; i < num_filter; i++) { + for (j = 0; j < filter_len; j++) { + result[j] += stream[i * filter_len + j] * filter[j]; + } + } + + for (i = 0; i < filter_len; i++) { + fprintf(stdout, "%.6e\n", result[i]); + } + + memkind_free(MEMKIND_HBW, result); + memkind_free(MEMKIND_HBW, filter); + memkind_free(MEMKIND_DEFAULT, stream); + + return 0; +} diff --git a/examples/hello_hbw_example.c b/examples/hello_hbw_example.c new file mode 100644 index 0000000..7b044fa --- /dev/null +++ b/examples/hello_hbw_example.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + const size_t size = 512; + char *default_str = NULL; + char *hbw_str = NULL; + char *hbw_hugetlb_str = NULL; + int err = 0; + + default_str = (char *)malloc(size); + if (default_str == NULL) { + perror("malloc()"); + fprintf(stderr, "Unable to allocate default string\n"); + err = errno ? -errno : 1; + goto exit; + } + hbw_str = (char *)hbw_malloc(size); + if (hbw_str == NULL) { + perror("hbw_malloc()"); + fprintf(stderr, "Unable to allocate hbw string\n"); + err = errno ? -errno : 1; + goto exit; + } + err = hbw_posix_memalign_psize((void **)&hbw_hugetlb_str, 2097152, size, + HBW_PAGESIZE_2MB); + if (err) { + perror("hbw_posix_memalign()"); + fprintf(stderr, "Unable to allocate hbw hugetlb string\n"); + err = errno ? -errno : 1; + goto exit; + } + + sprintf(default_str, "Hello world from standard memory\n"); + sprintf(hbw_str, "Hello world from high bandwidth memory\n"); + sprintf(hbw_hugetlb_str, "Hello world from high bandwidth 2 MB paged memory\n"); + + fprintf(stdout, "%s", default_str); + fprintf(stdout, "%s", hbw_str); + fprintf(stdout, "%s", hbw_hugetlb_str); + +exit: + if (hbw_hugetlb_str) { + hbw_free(hbw_hugetlb_str); + } + if (hbw_str) { + hbw_free(hbw_str); + } + if (default_str) { + free(default_str); + } + return err; +} diff --git a/examples/hello_memkind_example.c b/examples/hello_memkind_example.c new file mode 100644 index 0000000..e85e30c --- /dev/null +++ b/examples/hello_memkind_example.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +int main(int argc, char **argv) +{ + const size_t size = 512; + char *default_str = NULL; + char *hugetlb_str = NULL; + char *hbw_str = NULL; + char *hbw_hugetlb_str = NULL; + char *hbw_preferred_str = NULL; + char *hbw_preferred_hugetlb_str = NULL; + char *hbw_interleave_str = NULL; + + default_str = (char *)memkind_malloc(MEMKIND_DEFAULT, size); + if (default_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate default string\n"); + return errno ? -errno : 1; + } + hugetlb_str = (char *)memkind_malloc(MEMKIND_HUGETLB, size); + if (hugetlb_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate hugetlb string\n"); + return errno ? -errno : 1; + } + hbw_str = (char *)memkind_malloc(MEMKIND_HBW, size); + if (hbw_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate hbw string\n"); + return errno ? -errno : 1; + } + hbw_hugetlb_str = (char *)memkind_malloc(MEMKIND_HBW_HUGETLB, size); + if (hbw_hugetlb_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate hbw_hugetlb string\n"); + return errno ? -errno : 1; + } + hbw_preferred_str = (char *)memkind_malloc(MEMKIND_HBW_PREFERRED, size); + if (hbw_preferred_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate hbw_preferred string\n"); + return errno ? -errno : 1; + } + hbw_preferred_hugetlb_str = (char *)memkind_malloc( + MEMKIND_HBW_PREFERRED_HUGETLB, size); + if (hbw_preferred_hugetlb_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr, "Unable to allocate hbw_preferred_hugetlb string\n"); + return errno ? -errno : 1; + } + hbw_interleave_str = (char *)memkind_malloc(MEMKIND_HBW_INTERLEAVE, size); + if (hbw_interleave_str == NULL) { + perror("memkind_malloc()"); + fprintf(stderr,"Unable to allocate hbw_interleave string\n"); + return errno ? -errno : 1; + } + + sprintf(default_str, "Hello world from standard memory\n"); + sprintf(hugetlb_str, "Hello world from standard memory with 2 MB pages\n"); + sprintf(hbw_str, "Hello world from high bandwidth memory\n"); + sprintf(hbw_hugetlb_str, "Hello world from high bandwidth 2 MB paged memory\n"); + sprintf(hbw_preferred_str, + "Hello world from high bandwidth memory if sufficient resources exist\n"); + sprintf(hbw_preferred_hugetlb_str, + "Hello world from high bandwidth 2 MB paged memory if sufficient resources exist\n"); + + sprintf(hbw_interleave_str, + "Hello world from high bandwidth interleaved memory\n"); + + fprintf(stdout, "%s", default_str); + fprintf(stdout, "%s", hugetlb_str); + fprintf(stdout, "%s", hbw_str); + fprintf(stdout, "%s", hbw_hugetlb_str); + fprintf(stdout, "%s", hbw_preferred_str); + fprintf(stdout, "%s", hbw_preferred_hugetlb_str); + fprintf(stdout, "%s", hbw_interleave_str); + + memkind_free(MEMKIND_HBW_INTERLEAVE, hbw_interleave_str); + memkind_free(MEMKIND_HBW_PREFERRED_HUGETLB, hbw_preferred_hugetlb_str); + memkind_free(MEMKIND_HBW_PREFERRED, hbw_preferred_str); + memkind_free(MEMKIND_HBW_HUGETLB, hbw_hugetlb_str); + memkind_free(MEMKIND_HBW, hbw_str); + memkind_free(MEMKIND_HUGETLB, hugetlb_str); + memkind_free(MEMKIND_DEFAULT, default_str); + + return 0; +} diff --git a/examples/memkind_allocated.hpp b/examples/memkind_allocated.hpp new file mode 100644 index 0000000..dd75bef --- /dev/null +++ b/examples/memkind_allocated.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +template +class memkind_allocated +{ +public: + static memkind_t getClassKind() + { + return MEMKIND_DEFAULT; + } + + void *operator new(std::size_t size) + { + return deriving_class::operator new(size, deriving_class::getClassKind()); + } + + void *operator new[](std::size_t size) + { + return deriving_class::operator new(size, deriving_class::getClassKind()); + } + + void *operator new(std::size_t size, memkind_t memory_kind) + { + void *result_ptr = NULL; + int allocation_result = 0; + + //This check if deriving_class has specified alignment, which is suitable + //to be used with posix_memalign() + if(alignof(deriving_class) < sizeof(void *)) { + result_ptr = memkind_malloc(memory_kind, size); + allocation_result = result_ptr ? 1 : 0; + } else { + allocation_result = memkind_posix_memalign(memory_kind, &result_ptr, + alignof(deriving_class), size); + } + + if(allocation_result) { + throw std::bad_alloc(); + } + + return result_ptr; + } + + void *operator new[](std::size_t size, memkind_t memory_kind) + { + return deriving_class::operator new(size, memory_kind); + } + + void operator delete(void *ptr, memkind_t memory_kind) + { + memkind_free(memory_kind, ptr); + } + + void operator delete(void *ptr) + { + memkind_free(0, ptr); + } + + void operator delete[](void *ptr) + { + deriving_class::operator delete(ptr); + } + + void operator delete[](void *ptr, memkind_t memory_kind) + { + deriving_class::operator delete(ptr, memory_kind); + } + +protected: + memkind_allocated() + { + } + + ~memkind_allocated() + { + } + +}; diff --git a/examples/memkind_allocated_example.cpp b/examples/memkind_allocated_example.cpp new file mode 100644 index 0000000..52f916b --- /dev/null +++ b/examples/memkind_allocated_example.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include "memkind_allocated.hpp" + +// This code is example usage of C++11 features with custom allocator, +// support for C++11 is required. +#include + +#if __cplusplus > 199711L + +#include +#include +#include + +//example class definition, which derive from memkind_allocated template to +//have objects allocated with memkind, and have alignment specified by alignas() +class alignas(128) memkind_allocated_example : public + memkind_allocated +{ + std::string message; + +public: + //Override method for returning class default kind to make objects be by default allocated on High-Bandwidth Memory + static memkind_t getClassKind() + { + return MEMKIND_HBW; + } + + memkind_allocated_example(std::string my_message) + { + this->message = my_message; + } + + memkind_allocated_example() + { + } + + void print_message() + { + std::cout << message << std::endl; + std::cout << "Memory address of this object is: " << (void *)this << std::endl + << std::endl; + } +}; + +int main() +{ + memkind_t specified_kind = MEMKIND_HBW_HUGETLB; + + memkind_allocated_example *default_kind_example = new memkind_allocated_example( + std::string("This object has been allocated using class default kind, which is: MEMKIND_DEFAULT") ); + default_kind_example->print_message(); + delete default_kind_example; + + memkind_allocated_example *specified_kind_example = new( + specified_kind) memkind_allocated_example( + std::string("This object has been allocated using specified kind, which is: MEMKIND_HBW_HUGETLB") ); + specified_kind_example->print_message(); + delete specified_kind_example; + + //examples for using same approach for allocating arrays of objects, note that objects created that way can be initialized only with default (unparameterized) constructor + memkind_allocated_example *default_kind_array_example = new + memkind_allocated_example[5](); + delete[] default_kind_array_example; + + memkind_allocated_example *specified_kind_array_example = new( + specified_kind) memkind_allocated_example[5](); + delete[] specified_kind_array_example; + + return 0; +} +#else //If C++11 is not available - do nothing. +int main() +{ + std::cout << "WARNING: because your compiler does not support C++11 standard," + << std::endl; + std::cout << "this example is only as a dummy placeholder." << std::endl; + return 0; +} +#endif diff --git a/examples/memkind_cpp_allocator.cpp b/examples/memkind_cpp_allocator.cpp new file mode 100644 index 0000000..98b165f --- /dev/null +++ b/examples/memkind_cpp_allocator.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "memkind_allocator.h" + +#include +#include +#include +#include +#include +#include +#include + +#define STL_FWLIST_TEST +#define STL_DEQUE_TEST +#if _GLIBCXX_USE_CXX11_ABI +#define STL_MULTISET_TEST +#endif + +int main(int argc, char *argv[]) +{ + std::cout << "TEST SCOPE: HELLO" << std::endl; + +#ifdef STL_FWLIST_TEST + { + std::cout << "FORWARD LIST OPEN" << std::endl; + libmemkind::static_kind::allocator alc{ libmemkind::kinds::REGULAR }; + std::forward_list> fwlist {alc}; + int i; + + for (i = 0; i <= 20; ++i) { + fwlist.push_front(i); + } + + fwlist.sort(std::greater()); + + for(auto &el: fwlist) { + i--; + assert(el == i); + } + + fwlist.clear(); + + std::cout << "FORWARD LIST CLOSE" << std::endl; + } +#endif + +#ifdef STL_DEQUE_TEST + std::cout << "DEQUE OPEN" << std::endl; + libmemkind::static_kind::allocator int_alc{ libmemkind::kinds::REGULAR }; + std::deque> deque {int_alc}; + + for (int i=0; i<10; i++) { + deque.push_back(i); + } + + assert(deque.size() == 10); + + while(!deque.empty()) { + deque.pop_front(); + } + + assert(deque.size() == 0); + + std::cout << "DEQUE CLOSE" << std::endl; +#endif + +#ifdef STL_MULTISET_TEST + { + std::cout << "MULTISET OPEN" << std::endl; + typedef libmemkind::static_kind::allocator multiset_alloc_t; + multiset_alloc_t multiset_alloc { libmemkind::kinds::DEFAULT }; + std::multiset, std::scoped_allocator_adaptor > + multiset{ std::scoped_allocator_adaptor(multiset_alloc) }; + + multiset.insert("S"); + multiset.insert("A"); + multiset.insert("C"); + multiset.insert("S"); + multiset.insert("C"); + multiset.insert("E"); + + std::string test; + for (auto &n : multiset) { + test.append(n); + } + assert(test == "ACCESS"); + + std::cout << "MULTISET CLOSE" << std::endl; + } +#endif + + std::cout << "TEST SCOPE: GOODBYE" << std::endl; + + return 0; +} diff --git a/examples/memkind_decorator_debug.c b/examples/memkind_decorator_debug.c new file mode 100644 index 0000000..51183d3 --- /dev/null +++ b/examples/memkind_decorator_debug.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +/* This is an example that enables debug printing on every alloction call */ + +static void memkind_debug(const char *func, memkind_t kind, size_t size, + void *ptr) +{ + fprintf(stderr, "[ DEBUG ] func=%s kind=%p size=%zu ptr=0x%lx\n", func, kind, + size, (size_t)ptr); +} + +void memkind_malloc_post(memkind_t kind, size_t size, void **result) +{ + memkind_debug("memkind_malloc", kind, size, *result); +} + +void memkind_calloc_post(memkind_t kind, size_t nmemb, size_t size, + void **result) +{ + memkind_debug("memkind_calloc", kind, nmemb * size, *result); +} + +void memkind_posix_memalign_post(memkind_t kind, void **memptr, + size_t alignment, size_t size, int *err) +{ + memkind_debug("memkind_posix_memalign", kind, size, *memptr); +} + +void memkind_realloc_post(memkind_t kind, void *ptr, size_t size, void **result) +{ + memkind_debug("memkind_realloc", kind, size, *result); +} + +void memkind_free_pre(memkind_t kind, void **ptr) +{ + memkind_debug("memkind_free", kind, 0, *ptr); +} diff --git a/examples/memkind_get_stat.c b/examples/memkind_get_stat.c new file mode 100644 index 0000000..7e8d0d5 --- /dev/null +++ b/examples/memkind_get_stat.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +int main() +{ + const size_t size = 1024; + + size_t stats_active; + size_t stats_resident; + size_t stats_allocated; + size_t stats_kind_regular_active; + size_t stats_kind_regular_resident; + size_t stats_kind_regular_allocated; + + char *ptr_regular = (char *)memkind_malloc(MEMKIND_REGULAR, size); + + fprintf(stdout, + "This example shows how to use memkind API to retrieve information about allocation stats.\n"); + + snprintf(ptr_regular, size, + "Hello world from regular kind memory - ptr_regular.\n"); + + memkind_update_cached_stats(); + memkind_get_stat(NULL, MEMKIND_STAT_TYPE_RESIDENT, &stats_resident); + memkind_get_stat(NULL, MEMKIND_STAT_TYPE_ACTIVE, &stats_active); + memkind_get_stat(NULL, MEMKIND_STAT_TYPE_ALLOCATED, &stats_allocated); + memkind_get_stat(MEMKIND_REGULAR, MEMKIND_STAT_TYPE_RESIDENT, + &stats_kind_regular_resident); + memkind_get_stat(MEMKIND_REGULAR, MEMKIND_STAT_TYPE_ACTIVE, + &stats_kind_regular_active); + memkind_get_stat(MEMKIND_REGULAR, MEMKIND_STAT_TYPE_ALLOCATED, + &stats_kind_regular_allocated); + + fprintf(stdout, + "\n Global stats \nresident %zu \nactive %zu, \nallocated %zu \n", + stats_resident, stats_active, stats_allocated); + fprintf(stdout, + "\n MEMKIND_REGULAR stats \nresident %zu \nactive %zu, \nallocated %zu \n", + stats_kind_regular_resident, stats_kind_regular_active, + stats_kind_regular_allocated); + + memkind_free(NULL, ptr_regular); + + return 0; +} diff --git a/examples/pmem_alignment.c b/examples/pmem_alignment.c new file mode 100644 index 0000000..3c314fc --- /dev/null +++ b/examples/pmem_alignment.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#define PMEM_MAX_SIZE (1024 * 1024 * 32) + +static char path[PATH_MAX] = "/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to use memkind alignment and how it affects allocations.\nPMEM kind directory: %s\n", + path); + + err = memkind_create_pmem(path, PMEM_MAX_SIZE, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + char *pmem_str10 = NULL; + char *pmem_str11 = NULL; + + // Perform two allocations - 32 bytes + pmem_str10 = (char *)memkind_malloc(pmem_kind, 32); + if (pmem_str10 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str10).\n"); + return 1; + } + + pmem_str11 = (char *)memkind_malloc(pmem_kind, 32); + if (pmem_str11 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str11)\n"); + return 1; + } + + // The allocations should be very close to each other in memory + if (pmem_str11 - pmem_str10 != 32) { + fprintf(stderr, "Something went wrong with allocations.\n"); + return 1; + } + + memkind_free(pmem_kind, pmem_str10); + memkind_free(pmem_kind, pmem_str11); + + // Perform two allocations - 32 bytes with alignment 64 + err = memkind_posix_memalign(pmem_kind, (void **)&pmem_str10, 64, 32); + if (err) { + fprintf(stderr, + "Unable to allocate pmem string (pmem_str10) with alignment.\n"); + return 1; + } + + err = memkind_posix_memalign(pmem_kind, (void **)&pmem_str11, 64, 32); + if (err) { + fprintf(stderr, + "Unable to allocate pmem string (pmem_str11) with alignment.\n"); + return 1; + } + + // The addresses of allocations are not close to each other in memory, they are aligned to 64 + if (pmem_str11 - pmem_str10 != 64) { + fprintf(stderr, "Something went wrong with alignment allocations.\n"); + return 1; + } + + memkind_free(pmem_kind, pmem_str10); + memkind_free(pmem_kind, pmem_str11); + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, + "The memory has been successfully allocated using memkind alignment.\n"); + + return 0; +} diff --git a/examples/pmem_and_dax_kmem_kind.c b/examples/pmem_and_dax_kmem_kind.c new file mode 100644 index 0000000..45a544f --- /dev/null +++ b/examples/pmem_and_dax_kmem_kind.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + const size_t size = 512; + struct memkind *pmem_kind = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2) { + if (realpath(argv[1], path) == NULL) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + } + + char *ptr_dax_kmem = NULL; + char *ptr_pmem = NULL; + + fprintf(stdout, + "This example shows how to allocate to PMEM memory using file-backed memory (pmem kind) " + "and persistent memory NUMA node (MEMKIND_DAX_KMEM).\nPMEM kind directory: %s\n", + path); + + err = memkind_create_pmem(path, 0, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + ptr_dax_kmem = (char *)memkind_malloc(MEMKIND_DAX_KMEM, size); + if (!ptr_dax_kmem) { + fprintf(stderr, "Unable allocate 512 bytes in persistent memory NUMA node.\n"); + return 1; + } + + ptr_pmem = (char *)memkind_malloc(pmem_kind, size); + if (!ptr_pmem) { + fprintf(stderr, "Unable allocate 512 bytes in file-backed memory.\n"); + return 1; + } + + snprintf(ptr_dax_kmem, size, + "Hello world from persistent memory NUMA node - ptr_dax_kmem.\n"); + snprintf(ptr_pmem, size, "Hello world from file-backed memory - ptr_pmem.\n"); + + fprintf(stdout, "%s", ptr_dax_kmem); + fprintf(stdout, "%s", ptr_pmem); + + memkind_free(MEMKIND_DAX_KMEM, ptr_dax_kmem); + memkind_free(pmem_kind, ptr_pmem); + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory was successfully allocated and released.\n"); + + return 0; +} diff --git a/examples/pmem_and_default_kind.c b/examples/pmem_and_default_kind.c new file mode 100644 index 0000000..4b0ec38 --- /dev/null +++ b/examples/pmem_and_default_kind.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#define MB (1024 * 1024) +#define HEAP_LIMIT_SIMULATE (1024 * MB) + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + const size_t size = 512; + struct memkind *pmem_kind = NULL; + int err = 0; + errno = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2) { + if (realpath(argv[1], path) == NULL) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + } + + // Operation below limit the current size of heap + // to show different place of allocation + const struct rlimit heap_limit = { HEAP_LIMIT_SIMULATE, HEAP_LIMIT_SIMULATE }; + err = setrlimit(RLIMIT_DATA, &heap_limit); + if (err) { + fprintf(stderr, "Unable to set heap limit.\n"); + return 1; + } + + char *ptr_default = NULL; + char *ptr_default_not_possible = NULL; + char *ptr_pmem = NULL; + + fprintf(stdout, + "This example shows how to allocate memory using standard memory (MEMKIND_DEFAULT) " + "and file-backed kind of memory (PMEM).\nPMEM kind directory: %s\n", path); + + err = memkind_create_pmem(path, 0, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + ptr_default = (char *)memkind_malloc(MEMKIND_DEFAULT, size); + if (!ptr_default) { + fprintf(stderr, "Unable allocate 512 bytes in standard memory.\n"); + return 1; + } + + errno = 0; + ptr_default_not_possible = (char *)memkind_malloc(MEMKIND_DEFAULT, + HEAP_LIMIT_SIMULATE); + if (ptr_default_not_possible) { + fprintf(stderr, + "Failure, this allocation should not be possible " + "(expected result was NULL), because of setlimit function.\n"); + return 1; + } + if (errno != ENOMEM) { + fprintf(stderr, + "Failure, this allocation should set errno to ENOMEM value, because of setlimit function.\n"); + return 1; + } + + errno = 0; + ptr_pmem = (char *)memkind_malloc(pmem_kind, HEAP_LIMIT_SIMULATE); + if (!ptr_pmem) { + fprintf(stderr, "Unable allocate HEAP_LIMIT_SIMULATE in file-backed memory.\n"); + return 1; + } + if (errno != 0) { + fprintf(stderr, "Failure, this allocation should not set errno value.\n"); + return 1; + } + + sprintf(ptr_default, "Hello world from standard memory - ptr_default.\n"); + sprintf(ptr_pmem, "Hello world from file-backed memory - ptr_pmem.\n"); + + fprintf(stdout, "%s", ptr_default); + fprintf(stdout, "%s", ptr_pmem); + + memkind_free(MEMKIND_DEFAULT, ptr_default); + memkind_free(pmem_kind, ptr_pmem); + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory was successfully allocated and released.\n"); + + return 0; +} diff --git a/examples/pmem_config.c b/examples/pmem_config.c new file mode 100644 index 0000000..cd7cc00 --- /dev/null +++ b/examples/pmem_config.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#define PMEM_MAX_SIZE (1024 * 1024 * 32) + +static char path[PATH_MAX] = "/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to use custom configuration to create pmem kind." + "\nPMEM kind directory: %s\n", path); + + struct memkind_config *test_cfg = memkind_config_new(); + if (!test_cfg) { + fprintf(stderr, "Unable to create memkind cfg.\n"); + return 1; + } + + memkind_config_set_path(test_cfg, path); + memkind_config_set_size(test_cfg, PMEM_MAX_SIZE); + memkind_config_set_memory_usage_policy(test_cfg, + MEMKIND_MEM_USAGE_POLICY_CONSERVATIVE); + + + // Create PMEM partition with specific configuration + err = memkind_create_pmem_with_config(test_cfg, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + memkind_config_delete(test_cfg); + + fprintf(stdout, + "PMEM kind and configuration was successfully created and destroyed.\n"); + + return 0; +} diff --git a/examples/pmem_cpp_allocator.cpp b/examples/pmem_cpp_allocator.cpp new file mode 100644 index 0000000..e3decd1 --- /dev/null +++ b/examples/pmem_cpp_allocator.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pmem_allocator.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define STL_VECTOR_TEST +#define STL_LIST_TEST +#if _GLIBCXX_USE_CXX11_ABI +#define STL_VEC_STRING_TEST +#define STL_MAP_INT_STRING_TEST +#endif + +void cpp_allocator_test(const char *pmem_directory) +{ + std::cout << "TEST SCOPE: HELLO" << std::endl; + + size_t pmem_max_size = 1024*1024*1024; + +#ifdef STL_VECTOR_TEST + { + std::cout << "VECTOR OPEN" << std::endl; + libmemkind::pmem::allocator alc{ pmem_directory, pmem_max_size }; + std::vector> vector{ alc }; + + for (int i = 0; i < 20; ++i) { + vector.push_back(0xDEAD + i); + assert(vector.back() == 0xDEAD + i); + } + + std::cout << "VECTOR CLOSE" << std::endl; + } +#endif + +#ifdef STL_LIST_TEST + { + std::cout << "LIST OPEN" << std::endl; + libmemkind::pmem::allocator alc{ pmem_directory, pmem_max_size }; + std::list> list{ alc }; + + const int nx2 = 4; + for (int i = 0; i < nx2; ++i) { + list.emplace_back(0xBEAC011 + i); + assert(list.back() == 0xBEAC011 + i); + } + + for (int i = 0; i < nx2; ++i) { + list.pop_back(); + } + + std::cout << "LIST CLOSE" << std::endl; + } +#endif + +#ifdef STL_VEC_STRING_TEST + { + std::cout << "STRINGED VECTOR OPEN" << std::endl; + typedef libmemkind::pmem::allocator str_alloc_t; + typedef std::basic_string, str_alloc_t> + pmem_string; + typedef libmemkind::pmem::allocator vec_alloc_t; + + vec_alloc_t vec_alloc{ pmem_directory, pmem_max_size }; + str_alloc_t str_alloc{ pmem_directory, pmem_max_size }; + + std::vector > + vec{ std::scoped_allocator_adaptor(vec_alloc) }; + + pmem_string arg{ "Very very loooong striiiing", str_alloc }; + + vec.push_back(arg); + assert(vec.back() == arg); + + std::cout << "STRINGED VECTOR CLOSE" << std::endl; + } + +#endif + +#ifdef STL_MAP_INT_STRING_TEST + { + std::cout << "INT_STRING MAP OPEN" << std::endl; + typedef std::basic_string, libmemkind::pmem::allocator> + pmem_string; + typedef int key_t; + typedef pmem_string value_t; + typedef libmemkind::pmem::allocator> + allocator_t; + typedef std::map, std::scoped_allocator_adaptor> + map_t; + + allocator_t allocator( pmem_directory, pmem_max_size ); + + value_t source_str1("Lorem ipsum dolor ", allocator); + value_t source_str2("sit amet consectetuer adipiscing elit", allocator ); + + map_t target_map{ std::scoped_allocator_adaptor(allocator) }; + + target_map[key_t(165)] = source_str1; + assert(target_map[key_t(165)] == source_str1); + target_map[key_t(165)] = source_str2; + assert(target_map[key_t(165)] == source_str2); + + std::cout << "INT_STRING MAP CLOSE" << std::endl; + } +#endif + std::cout << "TEST SCOPE: GOODBYE" << std::endl; +} + +int main(int argc, char *argv[]) +{ + const char *pmem_directory = "/tmp/"; + + if (argc > 2) { + std::cerr << "Usage: pmem_cpp_allocator [directory path]\n" + << "\t[directory path] - directory where temporary file is created (default = \"/tmp/\")" + << std::endl; + return 0; + } else if (argc == 2) { + struct stat st; + if (stat(argv[1], &st) != 0 || !S_ISDIR(st.st_mode)) { + fprintf(stderr,"%s : Invalid path to pmem kind directory\n", argv[1]); + return 1; + } + pmem_directory = argv[1]; + } + + cpp_allocator_test(pmem_directory); + return 0; +} diff --git a/examples/pmem_detect_kind.c b/examples/pmem_detect_kind.c new file mode 100644 index 0000000..ba4c609 --- /dev/null +++ b/examples/pmem_detect_kind.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static char path[PATH_MAX]="/tmp/"; + +#define MALLOC_SIZE 512U +#define REALLOC_SIZE 2048U +#define ALLOC_LIMIT 1000U + +static void *alloc_buffer[ALLOC_LIMIT]; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +static int allocate_pmem_and_default_kind(struct memkind *pmem_kind) +{ + unsigned i; + for(i = 0; i < ALLOC_LIMIT; i++) { + if (i%2) + alloc_buffer[i] = memkind_malloc(pmem_kind, MALLOC_SIZE); + else + alloc_buffer[i] = memkind_malloc(MEMKIND_DEFAULT, MALLOC_SIZE); + + if (!alloc_buffer[i]) { + return 1; + } + } + + return 0; +} + +static int realloc_using_get_kind_only_on_pmem() +{ + unsigned i; + for(i = 0; i < ALLOC_LIMIT; i++) { + if (memkind_detect_kind(alloc_buffer[i]) != MEMKIND_DEFAULT) { + void *temp = memkind_realloc(NULL, alloc_buffer[i], REALLOC_SIZE); + if (!temp) { + return 1; + } + alloc_buffer[i] = temp; + } + } + + return 0; +} + + +static int verify_allocation_size(struct memkind *pmem_kind, size_t pmem_size) +{ + unsigned i; + for(i = 0; i < ALLOC_LIMIT; i++) { + void *val = alloc_buffer[i]; + if (i%2) { + if (memkind_malloc_usable_size(pmem_kind, val) != pmem_size ) { + return 1; + } + } else { + if (memkind_malloc_usable_size(MEMKIND_DEFAULT, val) != MALLOC_SIZE) { + return 1; + } + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + + struct memkind *pmem_kind = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to distinguish allocation from different kinds using detect kind function" + "\nPMEM kind directory: %s\n", path); + + err = memkind_create_pmem(path, 0, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Allocate to PMEM and DEFAULT kind.\n"); + + if (allocate_pmem_and_default_kind(pmem_kind)) { + fprintf(stderr, "allocate_pmem_and_default_kind().\n"); + return 1; + } + + if (verify_allocation_size(pmem_kind, MALLOC_SIZE)) { + fprintf(stderr, "verify_allocation_size() before resize.\n"); + return 1; + } + + fprintf(stdout, + "Reallocate memory only on PMEM kind using memkind_detect_kind().\n"); + + if (realloc_using_get_kind_only_on_pmem()) { + fprintf(stderr, "realloc_using_get_kind_only_on_pmem().\n"); + return 1; + } + + if (verify_allocation_size(pmem_kind, REALLOC_SIZE)) { + fprintf(stderr, "verify_allocation_size() after resize.\n"); + return 1; + } + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory from PMEM kind was successfully reallocated.\n"); + + return 0; +} diff --git a/examples/pmem_free_with_unknown_kind.c b/examples/pmem_free_with_unknown_kind.c new file mode 100644 index 0000000..cedd18a --- /dev/null +++ b/examples/pmem_free_with_unknown_kind.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static char path[PATH_MAX]="/tmp/"; +static const size_t PMEM_PART_SIZE = MEMKIND_PMEM_MIN_SIZE + 4 * 1024; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char **argv) +{ + const size_t size = 512; + struct memkind *pmem_kind = NULL; + const int arraySize = 100; + char *ptr[100] = { NULL }; + int i = 0; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to use memkind_free with unknown kind as a parameter.\n"); + + err = memkind_create_pmem(path, PMEM_PART_SIZE, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + for (i = 0; i < arraySize; ++i) { + if (i < 50) { + ptr[i] = memkind_malloc(MEMKIND_DEFAULT, size); + if (ptr[i] == NULL) { + fprintf(stderr, "Unable to allocate memkind default.\n"); + return 1; + } + } else { + ptr[i] = memkind_malloc(pmem_kind, size); + if (ptr[i] == NULL) { + fprintf(stderr, "Unable to allocate pmem.\n"); + return 1; + } + } + } + fprintf(stdout, + "Memory was successfully allocated in default kind and pmem kind.\n"); + + sprintf(ptr[10], "Hello world from standard memory - ptr[10].\n"); + sprintf(ptr[40], "Hello world from standard memory - ptr[40].\n"); + sprintf(ptr[80], "Hello world from persistent memory - ptr[80].\n"); + + fprintf(stdout, "%s", ptr[10]); + fprintf(stdout, "%s", ptr[40]); + fprintf(stdout, "%s", ptr[80]); + + fprintf(stdout, "Free memory without specifying kind.\n"); + for (i = 0; i < arraySize; ++i) { + memkind_free(NULL, ptr[i]); + } + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory was successfully released.\n"); + + return 0; +} diff --git a/examples/pmem_kinds.c b/examples/pmem_kinds.c new file mode 100644 index 0000000..0571428 --- /dev/null +++ b/examples/pmem_kinds.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#define PMEM_MAX_SIZE (1024 * 1024 * 32) +#define NUM_KINDS 10 + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kinds[NUM_KINDS] = {NULL}; + struct memkind *pmem_kind = NULL; + struct memkind *pmem_kind_unlimited = NULL; + + int err = 0, i = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to create and destroy pmem kind with defined or unlimited size." + "\nPMEM kind directory: %s\n", path); + + // Create first PMEM partition with specific size + err = memkind_create_pmem(path, PMEM_MAX_SIZE, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + // Create second PMEM partition with unlimited size + err = memkind_create_pmem(path, 0, &pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + // Destroy both PMEM partitions + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + err = memkind_destroy_kind(pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + // Create many PMEM kinds with same specific size + for (i = 0; i < NUM_KINDS; i++) { + err = memkind_create_pmem(path, PMEM_MAX_SIZE, &pmem_kinds[i]); + if (err) { + print_err_message(err); + return 1; + } + } + + // Destroy all of them + for (i = 0; i < NUM_KINDS; i++) { + err = memkind_destroy_kind(pmem_kinds[i]); + if (err) { + print_err_message(err); + return 1; + } + } + + fprintf(stdout, "PMEM kinds have been successfully created and destroyed.\n"); + + return 0; +} diff --git a/examples/pmem_malloc.c b/examples/pmem_malloc.c new file mode 100644 index 0000000..61e201d --- /dev/null +++ b/examples/pmem_malloc.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#define PMEM_MAX_SIZE (1024 * 1024 * 32) + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to allocate memory and possibility to exceed pmem kind size." + "\nPMEM kind directory: %s\n", path); + + // Create PMEM partition with specific size + err = memkind_create_pmem(path, PMEM_MAX_SIZE, &pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + char *pmem_str1 = NULL; + char *pmem_str2 = NULL; + char *pmem_str3 = NULL; + char *pmem_str4 = NULL; + + // Allocate 512 Bytes of 32 MB available + pmem_str1 = (char *)memkind_malloc(pmem_kind, 512); + if (pmem_str1 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str1).\n"); + return 1; + } + + // Allocate 8 MB of 31.9 MB available + pmem_str2 = (char *)memkind_malloc(pmem_kind, 8 * 1024 * 1024); + if (pmem_str2 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str2).\n"); + return 1; + } + + // Allocate 16 MB of 23.9 MB available + pmem_str3 = (char *)memkind_malloc(pmem_kind, 16 * 1024 * 1024); + if (pmem_str3 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str3).\n"); + return 1; + } + + // Allocate 16 MB of 7.9 MB available - Out Of Memory expected + pmem_str4 = (char *)memkind_malloc(pmem_kind, 16 * 1024 * 1024); + if (pmem_str4 != NULL) { + fprintf(stderr, + "Failure, this allocation should not be possible (expected result was NULL).\n"); + return 1; + } + + sprintf(pmem_str1, "Hello world from pmem - pmem_str1.\n"); + sprintf(pmem_str2, "Hello world from pmem - pmem_str2.\n"); + sprintf(pmem_str3, "Hello world from persistent memory - pmem_str3.\n"); + + fprintf(stdout, "%s", pmem_str1); + fprintf(stdout, "%s", pmem_str2); + fprintf(stdout, "%s", pmem_str3); + + memkind_free(pmem_kind, pmem_str1); + memkind_free(pmem_kind, pmem_str2); + memkind_free(pmem_kind, pmem_str3); + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory was successfully allocated and released.\n"); + + return 0; +} diff --git a/examples/pmem_malloc_unlimited.c b/examples/pmem_malloc_unlimited.c new file mode 100644 index 0000000..a267069 --- /dev/null +++ b/examples/pmem_malloc_unlimited.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind_unlimited = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to allocate memory with unlimited kind size." + "\nPMEM kind directory: %s\n", path); + + // Create PMEM partition with unlimited size + err = memkind_create_pmem(path, 0, &pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + char *pmem_str10 = NULL; + char *pmem_str11 = NULL; + + // Huge allocation + pmem_str10 = (char *)memkind_malloc(pmem_kind_unlimited, 32 * 1024 * 1024); + if (pmem_str10 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str10).\n"); + return 1; + } + + // Another huge allocation, kind size is only limited by OS resources + pmem_str11 = (char *)memkind_malloc(pmem_kind_unlimited, 32 * 1024 * 1024); + if (pmem_str11 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str11).\n"); + return 1; + } + + memkind_free(pmem_kind_unlimited, pmem_str10); + memkind_free(pmem_kind_unlimited, pmem_str11); + + err = memkind_destroy_kind(pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, "Memory was successfully allocated and released.\n"); + + return 0; +} diff --git a/examples/pmem_multithreads.c b/examples/pmem_multithreads.c new file mode 100644 index 0000000..fe72a43 --- /dev/null +++ b/examples/pmem_multithreads.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#define PMEM_MAX_SIZE (1024 * 1024 * 32) +#define NUM_THREADS 10 + +static char path[PATH_MAX]="/tmp/"; + +void *thread_ind(void *arg); + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to use multithreading with independent pmem kinds." + "\nPMEM kind directory: %s\n", path); + + pthread_t pmem_threads[NUM_THREADS]; + int t; + + // Create many independent threads + for (t = 0; t < NUM_THREADS; t++) { + if (pthread_create(&pmem_threads[t], NULL, thread_ind, NULL) != 0) { + fprintf(stderr, "Unable to create a thread.\n"); + return 1; + } + } + + sleep(1); + if (pthread_cond_broadcast(&cond) != 0) { + fprintf(stderr, "Unable to broadcast a condition.\n"); + return 1; + } + + for (t = 0; t < NUM_THREADS; t++) { + if (pthread_join(pmem_threads[t], NULL) != 0) { + fprintf(stderr, "Thread join failed.\n"); + return 1; + } + } + + fprintf(stdout, "Threads successfully allocated memory in the PMEM kinds.\n"); + + return 0; +} + +void *thread_ind(void *arg) +{ + struct memkind *pmem_kind; + + if (pthread_mutex_lock(&mutex) != 0) { + fprintf(stderr, "Failed to acquire mutex.\n"); + return NULL; + } + if (pthread_cond_wait(&cond, &mutex) != 0) { + fprintf(stderr, "Failed to block mutex on condition.\n"); + return NULL; + } + if (pthread_mutex_unlock(&mutex) != 0) { + fprintf(stderr, "Failed to release mutex.\n"); + return NULL; + } + + int err = memkind_create_pmem(path, PMEM_MAX_SIZE, &pmem_kind); + if (err) { + print_err_message(err); + return NULL; + } + + void *test = memkind_malloc(pmem_kind, 32); + if (test == NULL) { + fprintf(stderr, "Unable to allocate pmem (test) in thread.\n"); + return NULL; + } + + memkind_free(pmem_kind, test); + + err = memkind_destroy_kind(pmem_kind); + if (err) { + print_err_message(err); + } + + return NULL; +} diff --git a/examples/pmem_multithreads_onekind.c b/examples/pmem_multithreads_onekind.c new file mode 100644 index 0000000..ed7bc07 --- /dev/null +++ b/examples/pmem_multithreads_onekind.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#define NUM_THREADS 10 +#define NUM_ALLOCS 100 +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +struct arg_struct { + int id; + struct memkind *kind; + int **ptr; +}; + +void *thread_onekind(void *arg); + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind_unlimited = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows how to use multithreading with one main pmem kind." + "\nPMEM kind directory: %s\n", path); + + // Create PMEM partition with unlimited size + err = memkind_create_pmem(path, 0, &pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + // Create a few threads which will access to our main pmem_kind + pthread_t pmem_threads[NUM_THREADS]; + int *pmem_tint[NUM_THREADS][NUM_ALLOCS]; + int t = 0, i = 0; + + struct arg_struct *args[NUM_THREADS]; + + for (t = 0; tid = t; + args[t]->ptr = &pmem_tint[t][0]; + args[t]->kind = pmem_kind_unlimited; + + if (pthread_create(&pmem_threads[t], NULL, thread_onekind, + (void *)args[t])!= 0) { + fprintf(stderr, "Unable to create a thread.\n"); + return 1; + } + } + + sleep(1); + if (pthread_cond_broadcast(&cond) != 0) { + fprintf(stderr, "Unable to broadcast a condition.\n"); + return 1; + } + + for (t = 0; t < NUM_THREADS; t++) { + if (pthread_join(pmem_threads[t], NULL) != 0) { + fprintf(stderr, "Thread join failed.\n"); + return 1; + } + } + + // Check if we can read the values outside of threads and free resources + for (t = 0; t < NUM_THREADS; t++) { + for (i = 0; i < NUM_ALLOCS; i++) { + if(*pmem_tint[t][i] != t) { + fprintf(stderr, + "pmem_tint value has not been saved correctly in the thread.\n"); + return 1; + } + memkind_free(args[t]->kind, *(args[t]->ptr+i)); + } + free(args[t]); + } + + fprintf(stdout, "Threads successfully allocated memory in the PMEM kind.\n"); + + return 0; +} + +void *thread_onekind(void *arg) +{ + struct arg_struct *args = (struct arg_struct *)arg; + int i; + + if (pthread_mutex_lock(&mutex) != 0) { + fprintf(stderr, "Failed to acquire mutex.\n"); + return NULL; + } + if (pthread_cond_wait(&cond, &mutex) != 0) { + fprintf(stderr, "Failed to block mutex on condition.\n"); + return NULL; + } + if (pthread_mutex_unlock(&mutex) != 0) { + fprintf(stderr, "Failed to release mutex.\n"); + return NULL; + } + + // Lets alloc int and put there thread ID + for (i = 0; i < NUM_ALLOCS; i++) { + *(args->ptr+i) = (int *)memkind_malloc(args->kind, sizeof(int)); + if (*(args->ptr+i) == NULL) { + fprintf(stderr, "Unable to allocate pmem int.\n"); + return NULL; + } + **(args->ptr+i) = args->id; + } + + return NULL; +} diff --git a/examples/pmem_usable_size.c b/examples/pmem_usable_size.c new file mode 100644 index 0000000..92dd078 --- /dev/null +++ b/examples/pmem_usable_size.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2018 - 2019 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#define MB (1024 * 1024) + +static char path[PATH_MAX]="/tmp/"; + +static void print_err_message(int err) +{ + char error_message[MEMKIND_ERROR_MESSAGE_SIZE]; + memkind_error_message(err, error_message, MEMKIND_ERROR_MESSAGE_SIZE); + fprintf(stderr, "%s\n", error_message); +} + +int main(int argc, char *argv[]) +{ + struct memkind *pmem_kind_unlimited = NULL; + int err = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [pmem_kind_dir_path]\n", argv[0]); + return 1; + } else if (argc == 2 && (realpath(argv[1], path) == NULL)) { + fprintf(stderr, "Incorrect pmem_kind_dir_path %s\n", argv[1]); + return 1; + } + + fprintf(stdout, + "This example shows difference between the expected and the actual allocation size." + "\nPMEM kind directory: %s\n", path); + + err = memkind_create_pmem(path, 0, &pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + char *pmem_str10 = NULL; + char *pmem_str11 = NULL; + char *pmem_str12 = NULL; + + // 32 bytes allocation + pmem_str10 = (char *)memkind_malloc(pmem_kind_unlimited, 32); + if (pmem_str10 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str10).\n"); + return 1; + } + + // Check real usable size for this allocation + if (memkind_malloc_usable_size(pmem_kind_unlimited, pmem_str10) != 32) { + fprintf(stderr, "Wrong usable size for small allocation (pmem_str10).\n"); + return 1; + } + + // 31 bytes allocation + pmem_str11 = (char *)memkind_malloc(pmem_kind_unlimited, 31); + if (pmem_str11 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str11).\n"); + return 1; + } + + // Check real usable size for this allocation, its 32 again + if (memkind_malloc_usable_size(pmem_kind_unlimited, pmem_str11) != 32) { + fprintf(stderr, "Wrong usable size for small allocation (pmem_str11).\n"); + return 1; + } + + // 33 bytes allocation + pmem_str12 = (char *)memkind_malloc(pmem_kind_unlimited, 33); + if (pmem_str12 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str12).\n"); + return 1; + } + + // Check real usable size for this allocation, its 48 now + if (memkind_malloc_usable_size(pmem_kind_unlimited, pmem_str12) != 48) { + fprintf(stderr, "Wrong usable size for small allocation (pmem_str12).\n"); + return 1; + } + + memkind_free(pmem_kind_unlimited, pmem_str10); + memkind_free(pmem_kind_unlimited, pmem_str11); + memkind_free(pmem_kind_unlimited, pmem_str12); + + // 5MB allocation + pmem_str10 = (char *)memkind_malloc(pmem_kind_unlimited, 5 * MB); + if (pmem_str10 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str10).\n"); + return 1; + } + + // Check real usable size for this allocation + if (memkind_malloc_usable_size(pmem_kind_unlimited, pmem_str10) != 5 * MB) { + fprintf(stderr, "Wrong usable size for large allocation (pmem_str10).\n"); + return 1; + } + + // 5MB + 1B allocation + pmem_str11 = (char *)memkind_malloc(pmem_kind_unlimited, 5 * MB + 1); + if (pmem_str11 == NULL) { + fprintf(stderr, "Unable to allocate pmem string (pmem_str11).\n"); + return 1; + } + + // Check real usable size for this allocation, its 6MB now + if (memkind_malloc_usable_size(pmem_kind_unlimited, pmem_str11) != 6 * MB) { + fprintf(stderr, "Wrong usable size for large allocation (pmem_str11).\n"); + return 1; + } + + memkind_free(pmem_kind_unlimited, pmem_str10); + memkind_free(pmem_kind_unlimited, pmem_str11); + + err = memkind_destroy_kind(pmem_kind_unlimited); + if (err) { + print_err_message(err); + return 1; + } + + fprintf(stdout, + "The real size of the allocation has been successfully read.\n"); + + return 0; +} diff --git a/include/hbw_allocator.h b/include/hbw_allocator.h new file mode 100644 index 0000000..ec9c1c0 --- /dev/null +++ b/include/hbw_allocator.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +#include +#include +/* + * Header file for the C++ allocator compatible with the C++ standard library allocator concepts. + * More details in hbwallocator(3) man page. + * Note: memory heap management is based on hbwmalloc, refer to the hbwmalloc man page for more information. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ +namespace hbw +{ + + template + class allocator + { + public: + /* + * Public member types required and defined by the standard library allocator concepts. + */ + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + + template + struct rebind { + typedef hbw::allocator other; + }; + + /* + * Public member functions required and defined by the standard library allocator concepts. + */ + allocator() throw() { } + + template + allocator(const allocator &) throw() { } + + ~allocator() throw() { } + + pointer address(reference x) const + { + return &x; + } + + const_pointer address(const_reference x) const + { + return &x; + } + + /* + * Allocates n*sizeof(T) bytes of high bandwidth memory using hbw_malloc(). + * Throws std::bad_alloc when cannot allocate memory. + */ + pointer allocate(size_type n, const void * = 0) + { + if (n > this->max_size()) { + throw std::bad_alloc(); + } + pointer result = static_cast(hbw_malloc(n * sizeof(T))); + if (!result) { + throw std::bad_alloc(); + } + return result; + } + + /* + * Deallocates memory associated with pointer returned by allocate() using hbw_free(). + */ + void deallocate(pointer p, size_type n) + { + hbw_free(static_cast(p)); + } + + size_type max_size() const throw() + { + return size_t(-1) / sizeof(T); + } + + void construct(pointer p, const_reference val) + { + ::new(p) value_type(val); + } + + void destroy(pointer p) + { + p->~T(); + } + }; + + template + bool operator==(const allocator &, const allocator &) + { + return true; + } + + template + bool operator!=(const allocator &, const allocator &) + { + return false; + } + +} diff --git a/include/hbwmalloc.h b/include/hbwmalloc.h new file mode 100644 index 0000000..3e8eac8 --- /dev/null +++ b/include/hbwmalloc.h @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include +/* + * Header file for the high bandwidth memory interface. + * + * This file defines the external API's and enumerations for the + * hbwmalloc library. These interfaces define a heap manager that + * targets the high bandwidth memory numa nodes. + * + * hbwmalloc.h functionality is considered as stable API (STANDARD API). + * + * Please read hbwmalloc(3) man page for or more details. + */ + +/* + * Fallback policy. + * + * Policy that determines behavior when there is not enough free high + * bandwidth memory to satisfy a user request. This enum is used with + * hbw_get_policy() and hbw_set_policy(). + */ +typedef enum { + /* + * If insufficient high bandwidth memory pages on nearest NUMA node are + * available then OOM killer will be triggered. + */ + HBW_POLICY_BIND = 1, + /* + * If insufficient high bandwidth memory pages are available fall + * back on standard memory pages. + */ + HBW_POLICY_PREFERRED = 2, + /* + * Interleave pages across high bandwidth nodes. If insufficient memory + * pages are available then OOM killer will be triggered. + */ + HBW_POLICY_INTERLEAVE = 3, + /* + * If insufficient high bandwidth memory pages are available then + * OOM killer will be triggered. + */ + HBW_POLICY_BIND_ALL = 4, +} hbw_policy_t; + +/* + * Page size selection. + * + * The hbw_posix_memalign_psize() API gives the user the option to + * select the page size from this enumerated list. + */ +typedef enum { + + /* + * The four kilobyte page size option. Note that with transparent huge + * pages enabled these allocations may be promoted by the operating system + * to two megabyte pages. + */ + HBW_PAGESIZE_4KB = 1, + + /* + * The two megabyte page size option. + */ + HBW_PAGESIZE_2MB = 2, + /* + * This option is deprecated. + * Allocate high bandwidth memory using 1GB chunks backed by huge pages. + */ + HBW_PAGESIZE_1GB_STRICT = 3, + + /* + * This option is deprecated. + * Allocate high bandwidth memory using 1GB chunks backed by huge pages. + */ + HBW_PAGESIZE_1GB = 4, + + /* + * Helper representing value of the last enum element incremented by 1. + * Shall not be treated as a valid value for functions taking hbw_pagesize_t + * as parameter. + */ + HBW_PAGESIZE_MAX_VALUE +} hbw_pagesize_t; + +/* + * Flags for hbw_verify_ptr function + */ +enum { + + /* + * This option touches first byte of all pages in address range starting from "addr" to "addr" + "size" + * by read and write (so the content will be overwritten by the same data as it was read). + */ + HBW_TOUCH_PAGES = (1 << 0) +}; + +/* + * Returns the current fallback policy when insufficient high bandwidth memory + * is available. + */ +hbw_policy_t hbw_get_policy(void); + +/* + * Sets the current fallback policy. The policy can be modified only once in + * the lifetime of an application and before calling hbw_*alloc() or + * hbw_posix_memalign*() function. + * Note: If the policy is not set, than HBW_POLICY_PREFERRED will be used by + * default. + * + * Returns: + * 0: on success + * EPERM: if hbw_set_policy () was called more than once + * EINVAL: if mode argument was neither HBW_POLICY_PREFERRED, HBW_POLICY_BIND, HBW_POLICY_BIND_ALL nor HBW_POLICY_INTERLEAVE + */ +int hbw_set_policy(hbw_policy_t mode); + +/* + * Verifies high bandwidth memory availability. + * Returns: + * 0: if high bandwidth memory is available + * ENODEV: if high-bandwidth memory is unavailable. + */ +int hbw_check_available(void); + +/* + * Verifies if allocated memory fully fall into high bandwidth memory. + * Returns: + * 0: if memory in address range from "addr" to "addr" + "size" is allocated in high bandwidth memory + * -1: if any region of memory was not allocated in high bandwidth memory + * EINVAL: if addr is NULL, size equals 0 or flags contained unsupported bit set + * EFAULT: could not verify memory + */ +int hbw_verify_memory_region(void *addr, size_t size, int flags); + +/* + * Allocates size bytes of uninitialized high bandwidth memory. + * The allocated space is suitably aligned (after possible pointer + * coercion) for storage of any type of object. If size is zero then + * hbw_malloc() returns NULL. + */ +void *hbw_malloc(size_t size); + +/* + * Allocates space for num objects in high bandwidth memory, each size bytes + * in length. + * The result is identical to calling hbw_malloc() with an argument of + * num*size, with the exception that the allocated memory is explicitly + * initialized to zero bytes. + * If num or size is 0, then hbw_calloc() returns NULL. + */ +void *hbw_calloc(size_t num, size_t size); + +/* + * Allocates size bytes of high bandwidth memory such that the allocation's + * base address is an even multiple of alignment, and returns the allocation + * in the value pointed to by memptr. The requested alignment must be a power + * of 2 at least as large as sizeof(void *). + * Returns: + * 0: on success + * ENOMEM: if there was insufficient memory to satisfy the request + * EINVAL: if the alignment parameter was not a power of two, or was less than sizeof(void *) + */ +int hbw_posix_memalign(void **memptr, size_t alignment, size_t size); + +/* + * Allocates size bytes of high bandwidth memory such that the allocation's + * base address is an even multiple of alignment, and returns the allocation + * in the value pointed to by memptr. The requested alignment must be a power + * of 2 at least as large as sizeof(void *). The memory will be allocated + * using pages determined by the pagesize variable. + * Returns: + * 0: on success + * ENOMEM: if there was insufficient memory to satisfy the request + * EINVAL: if the alignment parameter was not a power of two, or was less than sizeof(void *) + */ +int hbw_posix_memalign_psize(void **memptr, size_t alignment, size_t size, + hbw_pagesize_t pagesize); + +/* + * Changes the size of the previously allocated memory referenced by ptr to + * size bytes of the specified kind. The contents of the memory are unchanged + * up to the lesser of the new and old size. + * If the new size is larger, the contents of the newly allocated portion + * of the memory are undefined. + * Upon success, the memory referenced by ptr is freed and a pointer to the + * newly allocated high bandwidth memory is returned. + * Note: memkind_realloc() may move the memory allocation, resulting in a + * different return value than ptr. + * If ptr is NULL, the hbw_realloc() function behaves identically to + * hbw_malloc() for the specified size. The address ptr, if not NULL, + * was returned by a previous call to hbw_malloc(), hbw_calloc(), + * hbw_realloc(), or hbw_posix_memalign(). Otherwise, or if hbw_free(ptr) + * was called before, undefined behavior occurs. + * Note: hbw_realloc() cannot be used with a pointer returned by + * hbw_posix_memalign_psize(). + */ +void *hbw_realloc(void *ptr, size_t size); + +/* + * Causes the allocated memory referenced by ptr to be made + * available for future allocations. If ptr is NULL, no action occurs. + * The address ptr, if not NULL, must have been returned by a previous call + * to hbw_malloc(), hbw_calloc(), hbw_realloc(), hbw_posix_memalign(), or + * hbw_posix_memalign_psize(). Otherwise, if hbw_free(ptr) was called before, + * undefined behavior occurs. + */ +void hbw_free(void *ptr); + +/* + * Returns the number of usable bytes in the block pointed to by ptr, a pointer + * to a block of memory allocated by hbw_malloc(), hbw_calloc(), hbw_realloc(), + * hbw_posix_memalign(), or hbw_posix_memalign_psize(). + */ +size_t hbw_malloc_usable_size(void *ptr); + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind.h b/include/memkind.h new file mode 100644 index 0000000..0be640e --- /dev/null +++ b/include/memkind.h @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Header file for the memkind heap manager. + * More details in memkind(3) man page. + * + * API standards are described in memkind(3) man page. + */ + +/// \warning EXPERIMENTAL API +#define _MEMKIND_BIT(N) (1ull << N) + +/// \brief Memkind memory types +/// \warning EXPERIMENTAL API +typedef enum memkind_memtype_t { + + /** + * Select standard memory, the same as process use. + */ + MEMKIND_MEMTYPE_DEFAULT = _MEMKIND_BIT(0), + + /** + * Select high bandwidth memory (HBM). + * There must be at least two memories with different bandwidth to + * determine the HBM. + */ + MEMKIND_MEMTYPE_HIGH_BANDWIDTH = _MEMKIND_BIT(1) + +} memkind_memtype_t; + +#undef _MEMKIND_BIT + +/// \brief Memkind policy +/// \warning EXPERIMENTAL API +typedef enum memkind_policy_t { + + /** + * Allocate local memory. + * If there is not enough memory to satisfy the request errno is set to + * ENOMEM and the allocated pointer is set to NULL. + */ + MEMKIND_POLICY_BIND_LOCAL = 0, + + /** + * Memory locality is ignored. + * If there is not enough memory to satisfy the request errno is set to + * ENOMEM and the allocated pointer is set to NULL. + */ + MEMKIND_POLICY_BIND_ALL, + + /** + * Allocate preferred memory that is local. + * If there is not enough preferred memory to satisfy the request or + * preferred memory is not available, the allocation will fall back on any + * other memory. + */ + MEMKIND_POLICY_PREFERRED_LOCAL, + + /** + * Interleave allocation across local memory. + * For n memory types the allocation will be interleaved across all of + * them. + */ + MEMKIND_POLICY_INTERLEAVE_LOCAL, + + /** + * Interleave allocation. Locality is ignored. + * For n memory types the allocation will be interleaved across all of + * them. + */ + MEMKIND_POLICY_INTERLEAVE_ALL, + + /** + * Max policy value. + */ + MEMKIND_POLICY_MAX_VALUE + +} memkind_policy_t; + +/// \brief Memkind bits definition +/// \warning EXPERIMENTAL API +/// \note The bits specify flags and masks. Bits <0,1,2,...,7> are reserved for page size, where page sizes are encoded +/// by base-2 logarithm. If the page size bits are set to zero value, than default page size will be used. +typedef enum memkind_bits_t { + MEMKIND_MASK_PAGE_SIZE_2MB = 21ull, /**< Allocations backed by 2 MB page size (2^21 = 2MB) */ +} memkind_bits_t; + +/// \brief Memkind type definition +/// \warning EXPERIMENTAL API +typedef struct memkind *memkind_t; + + +/// \brief Memkind constant values +/// \warning EXPERIMENTAL API +enum memkind_const { + MEMKIND_MAX_KIND = 512, /**< Maximum number of kinds */ + MEMKIND_ERROR_MESSAGE_SIZE = 128, /**< Error message size */ + MEMKIND_PMEM_MIN_SIZE = (1024 * 1024 * 16) /**< The minimum size which allows to limit the file-backed memory partition */ +}; + +/// \brief Memkind operation statuses +/// \warning EXPERIMENTAL API +enum { + MEMKIND_SUCCESS = 0, /**< Operation success */ + MEMKIND_ERROR_UNAVAILABLE = -1, /**< Error: Memory kind is not available */ + MEMKIND_ERROR_MBIND = -2, /**< Error: Call to mbind() failed */ + MEMKIND_ERROR_MMAP = -3, /**< Error: Call to mmap() failed */ + MEMKIND_ERROR_MALLOC = -6, /**< Error: Call to malloc() failed */ + MEMKIND_ERROR_ENVIRON = -12, /**< Error: Unable to parse environment variable */ + MEMKIND_ERROR_INVALID = -13, /**< Error: Invalid argument */ + MEMKIND_ERROR_TOOMANY = -15, /**< Error: Attempt to initialize more than MEMKIND_MAX_KIND number of kinds */ + MEMKIND_ERROR_BADOPS = -17, /**< Error: Invalid memkind_ops structure */ + MEMKIND_ERROR_HUGETLB = -18, /**< Error: Unable to allocate huge pages */ + MEMKIND_ERROR_MEMTYPE_NOT_AVAILABLE = -20, /**< Error: Requested memory type is not available */ + MEMKIND_ERROR_OPERATION_FAILED = -21, /**< Error: Operation failed */ + MEMKIND_ERROR_ARENAS_CREATE = -22, /**< Error: Call to jemalloc's arenas.create failed */ + MEMKIND_ERROR_RUNTIME = -255 /**< Error: Unspecified run-time error */ +}; + +/* KIND CONFIGURATION MANAGEMENT INTERFACE */ + +/// \brief Memkind memory usage policy +typedef enum memkind_mem_usage_policy { + MEMKIND_MEM_USAGE_POLICY_DEFAULT = 0, /**< Default memory usage */ + MEMKIND_MEM_USAGE_POLICY_CONSERVATIVE = 1, /**< Minimize memory usage at all costs, */ + MEMKIND_MEM_USAGE_POLICY_MAX_VALUE +} memkind_mem_usage_policy; + +/// \brief Memkind memory statistics type +typedef enum memkind_stat_type { + MEMKIND_STAT_TYPE_RESIDENT = 0, /**< Maximum number of bytes in physically resident data pages mapped */ + MEMKIND_STAT_TYPE_ACTIVE = 1, /**< Total number of bytes in active pages */ + MEMKIND_STAT_TYPE_ALLOCATED = 2, /**< Total number of allocated bytes */ + MEMKIND_STAT_TYPE_MAX_VALUE +} memkind_stat_type; + +/// \brief Forward declaration of memkind configuration +struct memkind_config; + +/// +/// \brief Create a memkind configuration +/// \note STANDARD API +/// \return Memkind configuration, NULL on failure +/// +struct memkind_config *memkind_config_new(void); + +/// +/// \brief Delete memkind configuration +/// \note STANDARD API +/// \param cfg memkind configuration +/// +void memkind_config_delete(struct memkind_config *cfg); + +/// +/// \brief Update memkind configuration with path to specified directory parameter +/// \note STANDARD API +/// \param cfg memkind configuration +/// \param pmem_dir path to specified directory for PMEM kind +/// +void memkind_config_set_path(struct memkind_config *cfg, const char *pmem_dir); + +/// +/// \brief Update memkind configuration with PMEM kind size +/// \note STANDARD API +/// \param cfg memkind configuration +/// \param pmem_size size limit for PMEM kind +/// +void memkind_config_set_size(struct memkind_config *cfg, size_t pmem_size); + +/// +/// \brief Update memkind configuration with memory usage policy parameter +/// \note STANDARD API +/// \param cfg memkind configuration +/// \param policy memkind memory usage policy +/// +void memkind_config_set_memory_usage_policy(struct memkind_config *cfg, + memkind_mem_usage_policy policy); + +/// +/// \brief Create kind that allocates memory with specific memory type, memory binding policy and flags. +/// \warning EXPERIMENTAL API +/// \note Currently implemented memory type and policy configurations: +///. {MEMKIND_MEMTYPE_DEFAULT, MEMKIND_POLICY_PREFERRED_LOCAL}, +///. {MEMKIND_MEMTYPE_HIGH_BANDWIDTH, MEMKIND_POLICY_BIND_LOCAL}, +/// {MEMKIND_MEMTYPE_HIGH_BANDWIDTH, MEMKIND_POLICY_PREFERRED_LOCAL}, +/// {MEMKIND_MEMTYPE_HIGH_BANDWIDTH, MEMKIND_POLICY_INTERLEAVE_ALL}, +/// {MEMKIND_MEMTYPE_DEFAULT | MEMKIND_MEMTYPE_HIGH_BANDWIDTH, MEMKIND_POLICY_INTERLEAVE_ALL}. +/// \param memtype_flags determine the memory types to allocate from by combination of memkind_memtype_t values. +/// This field cannot have zero value. +/// \param policy specify policy for page binding to memory types selected by memtype_flags. +/// This field must be set to memkind_policy_t value. If policy is set to MEMKIND_POLICY_PREFERRED_LOCAL then only one memory +/// type must be selected. Note: the value cannot be set to MEMKIND_POLICY_MAX_VALUE. +/// \param flags the field must be set to a combination of memkind_bits_t values. +/// \param kind pointer to kind which will be created +/// \return Memkind operation status, MEMKIND_SUCCESS on success, MEMKIND_ERROR_MEMTYPE_NOT_AVAILABLE or MEMKIND_ERROR_INVALID on failure +/// +int memkind_create_kind(memkind_memtype_t memtype_flags, + memkind_policy_t policy, + memkind_bits_t flags, + memkind_t *kind); + +/// +/// \brief Destroy previously created kind object, which must have been returned +/// by a call to memkind_create_kind() or memkind_create_pmem(). +/// The function has undefined behavior when the handle is invalid or +/// memkind_destroy_kind(kind) was already called before +/// \warning EXPERIMENTAL API +/// \note if the kind was returned by memkind_create_kind() all allocated memory must be freed +/// before kind is destroyed, otherwise this will cause memory leak. +/// \param kind specified memory kind +/// \return Memkind operation status, MEMKIND_SUCCESS on success, MEMKIND_ERROR_OPERATION_FAILED on failure +/// +int memkind_destroy_kind(memkind_t kind); + +/// +/// \brief Get kind associated with allocated memory referenced by ptr +/// \note STANDARD API +/// \note This function has non-trivial performance overhead +/// \param ptr pointer to the allocated memory +/// \return Kind associated with allocated memory, NULL on failure +/// +memkind_t memkind_detect_kind(void *ptr); + +#include "memkind_deprecated.h" + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_REGULAR; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_DEFAULT; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HUGETLB; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_ALL; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_PREFERRED; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_HUGETLB; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_ALL_HUGETLB; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_PREFERRED_HUGETLB; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_HBW_INTERLEAVE; + +/// \warning EXPERIMENTAL API +extern memkind_t MEMKIND_INTERLEAVE; + +/// \note STANDARD API +extern memkind_t MEMKIND_DAX_KMEM; + +/// \note STANDARD API +extern memkind_t MEMKIND_DAX_KMEM_ALL; + +/// \note STANDARD API +extern memkind_t MEMKIND_DAX_KMEM_PREFERRED; + +/// +/// \brief Get Memkind API version +/// \note STANDARD API +/// \return Version number represented by a single integer number(major * 1000000 + minor * 1000 + patch) +/// +int memkind_get_version(); + +/// +/// \brief Convert error number into an error message +/// \note STANDARD API +/// \param err error number +/// \param msg error message +/// \param size size of message +/// +void memkind_error_message(int err, char *msg, size_t size); + +/// +/// \brief Create a new PMEM (file-backed) kind of given size on top of a temporary file +/// in the given directory dir +/// \note STANDARD API +/// \param dir path to specified directory to temporary file +/// \param max_size size limit for kind +/// \param kind pointer to kind which will be created +/// \return Memkind operation status, MEMKIND_SUCCESS on success, other values on failure +/// +int memkind_create_pmem(const char *dir, size_t max_size, memkind_t *kind); + +/// +/// \brief Create a new PMEM kind with given memkind configuration +/// \note STANDARD API +/// \param cfg memkind configuration for specifying PMEM parameters +/// \param kind pointer to kind which will be created +/// \return Memkind operation status, MEMKIND_SUCCESS on success, other values on failure +/// +int memkind_create_pmem_with_config(struct memkind_config *cfg, + memkind_t *kind); + +/// +/// \brief Check if kind is available +/// \note STANDARD API +/// \param kind specified memory kind +/// \return Memkind operation status, MEMKIND_SUCCESS on success, other values on failure +/// +int memkind_check_available(memkind_t kind); + +/// +/// \brief Update memkind cached statistics +/// \note STANDARD API +/// \return Memkind operation status, MEMKIND_SUCCESS on success, other values on failure +/// +int memkind_update_cached_stats(void); + +/// +/// \brief Get memkind statistic +/// \note STANDARD API +/// \param kind specified memory kind +/// \param stat specified type of memory statistic +/// \param value reference to value of memory statistic +/// \return Memkind operation status, MEMKIND_SUCCESS on success, other values on failure +/// +int memkind_get_stat(memkind_t kind, memkind_stat_type stat, size_t *value); + +/* HEAP MANAGEMENT INTERFACE */ + +/// +/// \brief Allocates size bytes of uninitialized storage of the specified kind +/// \note STANDARD API +/// \param kind specified memory kind +/// \param size number of bytes to allocate +/// \return Pointer to the allocated memory +/// +void *memkind_malloc(memkind_t kind, size_t size); + +/// +/// \brief Obtain size of block of memory allocated with the memkind API +/// \note STANDARD API +/// \param kind specified memory kind +/// \param ptr pointer to the allocated memory +/// \return Number of usable bytes +/// +size_t memkind_malloc_usable_size(memkind_t kind, void *ptr); + +/// +/// \brief Allocates memory of the specified kind for an array of num elements +/// of size bytes each and initializes all bytes in the allocated storage to zero +/// \note STANDARD API +/// \param kind specified memory kind +/// \param num number of objects +/// \param size specified size of each element +/// \return Pointer to the allocated memory +/// +void *memkind_calloc(memkind_t kind, size_t num, size_t size); + +/// +/// \brief Allocates size bytes of the specified kind and places the address of the allocated memory +/// in *memptr. The address of the allocated memory will be a multiple of alignment, +/// which must be a power of two and a multiple of sizeof(void *) +/// \note EXPERIMENTAL API +/// \param kind specified memory kind +/// \param memptr address of the allocated memory +/// \param alignment specified alignment of bytes +/// \param size specified size of bytes +/// \return Memkind operation status, MEMKIND_SUCCESS on success, EINVAL or ENOMEM on failure +/// +int memkind_posix_memalign(memkind_t kind, void **memptr, size_t alignment, + size_t size); + +/// +/// \brief Reallocates memory of the specified kind +/// \note STANDARD API +/// \param kind specified memory kind +/// \param ptr pointer to the memory block to be reallocated +/// \param size new size for the memory block in bytes +/// \return Pointer to the allocated memory +/// +void *memkind_realloc(memkind_t kind, void *ptr, size_t size); + +/// +/// \brief Free the memory space of the specified kind pointed by ptr +/// \note STANDARD API +/// \param kind specified memory kind +/// \param ptr pointer to the allocated memory +/// +void memkind_free(memkind_t kind, void *ptr); + +/// +/// \brief Try to reallocate allocation to reduce fragmentation +/// \note STANDARD API +/// \param kind specified memory kind +/// \param ptr pointer to the allocated memory +/// \return Pointer to newly transferred allocated memory +/// +void *memkind_defrag_reallocate(memkind_t kind, void *ptr); + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/heap_manager.h b/include/memkind/internal/heap_manager.h new file mode 100644 index 0000000..2686f1f --- /dev/null +++ b/include/memkind/internal/heap_manager.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +void heap_manager_init(struct memkind *kind); +void heap_manager_free(void *ptr); +size_t heap_manager_malloc_usable_size(void *ptr); +void *heap_manager_realloc(void *ptr, size_t size); +struct memkind *heap_manager_detect_kind(void *ptr); +int heap_manager_update_cached_stats(void); +int heap_manager_get_stat(memkind_stat_type stat, size_t *value); +void *heap_manager_defrag_reallocate(void *ptr); diff --git a/include/memkind/internal/memkind_arena.h b/include/memkind/internal/memkind_arena.h new file mode 100644 index 0000000..210c3b2 --- /dev/null +++ b/include/memkind/internal/memkind_arena.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * Header file for the jemalloc arena allocation memkind operations. + * More details in memkind_arena(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +struct memkind *get_kind_by_arena(unsigned arena_ind); +struct memkind *memkind_arena_detect_kind(void *ptr); +int memkind_arena_create(struct memkind *kind, struct memkind_ops *ops, + const char *name); +int memkind_arena_create_map(struct memkind *kind, extent_hooks_t *hooks); +int memkind_arena_destroy(struct memkind *kind); +void *memkind_arena_malloc(struct memkind *kind, size_t size); +void *memkind_arena_calloc(struct memkind *kind, size_t num, size_t size); +int memkind_arena_posix_memalign(struct memkind *kind, void **memptr, + size_t alignment, size_t size); +void *memkind_arena_realloc(struct memkind *kind, void *ptr, size_t size); +void *memkind_arena_realloc_with_kind_detect(void *ptr, size_t size); +int memkind_bijective_get_arena(struct memkind *kind, unsigned int *arena, + size_t size); +int memkind_thread_get_arena(struct memkind *kind, unsigned int *arena, + size_t size); +int memkind_arena_finalize(struct memkind *kind); +void memkind_arena_init(struct memkind *kind); +void memkind_arena_free(struct memkind *kind, void *ptr); +void memkind_arena_free_with_kind_detect(void *ptr); +size_t memkind_arena_malloc_usable_size(void *ptr); +int memkind_arena_update_memory_usage_policy(struct memkind *kind, + memkind_mem_usage_policy policy); +int memkind_arena_enable_background_threads(size_t threads_limit); +int memkind_arena_update_cached_stats(void); +int memkind_arena_get_kind_stat(struct memkind *kind, + memkind_stat_type stat_type, + size_t *stat); +int memkind_arena_get_stat_with_check_init(struct memkind *kind, + memkind_stat_type stat, bool check_init, size_t *value); +int memkind_arena_get_global_stat(memkind_stat_type stat_type, size_t *stat); +void *memkind_arena_defrag_reallocate(struct memkind *kind, void *ptr); +void *memkind_arena_defrag_reallocate_with_kind_detect(void *ptr); +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_bandwidth.h b/include/memkind/internal/memkind_bandwidth.h new file mode 100644 index 0000000..e741a0b --- /dev/null +++ b/include/memkind/internal/memkind_bandwidth.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct vec_cpu_node; + +typedef int (*get_node_bitmask)(struct bitmask *); +typedef int (*fill_bandwidth_values)(int *); + +int bandwidth_fill(int *bandwidth, get_node_bitmask get_bitmask); +int set_closest_numanode(fill_bandwidth_values fill, const char *env, + struct vec_cpu_node **closest_numanode, int num_cpu, bool is_single_node); +void set_bitmask_for_all_closest_numanodes(unsigned long *nodemask, + unsigned long maxnode, const struct vec_cpu_node *closest_numanode, + int num_cpu); +int set_bitmask_for_current_closest_numanode(unsigned long *nodemask, + unsigned long maxnode, const struct vec_cpu_node *closest_numanode, + int num_cpu); + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_dax_kmem.h b/include/memkind/internal/memkind_dax_kmem.h new file mode 100644 index 0000000..2bbc193 --- /dev/null +++ b/include/memkind/internal/memkind_dax_kmem.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Header file for the DAX KMEM memory memkind operations. + * More details in memkind_dax_kmem(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +int memkind_dax_kmem_all_get_mbind_nodemask(struct memkind *kind, + unsigned long *nodemask, unsigned long maxnode); + +extern struct memkind_ops MEMKIND_DAX_KMEM_OPS; +extern struct memkind_ops MEMKIND_DAX_KMEM_ALL_OPS; +extern struct memkind_ops MEMKIND_DAX_KMEM_PREFERRED_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_default.h b/include/memkind/internal/memkind_default.h new file mode 100644 index 0000000..51e24d5 --- /dev/null +++ b/include/memkind/internal/memkind_default.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* + * Header file for the default implementations for memkind operations. + * More details in memkind_default(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +int memkind_default_create(struct memkind *kind, struct memkind_ops *ops, + const char *name); +int memkind_default_destroy(struct memkind *kind); +void *memkind_default_malloc(struct memkind *kind, size_t size); +void *memkind_default_calloc(struct memkind *kind, size_t num, size_t size); +int memkind_default_posix_memalign(struct memkind *kind, void **memptr, + size_t alignment, size_t size); +void *memkind_default_realloc(struct memkind *kind, void *ptr, size_t size); +void memkind_default_free(struct memkind *kind, void *ptr); +void *memkind_default_mmap(struct memkind *kind, void *addr, size_t size); +int memkind_default_mbind(struct memkind *kind, void *ptr, size_t size); +int memkind_default_get_mmap_flags(struct memkind *kind, int *flags); +int memkind_default_get_mbind_mode(struct memkind *kind, int *mode); +int memkind_default_get_mbind_nodemask(struct memkind *kind, + unsigned long *nodemask, unsigned long maxnode); +int memkind_preferred_get_mbind_mode(struct memkind *kind, int *mode); +int memkind_interleave_get_mbind_mode(struct memkind *kind, int *mode); +int memkind_nohugepage_madvise(struct memkind *kind, void *addr, size_t size); +int memkind_posix_check_alignment(struct memkind *kind, size_t alignment); +void memkind_default_init_once(void); +size_t memkind_default_malloc_usable_size(struct memkind *kind, void *ptr); +static inline bool size_out_of_bounds(size_t size) +{ + return !size; +} + +extern struct memkind_ops MEMKIND_DEFAULT_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_gbtlb.h b/include/memkind/internal/memkind_gbtlb.h new file mode 100755 index 0000000..97f0796 --- /dev/null +++ b/include/memkind/internal/memkind_gbtlb.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Header file for the gigabyte TLB memkind operations. + * + * All function declarations has been moved to memkind_deprecated.h + * because of end of GBTLB support. + * + * API standards are described in memkind(3) man page. + */ + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_hbw.h b/include/memkind/internal/memkind_hbw.h new file mode 100755 index 0000000..7eb039d --- /dev/null +++ b/include/memkind/internal/memkind_hbw.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Header file for the high bandwidth memory memkind operations. + * More details in memkind_hbw(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +int memkind_hbw_check_available(struct memkind *kind); +int memkind_hbw_hugetlb_check_available(struct memkind *kind); +int memkind_hbw_get_mbind_nodemask(struct memkind *kind, + unsigned long *nodemask, + unsigned long maxnode); +int memkind_hbw_all_get_mbind_nodemask(struct memkind *kind, + unsigned long *nodemask, + unsigned long maxnode); +void memkind_hbw_init_once(void); +void memkind_hbw_all_init_once(void); +void memkind_hbw_hugetlb_init_once(void); +void memkind_hbw_all_hugetlb_init_once(void); +void memkind_hbw_preferred_init_once(void); +void memkind_hbw_preferred_hugetlb_init_once(void); +void memkind_hbw_interleave_init_once(void); + +extern struct memkind_ops MEMKIND_HBW_OPS; +extern struct memkind_ops MEMKIND_HBW_ALL_OPS; +extern struct memkind_ops MEMKIND_HBW_HUGETLB_OPS; +extern struct memkind_ops MEMKIND_HBW_ALL_HUGETLB_OPS; +extern struct memkind_ops MEMKIND_HBW_PREFERRED_OPS; +extern struct memkind_ops MEMKIND_HBW_PREFERRED_HUGETLB_OPS; +extern struct memkind_ops MEMKIND_HBW_INTERLEAVE_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_hugetlb.h b/include/memkind/internal/memkind_hugetlb.h new file mode 100755 index 0000000..d76915f --- /dev/null +++ b/include/memkind/internal/memkind_hugetlb.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Header file for the hugetlb memory memkind operations. + * More details in memkind_hugetlb(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +int memkind_hugetlb_get_mmap_flags(struct memkind *kind, int *flags); +void memkind_hugetlb_init_once(void); +int memkind_hugetlb_check_available_2mb(struct memkind *kind); + +extern struct memkind_ops MEMKIND_HUGETLB_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_interleave.h b/include/memkind/internal/memkind_interleave.h new file mode 100755 index 0000000..1913d6a --- /dev/null +++ b/include/memkind/internal/memkind_interleave.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Header file for the interleave memory memkind operations. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +void memkind_interleave_init_once(void); + +extern struct memkind_ops MEMKIND_INTERLEAVE_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_log.h b/include/memkind/internal/memkind_log.h new file mode 100644 index 0000000..7e9b7e0 --- /dev/null +++ b/include/memkind/internal/memkind_log.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 - 2018 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#define PRINTF_FORMAT __attribute__ ((format (printf, 1, 2))) + +/* + * For printing informational messages + * Requires environment variable MEMKIND_DEBUG to be set to appropriate value + */ +void log_info(const char *format, ...) PRINTF_FORMAT; + +/* + * For printing messages regarding errors and failures + * Requires environment variable MEMKIND_DEBUG to be set to appropriate value + */ +void log_err(const char *format, ...) PRINTF_FORMAT; + +/* + * For printing messages regarding fatal errors before calling abort() + * Works *no matter* of MEMKIND_DEBUG state + */ +void log_fatal(const char *format, ...)PRINTF_FORMAT; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_pmem.h b/include/memkind/internal/memkind_pmem.h new file mode 100644 index 0000000..b6098ba --- /dev/null +++ b/include/memkind/internal/memkind_pmem.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "memkind_default.h" +#include "memkind_arena.h" + +#include + +/* + * Header file for the file-backed memory memkind operations. + * More details in memkind_pmem(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +#define MEMKIND_PMEM_CHUNK_SIZE (1ull << 21ull) // 2MB + +int memkind_pmem_create(struct memkind *kind, struct memkind_ops *ops, + const char *name); +int memkind_pmem_destroy(struct memkind *kind); +void *memkind_pmem_mmap(struct memkind *kind, void *addr, size_t size); +int memkind_pmem_get_mmap_flags(struct memkind *kind, int *flags); + +struct memkind_pmem { + int fd; + off_t offset; + size_t max_size; + pthread_mutex_t pmem_lock; + size_t current_size; +}; + +extern struct memkind_ops MEMKIND_PMEM_OPS; + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/memkind_private.h b/include/memkind/internal/memkind_private.h new file mode 100644 index 0000000..af01ba5 --- /dev/null +++ b/include/memkind/internal/memkind_private.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2016 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include "memkind.h" + +#include +#include + +#ifdef __GNUC__ +# define MEMKIND_LIKELY(x) __builtin_expect(!!(x), 1) +# define MEMKIND_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define MEMKIND_LIKELY(x) (x) +# define MEMKIND_UNLIKELY(x) (x) +#endif + +#ifndef MEMKIND_EXPORT +# define MEMKIND_EXPORT __attribute__((visibility("default"))) +#endif + +// This ladder call is required due to meanders of C's preprocessor logic. +// Without it, JE_PREFIX would be used directly (i.e. 'JE_PREFIX') and not +// substituted with defined value. +#define JE_SYMBOL2(a, b) a ## b +#define JE_SYMBOL1(a, b) JE_SYMBOL2(a, b) +#define JE_SYMBOL(b) JE_SYMBOL1(JE_PREFIX, b) + +// Redefine symbols +#define jemk_malloc JE_SYMBOL(malloc) +#define jemk_mallocx JE_SYMBOL(mallocx) +#define jemk_calloc JE_SYMBOL(calloc) +#define jemk_rallocx JE_SYMBOL(rallocx) +#define jemk_realloc JE_SYMBOL(realloc) +#define jemk_mallctl JE_SYMBOL(mallctl) +#define jemk_memalign JE_SYMBOL(memalign) +#define jemk_posix_memalign JE_SYMBOL(posix_memalign) +#define jemk_free JE_SYMBOL(free) +#define jemk_dallocx JE_SYMBOL(dallocx) +#define jemk_malloc_usable_size JE_SYMBOL(malloc_usable_size) + +enum memkind_const_private { + MEMKIND_NAME_LENGTH_PRIV = 64 +}; + +struct memkind_ops { + int (* create)(struct memkind *kind, struct memkind_ops *ops, const char *name); + int (* destroy)(struct memkind *kind); + void *(* malloc)(struct memkind *kind, size_t size); + void *(* calloc)(struct memkind *kind, size_t num, size_t size); + int (* posix_memalign)(struct memkind *kind, void **memptr, size_t alignment, + size_t size); + void *(* realloc)(struct memkind *kind, void *ptr, size_t size); + void (* free)(struct memkind *kind, void *ptr); + void *(* mmap)(struct memkind *kind, void *addr, size_t size); + int (* mbind)(struct memkind *kind, void *ptr, size_t size); + int (* madvise)(struct memkind *kind, void *addr, size_t size); + int (* get_mmap_flags)(struct memkind *kind, int *flags); + int (* get_mbind_mode)(struct memkind *kind, int *mode); + int (* get_mbind_nodemask)(struct memkind *kind, unsigned long *nodemask, + unsigned long maxnode); + int (* get_arena)(struct memkind *kind, unsigned int *arena, size_t size); + int (* check_available)(struct memkind *kind); + void (* init_once)(void); + int (* finalize)(struct memkind *kind); + size_t (* malloc_usable_size)(struct memkind *kind, void *ptr); + int (* update_memory_usage_policy)(struct memkind *kind, + memkind_mem_usage_policy policy); + int (* get_stat)(memkind_t kind, memkind_stat_type stat, size_t *value); + void *(* defrag_reallocate)(struct memkind *kind, void *ptr); +}; + +struct memkind { + struct memkind_ops *ops; + unsigned int partition; + char name[MEMKIND_NAME_LENGTH_PRIV]; + pthread_once_t init_once; + unsigned int arena_map_len; // is power of 2 + unsigned int *arena_map; // To be deleted beyond 1.2.0+ + pthread_key_t arena_key; + void *priv; + unsigned int + arena_map_mask; // arena_map_len - 1 to optimize modulo operation on arena_map_len + unsigned int arena_zero; // index first jemalloc arena of this kind +}; + +struct memkind_config { + const char *pmem_dir; //PMEM kind path + size_t pmem_size; //PMEM kind size + memkind_mem_usage_policy policy; //kind memory usage policy +}; + +void memkind_init(memkind_t kind, bool check_numa); + +void *kind_mmap(struct memkind *kind, void *addr, size_t size); + +#ifdef __cplusplus +} +#endif + diff --git a/include/memkind/internal/memkind_regular.h b/include/memkind/internal/memkind_regular.h new file mode 100755 index 0000000..067ea04 --- /dev/null +++ b/include/memkind/internal/memkind_regular.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Header file for the regular memory memkind operations. + * More details in memkind_regular(3) man page. + * + * Functionality defined in this header is considered as EXPERIMENTAL API. + * API standards are described in memkind(3) man page. + */ + +extern struct memkind_ops MEMKIND_REGULAR_OPS; +int memkind_regular_all_get_mbind_nodemask(struct memkind *kind, + unsigned long *nodemask, + unsigned long maxnode); + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/tbb_mem_pool_policy.h b/include/memkind/internal/tbb_mem_pool_policy.h new file mode 100644 index 0000000..085cb29 --- /dev/null +++ b/include/memkind/internal/tbb_mem_pool_policy.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2005-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +#include + +typedef void *(*rawAllocType)(intptr_t pool_id, size_t *bytes); +typedef int (*rawFreeType)(intptr_t pool_id, void *raw_ptr, size_t raw_bytes); + +struct MemPoolPolicy { + rawAllocType pAlloc; + rawFreeType pFree; + size_t granularity; + int version; + unsigned fixedPool : 1, + keepAllMemory : 1, + reserved : 30; +}; diff --git a/include/memkind/internal/tbb_wrapper.h b/include/memkind/internal/tbb_wrapper.h new file mode 100644 index 0000000..11615d8 --- /dev/null +++ b/include/memkind/internal/tbb_wrapper.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* dynamically load TBB symbols */ +void load_tbb_symbols(void); + +/* ops callbacks are replaced by TBB callbacks. */ +void tbb_initialize(struct memkind *kind); + +/* ptr pointer must come from the valid TBB pool allocation */ +void tbb_pool_free_with_kind_detect(void *ptr); + +/* ptr pointer must come from the valid TBB pool allocation */ +void *tbb_pool_realloc_with_kind_detect(void *ptr, size_t size); + +/* ptr pointer must come from the valid TBB pool allocation */ +size_t tbb_pool_malloc_usable_size_with_kind_detect(void *ptr); + +/* ptr pointer must come from the valid TBB pool allocation */ +struct memkind *tbb_detect_kind(void *ptr); + +/* update cached stats for TBB (unsupported) */ +int tbb_update_cached_stats(void); + +/* get allocator stat for TBB (unsupported) */ +int tbb_get_global_stat(memkind_stat_type stat, size_t *value); + +/* defrag reallocate for TBB (unsupported) */ +void *tbb_pool_defrag_reallocate_with_kind_detect(void *ptr); +#ifdef __cplusplus +} +#endif diff --git a/include/memkind/internal/vec.h b/include/memkind/internal/vec.h new file mode 100644 index 0000000..982618f --- /dev/null +++ b/include/memkind/internal/vec.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define VEC_INIT_SIZE (8) + +#define VEC(name, type)\ +struct name {\ + type *buffer;\ + size_t size;\ + size_t capacity;\ +} + +static inline int +vec_reserve(void *vec, size_t ncapacity, size_t s) +{ + size_t ncap = ncapacity == 0 ? VEC_INIT_SIZE : ncapacity; + VEC(vvec, void) *vecp = (struct vvec *)vec; + void *tbuf = realloc(vecp->buffer, s * ncap); + if (tbuf == NULL) { + return -1; + } + vecp->buffer = tbuf; + vecp->capacity = ncap; + return 0; +} + +#define VEC_RESERVE(vec, ncapacity)\ +(((vec)->size == 0 || (ncapacity) > (vec)->size) ?\ + vec_reserve((void *)vec, ncapacity, sizeof(*(vec)->buffer)) :\ + 0) + +#define VEC_INSERT(vec, element)\ +((vec)->buffer[(vec)->size - 1] = (element), 0) + +#define VEC_INC_SIZE(vec)\ +(((vec)->size++), 0) + +#define VEC_INC_BACK(vec)\ +((vec)->capacity == (vec)->size ?\ + (VEC_RESERVE((vec), ((vec)->capacity * 2)) == 0 ?\ + VEC_INC_SIZE(vec) : -1) :\ + VEC_INC_SIZE(vec)) + +#define VEC_PUSH_BACK(vec, element)\ +(VEC_INC_BACK(vec) == 0? VEC_INSERT(vec, element) : -1) + +#define VEC_FOREACH(el, vec)\ +size_t _vec_i; \ +for (_vec_i = 0;\ + _vec_i < (vec)->size && (((el) = (vec)->buffer[_vec_i]), 1);\ + ++_vec_i) + +#define VEC_SIZE(vec)\ +((vec)->size) + +#define VEC_GET(vec, id)\ +(&(vec)->buffer[id]) + +#define VEC_CLEAR(vec) do {\ + (vec)->size = 0;\ +} while (0) + +#define VEC_DELETE(vec) do {\ + free((vec)->buffer);\ + (vec)->buffer = NULL;\ + (vec)->size = 0;\ + (vec)->capacity = 0;\ +} while (0) + +#ifdef __cplusplus +} +#endif diff --git a/include/memkind_allocator.h b/include/memkind_allocator.h new file mode 100644 index 0000000..45bde75 --- /dev/null +++ b/include/memkind_allocator.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019 - 2020 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "memkind.h" + +/* + * Header file for the C++ allocator compatible with the C++ standard library allocator concepts. + * More details in memkind(3) man page. + * Note: memory heap management is based on memkind_malloc, refer to the memkind(3) man page for more + * information. + * + * Functionality defined in this header is considered as stable API (STANDARD API). + * API standards are described in memkind(3) man page. + */ +namespace libmemkind +{ + enum class kinds { + DEFAULT = 0, + HUGETLB = 1, + INTERLEAVE = 2, + HBW = 3, + HBW_ALL = 4, + HBW_HUGETLB = 5, + HBW_ALL_HUGETLB = 6, + HBW_PREFERRED = 7, + HBW_PREFERRED_HUGETLB = 8, + HBW_INTERLEAVE = 9, + REGULAR = 10, + DAX_KMEM = 11, + DAX_KMEM_ALL = 12, + DAX_KMEM_PREFERRED = 13, + }; + + namespace static_kind + { + template + class allocator + { + public: + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + + template + struct rebind { + using other = allocator; + }; + + template + friend class allocator; + +#if !_GLIBCXX_USE_CXX11_ABI + /* This is a workaround for compilers (e.g GCC 4.8) that uses C++11 standard, + * but use old - non C++11 ABI */ + template + explicit allocator() + { + static_assert(std::is_same::value, + "libmemkind::static_kind::allocator cannot be compiled without CXX11 ABI"); + } +#endif + + explicit allocator(libmemkind::kinds kind) + { + switch (kind) { + case libmemkind::kinds::DEFAULT: + _kind = MEMKIND_DEFAULT; + break; + case libmemkind::kinds::HUGETLB: + _kind = MEMKIND_HUGETLB; + break; + case libmemkind::kinds::INTERLEAVE: + _kind = MEMKIND_INTERLEAVE; + break; + case libmemkind::kinds::HBW: + _kind = MEMKIND_HBW; + break; + case libmemkind::kinds::HBW_ALL: + _kind = MEMKIND_HBW_ALL; + break; + case libmemkind::kinds::HBW_HUGETLB: + _kind = MEMKIND_HBW_HUGETLB; + break; + case libmemkind::kinds::HBW_ALL_HUGETLB: + _kind = MEMKIND_HBW_ALL_HUGETLB; + break; + case libmemkind::kinds::HBW_PREFERRED: + _kind = MEMKIND_HBW_PREFERRED; + break; + case libmemkind::kinds::HBW_PREFERRED_HUGETLB: + _kind = MEMKIND_HBW_PREFERRED_HUGETLB; + break; + case libmemkind::kinds::HBW_INTERLEAVE: + _kind = MEMKIND_HBW_INTERLEAVE; + break; + case libmemkind::kinds::REGULAR: + _kind = MEMKIND_REGULAR; + break; + case libmemkind::kinds::DAX_KMEM: + _kind = MEMKIND_DAX_KMEM; + break; + case libmemkind::kinds::DAX_KMEM_ALL: + _kind = MEMKIND_DAX_KMEM_ALL; + break; + case libmemkind::kinds::DAX_KMEM_PREFERRED: + _kind = MEMKIND_DAX_KMEM_PREFERRED; + break; + default: + throw std::runtime_error("Unknown libmemkind::kinds"); + break; + } + } + + allocator(const allocator &other) = default; + + template + allocator(const allocator &other) noexcept + { + _kind = other._kind; + } + + allocator(allocator &&other) = default; + + template + allocator(const allocator &&other) noexcept + { + _kind = std::move(other._kind); + } + + allocator &operator = (const allocator &other) = default; + + template + allocator &operator = (const allocator &other) noexcept + { + _kind = other._kind; + return *this; + } + + allocator &operator = (allocator &&other) = default; + + template + allocator &operator = (allocator &&other) noexcept + { + _kind = std::move(other._kind); + return *this; + } + + pointer allocate(size_type n) const + { + pointer result = static_cast(memkind_malloc(_kind, n*sizeof(T))); + if (!result) { + throw std::bad_alloc(); + } + return result; + } + + void deallocate(pointer p, size_type n) const + { + memkind_free(_kind, static_cast(p)); + } + + template + void construct(U *p, Args &&... args) const + { + ::new((void *)p) U(std::forward(args)...); + } + + void destroy(pointer p) const + { + p->~value_type(); + } + + template + friend bool operator ==(const allocator &lhs, const allocator &rhs); + + template + friend bool operator !=(const allocator &lhs, const allocator &rhs); + + private: + memkind_t _kind; + }; + + template + bool operator ==(const allocator &lhs, const allocator &rhs) + { + return lhs._kind == rhs._kind; + } + + template + bool operator !=(const allocator &lhs, const allocator &rhs) + { + return !(lhs._kind == rhs._kind); + } + } // namespace static_kind +} // namespace libmemkind diff --git a/include/memkind_deprecated.h b/include/memkind_deprecated.h new file mode 100644 index 0000000..3e2c3c5 --- /dev/null +++ b/include/memkind_deprecated.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 - 2019 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * !!!!!!!!!!!!!!!!!!! + * !!! WARNING !!! + * !!! PLEASE READ !!! + * !!!!!!!!!!!!!!!!!!! + * + * This header file contains all memkind deprecated symbols. + * + * Please avoid usage of this API in newly developed code, as + * eventually this code is subject for removal. + */ + +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MEMKIND_DEPRECATED + +#ifdef __GNUC__ +#define MEMKIND_DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define MEMKIND_DEPRECATED(func) __declspec(deprecated) func +#else +#pragma message("WARNING: You need to implement MEMKIND_DEPRECATED for this compiler") +#define MEMKIND_DEPRECATED(func) func +#endif + +#endif + +/* + * Symbols related to GBTLB that are no longer supported + */ +extern memkind_t MEMKIND_HBW_GBTLB; +extern memkind_t MEMKIND_HBW_PREFERRED_GBTLB; +extern memkind_t MEMKIND_GBTLB; + +int MEMKIND_DEPRECATED(memkind_get_kind_by_partition(int partition, + memkind_t *kind)); + +enum memkind_base_partition { + MEMKIND_PARTITION_DEFAULT = 0, + MEMKIND_PARTITION_HBW = 1, + MEMKIND_PARTITION_HBW_HUGETLB = 2, + MEMKIND_PARTITION_HBW_PREFERRED = 3, + MEMKIND_PARTITION_HBW_PREFERRED_HUGETLB = 4, + MEMKIND_PARTITION_HUGETLB = 5, + MEMKIND_PARTITION_HBW_GBTLB = 6, + MEMKIND_PARTITION_HBW_PREFERRED_GBTLB = 7, + MEMKIND_PARTITION_GBTLB = 8, + MEMKIND_PARTITION_HBW_INTERLEAVE = 9, + MEMKIND_PARTITION_INTERLEAVE = 10, + MEMKIND_PARTITION_REGULAR = 11, + MEMKIND_PARTITION_HBW_ALL = 12, + MEMKIND_PARTITION_HBW_ALL_HUGETLB = 13, + MEMKIND_PARTITION_DAX_KMEM = 14, + MEMKIND_PARTITION_DAX_KMEM_ALL = 15, + MEMKIND_PARTITION_DAX_KMEM_PREFERRED = 16, + MEMKIND_NUM_BASE_KIND +}; + +#ifdef __cplusplus +} +#endif diff --git a/include/pmem_allocator.h b/include/pmem_allocator.h new file mode 100644 index 0000000..d373e3c --- /dev/null +++ b/include/pmem_allocator.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2018 - 2020 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice(s), + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice(s), + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "memkind.h" + +/* + * Header file for the C++ allocator compatible with the C++ standard library allocator concepts. + * More details in pmemallocator(3) man page. + * Note: memory heap management is based on memkind_malloc, refer to the memkind(3) man page for more + * information. + * + * Functionality defined in this header is considered as stable API (STANDARD API). + * API standards are described in memkind(3) man page. + */ +namespace libmemkind +{ + enum class allocation_policy { + DEFAULT = MEMKIND_MEM_USAGE_POLICY_DEFAULT, + CONSERVATIVE = MEMKIND_MEM_USAGE_POLICY_CONSERVATIVE, + MAX + }; + + namespace pmem + { + namespace internal + { + class kind_wrapper_t + { + public: + kind_wrapper_t(const char *dir, std::size_t max_size, + libmemkind::allocation_policy alloc_policy= + libmemkind::allocation_policy::DEFAULT) + { + cfg = memkind_config_new(); + if (!cfg) { + throw std::runtime_error( + std::string("An error occurred while creating pmem config")); + } + memkind_config_set_path(cfg, dir); + memkind_config_set_size(cfg, max_size); + memkind_config_set_memory_usage_policy(cfg, + static_cast(alloc_policy)); + int err_c = memkind_create_pmem_with_config(cfg, &kind); + memkind_config_delete(cfg); + if (err_c) { + throw std::runtime_error( + std::string("An error occurred while creating pmem kind; error code: ") + + std::to_string(err_c)); + } + } + + kind_wrapper_t(const kind_wrapper_t &) = delete; + void operator=(const kind_wrapper_t &) = delete; + + ~kind_wrapper_t() + { + memkind_destroy_kind(kind); + } + + memkind_t get() const + { + return kind; + } + + private: + memkind_t kind; + struct memkind_config *cfg; + }; + } + + template + class allocator + { + using kind_wrapper_t = internal::kind_wrapper_t; + std::shared_ptr kind_wrapper_ptr; + public: + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + + template + struct rebind { + using other = allocator; + }; + + template + friend class allocator; + +#if !_GLIBCXX_USE_CXX11_ABI + /* This is a workaround for compilers (e.g GCC 4.8) that uses C++11 standard, + * but use old - non C++11 ABI */ + template + explicit allocator() + { + static_assert(std::is_same::value, + "libmemkind::pmem::allocator cannot be compiled without CXX11 ABI"); + } +#endif + + explicit allocator(const char *dir, size_t max_size) : + kind_wrapper_ptr(std::make_shared(dir, max_size)) + { + } + + explicit allocator(const std::string &dir, size_t max_size) : + allocator(dir.c_str(), max_size) + { + } + + explicit allocator(const char *dir, size_t max_size, + libmemkind::allocation_policy alloc_policy) : + kind_wrapper_ptr(std::make_shared(dir, max_size, alloc_policy)) + { + } + + explicit allocator(const std::string &dir, size_t max_size, + libmemkind::allocation_policy alloc_policy) : + allocator(dir.c_str(), max_size, alloc_policy) + { + } + + allocator(const allocator &other) = default; + + template + allocator(const allocator &other) noexcept : kind_wrapper_ptr( + other.kind_wrapper_ptr) + { + } + + allocator(allocator &&other) = default; + + template + allocator(allocator &&other) noexcept : + kind_wrapper_ptr(std::move(other.kind_wrapper_ptr)) + { + } + + allocator &operator = (const allocator &other) = default; + + template + allocator &operator = (const allocator &other) noexcept + { + kind_wrapper_ptr = other.kind_wrapper_ptr; + return *this; + } + + allocator &operator = (allocator &&other) = default; + + template + allocator &operator = (allocator &&other) noexcept + { + kind_wrapper_ptr = std::move(other.kind_wrapper_ptr); + return *this; + } + + pointer allocate(size_type n) const + { + pointer result = static_cast(memkind_malloc(kind_wrapper_ptr->get(), + n*sizeof(T))); + if (!result) { + throw std::bad_alloc(); + } + return result; + } + + void deallocate(pointer p, size_type n) const + { + memkind_free(kind_wrapper_ptr->get(), static_cast(p)); + } + + template + void construct(U *p, Args &&... args) const + { + ::new((void *)p) U(std::forward(args)...); + } + + void destroy(pointer p) const + { + p->~value_type(); + } + + template + friend bool operator ==(const allocator &lhs, const allocator &rhs); + + template + friend bool operator !=(const allocator &lhs, const allocator &rhs); + }; + + template + bool operator ==(const allocator &lhs, const allocator &rhs) + { + return lhs.kind_wrapper_ptr->get() == rhs.kind_wrapper_ptr->get(); + } + + template + bool operator !=(const allocator &lhs, const allocator &rhs) + { + return !(lhs == rhs); + } + } // namespace pmem +} // namespace libmemkind diff --git a/install_astyle.sh b/install_astyle.sh new file mode 100755 index 0000000..58615fc --- /dev/null +++ b/install_astyle.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# Copyright (C) 2018 Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice(s), +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice(s), +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -ex +curl -SL https://sourceforge.net/projects/astyle/files/astyle/astyle%203.1/astyle_3.1_linux.tar.gz -o /tmp/astyle.tar.gz +tar -xzvf /tmp/astyle.tar.gz -C /tmp/ +echo "Install astyle" +cd /tmp/astyle/build/gcc +make +sudo make install diff --git a/jemalloc/.appveyor.yml b/jemalloc/.appveyor.yml new file mode 100644 index 0000000..90b0368 --- /dev/null +++ b/jemalloc/.appveyor.yml @@ -0,0 +1,42 @@ +version: '{build}' + +environment: + matrix: + - MSYSTEM: MINGW64 + CPU: x86_64 + MSVC: amd64 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW64 + CPU: x86_64 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW32 + CPU: i686 + MSVC: x86 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW32 + CPU: i686 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW64 + CPU: x86_64 + MSVC: amd64 + - MSYSTEM: MINGW64 + CPU: x86_64 + - MSYSTEM: MINGW32 + CPU: i686 + MSVC: x86 + - MSYSTEM: MINGW32 + CPU: i686 + +install: + - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% + - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% + - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc + - pacman --noconfirm -Suy mingw-w64-%CPU%-make + +build_script: + - bash -c "autoconf" + - bash -c "./configure $CONFIG_FLAGS" + - mingw32-make + - file lib/jemalloc.dll + - mingw32-make tests + - mingw32-make -k check diff --git a/jemalloc/.autom4te.cfg b/jemalloc/.autom4te.cfg new file mode 100644 index 0000000..fe2424d --- /dev/null +++ b/jemalloc/.autom4te.cfg @@ -0,0 +1,3 @@ +begin-language: "Autoconf-without-aclocal-m4" +args: --no-cache +end-language: "Autoconf-without-aclocal-m4" diff --git a/jemalloc/.gitattributes b/jemalloc/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/jemalloc/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/jemalloc/.gitignore b/jemalloc/.gitignore new file mode 100644 index 0000000..5ca0ad1 --- /dev/null +++ b/jemalloc/.gitignore @@ -0,0 +1,92 @@ +/bin/jemalloc-config +/bin/jemalloc.sh +/bin/jeprof + +/config.stamp +/config.log +/config.status +/configure + +/doc/html.xsl +/doc/manpages.xsl +/doc/jemalloc.xml +/doc/jemalloc.html +/doc/jemalloc.3 + +/jemalloc.pc + +/lib/ + +/Makefile + +/include/jemalloc/internal/jemalloc_preamble.h +/include/jemalloc/internal/jemalloc_internal_defs.h +/include/jemalloc/internal/private_namespace.gen.h +/include/jemalloc/internal/private_namespace.h +/include/jemalloc/internal/private_namespace_jet.gen.h +/include/jemalloc/internal/private_namespace_jet.h +/include/jemalloc/internal/private_symbols.awk +/include/jemalloc/internal/private_symbols_jet.awk +/include/jemalloc/internal/public_namespace.h +/include/jemalloc/internal/public_symbols.txt +/include/jemalloc/internal/public_unnamespace.h +/include/jemalloc/jemalloc.h +/include/jemalloc/jemalloc_defs.h +/include/jemalloc/jemalloc_macros.h +/include/jemalloc/jemalloc_mangle.h +/include/jemalloc/jemalloc_mangle_jet.h +/include/jemalloc/jemalloc_protos.h +/include/jemalloc/jemalloc_protos_jet.h +/include/jemalloc/jemalloc_rename.h +/include/jemalloc/jemalloc_typedefs.h + +/src/*.[od] +/src/*.sym + +/run_tests.out/ + +/test/test.sh +test/include/test/jemalloc_test.h +test/include/test/jemalloc_test_defs.h + +/test/integration/[A-Za-z]* +!/test/integration/[A-Za-z]*.* +/test/integration/*.[od] +/test/integration/*.out + +/test/integration/cpp/[A-Za-z]* +!/test/integration/cpp/[A-Za-z]*.* +/test/integration/cpp/*.[od] +/test/integration/cpp/*.out + +/test/src/*.[od] + +/test/stress/[A-Za-z]* +!/test/stress/[A-Za-z]*.* +/test/stress/*.[od] +/test/stress/*.out + +/test/unit/[A-Za-z]* +!/test/unit/[A-Za-z]*.* +/test/unit/*.[od] +/test/unit/*.out + +/VERSION + +*.pdb +*.sdf +*.opendb +*.VC.db +*.opensdf +*.cachefile +*.suo +*.user +*.sln.docstates +*.tmp +.vs/ +/msvc/Win32/ +/msvc/x64/ +/msvc/projects/*/*/Debug*/ +/msvc/projects/*/*/Release*/ +/msvc/projects/*/*/Win32/ +/msvc/projects/*/*/x64/ diff --git a/jemalloc/.travis.yml b/jemalloc/.travis.yml new file mode 100644 index 0000000..2da5da8 --- /dev/null +++ b/jemalloc/.travis.yml @@ -0,0 +1,195 @@ +language: generic +dist: precise + +matrix: + include: + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: &gcc_multilib + apt: + packages: + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: *gcc_multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + # Development build + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + # --enable-expermental-smallocx: + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + + # Valgrind + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind" + addons: + apt: + packages: + - valgrind + + +before_script: + - autoconf + - scripts/gen_travis.py > travis_script && diff .travis.yml travis_script + - ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS + - make -j3 + - make -j3 tests + +script: + - make check + diff --git a/jemalloc/COPYING b/jemalloc/COPYING new file mode 100644 index 0000000..3b7fd35 --- /dev/null +++ b/jemalloc/COPYING @@ -0,0 +1,27 @@ +Unless otherwise specified, files in the jemalloc source distribution are +subject to the following license: +-------------------------------------------------------------------------------- +Copyright (C) 2002-present Jason Evans . +All rights reserved. +Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved. +Copyright (C) 2009-present Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice(s), + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice(s), + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- diff --git a/jemalloc/ChangeLog b/jemalloc/ChangeLog new file mode 100644 index 0000000..e55813b --- /dev/null +++ b/jemalloc/ChangeLog @@ -0,0 +1,1518 @@ +Following are change highlights associated with official releases. Important +bug fixes are all mentioned, but some internal enhancements are omitted here for +brevity. Much more detail can be found in the git revision history: + + https://github.com/jemalloc/jemalloc + +* 5.2.1 (August 5, 2019) + + This release is primarily about Windows. A critical virtual memory leak is + resolved on all Windows platforms. The regression was present in all releases + since 5.0.0. + + Bug fixes: + - Fix a severe virtual memory leak on Windows. This regression was first + released in 5.0.0. (@Ignition, @j0t, @frederik-h, @davidtgoldblatt, + @interwq) + - Fix size 0 handling in posix_memalign(). This regression was first released + in 5.2.0. (@interwq) + - Fix the prof_log unit test which may observe unexpected backtraces from + compiler optimizations. The test was first added in 5.2.0. (@marxin, + @gnzlbg, @interwq) + - Fix the declaration of the extent_avail tree. This regression was first + released in 5.1.0. (@zoulasc) + - Fix an incorrect reference in jeprof. This functionality was first released + in 3.0.0. (@prehistoric-penguin) + - Fix an assertion on the deallocation fast-path. This regression was first + released in 5.2.0. (@yinan1048576) + - Fix the TLS_MODEL attribute in headers. This regression was first released + in 5.0.0. (@zoulasc, @interwq) + + Optimizations and refactors: + - Implement opt.retain on Windows and enable by default on 64-bit. (@interwq, + @davidtgoldblatt) + - Optimize away a branch on the operator delete[] path. (@mgrice) + - Add format annotation to the format generator function. (@zoulasc) + - Refactor and improve the size class header generation. (@yinan1048576) + - Remove best fit. (@djwatson) + - Avoid blocking on background thread locks for stats. (@oranagra, @interwq) + +* 5.2.0 (April 2, 2019) + + This release includes a few notable improvements, which are summarized below: + 1) improved fast-path performance from the optimizations by @djwatson; 2) + reduced virtual memory fragmentation and metadata usage; and 3) bug fixes on + setting the number of background threads. In addition, peak / spike memory + usage is improved with certain allocation patterns. As usual, the release and + prior dev versions have gone through large-scale production testing. + + New features: + - Implement oversize_threshold, which uses a dedicated arena for allocations + crossing the specified threshold to reduce fragmentation. (@interwq) + - Add extents usage information to stats. (@tyleretzel) + - Log time information for sampled allocations. (@tyleretzel) + - Support 0 size in sdallocx. (@djwatson) + - Output rate for certain counters in malloc_stats. (@zinoale) + - Add configure option --enable-readlinkat, which allows the use of readlinkat + over readlink. (@davidtgoldblatt) + - Add configure options --{enable,disable}-{static,shared} to allow not + building unwanted libraries. (@Ericson2314) + - Add configure option --disable-libdl to enable fully static builds. + (@interwq) + - Add mallctl interfaces: + + opt.oversize_threshold (@interwq) + + stats.arenas..extent_avail (@tyleretzel) + + stats.arenas..extents..n{dirty,muzzy,retained} (@tyleretzel) + + stats.arenas..extents..{dirty,muzzy,retained}_bytes + (@tyleretzel) + + Portability improvements: + - Update MSVC builds. (@maksqwe, @rustyx) + - Workaround a compiler optimizer bug on s390x. (@rkmisra) + - Make use of pthread_set_name_np(3) on FreeBSD. (@trasz) + - Implement malloc_getcpu() to enable percpu_arena for windows. (@santagada) + - Link against -pthread instead of -lpthread. (@paravoid) + - Make background_thread not dependent on libdl. (@interwq) + - Add stringify to fix a linker directive issue on MSVC. (@daverigby) + - Detect and fall back when 8-bit atomics are unavailable. (@interwq) + - Fall back to the default pthread_create if dlsym(3) fails. (@interwq) + + Optimizations and refactors: + - Refactor the TSD module. (@davidtgoldblatt) + - Avoid taking extents_muzzy mutex when muzzy is disabled. (@interwq) + - Avoid taking large_mtx for auto arenas on the tcache flush path. (@interwq) + - Optimize ixalloc by avoiding a size lookup. (@interwq) + - Implement opt.oversize_threshold which uses a dedicated arena for requests + crossing the threshold, also eagerly purges the oversize extents. Default + the threshold to 8 MiB. (@interwq) + - Clean compilation with -Wextra. (@gnzlbg, @jasone) + - Refactor the size class module. (@davidtgoldblatt) + - Refactor the stats emitter. (@tyleretzel) + - Optimize pow2_ceil. (@rkmisra) + - Avoid runtime detection of lazy purging on FreeBSD. (@trasz) + - Optimize mmap(2) alignment handling on FreeBSD. (@trasz) + - Improve error handling for THP state initialization. (@jsteemann) + - Rework the malloc() fast path. (@djwatson) + - Rework the free() fast path. (@djwatson) + - Refactor and optimize the tcache fill / flush paths. (@djwatson) + - Optimize sync / lwsync on PowerPC. (@chmeeedalf) + - Bypass extent_dalloc() when retain is enabled. (@interwq) + - Optimize the locking on large deallocation. (@interwq) + - Reduce the number of pages committed from sanity checking in debug build. + (@trasz, @interwq) + - Deprecate OSSpinLock. (@interwq) + - Lower the default number of background threads to 4 (when the feature + is enabled). (@interwq) + - Optimize the trylock spin wait. (@djwatson) + - Use arena index for arena-matching checks. (@interwq) + - Avoid forced decay on thread termination when using background threads. + (@interwq) + - Disable muzzy decay by default. (@djwatson, @interwq) + - Only initialize libgcc unwinder when profiling is enabled. (@paravoid, + @interwq) + + Bug fixes (all only relevant to jemalloc 5.x): + - Fix background thread index issues with max_background_threads. (@djwatson, + @interwq) + - Fix stats output for opt.lg_extent_max_active_fit. (@interwq) + - Fix opt.prof_prefix initialization. (@davidtgoldblatt) + - Properly trigger decay on tcache destroy. (@interwq, @amosbird) + - Fix tcache.flush. (@interwq) + - Detect whether explicit extent zero out is necessary with huge pages or + custom extent hooks, which may change the purge semantics. (@interwq) + - Fix a side effect caused by extent_max_active_fit combined with decay-based + purging, where freed extents can accumulate and not be reused for an + extended period of time. (@interwq, @mpghf) + - Fix a missing unlock on extent register error handling. (@zoulasc) + + Testing: + - Simplify the Travis script output. (@gnzlbg) + - Update the test scripts for FreeBSD. (@devnexen) + - Add unit tests for the producer-consumer pattern. (@interwq) + - Add Cirrus-CI config for FreeBSD builds. (@jasone) + - Add size-matching sanity checks on tcache flush. (@davidtgoldblatt, + @interwq) + + Incompatible changes: + - Remove --with-lg-page-sizes. (@davidtgoldblatt) + + Documentation: + - Attempt to build docs by default, however skip doc building when xsltproc + is missing. (@interwq, @cmuellner) + +* 5.1.0 (May 4, 2018) + + This release is primarily about fine-tuning, ranging from several new features + to numerous notable performance and portability enhancements. The release and + prior dev versions have been running in multiple large scale applications for + months, and the cumulative improvements are substantial in many cases. + + Given the long and successful production runs, this release is likely a good + candidate for applications to upgrade, from both jemalloc 5.0 and before. For + performance-critical applications, the newly added TUNING.md provides + guidelines on jemalloc tuning. + + New features: + - Implement transparent huge page support for internal metadata. (@interwq) + - Add opt.thp to allow enabling / disabling transparent huge pages for all + mappings. (@interwq) + - Add maximum background thread count option. (@djwatson) + - Allow prof_active to control opt.lg_prof_interval and prof.gdump. + (@interwq) + - Allow arena index lookup based on allocation addresses via mallctl. + (@lionkov) + - Allow disabling initial-exec TLS model. (@davidtgoldblatt, @KenMacD) + - Add opt.lg_extent_max_active_fit to set the max ratio between the size of + the active extent selected (to split off from) and the size of the requested + allocation. (@interwq, @davidtgoldblatt) + - Add retain_grow_limit to set the max size when growing virtual address + space. (@interwq) + - Add mallctl interfaces: + + arena..retain_grow_limit (@interwq) + + arenas.lookup (@lionkov) + + max_background_threads (@djwatson) + + opt.lg_extent_max_active_fit (@interwq) + + opt.max_background_threads (@djwatson) + + opt.metadata_thp (@interwq) + + opt.thp (@interwq) + + stats.metadata_thp (@interwq) + + Portability improvements: + - Support GNU/kFreeBSD configuration. (@paravoid) + - Support m68k, nios2 and SH3 architectures. (@paravoid) + - Fall back to FD_CLOEXEC when O_CLOEXEC is unavailable. (@zonyitoo) + - Fix symbol listing for cross-compiling. (@tamird) + - Fix high bits computation on ARM. (@davidtgoldblatt, @paravoid) + - Disable the CPU_SPINWAIT macro for Power. (@davidtgoldblatt, @marxin) + - Fix MSVC 2015 & 2017 builds. (@rustyx) + - Improve RISC-V support. (@EdSchouten) + - Set name mangling script in strict mode. (@nicolov) + - Avoid MADV_HUGEPAGE on ARM. (@marxin) + - Modify configure to determine return value of strerror_r. + (@davidtgoldblatt, @cferris1000) + - Make sure CXXFLAGS is tested with CPP compiler. (@nehaljwani) + - Fix 32-bit build on MSVC. (@rustyx) + - Fix external symbol on MSVC. (@maksqwe) + - Avoid a printf format specifier warning. (@jasone) + - Add configure option --disable-initial-exec-tls which can allow jemalloc to + be dynamically loaded after program startup. (@davidtgoldblatt, @KenMacD) + - AArch64: Add ILP32 support. (@cmuellner) + - Add --with-lg-vaddr configure option to support cross compiling. + (@cmuellner, @davidtgoldblatt) + + Optimizations and refactors: + - Improve active extent fit with extent_max_active_fit. This considerably + reduces fragmentation over time and improves virtual memory and metadata + usage. (@davidtgoldblatt, @interwq) + - Eagerly coalesce large extents to reduce fragmentation. (@interwq) + - sdallocx: only read size info when page aligned (i.e. possibly sampled), + which speeds up the sized deallocation path significantly. (@interwq) + - Avoid attempting new mappings for in place expansion with retain, since + it rarely succeeds in practice and causes high overhead. (@interwq) + - Refactor OOM handling in newImpl. (@wqfish) + - Add internal fine-grained logging functionality for debugging use. + (@davidtgoldblatt) + - Refactor arena / tcache interactions. (@davidtgoldblatt) + - Refactor extent management with dumpable flag. (@davidtgoldblatt) + - Add runtime detection of lazy purging. (@interwq) + - Use pairing heap instead of red-black tree for extents_avail. (@djwatson) + - Use sysctl on startup in FreeBSD. (@trasz) + - Use thread local prng state instead of atomic. (@djwatson) + - Make decay to always purge one more extent than before, because in + practice large extents are usually the ones that cross the decay threshold. + Purging the additional extent helps save memory as well as reduce VM + fragmentation. (@interwq) + - Fast division by dynamic values. (@davidtgoldblatt) + - Improve the fit for aligned allocation. (@interwq, @edwinsmith) + - Refactor extent_t bitpacking. (@rkmisra) + - Optimize the generated assembly for ticker operations. (@davidtgoldblatt) + - Convert stats printing to use a structured text emitter. (@davidtgoldblatt) + - Remove preserve_lru feature for extents management. (@djwatson) + - Consolidate two memory loads into one on the fast deallocation path. + (@davidtgoldblatt, @interwq) + + Bug fixes (most of the issues are only relevant to jemalloc 5.0): + - Fix deadlock with multithreaded fork in OS X. (@davidtgoldblatt) + - Validate returned file descriptor before use. (@zonyitoo) + - Fix a few background thread initialization and shutdown issues. (@interwq) + - Fix an extent coalesce + decay race by taking both coalescing extents off + the LRU list. (@interwq) + - Fix potentially unbound increase during decay, caused by one thread keep + stashing memory to purge while other threads generating new pages. The + number of pages to purge is checked to prevent this. (@interwq) + - Fix a FreeBSD bootstrap assertion. (@strejda, @interwq) + - Handle 32 bit mutex counters. (@rkmisra) + - Fix a indexing bug when creating background threads. (@davidtgoldblatt, + @binliu19) + - Fix arguments passed to extent_init. (@yuleniwo, @interwq) + - Fix addresses used for ordering mutexes. (@rkmisra) + - Fix abort_conf processing during bootstrap. (@interwq) + - Fix include path order for out-of-tree builds. (@cmuellner) + + Incompatible changes: + - Remove --disable-thp. (@interwq) + - Remove mallctl interfaces: + + config.thp (@interwq) + + Documentation: + - Add TUNING.md. (@interwq, @davidtgoldblatt, @djwatson) + +* 5.0.1 (July 1, 2017) + + This bugfix release fixes several issues, most of which are obscure enough + that typical applications are not impacted. + + Bug fixes: + - Update decay->nunpurged before purging, in order to avoid potential update + races and subsequent incorrect purging volume. (@interwq) + - Only abort on dlsym(3) error if the failure impacts an enabled feature (lazy + locking and/or background threads). This mitigates an initialization + failure bug for which we still do not have a clear reproduction test case. + (@interwq) + - Modify tsd management so that it neither crashes nor leaks if a thread's + only allocation activity is to call free() after TLS destructors have been + executed. This behavior was observed when operating with GNU libc, and is + unlikely to be an issue with other libc implementations. (@interwq) + - Mask signals during background thread creation. This prevents signals from + being inadvertently delivered to background threads. (@jasone, + @davidtgoldblatt, @interwq) + - Avoid inactivity checks within background threads, in order to prevent + recursive mutex acquisition. (@interwq) + - Fix extent_grow_retained() to use the specified hooks when the + arena..extent_hooks mallctl is used to override the default hooks. + (@interwq) + - Add missing reentrancy support for custom extent hooks which allocate. + (@interwq) + - Post-fork(2), re-initialize the list of tcaches associated with each arena + to contain no tcaches except the forking thread's. (@interwq) + - Add missing post-fork(2) mutex reinitialization for extent_grow_mtx. This + fixes potential deadlocks after fork(2). (@interwq) + - Enforce minimum autoconf version (currently 2.68), since 2.63 is known to + generate corrupt configure scripts. (@jasone) + - Ensure that the configured page size (--with-lg-page) is no larger than the + configured huge page size (--with-lg-hugepage). (@jasone) + +* 5.0.0 (June 13, 2017) + + Unlike all previous jemalloc releases, this release does not use naturally + aligned "chunks" for virtual memory management, and instead uses page-aligned + "extents". This change has few externally visible effects, but the internal + impacts are... extensive. Many other internal changes combine to make this + the most cohesively designed version of jemalloc so far, with ample + opportunity for further enhancements. + + Continuous integration is now an integral aspect of development thanks to the + efforts of @davidtgoldblatt, and the dev branch tends to remain reasonably + stable on the tested platforms (Linux, FreeBSD, macOS, and Windows). As a + side effect the official release frequency may decrease over time. + + New features: + - Implement optional per-CPU arena support; threads choose which arena to use + based on current CPU rather than on fixed thread-->arena associations. + (@interwq) + - Implement two-phase decay of unused dirty pages. Pages transition from + dirty-->muzzy-->clean, where the first phase transition relies on + madvise(... MADV_FREE) semantics, and the second phase transition discards + pages such that they are replaced with demand-zeroed pages on next access. + (@jasone) + - Increase decay time resolution from seconds to milliseconds. (@jasone) + - Implement opt-in per CPU background threads, and use them for asynchronous + decay-driven unused dirty page purging. (@interwq) + - Add mutex profiling, which collects a variety of statistics useful for + diagnosing overhead/contention issues. (@interwq) + - Add C++ new/delete operator bindings. (@djwatson) + - Support manually created arena destruction, such that all data and metadata + are discarded. Add MALLCTL_ARENAS_DESTROYED for accessing merged stats + associated with destroyed arenas. (@jasone) + - Add MALLCTL_ARENAS_ALL as a fixed index for use in accessing + merged/destroyed arena statistics via mallctl. (@jasone) + - Add opt.abort_conf to optionally abort if invalid configuration options are + detected during initialization. (@interwq) + - Add opt.stats_print_opts, so that e.g. JSON output can be selected for the + stats dumped during exit if opt.stats_print is true. (@jasone) + - Add --with-version=VERSION for use when embedding jemalloc into another + project's git repository. (@jasone) + - Add --disable-thp to support cross compiling. (@jasone) + - Add --with-lg-hugepage to support cross compiling. (@jasone) + - Add mallctl interfaces (various authors): + + background_thread + + opt.abort_conf + + opt.retain + + opt.percpu_arena + + opt.background_thread + + opt.{dirty,muzzy}_decay_ms + + opt.stats_print_opts + + arena..initialized + + arena..destroy + + arena..{dirty,muzzy}_decay_ms + + arena..extent_hooks + + arenas.{dirty,muzzy}_decay_ms + + arenas.bin..slab_size + + arenas.nlextents + + arenas.lextent..size + + arenas.create + + stats.background_thread.{num_threads,num_runs,run_interval} + + stats.mutexes.{ctl,background_thread,prof,reset}. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + stats.arenas..{dirty,muzzy}_decay_ms + + stats.arenas..uptime + + stats.arenas..{pmuzzy,base,internal,resident} + + stats.arenas..{dirty,muzzy}_{npurge,nmadvise,purged} + + stats.arenas..bins..{nslabs,reslabs,curslabs} + + stats.arenas..bins..mutex. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + stats.arenas..lextents..{nmalloc,ndalloc,nrequests,curlextents} + + stats.arenas.i.mutexes.{large,extent_avail,extents_dirty,extents_muzzy, + extents_retained,decay_dirty,decay_muzzy,base,tcache_list}. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + Portability improvements: + - Improve reentrant allocation support, such that deadlock is less likely if + e.g. a system library call in turn allocates memory. (@davidtgoldblatt, + @interwq) + - Support static linking of jemalloc with glibc. (@djwatson) + + Optimizations and refactors: + - Organize virtual memory as "extents" of virtual memory pages, rather than as + naturally aligned "chunks", and store all metadata in arbitrarily distant + locations. This reduces virtual memory external fragmentation, and will + interact better with huge pages (not yet explicitly supported). (@jasone) + - Fold large and huge size classes together; only small and large size classes + remain. (@jasone) + - Unify the allocation paths, and merge most fast-path branching decisions. + (@davidtgoldblatt, @interwq) + - Embed per thread automatic tcache into thread-specific data, which reduces + conditional branches and dereferences. Also reorganize tcache to increase + fast-path data locality. (@interwq) + - Rewrite atomics to closely model the C11 API, convert various + synchronization from mutex-based to atomic, and use the explicit memory + ordering control to resolve various hypothetical races without increasing + synchronization overhead. (@davidtgoldblatt) + - Extensively optimize rtree via various methods: + + Add multiple layers of rtree lookup caching, since rtree lookups are now + part of fast-path deallocation. (@interwq) + + Determine rtree layout at compile time. (@jasone) + + Make the tree shallower for common configurations. (@jasone) + + Embed the root node in the top-level rtree data structure, thus avoiding + one level of indirection. (@jasone) + + Further specialize leaf elements as compared to internal node elements, + and directly embed extent metadata needed for fast-path deallocation. + (@jasone) + + Ignore leading always-zero address bits (architecture-specific). + (@jasone) + - Reorganize headers (ongoing work) to make them hermetic, and disentangle + various module dependencies. (@davidtgoldblatt) + - Convert various internal data structures such as size class metadata from + boot-time-initialized to compile-time-initialized. Propagate resulting data + structure simplifications, such as making arena metadata fixed-size. + (@jasone) + - Simplify size class lookups when constrained to size classes that are + multiples of the page size. This speeds lookups, but the primary benefit is + complexity reduction in code that was the source of numerous regressions. + (@jasone) + - Lock individual extents when possible for localized extent operations, + rather than relying on a top-level arena lock. (@davidtgoldblatt, @jasone) + - Use first fit layout policy instead of best fit, in order to improve + packing. (@jasone) + - If munmap(2) is not in use, use an exponential series to grow each arena's + virtual memory, so that the number of disjoint virtual memory mappings + remains low. (@jasone) + - Implement per arena base allocators, so that arenas never share any virtual + memory pages. (@jasone) + - Automatically generate private symbol name mangling macros. (@jasone) + + Incompatible changes: + - Replace chunk hooks with an expanded/normalized set of extent hooks. + (@jasone) + - Remove ratio-based purging. (@jasone) + - Remove --disable-tcache. (@jasone) + - Remove --disable-tls. (@jasone) + - Remove --enable-ivsalloc. (@jasone) + - Remove --with-lg-size-class-group. (@jasone) + - Remove --with-lg-tiny-min. (@jasone) + - Remove --disable-cc-silence. (@jasone) + - Remove --enable-code-coverage. (@jasone) + - Remove --disable-munmap (replaced by opt.retain). (@jasone) + - Remove Valgrind support. (@jasone) + - Remove quarantine support. (@jasone) + - Remove redzone support. (@jasone) + - Remove mallctl interfaces (various authors): + + config.munmap + + config.tcache + + config.tls + + config.valgrind + + opt.lg_chunk + + opt.purge + + opt.lg_dirty_mult + + opt.decay_time + + opt.quarantine + + opt.redzone + + opt.thp + + arena..lg_dirty_mult + + arena..decay_time + + arena..chunk_hooks + + arenas.initialized + + arenas.lg_dirty_mult + + arenas.decay_time + + arenas.bin..run_size + + arenas.nlruns + + arenas.lrun..size + + arenas.nhchunks + + arenas.hchunk..size + + arenas.extend + + stats.cactive + + stats.arenas..lg_dirty_mult + + stats.arenas..decay_time + + stats.arenas..metadata.{mapped,allocated} + + stats.arenas..{npurge,nmadvise,purged} + + stats.arenas..huge.{allocated,nmalloc,ndalloc,nrequests} + + stats.arenas..bins..{nruns,reruns,curruns} + + stats.arenas..lruns..{nmalloc,ndalloc,nrequests,curruns} + + stats.arenas..hchunks..{nmalloc,ndalloc,nrequests,curhchunks} + + Bug fixes: + - Improve interval-based profile dump triggering to dump only one profile when + a single allocation's size exceeds the interval. (@jasone) + - Use prefixed function names (as controlled by --with-jemalloc-prefix) when + pruning backtrace frames in jeprof. (@jasone) + +* 4.5.0 (February 28, 2017) + + This is the first release to benefit from much broader continuous integration + testing, thanks to @davidtgoldblatt. Had we had this testing infrastructure + in place for prior releases, it would have caught all of the most serious + regressions fixed by this release. + + New features: + - Add --disable-thp and the opt.thp mallctl to provide opt-out mechanisms for + transparent huge page integration. (@jasone) + - Update zone allocator integration to work with macOS 10.12. (@glandium) + - Restructure *CFLAGS configuration, so that CFLAGS behaves typically, and + EXTRA_CFLAGS provides a way to specify e.g. -Werror during building, but not + during configuration. (@jasone, @ronawho) + + Bug fixes: + - Fix DSS (sbrk(2)-based) allocation. This regression was first released in + 4.3.0. (@jasone) + - Handle race in per size class utilization computation. This functionality + was first released in 4.0.0. (@interwq) + - Fix lock order reversal during gdump. (@jasone) + - Fix/refactor tcache synchronization. This regression was first released in + 4.0.0. (@jasone) + - Fix various JSON-formatted malloc_stats_print() bugs. This functionality + was first released in 4.3.0. (@jasone) + - Fix huge-aligned allocation. This regression was first released in 4.4.0. + (@jasone) + - When transparent huge page integration is enabled, detect what state pages + start in according to the kernel's current operating mode, and only convert + arena chunks to non-huge during purging if that is not their initial state. + This functionality was first released in 4.4.0. (@jasone) + - Fix lg_chunk clamping for the --enable-cache-oblivious --disable-fill case. + This regression was first released in 4.0.0. (@jasone, @428desmo) + - Properly detect sparc64 when building for Linux. (@glaubitz) + +* 4.4.0 (December 3, 2016) + + New features: + - Add configure support for *-*-linux-android. (@cferris1000, @jasone) + - Add the --disable-syscall configure option, for use on systems that place + security-motivated limitations on syscall(2). (@jasone) + - Add support for Debian GNU/kFreeBSD. (@thesam) + + Optimizations: + - Add extent serial numbers and use them where appropriate as a sort key that + is higher priority than address, so that the allocation policy prefers older + extents. This tends to improve locality (decrease fragmentation) when + memory grows downward. (@jasone) + - Refactor madvise(2) configuration so that MADV_FREE is detected and utilized + on Linux 4.5 and newer. (@jasone) + - Mark partially purged arena chunks as non-huge-page. This improves + interaction with Linux's transparent huge page functionality. (@jasone) + + Bug fixes: + - Fix size class computations for edge conditions involving extremely large + allocations. This regression was first released in 4.0.0. (@jasone, + @ingvarha) + - Remove overly restrictive assertions related to the cactive statistic. This + regression was first released in 4.1.0. (@jasone) + - Implement a more reliable detection scheme for os_unfair_lock on macOS. + (@jszakmeister) + +* 4.3.1 (November 7, 2016) + + Bug fixes: + - Fix a severe virtual memory leak. This regression was first released in + 4.3.0. (@interwq, @jasone) + - Refactor atomic and prng APIs to restore support for 32-bit platforms that + use pre-C11 toolchains, e.g. FreeBSD's mips. (@jasone) + +* 4.3.0 (November 4, 2016) + + This is the first release that passes the test suite for multiple Windows + configurations, thanks in large part to @glandium setting up continuous + integration via AppVeyor (and Travis CI for Linux and OS X). + + New features: + - Add "J" (JSON) support to malloc_stats_print(). (@jasone) + - Add Cray compiler support. (@ronawho) + + Optimizations: + - Add/use adaptive spinning for bootstrapping and radix tree node + initialization. (@jasone) + + Bug fixes: + - Fix large allocation to search starting in the optimal size class heap, + which can substantially reduce virtual memory churn and fragmentation. This + regression was first released in 4.0.0. (@mjp41, @jasone) + - Fix stats.arenas..nthreads accounting. (@interwq) + - Fix and simplify decay-based purging. (@jasone) + - Make DSS (sbrk(2)-related) operations lockless, which resolves potential + deadlocks during thread exit. (@jasone) + - Fix over-sized allocation of radix tree leaf nodes. (@mjp41, @ogaun, + @jasone) + - Fix over-sized allocation of arena_t (plus associated stats) data + structures. (@jasone, @interwq) + - Fix EXTRA_CFLAGS to not affect configuration. (@jasone) + - Fix a Valgrind integration bug. (@ronawho) + - Disallow 0x5a junk filling when running in Valgrind. (@jasone) + - Fix a file descriptor leak on Linux. This regression was first released in + 4.2.0. (@vsarunas, @jasone) + - Fix static linking of jemalloc with glibc. (@djwatson) + - Use syscall(2) rather than {open,read,close}(2) during boot on Linux. This + works around other libraries' system call wrappers performing reentrant + allocation. (@kspinka, @Whissi, @jasone) + - Fix OS X default zone replacement to work with OS X 10.12. (@glandium, + @jasone) + - Fix cached memory management to avoid needless commit/decommit operations + during purging, which resolves permanent virtual memory map fragmentation + issues on Windows. (@mjp41, @jasone) + - Fix TSD fetches to avoid (recursive) allocation. This is relevant to + non-TLS and Windows configurations. (@jasone) + - Fix malloc_conf overriding to work on Windows. (@jasone) + - Forcibly disable lazy-lock on Windows (was forcibly *enabled*). (@jasone) + +* 4.2.1 (June 8, 2016) + + Bug fixes: + - Fix bootstrapping issues for configurations that require allocation during + tsd initialization (e.g. --disable-tls). (@cferris1000, @jasone) + - Fix gettimeofday() version of nstime_update(). (@ronawho) + - Fix Valgrind regressions in calloc() and chunk_alloc_wrapper(). (@ronawho) + - Fix potential VM map fragmentation regression. (@jasone) + - Fix opt_zero-triggered in-place huge reallocation zeroing. (@jasone) + - Fix heap profiling context leaks in reallocation edge cases. (@jasone) + +* 4.2.0 (May 12, 2016) + + New features: + - Add the arena..reset mallctl, which makes it possible to discard all of + an arena's allocations in a single operation. (@jasone) + - Add the stats.retained and stats.arenas..retained statistics. (@jasone) + - Add the --with-version configure option. (@jasone) + - Support --with-lg-page values larger than actual page size. (@jasone) + + Optimizations: + - Use pairing heaps rather than red-black trees for various hot data + structures. (@djwatson, @jasone) + - Streamline fast paths of rtree operations. (@jasone) + - Optimize the fast paths of calloc() and [m,d,sd]allocx(). (@jasone) + - Decommit unused virtual memory if the OS does not overcommit. (@jasone) + - Specify MAP_NORESERVE on Linux if [heuristic] overcommit is active, in order + to avoid unfortunate interactions during fork(2). (@jasone) + + Bug fixes: + - Fix chunk accounting related to triggering gdump profiles. (@jasone) + - Link against librt for clock_gettime(2) if glibc < 2.17. (@jasone) + - Scale leak report summary according to sampling probability. (@jasone) + +* 4.1.1 (May 3, 2016) + + This bugfix release resolves a variety of mostly minor issues, though the + bitmap fix is critical for 64-bit Windows. + + Bug fixes: + - Fix the linear scan version of bitmap_sfu() to shift by the proper amount + even when sizeof(long) is not the same as sizeof(void *), as on 64-bit + Windows. (@jasone) + - Fix hashing functions to avoid unaligned memory accesses (and resulting + crashes). This is relevant at least to some ARM-based platforms. + (@rkmisra) + - Fix fork()-related lock rank ordering reversals. These reversals were + unlikely to cause deadlocks in practice except when heap profiling was + enabled and active. (@jasone) + - Fix various chunk leaks in OOM code paths. (@jasone) + - Fix malloc_stats_print() to print opt.narenas correctly. (@jasone) + - Fix MSVC-specific build/test issues. (@rustyx, @yuslepukhin) + - Fix a variety of test failures that were due to test fragility rather than + core bugs. (@jasone) + +* 4.1.0 (February 28, 2016) + + This release is primarily about optimizations, but it also incorporates a lot + of portability-motivated refactoring and enhancements. Many people worked on + this release, to an extent that even with the omission here of minor changes + (see git revision history), and of the people who reported and diagnosed + issues, so much of the work was contributed that starting with this release, + changes are annotated with author credits to help reflect the collaborative + effort involved. + + New features: + - Implement decay-based unused dirty page purging, a major optimization with + mallctl API impact. This is an alternative to the existing ratio-based + unused dirty page purging, and is intended to eventually become the sole + purging mechanism. New mallctls: + + opt.purge + + opt.decay_time + + arena..decay + + arena..decay_time + + arenas.decay_time + + stats.arenas..decay_time + (@jasone, @cevans87) + - Add --with-malloc-conf, which makes it possible to embed a default + options string during configuration. This was motivated by the desire to + specify --with-malloc-conf=purge:decay , since the default must remain + purge:ratio until the 5.0.0 release. (@jasone) + - Add MS Visual Studio 2015 support. (@rustyx, @yuslepukhin) + - Make *allocx() size class overflow behavior defined. The maximum + size class is now less than PTRDIFF_MAX to protect applications against + numerical overflow, and all allocation functions are guaranteed to indicate + errors rather than potentially crashing if the request size exceeds the + maximum size class. (@jasone) + - jeprof: + + Add raw heap profile support. (@jasone) + + Add --retain and --exclude for backtrace symbol filtering. (@jasone) + + Optimizations: + - Optimize the fast path to combine various bootstrapping and configuration + checks and execute more streamlined code in the common case. (@interwq) + - Use linear scan for small bitmaps (used for small object tracking). In + addition to speeding up bitmap operations on 64-bit systems, this reduces + allocator metadata overhead by approximately 0.2%. (@djwatson) + - Separate arena_avail trees, which substantially speeds up run tree + operations. (@djwatson) + - Use memoization (boot-time-computed table) for run quantization. Separate + arena_avail trees reduced the importance of this optimization. (@jasone) + - Attempt mmap-based in-place huge reallocation. This can dramatically speed + up incremental huge reallocation. (@jasone) + + Incompatible changes: + - Make opt.narenas unsigned rather than size_t. (@jasone) + + Bug fixes: + - Fix stats.cactive accounting regression. (@rustyx, @jasone) + - Handle unaligned keys in hash(). This caused problems for some ARM systems. + (@jasone, @cferris1000) + - Refactor arenas array. In addition to fixing a fork-related deadlock, this + makes arena lookups faster and simpler. (@jasone) + - Move retained memory allocation out of the default chunk allocation + function, to a location that gets executed even if the application installs + a custom chunk allocation function. This resolves a virtual memory leak. + (@buchgr) + - Fix a potential tsd cleanup leak. (@cferris1000, @jasone) + - Fix run quantization. In practice this bug had no impact unless + applications requested memory with alignment exceeding one page. + (@jasone, @djwatson) + - Fix LinuxThreads-specific bootstrapping deadlock. (Cosmin Paraschiv) + - jeprof: + + Don't discard curl options if timeout is not defined. (@djwatson) + + Detect failed profile fetches. (@djwatson) + - Fix stats.arenas..{dss,lg_dirty_mult,decay_time,pactive,pdirty} for + --disable-stats case. (@jasone) + +* 4.0.4 (October 24, 2015) + + This bugfix release fixes another xallocx() regression. No other regressions + have come to light in over a month, so this is likely a good starting point + for people who prefer to wait for "dot one" releases with all the major issues + shaken out. + + Bug fixes: + - Fix xallocx(..., MALLOCX_ZERO to zero the last full trailing page of large + allocations that have been randomly assigned an offset of 0 when + --enable-cache-oblivious configure option is enabled. + +* 4.0.3 (September 24, 2015) + + This bugfix release continues the trend of xallocx() and heap profiling fixes. + + Bug fixes: + - Fix xallocx(..., MALLOCX_ZERO) to zero all trailing bytes of large + allocations when --enable-cache-oblivious configure option is enabled. + - Fix xallocx(..., MALLOCX_ZERO) to zero trailing bytes of huge allocations + when resizing from/to a size class that is not a multiple of the chunk size. + - Fix prof_tctx_dump_iter() to filter out nodes that were created after heap + profile dumping started. + - Work around a potentially bad thread-specific data initialization + interaction with NPTL (glibc's pthreads implementation). + +* 4.0.2 (September 21, 2015) + + This bugfix release addresses a few bugs specific to heap profiling. + + Bug fixes: + - Fix ixallocx_prof_sample() to never modify nor create sampled small + allocations. xallocx() is in general incapable of moving small allocations, + so this fix removes buggy code without loss of generality. + - Fix irallocx_prof_sample() to always allocate large regions, even when + alignment is non-zero. + - Fix prof_alloc_rollback() to read tdata from thread-specific data rather + than dereferencing a potentially invalid tctx. + +* 4.0.1 (September 15, 2015) + + This is a bugfix release that is somewhat high risk due to the amount of + refactoring required to address deep xallocx() problems. As a side effect of + these fixes, xallocx() now tries harder to partially fulfill requests for + optional extra space. Note that a couple of minor heap profiling + optimizations are included, but these are better thought of as performance + fixes that were integral to discovering most of the other bugs. + + Optimizations: + - Avoid a chunk metadata read in arena_prof_tctx_set(), since it is in the + fast path when heap profiling is enabled. Additionally, split a special + case out into arena_prof_tctx_reset(), which also avoids chunk metadata + reads. + - Optimize irallocx_prof() to optimistically update the sampler state. The + prior implementation appears to have been a holdover from when + rallocx()/xallocx() functionality was combined as rallocm(). + + Bug fixes: + - Fix TLS configuration such that it is enabled by default for platforms on + which it works correctly. + - Fix arenas_cache_cleanup() and arena_get_hard() to handle + allocation/deallocation within the application's thread-specific data + cleanup functions even after arenas_cache is torn down. + - Fix xallocx() bugs related to size+extra exceeding HUGE_MAXCLASS. + - Fix chunk purge hook calls for in-place huge shrinking reallocation to + specify the old chunk size rather than the new chunk size. This bug caused + no correctness issues for the default chunk purge function, but was + visible to custom functions set via the "arena..chunk_hooks" mallctl. + - Fix heap profiling bugs: + + Fix heap profiling to distinguish among otherwise identical sample sites + with interposed resets (triggered via the "prof.reset" mallctl). This bug + could cause data structure corruption that would most likely result in a + segfault. + + Fix irealloc_prof() to prof_alloc_rollback() on OOM. + + Make one call to prof_active_get_unlocked() per allocation event, and use + the result throughout the relevant functions that handle an allocation + event. Also add a missing check in prof_realloc(). These fixes protect + allocation events against concurrent prof_active changes. + + Fix ixallocx_prof() to pass usize_max and zero to ixallocx_prof_sample() + in the correct order. + + Fix prof_realloc() to call prof_free_sampled_object() after calling + prof_malloc_sample_object(). Prior to this fix, if tctx and old_tctx were + the same, the tctx could have been prematurely destroyed. + - Fix portability bugs: + + Don't bitshift by negative amounts when encoding/decoding run sizes in + chunk header maps. This affected systems with page sizes greater than 8 + KiB. + + Rename index_t to szind_t to avoid an existing type on Solaris. + + Add JEMALLOC_CXX_THROW to the memalign() function prototype, in order to + match glibc and avoid compilation errors when including both + jemalloc/jemalloc.h and malloc.h in C++ code. + + Don't assume that /bin/sh is appropriate when running size_classes.sh + during configuration. + + Consider __sparcv9 a synonym for __sparc64__ when defining LG_QUANTUM. + + Link tests to librt if it contains clock_gettime(2). + +* 4.0.0 (August 17, 2015) + + This version contains many speed and space optimizations, both minor and + major. The major themes are generalization, unification, and simplification. + Although many of these optimizations cause no visible behavior change, their + cumulative effect is substantial. + + New features: + - Normalize size class spacing to be consistent across the complete size + range. By default there are four size classes per size doubling, but this + is now configurable via the --with-lg-size-class-group option. Also add the + --with-lg-page, --with-lg-page-sizes, --with-lg-quantum, and + --with-lg-tiny-min options, which can be used to tweak page and size class + settings. Impacts: + + Worst case performance for incrementally growing/shrinking reallocation + is improved because there are far fewer size classes, and therefore + copying happens less often. + + Internal fragmentation is limited to 20% for all but the smallest size + classes (those less than four times the quantum). (1B + 4 KiB) + and (1B + 4 MiB) previously suffered nearly 50% internal fragmentation. + + Chunk fragmentation tends to be lower because there are fewer distinct run + sizes to pack. + - Add support for explicit tcaches. The "tcache.create", "tcache.flush", and + "tcache.destroy" mallctls control tcache lifetime and flushing, and the + MALLOCX_TCACHE(tc) and MALLOCX_TCACHE_NONE flags to the *allocx() API + control which tcache is used for each operation. + - Implement per thread heap profiling, as well as the ability to + enable/disable heap profiling on a per thread basis. Add the "prof.reset", + "prof.lg_sample", "thread.prof.name", "thread.prof.active", + "opt.prof_thread_active_init", "prof.thread_active_init", and + "thread.prof.active" mallctls. + - Add support for per arena application-specified chunk allocators, configured + via the "arena..chunk_hooks" mallctl. + - Refactor huge allocation to be managed by arenas, so that arenas now + function as general purpose independent allocators. This is important in + the context of user-specified chunk allocators, aside from the scalability + benefits. Related new statistics: + + The "stats.arenas..huge.allocated", "stats.arenas..huge.nmalloc", + "stats.arenas..huge.ndalloc", and "stats.arenas..huge.nrequests" + mallctls provide high level per arena huge allocation statistics. + + The "arenas.nhchunks", "arenas.hchunk..size", + "stats.arenas..hchunks..nmalloc", + "stats.arenas..hchunks..ndalloc", + "stats.arenas..hchunks..nrequests", and + "stats.arenas..hchunks..curhchunks" mallctls provide per size class + statistics. + - Add the 'util' column to malloc_stats_print() output, which reports the + proportion of available regions that are currently in use for each small + size class. + - Add "alloc" and "free" modes for for junk filling (see the "opt.junk" + mallctl), so that it is possible to separately enable junk filling for + allocation versus deallocation. + - Add the jemalloc-config script, which provides information about how + jemalloc was configured, and how to integrate it into application builds. + - Add metadata statistics, which are accessible via the "stats.metadata", + "stats.arenas..metadata.mapped", and + "stats.arenas..metadata.allocated" mallctls. + - Add the "stats.resident" mallctl, which reports the upper limit of + physically resident memory mapped by the allocator. + - Add per arena control over unused dirty page purging, via the + "arenas.lg_dirty_mult", "arena..lg_dirty_mult", and + "stats.arenas..lg_dirty_mult" mallctls. + - Add the "prof.gdump" mallctl, which makes it possible to toggle the gdump + feature on/off during program execution. + - Add sdallocx(), which implements sized deallocation. The primary + optimization over dallocx() is the removal of a metadata read, which often + suffers an L1 cache miss. + - Add missing header includes in jemalloc/jemalloc.h, so that applications + only have to #include . + - Add support for additional platforms: + + Bitrig + + Cygwin + + DragonFlyBSD + + iOS + + OpenBSD + + OpenRISC/or1k + + Optimizations: + - Maintain dirty runs in per arena LRUs rather than in per arena trees of + dirty-run-containing chunks. In practice this change significantly reduces + dirty page purging volume. + - Integrate whole chunks into the unused dirty page purging machinery. This + reduces the cost of repeated huge allocation/deallocation, because it + effectively introduces a cache of chunks. + - Split the arena chunk map into two separate arrays, in order to increase + cache locality for the frequently accessed bits. + - Move small run metadata out of runs, into arena chunk headers. This reduces + run fragmentation, smaller runs reduce external fragmentation for small size + classes, and packed (less uniformly aligned) metadata layout improves CPU + cache set distribution. + - Randomly distribute large allocation base pointer alignment relative to page + boundaries in order to more uniformly utilize CPU cache sets. This can be + disabled via the --disable-cache-oblivious configure option, and queried via + the "config.cache_oblivious" mallctl. + - Micro-optimize the fast paths for the public API functions. + - Refactor thread-specific data to reside in a single structure. This assures + that only a single TLS read is necessary per call into the public API. + - Implement in-place huge allocation growing and shrinking. + - Refactor rtree (radix tree for chunk lookups) to be lock-free, and make + additional optimizations that reduce maximum lookup depth to one or two + levels. This resolves what was a concurrency bottleneck for per arena huge + allocation, because a global data structure is critical for determining + which arenas own which huge allocations. + + Incompatible changes: + - Replace --enable-cc-silence with --disable-cc-silence to suppress spurious + warnings by default. + - Assure that the constness of malloc_usable_size()'s return type matches that + of the system implementation. + - Change the heap profile dump format to support per thread heap profiling, + rename pprof to jeprof, and enhance it with the --thread= option. As a + result, the bundled jeprof must now be used rather than the upstream + (gperftools) pprof. + - Disable "opt.prof_final" by default, in order to avoid atexit(3), which can + internally deadlock on some platforms. + - Change the "arenas.nlruns" mallctl type from size_t to unsigned. + - Replace the "stats.arenas..bins..allocated" mallctl with + "stats.arenas..bins..curregs". + - Ignore MALLOC_CONF in set{uid,gid,cap} binaries. + - Ignore MALLOCX_ARENA(a) in dallocx(), in favor of using the + MALLOCX_TCACHE(tc) and MALLOCX_TCACHE_NONE flags to control tcache usage. + + Removed features: + - Remove the *allocm() API, which is superseded by the *allocx() API. + - Remove the --enable-dss options, and make dss non-optional on all platforms + which support sbrk(2). + - Remove the "arenas.purge" mallctl, which was obsoleted by the + "arena..purge" mallctl in 3.1.0. + - Remove the unnecessary "opt.valgrind" mallctl; jemalloc automatically + detects whether it is running inside Valgrind. + - Remove the "stats.huge.allocated", "stats.huge.nmalloc", and + "stats.huge.ndalloc" mallctls. + - Remove the --enable-mremap option. + - Remove the "stats.chunks.current", "stats.chunks.total", and + "stats.chunks.high" mallctls. + + Bug fixes: + - Fix the cactive statistic to decrease (rather than increase) when active + memory decreases. This regression was first released in 3.5.0. + - Fix OOM handling in memalign() and valloc(). A variant of this bug existed + in all releases since 2.0.0, which introduced these functions. + - Fix an OOM-related regression in arena_tcache_fill_small(), which could + cause cache corruption on OOM. This regression was present in all releases + from 2.2.0 through 3.6.0. + - Fix size class overflow handling for malloc(), posix_memalign(), memalign(), + calloc(), and realloc() when profiling is enabled. + - Fix the "arena..dss" mallctl to return an error if "primary" or + "secondary" precedence is specified, but sbrk(2) is not supported. + - Fix fallback lg_floor() implementations to handle extremely large inputs. + - Ensure the default purgeable zone is after the default zone on OS X. + - Fix latent bugs in atomic_*(). + - Fix the "arena..dss" mallctl to handle read-only calls. + - Fix tls_model configuration to enable the initial-exec model when possible. + - Mark malloc_conf as a weak symbol so that the application can override it. + - Correctly detect glibc's adaptive pthread mutexes. + - Fix the --without-export configure option. + +* 3.6.0 (March 31, 2014) + + This version contains a critical bug fix for a regression present in 3.5.0 and + 3.5.1. + + Bug fixes: + - Fix a regression in arena_chunk_alloc() that caused crashes during + small/large allocation if chunk allocation failed. In the absence of this + bug, chunk allocation failure would result in allocation failure, e.g. NULL + return from malloc(). This regression was introduced in 3.5.0. + - Fix backtracing for gcc intrinsics-based backtracing by specifying + -fno-omit-frame-pointer to gcc. Note that the application (and all the + libraries it links to) must also be compiled with this option for + backtracing to be reliable. + - Use dss allocation precedence for huge allocations as well as small/large + allocations. + - Fix test assertion failure message formatting. This bug did not manifest on + x86_64 systems because of implementation subtleties in va_list. + - Fix inconsequential test failures for hash and SFMT code. + + New features: + - Support heap profiling on FreeBSD. This feature depends on the proc + filesystem being mounted during heap profile dumping. + +* 3.5.1 (February 25, 2014) + + This version primarily addresses minor bugs in test code. + + Bug fixes: + - Configure Solaris/Illumos to use MADV_FREE. + - Fix junk filling for mremap(2)-based huge reallocation. This is only + relevant if configuring with the --enable-mremap option specified. + - Avoid compilation failure if 'restrict' C99 keyword is not supported by the + compiler. + - Add a configure test for SSE2 rather than assuming it is usable on i686 + systems. This fixes test compilation errors, especially on 32-bit Linux + systems. + - Fix mallctl argument size mismatches (size_t vs. uint64_t) in the stats unit + test. + - Fix/remove flawed alignment-related overflow tests. + - Prevent compiler optimizations that could change backtraces in the + prof_accum unit test. + +* 3.5.0 (January 22, 2014) + + This version focuses on refactoring and automated testing, though it also + includes some non-trivial heap profiling optimizations not mentioned below. + + New features: + - Add the *allocx() API, which is a successor to the experimental *allocm() + API. The *allocx() functions are slightly simpler to use because they have + fewer parameters, they directly return the results of primary interest, and + mallocx()/rallocx() avoid the strict aliasing pitfall that + allocm()/rallocm() share with posix_memalign(). Note that *allocm() is + slated for removal in the next non-bugfix release. + - Add support for LinuxThreads. + + Bug fixes: + - Unless heap profiling is enabled, disable floating point code and don't link + with libm. This, in combination with e.g. EXTRA_CFLAGS=-mno-sse on x64 + systems, makes it possible to completely disable floating point register + use. Some versions of glibc neglect to save/restore caller-saved floating + point registers during dynamic lazy symbol loading, and the symbol loading + code uses whatever malloc the application happens to have linked/loaded + with, the result being potential floating point register corruption. + - Report ENOMEM rather than EINVAL if an OOM occurs during heap profiling + backtrace creation in imemalign(). This bug impacted posix_memalign() and + aligned_alloc(). + - Fix a file descriptor leak in a prof_dump_maps() error path. + - Fix prof_dump() to close the dump file descriptor for all relevant error + paths. + - Fix rallocm() to use the arena specified by the ALLOCM_ARENA(s) flag for + allocation, not just deallocation. + - Fix a data race for large allocation stats counters. + - Fix a potential infinite loop during thread exit. This bug occurred on + Solaris, and could affect other platforms with similar pthreads TSD + implementations. + - Don't junk-fill reallocations unless usable size changes. This fixes a + violation of the *allocx()/*allocm() semantics. + - Fix growing large reallocation to junk fill new space. + - Fix huge deallocation to junk fill when munmap is disabled. + - Change the default private namespace prefix from empty to je_, and change + --with-private-namespace-prefix so that it prepends an additional prefix + rather than replacing je_. This reduces the likelihood of applications + which statically link jemalloc experiencing symbol name collisions. + - Add missing private namespace mangling (relevant when + --with-private-namespace is specified). + - Add and use JEMALLOC_INLINE_C so that static inline functions are marked as + static even for debug builds. + - Add a missing mutex unlock in a malloc_init_hard() error path. In practice + this error path is never executed. + - Fix numerous bugs in malloc_strotumax() error handling/reporting. These + bugs had no impact except for malformed inputs. + - Fix numerous bugs in malloc_snprintf(). These bugs were not exercised by + existing calls, so they had no impact. + +* 3.4.1 (October 20, 2013) + + Bug fixes: + - Fix a race in the "arenas.extend" mallctl that could cause memory corruption + of internal data structures and subsequent crashes. + - Fix Valgrind integration flaws that caused Valgrind warnings about reads of + uninitialized memory in: + + arena chunk headers + + internal zero-initialized data structures (relevant to tcache and prof + code) + - Preserve errno during the first allocation. A readlink(2) call during + initialization fails unless /etc/malloc.conf exists, so errno was typically + set during the first allocation prior to this fix. + - Fix compilation warnings reported by gcc 4.8.1. + +* 3.4.0 (June 2, 2013) + + This version is essentially a small bugfix release, but the addition of + aarch64 support requires that the minor version be incremented. + + Bug fixes: + - Fix race-triggered deadlocks in chunk_record(). These deadlocks were + typically triggered by multiple threads concurrently deallocating huge + objects. + + New features: + - Add support for the aarch64 architecture. + +* 3.3.1 (March 6, 2013) + + This version fixes bugs that are typically encountered only when utilizing + custom run-time options. + + Bug fixes: + - Fix a locking order bug that could cause deadlock during fork if heap + profiling were enabled. + - Fix a chunk recycling bug that could cause the allocator to lose track of + whether a chunk was zeroed. On FreeBSD, NetBSD, and OS X, it could cause + corruption if allocating via sbrk(2) (unlikely unless running with the + "dss:primary" option specified). This was completely harmless on Linux + unless using mlockall(2) (and unlikely even then, unless the + --disable-munmap configure option or the "dss:primary" option was + specified). This regression was introduced in 3.1.0 by the + mlockall(2)/madvise(2) interaction fix. + - Fix TLS-related memory corruption that could occur during thread exit if the + thread never allocated memory. Only the quarantine and prof facilities were + susceptible. + - Fix two quarantine bugs: + + Internal reallocation of the quarantined object array leaked the old + array. + + Reallocation failure for internal reallocation of the quarantined object + array (very unlikely) resulted in memory corruption. + - Fix Valgrind integration to annotate all internally allocated memory in a + way that keeps Valgrind happy about internal data structure access. + - Fix building for s390 systems. + +* 3.3.0 (January 23, 2013) + + This version includes a few minor performance improvements in addition to the + listed new features and bug fixes. + + New features: + - Add clipping support to lg_chunk option processing. + - Add the --enable-ivsalloc option. + - Add the --without-export option. + - Add the --disable-zone-allocator option. + + Bug fixes: + - Fix "arenas.extend" mallctl to output the number of arenas. + - Fix chunk_recycle() to unconditionally inform Valgrind that returned memory + is undefined. + - Fix build break on FreeBSD related to alloca.h. + +* 3.2.0 (November 9, 2012) + + In addition to a couple of bug fixes, this version modifies page run + allocation and dirty page purging algorithms in order to better control + page-level virtual memory fragmentation. + + Incompatible changes: + - Change the "opt.lg_dirty_mult" default from 5 to 3 (32:1 to 8:1). + + Bug fixes: + - Fix dss/mmap allocation precedence code to use recyclable mmap memory only + after primary dss allocation fails. + - Fix deadlock in the "arenas.purge" mallctl. This regression was introduced + in 3.1.0 by the addition of the "arena..purge" mallctl. + +* 3.1.0 (October 16, 2012) + + New features: + - Auto-detect whether running inside Valgrind, thus removing the need to + manually specify MALLOC_CONF=valgrind:true. + - Add the "arenas.extend" mallctl, which allows applications to create + manually managed arenas. + - Add the ALLOCM_ARENA() flag for {,r,d}allocm(). + - Add the "opt.dss", "arena..dss", and "stats.arenas..dss" mallctls, + which provide control over dss/mmap precedence. + - Add the "arena..purge" mallctl, which obsoletes "arenas.purge". + - Define LG_QUANTUM for hppa. + + Incompatible changes: + - Disable tcache by default if running inside Valgrind, in order to avoid + making unallocated objects appear reachable to Valgrind. + - Drop const from malloc_usable_size() argument on Linux. + + Bug fixes: + - Fix heap profiling crash if sampled object is freed via realloc(p, 0). + - Remove const from __*_hook variable declarations, so that glibc can modify + them during process forking. + - Fix mlockall(2)/madvise(2) interaction. + - Fix fork(2)-related deadlocks. + - Fix error return value for "thread.tcache.enabled" mallctl. + +* 3.0.0 (May 11, 2012) + + Although this version adds some major new features, the primary focus is on + internal code cleanup that facilitates maintainability and portability, most + of which is not reflected in the ChangeLog. This is the first release to + incorporate substantial contributions from numerous other developers, and the + result is a more broadly useful allocator (see the git revision history for + contribution details). Note that the license has been unified, thanks to + Facebook granting a license under the same terms as the other copyright + holders (see COPYING). + + New features: + - Implement Valgrind support, redzones, and quarantine. + - Add support for additional platforms: + + FreeBSD + + Mac OS X Lion + + MinGW + + Windows (no support yet for replacing the system malloc) + - Add support for additional architectures: + + MIPS + + SH4 + + Tilera + - Add support for cross compiling. + - Add nallocm(), which rounds a request size up to the nearest size class + without actually allocating. + - Implement aligned_alloc() (blame C11). + - Add the "thread.tcache.enabled" mallctl. + - Add the "opt.prof_final" mallctl. + - Update pprof (from gperftools 2.0). + - Add the --with-mangling option. + - Add the --disable-experimental option. + - Add the --disable-munmap option, and make it the default on Linux. + - Add the --enable-mremap option, which disables use of mremap(2) by default. + + Incompatible changes: + - Enable stats by default. + - Enable fill by default. + - Disable lazy locking by default. + - Rename the "tcache.flush" mallctl to "thread.tcache.flush". + - Rename the "arenas.pagesize" mallctl to "arenas.page". + - Change the "opt.lg_prof_sample" default from 0 to 19 (1 B to 512 KiB). + - Change the "opt.prof_accum" default from true to false. + + Removed features: + - Remove the swap feature, including the "config.swap", "swap.avail", + "swap.prezeroed", "swap.nfds", and "swap.fds" mallctls. + - Remove highruns statistics, including the + "stats.arenas..bins..highruns" and + "stats.arenas..lruns..highruns" mallctls. + - As part of small size class refactoring, remove the "opt.lg_[qc]space_max", + "arenas.cacheline", "arenas.subpage", "arenas.[tqcs]space_{min,max}", and + "arenas.[tqcs]bins" mallctls. + - Remove the "arenas.chunksize" mallctl. + - Remove the "opt.lg_prof_tcmax" option. + - Remove the "opt.lg_prof_bt_max" option. + - Remove the "opt.lg_tcache_gc_sweep" option. + - Remove the --disable-tiny option, including the "config.tiny" mallctl. + - Remove the --enable-dynamic-page-shift configure option. + - Remove the --enable-sysv configure option. + + Bug fixes: + - Fix a statistics-related bug in the "thread.arena" mallctl that could cause + invalid statistics and crashes. + - Work around TLS deallocation via free() on Linux. This bug could cause + write-after-free memory corruption. + - Fix a potential deadlock that could occur during interval- and + growth-triggered heap profile dumps. + - Fix large calloc() zeroing bugs due to dropping chunk map unzeroed flags. + - Fix chunk_alloc_dss() to stop claiming memory is zeroed. This bug could + cause memory corruption and crashes with --enable-dss specified. + - Fix fork-related bugs that could cause deadlock in children between fork + and exec. + - Fix malloc_stats_print() to honor 'b' and 'l' in the opts parameter. + - Fix realloc(p, 0) to act like free(p). + - Do not enforce minimum alignment in memalign(). + - Check for NULL pointer in malloc_usable_size(). + - Fix an off-by-one heap profile statistics bug that could be observed in + interval- and growth-triggered heap profiles. + - Fix the "epoch" mallctl to update cached stats even if the passed in epoch + is 0. + - Fix bin->runcur management to fix a layout policy bug. This bug did not + affect correctness. + - Fix a bug in choose_arena_hard() that potentially caused more arenas to be + initialized than necessary. + - Add missing "opt.lg_tcache_max" mallctl implementation. + - Use glibc allocator hooks to make mixed allocator usage less likely. + - Fix build issues for --disable-tcache. + - Don't mangle pthread_create() when --with-private-namespace is specified. + +* 2.2.5 (November 14, 2011) + + Bug fixes: + - Fix huge_ralloc() race when using mremap(2). This is a serious bug that + could cause memory corruption and/or crashes. + - Fix huge_ralloc() to maintain chunk statistics. + - Fix malloc_stats_print(..., "a") output. + +* 2.2.4 (November 5, 2011) + + Bug fixes: + - Initialize arenas_tsd before using it. This bug existed for 2.2.[0-3], as + well as for --disable-tls builds in earlier releases. + - Do not assume a 4 KiB page size in test/rallocm.c. + +* 2.2.3 (August 31, 2011) + + This version fixes numerous bugs related to heap profiling. + + Bug fixes: + - Fix a prof-related race condition. This bug could cause memory corruption, + but only occurred in non-default configurations (prof_accum:false). + - Fix off-by-one backtracing issues (make sure that prof_alloc_prep() is + excluded from backtraces). + - Fix a prof-related bug in realloc() (only triggered by OOM errors). + - Fix prof-related bugs in allocm() and rallocm(). + - Fix prof_tdata_cleanup() for --disable-tls builds. + - Fix a relative include path, to fix objdir builds. + +* 2.2.2 (July 30, 2011) + + Bug fixes: + - Fix a build error for --disable-tcache. + - Fix assertions in arena_purge() (for real this time). + - Add the --with-private-namespace option. This is a workaround for symbol + conflicts that can inadvertently arise when using static libraries. + +* 2.2.1 (March 30, 2011) + + Bug fixes: + - Implement atomic operations for x86/x64. This fixes compilation failures + for versions of gcc that are still in wide use. + - Fix an assertion in arena_purge(). + +* 2.2.0 (March 22, 2011) + + This version incorporates several improvements to algorithms and data + structures that tend to reduce fragmentation and increase speed. + + New features: + - Add the "stats.cactive" mallctl. + - Update pprof (from google-perftools 1.7). + - Improve backtracing-related configuration logic, and add the + --disable-prof-libgcc option. + + Bug fixes: + - Change default symbol visibility from "internal", to "hidden", which + decreases the overhead of library-internal function calls. + - Fix symbol visibility so that it is also set on OS X. + - Fix a build dependency regression caused by the introduction of the .pic.o + suffix for PIC object files. + - Add missing checks for mutex initialization failures. + - Don't use libgcc-based backtracing except on x64, where it is known to work. + - Fix deadlocks on OS X that were due to memory allocation in + pthread_mutex_lock(). + - Heap profiling-specific fixes: + + Fix memory corruption due to integer overflow in small region index + computation, when using a small enough sample interval that profiling + context pointers are stored in small run headers. + + Fix a bootstrap ordering bug that only occurred with TLS disabled. + + Fix a rallocm() rsize bug. + + Fix error detection bugs for aligned memory allocation. + +* 2.1.3 (March 14, 2011) + + Bug fixes: + - Fix a cpp logic regression (due to the "thread.{de,}allocatedp" mallctl fix + for OS X in 2.1.2). + - Fix a "thread.arena" mallctl bug. + - Fix a thread cache stats merging bug. + +* 2.1.2 (March 2, 2011) + + Bug fixes: + - Fix "thread.{de,}allocatedp" mallctl for OS X. + - Add missing jemalloc.a to build system. + +* 2.1.1 (January 31, 2011) + + Bug fixes: + - Fix aligned huge reallocation (affected allocm()). + - Fix the ALLOCM_LG_ALIGN macro definition. + - Fix a heap dumping deadlock. + - Fix a "thread.arena" mallctl bug. + +* 2.1.0 (December 3, 2010) + + This version incorporates some optimizations that can't quite be considered + bug fixes. + + New features: + - Use Linux's mremap(2) for huge object reallocation when possible. + - Avoid locking in mallctl*() when possible. + - Add the "thread.[de]allocatedp" mallctl's. + - Convert the manual page source from roff to DocBook, and generate both roff + and HTML manuals. + + Bug fixes: + - Fix a crash due to incorrect bootstrap ordering. This only impacted + --enable-debug --enable-dss configurations. + - Fix a minor statistics bug for mallctl("swap.avail", ...). + +* 2.0.1 (October 29, 2010) + + Bug fixes: + - Fix a race condition in heap profiling that could cause undefined behavior + if "opt.prof_accum" were disabled. + - Add missing mutex unlocks for some OOM error paths in the heap profiling + code. + - Fix a compilation error for non-C99 builds. + +* 2.0.0 (October 24, 2010) + + This version focuses on the experimental *allocm() API, and on improved + run-time configuration/introspection. Nonetheless, numerous performance + improvements are also included. + + New features: + - Implement the experimental {,r,s,d}allocm() API, which provides a superset + of the functionality available via malloc(), calloc(), posix_memalign(), + realloc(), malloc_usable_size(), and free(). These functions can be used to + allocate/reallocate aligned zeroed memory, ask for optional extra memory + during reallocation, prevent object movement during reallocation, etc. + - Replace JEMALLOC_OPTIONS/JEMALLOC_PROF_PREFIX with MALLOC_CONF, which is + more human-readable, and more flexible. For example: + JEMALLOC_OPTIONS=AJP + is now: + MALLOC_CONF=abort:true,fill:true,stats_print:true + - Port to Apple OS X. Sponsored by Mozilla. + - Make it possible for the application to control thread-->arena mappings via + the "thread.arena" mallctl. + - Add compile-time support for all TLS-related functionality via pthreads TSD. + This is mainly of interest for OS X, which does not support TLS, but has a + TSD implementation with similar performance. + - Override memalign() and valloc() if they are provided by the system. + - Add the "arenas.purge" mallctl, which can be used to synchronously purge all + dirty unused pages. + - Make cumulative heap profiling data optional, so that it is possible to + limit the amount of memory consumed by heap profiling data structures. + - Add per thread allocation counters that can be accessed via the + "thread.allocated" and "thread.deallocated" mallctls. + + Incompatible changes: + - Remove JEMALLOC_OPTIONS and malloc_options (see MALLOC_CONF above). + - Increase default backtrace depth from 4 to 128 for heap profiling. + - Disable interval-based profile dumps by default. + + Bug fixes: + - Remove bad assertions in fork handler functions. These assertions could + cause aborts for some combinations of configure settings. + - Fix strerror_r() usage to deal with non-standard semantics in GNU libc. + - Fix leak context reporting. This bug tended to cause the number of contexts + to be underreported (though the reported number of objects and bytes were + correct). + - Fix a realloc() bug for large in-place growing reallocation. This bug could + cause memory corruption, but it was hard to trigger. + - Fix an allocation bug for small allocations that could be triggered if + multiple threads raced to create a new run of backing pages. + - Enhance the heap profiler to trigger samples based on usable size, rather + than request size. + - Fix a heap profiling bug due to sometimes losing track of requested object + size for sampled objects. + +* 1.0.3 (August 12, 2010) + + Bug fixes: + - Fix the libunwind-based implementation of stack backtracing (used for heap + profiling). This bug could cause zero-length backtraces to be reported. + - Add a missing mutex unlock in library initialization code. If multiple + threads raced to initialize malloc, some of them could end up permanently + blocked. + +* 1.0.2 (May 11, 2010) + + Bug fixes: + - Fix junk filling of large objects, which could cause memory corruption. + - Add MAP_NORESERVE support for chunk mapping, because otherwise virtual + memory limits could cause swap file configuration to fail. Contributed by + Jordan DeLong. + +* 1.0.1 (April 14, 2010) + + Bug fixes: + - Fix compilation when --enable-fill is specified. + - Fix threads-related profiling bugs that affected accuracy and caused memory + to be leaked during thread exit. + - Fix dirty page purging race conditions that could cause crashes. + - Fix crash in tcache flushing code during thread destruction. + +* 1.0.0 (April 11, 2010) + + This release focuses on speed and run-time introspection. Numerous + algorithmic improvements make this release substantially faster than its + predecessors. + + New features: + - Implement autoconf-based configuration system. + - Add mallctl*(), for the purposes of introspection and run-time + configuration. + - Make it possible for the application to manually flush a thread's cache, via + the "tcache.flush" mallctl. + - Base maximum dirty page count on proportion of active memory. + - Compute various additional run-time statistics, including per size class + statistics for large objects. + - Expose malloc_stats_print(), which can be called repeatedly by the + application. + - Simplify the malloc_message() signature to only take one string argument, + and incorporate an opaque data pointer argument for use by the application + in combination with malloc_stats_print(). + - Add support for allocation backed by one or more swap files, and allow the + application to disable over-commit if swap files are in use. + - Implement allocation profiling and leak checking. + + Removed features: + - Remove the dynamic arena rebalancing code, since thread-specific caching + reduces its utility. + + Bug fixes: + - Modify chunk allocation to work when address space layout randomization + (ASLR) is in use. + - Fix thread cleanup bugs related to TLS destruction. + - Handle 0-size allocation requests in posix_memalign(). + - Fix a chunk leak. The leaked chunks were never touched, so this impacted + virtual memory usage, but not physical memory usage. + +* linux_2008082[78]a (August 27/28, 2008) + + These snapshot releases are the simple result of incorporating Linux-specific + support into the FreeBSD malloc sources. + +-------------------------------------------------------------------------------- +vim:filetype=text:textwidth=80 diff --git a/jemalloc/INSTALL.md b/jemalloc/INSTALL.md new file mode 100644 index 0000000..b8f729b --- /dev/null +++ b/jemalloc/INSTALL.md @@ -0,0 +1,421 @@ +Building and installing a packaged release of jemalloc can be as simple as +typing the following while in the root directory of the source tree: + + ./configure + make + make install + +If building from unpackaged developer sources, the simplest command sequence +that might work is: + + ./autogen.sh + make dist + make + make install + +Note that documentation is not built by the default target because doing so +would create a dependency on xsltproc in packaged releases, hence the +requirement to either run 'make dist' or avoid installing docs via the various +install_* targets documented below. + + +## Advanced configuration + +The 'configure' script supports numerous options that allow control of which +functionality is enabled, where jemalloc is installed, etc. Optionally, pass +any of the following arguments (not a definitive list) to 'configure': + +* `--help` + + Print a definitive list of options. + +* `--prefix=` + + Set the base directory in which to install. For example: + + ./configure --prefix=/usr/local + + will cause files to be installed into /usr/local/include, /usr/local/lib, + and /usr/local/man. + +* `--with-version=(..--g|VERSION)` + + The VERSION file is mandatory for successful configuration, and the + following steps are taken to assure its presence: + 1) If --with-version=..--g is specified, + generate VERSION using the specified value. + 2) If --with-version is not specified in either form and the source + directory is inside a git repository, try to generate VERSION via 'git + describe' invocations that pattern-match release tags. + 3) If VERSION is missing, generate it with a bogus version: + 0.0.0-0-g0000000000000000000000000000000000000000 + + Note that --with-version=VERSION bypasses (1) and (2), which simplifies + VERSION configuration when embedding a jemalloc release into another + project's git repository. + +* `--with-rpath=` + + Embed one or more library paths, so that libjemalloc can find the libraries + it is linked to. This works only on ELF-based systems. + +* `--with-mangling=` + + Mangle public symbols specified in which is a comma-separated list of + name:mangled pairs. + + For example, to use ld's --wrap option as an alternative method for + overriding libc's malloc implementation, specify something like: + + --with-mangling=malloc:__wrap_malloc,free:__wrap_free[...] + + Note that mangling happens prior to application of the prefix specified by + --with-jemalloc-prefix, and mangled symbols are then ignored when applying + the prefix. + +* `--with-jemalloc-prefix=` + + Prefix all public APIs with . For example, if is + "prefix_", API changes like the following occur: + + malloc() --> prefix_malloc() + malloc_conf --> prefix_malloc_conf + /etc/malloc.conf --> /etc/prefix_malloc.conf + MALLOC_CONF --> PREFIX_MALLOC_CONF + + This makes it possible to use jemalloc at the same time as the system + allocator, or even to use multiple copies of jemalloc simultaneously. + + By default, the prefix is "", except on OS X, where it is "je_". On OS X, + jemalloc overlays the default malloc zone, but makes no attempt to actually + replace the "malloc", "calloc", etc. symbols. + +* `--without-export` + + Don't export public APIs. This can be useful when building jemalloc as a + static library, or to avoid exporting public APIs when using the zone + allocator on OSX. + +* `--with-private-namespace=` + + Prefix all library-private APIs with je_. For shared libraries, + symbol visibility mechanisms prevent these symbols from being exported, but + for static libraries, naming collisions are a real possibility. By + default, is empty, which results in a symbol prefix of je_ . + +* `--with-install-suffix=` + + Append to the base name of all installed files, such that multiple + versions of jemalloc can coexist in the same installation directory. For + example, libjemalloc.so.0 becomes libjemalloc.so.0. + +* `--with-malloc-conf=` + + Embed `` as a run-time options string that is processed prior to + the malloc_conf global variable, the /etc/malloc.conf symlink, and the + MALLOC_CONF environment variable. For example, to change the default decay + time to 30 seconds: + + --with-malloc-conf=decay_ms:30000 + +* `--enable-debug` + + Enable assertions and validation code. This incurs a substantial + performance hit, but is very useful during application development. + +* `--disable-stats` + + Disable statistics gathering functionality. See the "opt.stats_print" + option documentation for usage details. + +* `--enable-prof` + + Enable heap profiling and leak detection functionality. See the "opt.prof" + option documentation for usage details. When enabled, there are several + approaches to backtracing, and the configure script chooses the first one + in the following list that appears to function correctly: + + + libunwind (requires --enable-prof-libunwind) + + libgcc (unless --disable-prof-libgcc) + + gcc intrinsics (unless --disable-prof-gcc) + +* `--enable-prof-libunwind` + + Use the libunwind library (http://www.nongnu.org/libunwind/) for stack + backtracing. + +* `--disable-prof-libgcc` + + Disable the use of libgcc's backtracing functionality. + +* `--disable-prof-gcc` + + Disable the use of gcc intrinsics for backtracing. + +* `--with-static-libunwind=` + + Statically link against the specified libunwind.a rather than dynamically + linking with -lunwind. + +* `--disable-fill` + + Disable support for junk/zero filling of memory. See the "opt.junk" and + "opt.zero" option documentation for usage details. + +* `--disable-zone-allocator` + + Disable zone allocator for Darwin. This means jemalloc won't be hooked as + the default allocator on OSX/iOS. + +* `--enable-utrace` + + Enable utrace(2)-based allocation tracing. This feature is not broadly + portable (FreeBSD has it, but Linux and OS X do not). + +* `--enable-xmalloc` + + Enable support for optional immediate termination due to out-of-memory + errors, as is commonly implemented by "xmalloc" wrapper function for malloc. + See the "opt.xmalloc" option documentation for usage details. + +* `--enable-lazy-lock` + + Enable code that wraps pthread_create() to detect when an application + switches from single-threaded to multi-threaded mode, so that it can avoid + mutex locking/unlocking operations while in single-threaded mode. In + practice, this feature usually has little impact on performance unless + thread-specific caching is disabled. + +* `--disable-cache-oblivious` + + Disable cache-oblivious large allocation alignment for large allocation + requests with no alignment constraints. If this feature is disabled, all + large allocations are page-aligned as an implementation artifact, which can + severely harm CPU cache utilization. However, the cache-oblivious layout + comes at the cost of one extra page per large allocation, which in the + most extreme case increases physical memory usage for the 16 KiB size class + to 20 KiB. + +* `--disable-syscall` + + Disable use of syscall(2) rather than {open,read,write,close}(2). This is + intended as a workaround for systems that place security limitations on + syscall(2). + +* `--disable-cxx` + + Disable C++ integration. This will cause new and delete operator + implementations to be omitted. + +* `--with-xslroot=` + + Specify where to find DocBook XSL stylesheets when building the + documentation. + +* `--with-lg-page=` + + Specify the base 2 log of the allocator page size, which must in turn be at + least as large as the system page size. By default the configure script + determines the host's page size and sets the allocator page size equal to + the system page size, so this option need not be specified unless the + system page size may change between configuration and execution, e.g. when + cross compiling. + +* `--with-lg-hugepage=` + + Specify the base 2 log of the system huge page size. This option is useful + when cross compiling, or when overriding the default for systems that do + not explicitly support huge pages. + +* `--with-lg-quantum=` + + Specify the base 2 log of the minimum allocation alignment. jemalloc needs + to know the minimum alignment that meets the following C standard + requirement (quoted from the April 12, 2011 draft of the C11 standard): + + > The pointer returned if the allocation succeeds is suitably aligned so + that it may be assigned to a pointer to any type of object with a + fundamental alignment requirement and then used to access such an object + or an array of such objects in the space allocated [...] + + This setting is architecture-specific, and although jemalloc includes known + safe values for the most commonly used modern architectures, there is a + wrinkle related to GNU libc (glibc) that may impact your choice of + . On most modern architectures, this mandates 16-byte + alignment (=4), but the glibc developers chose not to meet this + requirement for performance reasons. An old discussion can be found at + . Unlike glibc, + jemalloc does follow the C standard by default (caveat: jemalloc + technically cheats for size classes smaller than the quantum), but the fact + that Linux systems already work around this allocator noncompliance means + that it is generally safe in practice to let jemalloc's minimum alignment + follow glibc's lead. If you specify `--with-lg-quantum=3` during + configuration, jemalloc will provide additional size classes that are not + 16-byte-aligned (24, 40, and 56). + +* `--with-lg-vaddr=` + + Specify the number of significant virtual address bits. By default, the + configure script attempts to detect virtual address size on those platforms + where it knows how, and picks a default otherwise. This option may be + useful when cross-compiling. + +* `--disable-initial-exec-tls` + + Disable the initial-exec TLS model for jemalloc's internal thread-local + storage (on those platforms that support explicit settings). This can allow + jemalloc to be dynamically loaded after program startup (e.g. using dlopen). + Note that in this case, there will be two malloc implementations operating + in the same process, which will almost certainly result in confusing runtime + crashes if pointers leak from one implementation to the other. + +* `--disable-libdl` + + Disable the usage of libdl, namely dlsym(3) which is required by the lazy + lock option. This can allow building static binaries. + +The following environment variables (not a definitive list) impact configure's +behavior: + +* `CFLAGS="?"` +* `CXXFLAGS="?"` + + Pass these flags to the C/C++ compiler. Any flags set by the configure + script are prepended, which means explicitly set flags generally take + precedence. Take care when specifying flags such as -Werror, because + configure tests may be affected in undesirable ways. + +* `EXTRA_CFLAGS="?"` +* `EXTRA_CXXFLAGS="?"` + + Append these flags to CFLAGS/CXXFLAGS, without passing them to the + compiler(s) during configuration. This makes it possible to add flags such + as -Werror, while allowing the configure script to determine what other + flags are appropriate for the specified configuration. + +* `CPPFLAGS="?"` + + Pass these flags to the C preprocessor. Note that CFLAGS is not passed to + 'cpp' when 'configure' is looking for include files, so you must use + CPPFLAGS instead if you need to help 'configure' find header files. + +* `LD_LIBRARY_PATH="?"` + + 'ld' uses this colon-separated list to find libraries. + +* `LDFLAGS="?"` + + Pass these flags when linking. + +* `PATH="?"` + + 'configure' uses this to find programs. + +In some cases it may be necessary to work around configuration results that do +not match reality. For example, Linux 4.5 added support for the MADV_FREE flag +to madvise(2), which can cause problems if building on a host with MADV_FREE +support and deploying to a target without. To work around this, use a cache +file to override the relevant configuration variable defined in configure.ac, +e.g.: + + echo "je_cv_madv_free=no" > config.cache && ./configure -C + + +## Advanced compilation + +To build only parts of jemalloc, use the following targets: + + build_lib_shared + build_lib_static + build_lib + build_doc_html + build_doc_man + build_doc + +To install only parts of jemalloc, use the following targets: + + install_bin + install_include + install_lib_shared + install_lib_static + install_lib_pc + install_lib + install_doc_html + install_doc_man + install_doc + +To clean up build results to varying degrees, use the following make targets: + + clean + distclean + relclean + + +## Advanced installation + +Optionally, define make variables when invoking make, including (not +exclusively): + +* `INCLUDEDIR="?"` + + Use this as the installation prefix for header files. + +* `LIBDIR="?"` + + Use this as the installation prefix for libraries. + +* `MANDIR="?"` + + Use this as the installation prefix for man pages. + +* `DESTDIR="?"` + + Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful + when installing to a different path than was specified via --prefix. + +* `CC="?"` + + Use this to invoke the C compiler. + +* `CFLAGS="?"` + + Pass these flags to the compiler. + +* `CPPFLAGS="?"` + + Pass these flags to the C preprocessor. + +* `LDFLAGS="?"` + + Pass these flags when linking. + +* `PATH="?"` + + Use this to search for programs used during configuration and building. + + +## Development + +If you intend to make non-trivial changes to jemalloc, use the 'autogen.sh' +script rather than 'configure'. This re-generates 'configure', enables +configuration dependency rules, and enables re-generation of automatically +generated source files. + +The build system supports using an object directory separate from the source +tree. For example, you can create an 'obj' directory, and from within that +directory, issue configuration and build commands: + + autoconf + mkdir obj + cd obj + ../configure --enable-autogen + make + + +## Documentation + +The manual page is generated in both html and roff formats. Any web browser +can be used to view the html manual. The roff manual page can be formatted +prior to installation via the following command: + + nroff -man -t doc/jemalloc.3 diff --git a/jemalloc/Makefile.in b/jemalloc/Makefile.in new file mode 100644 index 0000000..7128b00 --- /dev/null +++ b/jemalloc/Makefile.in @@ -0,0 +1,623 @@ +# Clear out all vpaths, then set just one (default vpath) for the main build +# directory. +vpath +vpath % . + +# Clear the default suffixes, so that built-in rules are not used. +.SUFFIXES : + +SHELL := /bin/sh + +CC := @CC@ +CXX := @CXX@ + +# Configuration parameters. +DESTDIR = +BINDIR := $(DESTDIR)@BINDIR@ +INCLUDEDIR := $(DESTDIR)@INCLUDEDIR@ +LIBDIR := $(DESTDIR)@LIBDIR@ +DATADIR := $(DESTDIR)@DATADIR@ +MANDIR := $(DESTDIR)@MANDIR@ +srcroot := @srcroot@ +objroot := @objroot@ +abs_srcroot := @abs_srcroot@ +abs_objroot := @abs_objroot@ + +# Build parameters. +CPPFLAGS := @CPPFLAGS@ -I$(objroot)include -I$(srcroot)include +CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@ +SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@ +EXTRA_CFLAGS := @EXTRA_CFLAGS@ +CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS)) +CONFIGURE_CXXFLAGS := @CONFIGURE_CXXFLAGS@ +SPECIFIED_CXXFLAGS := @SPECIFIED_CXXFLAGS@ +EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@ +CXXFLAGS := $(strip $(CONFIGURE_CXXFLAGS) $(SPECIFIED_CXXFLAGS) $(EXTRA_CXXFLAGS)) +LDFLAGS := @LDFLAGS@ +EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ +LIBS := @LIBS@ +RPATH_EXTRA := @RPATH_EXTRA@ +SO := @so@ +IMPORTLIB := @importlib@ +O := @o@ +A := @a@ +EXE := @exe@ +LIBPREFIX := @libprefix@ +REV := @rev@ +install_suffix := @install_suffix@ +ABI := @abi@ +XSLTPROC := @XSLTPROC@ +XSLROOT := @XSLROOT@ +AUTOCONF := @AUTOCONF@ +_RPATH = @RPATH@ +RPATH = $(if $(1),$(call _RPATH,$(1))) +cfghdrs_in := $(addprefix $(srcroot),@cfghdrs_in@) +cfghdrs_out := @cfghdrs_out@ +cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@) +cfgoutputs_out := @cfgoutputs_out@ +enable_autogen := @enable_autogen@ +enable_doc := @enable_doc@ +enable_shared := @enable_shared@ +enable_static := @enable_static@ +enable_prof := @enable_prof@ +enable_zone_allocator := @enable_zone_allocator@ +enable_experimental_smallocx := @enable_experimental_smallocx@ +MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF +link_whole_archive := @link_whole_archive@ +DSO_LDFLAGS = @DSO_LDFLAGS@ +SOREV = @SOREV@ +PIC_CFLAGS = @PIC_CFLAGS@ +CTARGET = @CTARGET@ +LDTARGET = @LDTARGET@ +TEST_LD_MODE = @TEST_LD_MODE@ +MKLIB = @MKLIB@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +DUMP_SYMS = @DUMP_SYMS@ +AWK := @AWK@ +CC_MM = @CC_MM@ +LM := @LM@ +INSTALL = @INSTALL@ + +ifeq (macho, $(ABI)) +TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib" +else +ifeq (pecoff, $(ABI)) +TEST_LIBRARY_PATH := PATH="$(PATH):$(objroot)lib" +else +TEST_LIBRARY_PATH := +endif +endif + +LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix) + +# Lists of files. +BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof +C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h +C_SRCS := $(srcroot)src/jemalloc.c \ + $(srcroot)src/arena.c \ + $(srcroot)src/background_thread.c \ + $(srcroot)src/base.c \ + $(srcroot)src/bin.c \ + $(srcroot)src/bitmap.c \ + $(srcroot)src/ckh.c \ + $(srcroot)src/ctl.c \ + $(srcroot)src/div.c \ + $(srcroot)src/extent.c \ + $(srcroot)src/extent_dss.c \ + $(srcroot)src/extent_mmap.c \ + $(srcroot)src/hash.c \ + $(srcroot)src/hook.c \ + $(srcroot)src/large.c \ + $(srcroot)src/log.c \ + $(srcroot)src/malloc_io.c \ + $(srcroot)src/mutex.c \ + $(srcroot)src/mutex_pool.c \ + $(srcroot)src/nstime.c \ + $(srcroot)src/pages.c \ + $(srcroot)src/prng.c \ + $(srcroot)src/prof.c \ + $(srcroot)src/rtree.c \ + $(srcroot)src/safety_check.c \ + $(srcroot)src/stats.c \ + $(srcroot)src/sc.c \ + $(srcroot)src/sz.c \ + $(srcroot)src/tcache.c \ + $(srcroot)src/test_hooks.c \ + $(srcroot)src/ticker.c \ + $(srcroot)src/tsd.c \ + $(srcroot)src/witness.c +ifeq ($(enable_zone_allocator), 1) +C_SRCS += $(srcroot)src/zone.c +endif +ifeq ($(IMPORTLIB),$(SO)) +STATIC_LIBS := $(objroot)lib/$(LIBJEMALLOC).$(A) +endif +ifdef PIC_CFLAGS +STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_pic.$(A) +else +STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_s.$(A) +endif +DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV) +ifneq ($(SOREV),$(SO)) +DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) +endif +ifeq (1, $(link_whole_archive)) +LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive +else +LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) +endif +PC := $(objroot)jemalloc.pc +MAN3 := $(objroot)doc/jemalloc$(install_suffix).3 +DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml +DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.html) +DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.3) +DOCS := $(DOCS_HTML) $(DOCS_MAN3) +C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ + $(srcroot)test/src/btalloc_1.c $(srcroot)test/src/math.c \ + $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ + $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ + $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c +ifeq (1, $(link_whole_archive)) +C_UTIL_INTEGRATION_SRCS := +C_UTIL_CPP_SRCS := +else +C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c +C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c +endif +TESTS_UNIT := \ + $(srcroot)test/unit/a0.c \ + $(srcroot)test/unit/arena_reset.c \ + $(srcroot)test/unit/atomic.c \ + $(srcroot)test/unit/background_thread.c \ + $(srcroot)test/unit/background_thread_enable.c \ + $(srcroot)test/unit/base.c \ + $(srcroot)test/unit/bitmap.c \ + $(srcroot)test/unit/bit_util.c \ + $(srcroot)test/unit/binshard.c \ + $(srcroot)test/unit/ckh.c \ + $(srcroot)test/unit/decay.c \ + $(srcroot)test/unit/div.c \ + $(srcroot)test/unit/emitter.c \ + $(srcroot)test/unit/extent_quantize.c \ + $(srcroot)test/unit/extent_util.c \ + $(srcroot)test/unit/fork.c \ + $(srcroot)test/unit/hash.c \ + $(srcroot)test/unit/hook.c \ + $(srcroot)test/unit/huge.c \ + $(srcroot)test/unit/junk.c \ + $(srcroot)test/unit/junk_alloc.c \ + $(srcroot)test/unit/junk_free.c \ + $(srcroot)test/unit/log.c \ + $(srcroot)test/unit/mallctl.c \ + $(srcroot)test/unit/malloc_io.c \ + $(srcroot)test/unit/math.c \ + $(srcroot)test/unit/mq.c \ + $(srcroot)test/unit/mtx.c \ + $(srcroot)test/unit/pack.c \ + $(srcroot)test/unit/pages.c \ + $(srcroot)test/unit/ph.c \ + $(srcroot)test/unit/prng.c \ + $(srcroot)test/unit/prof_accum.c \ + $(srcroot)test/unit/prof_active.c \ + $(srcroot)test/unit/prof_gdump.c \ + $(srcroot)test/unit/prof_idump.c \ + $(srcroot)test/unit/prof_log.c \ + $(srcroot)test/unit/prof_reset.c \ + $(srcroot)test/unit/prof_tctx.c \ + $(srcroot)test/unit/prof_thread_name.c \ + $(srcroot)test/unit/ql.c \ + $(srcroot)test/unit/qr.c \ + $(srcroot)test/unit/rb.c \ + $(srcroot)test/unit/retained.c \ + $(srcroot)test/unit/rtree.c \ + $(srcroot)test/unit/safety_check.c \ + $(srcroot)test/unit/seq.c \ + $(srcroot)test/unit/SFMT.c \ + $(srcroot)test/unit/sc.c \ + $(srcroot)test/unit/size_classes.c \ + $(srcroot)test/unit/slab.c \ + $(srcroot)test/unit/smoothstep.c \ + $(srcroot)test/unit/spin.c \ + $(srcroot)test/unit/stats.c \ + $(srcroot)test/unit/stats_print.c \ + $(srcroot)test/unit/test_hooks.c \ + $(srcroot)test/unit/ticker.c \ + $(srcroot)test/unit/nstime.c \ + $(srcroot)test/unit/tsd.c \ + $(srcroot)test/unit/witness.c \ + $(srcroot)test/unit/zero.c +ifeq (@enable_prof@, 1) +TESTS_UNIT += \ + $(srcroot)test/unit/arena_reset_prof.c +endif +TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ + $(srcroot)test/integration/allocated.c \ + $(srcroot)test/integration/extent.c \ + $(srcroot)test/integration/malloc.c \ + $(srcroot)test/integration/mallocx.c \ + $(srcroot)test/integration/MALLOCX_ARENA.c \ + $(srcroot)test/integration/overflow.c \ + $(srcroot)test/integration/posix_memalign.c \ + $(srcroot)test/integration/rallocx.c \ + $(srcroot)test/integration/sdallocx.c \ + $(srcroot)test/integration/slab_sizes.c \ + $(srcroot)test/integration/thread_arena.c \ + $(srcroot)test/integration/thread_tcache_enabled.c \ + $(srcroot)test/integration/xallocx.c +ifeq (@enable_experimental_smallocx@, 1) +TESTS_INTEGRATION += \ + $(srcroot)test/integration/smallocx.c +endif +ifeq (@enable_cxx@, 1) +CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp +TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp +else +CPP_SRCS := +TESTS_INTEGRATION_CPP := +endif +TESTS_STRESS := $(srcroot)test/stress/microbench.c \ + $(srcroot)test/stress/hookbench.c + + +TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS) + +PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h +PRIVATE_NAMESPACE_GEN_HDRS := $(PRIVATE_NAMESPACE_HDRS:%.h=%.gen.h) +C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O)) +C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym) +C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) +CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O)) +C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O)) +CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O)) +C_JET_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym.$(O)) +C_JET_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym) +C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O)) +C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O)) +C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) +C_UTIL_INTEGRATION_OBJS := $(C_UTIL_INTEGRATION_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) +C_TESTLIB_STRESS_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.stress.$(O)) +C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(C_TESTLIB_STRESS_OBJS) + +TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O)) +TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O)) +TESTS_INTEGRATION_CPP_OBJS := $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%.$(O)) +TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O)) +TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS) +TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS) + +.PHONY: all dist build_doc_html build_doc_man build_doc +.PHONY: install_bin install_include install_lib +.PHONY: install_doc_html install_doc_man install_doc install +.PHONY: tests check clean distclean relclean + +.SECONDARY : $(PRIVATE_NAMESPACE_GEN_HDRS) $(TESTS_OBJS) $(TESTS_CPP_OBJS) + +# Default target. +all: build_lib + +dist: build_doc + +$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl +ifneq ($(XSLROOT),) + $(XSLTPROC) -o $@ $(objroot)doc/html.xsl $< +else +ifeq ($(wildcard $(DOCS_HTML)),) + @echo "

Missing xsltproc. Doc not built.

" > $@ +endif + @echo "Missing xsltproc. "$@" not (re)built." +endif + +$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl +ifneq ($(XSLROOT),) + $(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $< +else +ifeq ($(wildcard $(DOCS_MAN3)),) + @echo "Missing xsltproc. Doc not built." > $@ +endif + @echo "Missing xsltproc. "$@" not (re)built." +endif + +build_doc_html: $(DOCS_HTML) +build_doc_man: $(DOCS_MAN3) +build_doc: $(DOCS) + +# +# Include generated dependency files. +# +ifdef CC_MM +-include $(C_SYM_OBJS:%.$(O)=%.d) +-include $(C_OBJS:%.$(O)=%.d) +-include $(CPP_OBJS:%.$(O)=%.d) +-include $(C_PIC_OBJS:%.$(O)=%.d) +-include $(CPP_PIC_OBJS:%.$(O)=%.d) +-include $(C_JET_SYM_OBJS:%.$(O)=%.d) +-include $(C_JET_OBJS:%.$(O)=%.d) +-include $(C_TESTLIB_OBJS:%.$(O)=%.d) +-include $(TESTS_OBJS:%.$(O)=%.d) +-include $(TESTS_CPP_OBJS:%.$(O)=%.d) +endif + +$(C_SYM_OBJS): $(objroot)src/%.sym.$(O): $(srcroot)src/%.c +$(C_SYM_OBJS): CPPFLAGS += -DJEMALLOC_NO_PRIVATE_NAMESPACE +$(C_SYMS): $(objroot)src/%.sym: $(objroot)src/%.sym.$(O) +$(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c +$(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp +$(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c +$(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS) +$(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp +$(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS) +$(C_JET_SYM_OBJS): $(objroot)src/%.jet.sym.$(O): $(srcroot)src/%.c +$(C_JET_SYM_OBJS): CPPFLAGS += -DJEMALLOC_JET -DJEMALLOC_NO_PRIVATE_NAMESPACE +$(C_JET_SYMS): $(objroot)src/%.jet.sym: $(objroot)src/%.jet.sym.$(O) +$(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c +$(C_JET_OBJS): CPPFLAGS += -DJEMALLOC_JET +$(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c +$(C_TESTLIB_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST +$(C_TESTLIB_INTEGRATION_OBJS): $(objroot)test/src/%.integration.$(O): $(srcroot)test/src/%.c +$(C_TESTLIB_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST +$(C_UTIL_INTEGRATION_OBJS): $(objroot)src/%.integration.$(O): $(srcroot)src/%.c +$(C_TESTLIB_STRESS_OBJS): $(objroot)test/src/%.stress.$(O): $(srcroot)test/src/%.c +$(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_TESTLIB +$(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +$(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST +$(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST +$(TESTS_INTEGRATION_CPP_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_CPP_TEST +$(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST +$(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c +$(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp +$(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +$(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +ifneq ($(IMPORTLIB),$(SO)) +$(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT +endif + +# Dependencies. +ifndef CC_MM +HEADER_DIRS = $(srcroot)include/jemalloc/internal \ + $(objroot)include/jemalloc $(objroot)include/jemalloc/internal +HEADERS = $(filter-out $(PRIVATE_NAMESPACE_HDRS),$(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h))) +$(C_SYM_OBJS) $(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(HEADERS) +$(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h +endif + +$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_INTEGRATION_CPP_OBJS): $(objroot)include/jemalloc/internal/private_namespace.h +$(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_STRESS_OBJS) $(TESTS_UNIT_OBJS) $(TESTS_STRESS_OBJS): $(objroot)include/jemalloc/internal/private_namespace_jet.h + +$(C_SYM_OBJS) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): + @mkdir -p $(@D) + $(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $< +ifdef CC_MM + @$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< +endif + +$(C_SYMS): %.sym: + @mkdir -p $(@D) + $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols.awk > $@ + +$(C_JET_SYMS): %.sym: + @mkdir -p $(@D) + $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@ + +$(objroot)include/jemalloc/internal/private_namespace.gen.h: $(C_SYMS) + $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ + +$(objroot)include/jemalloc/internal/private_namespace_jet.gen.h: $(C_JET_SYMS) + $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ + +%.h: %.gen.h + @if ! `cmp -s $< $@` ; then echo "cp $< $<"; cp $< $@ ; fi + +$(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): + @mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $< +ifdef CC_MM + @$(CXX) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< +endif + +ifneq ($(SOREV),$(SO)) +%.$(SO) : %.$(SOREV) + @mkdir -p $(@D) + ln -sf $( $(srcroot)config.stamp.in + +$(objroot)config.stamp : $(cfgoutputs_in) $(cfghdrs_in) $(srcroot)configure + ./$(objroot)config.status + @touch $@ + +# There must be some action in order for make to re-read Makefile when it is +# out of date. +$(cfgoutputs_out) $(cfghdrs_out) : $(objroot)config.stamp + @true +endif diff --git a/jemalloc/README b/jemalloc/README new file mode 100644 index 0000000..3a6e0d2 --- /dev/null +++ b/jemalloc/README @@ -0,0 +1,20 @@ +jemalloc is a general purpose malloc(3) implementation that emphasizes +fragmentation avoidance and scalable concurrency support. jemalloc first came +into use as the FreeBSD libc allocator in 2005, and since then it has found its +way into numerous applications that rely on its predictable behavior. In 2010 +jemalloc development efforts broadened to include developer support features +such as heap profiling and extensive monitoring/tuning hooks. Modern jemalloc +releases continue to be integrated back into FreeBSD, and therefore versatility +remains critical. Ongoing development efforts trend toward making jemalloc +among the best allocators for a broad range of demanding applications, and +eliminating/mitigating weaknesses that have practical repercussions for real +world applications. + +The COPYING file contains copyright and licensing information. + +The INSTALL file contains information on how to configure, build, and install +jemalloc. + +The ChangeLog file contains a brief summary of changes for each release. + +URL: http://jemalloc.net/ diff --git a/jemalloc/TUNING.md b/jemalloc/TUNING.md new file mode 100644 index 0000000..7d094f3 --- /dev/null +++ b/jemalloc/TUNING.md @@ -0,0 +1,129 @@ +This document summarizes the common approaches for performance fine tuning with +jemalloc (as of 5.1.0). The default configuration of jemalloc tends to work +reasonably well in practice, and most applications should not have to tune any +options. However, in order to cover a wide range of applications and avoid +pathological cases, the default setting is sometimes kept conservative and +suboptimal, even for many common workloads. When jemalloc is properly tuned for +a specific application / workload, it is common to improve system level metrics +by a few percent, or make favorable trade-offs. + + +## Notable runtime options for performance tuning + +Runtime options can be set via +[malloc_conf](http://jemalloc.net/jemalloc.3.html#tuning). + +* [background_thread](http://jemalloc.net/jemalloc.3.html#background_thread) + + Enabling jemalloc background threads generally improves the tail latency for + application threads, since unused memory purging is shifted to the dedicated + background threads. In addition, unintended purging delay caused by + application inactivity is avoided with background threads. + + Suggested: `background_thread:true` when jemalloc managed threads can be + allowed. + +* [metadata_thp](http://jemalloc.net/jemalloc.3.html#opt.metadata_thp) + + Allowing jemalloc to utilize transparent huge pages for its internal + metadata usually reduces TLB misses significantly, especially for programs + with large memory footprint and frequent allocation / deallocation + activities. Metadata memory usage may increase due to the use of huge + pages. + + Suggested for allocation intensive programs: `metadata_thp:auto` or + `metadata_thp:always`, which is expected to improve CPU utilization at a + small memory cost. + +* [dirty_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.dirty_decay_ms) and + [muzzy_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.muzzy_decay_ms) + + Decay time determines how fast jemalloc returns unused pages back to the + operating system, and therefore provides a fairly straightforward trade-off + between CPU and memory usage. Shorter decay time purges unused pages faster + to reduces memory usage (usually at the cost of more CPU cycles spent on + purging), and vice versa. + + Suggested: tune the values based on the desired trade-offs. + +* [narenas](http://jemalloc.net/jemalloc.3.html#opt.narenas) + + By default jemalloc uses multiple arenas to reduce internal lock contention. + However high arena count may also increase overall memory fragmentation, + since arenas manage memory independently. When high degree of parallelism + is not expected at the allocator level, lower number of arenas often + improves memory usage. + + Suggested: if low parallelism is expected, try lower arena count while + monitoring CPU and memory usage. + +* [percpu_arena](http://jemalloc.net/jemalloc.3.html#opt.percpu_arena) + + Enable dynamic thread to arena association based on running CPU. This has + the potential to improve locality, e.g. when thread to CPU affinity is + present. + + Suggested: try `percpu_arena:percpu` or `percpu_arena:phycpu` if + thread migration between processors is expected to be infrequent. + +Examples: + +* High resource consumption application, prioritizing CPU utilization: + + `background_thread:true,metadata_thp:auto` combined with relaxed decay time + (increased `dirty_decay_ms` and / or `muzzy_decay_ms`, + e.g. `dirty_decay_ms:30000,muzzy_decay_ms:30000`). + +* High resource consumption application, prioritizing memory usage: + + `background_thread:true` combined with shorter decay time (decreased + `dirty_decay_ms` and / or `muzzy_decay_ms`, + e.g. `dirty_decay_ms:5000,muzzy_decay_ms:5000`), and lower arena count + (e.g. number of CPUs). + +* Low resource consumption application: + + `narenas:1,lg_tcache_max:13` combined with shorter decay time (decreased + `dirty_decay_ms` and / or `muzzy_decay_ms`,e.g. + `dirty_decay_ms:1000,muzzy_decay_ms:0`). + +* Extremely conservative -- minimize memory usage at all costs, only suitable when +allocation activity is very rare: + + `narenas:1,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0` + +Note that it is recommended to combine the options with `abort_conf:true` which +aborts immediately on illegal options. + +## Beyond runtime options + +In addition to the runtime options, there are a number of programmatic ways to +improve application performance with jemalloc. + +* [Explicit arenas](http://jemalloc.net/jemalloc.3.html#arenas.create) + + Manually created arenas can help performance in various ways, e.g. by + managing locality and contention for specific usages. For example, + applications can explicitly allocate frequently accessed objects from a + dedicated arena with + [mallocx()](http://jemalloc.net/jemalloc.3.html#MALLOCX_ARENA) to improve + locality. In addition, explicit arenas often benefit from individually + tuned options, e.g. relaxed [decay + time](http://jemalloc.net/jemalloc.3.html#arena.i.dirty_decay_ms) if + frequent reuse is expected. + +* [Extent hooks](http://jemalloc.net/jemalloc.3.html#arena.i.extent_hooks) + + Extent hooks allow customization for managing underlying memory. One use + case for performance purpose is to utilize huge pages -- for example, + [HHVM](https://github.com/facebook/hhvm/blob/master/hphp/util/alloc.cpp) + uses explicit arenas with customized extent hooks to manage 1GB huge pages + for frequently accessed data, which reduces TLB misses significantly. + +* [Explicit thread-to-arena + binding](http://jemalloc.net/jemalloc.3.html#thread.arena) + + It is common for some threads in an application to have different memory + access / allocation patterns. Threads with heavy workloads often benefit + from explicit binding, e.g. binding very active threads to dedicated arenas + may reduce contention at the allocator level. diff --git a/jemalloc/autogen.sh b/jemalloc/autogen.sh new file mode 100755 index 0000000..75f32da --- /dev/null +++ b/jemalloc/autogen.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +for i in autoconf; do + echo "$i" + $i + if [ $? -ne 0 ]; then + echo "Error $? in $i" + exit 1 + fi +done + +echo "./configure --enable-autogen $@" +./configure --enable-autogen $@ +if [ $? -ne 0 ]; then + echo "Error $? in ./configure" + exit 1 +fi diff --git a/jemalloc/bin/jemalloc-config.in b/jemalloc/bin/jemalloc-config.in new file mode 100644 index 0000000..80eca2e --- /dev/null +++ b/jemalloc/bin/jemalloc-config.in @@ -0,0 +1,83 @@ +#!/bin/sh + +usage() { + cat < +Options: + --help | -h : Print usage. + --version : Print jemalloc version. + --revision : Print shared library revision number. + --config : Print configure options used to build jemalloc. + --prefix : Print installation directory prefix. + --bindir : Print binary installation directory. + --datadir : Print data installation directory. + --includedir : Print include installation directory. + --libdir : Print library installation directory. + --mandir : Print manual page installation directory. + --cc : Print compiler used to build jemalloc. + --cflags : Print compiler flags used to build jemalloc. + --cppflags : Print preprocessor flags used to build jemalloc. + --cxxflags : Print C++ compiler flags used to build jemalloc. + --ldflags : Print library flags used to build jemalloc. + --libs : Print libraries jemalloc was linked against. +EOF +} + +prefix="@prefix@" +exec_prefix="@exec_prefix@" + +case "$1" in +--help | -h) + usage + exit 0 + ;; +--version) + echo "@jemalloc_version@" + ;; +--revision) + echo "@rev@" + ;; +--config) + echo "@CONFIG@" + ;; +--prefix) + echo "@PREFIX@" + ;; +--bindir) + echo "@BINDIR@" + ;; +--datadir) + echo "@DATADIR@" + ;; +--includedir) + echo "@INCLUDEDIR@" + ;; +--libdir) + echo "@LIBDIR@" + ;; +--mandir) + echo "@MANDIR@" + ;; +--cc) + echo "@CC@" + ;; +--cflags) + echo "@CFLAGS@" + ;; +--cppflags) + echo "@CPPFLAGS@" + ;; +--cxxflags) + echo "@CXXFLAGS@" + ;; +--ldflags) + echo "@LDFLAGS@ @EXTRA_LDFLAGS@" + ;; +--libs) + echo "@LIBS@" + ;; +*) + usage + exit 1 +esac diff --git a/jemalloc/bin/jemalloc.sh.in b/jemalloc/bin/jemalloc.sh.in new file mode 100644 index 0000000..cdf3673 --- /dev/null +++ b/jemalloc/bin/jemalloc.sh.in @@ -0,0 +1,9 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ + +@LD_PRELOAD_VAR@=${libdir}/libjemalloc.@SOREV@ +export @LD_PRELOAD_VAR@ +exec "$@" diff --git a/jemalloc/bin/jeprof.in b/jemalloc/bin/jeprof.in new file mode 100644 index 0000000..3ed408c --- /dev/null +++ b/jemalloc/bin/jeprof.in @@ -0,0 +1,5625 @@ +#! /usr/bin/env perl + +# Copyright (c) 1998-2007, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# --- +# Program for printing the profile generated by common/profiler.cc, +# or by the heap profiler (common/debugallocation.cc) +# +# The profile contains a sequence of entries of the form: +# +# This program parses the profile, and generates user-readable +# output. +# +# Examples: +# +# % tools/jeprof "program" "profile" +# Enters "interactive" mode +# +# % tools/jeprof --text "program" "profile" +# Generates one line per procedure +# +# % tools/jeprof --gv "program" "profile" +# Generates annotated call-graph and displays via "gv" +# +# % tools/jeprof --gv --focus=Mutex "program" "profile" +# Restrict to code paths that involve an entry that matches "Mutex" +# +# % tools/jeprof --gv --focus=Mutex --ignore=string "program" "profile" +# Restrict to code paths that involve an entry that matches "Mutex" +# and does not match "string" +# +# % tools/jeprof --list=IBF_CheckDocid "program" "profile" +# Generates disassembly listing of all routines with at least one +# sample that match the --list= pattern. The listing is +# annotated with the flat and cumulative sample counts at each line. +# +# % tools/jeprof --disasm=IBF_CheckDocid "program" "profile" +# Generates disassembly listing of all routines with at least one +# sample that match the --disasm= pattern. The listing is +# annotated with the flat and cumulative sample counts at each PC value. +# +# TODO: Use color to indicate files? + +use strict; +use warnings; +use Getopt::Long; +use Cwd; + +my $JEPROF_VERSION = "@jemalloc_version@"; +my $PPROF_VERSION = "2.0"; + +# These are the object tools we use which can come from a +# user-specified location using --tools, from the JEPROF_TOOLS +# environment variable, or from the environment. +my %obj_tool_map = ( + "objdump" => "objdump", + "nm" => "nm", + "addr2line" => "addr2line", + "c++filt" => "c++filt", + ## ConfigureObjTools may add architecture-specific entries: + #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables + #"addr2line_pdb" => "addr2line-pdb", # ditto + #"otool" => "otool", # equivalent of objdump on OS X +); +# NOTE: these are lists, so you can put in commandline flags if you want. +my @DOT = ("dot"); # leave non-absolute, since it may be in /usr/local +my @GV = ("gv"); +my @EVINCE = ("evince"); # could also be xpdf or perhaps acroread +my @KCACHEGRIND = ("kcachegrind"); +my @PS2PDF = ("ps2pdf"); +# These are used for dynamic profiles +my @URL_FETCHER = ("curl", "-s", "--fail"); + +# These are the web pages that servers need to support for dynamic profiles +my $HEAP_PAGE = "/pprof/heap"; +my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#" +my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param + # ?seconds=#&event=x&period=n +my $GROWTH_PAGE = "/pprof/growth"; +my $CONTENTION_PAGE = "/pprof/contention"; +my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter +my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?"; +my $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param + # "?seconds=#", + # "?tags_regexp=#" and + # "?type=#". +my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST +my $PROGRAM_NAME_PAGE = "/pprof/cmdline"; + +# These are the web pages that can be named on the command line. +# All the alternatives must begin with /. +my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" . + "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" . + "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)"; + +# default binary name +my $UNKNOWN_BINARY = "(unknown)"; + +# There is a pervasive dependency on the length (in hex characters, +# i.e., nibbles) of an address, distinguishing between 32-bit and +# 64-bit profiles. To err on the safe size, default to 64-bit here: +my $address_length = 16; + +my $dev_null = "/dev/null"; +if (! -e $dev_null && $^O =~ /MSWin/) { # $^O is the OS perl was built for + $dev_null = "nul"; +} + +# A list of paths to search for shared object files +my @prefix_list = (); + +# Special routine name that should not have any symbols. +# Used as separator to parse "addr2line -i" output. +my $sep_symbol = '_fini'; +my $sep_address = undef; + +##### Argument parsing ##### + +sub usage_string { + return < + is a space separated list of profile names. +jeprof [options] + is a list of profile files where each file contains + the necessary symbol mappings as well as profile data (likely generated + with --raw). +jeprof [options] + is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE + + Each name can be: + /path/to/profile - a path to a profile file + host:port[/] - a location of a service to get profile from + + The / can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile, + $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall, + $CENSUSPROFILE_PAGE, or /pprof/filteredprofile. + For instance: + jeprof http://myserver.com:80$HEAP_PAGE + If / is omitted, the service defaults to $PROFILE_PAGE (cpu profiling). +jeprof --symbols + Maps addresses to symbol names. In this mode, stdin should be a + list of library mappings, in the same format as is found in the heap- + and cpu-profile files (this loosely matches that of /proc/self/maps + on linux), followed by a list of hex addresses to map, one per line. + + For more help with querying remote servers, including how to add the + necessary server-side support code, see this filename (or one like it): + + /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html + +Options: + --cum Sort by cumulative data + --base= Subtract from before display + --interactive Run in interactive mode (interactive "help" gives help) [default] + --seconds= Length of time for dynamic profiles [default=30 secs] + --add_lib= Read additional symbols and line info from the given library + --lib_prefix= Comma separated list of library path prefixes + +Reporting Granularity: + --addresses Report at address level + --lines Report at source line level + --functions Report at function level [default] + --files Report at source file level + +Output type: + --text Generate text report + --callgrind Generate callgrind format to stdout + --gv Generate Postscript and display + --evince Generate PDF and display + --web Generate SVG and display + --list= Generate source listing of matching routines + --disasm= Generate disassembly of matching routines + --symbols Print demangled symbol names found at given addresses + --dot Generate DOT file to stdout + --ps Generate Postcript to stdout + --pdf Generate PDF to stdout + --svg Generate SVG to stdout + --gif Generate GIF to stdout + --raw Generate symbolized jeprof data (useful with remote fetch) + +Heap-Profile Options: + --inuse_space Display in-use (mega)bytes [default] + --inuse_objects Display in-use objects + --alloc_space Display allocated (mega)bytes + --alloc_objects Display allocated objects + --show_bytes Display space in bytes + --drop_negative Ignore negative differences + +Contention-profile options: + --total_delay Display total delay at each region [default] + --contentions Display number of delays at each region + --mean_delay Display mean delay at each region + +Call-graph Options: + --nodecount= Show at most so many nodes [default=80] + --nodefraction= Hide nodes below *total [default=.005] + --edgefraction= Hide edges below *total [default=.001] + --maxdegree= Max incoming/outgoing edges per node [default=8] + --focus= Focus on backtraces with nodes matching + --thread= Show profile for thread + --ignore= Ignore backtraces with nodes matching + --scale= Set GV scaling [default=0] + --heapcheck Make nodes with non-0 object counts + (i.e. direct leak generators) more visible + --retain= Retain only nodes that match + --exclude= Exclude all nodes that match + +Miscellaneous: + --tools=[,...] \$PATH for object tool pathnames + --test Run unit tests + --help This message + --version Version information + +Environment Variables: + JEPROF_TMPDIR Profiles directory. Defaults to \$HOME/jeprof + JEPROF_TOOLS Prefix for object tools pathnames + +Examples: + +jeprof /bin/ls ls.prof + Enters "interactive" mode +jeprof --text /bin/ls ls.prof + Outputs one line per procedure +jeprof --web /bin/ls ls.prof + Displays annotated call-graph in web browser +jeprof --gv /bin/ls ls.prof + Displays annotated call-graph via 'gv' +jeprof --gv --focus=Mutex /bin/ls ls.prof + Restricts to code paths including a .*Mutex.* entry +jeprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof + Code paths including Mutex but not string +jeprof --list=getdir /bin/ls ls.prof + (Per-line) annotated source listing for getdir() +jeprof --disasm=getdir /bin/ls ls.prof + (Per-PC) annotated disassembly for getdir() + +jeprof http://localhost:1234/ + Enters "interactive" mode +jeprof --text localhost:1234 + Outputs one line per procedure for localhost:1234 +jeprof --raw localhost:1234 > ./local.raw +jeprof --text ./local.raw + Fetches a remote profile for later analysis and then + analyzes it in text mode. +EOF +} + +sub version_string { + return < \$main::opt_help, + "version!" => \$main::opt_version, + "cum!" => \$main::opt_cum, + "base=s" => \$main::opt_base, + "seconds=i" => \$main::opt_seconds, + "add_lib=s" => \$main::opt_lib, + "lib_prefix=s" => \$main::opt_lib_prefix, + "functions!" => \$main::opt_functions, + "lines!" => \$main::opt_lines, + "addresses!" => \$main::opt_addresses, + "files!" => \$main::opt_files, + "text!" => \$main::opt_text, + "callgrind!" => \$main::opt_callgrind, + "list=s" => \$main::opt_list, + "disasm=s" => \$main::opt_disasm, + "symbols!" => \$main::opt_symbols, + "gv!" => \$main::opt_gv, + "evince!" => \$main::opt_evince, + "web!" => \$main::opt_web, + "dot!" => \$main::opt_dot, + "ps!" => \$main::opt_ps, + "pdf!" => \$main::opt_pdf, + "svg!" => \$main::opt_svg, + "gif!" => \$main::opt_gif, + "raw!" => \$main::opt_raw, + "interactive!" => \$main::opt_interactive, + "nodecount=i" => \$main::opt_nodecount, + "nodefraction=f" => \$main::opt_nodefraction, + "edgefraction=f" => \$main::opt_edgefraction, + "maxdegree=i" => \$main::opt_maxdegree, + "focus=s" => \$main::opt_focus, + "thread=s" => \$main::opt_thread, + "ignore=s" => \$main::opt_ignore, + "scale=i" => \$main::opt_scale, + "heapcheck" => \$main::opt_heapcheck, + "retain=s" => \$main::opt_retain, + "exclude=s" => \$main::opt_exclude, + "inuse_space!" => \$main::opt_inuse_space, + "inuse_objects!" => \$main::opt_inuse_objects, + "alloc_space!" => \$main::opt_alloc_space, + "alloc_objects!" => \$main::opt_alloc_objects, + "show_bytes!" => \$main::opt_show_bytes, + "drop_negative!" => \$main::opt_drop_negative, + "total_delay!" => \$main::opt_total_delay, + "contentions!" => \$main::opt_contentions, + "mean_delay!" => \$main::opt_mean_delay, + "tools=s" => \$main::opt_tools, + "test!" => \$main::opt_test, + "debug!" => \$main::opt_debug, + # Undocumented flags used only by unittests: + "test_stride=i" => \$main::opt_test_stride, + ) || usage("Invalid option(s)"); + + # Deal with the standard --help and --version + if ($main::opt_help) { + print usage_string(); + exit(0); + } + + if ($main::opt_version) { + print version_string(); + exit(0); + } + + # Disassembly/listing/symbols mode requires address-level info + if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) { + $main::opt_functions = 0; + $main::opt_lines = 0; + $main::opt_addresses = 1; + $main::opt_files = 0; + } + + # Check heap-profiling flags + if ($main::opt_inuse_space + + $main::opt_inuse_objects + + $main::opt_alloc_space + + $main::opt_alloc_objects > 1) { + usage("Specify at most on of --inuse/--alloc options"); + } + + # Check output granularities + my $grains = + $main::opt_functions + + $main::opt_lines + + $main::opt_addresses + + $main::opt_files + + 0; + if ($grains > 1) { + usage("Only specify one output granularity option"); + } + if ($grains == 0) { + $main::opt_functions = 1; + } + + # Check output modes + my $modes = + $main::opt_text + + $main::opt_callgrind + + ($main::opt_list eq '' ? 0 : 1) + + ($main::opt_disasm eq '' ? 0 : 1) + + ($main::opt_symbols == 0 ? 0 : 1) + + $main::opt_gv + + $main::opt_evince + + $main::opt_web + + $main::opt_dot + + $main::opt_ps + + $main::opt_pdf + + $main::opt_svg + + $main::opt_gif + + $main::opt_raw + + $main::opt_interactive + + 0; + if ($modes > 1) { + usage("Only specify one output mode"); + } + if ($modes == 0) { + if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode + $main::opt_interactive = 1; + } else { + $main::opt_text = 1; + } + } + + if ($main::opt_test) { + RunUnitTests(); + # Should not return + exit(1); + } + + # Binary name and profile arguments list + $main::prog = ""; + @main::pfile_args = (); + + # Remote profiling without a binary (using $SYMBOL_PAGE instead) + if (@ARGV > 0) { + if (IsProfileURL($ARGV[0])) { + $main::use_symbol_page = 1; + } elsif (IsSymbolizedProfileFile($ARGV[0])) { + $main::use_symbolized_profile = 1; + $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file + } + } + + if ($main::use_symbol_page || $main::use_symbolized_profile) { + # We don't need a binary! + my %disabled = ('--lines' => $main::opt_lines, + '--disasm' => $main::opt_disasm); + for my $option (keys %disabled) { + usage("$option cannot be used without a binary") if $disabled{$option}; + } + # Set $main::prog later... + scalar(@ARGV) || usage("Did not specify profile file"); + } elsif ($main::opt_symbols) { + # --symbols needs a binary-name (to run nm on, etc) but not profiles + $main::prog = shift(@ARGV) || usage("Did not specify program"); + } else { + $main::prog = shift(@ARGV) || usage("Did not specify program"); + scalar(@ARGV) || usage("Did not specify profile file"); + } + + # Parse profile file/location arguments + foreach my $farg (@ARGV) { + if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) { + my $machine = $1; + my $num_machines = $2; + my $path = $3; + for (my $i = 0; $i < $num_machines; $i++) { + unshift(@main::pfile_args, "$i.$machine$path"); + } + } else { + unshift(@main::pfile_args, $farg); + } + } + + if ($main::use_symbol_page) { + unless (IsProfileURL($main::pfile_args[0])) { + error("The first profile should be a remote form to use $SYMBOL_PAGE\n"); + } + CheckSymbolPage(); + $main::prog = FetchProgramName(); + } elsif (!$main::use_symbolized_profile) { # may not need objtools! + ConfigureObjTools($main::prog) + } + + # Break the opt_lib_prefix into the prefix_list array + @prefix_list = split (',', $main::opt_lib_prefix); + + # Remove trailing / from the prefixes, in the list to prevent + # searching things like /my/path//lib/mylib.so + foreach (@prefix_list) { + s|/+$||; + } +} + +sub FilterAndPrint { + my ($profile, $symbols, $libs, $thread) = @_; + + # Get total data in profile + my $total = TotalProfile($profile); + + # Remove uniniteresting stack items + $profile = RemoveUninterestingFrames($symbols, $profile); + + # Focus? + if ($main::opt_focus ne '') { + $profile = FocusProfile($symbols, $profile, $main::opt_focus); + } + + # Ignore? + if ($main::opt_ignore ne '') { + $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore); + } + + my $calls = ExtractCalls($symbols, $profile); + + # Reduce profiles to required output granularity, and also clean + # each stack trace so a given entry exists at most once. + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + # Print + if (!$main::opt_interactive) { + if ($main::opt_disasm) { + PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm); + } elsif ($main::opt_list) { + PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0); + } elsif ($main::opt_text) { + # Make sure the output is empty when have nothing to report + # (only matters when --heapcheck is given but we must be + # compatible with old branches that did not pass --heapcheck always): + if ($total != 0) { + printf("Total%s: %s %s\n", + (defined($thread) ? " (t$thread)" : ""), + Unparse($total), Units()); + } + PrintText($symbols, $flat, $cumulative, -1); + } elsif ($main::opt_raw) { + PrintSymbolizedProfile($symbols, $profile, $main::prog); + } elsif ($main::opt_callgrind) { + PrintCallgrind($calls); + } else { + if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { + if ($main::opt_gv) { + RunGV(TempName($main::next_tmpfile, "ps"), ""); + } elsif ($main::opt_evince) { + RunEvince(TempName($main::next_tmpfile, "pdf"), ""); + } elsif ($main::opt_web) { + my $tmp = TempName($main::next_tmpfile, "svg"); + RunWeb($tmp); + # The command we run might hand the file name off + # to an already running browser instance and then exit. + # Normally, we'd remove $tmp on exit (right now), + # but fork a child to remove $tmp a little later, so that the + # browser has time to load it first. + delete $main::tempnames{$tmp}; + if (fork() == 0) { + sleep 5; + unlink($tmp); + exit(0); + } + } + } else { + cleanup(); + exit(1); + } + } + } else { + InteractiveMode($profile, $symbols, $libs, $total); + } +} + +sub Main() { + Init(); + $main::collected_profile = undef; + @main::profile_files = (); + $main::op_time = time(); + + # Printing symbols is special and requires a lot less info that most. + if ($main::opt_symbols) { + PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin + return; + } + + # Fetch all profile data + FetchDynamicProfiles(); + + # this will hold symbols that we read from the profile files + my $symbol_map = {}; + + # Read one profile, pick the last item on the list + my $data = ReadProfile($main::prog, pop(@main::profile_files)); + my $profile = $data->{profile}; + my $pcs = $data->{pcs}; + my $libs = $data->{libs}; # Info about main program and shared libraries + $symbol_map = MergeSymbols($symbol_map, $data->{symbols}); + + # Add additional profiles, if available. + if (scalar(@main::profile_files) > 0) { + foreach my $pname (@main::profile_files) { + my $data2 = ReadProfile($main::prog, $pname); + $profile = AddProfile($profile, $data2->{profile}); + $pcs = AddPcs($pcs, $data2->{pcs}); + $symbol_map = MergeSymbols($symbol_map, $data2->{symbols}); + } + } + + # Subtract base from profile, if specified + if ($main::opt_base ne '') { + my $base = ReadProfile($main::prog, $main::opt_base); + $profile = SubtractProfile($profile, $base->{profile}); + $pcs = AddPcs($pcs, $base->{pcs}); + $symbol_map = MergeSymbols($symbol_map, $base->{symbols}); + } + + # Collect symbols + my $symbols; + if ($main::use_symbolized_profile) { + $symbols = FetchSymbols($pcs, $symbol_map); + } elsif ($main::use_symbol_page) { + $symbols = FetchSymbols($pcs); + } else { + # TODO(csilvers): $libs uses the /proc/self/maps data from profile1, + # which may differ from the data from subsequent profiles, especially + # if they were run on different machines. Use appropriate libs for + # each pc somehow. + $symbols = ExtractSymbols($libs, $pcs); + } + + if (!defined($main::opt_thread)) { + FilterAndPrint($profile, $symbols, $libs); + } + if (defined($data->{threads})) { + foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) { + if (defined($main::opt_thread) && + ($main::opt_thread eq '*' || $main::opt_thread == $thread)) { + my $thread_profile = $data->{threads}{$thread}; + FilterAndPrint($thread_profile, $symbols, $libs, $thread); + } + } + } + + cleanup(); + exit(0); +} + +##### Entry Point ##### + +Main(); + +# Temporary code to detect if we're running on a Goobuntu system. +# These systems don't have the right stuff installed for the special +# Readline libraries to work, so as a temporary workaround, we default +# to using the normal stdio code, rather than the fancier readline-based +# code +sub ReadlineMightFail { + if (-e '/lib/libtermcap.so.2') { + return 0; # libtermcap exists, so readline should be okay + } else { + return 1; + } +} + +sub RunGV { + my $fname = shift; + my $bg = shift; # "" or " &" if we should run in background + if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) { + # Options using double dash are supported by this gv version. + # Also, turn on noantialias to better handle bug in gv for + # postscript files with large dimensions. + # TODO: Maybe we should not pass the --noantialias flag + # if the gv version is known to work properly without the flag. + system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname) + . $bg); + } else { + # Old gv version - only supports options that use single dash. + print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n"; + system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg); + } +} + +sub RunEvince { + my $fname = shift; + my $bg = shift; # "" or " &" if we should run in background + system(ShellEscape(@EVINCE, $fname) . $bg); +} + +sub RunWeb { + my $fname = shift; + print STDERR "Loading web page file:///$fname\n"; + + if (`uname` =~ /Darwin/) { + # OS X: open will use standard preference for SVG files. + system("/usr/bin/open", $fname); + return; + } + + # Some kind of Unix; try generic symlinks, then specific browsers. + # (Stop once we find one.) + # Works best if the browser is already running. + my @alt = ( + "/etc/alternatives/gnome-www-browser", + "/etc/alternatives/x-www-browser", + "google-chrome", + "firefox", + ); + foreach my $b (@alt) { + if (system($b, $fname) == 0) { + return; + } + } + + print STDERR "Could not load web browser.\n"; +} + +sub RunKcachegrind { + my $fname = shift; + my $bg = shift; # "" or " &" if we should run in background + print STDERR "Starting '@KCACHEGRIND " . $fname . $bg . "'\n"; + system(ShellEscape(@KCACHEGRIND, $fname) . $bg); +} + + +##### Interactive helper routines ##### + +sub InteractiveMode { + $| = 1; # Make output unbuffered for interactive mode + my ($orig_profile, $symbols, $libs, $total) = @_; + + print STDERR "Welcome to jeprof! For help, type 'help'.\n"; + + # Use ReadLine if it's installed and input comes from a console. + if ( -t STDIN && + !ReadlineMightFail() && + defined(eval {require Term::ReadLine}) ) { + my $term = new Term::ReadLine 'jeprof'; + while ( defined ($_ = $term->readline('(jeprof) '))) { + $term->addhistory($_) if /\S/; + if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { + last; # exit when we get an interactive command to quit + } + } + } else { # don't have readline + while (1) { + print STDERR "(jeprof) "; + $_ = ; + last if ! defined $_ ; + s/\r//g; # turn windows-looking lines into unix-looking lines + + # Save some flags that might be reset by InteractiveCommand() + my $save_opt_lines = $main::opt_lines; + + if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) { + last; # exit when we get an interactive command to quit + } + + # Restore flags + $main::opt_lines = $save_opt_lines; + } + } +} + +# Takes two args: orig profile, and command to run. +# Returns 1 if we should keep going, or 0 if we were asked to quit +sub InteractiveCommand { + my($orig_profile, $symbols, $libs, $total, $command) = @_; + $_ = $command; # just to make future m//'s easier + if (!defined($_)) { + print STDERR "\n"; + return 0; + } + if (m/^\s*quit/) { + return 0; + } + if (m/^\s*help/) { + InteractiveHelpMessage(); + return 1; + } + # Clear all the mode options -- mode is controlled by "$command" + $main::opt_text = 0; + $main::opt_callgrind = 0; + $main::opt_disasm = 0; + $main::opt_list = 0; + $main::opt_gv = 0; + $main::opt_evince = 0; + $main::opt_cum = 0; + + if (m/^\s*(text|top)(\d*)\s*(.*)/) { + $main::opt_text = 1; + + my $line_limit = ($2 ne "") ? int($2) : 10; + + my $routine; + my $ignore; + ($routine, $ignore) = ParseInteractiveArgs($3); + + my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + PrintText($symbols, $flat, $cumulative, $line_limit); + return 1; + } + if (m/^\s*callgrind\s*([^ \n]*)/) { + $main::opt_callgrind = 1; + + # Get derived profiles + my $calls = ExtractCalls($symbols, $orig_profile); + my $filename = $1; + if ( $1 eq '' ) { + $filename = TempName($main::next_tmpfile, "callgrind"); + } + PrintCallgrind($calls, $filename); + if ( $1 eq '' ) { + RunKcachegrind($filename, " & "); + $main::next_tmpfile++; + } + + return 1; + } + if (m/^\s*(web)?list\s*(.+)/) { + my $html = (defined($1) && ($1 eq "web")); + $main::opt_list = 1; + + my $routine; + my $ignore; + ($routine, $ignore) = ParseInteractiveArgs($2); + + my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + PrintListing($total, $libs, $flat, $cumulative, $routine, $html); + return 1; + } + if (m/^\s*disasm\s*(.+)/) { + $main::opt_disasm = 1; + + my $routine; + my $ignore; + ($routine, $ignore) = ParseInteractiveArgs($1); + + # Process current profile to account for various settings + my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore); + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + PrintDisassembly($libs, $flat, $cumulative, $routine); + return 1; + } + if (m/^\s*(gv|web|evince)\s*(.*)/) { + $main::opt_gv = 0; + $main::opt_evince = 0; + $main::opt_web = 0; + if ($1 eq "gv") { + $main::opt_gv = 1; + } elsif ($1 eq "evince") { + $main::opt_evince = 1; + } elsif ($1 eq "web") { + $main::opt_web = 1; + } + + my $focus; + my $ignore; + ($focus, $ignore) = ParseInteractiveArgs($2); + + # Process current profile to account for various settings + my $profile = ProcessProfile($total, $orig_profile, $symbols, + $focus, $ignore); + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { + if ($main::opt_gv) { + RunGV(TempName($main::next_tmpfile, "ps"), " &"); + } elsif ($main::opt_evince) { + RunEvince(TempName($main::next_tmpfile, "pdf"), " &"); + } elsif ($main::opt_web) { + RunWeb(TempName($main::next_tmpfile, "svg")); + } + $main::next_tmpfile++; + } + return 1; + } + if (m/^\s*$/) { + return 1; + } + print STDERR "Unknown command: try 'help'.\n"; + return 1; +} + + +sub ProcessProfile { + my $total_count = shift; + my $orig_profile = shift; + my $symbols = shift; + my $focus = shift; + my $ignore = shift; + + # Process current profile to account for various settings + my $profile = $orig_profile; + printf("Total: %s %s\n", Unparse($total_count), Units()); + if ($focus ne '') { + $profile = FocusProfile($symbols, $profile, $focus); + my $focus_count = TotalProfile($profile); + printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n", + $focus, + Unparse($focus_count), Units(), + Unparse($total_count), ($focus_count*100.0) / $total_count); + } + if ($ignore ne '') { + $profile = IgnoreProfile($symbols, $profile, $ignore); + my $ignore_count = TotalProfile($profile); + printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n", + $ignore, + Unparse($ignore_count), Units(), + Unparse($total_count), + ($ignore_count*100.0) / $total_count); + } + + return $profile; +} + +sub InteractiveHelpMessage { + print STDERR <{$k}; + my @addrs = split(/\n/, $k); + if ($#addrs >= 0) { + my $depth = $#addrs + 1; + # int(foo / 2**32) is the only reliable way to get rid of bottom + # 32 bits on both 32- and 64-bit systems. + print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32)); + print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32)); + + foreach my $full_addr (@addrs) { + my $addr = $full_addr; + $addr =~ s/0x0*//; # strip off leading 0x, zeroes + if (length($addr) > 16) { + print STDERR "Invalid address in profile: $full_addr\n"; + next; + } + my $low_addr = substr($addr, -8); # get last 8 hex chars + my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars + print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr)); + } + } + } +} + +# Print symbols and profile data +sub PrintSymbolizedProfile { + my $symbols = shift; + my $profile = shift; + my $prog = shift; + + $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $symbol_marker = $&; + + print '--- ', $symbol_marker, "\n"; + if (defined($prog)) { + print 'binary=', $prog, "\n"; + } + while (my ($pc, $name) = each(%{$symbols})) { + my $sep = ' '; + print '0x', $pc; + # We have a list of function names, which include the inlined + # calls. They are separated (and terminated) by --, which is + # illegal in function names. + for (my $j = 2; $j <= $#{$name}; $j += 3) { + print $sep, $name->[$j]; + $sep = '--'; + } + print "\n"; + } + print '---', "\n"; + + my $profile_marker; + if ($main::profile_type eq 'heap') { + $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash + $profile_marker = $&; + } elsif ($main::profile_type eq 'growth') { + $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash + $profile_marker = $&; + } elsif ($main::profile_type eq 'contention') { + $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash + $profile_marker = $&; + } else { # elsif ($main::profile_type eq 'cpu') + $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash + $profile_marker = $&; + } + + print '--- ', $profile_marker, "\n"; + if (defined($main::collected_profile)) { + # if used with remote fetch, simply dump the collected profile to output. + open(SRC, "<$main::collected_profile"); + while () { + print $_; + } + close(SRC); + } else { + # --raw/http: For everything to work correctly for non-remote profiles, we + # would need to extend PrintProfileData() to handle all possible profile + # types, re-enable the code that is currently disabled in ReadCPUProfile() + # and FixCallerAddresses(), and remove the remote profile dumping code in + # the block above. + die "--raw/http: jeprof can only dump remote profiles for --raw\n"; + # dump a cpu-format profile to standard out + PrintProfileData($profile); + } +} + +# Print text output +sub PrintText { + my $symbols = shift; + my $flat = shift; + my $cumulative = shift; + my $line_limit = shift; + + my $total = TotalProfile($flat); + + # Which profile to sort by? + my $s = $main::opt_cum ? $cumulative : $flat; + + my $running_sum = 0; + my $lines = 0; + foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b } + keys(%{$cumulative})) { + my $f = GetEntry($flat, $k); + my $c = GetEntry($cumulative, $k); + $running_sum += $f; + + my $sym = $k; + if (exists($symbols->{$k})) { + $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1]; + if ($main::opt_addresses) { + $sym = $k . " " . $sym; + } + } + + if ($f != 0 || $c != 0) { + printf("%8s %6s %6s %8s %6s %s\n", + Unparse($f), + Percent($f, $total), + Percent($running_sum, $total), + Unparse($c), + Percent($c, $total), + $sym); + } + $lines++; + last if ($line_limit >= 0 && $lines >= $line_limit); + } +} + +# Callgrind format has a compression for repeated function and file +# names. You show the name the first time, and just use its number +# subsequently. This can cut down the file to about a third or a +# quarter of its uncompressed size. $key and $val are the key/value +# pair that would normally be printed by callgrind; $map is a map from +# value to number. +sub CompressedCGName { + my($key, $val, $map) = @_; + my $idx = $map->{$val}; + # For very short keys, providing an index hurts rather than helps. + if (length($val) <= 3) { + return "$key=$val\n"; + } elsif (defined($idx)) { + return "$key=($idx)\n"; + } else { + # scalar(keys $map) gives the number of items in the map. + $idx = scalar(keys(%{$map})) + 1; + $map->{$val} = $idx; + return "$key=($idx) $val\n"; + } +} + +# Print the call graph in a way that's suiteable for callgrind. +sub PrintCallgrind { + my $calls = shift; + my $filename; + my %filename_to_index_map; + my %fnname_to_index_map; + + if ($main::opt_interactive) { + $filename = shift; + print STDERR "Writing callgrind file to '$filename'.\n" + } else { + $filename = "&STDOUT"; + } + open(CG, ">$filename"); + printf CG ("events: Hits\n\n"); + foreach my $call ( map { $_->[0] } + sort { $a->[1] cmp $b ->[1] || + $a->[2] <=> $b->[2] } + map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; + [$_, $1, $2] } + keys %$calls ) { + my $count = int($calls->{$call}); + $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/; + my ( $caller_file, $caller_line, $caller_function, + $callee_file, $callee_line, $callee_function ) = + ( $1, $2, $3, $5, $6, $7 ); + + # TODO(csilvers): for better compression, collect all the + # caller/callee_files and functions first, before printing + # anything, and only compress those referenced more than once. + printf CG CompressedCGName("fl", $caller_file, \%filename_to_index_map); + printf CG CompressedCGName("fn", $caller_function, \%fnname_to_index_map); + if (defined $6) { + printf CG CompressedCGName("cfl", $callee_file, \%filename_to_index_map); + printf CG CompressedCGName("cfn", $callee_function, \%fnname_to_index_map); + printf CG ("calls=$count $callee_line\n"); + } + printf CG ("$caller_line $count\n\n"); + } +} + +# Print disassembly for all all routines that match $main::opt_disasm +sub PrintDisassembly { + my $libs = shift; + my $flat = shift; + my $cumulative = shift; + my $disasm_opts = shift; + + my $total = TotalProfile($flat); + + foreach my $lib (@{$libs}) { + my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts); + my $offset = AddressSub($lib->[1], $lib->[3]); + foreach my $routine (sort ByName keys(%{$symbol_table})) { + my $start_addr = $symbol_table->{$routine}->[0]; + my $end_addr = $symbol_table->{$routine}->[1]; + # See if there are any samples in this routine + my $length = hex(AddressSub($end_addr, $start_addr)); + my $addr = AddressAdd($start_addr, $offset); + for (my $i = 0; $i < $length; $i++) { + if (defined($cumulative->{$addr})) { + PrintDisassembledFunction($lib->[0], $offset, + $routine, $flat, $cumulative, + $start_addr, $end_addr, $total); + last; + } + $addr = AddressInc($addr); + } + } + } +} + +# Return reference to array of tuples of the form: +# [start_address, filename, linenumber, instruction, limit_address] +# E.g., +# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"] +sub Disassemble { + my $prog = shift; + my $offset = shift; + my $start_addr = shift; + my $end_addr = shift; + + my $objdump = $obj_tool_map{"objdump"}; + my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn", + "--start-address=0x$start_addr", + "--stop-address=0x$end_addr", $prog); + open(OBJDUMP, "$cmd |") || error("$cmd: $!\n"); + my @result = (); + my $filename = ""; + my $linenumber = -1; + my $last = ["", "", "", ""]; + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + chop; + if (m|\s*([^:\s]+):(\d+)\s*$|) { + # Location line of the form: + # : + $filename = $1; + $linenumber = $2; + } elsif (m/^ +([0-9a-f]+):\s*(.*)/) { + # Disassembly line -- zero-extend address to full length + my $addr = HexExtend($1); + my $k = AddressAdd($addr, $offset); + $last->[4] = $k; # Store ending address for previous instruction + $last = [$k, $filename, $linenumber, $2, $end_addr]; + push(@result, $last); + } + } + close(OBJDUMP); + return @result; +} + +# The input file should contain lines of the form /proc/maps-like +# output (same format as expected from the profiles) or that looks +# like hex addresses (like "0xDEADBEEF"). We will parse all +# /proc/maps output, and for all the hex addresses, we will output +# "short" symbol names, one per line, in the same order as the input. +sub PrintSymbols { + my $maps_and_symbols_file = shift; + + # ParseLibraries expects pcs to be in a set. Fine by us... + my @pclist = (); # pcs in sorted order + my $pcs = {}; + my $map = ""; + foreach my $line (<$maps_and_symbols_file>) { + $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines + if ($line =~ /\b(0x[0-9a-f]+)\b/i) { + push(@pclist, HexExtend($1)); + $pcs->{$pclist[-1]} = 1; + } else { + $map .= $line; + } + } + + my $libs = ParseLibraries($main::prog, $map, $pcs); + my $symbols = ExtractSymbols($libs, $pcs); + + foreach my $pc (@pclist) { + # ->[0] is the shortname, ->[2] is the full name + print(($symbols->{$pc}->[0] || "??") . "\n"); + } +} + + +# For sorting functions by name +sub ByName { + return ShortFunctionName($a) cmp ShortFunctionName($b); +} + +# Print source-listing for all all routines that match $list_opts +sub PrintListing { + my $total = shift; + my $libs = shift; + my $flat = shift; + my $cumulative = shift; + my $list_opts = shift; + my $html = shift; + + my $output = \*STDOUT; + my $fname = ""; + + if ($html) { + # Arrange to write the output to a temporary file + $fname = TempName($main::next_tmpfile, "html"); + $main::next_tmpfile++; + if (!open(TEMP, ">$fname")) { + print STDERR "$fname: $!\n"; + return; + } + $output = \*TEMP; + print $output HtmlListingHeader(); + printf $output ("
%s
Total: %s %s
\n", + $main::prog, Unparse($total), Units()); + } + + my $listed = 0; + foreach my $lib (@{$libs}) { + my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts); + my $offset = AddressSub($lib->[1], $lib->[3]); + foreach my $routine (sort ByName keys(%{$symbol_table})) { + # Print if there are any samples in this routine + my $start_addr = $symbol_table->{$routine}->[0]; + my $end_addr = $symbol_table->{$routine}->[1]; + my $length = hex(AddressSub($end_addr, $start_addr)); + my $addr = AddressAdd($start_addr, $offset); + for (my $i = 0; $i < $length; $i++) { + if (defined($cumulative->{$addr})) { + $listed += PrintSource( + $lib->[0], $offset, + $routine, $flat, $cumulative, + $start_addr, $end_addr, + $html, + $output); + last; + } + $addr = AddressInc($addr); + } + } + } + + if ($html) { + if ($listed > 0) { + print $output HtmlListingFooter(); + close($output); + RunWeb($fname); + } else { + close($output); + unlink($fname); + } + } +} + +sub HtmlListingHeader { + return <<'EOF'; + + + +Pprof listing + + + + +EOF +} + +sub HtmlListingFooter { + return <<'EOF'; + + +EOF +} + +sub HtmlEscape { + my $text = shift; + $text =~ s/&/&/g; + $text =~ s//>/g; + return $text; +} + +# Returns the indentation of the line, if it has any non-whitespace +# characters. Otherwise, returns -1. +sub Indentation { + my $line = shift; + if (m/^(\s*)\S/) { + return length($1); + } else { + return -1; + } +} + +# If the symbol table contains inlining info, Disassemble() may tag an +# instruction with a location inside an inlined function. But for +# source listings, we prefer to use the location in the function we +# are listing. So use MapToSymbols() to fetch full location +# information for each instruction and then pick out the first +# location from a location list (location list contains callers before +# callees in case of inlining). +# +# After this routine has run, each entry in $instructions contains: +# [0] start address +# [1] filename for function we are listing +# [2] line number for function we are listing +# [3] disassembly +# [4] limit address +# [5] most specific filename (may be different from [1] due to inlining) +# [6] most specific line number (may be different from [2] due to inlining) +sub GetTopLevelLineNumbers { + my ($lib, $offset, $instructions) = @_; + my $pcs = []; + for (my $i = 0; $i <= $#{$instructions}; $i++) { + push(@{$pcs}, $instructions->[$i]->[0]); + } + my $symbols = {}; + MapToSymbols($lib, $offset, $pcs, $symbols); + for (my $i = 0; $i <= $#{$instructions}; $i++) { + my $e = $instructions->[$i]; + push(@{$e}, $e->[1]); + push(@{$e}, $e->[2]); + my $addr = $e->[0]; + my $sym = $symbols->{$addr}; + if (defined($sym)) { + if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) { + $e->[1] = $1; # File name + $e->[2] = $2; # Line number + } + } + } +} + +# Print source-listing for one routine +sub PrintSource { + my $prog = shift; + my $offset = shift; + my $routine = shift; + my $flat = shift; + my $cumulative = shift; + my $start_addr = shift; + my $end_addr = shift; + my $html = shift; + my $output = shift; + + # Disassemble all instructions (just to get line numbers) + my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); + GetTopLevelLineNumbers($prog, $offset, \@instructions); + + # Hack 1: assume that the first source file encountered in the + # disassembly contains the routine + my $filename = undef; + for (my $i = 0; $i <= $#instructions; $i++) { + if ($instructions[$i]->[2] >= 0) { + $filename = $instructions[$i]->[1]; + last; + } + } + if (!defined($filename)) { + print STDERR "no filename found in $routine\n"; + return 0; + } + + # Hack 2: assume that the largest line number from $filename is the + # end of the procedure. This is typically safe since if P1 contains + # an inlined call to P2, then P2 usually occurs earlier in the + # source file. If this does not work, we might have to compute a + # density profile or just print all regions we find. + my $lastline = 0; + for (my $i = 0; $i <= $#instructions; $i++) { + my $f = $instructions[$i]->[1]; + my $l = $instructions[$i]->[2]; + if (($f eq $filename) && ($l > $lastline)) { + $lastline = $l; + } + } + + # Hack 3: assume the first source location from "filename" is the start of + # the source code. + my $firstline = 1; + for (my $i = 0; $i <= $#instructions; $i++) { + if ($instructions[$i]->[1] eq $filename) { + $firstline = $instructions[$i]->[2]; + last; + } + } + + # Hack 4: Extend last line forward until its indentation is less than + # the indentation we saw on $firstline + my $oldlastline = $lastline; + { + if (!open(FILE, "<$filename")) { + print STDERR "$filename: $!\n"; + return 0; + } + my $l = 0; + my $first_indentation = -1; + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + $l++; + my $indent = Indentation($_); + if ($l >= $firstline) { + if ($first_indentation < 0 && $indent >= 0) { + $first_indentation = $indent; + last if ($first_indentation == 0); + } + } + if ($l >= $lastline && $indent >= 0) { + if ($indent >= $first_indentation) { + $lastline = $l+1; + } else { + last; + } + } + } + close(FILE); + } + + # Assign all samples to the range $firstline,$lastline, + # Hack 4: If an instruction does not occur in the range, its samples + # are moved to the next instruction that occurs in the range. + my $samples1 = {}; # Map from line number to flat count + my $samples2 = {}; # Map from line number to cumulative count + my $running1 = 0; # Unassigned flat counts + my $running2 = 0; # Unassigned cumulative counts + my $total1 = 0; # Total flat counts + my $total2 = 0; # Total cumulative counts + my %disasm = (); # Map from line number to disassembly + my $running_disasm = ""; # Unassigned disassembly + my $skip_marker = "---\n"; + if ($html) { + $skip_marker = ""; + for (my $l = $firstline; $l <= $lastline; $l++) { + $disasm{$l} = ""; + } + } + my $last_dis_filename = ''; + my $last_dis_linenum = -1; + my $last_touched_line = -1; # To detect gaps in disassembly for a line + foreach my $e (@instructions) { + # Add up counts for all address that fall inside this instruction + my $c1 = 0; + my $c2 = 0; + for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { + $c1 += GetEntry($flat, $a); + $c2 += GetEntry($cumulative, $a); + } + + if ($html) { + my $dis = sprintf(" %6s %6s \t\t%8s: %s ", + HtmlPrintNumber($c1), + HtmlPrintNumber($c2), + UnparseAddress($offset, $e->[0]), + CleanDisassembly($e->[3])); + + # Append the most specific source line associated with this instruction + if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) }; + $dis = HtmlEscape($dis); + my $f = $e->[5]; + my $l = $e->[6]; + if ($f ne $last_dis_filename) { + $dis .= sprintf("%s:%d", + HtmlEscape(CleanFileName($f)), $l); + } elsif ($l ne $last_dis_linenum) { + # De-emphasize the unchanged file name portion + $dis .= sprintf("%s" . + ":%d", + HtmlEscape(CleanFileName($f)), $l); + } else { + # De-emphasize the entire location + $dis .= sprintf("%s:%d", + HtmlEscape(CleanFileName($f)), $l); + } + $last_dis_filename = $f; + $last_dis_linenum = $l; + $running_disasm .= $dis; + $running_disasm .= "\n"; + } + + $running1 += $c1; + $running2 += $c2; + $total1 += $c1; + $total2 += $c2; + my $file = $e->[1]; + my $line = $e->[2]; + if (($file eq $filename) && + ($line >= $firstline) && + ($line <= $lastline)) { + # Assign all accumulated samples to this line + AddEntry($samples1, $line, $running1); + AddEntry($samples2, $line, $running2); + $running1 = 0; + $running2 = 0; + if ($html) { + if ($line != $last_touched_line && $disasm{$line} ne '') { + $disasm{$line} .= "\n"; + } + $disasm{$line} .= $running_disasm; + $running_disasm = ''; + $last_touched_line = $line; + } + } + } + + # Assign any leftover samples to $lastline + AddEntry($samples1, $lastline, $running1); + AddEntry($samples2, $lastline, $running2); + if ($html) { + if ($lastline != $last_touched_line && $disasm{$lastline} ne '') { + $disasm{$lastline} .= "\n"; + } + $disasm{$lastline} .= $running_disasm; + } + + if ($html) { + printf $output ( + "

%s

%s\n
\n" .
+      "Total:%6s %6s (flat / cumulative %s)\n",
+      HtmlEscape(ShortFunctionName($routine)),
+      HtmlEscape(CleanFileName($filename)),
+      Unparse($total1),
+      Unparse($total2),
+      Units());
+  } else {
+    printf $output (
+      "ROUTINE ====================== %s in %s\n" .
+      "%6s %6s Total %s (flat / cumulative)\n",
+      ShortFunctionName($routine),
+      CleanFileName($filename),
+      Unparse($total1),
+      Unparse($total2),
+      Units());
+  }
+  if (!open(FILE, "<$filename")) {
+    print STDERR "$filename: $!\n";
+    return 0;
+  }
+  my $l = 0;
+  while () {
+    s/\r//g;         # turn windows-looking lines into unix-looking lines
+    $l++;
+    if ($l >= $firstline - 5 &&
+        (($l <= $oldlastline + 5) || ($l <= $lastline))) {
+      chop;
+      my $text = $_;
+      if ($l == $firstline) { print $output $skip_marker; }
+      my $n1 = GetEntry($samples1, $l);
+      my $n2 = GetEntry($samples2, $l);
+      if ($html) {
+        # Emit a span that has one of the following classes:
+        #    livesrc -- has samples
+        #    deadsrc -- has disassembly, but with no samples
+        #    nop     -- has no matching disasembly
+        # Also emit an optional span containing disassembly.
+        my $dis = $disasm{$l};
+        my $asm = "";
+        if (defined($dis) && $dis ne '') {
+          $asm = "" . $dis . "";
+        }
+        my $source_class = (($n1 + $n2 > 0)
+                            ? "livesrc"
+                            : (($asm ne "") ? "deadsrc" : "nop"));
+        printf $output (
+          "%5d " .
+          "%6s %6s %s%s\n",
+          $l, $source_class,
+          HtmlPrintNumber($n1),
+          HtmlPrintNumber($n2),
+          HtmlEscape($text),
+          $asm);
+      } else {
+        printf $output(
+          "%6s %6s %4d: %s\n",
+          UnparseAlt($n1),
+          UnparseAlt($n2),
+          $l,
+          $text);
+      }
+      if ($l == $lastline)  { print $output $skip_marker; }
+    };
+  }
+  close(FILE);
+  if ($html) {
+    print $output "
\n"; + } + return 1; +} + +# Return the source line for the specified file/linenumber. +# Returns undef if not found. +sub SourceLine { + my $file = shift; + my $line = shift; + + # Look in cache + if (!defined($main::source_cache{$file})) { + if (100 < scalar keys(%main::source_cache)) { + # Clear the cache when it gets too big + $main::source_cache = (); + } + + # Read all lines from the file + if (!open(FILE, "<$file")) { + print STDERR "$file: $!\n"; + $main::source_cache{$file} = []; # Cache the negative result + return undef; + } + my $lines = []; + push(@{$lines}, ""); # So we can use 1-based line numbers as indices + while () { + push(@{$lines}, $_); + } + close(FILE); + + # Save the lines in the cache + $main::source_cache{$file} = $lines; + } + + my $lines = $main::source_cache{$file}; + if (($line < 0) || ($line > $#{$lines})) { + return undef; + } else { + return $lines->[$line]; + } +} + +# Print disassembly for one routine with interspersed source if available +sub PrintDisassembledFunction { + my $prog = shift; + my $offset = shift; + my $routine = shift; + my $flat = shift; + my $cumulative = shift; + my $start_addr = shift; + my $end_addr = shift; + my $total = shift; + + # Disassemble all instructions + my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); + + # Make array of counts per instruction + my @flat_count = (); + my @cum_count = (); + my $flat_total = 0; + my $cum_total = 0; + foreach my $e (@instructions) { + # Add up counts for all address that fall inside this instruction + my $c1 = 0; + my $c2 = 0; + for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { + $c1 += GetEntry($flat, $a); + $c2 += GetEntry($cumulative, $a); + } + push(@flat_count, $c1); + push(@cum_count, $c2); + $flat_total += $c1; + $cum_total += $c2; + } + + # Print header with total counts + printf("ROUTINE ====================== %s\n" . + "%6s %6s %s (flat, cumulative) %.1f%% of total\n", + ShortFunctionName($routine), + Unparse($flat_total), + Unparse($cum_total), + Units(), + ($cum_total * 100.0) / $total); + + # Process instructions in order + my $current_file = ""; + for (my $i = 0; $i <= $#instructions; ) { + my $e = $instructions[$i]; + + # Print the new file name whenever we switch files + if ($e->[1] ne $current_file) { + $current_file = $e->[1]; + my $fname = $current_file; + $fname =~ s|^\./||; # Trim leading "./" + + # Shorten long file names + if (length($fname) >= 58) { + $fname = "..." . substr($fname, -55); + } + printf("-------------------- %s\n", $fname); + } + + # TODO: Compute range of lines to print together to deal with + # small reorderings. + my $first_line = $e->[2]; + my $last_line = $first_line; + my %flat_sum = (); + my %cum_sum = (); + for (my $l = $first_line; $l <= $last_line; $l++) { + $flat_sum{$l} = 0; + $cum_sum{$l} = 0; + } + + # Find run of instructions for this range of source lines + my $first_inst = $i; + while (($i <= $#instructions) && + ($instructions[$i]->[2] >= $first_line) && + ($instructions[$i]->[2] <= $last_line)) { + $e = $instructions[$i]; + $flat_sum{$e->[2]} += $flat_count[$i]; + $cum_sum{$e->[2]} += $cum_count[$i]; + $i++; + } + my $last_inst = $i - 1; + + # Print source lines + for (my $l = $first_line; $l <= $last_line; $l++) { + my $line = SourceLine($current_file, $l); + if (!defined($line)) { + $line = "?\n"; + next; + } else { + $line =~ s/^\s+//; + } + printf("%6s %6s %5d: %s", + UnparseAlt($flat_sum{$l}), + UnparseAlt($cum_sum{$l}), + $l, + $line); + } + + # Print disassembly + for (my $x = $first_inst; $x <= $last_inst; $x++) { + my $e = $instructions[$x]; + printf("%6s %6s %8s: %6s\n", + UnparseAlt($flat_count[$x]), + UnparseAlt($cum_count[$x]), + UnparseAddress($offset, $e->[0]), + CleanDisassembly($e->[3])); + } + } +} + +# Print DOT graph +sub PrintDot { + my $prog = shift; + my $symbols = shift; + my $raw = shift; + my $flat = shift; + my $cumulative = shift; + my $overall_total = shift; + + # Get total + my $local_total = TotalProfile($flat); + my $nodelimit = int($main::opt_nodefraction * $local_total); + my $edgelimit = int($main::opt_edgefraction * $local_total); + my $nodecount = $main::opt_nodecount; + + # Find nodes to include + my @list = (sort { abs(GetEntry($cumulative, $b)) <=> + abs(GetEntry($cumulative, $a)) + || $a cmp $b } + keys(%{$cumulative})); + my $last = $nodecount - 1; + if ($last > $#list) { + $last = $#list; + } + while (($last >= 0) && + (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) { + $last--; + } + if ($last < 0) { + print STDERR "No nodes to print\n"; + return 0; + } + + if ($nodelimit > 0 || $edgelimit > 0) { + printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n", + Unparse($nodelimit), Units(), + Unparse($edgelimit), Units()); + } + + # Open DOT output file + my $output; + my $escaped_dot = ShellEscape(@DOT); + my $escaped_ps2pdf = ShellEscape(@PS2PDF); + if ($main::opt_gv) { + my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "ps")); + $output = "| $escaped_dot -Tps2 >$escaped_outfile"; + } elsif ($main::opt_evince) { + my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "pdf")); + $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile"; + } elsif ($main::opt_ps) { + $output = "| $escaped_dot -Tps2"; + } elsif ($main::opt_pdf) { + $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -"; + } elsif ($main::opt_web || $main::opt_svg) { + # We need to post-process the SVG, so write to a temporary file always. + my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "svg")); + $output = "| $escaped_dot -Tsvg >$escaped_outfile"; + } elsif ($main::opt_gif) { + $output = "| $escaped_dot -Tgif"; + } else { + $output = ">&STDOUT"; + } + open(DOT, $output) || error("$output: $!\n"); + + # Title + printf DOT ("digraph \"%s; %s %s\" {\n", + $prog, + Unparse($overall_total), + Units()); + if ($main::opt_pdf) { + # The output is more printable if we set the page size for dot. + printf DOT ("size=\"8,11\"\n"); + } + printf DOT ("node [width=0.375,height=0.25];\n"); + + # Print legend + printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," . + "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n", + $prog, + sprintf("Total %s: %s", Units(), Unparse($overall_total)), + sprintf("Focusing on: %s", Unparse($local_total)), + sprintf("Dropped nodes with <= %s abs(%s)", + Unparse($nodelimit), Units()), + sprintf("Dropped edges with <= %s %s", + Unparse($edgelimit), Units()) + ); + + # Print nodes + my %node = (); + my $nextnode = 1; + foreach my $a (@list[0..$last]) { + # Pick font size + my $f = GetEntry($flat, $a); + my $c = GetEntry($cumulative, $a); + + my $fs = 8; + if ($local_total > 0) { + $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total))); + } + + $node{$a} = $nextnode++; + my $sym = $a; + $sym =~ s/\s+/\\n/g; + $sym =~ s/::/\\n/g; + + # Extra cumulative info to print for non-leaves + my $extra = ""; + if ($f != $c) { + $extra = sprintf("\\rof %s (%s)", + Unparse($c), + Percent($c, $local_total)); + } + my $style = ""; + if ($main::opt_heapcheck) { + if ($f > 0) { + # make leak-causing nodes more visible (add a background) + $style = ",style=filled,fillcolor=gray" + } elsif ($f < 0) { + # make anti-leak-causing nodes (which almost never occur) + # stand out as well (triple border) + $style = ",peripheries=3" + } + } + + printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" . + "\",shape=box,fontsize=%.1f%s];\n", + $node{$a}, + $sym, + Unparse($f), + Percent($f, $local_total), + $extra, + $fs, + $style, + ); + } + + # Get edges and counts per edge + my %edge = (); + my $n; + my $fullname_to_shortname_map = {}; + FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map); + foreach my $k (keys(%{$raw})) { + # TODO: omit low %age edges + $n = $raw->{$k}; + my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k); + for (my $i = 1; $i <= $#translated; $i++) { + my $src = $translated[$i]; + my $dst = $translated[$i-1]; + #next if ($src eq $dst); # Avoid self-edges? + if (exists($node{$src}) && exists($node{$dst})) { + my $edge_label = "$src\001$dst"; + if (!exists($edge{$edge_label})) { + $edge{$edge_label} = 0; + } + $edge{$edge_label} += $n; + } + } + } + + # Print edges (process in order of decreasing counts) + my %indegree = (); # Number of incoming edges added per node so far + my %outdegree = (); # Number of outgoing edges added per node so far + foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) { + my @x = split(/\001/, $e); + $n = $edge{$e}; + + # Initialize degree of kept incoming and outgoing edges if necessary + my $src = $x[0]; + my $dst = $x[1]; + if (!exists($outdegree{$src})) { $outdegree{$src} = 0; } + if (!exists($indegree{$dst})) { $indegree{$dst} = 0; } + + my $keep; + if ($indegree{$dst} == 0) { + # Keep edge if needed for reachability + $keep = 1; + } elsif (abs($n) <= $edgelimit) { + # Drop if we are below --edgefraction + $keep = 0; + } elsif ($outdegree{$src} >= $main::opt_maxdegree || + $indegree{$dst} >= $main::opt_maxdegree) { + # Keep limited number of in/out edges per node + $keep = 0; + } else { + $keep = 1; + } + + if ($keep) { + $outdegree{$src}++; + $indegree{$dst}++; + + # Compute line width based on edge count + my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0); + if ($fraction > 1) { $fraction = 1; } + my $w = $fraction * 2; + if ($w < 1 && ($main::opt_web || $main::opt_svg)) { + # SVG output treats line widths < 1 poorly. + $w = 1; + } + + # Dot sometimes segfaults if given edge weights that are too large, so + # we cap the weights at a large value + my $edgeweight = abs($n) ** 0.7; + if ($edgeweight > 100000) { $edgeweight = 100000; } + $edgeweight = int($edgeweight); + + my $style = sprintf("setlinewidth(%f)", $w); + if ($x[1] =~ m/\(inline\)/) { + $style .= ",dashed"; + } + + # Use a slightly squashed function of the edge count as the weight + printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n", + $node{$x[0]}, + $node{$x[1]}, + Unparse($n), + $edgeweight, + $style); + } + } + + print DOT ("}\n"); + close(DOT); + + if ($main::opt_web || $main::opt_svg) { + # Rewrite SVG to be more usable inside web browser. + RewriteSvg(TempName($main::next_tmpfile, "svg")); + } + + return 1; +} + +sub RewriteSvg { + my $svgfile = shift; + + open(SVG, $svgfile) || die "open temp svg: $!"; + my @svg = ; + close(SVG); + unlink $svgfile; + my $svg = join('', @svg); + + # Dot's SVG output is + # + # + # + # ... + # + # + # + # Change it to + # + # + # $svg_javascript + # + # + # ... + # + # + # + + # Fix width, height; drop viewBox. + $svg =~ s/(?s) above first + my $svg_javascript = SvgJavascript(); + my $viewport = "\n"; + $svg =~ s/ above . + $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/; + $svg =~ s/$svgfile") || die "open $svgfile: $!"; + print SVG $svg; + close(SVG); + } +} + +sub SvgJavascript { + return <<'EOF'; + +EOF +} + +# Provides a map from fullname to shortname for cases where the +# shortname is ambiguous. The symlist has both the fullname and +# shortname for all symbols, which is usually fine, but sometimes -- +# such as overloaded functions -- two different fullnames can map to +# the same shortname. In that case, we use the address of the +# function to disambiguate the two. This function fills in a map that +# maps fullnames to modified shortnames in such cases. If a fullname +# is not present in the map, the 'normal' shortname provided by the +# symlist is the appropriate one to use. +sub FillFullnameToShortnameMap { + my $symbols = shift; + my $fullname_to_shortname_map = shift; + my $shortnames_seen_once = {}; + my $shortnames_seen_more_than_once = {}; + + foreach my $symlist (values(%{$symbols})) { + # TODO(csilvers): deal with inlined symbols too. + my $shortname = $symlist->[0]; + my $fullname = $symlist->[2]; + if ($fullname !~ /<[0-9a-fA-F]+>$/) { # fullname doesn't end in an address + next; # the only collisions we care about are when addresses differ + } + if (defined($shortnames_seen_once->{$shortname}) && + $shortnames_seen_once->{$shortname} ne $fullname) { + $shortnames_seen_more_than_once->{$shortname} = 1; + } else { + $shortnames_seen_once->{$shortname} = $fullname; + } + } + + foreach my $symlist (values(%{$symbols})) { + my $shortname = $symlist->[0]; + my $fullname = $symlist->[2]; + # TODO(csilvers): take in a list of addresses we care about, and only + # store in the map if $symlist->[1] is in that list. Saves space. + next if defined($fullname_to_shortname_map->{$fullname}); + if (defined($shortnames_seen_more_than_once->{$shortname})) { + if ($fullname =~ /<0*([^>]*)>$/) { # fullname has address at end of it + $fullname_to_shortname_map->{$fullname} = "$shortname\@$1"; + } + } + } +} + +# Return a small number that identifies the argument. +# Multiple calls with the same argument will return the same number. +# Calls with different arguments will return different numbers. +sub ShortIdFor { + my $key = shift; + my $id = $main::uniqueid{$key}; + if (!defined($id)) { + $id = keys(%main::uniqueid) + 1; + $main::uniqueid{$key} = $id; + } + return $id; +} + +# Translate a stack of addresses into a stack of symbols +sub TranslateStack { + my $symbols = shift; + my $fullname_to_shortname_map = shift; + my $k = shift; + + my @addrs = split(/\n/, $k); + my @result = (); + for (my $i = 0; $i <= $#addrs; $i++) { + my $a = $addrs[$i]; + + # Skip large addresses since they sometimes show up as fake entries on RH9 + if (length($a) > 8 && $a gt "7fffffffffffffff") { + next; + } + + if ($main::opt_disasm || $main::opt_list) { + # We want just the address for the key + push(@result, $a); + next; + } + + my $symlist = $symbols->{$a}; + if (!defined($symlist)) { + $symlist = [$a, "", $a]; + } + + # We can have a sequence of symbols for a particular entry + # (more than one symbol in the case of inlining). Callers + # come before callees in symlist, so walk backwards since + # the translated stack should contain callees before callers. + for (my $j = $#{$symlist}; $j >= 2; $j -= 3) { + my $func = $symlist->[$j-2]; + my $fileline = $symlist->[$j-1]; + my $fullfunc = $symlist->[$j]; + if (defined($fullname_to_shortname_map->{$fullfunc})) { + $func = $fullname_to_shortname_map->{$fullfunc}; + } + if ($j > 2) { + $func = "$func (inline)"; + } + + # Do not merge nodes corresponding to Callback::Run since that + # causes confusing cycles in dot display. Instead, we synthesize + # a unique name for this frame per caller. + if ($func =~ m/Callback.*::Run$/) { + my $caller = ($i > 0) ? $addrs[$i-1] : 0; + $func = "Run#" . ShortIdFor($caller); + } + + if ($main::opt_addresses) { + push(@result, "$a $func $fileline"); + } elsif ($main::opt_lines) { + if ($func eq '??' && $fileline eq '??:0') { + push(@result, "$a"); + } else { + push(@result, "$func $fileline"); + } + } elsif ($main::opt_functions) { + if ($func eq '??') { + push(@result, "$a"); + } else { + push(@result, $func); + } + } elsif ($main::opt_files) { + if ($fileline eq '??:0' || $fileline eq '') { + push(@result, "$a"); + } else { + my $f = $fileline; + $f =~ s/:\d+$//; + push(@result, $f); + } + } else { + push(@result, $a); + last; # Do not print inlined info + } + } + } + + # print join(",", @addrs), " => ", join(",", @result), "\n"; + return @result; +} + +# Generate percent string for a number and a total +sub Percent { + my $num = shift; + my $tot = shift; + if ($tot != 0) { + return sprintf("%.1f%%", $num * 100.0 / $tot); + } else { + return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf"); + } +} + +# Generate pretty-printed form of number +sub Unparse { + my $num = shift; + if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { + if ($main::opt_inuse_objects || $main::opt_alloc_objects) { + return sprintf("%d", $num); + } else { + if ($main::opt_show_bytes) { + return sprintf("%d", $num); + } else { + return sprintf("%.1f", $num / 1048576.0); + } + } + } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { + return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds + } else { + return sprintf("%d", $num); + } +} + +# Alternate pretty-printed form: 0 maps to "." +sub UnparseAlt { + my $num = shift; + if ($num == 0) { + return "."; + } else { + return Unparse($num); + } +} + +# Alternate pretty-printed form: 0 maps to "" +sub HtmlPrintNumber { + my $num = shift; + if ($num == 0) { + return ""; + } else { + return Unparse($num); + } +} + +# Return output units +sub Units { + if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { + if ($main::opt_inuse_objects || $main::opt_alloc_objects) { + return "objects"; + } else { + if ($main::opt_show_bytes) { + return "B"; + } else { + return "MB"; + } + } + } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) { + return "seconds"; + } else { + return "samples"; + } +} + +##### Profile manipulation code ##### + +# Generate flattened profile: +# If count is charged to stack [a,b,c,d], in generated profile, +# it will be charged to [a] +sub FlatProfile { + my $profile = shift; + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + if ($#addrs >= 0) { + AddEntry($result, $addrs[0], $count); + } + } + return $result; +} + +# Generate cumulative profile: +# If count is charged to stack [a,b,c,d], in generated profile, +# it will be charged to [a], [b], [c], [d] +sub CumulativeProfile { + my $profile = shift; + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + foreach my $a (@addrs) { + AddEntry($result, $a, $count); + } + } + return $result; +} + +# If the second-youngest PC on the stack is always the same, returns +# that pc. Otherwise, returns undef. +sub IsSecondPcAlwaysTheSame { + my $profile = shift; + + my $second_pc = undef; + foreach my $k (keys(%{$profile})) { + my @addrs = split(/\n/, $k); + if ($#addrs < 1) { + return undef; + } + if (not defined $second_pc) { + $second_pc = $addrs[1]; + } else { + if ($second_pc ne $addrs[1]) { + return undef; + } + } + } + return $second_pc; +} + +sub ExtractSymbolLocation { + my $symbols = shift; + my $address = shift; + # 'addr2line' outputs "??:0" for unknown locations; we do the + # same to be consistent. + my $location = "??:0:unknown"; + if (exists $symbols->{$address}) { + my $file = $symbols->{$address}->[1]; + if ($file eq "?") { + $file = "??:0" + } + $location = $file . ":" . $symbols->{$address}->[0]; + } + return $location; +} + +# Extracts a graph of calls. +sub ExtractCalls { + my $symbols = shift; + my $profile = shift; + + my $calls = {}; + while( my ($stack_trace, $count) = each %$profile ) { + my @address = split(/\n/, $stack_trace); + my $destination = ExtractSymbolLocation($symbols, $address[0]); + AddEntry($calls, $destination, $count); + for (my $i = 1; $i <= $#address; $i++) { + my $source = ExtractSymbolLocation($symbols, $address[$i]); + my $call = "$source -> $destination"; + AddEntry($calls, $call, $count); + $destination = $source; + } + } + + return $calls; +} + +sub FilterFrames { + my $symbols = shift; + my $profile = shift; + + if ($main::opt_retain eq '' && $main::opt_exclude eq '') { + return $profile; + } + + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + my @path = (); + foreach my $a (@addrs) { + my $sym; + if (exists($symbols->{$a})) { + $sym = $symbols->{$a}->[0]; + } else { + $sym = $a; + } + if ($main::opt_retain ne '' && $sym !~ m/$main::opt_retain/) { + next; + } + if ($main::opt_exclude ne '' && $sym =~ m/$main::opt_exclude/) { + next; + } + push(@path, $a); + } + if (scalar(@path) > 0) { + my $reduced_path = join("\n", @path); + AddEntry($result, $reduced_path, $count); + } + } + + return $result; +} + +sub RemoveUninterestingFrames { + my $symbols = shift; + my $profile = shift; + + # List of function names to skip + my %skip = (); + my $skip_regexp = 'NOMATCH'; + if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { + foreach my $name ('@JEMALLOC_PREFIX@calloc', + 'cfree', + '@JEMALLOC_PREFIX@malloc', + 'newImpl', + 'void* newImpl', + '@JEMALLOC_PREFIX@free', + '@JEMALLOC_PREFIX@memalign', + '@JEMALLOC_PREFIX@posix_memalign', + '@JEMALLOC_PREFIX@aligned_alloc', + 'pvalloc', + '@JEMALLOC_PREFIX@valloc', + '@JEMALLOC_PREFIX@realloc', + '@JEMALLOC_PREFIX@mallocx', + '@JEMALLOC_PREFIX@rallocx', + '@JEMALLOC_PREFIX@xallocx', + '@JEMALLOC_PREFIX@dallocx', + '@JEMALLOC_PREFIX@sdallocx', + '@JEMALLOC_PREFIX@sdallocx_noflags', + 'tc_calloc', + 'tc_cfree', + 'tc_malloc', + 'tc_free', + 'tc_memalign', + 'tc_posix_memalign', + 'tc_pvalloc', + 'tc_valloc', + 'tc_realloc', + 'tc_new', + 'tc_delete', + 'tc_newarray', + 'tc_deletearray', + 'tc_new_nothrow', + 'tc_newarray_nothrow', + 'do_malloc', + '::do_malloc', # new name -- got moved to an unnamed ns + '::do_malloc_or_cpp_alloc', + 'DoSampledAllocation', + 'simple_alloc::allocate', + '__malloc_alloc_template::allocate', + '__builtin_delete', + '__builtin_new', + '__builtin_vec_delete', + '__builtin_vec_new', + 'operator new', + 'operator new[]', + # The entry to our memory-allocation routines on OS X + 'malloc_zone_malloc', + 'malloc_zone_calloc', + 'malloc_zone_valloc', + 'malloc_zone_realloc', + 'malloc_zone_memalign', + 'malloc_zone_free', + # These mark the beginning/end of our custom sections + '__start_google_malloc', + '__stop_google_malloc', + '__start_malloc_hook', + '__stop_malloc_hook') { + $skip{$name} = 1; + $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything + } + # TODO: Remove TCMalloc once everything has been + # moved into the tcmalloc:: namespace and we have flushed + # old code out of the system. + $skip_regexp = "TCMalloc|^tcmalloc::"; + } elsif ($main::profile_type eq 'contention') { + foreach my $vname ('base::RecordLockProfileData', + 'base::SubmitMutexProfileData', + 'base::SubmitSpinLockProfileData', + 'Mutex::Unlock', + 'Mutex::UnlockSlow', + 'Mutex::ReaderUnlock', + 'MutexLock::~MutexLock', + 'SpinLock::Unlock', + 'SpinLock::SlowUnlock', + 'SpinLockHolder::~SpinLockHolder') { + $skip{$vname} = 1; + } + } elsif ($main::profile_type eq 'cpu') { + # Drop signal handlers used for CPU profile collection + # TODO(dpeng): this should not be necessary; it's taken + # care of by the general 2nd-pc mechanism below. + foreach my $name ('ProfileData::Add', # historical + 'ProfileData::prof_handler', # historical + 'CpuProfiler::prof_handler', + '__FRAME_END__', + '__pthread_sighandler', + '__restore') { + $skip{$name} = 1; + } + } else { + # Nothing skipped for unknown types + } + + if ($main::profile_type eq 'cpu') { + # If all the second-youngest program counters are the same, + # this STRONGLY suggests that it is an artifact of measurement, + # i.e., stack frames pushed by the CPU profiler signal handler. + # Hence, we delete them. + # (The topmost PC is read from the signal structure, not from + # the stack, so it does not get involved.) + while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) { + my $result = {}; + my $func = ''; + if (exists($symbols->{$second_pc})) { + $second_pc = $symbols->{$second_pc}->[0]; + } + print STDERR "Removing $second_pc from all stack traces.\n"; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + splice @addrs, 1, 1; + my $reduced_path = join("\n", @addrs); + AddEntry($result, $reduced_path, $count); + } + $profile = $result; + } + } + + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + my @path = (); + foreach my $a (@addrs) { + if (exists($symbols->{$a})) { + my $func = $symbols->{$a}->[0]; + if ($skip{$func} || ($func =~ m/$skip_regexp/)) { + # Throw away the portion of the backtrace seen so far, under the + # assumption that previous frames were for functions internal to the + # allocator. + @path = (); + next; + } + } + push(@path, $a); + } + my $reduced_path = join("\n", @path); + AddEntry($result, $reduced_path, $count); + } + + $result = FilterFrames($symbols, $result); + + return $result; +} + +# Reduce profile to granularity given by user +sub ReduceProfile { + my $symbols = shift; + my $profile = shift; + my $result = {}; + my $fullname_to_shortname_map = {}; + FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map); + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k); + my @path = (); + my %seen = (); + $seen{''} = 1; # So that empty keys are skipped + foreach my $e (@translated) { + # To avoid double-counting due to recursion, skip a stack-trace + # entry if it has already been seen + if (!$seen{$e}) { + $seen{$e} = 1; + push(@path, $e); + } + } + my $reduced_path = join("\n", @path); + AddEntry($result, $reduced_path, $count); + } + return $result; +} + +# Does the specified symbol array match the regexp? +sub SymbolMatches { + my $sym = shift; + my $re = shift; + if (defined($sym)) { + for (my $i = 0; $i < $#{$sym}; $i += 3) { + if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) { + return 1; + } + } + } + return 0; +} + +# Focus only on paths involving specified regexps +sub FocusProfile { + my $symbols = shift; + my $profile = shift; + my $focus = shift; + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + foreach my $a (@addrs) { + # Reply if it matches either the address/shortname/fileline + if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) { + AddEntry($result, $k, $count); + last; + } + } + } + return $result; +} + +# Focus only on paths not involving specified regexps +sub IgnoreProfile { + my $symbols = shift; + my $profile = shift; + my $ignore = shift; + my $result = {}; + foreach my $k (keys(%{$profile})) { + my $count = $profile->{$k}; + my @addrs = split(/\n/, $k); + my $matched = 0; + foreach my $a (@addrs) { + # Reply if it matches either the address/shortname/fileline + if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) { + $matched = 1; + last; + } + } + if (!$matched) { + AddEntry($result, $k, $count); + } + } + return $result; +} + +# Get total count in profile +sub TotalProfile { + my $profile = shift; + my $result = 0; + foreach my $k (keys(%{$profile})) { + $result += $profile->{$k}; + } + return $result; +} + +# Add A to B +sub AddProfile { + my $A = shift; + my $B = shift; + + my $R = {}; + # add all keys in A + foreach my $k (keys(%{$A})) { + my $v = $A->{$k}; + AddEntry($R, $k, $v); + } + # add all keys in B + foreach my $k (keys(%{$B})) { + my $v = $B->{$k}; + AddEntry($R, $k, $v); + } + return $R; +} + +# Merges symbol maps +sub MergeSymbols { + my $A = shift; + my $B = shift; + + my $R = {}; + foreach my $k (keys(%{$A})) { + $R->{$k} = $A->{$k}; + } + if (defined($B)) { + foreach my $k (keys(%{$B})) { + $R->{$k} = $B->{$k}; + } + } + return $R; +} + + +# Add A to B +sub AddPcs { + my $A = shift; + my $B = shift; + + my $R = {}; + # add all keys in A + foreach my $k (keys(%{$A})) { + $R->{$k} = 1 + } + # add all keys in B + foreach my $k (keys(%{$B})) { + $R->{$k} = 1 + } + return $R; +} + +# Subtract B from A +sub SubtractProfile { + my $A = shift; + my $B = shift; + + my $R = {}; + foreach my $k (keys(%{$A})) { + my $v = $A->{$k} - GetEntry($B, $k); + if ($v < 0 && $main::opt_drop_negative) { + $v = 0; + } + AddEntry($R, $k, $v); + } + if (!$main::opt_drop_negative) { + # Take care of when subtracted profile has more entries + foreach my $k (keys(%{$B})) { + if (!exists($A->{$k})) { + AddEntry($R, $k, 0 - $B->{$k}); + } + } + } + return $R; +} + +# Get entry from profile; zero if not present +sub GetEntry { + my $profile = shift; + my $k = shift; + if (exists($profile->{$k})) { + return $profile->{$k}; + } else { + return 0; + } +} + +# Add entry to specified profile +sub AddEntry { + my $profile = shift; + my $k = shift; + my $n = shift; + if (!exists($profile->{$k})) { + $profile->{$k} = 0; + } + $profile->{$k} += $n; +} + +# Add a stack of entries to specified profile, and add them to the $pcs +# list. +sub AddEntries { + my $profile = shift; + my $pcs = shift; + my $stack = shift; + my $count = shift; + my @k = (); + + foreach my $e (split(/\s+/, $stack)) { + my $pc = HexExtend($e); + $pcs->{$pc} = 1; + push @k, $pc; + } + AddEntry($profile, (join "\n", @k), $count); +} + +##### Code to profile a server dynamically ##### + +sub CheckSymbolPage { + my $url = SymbolPageURL(); + my $command = ShellEscape(@URL_FETCHER, $url); + open(SYMBOL, "$command |") or error($command); + my $line = ; + $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines + close(SYMBOL); + unless (defined($line)) { + error("$url doesn't exist\n"); + } + + if ($line =~ /^num_symbols:\s+(\d+)$/) { + if ($1 == 0) { + error("Stripped binary. No symbols available.\n"); + } + } else { + error("Failed to get the number of symbols from $url\n"); + } +} + +sub IsProfileURL { + my $profile_name = shift; + if (-f $profile_name) { + printf STDERR "Using local file $profile_name.\n"; + return 0; + } + return 1; +} + +sub ParseProfileURL { + my $profile_name = shift; + + if (!defined($profile_name) || $profile_name eq "") { + return (); + } + + # Split profile URL - matches all non-empty strings, so no test. + $profile_name =~ m,^(https?://)?([^/]+)(.*?)(/|$PROFILES)?$,; + + my $proto = $1 || "http://"; + my $hostport = $2; + my $prefix = $3; + my $profile = $4 || "/"; + + my $host = $hostport; + $host =~ s/:.*//; + + my $baseurl = "$proto$hostport$prefix"; + return ($host, $baseurl, $profile); +} + +# We fetch symbols from the first profile argument. +sub SymbolPageURL { + my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); + return "$baseURL$SYMBOL_PAGE"; +} + +sub FetchProgramName() { + my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]); + my $url = "$baseURL$PROGRAM_NAME_PAGE"; + my $command_line = ShellEscape(@URL_FETCHER, $url); + open(CMDLINE, "$command_line |") or error($command_line); + my $cmdline = ; + $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines + close(CMDLINE); + error("Failed to get program name from $url\n") unless defined($cmdline); + $cmdline =~ s/\x00.+//; # Remove argv[1] and latters. + $cmdline =~ s!\n!!g; # Remove LFs. + return $cmdline; +} + +# Gee, curl's -L (--location) option isn't reliable at least +# with its 7.12.3 version. Curl will forget to post data if +# there is a redirection. This function is a workaround for +# curl. Redirection happens on borg hosts. +sub ResolveRedirectionForCurl { + my $url = shift; + my $command_line = ShellEscape(@URL_FETCHER, "--head", $url); + open(CMDLINE, "$command_line |") or error($command_line); + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + if (/^Location: (.*)/) { + $url = $1; + } + } + close(CMDLINE); + return $url; +} + +# Add a timeout flat to URL_FETCHER. Returns a new list. +sub AddFetchTimeout { + my $timeout = shift; + my @fetcher = @_; + if (defined($timeout)) { + if (join(" ", @fetcher) =~ m/\bcurl -s/) { + push(@fetcher, "--max-time", sprintf("%d", $timeout)); + } elsif (join(" ", @fetcher) =~ m/\brpcget\b/) { + push(@fetcher, sprintf("--deadline=%d", $timeout)); + } + } + return @fetcher; +} + +# Reads a symbol map from the file handle name given as $1, returning +# the resulting symbol map. Also processes variables relating to symbols. +# Currently, the only variable processed is 'binary=' which updates +# $main::prog to have the correct program name. +sub ReadSymbols { + my $in = shift; + my $map = {}; + while (<$in>) { + s/\r//g; # turn windows-looking lines into unix-looking lines + # Removes all the leading zeroes from the symbols, see comment below. + if (m/^0x0*([0-9a-f]+)\s+(.+)/) { + $map->{$1} = $2; + } elsif (m/^---/) { + last; + } elsif (m/^([a-z][^=]*)=(.*)$/ ) { + my ($variable, $value) = ($1, $2); + for ($variable, $value) { + s/^\s+//; + s/\s+$//; + } + if ($variable eq "binary") { + if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) { + printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n", + $main::prog, $value); + } + $main::prog = $value; + } else { + printf STDERR ("Ignoring unknown variable in symbols list: " . + "'%s' = '%s'\n", $variable, $value); + } + } + } + return $map; +} + +sub URLEncode { + my $str = shift; + $str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg; + return $str; +} + +sub AppendSymbolFilterParams { + my $url = shift; + my @params = (); + if ($main::opt_retain ne '') { + push(@params, sprintf("retain=%s", URLEncode($main::opt_retain))); + } + if ($main::opt_exclude ne '') { + push(@params, sprintf("exclude=%s", URLEncode($main::opt_exclude))); + } + if (scalar @params > 0) { + $url = sprintf("%s?%s", $url, join("&", @params)); + } + return $url; +} + +# Fetches and processes symbols to prepare them for use in the profile output +# code. If the optional 'symbol_map' arg is not given, fetches symbols from +# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols +# are assumed to have already been fetched into 'symbol_map' and are simply +# extracted and processed. +sub FetchSymbols { + my $pcset = shift; + my $symbol_map = shift; + + my %seen = (); + my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq + + if (!defined($symbol_map)) { + my $post_data = join("+", sort((map {"0x" . "$_"} @pcs))); + + open(POSTFILE, ">$main::tmpfile_sym"); + print POSTFILE $post_data; + close(POSTFILE); + + my $url = SymbolPageURL(); + + my $command_line; + if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) { + $url = ResolveRedirectionForCurl($url); + $url = AppendSymbolFilterParams($url); + $command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym", + $url); + } else { + $url = AppendSymbolFilterParams($url); + $command_line = (ShellEscape(@URL_FETCHER, "--post", $url) + . " < " . ShellEscape($main::tmpfile_sym)); + } + # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols. + my $escaped_cppfilt = ShellEscape($obj_tool_map{"c++filt"}); + open(SYMBOL, "$command_line | $escaped_cppfilt |") or error($command_line); + $symbol_map = ReadSymbols(*SYMBOL{IO}); + close(SYMBOL); + } + + my $symbols = {}; + foreach my $pc (@pcs) { + my $fullname; + # For 64 bits binaries, symbols are extracted with 8 leading zeroes. + # Then /symbol reads the long symbols in as uint64, and outputs + # the result with a "0x%08llx" format which get rid of the zeroes. + # By removing all the leading zeroes in both $pc and the symbols from + # /symbol, the symbols match and are retrievable from the map. + my $shortpc = $pc; + $shortpc =~ s/^0*//; + # Each line may have a list of names, which includes the function + # and also other functions it has inlined. They are separated (in + # PrintSymbolizedProfile), by --, which is illegal in function names. + my $fullnames; + if (defined($symbol_map->{$shortpc})) { + $fullnames = $symbol_map->{$shortpc}; + } else { + $fullnames = "0x" . $pc; # Just use addresses + } + my $sym = []; + $symbols->{$pc} = $sym; + foreach my $fullname (split("--", $fullnames)) { + my $name = ShortFunctionName($fullname); + push(@{$sym}, $name, "?", $fullname); + } + } + return $symbols; +} + +sub BaseName { + my $file_name = shift; + $file_name =~ s!^.*/!!; # Remove directory name + return $file_name; +} + +sub MakeProfileBaseName { + my ($binary_name, $profile_name) = @_; + my ($host, $baseURL, $path) = ParseProfileURL($profile_name); + my $binary_shortname = BaseName($binary_name); + return sprintf("%s.%s.%s", + $binary_shortname, $main::op_time, $host); +} + +sub FetchDynamicProfile { + my $binary_name = shift; + my $profile_name = shift; + my $fetch_name_only = shift; + my $encourage_patience = shift; + + if (!IsProfileURL($profile_name)) { + return $profile_name; + } else { + my ($host, $baseURL, $path) = ParseProfileURL($profile_name); + if ($path eq "" || $path eq "/") { + # Missing type specifier defaults to cpu-profile + $path = $PROFILE_PAGE; + } + + my $profile_file = MakeProfileBaseName($binary_name, $profile_name); + + my $url = "$baseURL$path"; + my $fetch_timeout = undef; + if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/) { + if ($path =~ m/[?]/) { + $url .= "&"; + } else { + $url .= "?"; + } + $url .= sprintf("seconds=%d", $main::opt_seconds); + $fetch_timeout = $main::opt_seconds * 1.01 + 60; + # Set $profile_type for consumption by PrintSymbolizedProfile. + $main::profile_type = 'cpu'; + } else { + # For non-CPU profiles, we add a type-extension to + # the target profile file name. + my $suffix = $path; + $suffix =~ s,/,.,g; + $profile_file .= $suffix; + # Set $profile_type for consumption by PrintSymbolizedProfile. + if ($path =~ m/$HEAP_PAGE/) { + $main::profile_type = 'heap'; + } elsif ($path =~ m/$GROWTH_PAGE/) { + $main::profile_type = 'growth'; + } elsif ($path =~ m/$CONTENTION_PAGE/) { + $main::profile_type = 'contention'; + } + } + + my $profile_dir = $ENV{"JEPROF_TMPDIR"} || ($ENV{HOME} . "/jeprof"); + if (! -d $profile_dir) { + mkdir($profile_dir) + || die("Unable to create profile directory $profile_dir: $!\n"); + } + my $tmp_profile = "$profile_dir/.tmp.$profile_file"; + my $real_profile = "$profile_dir/$profile_file"; + + if ($fetch_name_only > 0) { + return $real_profile; + } + + my @fetcher = AddFetchTimeout($fetch_timeout, @URL_FETCHER); + my $cmd = ShellEscape(@fetcher, $url) . " > " . ShellEscape($tmp_profile); + if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){ + print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n"; + if ($encourage_patience) { + print STDERR "Be patient...\n"; + } + } else { + print STDERR "Fetching $path profile from $url to\n ${real_profile}\n"; + } + + (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n"); + (system("mv", $tmp_profile, $real_profile) == 0) || error("Unable to rename profile\n"); + print STDERR "Wrote profile to $real_profile\n"; + $main::collected_profile = $real_profile; + return $main::collected_profile; + } +} + +# Collect profiles in parallel +sub FetchDynamicProfiles { + my $items = scalar(@main::pfile_args); + my $levels = log($items) / log(2); + + if ($items == 1) { + $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1); + } else { + # math rounding issues + if ((2 ** $levels) < $items) { + $levels++; + } + my $count = scalar(@main::pfile_args); + for (my $i = 0; $i < $count; $i++) { + $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0); + } + print STDERR "Fetching $count profiles, Be patient...\n"; + FetchDynamicProfilesRecurse($levels, 0, 0); + $main::collected_profile = join(" \\\n ", @main::profile_files); + } +} + +# Recursively fork a process to get enough processes +# collecting profiles +sub FetchDynamicProfilesRecurse { + my $maxlevel = shift; + my $level = shift; + my $position = shift; + + if (my $pid = fork()) { + $position = 0 | ($position << 1); + TryCollectProfile($maxlevel, $level, $position); + wait; + } else { + $position = 1 | ($position << 1); + TryCollectProfile($maxlevel, $level, $position); + cleanup(); + exit(0); + } +} + +# Collect a single profile +sub TryCollectProfile { + my $maxlevel = shift; + my $level = shift; + my $position = shift; + + if ($level >= ($maxlevel - 1)) { + if ($position < scalar(@main::pfile_args)) { + FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0); + } + } else { + FetchDynamicProfilesRecurse($maxlevel, $level+1, $position); + } +} + +##### Parsing code ##### + +# Provide a small streaming-read module to handle very large +# cpu-profile files. Stream in chunks along a sliding window. +# Provides an interface to get one 'slot', correctly handling +# endian-ness differences. A slot is one 32-bit or 64-bit word +# (depending on the input profile). We tell endianness and bit-size +# for the profile by looking at the first 8 bytes: in cpu profiles, +# the second slot is always 3 (we'll accept anything that's not 0). +BEGIN { + package CpuProfileStream; + + sub new { + my ($class, $file, $fname) = @_; + my $self = { file => $file, + base => 0, + stride => 512 * 1024, # must be a multiple of bitsize/8 + slots => [], + unpack_code => "", # N for big-endian, V for little + perl_is_64bit => 1, # matters if profile is 64-bit + }; + bless $self, $class; + # Let unittests adjust the stride + if ($main::opt_test_stride > 0) { + $self->{stride} = $main::opt_test_stride; + } + # Read the first two slots to figure out bitsize and endianness. + my $slots = $self->{slots}; + my $str; + read($self->{file}, $str, 8); + # Set the global $address_length based on what we see here. + # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars). + $address_length = ($str eq (chr(0)x8)) ? 16 : 8; + if ($address_length == 8) { + if (substr($str, 6, 2) eq chr(0)x2) { + $self->{unpack_code} = 'V'; # Little-endian. + } elsif (substr($str, 4, 2) eq chr(0)x2) { + $self->{unpack_code} = 'N'; # Big-endian + } else { + ::error("$fname: header size >= 2**16\n"); + } + @$slots = unpack($self->{unpack_code} . "*", $str); + } else { + # If we're a 64-bit profile, check if we're a 64-bit-capable + # perl. Otherwise, each slot will be represented as a float + # instead of an int64, losing precision and making all the + # 64-bit addresses wrong. We won't complain yet, but will + # later if we ever see a value that doesn't fit in 32 bits. + my $has_q = 0; + eval { $has_q = pack("Q", "1") ? 1 : 1; }; + if (!$has_q) { + $self->{perl_is_64bit} = 0; + } + read($self->{file}, $str, 8); + if (substr($str, 4, 4) eq chr(0)x4) { + # We'd love to use 'Q', but it's a) not universal, b) not endian-proof. + $self->{unpack_code} = 'V'; # Little-endian. + } elsif (substr($str, 0, 4) eq chr(0)x4) { + $self->{unpack_code} = 'N'; # Big-endian + } else { + ::error("$fname: header size >= 2**32\n"); + } + my @pair = unpack($self->{unpack_code} . "*", $str); + # Since we know one of the pair is 0, it's fine to just add them. + @$slots = (0, $pair[0] + $pair[1]); + } + return $self; + } + + # Load more data when we access slots->get(X) which is not yet in memory. + sub overflow { + my ($self) = @_; + my $slots = $self->{slots}; + $self->{base} += $#$slots + 1; # skip over data we're replacing + my $str; + read($self->{file}, $str, $self->{stride}); + if ($address_length == 8) { # the 32-bit case + # This is the easy case: unpack provides 32-bit unpacking primitives. + @$slots = unpack($self->{unpack_code} . "*", $str); + } else { + # We need to unpack 32 bits at a time and combine. + my @b32_values = unpack($self->{unpack_code} . "*", $str); + my @b64_values = (); + for (my $i = 0; $i < $#b32_values; $i += 2) { + # TODO(csilvers): if this is a 32-bit perl, the math below + # could end up in a too-large int, which perl will promote + # to a double, losing necessary precision. Deal with that. + # Right now, we just die. + my ($lo, $hi) = ($b32_values[$i], $b32_values[$i+1]); + if ($self->{unpack_code} eq 'N') { # big-endian + ($lo, $hi) = ($hi, $lo); + } + my $value = $lo + $hi * (2**32); + if (!$self->{perl_is_64bit} && # check value is exactly represented + (($value % (2**32)) != $lo || int($value / (2**32)) != $hi)) { + ::error("Need a 64-bit perl to process this 64-bit profile.\n"); + } + push(@b64_values, $value); + } + @$slots = @b64_values; + } + } + + # Access the i-th long in the file (logically), or -1 at EOF. + sub get { + my ($self, $idx) = @_; + my $slots = $self->{slots}; + while ($#$slots >= 0) { + if ($idx < $self->{base}) { + # The only time we expect a reference to $slots[$i - something] + # after referencing $slots[$i] is reading the very first header. + # Since $stride > |header|, that shouldn't cause any lookback + # errors. And everything after the header is sequential. + print STDERR "Unexpected look-back reading CPU profile"; + return -1; # shrug, don't know what better to return + } elsif ($idx > $self->{base} + $#$slots) { + $self->overflow(); + } else { + return $slots->[$idx - $self->{base}]; + } + } + # If we get here, $slots is [], which means we've reached EOF + return -1; # unique since slots is supposed to hold unsigned numbers + } +} + +# Reads the top, 'header' section of a profile, and returns the last +# line of the header, commonly called a 'header line'. The header +# section of a profile consists of zero or more 'command' lines that +# are instructions to jeprof, which jeprof executes when reading the +# header. All 'command' lines start with a %. After the command +# lines is the 'header line', which is a profile-specific line that +# indicates what type of profile it is, and perhaps other global +# information about the profile. For instance, here's a header line +# for a heap profile: +# heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile +# For historical reasons, the CPU profile does not contain a text- +# readable header line. If the profile looks like a CPU profile, +# this function returns "". If no header line could be found, this +# function returns undef. +# +# The following commands are recognized: +# %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:' +# +# The input file should be in binmode. +sub ReadProfileHeader { + local *PROFILE = shift; + my $firstchar = ""; + my $line = ""; + read(PROFILE, $firstchar, 1); + seek(PROFILE, -1, 1); # unread the firstchar + if ($firstchar !~ /[[:print:]]/) { # is not a text character + return ""; + } + while (defined($line = )) { + $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines + if ($line =~ /^%warn\s+(.*)/) { # 'warn' command + # Note this matches both '%warn blah\n' and '%warn\n'. + print STDERR "WARNING: $1\n"; # print the rest of the line + } elsif ($line =~ /^%/) { + print STDERR "Ignoring unknown command from profile header: $line"; + } else { + # End of commands, must be the header line. + return $line; + } + } + return undef; # got to EOF without seeing a header line +} + +sub IsSymbolizedProfileFile { + my $file_name = shift; + if (!(-e $file_name) || !(-r $file_name)) { + return 0; + } + # Check if the file contains a symbol-section marker. + open(TFILE, "<$file_name"); + binmode TFILE; + my $firstline = ReadProfileHeader(*TFILE); + close(TFILE); + if (!$firstline) { + return 0; + } + $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $symbol_marker = $&; + return $firstline =~ /^--- *$symbol_marker/; +} + +# Parse profile generated by common/profiler.cc and return a reference +# to a map: +# $result->{version} Version number of profile file +# $result->{period} Sampling period (in microseconds) +# $result->{profile} Profile object +# $result->{threads} Map of thread IDs to profile objects +# $result->{map} Memory map info from profile +# $result->{pcs} Hash of all PC values seen, key is hex address +sub ReadProfile { + my $prog = shift; + my $fname = shift; + my $result; # return value + + $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $contention_marker = $&; + $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $growth_marker = $&; + $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $symbol_marker = $&; + $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $profile_marker = $&; + $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $heap_marker = $&; + + # Look at first line to see if it is a heap or a CPU profile. + # CPU profile may start with no header at all, and just binary data + # (starting with \0\0\0\0) -- in that case, don't try to read the + # whole firstline, since it may be gigabytes(!) of data. + open(PROFILE, "<$fname") || error("$fname: $!\n"); + binmode PROFILE; # New perls do UTF-8 processing + my $header = ReadProfileHeader(*PROFILE); + if (!defined($header)) { # means "at EOF" + error("Profile is empty.\n"); + } + + my $symbols; + if ($header =~ m/^--- *$symbol_marker/o) { + # Verify that the user asked for a symbolized profile + if (!$main::use_symbolized_profile) { + # we have both a binary and symbolized profiles, abort + error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " . + "a binary arg. Try again without passing\n $prog\n"); + } + # Read the symbol section of the symbolized profile file. + $symbols = ReadSymbols(*PROFILE{IO}); + # Read the next line to get the header for the remaining profile. + $header = ReadProfileHeader(*PROFILE) || ""; + } + + if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) { + # Skip "--- ..." line for profile types that have their own headers. + $header = ReadProfileHeader(*PROFILE) || ""; + } + + $main::profile_type = ''; + + if ($header =~ m/^heap profile:.*$growth_marker/o) { + $main::profile_type = 'growth'; + $result = ReadHeapProfile($prog, *PROFILE, $header); + } elsif ($header =~ m/^heap profile:/) { + $main::profile_type = 'heap'; + $result = ReadHeapProfile($prog, *PROFILE, $header); + } elsif ($header =~ m/^heap/) { + $main::profile_type = 'heap'; + $result = ReadThreadedHeapProfile($prog, $fname, $header); + } elsif ($header =~ m/^--- *$contention_marker/o) { + $main::profile_type = 'contention'; + $result = ReadSynchProfile($prog, *PROFILE); + } elsif ($header =~ m/^--- *Stacks:/) { + print STDERR + "Old format contention profile: mistakenly reports " . + "condition variable signals as lock contentions.\n"; + $main::profile_type = 'contention'; + $result = ReadSynchProfile($prog, *PROFILE); + } elsif ($header =~ m/^--- *$profile_marker/) { + # the binary cpu profile data starts immediately after this line + $main::profile_type = 'cpu'; + $result = ReadCPUProfile($prog, $fname, *PROFILE); + } else { + if (defined($symbols)) { + # a symbolized profile contains a format we don't recognize, bail out + error("$fname: Cannot recognize profile section after symbols.\n"); + } + # no ascii header present -- must be a CPU profile + $main::profile_type = 'cpu'; + $result = ReadCPUProfile($prog, $fname, *PROFILE); + } + + close(PROFILE); + + # if we got symbols along with the profile, return those as well + if (defined($symbols)) { + $result->{symbols} = $symbols; + } + + return $result; +} + +# Subtract one from caller pc so we map back to call instr. +# However, don't do this if we're reading a symbolized profile +# file, in which case the subtract-one was done when the file +# was written. +# +# We apply the same logic to all readers, though ReadCPUProfile uses an +# independent implementation. +sub FixCallerAddresses { + my $stack = shift; + # --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile() + # dumps unadjusted profiles. + { + $stack =~ /(\s)/; + my $delimiter = $1; + my @addrs = split(' ', $stack); + my @fixedaddrs; + $#fixedaddrs = $#addrs; + if ($#addrs >= 0) { + $fixedaddrs[0] = $addrs[0]; + } + for (my $i = 1; $i <= $#addrs; $i++) { + $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1"); + } + return join $delimiter, @fixedaddrs; + } +} + +# CPU profile reader +sub ReadCPUProfile { + my $prog = shift; + my $fname = shift; # just used for logging + local *PROFILE = shift; + my $version; + my $period; + my $i; + my $profile = {}; + my $pcs = {}; + + # Parse string into array of slots. + my $slots = CpuProfileStream->new(*PROFILE, $fname); + + # Read header. The current header version is a 5-element structure + # containing: + # 0: header count (always 0) + # 1: header "words" (after this one: 3) + # 2: format version (0) + # 3: sampling period (usec) + # 4: unused padding (always 0) + if ($slots->get(0) != 0 ) { + error("$fname: not a profile file, or old format profile file\n"); + } + $i = 2 + $slots->get(1); + $version = $slots->get(2); + $period = $slots->get(3); + # Do some sanity checking on these header values. + if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) { + error("$fname: not a profile file, or corrupted profile file\n"); + } + + # Parse profile + while ($slots->get($i) != -1) { + my $n = $slots->get($i++); + my $d = $slots->get($i++); + if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth? + my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8)); + print STDERR "At index $i (address $addr):\n"; + error("$fname: stack trace depth >= 2**32\n"); + } + if ($slots->get($i) == 0) { + # End of profile data marker + $i += $d; + last; + } + + # Make key out of the stack entries + my @k = (); + for (my $j = 0; $j < $d; $j++) { + my $pc = $slots->get($i+$j); + # Subtract one from caller pc so we map back to call instr. + $pc--; + $pc = sprintf("%0*x", $address_length, $pc); + $pcs->{$pc} = 1; + push @k, $pc; + } + + AddEntry($profile, (join "\n", @k), $n); + $i += $d; + } + + # Parse map + my $map = ''; + seek(PROFILE, $i * 4, 0); + read(PROFILE, $map, (stat PROFILE)[7]); + + my $r = {}; + $r->{version} = $version; + $r->{period} = $period; + $r->{profile} = $profile; + $r->{libs} = ParseLibraries($prog, $map, $pcs); + $r->{pcs} = $pcs; + + return $r; +} + +sub HeapProfileIndex { + my $index = 1; + if ($main::opt_inuse_space) { + $index = 1; + } elsif ($main::opt_inuse_objects) { + $index = 0; + } elsif ($main::opt_alloc_space) { + $index = 3; + } elsif ($main::opt_alloc_objects) { + $index = 2; + } + return $index; +} + +sub ReadMappedLibraries { + my $fh = shift; + my $map = ""; + # Read the /proc/self/maps data + while (<$fh>) { + s/\r//g; # turn windows-looking lines into unix-looking lines + $map .= $_; + } + return $map; +} + +sub ReadMemoryMap { + my $fh = shift; + my $map = ""; + # Read /proc/self/maps data as formatted by DumpAddressMap() + my $buildvar = ""; + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + # Parse "build=" specification if supplied + if (m/^\s*build=(.*)\n/) { + $buildvar = $1; + } + + # Expand "$build" variable if available + $_ =~ s/\$build\b/$buildvar/g; + + $map .= $_; + } + return $map; +} + +sub AdjustSamples { + my ($sample_adjustment, $sampling_algorithm, $n1, $s1, $n2, $s2) = @_; + if ($sample_adjustment) { + if ($sampling_algorithm == 2) { + # Remote-heap version 2 + # The sampling frequency is the rate of a Poisson process. + # This means that the probability of sampling an allocation of + # size X with sampling rate Y is 1 - exp(-X/Y) + if ($n1 != 0) { + my $ratio = (($s1*1.0)/$n1)/($sample_adjustment); + my $scale_factor = 1/(1 - exp(-$ratio)); + $n1 *= $scale_factor; + $s1 *= $scale_factor; + } + if ($n2 != 0) { + my $ratio = (($s2*1.0)/$n2)/($sample_adjustment); + my $scale_factor = 1/(1 - exp(-$ratio)); + $n2 *= $scale_factor; + $s2 *= $scale_factor; + } + } else { + # Remote-heap version 1 + my $ratio; + $ratio = (($s1*1.0)/$n1)/($sample_adjustment); + if ($ratio < 1) { + $n1 /= $ratio; + $s1 /= $ratio; + } + $ratio = (($s2*1.0)/$n2)/($sample_adjustment); + if ($ratio < 1) { + $n2 /= $ratio; + $s2 /= $ratio; + } + } + } + return ($n1, $s1, $n2, $s2); +} + +sub ReadHeapProfile { + my $prog = shift; + local *PROFILE = shift; + my $header = shift; + + my $index = HeapProfileIndex(); + + # Find the type of this profile. The header line looks like: + # heap profile: 1246: 8800744 [ 1246: 8800744] @ /266053 + # There are two pairs , the first inuse objects/space, and the + # second allocated objects/space. This is followed optionally by a profile + # type, and if that is present, optionally by a sampling frequency. + # For remote heap profiles (v1): + # The interpretation of the sampling frequency is that the profiler, for + # each sample, calculates a uniformly distributed random integer less than + # the given value, and records the next sample after that many bytes have + # been allocated. Therefore, the expected sample interval is half of the + # given frequency. By default, if not specified, the expected sample + # interval is 128KB. Only remote-heap-page profiles are adjusted for + # sample size. + # For remote heap profiles (v2): + # The sampling frequency is the rate of a Poisson process. This means that + # the probability of sampling an allocation of size X with sampling rate Y + # is 1 - exp(-X/Y) + # For version 2, a typical header line might look like this: + # heap profile: 1922: 127792360 [ 1922: 127792360] @ _v2/524288 + # the trailing number (524288) is the sampling rate. (Version 1 showed + # double the 'rate' here) + my $sampling_algorithm = 0; + my $sample_adjustment = 0; + chomp($header); + my $type = "unknown"; + if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") { + if (defined($6) && ($6 ne '')) { + $type = $6; + my $sample_period = $8; + # $type is "heapprofile" for profiles generated by the + # heap-profiler, and either "heap" or "heap_v2" for profiles + # generated by sampling directly within tcmalloc. It can also + # be "growth" for heap-growth profiles. The first is typically + # found for profiles generated locally, and the others for + # remote profiles. + if (($type eq "heapprofile") || ($type !~ /heap/) ) { + # No need to adjust for the sampling rate with heap-profiler-derived data + $sampling_algorithm = 0; + } elsif ($type =~ /_v2/) { + $sampling_algorithm = 2; # version 2 sampling + if (defined($sample_period) && ($sample_period ne '')) { + $sample_adjustment = int($sample_period); + } + } else { + $sampling_algorithm = 1; # version 1 sampling + if (defined($sample_period) && ($sample_period ne '')) { + $sample_adjustment = int($sample_period)/2; + } + } + } else { + # We detect whether or not this is a remote-heap profile by checking + # that the total-allocated stats ($n2,$s2) are exactly the + # same as the in-use stats ($n1,$s1). It is remotely conceivable + # that a non-remote-heap profile may pass this check, but it is hard + # to imagine how that could happen. + # In this case it's so old it's guaranteed to be remote-heap version 1. + my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); + if (($n1 == $n2) && ($s1 == $s2)) { + # This is likely to be a remote-heap based sample profile + $sampling_algorithm = 1; + } + } + } + + if ($sampling_algorithm > 0) { + # For remote-heap generated profiles, adjust the counts and sizes to + # account for the sample rate (we sample once every 128KB by default). + if ($sample_adjustment == 0) { + # Turn on profile adjustment. + $sample_adjustment = 128*1024; + print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n"; + } else { + printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n", + $sample_adjustment); + } + if ($sampling_algorithm > 1) { + # We don't bother printing anything for the original version (version 1) + printf STDERR "Heap version $sampling_algorithm\n"; + } + } + + my $profile = {}; + my $pcs = {}; + my $map = ""; + + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + if (/^MAPPED_LIBRARIES:/) { + $map .= ReadMappedLibraries(*PROFILE); + last; + } + + if (/^--- Memory map:/) { + $map .= ReadMemoryMap(*PROFILE); + last; + } + + # Read entry of the form: + # : [: ] @ a1 a2 a3 ... an + s/^\s*//; + s/\s*$//; + if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) { + my $stack = $5; + my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); + my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, + $n1, $s1, $n2, $s2); + AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); + } + } + + my $r = {}; + $r->{version} = "heap"; + $r->{period} = 1; + $r->{profile} = $profile; + $r->{libs} = ParseLibraries($prog, $map, $pcs); + $r->{pcs} = $pcs; + return $r; +} + +sub ReadThreadedHeapProfile { + my ($prog, $fname, $header) = @_; + + my $index = HeapProfileIndex(); + my $sampling_algorithm = 0; + my $sample_adjustment = 0; + chomp($header); + my $type = "unknown"; + # Assuming a very specific type of header for now. + if ($header =~ m"^heap_v2/(\d+)") { + $type = "_v2"; + $sampling_algorithm = 2; + $sample_adjustment = int($1); + } + if ($type ne "_v2" || !defined($sample_adjustment)) { + die "Threaded heap profiles require v2 sampling with a sample rate\n"; + } + + my $profile = {}; + my $thread_profiles = {}; + my $pcs = {}; + my $map = ""; + my $stack = ""; + + while () { + s/\r//g; + if (/^MAPPED_LIBRARIES:/) { + $map .= ReadMappedLibraries(*PROFILE); + last; + } + + if (/^--- Memory map:/) { + $map .= ReadMemoryMap(*PROFILE); + last; + } + + # Read entry of the form: + # @ a1 a2 ... an + # t*: : [: ] + # t1: : [: ] + # ... + # tn: : [: ] + s/^\s*//; + s/\s*$//; + if (m/^@\s+(.*)$/) { + $stack = $1; + } elsif (m/^\s*(t(\*|\d+)):\s+(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]$/) { + if ($stack eq "") { + # Still in the header, so this is just a per-thread summary. + next; + } + my $thread = $2; + my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6); + my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, + $n1, $s1, $n2, $s2); + if ($thread eq "*") { + AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); + } else { + if (!exists($thread_profiles->{$thread})) { + $thread_profiles->{$thread} = {}; + } + AddEntries($thread_profiles->{$thread}, $pcs, + FixCallerAddresses($stack), $counts[$index]); + } + } + } + + my $r = {}; + $r->{version} = "heap"; + $r->{period} = 1; + $r->{profile} = $profile; + $r->{threads} = $thread_profiles; + $r->{libs} = ParseLibraries($prog, $map, $pcs); + $r->{pcs} = $pcs; + return $r; +} + +sub ReadSynchProfile { + my $prog = shift; + local *PROFILE = shift; + my $header = shift; + + my $map = ''; + my $profile = {}; + my $pcs = {}; + my $sampling_period = 1; + my $cyclespernanosec = 2.8; # Default assumption for old binaries + my $seen_clockrate = 0; + my $line; + + my $index = 0; + if ($main::opt_total_delay) { + $index = 0; + } elsif ($main::opt_contentions) { + $index = 1; + } elsif ($main::opt_mean_delay) { + $index = 2; + } + + while ( $line = ) { + $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines + if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) { + my ($cycles, $count, $stack) = ($1, $2, $3); + + # Convert cycles to nanoseconds + $cycles /= $cyclespernanosec; + + # Adjust for sampling done by application + $cycles *= $sampling_period; + $count *= $sampling_period; + + my @values = ($cycles, $count, $cycles / $count); + AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]); + + } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ || + $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) { + my ($cycles, $stack) = ($1, $2); + if ($cycles !~ /^\d+$/) { + next; + } + + # Convert cycles to nanoseconds + $cycles /= $cyclespernanosec; + + # Adjust for sampling done by application + $cycles *= $sampling_period; + + AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles); + + } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) { + my ($variable, $value) = ($1,$2); + for ($variable, $value) { + s/^\s+//; + s/\s+$//; + } + if ($variable eq "cycles/second") { + $cyclespernanosec = $value / 1e9; + $seen_clockrate = 1; + } elsif ($variable eq "sampling period") { + $sampling_period = $value; + } elsif ($variable eq "ms since reset") { + # Currently nothing is done with this value in jeprof + # So we just silently ignore it for now + } elsif ($variable eq "discarded samples") { + # Currently nothing is done with this value in jeprof + # So we just silently ignore it for now + } else { + printf STDERR ("Ignoring unnknown variable in /contention output: " . + "'%s' = '%s'\n",$variable,$value); + } + } else { + # Memory map entry + $map .= $line; + } + } + + if (!$seen_clockrate) { + printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n", + $cyclespernanosec); + } + + my $r = {}; + $r->{version} = 0; + $r->{period} = $sampling_period; + $r->{profile} = $profile; + $r->{libs} = ParseLibraries($prog, $map, $pcs); + $r->{pcs} = $pcs; + return $r; +} + +# Given a hex value in the form "0x1abcd" or "1abcd", return either +# "0001abcd" or "000000000001abcd", depending on the current (global) +# address length. +sub HexExtend { + my $addr = shift; + + $addr =~ s/^(0x)?0*//; + my $zeros_needed = $address_length - length($addr); + if ($zeros_needed < 0) { + printf STDERR "Warning: address $addr is longer than address length $address_length\n"; + return $addr; + } + return ("0" x $zeros_needed) . $addr; +} + +##### Symbol extraction ##### + +# Aggressively search the lib_prefix values for the given library +# If all else fails, just return the name of the library unmodified. +# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so" +# it will search the following locations in this order, until it finds a file: +# /my/path/lib/dir/mylib.so +# /other/path/lib/dir/mylib.so +# /my/path/dir/mylib.so +# /other/path/dir/mylib.so +# /my/path/mylib.so +# /other/path/mylib.so +# /lib/dir/mylib.so (returned as last resort) +sub FindLibrary { + my $file = shift; + my $suffix = $file; + + # Search for the library as described above + do { + foreach my $prefix (@prefix_list) { + my $fullpath = $prefix . $suffix; + if (-e $fullpath) { + return $fullpath; + } + } + } while ($suffix =~ s|^/[^/]+/|/|); + return $file; +} + +# Return path to library with debugging symbols. +# For libc libraries, the copy in /usr/lib/debug contains debugging symbols +sub DebuggingLibrary { + my $file = shift; + if ($file =~ m|^/|) { + if (-f "/usr/lib/debug$file") { + return "/usr/lib/debug$file"; + } elsif (-f "/usr/lib/debug$file.debug") { + return "/usr/lib/debug$file.debug"; + } + } + return undef; +} + +# Parse text section header of a library using objdump +sub ParseTextSectionHeaderFromObjdump { + my $lib = shift; + + my $size = undef; + my $vma; + my $file_offset; + # Get objdump output from the library file to figure out how to + # map between mapped addresses and addresses in the library. + my $cmd = ShellEscape($obj_tool_map{"objdump"}, "-h", $lib); + open(OBJDUMP, "$cmd |") || error("$cmd: $!\n"); + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + # Idx Name Size VMA LMA File off Algn + # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4 + # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file + # offset may still be 8. But AddressSub below will still handle that. + my @x = split; + if (($#x >= 6) && ($x[1] eq '.text')) { + $size = $x[2]; + $vma = $x[3]; + $file_offset = $x[5]; + last; + } + } + close(OBJDUMP); + + if (!defined($size)) { + return undef; + } + + my $r = {}; + $r->{size} = $size; + $r->{vma} = $vma; + $r->{file_offset} = $file_offset; + + return $r; +} + +# Parse text section header of a library using otool (on OS X) +sub ParseTextSectionHeaderFromOtool { + my $lib = shift; + + my $size = undef; + my $vma = undef; + my $file_offset = undef; + # Get otool output from the library file to figure out how to + # map between mapped addresses and addresses in the library. + my $command = ShellEscape($obj_tool_map{"otool"}, "-l", $lib); + open(OTOOL, "$command |") || error("$command: $!\n"); + my $cmd = ""; + my $sectname = ""; + my $segname = ""; + foreach my $line () { + $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines + # Load command <#> + # cmd LC_SEGMENT + # [...] + # Section + # sectname __text + # segname __TEXT + # addr 0x000009f8 + # size 0x00018b9e + # offset 2552 + # align 2^2 (4) + # We will need to strip off the leading 0x from the hex addresses, + # and convert the offset into hex. + if ($line =~ /Load command/) { + $cmd = ""; + $sectname = ""; + $segname = ""; + } elsif ($line =~ /Section/) { + $sectname = ""; + $segname = ""; + } elsif ($line =~ /cmd (\w+)/) { + $cmd = $1; + } elsif ($line =~ /sectname (\w+)/) { + $sectname = $1; + } elsif ($line =~ /segname (\w+)/) { + $segname = $1; + } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") && + $sectname eq "__text" && + $segname eq "__TEXT")) { + next; + } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) { + $vma = $1; + } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) { + $size = $1; + } elsif ($line =~ /\boffset ([0-9]+)/) { + $file_offset = sprintf("%016x", $1); + } + if (defined($vma) && defined($size) && defined($file_offset)) { + last; + } + } + close(OTOOL); + + if (!defined($vma) || !defined($size) || !defined($file_offset)) { + return undef; + } + + my $r = {}; + $r->{size} = $size; + $r->{vma} = $vma; + $r->{file_offset} = $file_offset; + + return $r; +} + +sub ParseTextSectionHeader { + # obj_tool_map("otool") is only defined if we're in a Mach-O environment + if (defined($obj_tool_map{"otool"})) { + my $r = ParseTextSectionHeaderFromOtool(@_); + if (defined($r)){ + return $r; + } + } + # If otool doesn't work, or we don't have it, fall back to objdump + return ParseTextSectionHeaderFromObjdump(@_); +} + +# Split /proc/pid/maps dump into a list of libraries +sub ParseLibraries { + return if $main::use_symbol_page; # We don't need libraries info. + my $prog = Cwd::abs_path(shift); + my $map = shift; + my $pcs = shift; + + my $result = []; + my $h = "[a-f0-9]+"; + my $zero_offset = HexExtend("0"); + + my $buildvar = ""; + foreach my $l (split("\n", $map)) { + if ($l =~ m/^\s*build=(.*)$/) { + $buildvar = $1; + } + + my $start; + my $finish; + my $offset; + my $lib; + if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) { + # Full line from /proc/self/maps. Example: + # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so + $start = HexExtend($1); + $finish = HexExtend($2); + $offset = HexExtend($3); + $lib = $4; + $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths + } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) { + # Cooked line from DumpAddressMap. Example: + # 40000000-40015000: /lib/ld-2.3.2.so + $start = HexExtend($1); + $finish = HexExtend($2); + $offset = $zero_offset; + $lib = $3; + } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) { + # PIEs and address space randomization do not play well with our + # default assumption that main executable is at lowest + # addresses. So we're detecting main executable in + # /proc/self/maps as well. + $start = HexExtend($1); + $finish = HexExtend($2); + $offset = HexExtend($3); + $lib = $4; + $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths + } + # FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in + # function procfs_doprocmap (sys/fs/procfs/procfs_map.c) + # + # Example: + # 0x800600000 0x80061a000 26 0 0xfffff800035a0000 r-x 75 33 0x1004 COW NC vnode /libexec/ld-elf.s + # o.1 NCH -1 + elsif ($l =~ /^(0x$h)\s(0x$h)\s\d+\s\d+\s0x$h\sr-x\s\d+\s\d+\s0x\d+\s(COW|NCO)\s(NC|NNC)\svnode\s(\S+\.so(\.\d+)*)/) { + $start = HexExtend($1); + $finish = HexExtend($2); + $offset = $zero_offset; + $lib = FindLibrary($5); + + } else { + next; + } + + # Expand "$build" variable if available + $lib =~ s/\$build\b/$buildvar/g; + + $lib = FindLibrary($lib); + + # Check for pre-relocated libraries, which use pre-relocated symbol tables + # and thus require adjusting the offset that we'll use to translate + # VM addresses into symbol table addresses. + # Only do this if we're not going to fetch the symbol table from a + # debugging copy of the library. + if (!DebuggingLibrary($lib)) { + my $text = ParseTextSectionHeader($lib); + if (defined($text)) { + my $vma_offset = AddressSub($text->{vma}, $text->{file_offset}); + $offset = AddressAdd($offset, $vma_offset); + } + } + + if($main::opt_debug) { printf STDERR "$start:$finish ($offset) $lib\n"; } + push(@{$result}, [$lib, $start, $finish, $offset]); + } + + # Append special entry for additional library (not relocated) + if ($main::opt_lib ne "") { + my $text = ParseTextSectionHeader($main::opt_lib); + if (defined($text)) { + my $start = $text->{vma}; + my $finish = AddressAdd($start, $text->{size}); + + push(@{$result}, [$main::opt_lib, $start, $finish, $start]); + } + } + + # Append special entry for the main program. This covers + # 0..max_pc_value_seen, so that we assume pc values not found in one + # of the library ranges will be treated as coming from the main + # program binary. + my $min_pc = HexExtend("0"); + my $max_pc = $min_pc; # find the maximal PC value in any sample + foreach my $pc (keys(%{$pcs})) { + if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); } + } + push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]); + + return $result; +} + +# Add two hex addresses of length $address_length. +# Run jeprof --test for unit test if this is changed. +sub AddressAdd { + my $addr1 = shift; + my $addr2 = shift; + my $sum; + + if ($address_length == 8) { + # Perl doesn't cope with wraparound arithmetic, so do it explicitly: + $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16); + return sprintf("%08x", $sum); + + } else { + # Do the addition in 7-nibble chunks to trivialize carry handling. + + if ($main::opt_debug and $main::opt_test) { + print STDERR "AddressAdd $addr1 + $addr2 = "; + } + + my $a1 = substr($addr1,-7); + $addr1 = substr($addr1,0,-7); + my $a2 = substr($addr2,-7); + $addr2 = substr($addr2,0,-7); + $sum = hex($a1) + hex($a2); + my $c = 0; + if ($sum > 0xfffffff) { + $c = 1; + $sum -= 0x10000000; + } + my $r = sprintf("%07x", $sum); + + $a1 = substr($addr1,-7); + $addr1 = substr($addr1,0,-7); + $a2 = substr($addr2,-7); + $addr2 = substr($addr2,0,-7); + $sum = hex($a1) + hex($a2) + $c; + $c = 0; + if ($sum > 0xfffffff) { + $c = 1; + $sum -= 0x10000000; + } + $r = sprintf("%07x", $sum) . $r; + + $sum = hex($addr1) + hex($addr2) + $c; + if ($sum > 0xff) { $sum -= 0x100; } + $r = sprintf("%02x", $sum) . $r; + + if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; } + + return $r; + } +} + + +# Subtract two hex addresses of length $address_length. +# Run jeprof --test for unit test if this is changed. +sub AddressSub { + my $addr1 = shift; + my $addr2 = shift; + my $diff; + + if ($address_length == 8) { + # Perl doesn't cope with wraparound arithmetic, so do it explicitly: + $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16); + return sprintf("%08x", $diff); + + } else { + # Do the addition in 7-nibble chunks to trivialize borrow handling. + # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; } + + my $a1 = hex(substr($addr1,-7)); + $addr1 = substr($addr1,0,-7); + my $a2 = hex(substr($addr2,-7)); + $addr2 = substr($addr2,0,-7); + my $b = 0; + if ($a2 > $a1) { + $b = 1; + $a1 += 0x10000000; + } + $diff = $a1 - $a2; + my $r = sprintf("%07x", $diff); + + $a1 = hex(substr($addr1,-7)); + $addr1 = substr($addr1,0,-7); + $a2 = hex(substr($addr2,-7)) + $b; + $addr2 = substr($addr2,0,-7); + $b = 0; + if ($a2 > $a1) { + $b = 1; + $a1 += 0x10000000; + } + $diff = $a1 - $a2; + $r = sprintf("%07x", $diff) . $r; + + $a1 = hex($addr1); + $a2 = hex($addr2) + $b; + if ($a2 > $a1) { $a1 += 0x100; } + $diff = $a1 - $a2; + $r = sprintf("%02x", $diff) . $r; + + # if ($main::opt_debug) { print STDERR "$r\n"; } + + return $r; + } +} + +# Increment a hex addresses of length $address_length. +# Run jeprof --test for unit test if this is changed. +sub AddressInc { + my $addr = shift; + my $sum; + + if ($address_length == 8) { + # Perl doesn't cope with wraparound arithmetic, so do it explicitly: + $sum = (hex($addr)+1) % (0x10000000 * 16); + return sprintf("%08x", $sum); + + } else { + # Do the addition in 7-nibble chunks to trivialize carry handling. + # We are always doing this to step through the addresses in a function, + # and will almost never overflow the first chunk, so we check for this + # case and exit early. + + # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; } + + my $a1 = substr($addr,-7); + $addr = substr($addr,0,-7); + $sum = hex($a1) + 1; + my $r = sprintf("%07x", $sum); + if ($sum <= 0xfffffff) { + $r = $addr . $r; + # if ($main::opt_debug) { print STDERR "$r\n"; } + return HexExtend($r); + } else { + $r = "0000000"; + } + + $a1 = substr($addr,-7); + $addr = substr($addr,0,-7); + $sum = hex($a1) + 1; + $r = sprintf("%07x", $sum) . $r; + if ($sum <= 0xfffffff) { + $r = $addr . $r; + # if ($main::opt_debug) { print STDERR "$r\n"; } + return HexExtend($r); + } else { + $r = "00000000000000"; + } + + $sum = hex($addr) + 1; + if ($sum > 0xff) { $sum -= 0x100; } + $r = sprintf("%02x", $sum) . $r; + + # if ($main::opt_debug) { print STDERR "$r\n"; } + return $r; + } +} + +# Extract symbols for all PC values found in profile +sub ExtractSymbols { + my $libs = shift; + my $pcset = shift; + + my $symbols = {}; + + # Map each PC value to the containing library. To make this faster, + # we sort libraries by their starting pc value (highest first), and + # advance through the libraries as we advance the pc. Sometimes the + # addresses of libraries may overlap with the addresses of the main + # binary, so to make sure the libraries 'win', we iterate over the + # libraries in reverse order (which assumes the binary doesn't start + # in the middle of a library, which seems a fair assumption). + my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings + foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) { + my $libname = $lib->[0]; + my $start = $lib->[1]; + my $finish = $lib->[2]; + my $offset = $lib->[3]; + + # Use debug library if it exists + my $debug_libname = DebuggingLibrary($libname); + if ($debug_libname) { + $libname = $debug_libname; + } + + # Get list of pcs that belong in this library. + my $contained = []; + my ($start_pc_index, $finish_pc_index); + # Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index]. + for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0; + $finish_pc_index--) { + last if $pcs[$finish_pc_index - 1] le $finish; + } + # Find smallest start_pc_index such that $start <= $pc[$start_pc_index]. + for ($start_pc_index = $finish_pc_index; $start_pc_index > 0; + $start_pc_index--) { + last if $pcs[$start_pc_index - 1] lt $start; + } + # This keeps PC values higher than $pc[$finish_pc_index] in @pcs, + # in case there are overlaps in libraries and the main binary. + @{$contained} = splice(@pcs, $start_pc_index, + $finish_pc_index - $start_pc_index); + # Map to symbols + MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols); + } + + return $symbols; +} + +# Map list of PC values to symbols for a given image +sub MapToSymbols { + my $image = shift; + my $offset = shift; + my $pclist = shift; + my $symbols = shift; + + my $debug = 0; + + # Ignore empty binaries + if ($#{$pclist} < 0) { return; } + + # Figure out the addr2line command to use + my $addr2line = $obj_tool_map{"addr2line"}; + my $cmd = ShellEscape($addr2line, "-f", "-C", "-e", $image); + if (exists $obj_tool_map{"addr2line_pdb"}) { + $addr2line = $obj_tool_map{"addr2line_pdb"}; + $cmd = ShellEscape($addr2line, "--demangle", "-f", "-C", "-e", $image); + } + + # If "addr2line" isn't installed on the system at all, just use + # nm to get what info we can (function names, but not line numbers). + if (system(ShellEscape($addr2line, "--help") . " >$dev_null 2>&1") != 0) { + MapSymbolsWithNM($image, $offset, $pclist, $symbols); + return; + } + + # "addr2line -i" can produce a variable number of lines per input + # address, with no separator that allows us to tell when data for + # the next address starts. So we find the address for a special + # symbol (_fini) and interleave this address between all real + # addresses passed to addr2line. The name of this special symbol + # can then be used as a separator. + $sep_address = undef; # May be filled in by MapSymbolsWithNM() + my $nm_symbols = {}; + MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols); + if (defined($sep_address)) { + # Only add " -i" to addr2line if the binary supports it. + # addr2line --help returns 0, but not if it sees an unknown flag first. + if (system("$cmd -i --help >$dev_null 2>&1") == 0) { + $cmd .= " -i"; + } else { + $sep_address = undef; # no need for sep_address if we don't support -i + } + } + + # Make file with all PC values with intervening 'sep_address' so + # that we can reliably detect the end of inlined function list + open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n"); + if ($debug) { print("---- $image ---\n"); } + for (my $i = 0; $i <= $#{$pclist}; $i++) { + # addr2line always reads hex addresses, and does not need '0x' prefix. + if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); } + printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset)); + if (defined($sep_address)) { + printf ADDRESSES ("%s\n", $sep_address); + } + } + close(ADDRESSES); + if ($debug) { + print("----\n"); + system("cat", $main::tmpfile_sym); + print("----\n"); + system("$cmd < " . ShellEscape($main::tmpfile_sym)); + print("----\n"); + } + + open(SYMBOLS, "$cmd <" . ShellEscape($main::tmpfile_sym) . " |") + || error("$cmd: $!\n"); + my $count = 0; # Index in pclist + while () { + # Read fullfunction and filelineinfo from next pair of lines + s/\r?\n$//g; + my $fullfunction = $_; + $_ = ; + s/\r?\n$//g; + my $filelinenum = $_; + + if (defined($sep_address) && $fullfunction eq $sep_symbol) { + # Terminating marker for data for this address + $count++; + next; + } + + $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths + + my $pcstr = $pclist->[$count]; + my $function = ShortFunctionName($fullfunction); + my $nms = $nm_symbols->{$pcstr}; + if (defined($nms)) { + if ($fullfunction eq '??') { + # nm found a symbol for us. + $function = $nms->[0]; + $fullfunction = $nms->[2]; + } else { + # MapSymbolsWithNM tags each routine with its starting address, + # useful in case the image has multiple occurrences of this + # routine. (It uses a syntax that resembles template paramters, + # that are automatically stripped out by ShortFunctionName().) + # addr2line does not provide the same information. So we check + # if nm disambiguated our symbol, and if so take the annotated + # (nm) version of the routine-name. TODO(csilvers): this won't + # catch overloaded, inlined symbols, which nm doesn't see. + # Better would be to do a check similar to nm's, in this fn. + if ($nms->[2] =~ m/^\Q$function\E/) { # sanity check it's the right fn + $function = $nms->[0]; + $fullfunction = $nms->[2]; + } + } + } + + # Prepend to accumulated symbols for pcstr + # (so that caller comes before callee) + my $sym = $symbols->{$pcstr}; + if (!defined($sym)) { + $sym = []; + $symbols->{$pcstr} = $sym; + } + unshift(@{$sym}, $function, $filelinenum, $fullfunction); + if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); } + if (!defined($sep_address)) { + # Inlining is off, so this entry ends immediately + $count++; + } + } + close(SYMBOLS); +} + +# Use nm to map the list of referenced PCs to symbols. Return true iff we +# are able to read procedure information via nm. +sub MapSymbolsWithNM { + my $image = shift; + my $offset = shift; + my $pclist = shift; + my $symbols = shift; + + # Get nm output sorted by increasing address + my $symbol_table = GetProcedureBoundaries($image, "."); + if (!%{$symbol_table}) { + return 0; + } + # Start addresses are already the right length (8 or 16 hex digits). + my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] } + keys(%{$symbol_table}); + + if ($#names < 0) { + # No symbols: just use addresses + foreach my $pc (@{$pclist}) { + my $pcstr = "0x" . $pc; + $symbols->{$pc} = [$pcstr, "?", $pcstr]; + } + return 0; + } + + # Sort addresses so we can do a join against nm output + my $index = 0; + my $fullname = $names[0]; + my $name = ShortFunctionName($fullname); + foreach my $pc (sort { $a cmp $b } @{$pclist}) { + # Adjust for mapped offset + my $mpc = AddressSub($pc, $offset); + while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){ + $index++; + $fullname = $names[$index]; + $name = ShortFunctionName($fullname); + } + if ($mpc lt $symbol_table->{$fullname}->[1]) { + $symbols->{$pc} = [$name, "?", $fullname]; + } else { + my $pcstr = "0x" . $pc; + $symbols->{$pc} = [$pcstr, "?", $pcstr]; + } + } + return 1; +} + +sub ShortFunctionName { + my $function = shift; + while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types + while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments + $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type + return $function; +} + +# Trim overly long symbols found in disassembler output +sub CleanDisassembly { + my $d = shift; + while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax) + while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments + return $d; +} + +# Clean file name for display +sub CleanFileName { + my ($f) = @_; + $f =~ s|^/proc/self/cwd/||; + $f =~ s|^\./||; + return $f; +} + +# Make address relative to section and clean up for display +sub UnparseAddress { + my ($offset, $address) = @_; + $address = AddressSub($address, $offset); + $address =~ s/^0x//; + $address =~ s/^0*//; + return $address; +} + +##### Miscellaneous ##### + +# Find the right versions of the above object tools to use. The +# argument is the program file being analyzed, and should be an ELF +# 32-bit or ELF 64-bit executable file. The location of the tools +# is determined by considering the following options in this order: +# 1) --tools option, if set +# 2) JEPROF_TOOLS environment variable, if set +# 3) the environment +sub ConfigureObjTools { + my $prog_file = shift; + + # Check for the existence of $prog_file because /usr/bin/file does not + # predictably return error status in prod. + (-e $prog_file) || error("$prog_file does not exist.\n"); + + my $file_type = undef; + if (-e "/usr/bin/file") { + # Follow symlinks (at least for systems where "file" supports that). + my $escaped_prog_file = ShellEscape($prog_file); + $file_type = `/usr/bin/file -L $escaped_prog_file 2>$dev_null || + /usr/bin/file $escaped_prog_file`; + } elsif ($^O == "MSWin32") { + $file_type = "MS Windows"; + } else { + print STDERR "WARNING: Can't determine the file type of $prog_file"; + } + + if ($file_type =~ /64-bit/) { + # Change $address_length to 16 if the program file is ELF 64-bit. + # We can't detect this from many (most?) heap or lock contention + # profiles, since the actual addresses referenced are generally in low + # memory even for 64-bit programs. + $address_length = 16; + } + + if ($file_type =~ /MS Windows/) { + # For windows, we provide a version of nm and addr2line as part of + # the opensource release, which is capable of parsing + # Windows-style PDB executables. It should live in the path, or + # in the same directory as jeprof. + $obj_tool_map{"nm_pdb"} = "nm-pdb"; + $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb"; + } + + if ($file_type =~ /Mach-O/) { + # OS X uses otool to examine Mach-O files, rather than objdump. + $obj_tool_map{"otool"} = "otool"; + $obj_tool_map{"addr2line"} = "false"; # no addr2line + $obj_tool_map{"objdump"} = "false"; # no objdump + } + + # Go fill in %obj_tool_map with the pathnames to use: + foreach my $tool (keys %obj_tool_map) { + $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool}); + } +} + +# Returns the path of a caller-specified object tool. If --tools or +# JEPROF_TOOLS are specified, then returns the full path to the tool +# with that prefix. Otherwise, returns the path unmodified (which +# means we will look for it on PATH). +sub ConfigureTool { + my $tool = shift; + my $path; + + # --tools (or $JEPROF_TOOLS) is a comma separated list, where each + # item is either a) a pathname prefix, or b) a map of the form + # :. First we look for an entry of type (b) for our + # tool. If one is found, we use it. Otherwise, we consider all the + # pathname prefixes in turn, until one yields an existing file. If + # none does, we use a default path. + my $tools = $main::opt_tools || $ENV{"JEPROF_TOOLS"} || ""; + if ($tools =~ m/(,|^)\Q$tool\E:([^,]*)/) { + $path = $2; + # TODO(csilvers): sanity-check that $path exists? Hard if it's relative. + } elsif ($tools ne '') { + foreach my $prefix (split(',', $tools)) { + next if ($prefix =~ /:/); # ignore "tool:fullpath" entries in the list + if (-x $prefix . $tool) { + $path = $prefix . $tool; + last; + } + } + if (!$path) { + error("No '$tool' found with prefix specified by " . + "--tools (or \$JEPROF_TOOLS) '$tools'\n"); + } + } else { + # ... otherwise use the version that exists in the same directory as + # jeprof. If there's nothing there, use $PATH. + $0 =~ m,[^/]*$,; # this is everything after the last slash + my $dirname = $`; # this is everything up to and including the last slash + if (-x "$dirname$tool") { + $path = "$dirname$tool"; + } else { + $path = $tool; + } + } + if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; } + return $path; +} + +sub ShellEscape { + my @escaped_words = (); + foreach my $word (@_) { + my $escaped_word = $word; + if ($word =~ m![^a-zA-Z0-9/.,_=-]!) { # check for anything not in whitelist + $escaped_word =~ s/'/'\\''/; + $escaped_word = "'$escaped_word'"; + } + push(@escaped_words, $escaped_word); + } + return join(" ", @escaped_words); +} + +sub cleanup { + unlink($main::tmpfile_sym); + unlink(keys %main::tempnames); + + # We leave any collected profiles in $HOME/jeprof in case the user wants + # to look at them later. We print a message informing them of this. + if ((scalar(@main::profile_files) > 0) && + defined($main::collected_profile)) { + if (scalar(@main::profile_files) == 1) { + print STDERR "Dynamically gathered profile is in $main::collected_profile\n"; + } + print STDERR "If you want to investigate this profile further, you can do:\n"; + print STDERR "\n"; + print STDERR " jeprof \\\n"; + print STDERR " $main::prog \\\n"; + print STDERR " $main::collected_profile\n"; + print STDERR "\n"; + } +} + +sub sighandler { + cleanup(); + exit(1); +} + +sub error { + my $msg = shift; + print STDERR $msg; + cleanup(); + exit(1); +} + + +# Run $nm_command and get all the resulting procedure boundaries whose +# names match "$regexp" and returns them in a hashtable mapping from +# procedure name to a two-element vector of [start address, end address] +sub GetProcedureBoundariesViaNm { + my $escaped_nm_command = shift; # shell-escaped + my $regexp = shift; + + my $symbol_table = {}; + open(NM, "$escaped_nm_command |") || error("$escaped_nm_command: $!\n"); + my $last_start = "0"; + my $routine = ""; + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + if (m/^\s*([0-9a-f]+) (.) (..*)/) { + my $start_val = $1; + my $type = $2; + my $this_routine = $3; + + # It's possible for two symbols to share the same address, if + # one is a zero-length variable (like __start_google_malloc) or + # one symbol is a weak alias to another (like __libc_malloc). + # In such cases, we want to ignore all values except for the + # actual symbol, which in nm-speak has type "T". The logic + # below does this, though it's a bit tricky: what happens when + # we have a series of lines with the same address, is the first + # one gets queued up to be processed. However, it won't + # *actually* be processed until later, when we read a line with + # a different address. That means that as long as we're reading + # lines with the same address, we have a chance to replace that + # item in the queue, which we do whenever we see a 'T' entry -- + # that is, a line with type 'T'. If we never see a 'T' entry, + # we'll just go ahead and process the first entry (which never + # got touched in the queue), and ignore the others. + if ($start_val eq $last_start && $type =~ /t/i) { + # We are the 'T' symbol at this address, replace previous symbol. + $routine = $this_routine; + next; + } elsif ($start_val eq $last_start) { + # We're not the 'T' symbol at this address, so ignore us. + next; + } + + if ($this_routine eq $sep_symbol) { + $sep_address = HexExtend($start_val); + } + + # Tag this routine with the starting address in case the image + # has multiple occurrences of this routine. We use a syntax + # that resembles template parameters that are automatically + # stripped out by ShortFunctionName() + $this_routine .= "<$start_val>"; + + if (defined($routine) && $routine =~ m/$regexp/) { + $symbol_table->{$routine} = [HexExtend($last_start), + HexExtend($start_val)]; + } + $last_start = $start_val; + $routine = $this_routine; + } elsif (m/^Loaded image name: (.+)/) { + # The win32 nm workalike emits information about the binary it is using. + if ($main::opt_debug) { print STDERR "Using Image $1\n"; } + } elsif (m/^PDB file name: (.+)/) { + # The win32 nm workalike emits information about the pdb it is using. + if ($main::opt_debug) { print STDERR "Using PDB $1\n"; } + } + } + close(NM); + # Handle the last line in the nm output. Unfortunately, we don't know + # how big this last symbol is, because we don't know how big the file + # is. For now, we just give it a size of 0. + # TODO(csilvers): do better here. + if (defined($routine) && $routine =~ m/$regexp/) { + $symbol_table->{$routine} = [HexExtend($last_start), + HexExtend($last_start)]; + } + return $symbol_table; +} + +# Gets the procedure boundaries for all routines in "$image" whose names +# match "$regexp" and returns them in a hashtable mapping from procedure +# name to a two-element vector of [start address, end address]. +# Will return an empty map if nm is not installed or not working properly. +sub GetProcedureBoundaries { + my $image = shift; + my $regexp = shift; + + # If $image doesn't start with /, then put ./ in front of it. This works + # around an obnoxious bug in our probing of nm -f behavior. + # "nm -f $image" is supposed to fail on GNU nm, but if: + # + # a. $image starts with [BbSsPp] (for example, bin/foo/bar), AND + # b. you have a.out in your current directory (a not uncommon occurence) + # + # then "nm -f $image" succeeds because -f only looks at the first letter of + # the argument, which looks valid because it's [BbSsPp], and then since + # there's no image provided, it looks for a.out and finds it. + # + # This regex makes sure that $image starts with . or /, forcing the -f + # parsing to fail since . and / are not valid formats. + $image =~ s#^[^/]#./$&#; + + # For libc libraries, the copy in /usr/lib/debug contains debugging symbols + my $debugging = DebuggingLibrary($image); + if ($debugging) { + $image = $debugging; + } + + my $nm = $obj_tool_map{"nm"}; + my $cppfilt = $obj_tool_map{"c++filt"}; + + # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm + # binary doesn't support --demangle. In addition, for OS X we need + # to use the -f flag to get 'flat' nm output (otherwise we don't sort + # properly and get incorrect results). Unfortunately, GNU nm uses -f + # in an incompatible way. So first we test whether our nm supports + # --demangle and -f. + my $demangle_flag = ""; + my $cppfilt_flag = ""; + my $to_devnull = ">$dev_null 2>&1"; + if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) { + # In this mode, we do "nm --demangle " + $demangle_flag = "--demangle"; + $cppfilt_flag = ""; + } elsif (system(ShellEscape($cppfilt, $image) . $to_devnull) == 0) { + # In this mode, we do "nm | c++filt" + $cppfilt_flag = " | " . ShellEscape($cppfilt); + }; + my $flatten_flag = ""; + if (system(ShellEscape($nm, "-f", $image) . $to_devnull) == 0) { + $flatten_flag = "-f"; + } + + # Finally, in the case $imagie isn't a debug library, we try again with + # -D to at least get *exported* symbols. If we can't use --demangle, + # we use c++filt instead, if it exists on this system. + my @nm_commands = (ShellEscape($nm, "-n", $flatten_flag, $demangle_flag, + $image) . " 2>$dev_null $cppfilt_flag", + ShellEscape($nm, "-D", "-n", $flatten_flag, $demangle_flag, + $image) . " 2>$dev_null $cppfilt_flag", + # 6nm is for Go binaries + ShellEscape("6nm", "$image") . " 2>$dev_null | sort", + ); + + # If the executable is an MS Windows PDB-format executable, we'll + # have set up obj_tool_map("nm_pdb"). In this case, we actually + # want to use both unix nm and windows-specific nm_pdb, since + # PDB-format executables can apparently include dwarf .o files. + if (exists $obj_tool_map{"nm_pdb"}) { + push(@nm_commands, + ShellEscape($obj_tool_map{"nm_pdb"}, "--demangle", $image) + . " 2>$dev_null"); + } + + foreach my $nm_command (@nm_commands) { + my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp); + return $symbol_table if (%{$symbol_table}); + } + my $symbol_table = {}; + return $symbol_table; +} + + +# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings. +# To make them more readable, we add underscores at interesting places. +# This routine removes the underscores, producing the canonical representation +# used by jeprof to represent addresses, particularly in the tested routines. +sub CanonicalHex { + my $arg = shift; + return join '', (split '_',$arg); +} + + +# Unit test for AddressAdd: +sub AddressAddUnitTest { + my $test_data_8 = shift; + my $test_data_16 = shift; + my $error_count = 0; + my $fail_count = 0; + my $pass_count = 0; + # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n"; + + # First a few 8-nibble addresses. Note that this implementation uses + # plain old arithmetic, so a quick sanity check along with verifying what + # happens to overflow (we want it to wrap): + $address_length = 8; + foreach my $row (@{$test_data_8}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressAdd ($row->[0], $row->[1]); + if ($sum ne $row->[2]) { + printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, + $row->[0], $row->[1], $row->[2]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count = $fail_count; + $fail_count = 0; + $pass_count = 0; + + # Now 16-nibble addresses. + $address_length = 16; + foreach my $row (@{$test_data_16}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1])); + my $expected = join '', (split '_',$row->[2]); + if ($sum ne CanonicalHex($row->[2])) { + printf STDERR "ERROR: %s != %s + %s = %s\n", $sum, + $row->[0], $row->[1], $row->[2]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count += $fail_count; + + return $error_count; +} + + +# Unit test for AddressSub: +sub AddressSubUnitTest { + my $test_data_8 = shift; + my $test_data_16 = shift; + my $error_count = 0; + my $fail_count = 0; + my $pass_count = 0; + # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n"; + + # First a few 8-nibble addresses. Note that this implementation uses + # plain old arithmetic, so a quick sanity check along with verifying what + # happens to overflow (we want it to wrap): + $address_length = 8; + foreach my $row (@{$test_data_8}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressSub ($row->[0], $row->[1]); + if ($sum ne $row->[3]) { + printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, + $row->[0], $row->[1], $row->[3]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count = $fail_count; + $fail_count = 0; + $pass_count = 0; + + # Now 16-nibble addresses. + $address_length = 16; + foreach my $row (@{$test_data_16}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1])); + if ($sum ne CanonicalHex($row->[3])) { + printf STDERR "ERROR: %s != %s - %s = %s\n", $sum, + $row->[0], $row->[1], $row->[3]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count += $fail_count; + + return $error_count; +} + + +# Unit test for AddressInc: +sub AddressIncUnitTest { + my $test_data_8 = shift; + my $test_data_16 = shift; + my $error_count = 0; + my $fail_count = 0; + my $pass_count = 0; + # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n"; + + # First a few 8-nibble addresses. Note that this implementation uses + # plain old arithmetic, so a quick sanity check along with verifying what + # happens to overflow (we want it to wrap): + $address_length = 8; + foreach my $row (@{$test_data_8}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressInc ($row->[0]); + if ($sum ne $row->[4]) { + printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, + $row->[0], $row->[4]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count = $fail_count; + $fail_count = 0; + $pass_count = 0; + + # Now 16-nibble addresses. + $address_length = 16; + foreach my $row (@{$test_data_16}) { + if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; } + my $sum = AddressInc (CanonicalHex($row->[0])); + if ($sum ne CanonicalHex($row->[4])) { + printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum, + $row->[0], $row->[4]; + ++$fail_count; + } else { + ++$pass_count; + } + } + printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n", + $pass_count, $fail_count; + $error_count += $fail_count; + + return $error_count; +} + + +# Driver for unit tests. +# Currently just the address add/subtract/increment routines for 64-bit. +sub RunUnitTests { + my $error_count = 0; + + # This is a list of tuples [a, b, a+b, a-b, a+1] + my $unit_test_data_8 = [ + [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)], + [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)], + [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)], + [qw(00000001 ffffffff 00000000 00000002 00000002)], + [qw(00000001 fffffff0 fffffff1 00000011 00000002)], + ]; + my $unit_test_data_16 = [ + # The implementation handles data in 7-nibble chunks, so those are the + # interesting boundaries. + [qw(aaaaaaaa 50505050 + 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)], + [qw(50505050 aaaaaaaa + 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)], + [qw(ffffffff aaaaaaaa + 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)], + [qw(00000001 ffffffff + 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)], + [qw(00000001 fffffff0 + 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)], + + [qw(00_a00000a_aaaaaaa 50505050 + 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)], + [qw(0f_fff0005_0505050 aaaaaaaa + 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)], + [qw(00_000000f_fffffff 01_800000a_aaaaaaa + 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)], + [qw(00_0000000_0000001 ff_fffffff_fffffff + 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)], + [qw(00_0000000_0000001 ff_fffffff_ffffff0 + ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)], + ]; + + $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16); + $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16); + $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16); + if ($error_count > 0) { + print STDERR $error_count, " errors: FAILED\n"; + } else { + print STDERR "PASS\n"; + } + exit ($error_count); +} diff --git a/jemalloc/build-aux/config.guess b/jemalloc/build-aux/config.guess new file mode 100755 index 0000000..2e9ad7f --- /dev/null +++ b/jemalloc/build-aux/config.guess @@ -0,0 +1,1462 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-10-02' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/jemalloc/build-aux/config.sub b/jemalloc/build-aux/config.sub new file mode 100755 index 0000000..dd2ca93 --- /dev/null +++ b/jemalloc/build-aux/config.sub @@ -0,0 +1,1825 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-11-04' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/jemalloc/build-aux/install-sh b/jemalloc/build-aux/install-sh new file mode 100755 index 0000000..ebc6691 --- /dev/null +++ b/jemalloc/build-aux/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/jemalloc/config.stamp.in b/jemalloc/config.stamp.in new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/jemalloc/config.stamp.in diff --git a/jemalloc/configure.ac b/jemalloc/configure.ac new file mode 100644 index 0000000..ea6b756 --- /dev/null +++ b/jemalloc/configure.ac @@ -0,0 +1,2410 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.63) +AC_INIT([Makefile.in]) + +AC_CONFIG_AUX_DIR([build-aux]) + +dnl ============================================================================ +dnl Custom macro definitions. + +dnl JE_CONCAT_VVV(r, a, b) +dnl +dnl Set $r to the concatenation of $a and $b, with a space separating them iff +dnl both $a and $b are non-empty. +AC_DEFUN([JE_CONCAT_VVV], +if test "x[$]{$2}" = "x" -o "x[$]{$3}" = "x" ; then + $1="[$]{$2}[$]{$3}" +else + $1="[$]{$2} [$]{$3}" +fi +) + +dnl JE_APPEND_VS(a, b) +dnl +dnl Set $a to the concatenation of $a and b, with a space separating them iff +dnl both $a and b are non-empty. +AC_DEFUN([JE_APPEND_VS], + T_APPEND_V=$2 + JE_CONCAT_VVV($1, $1, T_APPEND_V) +) + +CONFIGURE_CFLAGS= +SPECIFIED_CFLAGS="${CFLAGS}" +dnl JE_CFLAGS_ADD(cflag) +dnl +dnl CFLAGS is the concatenation of CONFIGURE_CFLAGS and SPECIFIED_CFLAGS +dnl (ignoring EXTRA_CFLAGS, which does not impact configure tests. This macro +dnl appends to CONFIGURE_CFLAGS and regenerates CFLAGS. +AC_DEFUN([JE_CFLAGS_ADD], +[ +AC_MSG_CHECKING([whether compiler supports $1]) +T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}" +JE_APPEND_VS(CONFIGURE_CFLAGS, $1) +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[ +]], [[ + return 0; +]])], + [je_cv_cflags_added=$1] + AC_MSG_RESULT([yes]), + [je_cv_cflags_added=] + AC_MSG_RESULT([no]) + [CONFIGURE_CFLAGS="${T_CONFIGURE_CFLAGS}"] +) +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) +]) + +dnl JE_CFLAGS_SAVE() +dnl JE_CFLAGS_RESTORE() +dnl +dnl Save/restore CFLAGS. Nesting is not supported. +AC_DEFUN([JE_CFLAGS_SAVE], +SAVED_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}" +) +AC_DEFUN([JE_CFLAGS_RESTORE], +CONFIGURE_CFLAGS="${SAVED_CONFIGURE_CFLAGS}" +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) +) + +CONFIGURE_CXXFLAGS= +SPECIFIED_CXXFLAGS="${CXXFLAGS}" +dnl JE_CXXFLAGS_ADD(cxxflag) +AC_DEFUN([JE_CXXFLAGS_ADD], +[ +AC_MSG_CHECKING([whether compiler supports $1]) +T_CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}" +JE_APPEND_VS(CONFIGURE_CXXFLAGS, $1) +JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) +AC_LANG_PUSH([C++]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[ +]], [[ + return 0; +]])], + [je_cv_cxxflags_added=$1] + AC_MSG_RESULT([yes]), + [je_cv_cxxflags_added=] + AC_MSG_RESULT([no]) + [CONFIGURE_CXXFLAGS="${T_CONFIGURE_CXXFLAGS}"] +) +AC_LANG_POP([C++]) +JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) +]) + +dnl JE_COMPILABLE(label, hcode, mcode, rvar) +dnl +dnl Use AC_LINK_IFELSE() rather than AC_COMPILE_IFELSE() so that linker errors +dnl cause failure. +AC_DEFUN([JE_COMPILABLE], +[ +AC_CACHE_CHECK([whether $1 is compilable], + [$4], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([$2], + [$3])], + [$4=yes], + [$4=no])]) +]) + +dnl ============================================================================ + +CONFIG=`echo ${ac_configure_args} | sed -e 's#'"'"'\([^ ]*\)'"'"'#\1#g'` +AC_SUBST([CONFIG]) + +dnl Library revision. +rev=2 +AC_SUBST([rev]) + +srcroot=$srcdir +if test "x${srcroot}" = "x." ; then + srcroot="" +else + srcroot="${srcroot}/" +fi +AC_SUBST([srcroot]) +abs_srcroot="`cd \"${srcdir}\"; pwd`/" +AC_SUBST([abs_srcroot]) + +objroot="" +AC_SUBST([objroot]) +abs_objroot="`pwd`/" +AC_SUBST([abs_objroot]) + +dnl Munge install path variables. +if test "x$prefix" = "xNONE" ; then + prefix="/usr/local" +fi +if test "x$exec_prefix" = "xNONE" ; then + exec_prefix=$prefix +fi +PREFIX=$prefix +AC_SUBST([PREFIX]) +BINDIR=`eval echo $bindir` +BINDIR=`eval echo $BINDIR` +AC_SUBST([BINDIR]) +INCLUDEDIR=`eval echo $includedir` +INCLUDEDIR=`eval echo $INCLUDEDIR` +AC_SUBST([INCLUDEDIR]) +LIBDIR=`eval echo $libdir` +LIBDIR=`eval echo $LIBDIR` +AC_SUBST([LIBDIR]) +DATADIR=`eval echo $datadir` +DATADIR=`eval echo $DATADIR` +AC_SUBST([DATADIR]) +MANDIR=`eval echo $mandir` +MANDIR=`eval echo $MANDIR` +AC_SUBST([MANDIR]) + +dnl Support for building documentation. +AC_PATH_PROG([XSLTPROC], [xsltproc], [false], [$PATH]) +if test -d "/usr/share/xml/docbook/stylesheet/docbook-xsl" ; then + DEFAULT_XSLROOT="/usr/share/xml/docbook/stylesheet/docbook-xsl" +elif test -d "/usr/share/sgml/docbook/xsl-stylesheets" ; then + DEFAULT_XSLROOT="/usr/share/sgml/docbook/xsl-stylesheets" +else + dnl Documentation building will fail if this default gets used. + DEFAULT_XSLROOT="" +fi +AC_ARG_WITH([xslroot], + [AS_HELP_STRING([--with-xslroot=], [XSL stylesheet root path])], [ +if test "x$with_xslroot" = "xno" ; then + XSLROOT="${DEFAULT_XSLROOT}" +else + XSLROOT="${with_xslroot}" +fi +], + XSLROOT="${DEFAULT_XSLROOT}" +) +if test "x$XSLTPROC" = "xfalse" ; then + XSLROOT="" +fi +AC_SUBST([XSLROOT]) + +dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise, +dnl just prevent autoconf from molesting CFLAGS. +CFLAGS=$CFLAGS +AC_PROG_CC + +if test "x$GCC" != "xyes" ; then + AC_CACHE_CHECK([whether compiler is MSVC], + [je_cv_msvc], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [ +#ifndef _MSC_VER + int fail[-1]; +#endif +])], + [je_cv_msvc=yes], + [je_cv_msvc=no])]) +fi + +dnl check if a cray prgenv wrapper compiler is being used +je_cv_cray_prgenv_wrapper="" +if test "x${PE_ENV}" != "x" ; then + case "${CC}" in + CC|cc) + je_cv_cray_prgenv_wrapper="yes" + ;; + *) + ;; + esac +fi + +AC_CACHE_CHECK([whether compiler is cray], + [je_cv_cray], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [ +#ifndef _CRAYC + int fail[-1]; +#endif +])], + [je_cv_cray=yes], + [je_cv_cray=no])]) + +if test "x${je_cv_cray}" = "xyes" ; then + AC_CACHE_CHECK([whether cray compiler version is 8.4], + [je_cv_cray_84], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [ +#if !(_RELEASE_MAJOR == 8 && _RELEASE_MINOR == 4) + int fail[-1]; +#endif +])], + [je_cv_cray_84=yes], + [je_cv_cray_84=no])]) +fi + +if test "x$GCC" = "xyes" ; then + JE_CFLAGS_ADD([-std=gnu11]) + if test "x$je_cv_cflags_added" = "x-std=gnu11" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) + else + JE_CFLAGS_ADD([-std=gnu99]) + if test "x$je_cv_cflags_added" = "x-std=gnu99" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) + fi + fi + JE_CFLAGS_ADD([-Wall]) + JE_CFLAGS_ADD([-Wextra]) + JE_CFLAGS_ADD([-Wshorten-64-to-32]) + JE_CFLAGS_ADD([-Wsign-compare]) + JE_CFLAGS_ADD([-Wundef]) + JE_CFLAGS_ADD([-Wno-format-zero-length]) + JE_CFLAGS_ADD([-pipe]) + JE_CFLAGS_ADD([-g3]) +elif test "x$je_cv_msvc" = "xyes" ; then + CC="$CC -nologo" + JE_CFLAGS_ADD([-Zi]) + JE_CFLAGS_ADD([-MT]) + JE_CFLAGS_ADD([-W3]) + JE_CFLAGS_ADD([-FS]) + JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat) +fi +if test "x$je_cv_cray" = "xyes" ; then + dnl cray compiler 8.4 has an inlining bug + if test "x$je_cv_cray_84" = "xyes" ; then + JE_CFLAGS_ADD([-hipa2]) + JE_CFLAGS_ADD([-hnognu]) + fi + dnl ignore unreachable code warning + JE_CFLAGS_ADD([-hnomessage=128]) + dnl ignore redefinition of "malloc", "free", etc warning + JE_CFLAGS_ADD([-hnomessage=1357]) +fi +AC_SUBST([CONFIGURE_CFLAGS]) +AC_SUBST([SPECIFIED_CFLAGS]) +AC_SUBST([EXTRA_CFLAGS]) +AC_PROG_CPP + +AC_ARG_ENABLE([cxx], + [AS_HELP_STRING([--disable-cxx], [Disable C++ integration])], +if test "x$enable_cxx" = "xno" ; then + enable_cxx="0" +else + enable_cxx="1" +fi +, +enable_cxx="1" +) +if test "x$enable_cxx" = "x1" ; then + dnl Require at least c++14, which is the first version to support sized + dnl deallocation. C++ support is not compiled otherwise. + m4_include([m4/ax_cxx_compile_stdcxx.m4]) + AX_CXX_COMPILE_STDCXX([14], [noext], [optional]) + if test "x${HAVE_CXX14}" = "x1" ; then + JE_CXXFLAGS_ADD([-Wall]) + JE_CXXFLAGS_ADD([-Wextra]) + JE_CXXFLAGS_ADD([-g3]) + + SAVED_LIBS="${LIBS}" + JE_APPEND_VS(LIBS, -lstdc++) + JE_COMPILABLE([libstdc++ linkage], [ +#include +], [[ + int *arr = (int *)malloc(sizeof(int) * 42); + if (arr == NULL) + return 1; +]], [je_cv_libstdcxx]) + if test "x${je_cv_libstdcxx}" = "xno" ; then + LIBS="${SAVED_LIBS}" + fi + else + enable_cxx="0" + fi +fi +AC_SUBST([enable_cxx]) +AC_SUBST([CONFIGURE_CXXFLAGS]) +AC_SUBST([SPECIFIED_CXXFLAGS]) +AC_SUBST([EXTRA_CXXFLAGS]) + +AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) +if test "x${ac_cv_big_endian}" = "x1" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ]) +fi + +if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then + JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat/C99) +fi + +if test "x${je_cv_msvc}" = "xyes" ; then + LG_SIZEOF_PTR=LG_SIZEOF_PTR_WIN + AC_MSG_RESULT([Using a predefined value for sizeof(void *): 4 for 32-bit, 8 for 64-bit]) +else + AC_CHECK_SIZEOF([void *]) + if test "x${ac_cv_sizeof_void_p}" = "x8" ; then + LG_SIZEOF_PTR=3 + elif test "x${ac_cv_sizeof_void_p}" = "x4" ; then + LG_SIZEOF_PTR=2 + else + AC_MSG_ERROR([Unsupported pointer size: ${ac_cv_sizeof_void_p}]) + fi +fi +AC_DEFINE_UNQUOTED([LG_SIZEOF_PTR], [$LG_SIZEOF_PTR]) + +AC_CHECK_SIZEOF([int]) +if test "x${ac_cv_sizeof_int}" = "x8" ; then + LG_SIZEOF_INT=3 +elif test "x${ac_cv_sizeof_int}" = "x4" ; then + LG_SIZEOF_INT=2 +else + AC_MSG_ERROR([Unsupported int size: ${ac_cv_sizeof_int}]) +fi +AC_DEFINE_UNQUOTED([LG_SIZEOF_INT], [$LG_SIZEOF_INT]) + +AC_CHECK_SIZEOF([long]) +if test "x${ac_cv_sizeof_long}" = "x8" ; then + LG_SIZEOF_LONG=3 +elif test "x${ac_cv_sizeof_long}" = "x4" ; then + LG_SIZEOF_LONG=2 +else + AC_MSG_ERROR([Unsupported long size: ${ac_cv_sizeof_long}]) +fi +AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG], [$LG_SIZEOF_LONG]) + +AC_CHECK_SIZEOF([long long]) +if test "x${ac_cv_sizeof_long_long}" = "x8" ; then + LG_SIZEOF_LONG_LONG=3 +elif test "x${ac_cv_sizeof_long_long}" = "x4" ; then + LG_SIZEOF_LONG_LONG=2 +else + AC_MSG_ERROR([Unsupported long long size: ${ac_cv_sizeof_long_long}]) +fi +AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG_LONG], [$LG_SIZEOF_LONG_LONG]) + +AC_CHECK_SIZEOF([intmax_t]) +if test "x${ac_cv_sizeof_intmax_t}" = "x16" ; then + LG_SIZEOF_INTMAX_T=4 +elif test "x${ac_cv_sizeof_intmax_t}" = "x8" ; then + LG_SIZEOF_INTMAX_T=3 +elif test "x${ac_cv_sizeof_intmax_t}" = "x4" ; then + LG_SIZEOF_INTMAX_T=2 +else + AC_MSG_ERROR([Unsupported intmax_t size: ${ac_cv_sizeof_intmax_t}]) +fi +AC_DEFINE_UNQUOTED([LG_SIZEOF_INTMAX_T], [$LG_SIZEOF_INTMAX_T]) + +AC_CANONICAL_HOST +dnl CPU-specific settings. +CPU_SPINWAIT="" +case "${host_cpu}" in + i686|x86_64) + HAVE_CPU_SPINWAIT=1 + if test "x${je_cv_msvc}" = "xyes" ; then + AC_CACHE_VAL([je_cv_pause_msvc], + [JE_COMPILABLE([pause instruction MSVC], [], + [[_mm_pause(); return 0;]], + [je_cv_pause_msvc])]) + if test "x${je_cv_pause_msvc}" = "xyes" ; then + CPU_SPINWAIT='_mm_pause()' + fi + else + AC_CACHE_VAL([je_cv_pause], + [JE_COMPILABLE([pause instruction], [], + [[__asm__ volatile("pause"); return 0;]], + [je_cv_pause])]) + if test "x${je_cv_pause}" = "xyes" ; then + CPU_SPINWAIT='__asm__ volatile("pause")' + fi + fi + ;; + *) + HAVE_CPU_SPINWAIT=0 + ;; +esac +AC_DEFINE_UNQUOTED([HAVE_CPU_SPINWAIT], [$HAVE_CPU_SPINWAIT]) +AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT]) + +AC_ARG_WITH([lg_vaddr], + [AS_HELP_STRING([--with-lg-vaddr=], [Number of significant virtual address bits])], + [LG_VADDR="$with_lg_vaddr"], [LG_VADDR="detect"]) + +case "${host_cpu}" in + aarch64) + if test "x$LG_VADDR" = "xdetect"; then + AC_MSG_CHECKING([number of significant virtual address bits]) + if test "x${LG_SIZEOF_PTR}" = "x2" ; then + #aarch64 ILP32 + LG_VADDR=32 + else + #aarch64 LP64 + LG_VADDR=48 + fi + AC_MSG_RESULT([$LG_VADDR]) + fi + ;; + x86_64) + if test "x$LG_VADDR" = "xdetect"; then + AC_CACHE_CHECK([number of significant virtual address bits], + [je_cv_lg_vaddr], + AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include +#ifdef _WIN32 +#include +#include +typedef unsigned __int32 uint32_t; +#else +#include +#endif +]], [[ + uint32_t r[[4]]; + uint32_t eax_in = 0x80000008U; +#ifdef _WIN32 + __cpuid((int *)r, (int)eax_in); +#else + asm volatile ("cpuid" + : "=a" (r[[0]]), "=b" (r[[1]]), "=c" (r[[2]]), "=d" (r[[3]]) + : "a" (eax_in), "c" (0) + ); +#endif + uint32_t eax_out = r[[0]]; + uint32_t vaddr = ((eax_out & 0x0000ff00U) >> 8); + FILE *f = fopen("conftest.out", "w"); + if (f == NULL) { + return 1; + } + if (vaddr > (sizeof(void *) << 3)) { + vaddr = sizeof(void *) << 3; + } + fprintf(f, "%u", vaddr); + fclose(f); + return 0; +]])], + [je_cv_lg_vaddr=`cat conftest.out`], + [je_cv_lg_vaddr=error], + [je_cv_lg_vaddr=57])) + if test "x${je_cv_lg_vaddr}" != "x" ; then + LG_VADDR="${je_cv_lg_vaddr}" + fi + if test "x${LG_VADDR}" != "xerror" ; then + AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) + else + AC_MSG_ERROR([cannot determine number of significant virtual address bits]) + fi + fi + ;; + *) + if test "x$LG_VADDR" = "xdetect"; then + AC_MSG_CHECKING([number of significant virtual address bits]) + if test "x${LG_SIZEOF_PTR}" = "x3" ; then + LG_VADDR=64 + elif test "x${LG_SIZEOF_PTR}" = "x2" ; then + LG_VADDR=32 + elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then + LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))" + else + AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}]) + fi + AC_MSG_RESULT([$LG_VADDR]) + fi + ;; +esac +AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) + +LD_PRELOAD_VAR="LD_PRELOAD" +so="so" +importlib="${so}" +o="$ac_objext" +a="a" +exe="$ac_exeext" +libprefix="lib" +link_whole_archive="0" +DSO_LDFLAGS='-shared -Wl,-soname,$(@F)' +RPATH='-Wl,-rpath,$(1)' +SOREV="${so}.${rev}" +PIC_CFLAGS='-fPIC -DPIC' +CTARGET='-o $@' +LDTARGET='-o $@' +TEST_LD_MODE= +EXTRA_LDFLAGS= +ARFLAGS='crus' +AROUT=' $@' +CC_MM=1 + +if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then + TEST_LD_MODE='-dynamic' +fi + +if test "x${je_cv_cray}" = "xyes" ; then + CC_MM= +fi + +AN_MAKEVAR([AR], [AC_PROG_AR]) +AN_PROGRAM([ar], [AC_PROG_AR]) +AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) +AC_PROG_AR + +AN_MAKEVAR([NM], [AC_PROG_NM]) +AN_PROGRAM([nm], [AC_PROG_NM]) +AC_DEFUN([AC_PROG_NM], [AC_CHECK_TOOL(NM, nm, :)]) +AC_PROG_NM + +AC_PROG_AWK + +dnl ============================================================================ +dnl jemalloc version. +dnl + +AC_ARG_WITH([version], + [AS_HELP_STRING([--with-version=..--g], + [Version string])], + [ + echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null + if test $? -eq 0 ; then + echo "$with_version" > "${objroot}VERSION" + else + echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null + if test $? -ne 0 ; then + AC_MSG_ERROR([${with_version} does not match ..--g or VERSION]) + fi + fi + ], [ + dnl Set VERSION if source directory is inside a git repository. + if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then + dnl Pattern globs aren't powerful enough to match both single- and + dnl double-digit version numbers, so iterate over patterns to support up + dnl to version 99.99.99 without any accidental matches. + for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \ + '[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \ + '[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \ + '[0-9][0-9].[0-9][0-9].[0-9]' \ + '[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do + (test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null + if test $? -eq 0 ; then + mv "${objroot}VERSION.tmp" "${objroot}VERSION" + break + fi + done + fi + rm -f "${objroot}VERSION.tmp" + ]) + +if test ! -e "${objroot}VERSION" ; then + if test ! -e "${srcroot}VERSION" ; then + AC_MSG_RESULT( + [Missing VERSION file, and unable to generate it; creating bogus VERSION]) + echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION" + else + cp ${srcroot}VERSION ${objroot}VERSION + fi +fi +jemalloc_version=`cat "${objroot}VERSION"` +jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'` +jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'` +jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'` +jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'` +jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'` +AC_SUBST([jemalloc_version]) +AC_SUBST([jemalloc_version_major]) +AC_SUBST([jemalloc_version_minor]) +AC_SUBST([jemalloc_version_bugfix]) +AC_SUBST([jemalloc_version_nrev]) +AC_SUBST([jemalloc_version_gid]) + +dnl Platform-specific settings. abi and RPATH can probably be determined +dnl programmatically, but doing so is error-prone, which makes it generally +dnl not worth the trouble. +dnl +dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the +dnl definitions need to be seen before any headers are included, which is a pain +dnl to make happen otherwise. +default_retain="0" +maps_coalesce="1" +DUMP_SYMS="${NM} -a" +SYM_PREFIX="" +case "${host}" in + *-*-darwin* | *-*-ios*) + abi="macho" + RPATH="" + LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + so="dylib" + importlib="${so}" + force_tls="0" + DSO_LDFLAGS='-shared -Wl,-install_name,$(LIBDIR)/$(@F)' + SOREV="${rev}.${so}" + sbrk_deprecated="1" + SYM_PREFIX="_" + ;; + *-*-freebsd*) + abi="elf" + AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) + force_lazy_lock="1" + ;; + *-*-dragonfly*) + abi="elf" + ;; + *-*-openbsd*) + abi="elf" + force_tls="0" + ;; + *-*-bitrig*) + abi="elf" + ;; + *-*-linux-android) + dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. + JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) + abi="elf" + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ]) + AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) + AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) + AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) + AC_DEFINE([JEMALLOC_C11_ATOMICS]) + force_tls="0" + if test "${LG_SIZEOF_PTR}" = "3"; then + default_retain="1" + fi + ;; + *-*-linux*) + dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. + JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) + abi="elf" + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ]) + AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) + AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) + AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) + AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) + if test "${LG_SIZEOF_PTR}" = "3"; then + default_retain="1" + fi + ;; + *-*-kfreebsd*) + dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. + JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) + abi="elf" + AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) + AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) + AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) + AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) + ;; + *-*-netbsd*) + AC_MSG_CHECKING([ABI]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[#ifdef __ELF__ +/* ELF */ +#else +#error aout +#endif +]])], + [abi="elf"], + [abi="aout"]) + AC_MSG_RESULT([$abi]) + ;; + *-*-solaris2*) + abi="elf" + RPATH='-Wl,-R,$(1)' + dnl Solaris needs this for sigwait(). + JE_APPEND_VS(CPPFLAGS, -D_POSIX_PTHREAD_SEMANTICS) + JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl) + ;; + *-ibm-aix*) + if test "${LG_SIZEOF_PTR}" = "3"; then + dnl 64bit AIX + LD_PRELOAD_VAR="LDR_PRELOAD64" + else + dnl 32bit AIX + LD_PRELOAD_VAR="LDR_PRELOAD" + fi + abi="xcoff" + ;; + *-*-mingw* | *-*-cygwin*) + abi="pecoff" + force_tls="0" + maps_coalesce="0" + RPATH="" + so="dll" + if test "x$je_cv_msvc" = "xyes" ; then + importlib="lib" + DSO_LDFLAGS="-LD" + EXTRA_LDFLAGS="-link -DEBUG" + CTARGET='-Fo$@' + LDTARGET='-Fe$@' + AR='lib' + ARFLAGS='-nologo -out:' + AROUT='$@' + CC_MM= + else + importlib="${so}" + DSO_LDFLAGS="-shared" + link_whole_archive="1" + fi + case "${host}" in + *-*-cygwin*) + DUMP_SYMS="dumpbin /SYMBOLS" + ;; + *) + ;; + esac + a="lib" + libprefix="" + SOREV="${so}" + PIC_CFLAGS="" + if test "${LG_SIZEOF_PTR}" = "3"; then + default_retain="1" + fi + ;; + *) + AC_MSG_RESULT([Unsupported operating system: ${host}]) + abi="elf" + ;; +esac + +JEMALLOC_USABLE_SIZE_CONST=const +AC_CHECK_HEADERS([malloc.h], [ + AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [#include + #include + size_t malloc_usable_size(const void *ptr); + ], + [])],[ + AC_MSG_RESULT([yes]) + ],[ + JEMALLOC_USABLE_SIZE_CONST= + AC_MSG_RESULT([no]) + ]) +]) +AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST]) +AC_SUBST([abi]) +AC_SUBST([RPATH]) +AC_SUBST([LD_PRELOAD_VAR]) +AC_SUBST([so]) +AC_SUBST([importlib]) +AC_SUBST([o]) +AC_SUBST([a]) +AC_SUBST([exe]) +AC_SUBST([libprefix]) +AC_SUBST([link_whole_archive]) +AC_SUBST([DSO_LDFLAGS]) +AC_SUBST([EXTRA_LDFLAGS]) +AC_SUBST([SOREV]) +AC_SUBST([PIC_CFLAGS]) +AC_SUBST([CTARGET]) +AC_SUBST([LDTARGET]) +AC_SUBST([TEST_LD_MODE]) +AC_SUBST([MKLIB]) +AC_SUBST([ARFLAGS]) +AC_SUBST([AROUT]) +AC_SUBST([DUMP_SYMS]) +AC_SUBST([CC_MM]) + +dnl Determine whether libm must be linked to use e.g. log(3). +AC_SEARCH_LIBS([log], [m], , [AC_MSG_ERROR([Missing math functions])]) +if test "x$ac_cv_search_log" != "xnone required" ; then + LM="$ac_cv_search_log" +else + LM= +fi +AC_SUBST(LM) + +JE_COMPILABLE([__attribute__ syntax], + [static __attribute__((unused)) void foo(void){}], + [], + [je_cv_attribute]) +if test "x${je_cv_attribute}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ]) + if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then + JE_CFLAGS_ADD([-fvisibility=hidden]) + JE_CXXFLAGS_ADD([-fvisibility=hidden]) + fi +fi +dnl Check for tls_model attribute support (clang 3.0 still lacks support). +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([tls_model attribute], [], + [static __thread int + __attribute__((tls_model("initial-exec"), unused)) foo; + foo = 0;], + [je_cv_tls_model]) +JE_CFLAGS_RESTORE() +dnl (Setting of JEMALLOC_TLS_MODEL is done later, after we've checked for +dnl --disable-initial-exec-tls) + +dnl Check for alloc_size attribute support. +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([alloc_size attribute], [#include ], + [void *foo(size_t size) __attribute__((alloc_size(1)));], + [je_cv_alloc_size]) +JE_CFLAGS_RESTORE() +if test "x${je_cv_alloc_size}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ]) +fi +dnl Check for format(gnu_printf, ...) attribute support. +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include ], + [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));], + [je_cv_format_gnu_printf]) +JE_CFLAGS_RESTORE() +if test "x${je_cv_format_gnu_printf}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ]) +fi +dnl Check for format(printf, ...) attribute support. +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([format(printf, ...) attribute], [#include ], + [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));], + [je_cv_format_printf]) +JE_CFLAGS_RESTORE() +if test "x${je_cv_format_printf}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ]) +fi + +dnl Check for format_arg(...) attribute support. +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([format(printf, ...) attribute], [#include ], + [const char * __attribute__((__format_arg__(1))) foo(const char *format);], + [je_cv_format_arg]) +JE_CFLAGS_RESTORE() +if test "x${je_cv_format_arg}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ]) +fi + +dnl Support optional additions to rpath. +AC_ARG_WITH([rpath], + [AS_HELP_STRING([--with-rpath=], [Colon-separated rpath (ELF systems only)])], +if test "x$with_rpath" = "xno" ; then + RPATH_EXTRA= +else + RPATH_EXTRA="`echo $with_rpath | tr \":\" \" \"`" +fi, + RPATH_EXTRA= +) +AC_SUBST([RPATH_EXTRA]) + +dnl Disable rules that do automatic regeneration of configure output by default. +AC_ARG_ENABLE([autogen], + [AS_HELP_STRING([--enable-autogen], [Automatically regenerate configure output])], +if test "x$enable_autogen" = "xno" ; then + enable_autogen="0" +else + enable_autogen="1" +fi +, +enable_autogen="0" +) +AC_SUBST([enable_autogen]) + +AC_PROG_INSTALL +AC_PROG_RANLIB +AC_PATH_PROG([LD], [ld], [false], [$PATH]) +AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH]) + +dnl Enable documentation +AC_ARG_ENABLE([doc], + [AS_HELP_STRING([--enable-documentation], [Build documentation])], +if test "x$enable_doc" = "xno" ; then + enable_doc="0" +else + enable_doc="1" +fi +, +enable_doc="1" +) +AC_SUBST([enable_doc]) + +dnl Enable shared libs +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared], [Build shared libaries])], +if test "x$enable_shared" = "xno" ; then + enable_shared="0" +else + enable_shared="1" +fi +, +enable_shared="1" +) +AC_SUBST([enable_shared]) + +dnl Enable static libs +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static], [Build static libaries])], +if test "x$enable_static" = "xno" ; then + enable_static="0" +else + enable_static="1" +fi +, +enable_static="1" +) +AC_SUBST([enable_static]) + +if test "$enable_shared$enable_static" = "00" ; then + AC_MSG_ERROR([Please enable one of shared or static builds]) +fi + +dnl Perform no name mangling by default. +AC_ARG_WITH([mangling], + [AS_HELP_STRING([--with-mangling=], [Mangle symbols in ])], + [mangling_map="$with_mangling"], [mangling_map=""]) + +dnl Do not prefix public APIs by default. +AC_ARG_WITH([jemalloc_prefix], + [AS_HELP_STRING([--with-jemalloc-prefix=], [Prefix to prepend to all public APIs])], + [JEMALLOC_PREFIX="$with_jemalloc_prefix"], + [if test "x$abi" != "xmacho" -a "x$abi" != "xpecoff"; then + JEMALLOC_PREFIX="" +else + JEMALLOC_PREFIX="je_" +fi] +) +if test "x$JEMALLOC_PREFIX" = "x" ; then + AC_DEFINE([JEMALLOC_IS_MALLOC]) +else + JEMALLOC_CPREFIX=`echo ${JEMALLOC_PREFIX} | tr "a-z" "A-Z"` + AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"]) + AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"]) +fi +AC_SUBST([JEMALLOC_PREFIX]) +AC_SUBST([JEMALLOC_CPREFIX]) + +AC_ARG_WITH([export], + [AS_HELP_STRING([--without-export], [disable exporting jemalloc public APIs])], + [if test "x$with_export" = "xno"; then + AC_DEFINE([JEMALLOC_EXPORT],[]) +fi] +) + +public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx" +dnl Check for additional platform-specific public API functions. +AC_CHECK_FUNC([memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ]) + public_syms="${public_syms} memalign"]) +AC_CHECK_FUNC([valloc], + [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) + public_syms="${public_syms} valloc"]) + +dnl Check for allocator-related functions that should be wrapped. +wrap_syms= +if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_CHECK_FUNC([__libc_calloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_CALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_calloc"]) + AC_CHECK_FUNC([__libc_free], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ]) + wrap_syms="${wrap_syms} __libc_free"]) + AC_CHECK_FUNC([__libc_malloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_malloc"]) + AC_CHECK_FUNC([__libc_memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MEMALIGN], [ ]) + wrap_syms="${wrap_syms} __libc_memalign"]) + AC_CHECK_FUNC([__libc_realloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_REALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_realloc"]) + AC_CHECK_FUNC([__libc_valloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_VALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_valloc"]) + AC_CHECK_FUNC([__posix_memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE___POSIX_MEMALIGN], [ ]) + wrap_syms="${wrap_syms} __posix_memalign"]) +fi + +case "${host}" in + *-*-mingw* | *-*-cygwin*) + wrap_syms="${wrap_syms} tls_callback" + ;; + *) + ;; +esac + +dnl Mangle library-private APIs. +AC_ARG_WITH([private_namespace], + [AS_HELP_STRING([--with-private-namespace=], [Prefix to prepend to all library-private APIs])], + [JEMALLOC_PRIVATE_NAMESPACE="${with_private_namespace}je_"], + [JEMALLOC_PRIVATE_NAMESPACE="je_"] +) +AC_DEFINE_UNQUOTED([JEMALLOC_PRIVATE_NAMESPACE], [$JEMALLOC_PRIVATE_NAMESPACE]) +private_namespace="$JEMALLOC_PRIVATE_NAMESPACE" +AC_SUBST([private_namespace]) + +dnl Do not add suffix to installed files by default. +AC_ARG_WITH([install_suffix], + [AS_HELP_STRING([--with-install-suffix=], [Suffix to append to all installed files])], + [INSTALL_SUFFIX="$with_install_suffix"], + [INSTALL_SUFFIX=] +) +install_suffix="$INSTALL_SUFFIX" +AC_SUBST([install_suffix]) + +dnl Specify default malloc_conf. +AC_ARG_WITH([malloc_conf], + [AS_HELP_STRING([--with-malloc-conf=], [config.malloc_conf options string])], + [JEMALLOC_CONFIG_MALLOC_CONF="$with_malloc_conf"], + [JEMALLOC_CONFIG_MALLOC_CONF=""] +) +config_malloc_conf="$JEMALLOC_CONFIG_MALLOC_CONF" +AC_DEFINE_UNQUOTED([JEMALLOC_CONFIG_MALLOC_CONF], ["$config_malloc_conf"]) + +dnl Substitute @je_@ in jemalloc_protos.h.in, primarily to make generation of +dnl jemalloc_protos_jet.h easy. +je_="je_" +AC_SUBST([je_]) + +cfgoutputs_in="Makefile.in" +cfgoutputs_in="${cfgoutputs_in} jemalloc.pc.in" +cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" +cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" +cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_preamble.h.in" +cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" +cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" + +cfgoutputs_out="Makefile" +cfgoutputs_out="${cfgoutputs_out} jemalloc.pc" +cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" +cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" +cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_preamble.h" +cfgoutputs_out="${cfgoutputs_out} test/test.sh" +cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h" + +cfgoutputs_tup="Makefile" +cfgoutputs_tup="${cfgoutputs_tup} jemalloc.pc:jemalloc.pc.in" +cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in" +cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" +cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_preamble.h" +cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" +cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" + +cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh" +cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh" +cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" + +cfghdrs_out="include/jemalloc/jemalloc_defs.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols.awk" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle_jet.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/jemalloc_internal_defs.h" +cfghdrs_out="${cfghdrs_out} test/include/test/jemalloc_test_defs.h" + +cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.in" +cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" +cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" + +dnl ============================================================================ +dnl jemalloc build options. +dnl + +dnl Do not compile with debugging by default. +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [Build debugging code])], +[if test "x$enable_debug" = "xno" ; then + enable_debug="0" +else + enable_debug="1" +fi +], +[enable_debug="0"] +) +if test "x$enable_debug" = "x1" ; then + AC_DEFINE([JEMALLOC_DEBUG], [ ]) +fi +if test "x$enable_debug" = "x1" ; then + AC_DEFINE([JEMALLOC_DEBUG], [ ]) +fi +AC_SUBST([enable_debug]) + +dnl Only optimize if not debugging. +if test "x$enable_debug" = "x0" ; then + if test "x$GCC" = "xyes" ; then + JE_CFLAGS_ADD([-O3]) + JE_CXXFLAGS_ADD([-O3]) + JE_CFLAGS_ADD([-funroll-loops]) + elif test "x$je_cv_msvc" = "xyes" ; then + JE_CFLAGS_ADD([-O2]) + JE_CXXFLAGS_ADD([-O2]) + else + JE_CFLAGS_ADD([-O]) + JE_CXXFLAGS_ADD([-O]) + fi +fi + +dnl Enable statistics calculation by default. +AC_ARG_ENABLE([stats], + [AS_HELP_STRING([--disable-stats], + [Disable statistics calculation/reporting])], +[if test "x$enable_stats" = "xno" ; then + enable_stats="0" +else + enable_stats="1" +fi +], +[enable_stats="1"] +) +if test "x$enable_stats" = "x1" ; then + AC_DEFINE([JEMALLOC_STATS], [ ]) +fi +AC_SUBST([enable_stats]) + +dnl Do not enable smallocx by default. +AC_ARG_ENABLE([experimental_smallocx], + [AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])], +[if test "x$enable_experimental_smallocx" = "xno" ; then +enable_experimental_smallocx="0" +else +enable_experimental_smallocx="1" +fi +], +[enable_experimental_smallocx="0"] +) +if test "x$enable_experimental_smallocx" = "x1" ; then + AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API]) +fi +AC_SUBST([enable_experimental_smallocx]) + +dnl Do not enable profiling by default. +AC_ARG_ENABLE([prof], + [AS_HELP_STRING([--enable-prof], [Enable allocation profiling])], +[if test "x$enable_prof" = "xno" ; then + enable_prof="0" +else + enable_prof="1" +fi +], +[enable_prof="0"] +) +if test "x$enable_prof" = "x1" ; then + backtrace_method="" +else + backtrace_method="N/A" +fi + +AC_ARG_ENABLE([prof-libunwind], + [AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])], +[if test "x$enable_prof_libunwind" = "xno" ; then + enable_prof_libunwind="0" +else + enable_prof_libunwind="1" +fi +], +[enable_prof_libunwind="0"] +) +AC_ARG_WITH([static_libunwind], + [AS_HELP_STRING([--with-static-libunwind=], + [Path to static libunwind library; use rather than dynamically linking])], +if test "x$with_static_libunwind" = "xno" ; then + LUNWIND="-lunwind" +else + if test ! -f "$with_static_libunwind" ; then + AC_MSG_ERROR([Static libunwind not found: $with_static_libunwind]) + fi + LUNWIND="$with_static_libunwind" +fi, + LUNWIND="-lunwind" +) +if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then + AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"]) + if test "x$LUNWIND" = "x-lunwind" ; then + AC_CHECK_LIB([unwind], [unw_backtrace], [JE_APPEND_VS(LIBS, $LUNWIND)], + [enable_prof_libunwind="0"]) + else + JE_APPEND_VS(LIBS, $LUNWIND) + fi + if test "x${enable_prof_libunwind}" = "x1" ; then + backtrace_method="libunwind" + AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ]) + fi +fi + +AC_ARG_ENABLE([prof-libgcc], + [AS_HELP_STRING([--disable-prof-libgcc], + [Do not use libgcc for backtracing])], +[if test "x$enable_prof_libgcc" = "xno" ; then + enable_prof_libgcc="0" +else + enable_prof_libgcc="1" +fi +], +[enable_prof_libgcc="1"] +) +if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \ + -a "x$GCC" = "xyes" ; then + AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"]) + if test "x${enable_prof_libgcc}" = "x1" ; then + AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"]) + fi + if test "x${enable_prof_libgcc}" = "x1" ; then + backtrace_method="libgcc" + AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ]) + fi +else + enable_prof_libgcc="0" +fi + +AC_ARG_ENABLE([prof-gcc], + [AS_HELP_STRING([--disable-prof-gcc], + [Do not use gcc intrinsics for backtracing])], +[if test "x$enable_prof_gcc" = "xno" ; then + enable_prof_gcc="0" +else + enable_prof_gcc="1" +fi +], +[enable_prof_gcc="1"] +) +if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \ + -a "x$GCC" = "xyes" ; then + JE_CFLAGS_ADD([-fno-omit-frame-pointer]) + backtrace_method="gcc intrinsics" + AC_DEFINE([JEMALLOC_PROF_GCC], [ ]) +else + enable_prof_gcc="0" +fi + +if test "x$backtrace_method" = "x" ; then + backtrace_method="none (disabling profiling)" + enable_prof="0" +fi +AC_MSG_CHECKING([configured backtracing method]) +AC_MSG_RESULT([$backtrace_method]) +if test "x$enable_prof" = "x1" ; then + dnl Heap profiling uses the log(3) function. + JE_APPEND_VS(LIBS, $LM) + + AC_DEFINE([JEMALLOC_PROF], [ ]) +fi +AC_SUBST([enable_prof]) + +dnl Indicate whether adjacent virtual memory mappings automatically coalesce +dnl (and fragment on demand). +if test "x${maps_coalesce}" = "x1" ; then + AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ]) +fi + +dnl Indicate whether to retain memory (rather than using munmap()) by default. +if test "x$default_retain" = "x1" ; then + AC_DEFINE([JEMALLOC_RETAIN], [ ]) +fi + +dnl Enable allocation from DSS if supported by the OS. +have_dss="1" +dnl Check whether the BSD/SUSv1 sbrk() exists. If not, disable DSS support. +AC_CHECK_FUNC([sbrk], [have_sbrk="1"], [have_sbrk="0"]) +if test "x$have_sbrk" = "x1" ; then + if test "x$sbrk_deprecated" = "x1" ; then + AC_MSG_RESULT([Disabling dss allocation because sbrk is deprecated]) + have_dss="0" + fi +else + have_dss="0" +fi + +if test "x$have_dss" = "x1" ; then + AC_DEFINE([JEMALLOC_DSS], [ ]) +fi + +dnl Support the junk/zero filling option by default. +AC_ARG_ENABLE([fill], + [AS_HELP_STRING([--disable-fill], [Disable support for junk/zero filling])], +[if test "x$enable_fill" = "xno" ; then + enable_fill="0" +else + enable_fill="1" +fi +], +[enable_fill="1"] +) +if test "x$enable_fill" = "x1" ; then + AC_DEFINE([JEMALLOC_FILL], [ ]) +fi +AC_SUBST([enable_fill]) + +dnl Disable utrace(2)-based tracing by default. +AC_ARG_ENABLE([utrace], + [AS_HELP_STRING([--enable-utrace], [Enable utrace(2)-based tracing])], +[if test "x$enable_utrace" = "xno" ; then + enable_utrace="0" +else + enable_utrace="1" +fi +], +[enable_utrace="0"] +) +JE_COMPILABLE([utrace(2)], [ +#include +#include +#include +#include +#include +], [ + utrace((void *)0, 0); +], [je_cv_utrace]) +if test "x${je_cv_utrace}" = "xno" ; then + enable_utrace="0" +fi +if test "x$enable_utrace" = "x1" ; then + AC_DEFINE([JEMALLOC_UTRACE], [ ]) +fi +AC_SUBST([enable_utrace]) + +dnl Do not support the xmalloc option by default. +AC_ARG_ENABLE([xmalloc], + [AS_HELP_STRING([--enable-xmalloc], [Support xmalloc option])], +[if test "x$enable_xmalloc" = "xno" ; then + enable_xmalloc="0" +else + enable_xmalloc="1" +fi +], +[enable_xmalloc="0"] +) +if test "x$enable_xmalloc" = "x1" ; then + AC_DEFINE([JEMALLOC_XMALLOC], [ ]) +fi +AC_SUBST([enable_xmalloc]) + +dnl Support cache-oblivious allocation alignment by default. +AC_ARG_ENABLE([cache-oblivious], + [AS_HELP_STRING([--disable-cache-oblivious], + [Disable support for cache-oblivious allocation alignment])], +[if test "x$enable_cache_oblivious" = "xno" ; then + enable_cache_oblivious="0" +else + enable_cache_oblivious="1" +fi +], +[enable_cache_oblivious="1"] +) +if test "x$enable_cache_oblivious" = "x1" ; then + AC_DEFINE([JEMALLOC_CACHE_OBLIVIOUS], [ ]) +fi +AC_SUBST([enable_cache_oblivious]) + +dnl Do not log by default. +AC_ARG_ENABLE([log], + [AS_HELP_STRING([--enable-log], [Support debug logging])], +[if test "x$enable_log" = "xno" ; then + enable_log="0" +else + enable_log="1" +fi +], +[enable_log="0"] +) +if test "x$enable_log" = "x1" ; then + AC_DEFINE([JEMALLOC_LOG], [ ]) +fi +AC_SUBST([enable_log]) + +dnl Do not use readlinkat by default +AC_ARG_ENABLE([readlinkat], + [AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])], +[if test "x$enable_readlinkat" = "xno" ; then + enable_readlinkat="0" +else + enable_readlinkat="1" +fi +], +[enable_readlinkat="0"] +) +if test "x$enable_readlinkat" = "x1" ; then + AC_DEFINE([JEMALLOC_READLINKAT], [ ]) +fi +AC_SUBST([enable_readlinkat]) + +dnl Avoid extra safety checks by default +AC_ARG_ENABLE([opt-safety-checks], + [AS_HELP_STRING([--enable-opt-safety-checks], + [Perform certain low-overhead checks, even in opt mode])], +[if test "x$enable_opt_safety_checks" = "xno" ; then + enable_opt_safety_checks="0" +else + enable_opt_safety_checks="1" +fi +], +[enable_opt_safety_checks="0"] +) +if test "x$enable_opt_safety_checks" = "x1" ; then + AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ]) +fi +AC_SUBST([enable_opt_safety_checks]) + +JE_COMPILABLE([a program using __builtin_unreachable], [ +void foo (void) { + __builtin_unreachable(); +} +], [ + { + foo(); + } +], [je_cv_gcc_builtin_unreachable]) +if test "x${je_cv_gcc_builtin_unreachable}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [__builtin_unreachable]) +else + AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [abort]) +fi + +dnl ============================================================================ +dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. +dnl One of those two functions should (theoretically) exist on all platforms +dnl that jemalloc currently has a chance of functioning on without modification. +dnl We additionally assume ffs[ll]() or __builtin_ffs[ll]() are defined if +dnl ffsl() or __builtin_ffsl() are defined, respectively. +JE_COMPILABLE([a program using __builtin_ffsl], [ +#include +#include +#include +], [ + { + int rv = __builtin_ffsl(0x08); + printf("%d\n", rv); + } +], [je_cv_gcc_builtin_ffsl]) +if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [__builtin_ffsll]) + AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) + AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) +else + JE_COMPILABLE([a program using ffsl], [ + #include + #include + #include + ], [ + { + int rv = ffsl(0x08); + printf("%d\n", rv); + } + ], [je_cv_function_ffsl]) + if test "x${je_cv_function_ffsl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [ffsll]) + AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) + AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) + else + AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) + fi +fi + +JE_COMPILABLE([a program using __builtin_popcountl], [ +#include +#include +#include +], [ + { + int rv = __builtin_popcountl(0x08); + printf("%d\n", rv); + } +], [je_cv_gcc_builtin_popcountl]) +if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount]) + AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl]) +fi + +AC_ARG_WITH([lg_quantum], + [AS_HELP_STRING([--with-lg-quantum=], + [Base 2 log of minimum allocation alignment])], + [LG_QUANTA="$with_lg_quantum"], + [LG_QUANTA="3 4"]) +if test "x$with_lg_quantum" != "x" ; then + AC_DEFINE_UNQUOTED([LG_QUANTUM], [$with_lg_quantum]) +fi + +AC_ARG_WITH([lg_page], + [AS_HELP_STRING([--with-lg-page=], [Base 2 log of system page size])], + [LG_PAGE="$with_lg_page"], [LG_PAGE="detect"]) +if test "x$LG_PAGE" = "xdetect"; then + AC_CACHE_CHECK([LG_PAGE], + [je_cv_lg_page], + AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#include +]], +[[ + int result; + FILE *f; + +#ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + result = si.dwPageSize; +#else + result = sysconf(_SC_PAGESIZE); +#endif + if (result == -1) { + return 1; + } + result = JEMALLOC_INTERNAL_FFSL(result) - 1; + + f = fopen("conftest.out", "w"); + if (f == NULL) { + return 1; + } + fprintf(f, "%d", result); + fclose(f); + + return 0; +]])], + [je_cv_lg_page=`cat conftest.out`], + [je_cv_lg_page=undefined], + [je_cv_lg_page=12])) +fi +if test "x${je_cv_lg_page}" != "x" ; then + LG_PAGE="${je_cv_lg_page}" +fi +if test "x${LG_PAGE}" != "xundefined" ; then + AC_DEFINE_UNQUOTED([LG_PAGE], [$LG_PAGE]) +else + AC_MSG_ERROR([cannot determine value for LG_PAGE]) +fi + +AC_ARG_WITH([lg_hugepage], + [AS_HELP_STRING([--with-lg-hugepage=], + [Base 2 log of system huge page size])], + [je_cv_lg_hugepage="${with_lg_hugepage}"], + [je_cv_lg_hugepage=""]) +if test "x${je_cv_lg_hugepage}" = "x" ; then + dnl Look in /proc/meminfo (Linux-specific) for information on the default huge + dnl page size, if any. The relevant line looks like: + dnl + dnl Hugepagesize: 2048 kB + if test -e "/proc/meminfo" ; then + hpsk=[`cat /proc/meminfo 2>/dev/null | \ + grep -e '^Hugepagesize:[[:space:]]\+[0-9]\+[[:space:]]kB$' | \ + awk '{print $2}'`] + if test "x${hpsk}" != "x" ; then + je_cv_lg_hugepage=10 + while test "${hpsk}" -gt 1 ; do + hpsk="$((hpsk / 2))" + je_cv_lg_hugepage="$((je_cv_lg_hugepage + 1))" + done + fi + fi + + dnl Set default if unable to automatically configure. + if test "x${je_cv_lg_hugepage}" = "x" ; then + je_cv_lg_hugepage=21 + fi +fi +if test "x${LG_PAGE}" != "xundefined" -a \ + "${je_cv_lg_hugepage}" -lt "${LG_PAGE}" ; then + AC_MSG_ERROR([Huge page size (2^${je_cv_lg_hugepage}) must be at least page size (2^${LG_PAGE})]) +fi +AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}]) + +dnl ============================================================================ +dnl Enable libdl by default. +AC_ARG_ENABLE([libdl], + [AS_HELP_STRING([--disable-libdl], + [Do not use libdl])], +[if test "x$enable_libdl" = "xno" ; then + enable_libdl="0" +else + enable_libdl="1" +fi +], +[enable_libdl="1"] +) +AC_SUBST([libdl]) + +dnl ============================================================================ +dnl Configure pthreads. + +if test "x$abi" != "xpecoff" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD], [ ]) + AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])]) + dnl Some systems may embed pthreads functionality in libc; check for libpthread + dnl first, but try libc too before failing. + AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)], + [AC_SEARCH_LIBS([pthread_create], , , + AC_MSG_ERROR([libpthread is missing]))]) + wrap_syms="${wrap_syms} pthread_create" + have_pthread="1" + +dnl Check if we have dlsym support. + if test "x$enable_libdl" = "x1" ; then + have_dlsym="1" + AC_CHECK_HEADERS([dlfcn.h], , [have_dlsym="0"]) + check_dlsym_in_libdl="0" + if test "x$have_dlsym" = "x1" ; then + AC_CHECK_FUNC([dlsym], [], [check_dlsym_in_libdl="1"]) + fi + if test "x$check_dlsym_in_libdl" = "x1" ; then + AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"]) + fi + if test "x$have_dlsym" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ]) + fi + else + have_dlsym="0" + fi + + JE_COMPILABLE([pthread_atfork(3)], [ +#include +], [ + pthread_atfork((void *)0, (void *)0, (void *)0); +], [je_cv_pthread_atfork]) + if test "x${je_cv_pthread_atfork}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD_ATFORK], [ ]) + fi + dnl Check if pthread_setname_np is available with the expected API. + JE_COMPILABLE([pthread_setname_np(3)], [ +#include +], [ + pthread_setname_np(pthread_self(), "setname_test"); +], [je_cv_pthread_setname_np]) + if test "x${je_cv_pthread_setname_np}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD_SETNAME_NP], [ ]) + fi +fi + +JE_APPEND_VS(CPPFLAGS, -D_REENTRANT) + +dnl Check whether clock_gettime(2) is in libc or librt. +AC_SEARCH_LIBS([clock_gettime], [rt]) + +dnl Cray wrapper compiler often adds `-lrt` when using `-static`. Check with +dnl `-dynamic` as well in case a user tries to dynamically link in jemalloc +if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then + if test "$ac_cv_search_clock_gettime" != "-lrt"; then + JE_CFLAGS_SAVE() + + unset ac_cv_search_clock_gettime + JE_CFLAGS_ADD([-dynamic]) + AC_SEARCH_LIBS([clock_gettime], [rt]) + + JE_CFLAGS_RESTORE() + fi +fi + +dnl check for CLOCK_MONOTONIC_COARSE (Linux-specific). +JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_COARSE, ...)], [ +#include +], [ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); +], [je_cv_clock_monotonic_coarse]) +if test "x${je_cv_clock_monotonic_coarse}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE]) +fi + +dnl check for CLOCK_MONOTONIC. +JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC, ...)], [ +#include +#include +], [ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); +#if !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0 +# error _POSIX_MONOTONIC_CLOCK missing/invalid +#endif +], [je_cv_clock_monotonic]) +if test "x${je_cv_clock_monotonic}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC]) +fi + +dnl Check for mach_absolute_time(). +JE_COMPILABLE([mach_absolute_time()], [ +#include +], [ + mach_absolute_time(); +], [je_cv_mach_absolute_time]) +if test "x${je_cv_mach_absolute_time}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME]) +fi + +dnl Use syscall(2) (if available) by default. +AC_ARG_ENABLE([syscall], + [AS_HELP_STRING([--disable-syscall], [Disable use of syscall(2)])], +[if test "x$enable_syscall" = "xno" ; then + enable_syscall="0" +else + enable_syscall="1" +fi +], +[enable_syscall="1"] +) +if test "x$enable_syscall" = "x1" ; then + dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS + dnl X 10.12's deprecation warning prevents use. + JE_CFLAGS_SAVE() + JE_CFLAGS_ADD([-Werror]) + JE_COMPILABLE([syscall(2)], [ +#include +#include +], [ + syscall(SYS_write, 2, "hello", 5); +], + [je_cv_syscall]) + JE_CFLAGS_RESTORE() + if test "x$je_cv_syscall" = "xyes" ; then + AC_DEFINE([JEMALLOC_USE_SYSCALL], [ ]) + fi +fi + +dnl Check if the GNU-specific secure_getenv function exists. +AC_CHECK_FUNC([secure_getenv], + [have_secure_getenv="1"], + [have_secure_getenv="0"] + ) +if test "x$have_secure_getenv" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SECURE_GETENV], [ ]) +fi + +dnl Check if the GNU-specific sched_getcpu function exists. +AC_CHECK_FUNC([sched_getcpu], + [have_sched_getcpu="1"], + [have_sched_getcpu="0"] + ) +if test "x$have_sched_getcpu" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SCHED_GETCPU], [ ]) +fi + +dnl Check if the GNU-specific sched_setaffinity function exists. +AC_CHECK_FUNC([sched_setaffinity], + [have_sched_setaffinity="1"], + [have_sched_setaffinity="0"] + ) +if test "x$have_sched_setaffinity" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SCHED_SETAFFINITY], [ ]) +fi + +dnl Check if the Solaris/BSD issetugid function exists. +AC_CHECK_FUNC([issetugid], + [have_issetugid="1"], + [have_issetugid="0"] + ) +if test "x$have_issetugid" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_ISSETUGID], [ ]) +fi + +dnl Check whether the BSD-specific _malloc_thread_cleanup() exists. If so, use +dnl it rather than pthreads TSD cleanup functions to support cleanup during +dnl thread exit, in order to avoid pthreads library recursion during +dnl bootstrapping. +AC_CHECK_FUNC([_malloc_thread_cleanup], + [have__malloc_thread_cleanup="1"], + [have__malloc_thread_cleanup="0"] + ) +if test "x$have__malloc_thread_cleanup" = "x1" ; then + AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ]) + wrap_syms="${wrap_syms} _malloc_thread_cleanup" + force_tls="1" +fi + +dnl Check whether the BSD-specific _pthread_mutex_init_calloc_cb() exists. If +dnl so, mutex initialization causes allocation, and we need to implement this +dnl callback function in order to prevent recursive allocation. +AC_CHECK_FUNC([_pthread_mutex_init_calloc_cb], + [have__pthread_mutex_init_calloc_cb="1"], + [have__pthread_mutex_init_calloc_cb="0"] + ) +if test "x$have__pthread_mutex_init_calloc_cb" = "x1" ; then + AC_DEFINE([JEMALLOC_MUTEX_INIT_CB]) + wrap_syms="${wrap_syms} _malloc_prefork _malloc_postfork" +fi + +dnl Disable lazy locking by default. +AC_ARG_ENABLE([lazy_lock], + [AS_HELP_STRING([--enable-lazy-lock], + [Enable lazy locking (only lock when multi-threaded)])], +[if test "x$enable_lazy_lock" = "xno" ; then + enable_lazy_lock="0" +else + enable_lazy_lock="1" +fi +], +[enable_lazy_lock=""] +) +if test "x${enable_lazy_lock}" = "x" ; then + if test "x${force_lazy_lock}" = "x1" ; then + AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues]) + enable_lazy_lock="1" + else + enable_lazy_lock="0" + fi +fi +if test "x${enable_lazy_lock}" = "x1" -a "x${abi}" = "xpecoff" ; then + AC_MSG_RESULT([Forcing no lazy-lock because thread creation monitoring is unimplemented]) + enable_lazy_lock="0" +fi +if test "x$enable_lazy_lock" = "x1" ; then + if test "x$have_dlsym" = "x1" ; then + AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) + else + AC_MSG_ERROR([Missing dlsym support: lazy-lock cannot be enabled.]) + fi +fi +AC_SUBST([enable_lazy_lock]) + +dnl Automatically configure TLS. +if test "x${force_tls}" = "x1" ; then + enable_tls="1" +elif test "x${force_tls}" = "x0" ; then + enable_tls="0" +else + enable_tls="1" +fi +if test "x${enable_tls}" = "x1" ; then +AC_MSG_CHECKING([for TLS]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[[ + __thread int x; +]], [[ + x = 42; + + return 0; +]])], + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no]) + enable_tls="0") +else + enable_tls="0" +fi +AC_SUBST([enable_tls]) +if test "x${enable_tls}" = "x1" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ]) +fi + +dnl ============================================================================ +dnl Check for C11 atomics. + +JE_COMPILABLE([C11 atomics], [ +#include +#if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) +#include +#else +#error Atomics not available +#endif +], [ + uint64_t *p = (uint64_t *)0; + uint64_t x = 1; + volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; + uint64_t r = atomic_fetch_add(a, x) + x; + return r == 0; +], [je_cv_c11_atomics]) +if test "x${je_cv_c11_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_C11_ATOMICS]) +fi + +dnl ============================================================================ +dnl Check for GCC-style __atomic atomics. + +JE_COMPILABLE([GCC __atomic atomics], [ +], [ + int x = 0; + int val = 1; + int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED); + int after_add = x; + return after_add == 1; +], [je_cv_gcc_atomic_atomics]) +if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS]) + + dnl check for 8-bit atomic support + JE_COMPILABLE([GCC 8-bit __atomic atomics], [ + ], [ + unsigned char x = 0; + int val = 1; + int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED); + int after_add = (int)x; + return after_add == 1; + ], [je_cv_gcc_u8_atomic_atomics]) + if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS]) + fi +fi + +dnl ============================================================================ +dnl Check for GCC-style __sync atomics. + +JE_COMPILABLE([GCC __sync atomics], [ +], [ + int x = 0; + int before_add = __sync_fetch_and_add(&x, 1); + int after_add = x; + return (before_add == 0) && (after_add == 1); +], [je_cv_gcc_sync_atomics]) +if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS]) + + dnl check for 8-bit atomic support + JE_COMPILABLE([GCC 8-bit __sync atomics], [ + ], [ + unsigned char x = 0; + int before_add = __sync_fetch_and_add(&x, 1); + int after_add = (int)x; + return (before_add == 0) && (after_add == 1); + ], [je_cv_gcc_u8_sync_atomics]) + if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS]) + fi +fi + +dnl ============================================================================ +dnl Check for atomic(3) operations as provided on Darwin. +dnl We need this not for the atomic operations (which are provided above), but +dnl rather for the OS_unfair_lock type it exposes. + +JE_COMPILABLE([Darwin OSAtomic*()], [ +#include +#include +], [ + { + int32_t x32 = 0; + volatile int32_t *x32p = &x32; + OSAtomicAdd32(1, x32p); + } + { + int64_t x64 = 0; + volatile int64_t *x64p = &x64; + OSAtomicAdd64(1, x64p); + } +], [je_cv_osatomic]) +if test "x${je_cv_osatomic}" = "xyes" ; then + AC_DEFINE([JEMALLOC_OSATOMIC], [ ]) +fi + +dnl ============================================================================ +dnl Check for madvise(2). + +JE_COMPILABLE([madvise(2)], [ +#include +], [ + madvise((void *)0, 0, 0); +], [je_cv_madvise]) +if test "x${je_cv_madvise}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) + + dnl Check for madvise(..., MADV_FREE). + JE_COMPILABLE([madvise(..., MADV_FREE)], [ +#include +], [ + madvise((void *)0, 0, MADV_FREE); +], [je_cv_madv_free]) + if test "x${je_cv_madv_free}" = "xyes" ; then + AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) + elif test "x${je_cv_madvise}" = "xyes" ; then + case "${host_cpu}" in i686|x86_64) + case "${host}" in *-*-linux*) + AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) + AC_DEFINE([JEMALLOC_DEFINE_MADVISE_FREE], [ ]) + ;; + esac + ;; + esac + fi + + dnl Check for madvise(..., MADV_DONTNEED). + JE_COMPILABLE([madvise(..., MADV_DONTNEED)], [ +#include +], [ + madvise((void *)0, 0, MADV_DONTNEED); +], [je_cv_madv_dontneed]) + if test "x${je_cv_madv_dontneed}" = "xyes" ; then + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) + fi + + dnl Check for madvise(..., MADV_DO[NT]DUMP). + JE_COMPILABLE([madvise(..., MADV_DO[[NT]]DUMP)], [ +#include +], [ + madvise((void *)0, 0, MADV_DONTDUMP); + madvise((void *)0, 0, MADV_DODUMP); +], [je_cv_madv_dontdump]) + if test "x${je_cv_madv_dontdump}" = "xyes" ; then + AC_DEFINE([JEMALLOC_MADVISE_DONTDUMP], [ ]) + fi + + dnl Check for madvise(..., MADV_[NO]HUGEPAGE). + JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [ +#include +], [ + madvise((void *)0, 0, MADV_HUGEPAGE); + madvise((void *)0, 0, MADV_NOHUGEPAGE); +], [je_cv_thp]) +case "${host_cpu}" in + arm*) + ;; + *) + if test "x${je_cv_thp}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MADVISE_HUGE], [ ]) + fi + ;; +esac +fi + +dnl ============================================================================ +dnl Check for __builtin_clz() and __builtin_clzl(). + +AC_CACHE_CHECK([for __builtin_clz], + [je_cv_builtin_clz], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([], + [ + { + unsigned x = 0; + int y = __builtin_clz(x); + } + { + unsigned long x = 0; + int y = __builtin_clzl(x); + } + ])], + [je_cv_builtin_clz=yes], + [je_cv_builtin_clz=no])]) + +if test "x${je_cv_builtin_clz}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ]) +fi + +dnl ============================================================================ +dnl Check for os_unfair_lock operations as provided on Darwin. + +JE_COMPILABLE([Darwin os_unfair_lock_*()], [ +#include +#include +], [ + #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 + #error "os_unfair_lock is not supported" + #else + os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; + os_unfair_lock_lock(&lock); + os_unfair_lock_unlock(&lock); + #endif +], [je_cv_os_unfair_lock]) +if test "x${je_cv_os_unfair_lock}" = "xyes" ; then + AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ]) +fi + +dnl ============================================================================ +dnl Darwin-related configuration. + +AC_ARG_ENABLE([zone-allocator], + [AS_HELP_STRING([--disable-zone-allocator], + [Disable zone allocator for Darwin])], +[if test "x$enable_zone_allocator" = "xno" ; then + enable_zone_allocator="0" +else + enable_zone_allocator="1" +fi +], +[if test "x${abi}" = "xmacho"; then + enable_zone_allocator="1" +fi +] +) +AC_SUBST([enable_zone_allocator]) + +if test "x${enable_zone_allocator}" = "x1" ; then + if test "x${abi}" != "xmacho"; then + AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin]) + fi + AC_DEFINE([JEMALLOC_ZONE], [ ]) +fi + +dnl ============================================================================ +dnl Use initial-exec TLS by default. +AC_ARG_ENABLE([initial-exec-tls], + [AS_HELP_STRING([--disable-initial-exec-tls], + [Disable the initial-exec tls model])], +[if test "x$enable_initial_exec_tls" = "xno" ; then + enable_initial_exec_tls="0" +else + enable_initial_exec_tls="1" +fi +], +[enable_initial_exec_tls="1"] +) +AC_SUBST([enable_initial_exec_tls]) + +if test "x${je_cv_tls_model}" = "xyes" -a \ + "x${enable_initial_exec_tls}" = "x1" ; then + AC_DEFINE([JEMALLOC_TLS_MODEL], + [__attribute__((tls_model("initial-exec")))]) +else + AC_DEFINE([JEMALLOC_TLS_MODEL], [ ]) +fi + +dnl ============================================================================ +dnl Enable background threads if possible. + +if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then + AC_DEFINE([JEMALLOC_BACKGROUND_THREAD]) +fi + +dnl ============================================================================ +dnl Check for glibc malloc hooks + +JE_COMPILABLE([glibc malloc hook], [ +#include + +extern void (* __free_hook)(void *ptr); +extern void *(* __malloc_hook)(size_t size); +extern void *(* __realloc_hook)(void *ptr, size_t size); +], [ + void *ptr = 0L; + if (__malloc_hook) ptr = __malloc_hook(1); + if (__realloc_hook) ptr = __realloc_hook(ptr, 2); + if (__free_hook && ptr) __free_hook(ptr); +], [je_cv_glibc_malloc_hook]) +if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then + if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ]) + wrap_syms="${wrap_syms} __free_hook __malloc_hook __realloc_hook" + fi +fi + +JE_COMPILABLE([glibc memalign hook], [ +#include + +extern void *(* __memalign_hook)(size_t alignment, size_t size); +], [ + void *ptr = 0L; + if (__memalign_hook) ptr = __memalign_hook(16, 7); +], [je_cv_glibc_memalign_hook]) +if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then + if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ]) + wrap_syms="${wrap_syms} __memalign_hook" + fi +fi + +JE_COMPILABLE([pthreads adaptive mutexes], [ +#include +], [ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutexattr_destroy(&attr); +], [je_cv_pthread_mutex_adaptive_np]) +if test "x${je_cv_pthread_mutex_adaptive_np}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [ ]) +fi + +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-D_GNU_SOURCE]) +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) +JE_COMPILABLE([strerror_r returns char with gnu source], [ +#include +#include +#include +#include +], [ + char *buffer = (char *) malloc(100); + char *error = strerror_r(EINVAL, buffer, 100); + printf("%s\n", error); +], [je_cv_strerror_r_returns_char_with_gnu_source]) +JE_CFLAGS_RESTORE() +if test "x${je_cv_strerror_r_returns_char_with_gnu_source}" = "xyes" ; then + AC_DEFINE([JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE], [ ]) +fi + +dnl ============================================================================ +dnl Check for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL + +dnl ============================================================================ +dnl Define commands that generate output files. + +AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [ + f="${objroot}include/jemalloc/internal/public_symbols.txt" + mkdir -p "${objroot}include/jemalloc/internal" + cp /dev/null "${f}" + for nm in `echo ${mangling_map} |tr ',' ' '` ; do + n=`echo ${nm} |tr ':' ' ' |awk '{print $[]1}'` + m=`echo ${nm} |tr ':' ' ' |awk '{print $[]2}'` + echo "${n}:${m}" >> "${f}" + dnl Remove name from public_syms so that it isn't redefined later. + public_syms=`for sym in ${public_syms}; do echo "${sym}"; done |grep -v "^${n}\$" |tr '\n' ' '` + done + for sym in ${public_syms} ; do + n="${sym}" + m="${JEMALLOC_PREFIX}${sym}" + echo "${n}:${m}" >> "${f}" + done +], [ + srcdir="${srcdir}" + objroot="${objroot}" + mangling_map="${mangling_map}" + public_syms="${public_syms}" + JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols.awk], [ + f="${objroot}include/jemalloc/internal/private_symbols.awk" + mkdir -p "${objroot}include/jemalloc/internal" + export_syms=`for sym in ${public_syms}; do echo "${JEMALLOC_PREFIX}${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` + "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols.awk" +], [ + srcdir="${srcdir}" + objroot="${objroot}" + public_syms="${public_syms}" + wrap_syms="${wrap_syms}" + SYM_PREFIX="${SYM_PREFIX}" + JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols_jet.awk], [ + f="${objroot}include/jemalloc/internal/private_symbols_jet.awk" + mkdir -p "${objroot}include/jemalloc/internal" + export_syms=`for sym in ${public_syms}; do echo "jet_${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` + "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols_jet.awk" +], [ + srcdir="${srcdir}" + objroot="${objroot}" + public_syms="${public_syms}" + wrap_syms="${wrap_syms}" + SYM_PREFIX="${SYM_PREFIX}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/public_namespace.h], [ + mkdir -p "${objroot}include/jemalloc/internal" + "${srcdir}/include/jemalloc/internal/public_namespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_namespace.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [ + mkdir -p "${objroot}include/jemalloc/internal" + "${srcdir}/include/jemalloc/internal/public_unnamespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_unnamespace.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [ + mkdir -p "${objroot}include/jemalloc" + cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_rename.h], [ + mkdir -p "${objroot}include/jemalloc" + "${srcdir}/include/jemalloc/jemalloc_rename.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/jemalloc_rename.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle.h], [ + mkdir -p "${objroot}include/jemalloc" + "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" je_ > "${objroot}include/jemalloc/jemalloc_mangle.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle_jet.h], [ + mkdir -p "${objroot}include/jemalloc" + "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" jet_ > "${objroot}include/jemalloc/jemalloc_mangle_jet.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/jemalloc.h], [ + mkdir -p "${objroot}include/jemalloc" + "${srcdir}/include/jemalloc/jemalloc.sh" "${objroot}" > "${objroot}include/jemalloc/jemalloc${install_suffix}.h" +], [ + srcdir="${srcdir}" + objroot="${objroot}" + install_suffix="${install_suffix}" +]) + +dnl Process .in files. +AC_SUBST([cfghdrs_in]) +AC_SUBST([cfghdrs_out]) +AC_CONFIG_HEADERS([$cfghdrs_tup]) + +dnl ============================================================================ +dnl Generate outputs. + +AC_CONFIG_FILES([$cfgoutputs_tup config.stamp bin/jemalloc-config bin/jemalloc.sh bin/jeprof]) +AC_SUBST([cfgoutputs_in]) +AC_SUBST([cfgoutputs_out]) +AC_OUTPUT + +dnl ============================================================================ +dnl Print out the results of configuration. +AC_MSG_RESULT([===============================================================================]) +AC_MSG_RESULT([jemalloc version : ${jemalloc_version}]) +AC_MSG_RESULT([library revision : ${rev}]) +AC_MSG_RESULT([]) +AC_MSG_RESULT([CONFIG : ${CONFIG}]) +AC_MSG_RESULT([CC : ${CC}]) +AC_MSG_RESULT([CONFIGURE_CFLAGS : ${CONFIGURE_CFLAGS}]) +AC_MSG_RESULT([SPECIFIED_CFLAGS : ${SPECIFIED_CFLAGS}]) +AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}]) +AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}]) +AC_MSG_RESULT([CXX : ${CXX}]) +AC_MSG_RESULT([CONFIGURE_CXXFLAGS : ${CONFIGURE_CXXFLAGS}]) +AC_MSG_RESULT([SPECIFIED_CXXFLAGS : ${SPECIFIED_CXXFLAGS}]) +AC_MSG_RESULT([EXTRA_CXXFLAGS : ${EXTRA_CXXFLAGS}]) +AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) +AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) +AC_MSG_RESULT([DSO_LDFLAGS : ${DSO_LDFLAGS}]) +AC_MSG_RESULT([LIBS : ${LIBS}]) +AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}]) +AC_MSG_RESULT([]) +AC_MSG_RESULT([XSLTPROC : ${XSLTPROC}]) +AC_MSG_RESULT([XSLROOT : ${XSLROOT}]) +AC_MSG_RESULT([]) +AC_MSG_RESULT([PREFIX : ${PREFIX}]) +AC_MSG_RESULT([BINDIR : ${BINDIR}]) +AC_MSG_RESULT([DATADIR : ${DATADIR}]) +AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}]) +AC_MSG_RESULT([LIBDIR : ${LIBDIR}]) +AC_MSG_RESULT([MANDIR : ${MANDIR}]) +AC_MSG_RESULT([]) +AC_MSG_RESULT([srcroot : ${srcroot}]) +AC_MSG_RESULT([abs_srcroot : ${abs_srcroot}]) +AC_MSG_RESULT([objroot : ${objroot}]) +AC_MSG_RESULT([abs_objroot : ${abs_objroot}]) +AC_MSG_RESULT([]) +AC_MSG_RESULT([JEMALLOC_PREFIX : ${JEMALLOC_PREFIX}]) +AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE]) +AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}]) +AC_MSG_RESULT([install_suffix : ${install_suffix}]) +AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}]) +AC_MSG_RESULT([documentation : ${enable_doc}]) +AC_MSG_RESULT([shared libs : ${enable_shared}]) +AC_MSG_RESULT([static libs : ${enable_static}]) +AC_MSG_RESULT([autogen : ${enable_autogen}]) +AC_MSG_RESULT([debug : ${enable_debug}]) +AC_MSG_RESULT([stats : ${enable_stats}]) +AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}]) +AC_MSG_RESULT([prof : ${enable_prof}]) +AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}]) +AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}]) +AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) +AC_MSG_RESULT([fill : ${enable_fill}]) +AC_MSG_RESULT([utrace : ${enable_utrace}]) +AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) +AC_MSG_RESULT([log : ${enable_log}]) +AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) +AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) +AC_MSG_RESULT([cxx : ${enable_cxx}]) +AC_MSG_RESULT([===============================================================================]) diff --git a/jemalloc/doc/html.xsl.in b/jemalloc/doc/html.xsl.in new file mode 100644 index 0000000..ec4fa65 --- /dev/null +++ b/jemalloc/doc/html.xsl.in @@ -0,0 +1,5 @@ + + + + + diff --git a/jemalloc/doc/jemalloc.xml.in b/jemalloc/doc/jemalloc.xml.in new file mode 100644 index 0000000..7fecda7 --- /dev/null +++ b/jemalloc/doc/jemalloc.xml.in @@ -0,0 +1,3513 @@ + + + + + + + User Manual + jemalloc + @jemalloc_version@ + + + Jason + Evans + Author + + + + + JEMALLOC + 3 + + + jemalloc + jemalloc + + general purpose memory allocation functions + + + LIBRARY + This manual describes jemalloc @jemalloc_version@. More information + can be found at the jemalloc website. + + + SYNOPSIS + + #include <jemalloc/jemalloc.h> + + Standard API + + void *malloc + size_t size + + + void *calloc + size_t number + size_t size + + + int posix_memalign + void **ptr + size_t alignment + size_t size + + + void *aligned_alloc + size_t alignment + size_t size + + + void *realloc + void *ptr + size_t size + + + void free + void *ptr + + + + Non-standard API + + void *mallocx + size_t size + int flags + + + void *rallocx + void *ptr + size_t size + int flags + + + size_t xallocx + void *ptr + size_t size + size_t extra + int flags + + + size_t sallocx + void *ptr + int flags + + + void dallocx + void *ptr + int flags + + + void sdallocx + void *ptr + size_t size + int flags + + + size_t nallocx + size_t size + int flags + + + int mallctl + const char *name + void *oldp + size_t *oldlenp + void *newp + size_t newlen + + + int mallctlnametomib + const char *name + size_t *mibp + size_t *miblenp + + + int mallctlbymib + const size_t *mib + size_t miblen + void *oldp + size_t *oldlenp + void *newp + size_t newlen + + + void malloc_stats_print + void (*write_cb) + void *, const char * + + void *cbopaque + const char *opts + + + size_t malloc_usable_size + const void *ptr + + + void (*malloc_message) + void *cbopaque + const char *s + + const char *malloc_conf; + + + + + DESCRIPTION + + Standard API + + The malloc() function allocates + size bytes of uninitialized memory. The allocated + space is suitably aligned (after possible pointer coercion) for storage + of any type of object. + + The calloc() function allocates + space for number objects, each + size bytes in length. The result is identical to + calling malloc() with an argument of + number * size, with the + exception that the allocated memory is explicitly initialized to zero + bytes. + + The posix_memalign() function + allocates size bytes of memory such that the + allocation's base address is a multiple of + alignment, and returns the allocation in the value + pointed to by ptr. The requested + alignment must be a power of 2 at least as large as + sizeof(void *). + + The aligned_alloc() function + allocates size bytes of memory such that the + allocation's base address is a multiple of + alignment. The requested + alignment must be a power of 2. Behavior is + undefined if size is not an integral multiple of + alignment. + + The realloc() function changes the + size of the previously allocated memory referenced by + ptr to size bytes. The + contents of the memory are unchanged up to the lesser of the new and old + sizes. If the new size is larger, the contents of the newly allocated + portion of the memory are undefined. Upon success, the memory referenced + by ptr is freed and a pointer to the newly + allocated memory is returned. Note that + realloc() may move the memory allocation, + resulting in a different return value than ptr. + If ptr is NULL, the + realloc() function behaves identically to + malloc() for the specified size. + + The free() function causes the + allocated memory referenced by ptr to be made + available for future allocations. If ptr is + NULL, no action occurs. + + + Non-standard API + The mallocx(), + rallocx(), + xallocx(), + sallocx(), + dallocx(), + sdallocx(), and + nallocx() functions all have a + flags argument that can be used to specify + options. The functions only check the options that are contextually + relevant. Use bitwise or (|) operations to + specify one or more of the following: + + + MALLOCX_LG_ALIGN(la) + + + Align the memory allocation to start at an address + that is a multiple of (1 << + la). This macro does not validate + that la is within the valid + range. + + + MALLOCX_ALIGN(a) + + + Align the memory allocation to start at an address + that is a multiple of a, where + a is a power of two. This macro does not + validate that a is a power of 2. + + + + MALLOCX_ZERO + + Initialize newly allocated memory to contain zero + bytes. In the growing reallocation case, the real size prior to + reallocation defines the boundary between untouched bytes and those + that are initialized to contain zero bytes. If this macro is + absent, newly allocated memory is uninitialized. + + + MALLOCX_TCACHE(tc) + + + Use the thread-specific cache (tcache) specified by + the identifier tc, which must have been + acquired via the tcache.create + mallctl. This macro does not validate that + tc specifies a valid + identifier. + + + MALLOCX_TCACHE_NONE + + Do not use a thread-specific cache (tcache). Unless + MALLOCX_TCACHE(tc) or + MALLOCX_TCACHE_NONE is specified, an + automatically managed tcache will be used under many circumstances. + This macro cannot be used in the same flags + argument as + MALLOCX_TCACHE(tc). + + + MALLOCX_ARENA(a) + + + Use the arena specified by the index + a. This macro has no effect for regions that + were allocated via an arena other than the one specified. This + macro does not validate that a specifies an + arena index in the valid range. + + + + + The mallocx() function allocates at + least size bytes of memory, and returns a pointer + to the base address of the allocation. Behavior is undefined if + size is 0. + + The rallocx() function resizes the + allocation at ptr to be at least + size bytes, and returns a pointer to the base + address of the resulting allocation, which may or may not have moved from + its original location. Behavior is undefined if + size is 0. + + The xallocx() function resizes the + allocation at ptr in place to be at least + size bytes, and returns the real size of the + allocation. If extra is non-zero, an attempt is + made to resize the allocation to be at least (size + + extra) bytes, though inability to allocate + the extra byte(s) will not by itself result in failure to resize. + Behavior is undefined if size is + 0, or if (size + extra + > SIZE_T_MAX). + + The sallocx() function returns the + real size of the allocation at ptr. + + The dallocx() function causes the + memory referenced by ptr to be made available for + future allocations. + + The sdallocx() function is an + extension of dallocx() with a + size parameter to allow the caller to pass in the + allocation size as an optimization. The minimum valid input size is the + original requested size of the allocation, and the maximum valid input + size is the corresponding value returned by + nallocx() or + sallocx(). + + The nallocx() function allocates no + memory, but it performs the same size computation as the + mallocx() function, and returns the real + size of the allocation that would result from the equivalent + mallocx() function call, or + 0 if the inputs exceed the maximum supported size + class and/or alignment. Behavior is undefined if + size is 0. + + The mallctl() function provides a + general interface for introspecting the memory allocator, as well as + setting modifiable parameters and triggering actions. The + period-separated name argument specifies a + location in a tree-structured namespace; see the section for + documentation on the tree contents. To read a value, pass a pointer via + oldp to adequate space to contain the value, and a + pointer to its length via oldlenp; otherwise pass + NULL and NULL. Similarly, to + write a value, pass a pointer to the value via + newp, and its length via + newlen; otherwise pass NULL + and 0. + + The mallctlnametomib() function + provides a way to avoid repeated name lookups for applications that + repeatedly query the same portion of the namespace, by translating a name + to a Management Information Base (MIB) that can be passed + repeatedly to mallctlbymib(). Upon + successful return from mallctlnametomib(), + mibp contains an array of + *miblenp integers, where + *miblenp is the lesser of the number of components + in name and the input value of + *miblenp. Thus it is possible to pass a + *miblenp that is smaller than the number of + period-separated name components, which results in a partial MIB that can + be used as the basis for constructing a complete MIB. For name + components that are integers (e.g. the 2 in + arenas.bin.2.size), + the corresponding MIB component will always be that integer. Therefore, + it is legitimate to construct code like the following: + + + + The malloc_stats_print() function writes + summary statistics via the write_cb callback + function pointer and cbopaque data passed to + write_cb, or malloc_message() + if write_cb is NULL. The + statistics are presented in human-readable form unless J is + specified as a character within the opts string, in + which case the statistics are presented in JSON format. This function can be + called repeatedly. General information that never changes during + execution can be omitted by specifying g as a character + within the opts string. Note that + malloc_stats_print() uses the + mallctl*() functions internally, so inconsistent + statistics can be reported if multiple threads use these functions + simultaneously. If is specified during + configuration, m, d, and a + can be specified to omit merged arena, destroyed merged arena, and per + arena statistics, respectively; b and l can + be specified to omit per size class statistics for bins and large objects, + respectively; x can be specified to omit all mutex + statistics; e can be used to omit extent statistics. + Unrecognized characters are silently ignored. Note that thread caching + may prevent some statistics from being completely up to date, since extra + locking would be required to merge counters that track thread cache + operations. + + The malloc_usable_size() function + returns the usable size of the allocation pointed to by + ptr. The return value may be larger than the size + that was requested during allocation. The + malloc_usable_size() function is not a + mechanism for in-place realloc(); rather + it is provided solely as a tool for introspection purposes. Any + discrepancy between the requested allocation size and the size reported + by malloc_usable_size() should not be + depended on, since such behavior is entirely implementation-dependent. + + + + + TUNING + Once, when the first call is made to one of the memory allocation + routines, the allocator initializes its internals based in part on various + options that can be specified at compile- or run-time. + + The string specified via , the + string pointed to by the global variable malloc_conf, the + name of the file referenced by the symbolic link named + /etc/malloc.conf, and the value of the + environment variable MALLOC_CONF, will be interpreted, in + that order, from left to right as options. Note that + malloc_conf may be read before + main() is entered, so the declaration of + malloc_conf should specify an initializer that contains + the final value to be read by jemalloc. + and malloc_conf are compile-time mechanisms, whereas + /etc/malloc.conf and + MALLOC_CONF can be safely set any time prior to program + invocation. + + An options string is a comma-separated list of option:value pairs. + There is one key corresponding to each opt.* mallctl (see the section for options + documentation). For example, abort:true,narenas:1 sets + the opt.abort and opt.narenas options. Some + options have boolean values (true/false), others have integer values (base + 8, 10, or 16, depending on prefix), and yet others have raw string + values. + + + IMPLEMENTATION NOTES + Traditionally, allocators have used + sbrk + 2 to obtain memory, which is + suboptimal for several reasons, including race conditions, increased + fragmentation, and artificial limitations on maximum usable memory. If + sbrk + 2 is supported by the operating + system, this allocator uses both + mmap + 2 and + sbrk + 2, in that order of preference; + otherwise only mmap + 2 is used. + + This allocator uses multiple arenas in order to reduce lock + contention for threaded programs on multi-processor systems. This works + well with regard to threading scalability, but incurs some costs. There is + a small fixed per-arena overhead, and additionally, arenas manage memory + completely independently of each other, which means a small fixed increase + in overall memory fragmentation. These overheads are not generally an + issue, given the number of arenas normally used. Note that using + substantially more arenas than the default is not likely to improve + performance, mainly due to reduced cache performance. However, it may make + sense to reduce the number of arenas if an application does not make much + use of the allocation functions. + + In addition to multiple arenas, this allocator supports + thread-specific caching, in order to make it possible to completely avoid + synchronization for most allocation requests. Such caching allows very fast + allocation in the common case, but it increases memory usage and + fragmentation, since a bounded number of objects can remain allocated in + each thread cache. + + Memory is conceptually broken into extents. Extents are always + aligned to multiples of the page size. This alignment makes it possible to + find metadata for user objects quickly. User objects are broken into two + categories according to size: small and large. Contiguous small objects + comprise a slab, which resides within a single extent, whereas large objects + each have their own extents backing them. + + Small objects are managed in groups by slabs. Each slab maintains + a bitmap to track which regions are in use. Allocation requests that are no + more than half the quantum (8 or 16, depending on architecture) are rounded + up to the nearest power of two that is at least sizeof(double). All other object size + classes are multiples of the quantum, spaced such that there are four size + classes for each doubling in size, which limits internal fragmentation to + approximately 20% for all but the smallest size classes. Small size classes + are smaller than four times the page size, and large size classes extend + from four times the page size up to the largest size class that does not + exceed PTRDIFF_MAX. + + Allocations are packed tightly together, which can be an issue for + multi-threaded applications. If you need to assure that allocations do not + suffer from cacheline sharing, round your allocation requests up to the + nearest multiple of the cacheline size, or specify cacheline alignment when + allocating. + + The realloc(), + rallocx(), and + xallocx() functions may resize allocations + without moving them under limited circumstances. Unlike the + *allocx() API, the standard API does not + officially round up the usable size of an allocation to the nearest size + class, so technically it is necessary to call + realloc() to grow e.g. a 9-byte allocation to + 16 bytes, or shrink a 16-byte allocation to 9 bytes. Growth and shrinkage + trivially succeeds in place as long as the pre-size and post-size both round + up to the same size class. No other API guarantees are made regarding + in-place resizing, but the current implementation also tries to resize large + allocations in place, as long as the pre-size and post-size are both large. + For shrinkage to succeed, the extent allocator must support splitting (see + arena.<i>.extent_hooks). + Growth only succeeds if the trailing memory is currently available, and the + extent allocator supports merging. + + Assuming 4 KiB pages and a 16-byte quantum on a 64-bit system, the + size classes in each category are as shown in . + + + Size classes + + + + + + + Category + Spacing + Size + + + + + Small + lg + [8] + + + 16 + [16, 32, 48, 64, 80, 96, 112, 128] + + + 32 + [160, 192, 224, 256] + + + 64 + [320, 384, 448, 512] + + + 128 + [640, 768, 896, 1024] + + + 256 + [1280, 1536, 1792, 2048] + + + 512 + [2560, 3072, 3584, 4096] + + + 1 KiB + [5 KiB, 6 KiB, 7 KiB, 8 KiB] + + + 2 KiB + [10 KiB, 12 KiB, 14 KiB] + + + Large + 2 KiB + [16 KiB] + + + 4 KiB + [20 KiB, 24 KiB, 28 KiB, 32 KiB] + + + 8 KiB + [40 KiB, 48 KiB, 54 KiB, 64 KiB] + + + 16 KiB + [80 KiB, 96 KiB, 112 KiB, 128 KiB] + + + 32 KiB + [160 KiB, 192 KiB, 224 KiB, 256 KiB] + + + 64 KiB + [320 KiB, 384 KiB, 448 KiB, 512 KiB] + + + 128 KiB + [640 KiB, 768 KiB, 896 KiB, 1 MiB] + + + 256 KiB + [1280 KiB, 1536 KiB, 1792 KiB, 2 MiB] + + + 512 KiB + [2560 KiB, 3 MiB, 3584 KiB, 4 MiB] + + + 1 MiB + [5 MiB, 6 MiB, 7 MiB, 8 MiB] + + + 2 MiB + [10 MiB, 12 MiB, 14 MiB, 16 MiB] + + + 4 MiB + [20 MiB, 24 MiB, 28 MiB, 32 MiB] + + + 8 MiB + [40 MiB, 48 MiB, 56 MiB, 64 MiB] + + + ... + ... + + + 512 PiB + [2560 PiB, 3 EiB, 3584 PiB, 4 EiB] + + + 1 EiB + [5 EiB, 6 EiB, 7 EiB] + + + +
+
+ + MALLCTL NAMESPACE + The following names are defined in the namespace accessible via the + mallctl*() functions. Value types are specified in + parentheses, their readable/writable statuses are encoded as + rw, r-, -w, or + --, and required build configuration flags follow, if + any. A name element encoded as <i> or + <j> indicates an integer component, where the + integer varies from 0 to some upper value that must be determined via + introspection. In the case of stats.arenas.<i>.* + and arena.<i>.{initialized,purge,decay,dss}, + <i> equal to + MALLCTL_ARENAS_ALL can be used to operate on all arenas + or access the summation of statistics from all arenas; similarly + <i> equal to + MALLCTL_ARENAS_DESTROYED can be used to access the + summation of statistics from all destroyed arenas. These constants can be + utilized either via mallctlnametomib() followed by + mallctlbymib(), or via code such as the following: + + Take special note of the epoch mallctl, which controls + refreshing of cached dynamic statistics. + + + + + version + (const char *) + r- + + Return the jemalloc version string. + + + + + epoch + (uint64_t) + rw + + If a value is passed in, refresh the data from which + the mallctl*() functions report values, + and increment the epoch. Return the current epoch. This is useful for + detecting whether another thread caused a refresh. + + + + + background_thread + (bool) + rw + + Enable/disable internal background worker threads. When + set to true, background threads are created on demand (the number of + background threads will be no more than the number of CPUs or active + arenas). Threads run periodically, and handle purging asynchronously. When switching + off, background threads are terminated synchronously. Note that after + fork2 + function, the state in the child process will be disabled regardless + the state in parent process. See stats.background_thread + for related stats. opt.background_thread + can be used to set the default option. This option is only available on + selected pthread-based platforms. + + + + + max_background_threads + (size_t) + rw + + Maximum number of background worker threads that will + be created. This value is capped at opt.max_background_threads at + startup. + + + + + config.cache_oblivious + (bool) + r- + + was specified + during build configuration. + + + + + config.debug + (bool) + r- + + was specified during + build configuration. + + + + + config.fill + (bool) + r- + + was specified during + build configuration. + + + + + config.lazy_lock + (bool) + r- + + was specified + during build configuration. + + + + + config.malloc_conf + (const char *) + r- + + Embedded configure-time-specified run-time options + string, empty unless was specified + during build configuration. + + + + + config.prof + (bool) + r- + + was specified during + build configuration. + + + + + config.prof_libgcc + (bool) + r- + + was not + specified during build configuration. + + + + + config.prof_libunwind + (bool) + r- + + was specified + during build configuration. + + + + + config.stats + (bool) + r- + + was specified during + build configuration. + + + + + + config.utrace + (bool) + r- + + was specified during + build configuration. + + + + + config.xmalloc + (bool) + r- + + was specified during + build configuration. + + + + + opt.abort + (bool) + r- + + Abort-on-warning enabled/disabled. If true, most + warnings are fatal. Note that runtime option warnings are not included + (see opt.abort_conf for + that). The process will call + abort + 3 in these cases. This option is + disabled by default unless is + specified during configuration, in which case it is enabled by default. + + + + + + opt.confirm_conf + (bool) + r- + + Confirm-runtime-options-when-program-starts + enabled/disabled. If true, the string specified via + , the string pointed to by the + global variable malloc_conf, the name + of the file referenced by the symbolic link named + /etc/malloc.conf, and the value of + the environment variable MALLOC_CONF, will be printed in + order. Then, each option being set will be individually printed. This + option is disabled by default. + + + + + opt.abort_conf + (bool) + r- + + Abort-on-invalid-configuration enabled/disabled. If + true, invalid runtime options are fatal. The process will call + abort + 3 in these cases. This option is + disabled by default unless is + specified during configuration, in which case it is enabled by default. + + + + + + opt.metadata_thp + (const char *) + r- + + Controls whether to allow jemalloc to use transparent + huge page (THP) for internal metadata (see stats.metadata). always + allows such usage. auto uses no THP initially, but may + begin to do so when metadata usage reaches certain level. The default + is disabled. + + + + + opt.retain + (bool) + r- + + If true, retain unused virtual memory for later reuse + rather than discarding it by calling + munmap + 2 or equivalent (see stats.retained for related details). + It also makes jemalloc use + mmap2 + or equivalent in a more greedy way, mapping larger + chunks in one go. This option is disabled by default unless discarding + virtual memory is known to trigger platform-specific performance + problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual + memory allocation algorithm that causes semi-permanent VM map holes + under normal jemalloc operation; and 2) for [64-bit] Windows, which + disallows split / merged regions with + MEM_RELEASE. Although the + same issues may present on 32-bit platforms as well, retaining virtual + memory for 32-bit Linux and Windows is disabled by default due to the + practical possibility of address space exhaustion. + + + + + opt.dss + (const char *) + r- + + dss (sbrk + 2) allocation precedence as + related to mmap + 2 allocation. The following + settings are supported if + sbrk + 2 is supported by the operating + system: disabled, primary, and + secondary; otherwise only disabled is + supported. The default is secondary if + sbrk + 2 is supported by the operating + system; disabled otherwise. + + + + + + opt.narenas + (unsigned) + r- + + Maximum number of arenas to use for automatic + multiplexing of threads and arenas. The default is four times the + number of CPUs, or one if there is a single CPU. + + + + + opt.oversize_threshold + (size_t) + r- + + The threshold in bytes of which requests are considered + oversize. Allocation requests with greater sizes are fulfilled from a + dedicated arena (automatically managed, however not within + narenas), in order to reduce fragmentation by not + mixing huge allocations with small ones. In addition, the decay API + guarantees on the extents greater than the specified threshold may be + overridden. Note that requests with arena index specified via + MALLOCX_ARENA, or threads associated with explicit + arenas will not be considered. The default threshold is 8MiB. Values + not within large size classes disables this feature. + + + + + opt.percpu_arena + (const char *) + r- + + Per CPU arena mode. Use the percpu + setting to enable this feature, which uses number of CPUs to determine + number of arenas, and bind threads to arenas dynamically based on the + CPU the thread runs on currently. phycpu setting uses + one arena per physical CPU, which means the two hyper threads on the + same CPU share one arena. Note that no runtime checking regarding the + availability of hyper threading is done at the moment. When set to + disabled, narenas and thread to arena association will + not be impacted by this option. The default is disabled. + + + + + + opt.background_thread + (bool) + r- + + Internal background worker threads enabled/disabled. + Because of potential circular dependencies, enabling background thread + using this option may cause crash or deadlock during initialization. For + a reliable way to use this feature, see background_thread for dynamic control + options and details. This option is disabled by + default. + + + + + opt.max_background_threads + (size_t) + r- + + Maximum number of background threads that will be created + if background_thread is set. + Defaults to number of cpus. + + + + + opt.dirty_decay_ms + (ssize_t) + r- + + Approximate time in milliseconds from the creation of a + set of unused dirty pages until an equivalent set of unused dirty pages + is purged (i.e. converted to muzzy via e.g. + madvise(...MADV_FREE) + if supported by the operating system, or converted to clean otherwise) + and/or reused. Dirty pages are defined as previously having been + potentially written to by the application, and therefore consuming + physical memory, yet having no current use. The pages are incrementally + purged according to a sigmoidal decay curve that starts and ends with + zero purge rate. A decay time of 0 causes all unused dirty pages to be + purged immediately upon creation. A decay time of -1 disables purging. + The default decay time is 10 seconds. See arenas.dirty_decay_ms + and arena.<i>.dirty_decay_ms + for related dynamic control options. See opt.muzzy_decay_ms + for a description of muzzy pages.for a description of muzzy pages. Note + that when the oversize_threshold + feature is enabled, the arenas reserved for oversize requests may have + its own default decay settings. + + + + + opt.muzzy_decay_ms + (ssize_t) + r- + + Approximate time in milliseconds from the creation of a + set of unused muzzy pages until an equivalent set of unused muzzy pages + is purged (i.e. converted to clean) and/or reused. Muzzy pages are + defined as previously having been unused dirty pages that were + subsequently purged in a manner that left them subject to the + reclamation whims of the operating system (e.g. + madvise(...MADV_FREE)), + and therefore in an indeterminate state. The pages are incrementally + purged according to a sigmoidal decay curve that starts and ends with + zero purge rate. A decay time of 0 causes all unused muzzy pages to be + purged immediately upon creation. A decay time of -1 disables purging. + The default decay time is 10 seconds. See arenas.muzzy_decay_ms + and arena.<i>.muzzy_decay_ms + for related dynamic control options. + + + + + opt.lg_extent_max_active_fit + (size_t) + r- + + When reusing dirty extents, this determines the (log + base 2 of the) maximum ratio between the size of the active extent + selected (to split off from) and the size of the requested allocation. + This prevents the splitting of large active extents for smaller + allocations, which can reduce fragmentation over the long run + (especially for non-active extents). Lower value may reduce + fragmentation, at the cost of extra active extents. The default value + is 6, which gives a maximum ratio of 64 (2^6). + + + + + opt.stats_print + (bool) + r- + + Enable/disable statistics printing at exit. If + enabled, the malloc_stats_print() + function is called at program exit via an + atexit + 3 function. opt.stats_print_opts + can be combined to specify output options. If + is specified during configuration, this + has the potential to cause deadlock for a multi-threaded process that + exits while one or more threads are executing in the memory allocation + functions. Furthermore, atexit() may + allocate memory during application initialization and then deadlock + internally when jemalloc in turn calls + atexit(), so this option is not + universally usable (though the application can register its own + atexit() function with equivalent + functionality). Therefore, this option should only be used with care; + it is primarily intended as a performance tuning aid during application + development. This option is disabled by default. + + + + + opt.stats_print_opts + (const char *) + r- + + Options (the opts string) to pass + to the malloc_stats_print() at exit (enabled + through opt.stats_print). See + available options in malloc_stats_print(). + Has no effect unless opt.stats_print is + enabled. The default is . + + + + + opt.junk + (const char *) + r- + [] + + Junk filling. If set to alloc, each byte + of uninitialized allocated memory will be initialized to + 0xa5. If set to free, all deallocated + memory will be initialized to 0x5a. If set to + true, both allocated and deallocated memory will be + initialized, and if set to false, junk filling be + disabled entirely. This is intended for debugging and will impact + performance negatively. This option is false by default + unless is specified during + configuration, in which case it is true by + default. + + + + + opt.zero + (bool) + r- + [] + + Zero filling enabled/disabled. If enabled, each byte + of uninitialized allocated memory will be initialized to 0. Note that + this initialization only happens once for each byte, so + realloc() and + rallocx() calls do not zero memory that + was previously allocated. This is intended for debugging and will + impact performance negatively. This option is disabled by default. + + + + + + opt.utrace + (bool) + r- + [] + + Allocation tracing based on + utrace + 2 enabled/disabled. This option + is disabled by default. + + + + + opt.xmalloc + (bool) + r- + [] + + Abort-on-out-of-memory enabled/disabled. If enabled, + rather than returning failure for any allocation function, display a + diagnostic message on STDERR_FILENO and cause the + program to drop core (using + abort + 3). If an application is + designed to depend on this behavior, set the option at compile time by + including the following in the source code: + + This option is disabled by default. + + + + + opt.tcache + (bool) + r- + + Thread-specific caching (tcache) enabled/disabled. When + there are multiple threads, each thread uses a tcache for objects up to + a certain size. Thread-specific caching allows many allocations to be + satisfied without performing any thread synchronization, at the cost of + increased memory use. See the opt.lg_tcache_max + option for related tuning information. This option is enabled by + default. + + + + + opt.lg_tcache_max + (size_t) + r- + + Maximum size class (log base 2) to cache in the + thread-specific cache (tcache). At a minimum, all small size classes + are cached, and at a maximum all large size classes are cached. The + default maximum is 32 KiB (2^15). + + + + + opt.thp + (const char *) + r- + + Transparent hugepage (THP) mode. Settings "always", + "never" and "default" are available if THP is supported by the operating + system. The "always" setting enables transparent hugepage for all user + memory mappings with + MADV_HUGEPAGE; "never" + ensures no transparent hugepage with + MADV_NOHUGEPAGE; the default + setting "default" makes no changes. Note that: this option does not + affect THP for jemalloc internal metadata (see opt.metadata_thp); + in addition, for arenas with customized extent_hooks, + this option is bypassed as it is implemented as part of the default + extent hooks. + + + + + opt.prof + (bool) + r- + [] + + Memory profiling enabled/disabled. If enabled, profile + memory allocation activity. See the opt.prof_active + option for on-the-fly activation/deactivation. See the opt.lg_prof_sample + option for probabilistic sampling control. See the opt.prof_accum + option for control of cumulative sample reporting. See the opt.lg_prof_interval + option for information on interval-triggered profile dumping, the opt.prof_gdump + option for information on high-water-triggered profile dumping, and the + opt.prof_final + option for final profile dumping. Profile output is compatible with + the jeprof command, which is based on the + pprof that is developed as part of the gperftools + package. See HEAP PROFILE + FORMAT for heap profile format documentation. + + + + + opt.prof_prefix + (const char *) + r- + [] + + Filename prefix for profile dumps. If the prefix is + set to the empty string, no automatic dumps will occur; this is + primarily useful for disabling the automatic final heap dump (which + also disables leak reporting, if enabled). The default prefix is + jeprof. + + + + + opt.prof_active + (bool) + r- + [] + + Profiling activated/deactivated. This is a secondary + control mechanism that makes it possible to start the application with + profiling enabled (see the opt.prof option) but + inactive, then toggle profiling at any time during program execution + with the prof.active mallctl. + This option is enabled by default. + + + + + opt.prof_thread_active_init + (bool) + r- + [] + + Initial setting for thread.prof.active + in newly created threads. The initial setting for newly created threads + can also be changed during execution via the prof.thread_active_init + mallctl. This option is enabled by default. + + + + + opt.lg_prof_sample + (size_t) + r- + [] + + Average interval (log base 2) between allocation + samples, as measured in bytes of allocation activity. Increasing the + sampling interval decreases profile fidelity, but also decreases the + computational overhead. The default sample interval is 512 KiB (2^19 + B). + + + + + opt.prof_accum + (bool) + r- + [] + + Reporting of cumulative object/byte counts in profile + dumps enabled/disabled. If this option is enabled, every unique + backtrace must be stored for the duration of execution. Depending on + the application, this can impose a large memory overhead, and the + cumulative counts are not always of interest. This option is disabled + by default. + + + + + opt.lg_prof_interval + (ssize_t) + r- + [] + + Average interval (log base 2) between memory profile + dumps, as measured in bytes of allocation activity. The actual + interval between dumps may be sporadic because decentralized allocation + counters are used to avoid synchronization bottlenecks. Profiles are + dumped to files named according to the pattern + <prefix>.<pid>.<seq>.i<iseq>.heap, + where <prefix> is controlled by the + opt.prof_prefix + option. By default, interval-triggered profile dumping is disabled + (encoded as -1). + + + + + + opt.prof_gdump + (bool) + r- + [] + + Set the initial state of prof.gdump, which when + enabled triggers a memory profile dump every time the total virtual + memory exceeds the previous maximum. This option is disabled by + default. + + + + + opt.prof_final + (bool) + r- + [] + + Use an + atexit + 3 function to dump final memory + usage to a file named according to the pattern + <prefix>.<pid>.<seq>.f.heap, + where <prefix> is controlled by the opt.prof_prefix + option. Note that atexit() may allocate + memory during application initialization and then deadlock internally + when jemalloc in turn calls atexit(), so + this option is not universally usable (though the application can + register its own atexit() function with + equivalent functionality). This option is disabled by + default. + + + + + opt.prof_leak + (bool) + r- + [] + + Leak reporting enabled/disabled. If enabled, use an + atexit + 3 function to report memory leaks + detected by allocation sampling. See the + opt.prof option for + information on analyzing heap profile output. This option is disabled + by default. + + + + + thread.arena + (unsigned) + rw + + Get or set the arena associated with the calling + thread. If the specified arena was not initialized beforehand (see the + arena.i.initialized + mallctl), it will be automatically initialized as a side effect of + calling this interface. + + + + + thread.allocated + (uint64_t) + r- + [] + + Get the total number of bytes ever allocated by the + calling thread. This counter has the potential to wrap around; it is + up to the application to appropriately interpret the counter in such + cases. + + + + + thread.allocatedp + (uint64_t *) + r- + [] + + Get a pointer to the the value that is returned by the + thread.allocated + mallctl. This is useful for avoiding the overhead of repeated + mallctl*() calls. + + + + + thread.deallocated + (uint64_t) + r- + [] + + Get the total number of bytes ever deallocated by the + calling thread. This counter has the potential to wrap around; it is + up to the application to appropriately interpret the counter in such + cases. + + + + + thread.deallocatedp + (uint64_t *) + r- + [] + + Get a pointer to the the value that is returned by the + thread.deallocated + mallctl. This is useful for avoiding the overhead of repeated + mallctl*() calls. + + + + + thread.tcache.enabled + (bool) + rw + + Enable/disable calling thread's tcache. The tcache is + implicitly flushed as a side effect of becoming + disabled (see thread.tcache.flush). + + + + + + thread.tcache.flush + (void) + -- + + Flush calling thread's thread-specific cache (tcache). + This interface releases all cached objects and internal data structures + associated with the calling thread's tcache. Ordinarily, this interface + need not be called, since automatic periodic incremental garbage + collection occurs, and the thread cache is automatically discarded when + a thread exits. However, garbage collection is triggered by allocation + activity, so it is possible for a thread that stops + allocating/deallocating to retain its cache indefinitely, in which case + the developer may find manual flushing useful. + + + + + thread.prof.name + (const char *) + r- or + -w + [] + + Get/set the descriptive name associated with the calling + thread in memory profile dumps. An internal copy of the name string is + created, so the input string need not be maintained after this interface + completes execution. The output string of this interface should be + copied for non-ephemeral uses, because multiple implementation details + can cause asynchronous string deallocation. Furthermore, each + invocation of this interface can only read or write; simultaneous + read/write is not supported due to string lifetime limitations. The + name string must be nil-terminated and comprised only of characters in + the sets recognized + by isgraph + 3 and + isblank + 3. + + + + + thread.prof.active + (bool) + rw + [] + + Control whether sampling is currently active for the + calling thread. This is an activation mechanism in addition to prof.active; both must + be active for the calling thread to sample. This flag is enabled by + default. + + + + + tcache.create + (unsigned) + r- + + Create an explicit thread-specific cache (tcache) and + return an identifier that can be passed to the MALLOCX_TCACHE(tc) + macro to explicitly use the specified cache rather than the + automatically managed one that is used by default. Each explicit cache + can be used by only one thread at a time; the application must assure + that this constraint holds. + + + + + + tcache.flush + (unsigned) + -w + + Flush the specified thread-specific cache (tcache). The + same considerations apply to this interface as to thread.tcache.flush, + except that the tcache will never be automatically discarded. + + + + + + tcache.destroy + (unsigned) + -w + + Flush the specified thread-specific cache (tcache) and + make the identifier available for use during a future tcache creation. + + + + + + arena.<i>.initialized + (bool) + r- + + Get whether the specified arena's statistics are + initialized (i.e. the arena was initialized prior to the current epoch). + This interface can also be nominally used to query whether the merged + statistics corresponding to MALLCTL_ARENAS_ALL are + initialized (always true). + + + + + arena.<i>.decay + (void) + -- + + Trigger decay-based purging of unused dirty/muzzy pages + for arena <i>, or for all arenas if <i> equals + MALLCTL_ARENAS_ALL. The proportion of unused + dirty/muzzy pages to be purged depends on the current time; see opt.dirty_decay_ms + and opt.muzy_decay_ms + for details. + + + + + arena.<i>.purge + (void) + -- + + Purge all unused dirty pages for arena <i>, or for + all arenas if <i> equals MALLCTL_ARENAS_ALL. + + + + + + arena.<i>.reset + (void) + -- + + Discard all of the arena's extant allocations. This + interface can only be used with arenas explicitly created via arenas.create. None + of the arena's discarded/cached allocations may accessed afterward. As + part of this requirement, all thread caches which were used to + allocate/deallocate in conjunction with the arena must be flushed + beforehand. + + + + + arena.<i>.destroy + (void) + -- + + Destroy the arena. Discard all of the arena's extant + allocations using the same mechanism as for arena.<i>.reset + (with all the same constraints and side effects), merge the arena stats + into those accessible at arena index + MALLCTL_ARENAS_DESTROYED, and then completely + discard all metadata associated with the arena. Future calls to arenas.create may + recycle the arena index. Destruction will fail if any threads are + currently associated with the arena as a result of calls to thread.arena. + + + + + arena.<i>.dss + (const char *) + rw + + Set the precedence of dss allocation as related to mmap + allocation for arena <i>, or for all arenas if <i> equals + MALLCTL_ARENAS_ALL. See opt.dss for supported + settings. + + + + + arena.<i>.dirty_decay_ms + (ssize_t) + rw + + Current per-arena approximate time in milliseconds from + the creation of a set of unused dirty pages until an equivalent set of + unused dirty pages is purged and/or reused. Each time this interface is + set, all currently unused dirty pages are considered to have fully + decayed, which causes immediate purging of all unused dirty pages unless + the decay time is set to -1 (i.e. purging disabled). See opt.dirty_decay_ms + for additional information. + + + + + arena.<i>.muzzy_decay_ms + (ssize_t) + rw + + Current per-arena approximate time in milliseconds from + the creation of a set of unused muzzy pages until an equivalent set of + unused muzzy pages is purged and/or reused. Each time this interface is + set, all currently unused muzzy pages are considered to have fully + decayed, which causes immediate purging of all unused muzzy pages unless + the decay time is set to -1 (i.e. purging disabled). See opt.muzzy_decay_ms + for additional information. + + + + + arena.<i>.retain_grow_limit + (size_t) + rw + + Maximum size to grow retained region (only relevant when + opt.retain is + enabled). This controls the maximum increment to expand virtual memory, + or allocation through arena.<i>extent_hooks. + In particular, if customized extent hooks reserve physical memory + (e.g. 1G huge pages), this is useful to control the allocation hook's + input size. The default is no limit. + + + + + arena.<i>.extent_hooks + (extent_hooks_t *) + rw + + Get or set the extent management hook functions for + arena <i>. The functions must be capable of operating on all + extant extents associated with arena <i>, usually by passing + unknown extents to the replaced functions. In practice, it is feasible + to control allocation for arenas explicitly created via arenas.create such + that all extents originate from an application-supplied extent allocator + (by specifying the custom extent hook functions during arena creation). + However, the API guarantees for the automatically created arenas may be + relaxed -- hooks set there may be called in a "best effort" fashion; in + addition there may be extents created prior to the application having an + opportunity to take over extent allocation. + + + The extent_hooks_t structure comprises function + pointers which are described individually below. jemalloc uses these + functions to manage extent lifetime, which starts off with allocation of + mapped committed memory, in the simplest case followed by deallocation. + However, there are performance and platform reasons to retain extents + for later reuse. Cleanup attempts cascade from deallocation to decommit + to forced purging to lazy purging, which gives the extent management + functions opportunities to reject the most permanent cleanup operations + in favor of less permanent (and often less costly) operations. All + operations except allocation can be universally opted out of by setting + the hook pointers to NULL, or selectively opted out + of by returning failure. Note that once the extent hook is set, the + structure is accessed directly by the associated arenas, so it must + remain valid for the entire lifetime of the arenas. + + + typedef void *(extent_alloc_t) + extent_hooks_t *extent_hooks + void *new_addr + size_t size + size_t alignment + bool *zero + bool *commit + unsigned arena_ind + + + An extent allocation function conforms to the + extent_alloc_t type and upon success returns a pointer to + size bytes of mapped memory on behalf of arena + arena_ind such that the extent's base address is + a multiple of alignment, as well as setting + *zero to indicate whether the extent is zeroed + and *commit to indicate whether the extent is + committed. Upon error the function returns NULL + and leaves *zero and + *commit unmodified. The + size parameter is always a multiple of the page + size. The alignment parameter is always a power + of two at least as large as the page size. Zeroing is mandatory if + *zero is true upon function entry. Committing is + mandatory if *commit is true upon function entry. + If new_addr is not NULL, the + returned pointer must be new_addr on success or + NULL on error. Committed memory may be committed + in absolute terms as on a system that does not overcommit, or in + implicit terms as on a system that overcommits and satisfies physical + memory needs on demand via soft page faults. Note that replacing the + default extent allocation function makes the arena's arena.<i>.dss + setting irrelevant. + + + typedef bool (extent_dalloc_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + bool committed + unsigned arena_ind + + + + An extent deallocation function conforms to the + extent_dalloc_t type and deallocates an extent at given + addr and size with + committed/decommited memory as indicated, on + behalf of arena arena_ind, returning false upon + success. If the function returns true, this indicates opt-out from + deallocation; the virtual memory mapping associated with the extent + remains mapped, in the same commit state, and available for future use, + in which case it will be automatically retained for later reuse. + + + typedef void (extent_destroy_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + bool committed + unsigned arena_ind + + + + An extent destruction function conforms to the + extent_destroy_t type and unconditionally destroys an + extent at given addr and + size with + committed/decommited memory as indicated, on + behalf of arena arena_ind. This function may be + called to destroy retained extents during arena destruction (see arena.<i>.destroy). + + + typedef bool (extent_commit_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + size_t offset + size_t length + unsigned arena_ind + + + An extent commit function conforms to the + extent_commit_t type and commits zeroed physical memory to + back pages within an extent at given addr and + size at offset bytes, + extending for length on behalf of arena + arena_ind, returning false upon success. + Committed memory may be committed in absolute terms as on a system that + does not overcommit, or in implicit terms as on a system that + overcommits and satisfies physical memory needs on demand via soft page + faults. If the function returns true, this indicates insufficient + physical memory to satisfy the request. + + + typedef bool (extent_decommit_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + size_t offset + size_t length + unsigned arena_ind + + + An extent decommit function conforms to the + extent_decommit_t type and decommits any physical memory + that is backing pages within an extent at given + addr and size at + offset bytes, extending for + length on behalf of arena + arena_ind, returning false upon success, in which + case the pages will be committed via the extent commit function before + being reused. If the function returns true, this indicates opt-out from + decommit; the memory remains committed and available for future use, in + which case it will be automatically retained for later reuse. + + + typedef bool (extent_purge_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + size_t offset + size_t length + unsigned arena_ind + + + An extent purge function conforms to the + extent_purge_t type and discards physical pages + within the virtual memory mapping associated with an extent at given + addr and size at + offset bytes, extending for + length on behalf of arena + arena_ind. A lazy extent purge function (e.g. + implemented via + madvise(...MADV_FREE)) + can delay purging indefinitely and leave the pages within the purged + virtual memory range in an indeterminite state, whereas a forced extent + purge function immediately purges, and the pages within the virtual + memory range will be zero-filled the next time they are accessed. If + the function returns true, this indicates failure to purge. + + + typedef bool (extent_split_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + size_t size_a + size_t size_b + bool committed + unsigned arena_ind + + + An extent split function conforms to the + extent_split_t type and optionally splits an extent at + given addr and size into + two adjacent extents, the first of size_a bytes, + and the second of size_b bytes, operating on + committed/decommitted memory as indicated, on + behalf of arena arena_ind, returning false upon + success. If the function returns true, this indicates that the extent + remains unsplit and therefore should continue to be operated on as a + whole. + + + typedef bool (extent_merge_t) + extent_hooks_t *extent_hooks + void *addr_a + size_t size_a + void *addr_b + size_t size_b + bool committed + unsigned arena_ind + + + An extent merge function conforms to the + extent_merge_t type and optionally merges adjacent extents, + at given addr_a and size_a + with given addr_b and + size_b into one contiguous extent, operating on + committed/decommitted memory as indicated, on + behalf of arena arena_ind, returning false upon + success. If the function returns true, this indicates that the extents + remain distinct mappings and therefore should continue to be operated on + independently. + + + + + + arenas.narenas + (unsigned) + r- + + Current limit on number of arenas. + + + + + arenas.dirty_decay_ms + (ssize_t) + rw + + Current default per-arena approximate time in + milliseconds from the creation of a set of unused dirty pages until an + equivalent set of unused dirty pages is purged and/or reused, used to + initialize arena.<i>.dirty_decay_ms + during arena creation. See opt.dirty_decay_ms + for additional information. + + + + + arenas.muzzy_decay_ms + (ssize_t) + rw + + Current default per-arena approximate time in + milliseconds from the creation of a set of unused muzzy pages until an + equivalent set of unused muzzy pages is purged and/or reused, used to + initialize arena.<i>.muzzy_decay_ms + during arena creation. See opt.muzzy_decay_ms + for additional information. + + + + + arenas.quantum + (size_t) + r- + + Quantum size. + + + + + arenas.page + (size_t) + r- + + Page size. + + + + + arenas.tcache_max + (size_t) + r- + + Maximum thread-cached size class. + + + + + arenas.nbins + (unsigned) + r- + + Number of bin size classes. + + + + + arenas.nhbins + (unsigned) + r- + + Total number of thread cache bin size + classes. + + + + + arenas.bin.<i>.size + (size_t) + r- + + Maximum size supported by size class. + + + + + arenas.bin.<i>.nregs + (uint32_t) + r- + + Number of regions per slab. + + + + + arenas.bin.<i>.slab_size + (size_t) + r- + + Number of bytes per slab. + + + + + arenas.nlextents + (unsigned) + r- + + Total number of large size classes. + + + + + arenas.lextent.<i>.size + (size_t) + r- + + Maximum size supported by this large size + class. + + + + + arenas.create + (unsigned, extent_hooks_t *) + rw + + Explicitly create a new arena outside the range of + automatically managed arenas, with optionally specified extent hooks, + and return the new arena index. + + + + + arenas.lookup + (unsigned, void*) + rw + + Index of the arena to which an allocation belongs to. + + + + + prof.thread_active_init + (bool) + rw + [] + + Control the initial setting for thread.prof.active + in newly created threads. See the opt.prof_thread_active_init + option for additional information. + + + + + prof.active + (bool) + rw + [] + + Control whether sampling is currently active. See the + opt.prof_active + option for additional information, as well as the interrelated thread.prof.active + mallctl. + + + + + prof.dump + (const char *) + -w + [] + + Dump a memory profile to the specified file, or if NULL + is specified, to a file according to the pattern + <prefix>.<pid>.<seq>.m<mseq>.heap, + where <prefix> is controlled by the + opt.prof_prefix + option. + + + + + prof.gdump + (bool) + rw + [] + + When enabled, trigger a memory profile dump every time + the total virtual memory exceeds the previous maximum. Profiles are + dumped to files named according to the pattern + <prefix>.<pid>.<seq>.u<useq>.heap, + where <prefix> is controlled by the opt.prof_prefix + option. + + + + + prof.reset + (size_t) + -w + [] + + Reset all memory profile statistics, and optionally + update the sample rate (see opt.lg_prof_sample + and prof.lg_sample). + + + + + + prof.lg_sample + (size_t) + r- + [] + + Get the current sample rate (see opt.lg_prof_sample). + + + + + + prof.interval + (uint64_t) + r- + [] + + Average number of bytes allocated between + interval-based profile dumps. See the + opt.lg_prof_interval + option for additional information. + + + + + stats.allocated + (size_t) + r- + [] + + Total number of bytes allocated by the + application. + + + + + stats.active + (size_t) + r- + [] + + Total number of bytes in active pages allocated by the + application. This is a multiple of the page size, and greater than or + equal to stats.allocated. + This does not include + stats.arenas.<i>.pdirty, + + stats.arenas.<i>.pmuzzy, nor pages + entirely devoted to allocator metadata. + + + + + stats.metadata + (size_t) + r- + [] + + Total number of bytes dedicated to metadata, which + comprise base allocations used for bootstrap-sensitive allocator + metadata structures (see stats.arenas.<i>.base) + and internal allocations (see stats.arenas.<i>.internal). + Transparent huge page (enabled with opt.metadata_thp) usage is not + considered. + + + + + stats.metadata_thp + (size_t) + r- + [] + + Number of transparent huge pages (THP) used for + metadata. See stats.metadata and + opt.metadata_thp) for + details. + + + + + stats.resident + (size_t) + r- + [] + + Maximum number of bytes in physically resident data + pages mapped by the allocator, comprising all pages dedicated to + allocator metadata, pages backing active allocations, and unused dirty + pages. This is a maximum rather than precise because pages may not + actually be physically resident if they correspond to demand-zeroed + virtual memory that has not yet been touched. This is a multiple of the + page size, and is larger than stats.active. + + + + + stats.mapped + (size_t) + r- + [] + + Total number of bytes in active extents mapped by the + allocator. This is larger than stats.active. This + does not include inactive extents, even those that contain unused dirty + pages, which means that there is no strict ordering between this and + stats.resident. + + + + + stats.retained + (size_t) + r- + [] + + Total number of bytes in virtual memory mappings that + were retained rather than being returned to the operating system via + e.g. munmap + 2 or similar. Retained virtual + memory is typically untouched, decommitted, or purged, so it has no + strongly associated physical memory (see extent hooks for details). + Retained memory is excluded from mapped memory statistics, e.g. stats.mapped. + + + + + + stats.background_thread.num_threads + (size_t) + r- + [] + + Number of background + threads running currently. + + + + + stats.background_thread.num_runs + (uint64_t) + r- + [] + + Total number of runs from all background threads. + + + + + stats.background_thread.run_interval + (uint64_t) + r- + [] + + Average run interval in nanoseconds of background threads. + + + + + stats.mutexes.ctl.{counter}; + (counter specific type) + r- + [] + + Statistics on ctl mutex (global + scope; mallctl related). {counter} is one of the + counters below: + + num_ops (uint64_t): + Total number of lock acquisition operations on this mutex. + + num_spin_acq (uint64_t): Number + of times the mutex was spin-acquired. When the mutex is currently + locked and cannot be acquired immediately, a short period of + spin-retry within jemalloc will be performed. Acquired through spin + generally means the contention was lightweight and not causing context + switches. + + num_wait (uint64_t): Number of + times the mutex was wait-acquired, which means the mutex contention + was not solved by spin-retry, and blocking operation was likely + involved in order to acquire the mutex. This event generally implies + higher cost / longer delay, and should be investigated if it happens + often. + + max_wait_time (uint64_t): + Maximum length of time in nanoseconds spent on a single wait-acquired + lock operation. Note that to avoid profiling overhead on the common + path, this does not consider spin-acquired cases. + + total_wait_time (uint64_t): + Cumulative time in nanoseconds spent on wait-acquired lock operations. + Similarly, spin-acquired cases are not considered. + + max_num_thds (uint32_t): Maximum + number of threads waiting on this mutex simultaneously. Similarly, + spin-acquired cases are not considered. + + num_owner_switch (uint64_t): + Number of times the current mutex owner is different from the previous + one. This event does not generally imply an issue; rather it is an + indicator of how often the protected data are accessed by different + threads. + + + + + + + + + stats.mutexes.background_thread.{counter} + (counter specific type) r- + [] + + Statistics on background_thread mutex + (global scope; background_thread + related). {counter} is one of the counters in mutex profiling + counters. + + + + + stats.mutexes.prof.{counter} + (counter specific type) r- + [] + + Statistics on prof mutex (global + scope; profiling related). {counter} is one of the + counters in mutex profiling + counters. + + + + + stats.mutexes.reset + (void) -- + [] + + Reset all mutex profile statistics, including global + mutexes, arena mutexes and bin mutexes. + + + + + stats.arenas.<i>.dss + (const char *) + r- + + dss (sbrk + 2) allocation precedence as + related to mmap + 2 allocation. See opt.dss for details. + + + + + + stats.arenas.<i>.dirty_decay_ms + (ssize_t) + r- + + Approximate time in milliseconds from the creation of a + set of unused dirty pages until an equivalent set of unused dirty pages + is purged and/or reused. See opt.dirty_decay_ms + for details. + + + + + stats.arenas.<i>.muzzy_decay_ms + (ssize_t) + r- + + Approximate time in milliseconds from the creation of a + set of unused muzzy pages until an equivalent set of unused muzzy pages + is purged and/or reused. See opt.muzzy_decay_ms + for details. + + + + + stats.arenas.<i>.nthreads + (unsigned) + r- + + Number of threads currently assigned to + arena. + + + + + stats.arenas.<i>.uptime + (uint64_t) + r- + + Time elapsed (in nanoseconds) since the arena was + created. If <i> equals 0 or + MALLCTL_ARENAS_ALL, this is the uptime since malloc + initialization. + + + + + stats.arenas.<i>.pactive + (size_t) + r- + + Number of pages in active extents. + + + + + stats.arenas.<i>.pdirty + (size_t) + r- + + Number of pages within unused extents that are + potentially dirty, and for which madvise() or + similar has not been called. See opt.dirty_decay_ms + for a description of dirty pages. + + + + + stats.arenas.<i>.pmuzzy + (size_t) + r- + + Number of pages within unused extents that are muzzy. + See opt.muzzy_decay_ms + for a description of muzzy pages. + + + + + stats.arenas.<i>.mapped + (size_t) + r- + [] + + Number of mapped bytes. + + + + + stats.arenas.<i>.retained + (size_t) + r- + [] + + Number of retained bytes. See stats.retained for + details. + + + + + stats.arenas.<i>.extent_avail + (size_t) + r- + [] + + Number of allocated (but unused) extent structs in this + arena. + + + + + stats.arenas.<i>.base + (size_t) + r- + [] + + + Number of bytes dedicated to bootstrap-sensitive allocator metadata + structures. + + + + + stats.arenas.<i>.internal + (size_t) + r- + [] + + Number of bytes dedicated to internal allocations. + Internal allocations differ from application-originated allocations in + that they are for internal use, and that they are omitted from heap + profiles. + + + + + stats.arenas.<i>.metadata_thp + (size_t) + r- + [] + + Number of transparent huge pages (THP) used for + metadata. See opt.metadata_thp + for details. + + + + + stats.arenas.<i>.resident + (size_t) + r- + [] + + Maximum number of bytes in physically resident data + pages mapped by the arena, comprising all pages dedicated to allocator + metadata, pages backing active allocations, and unused dirty pages. + This is a maximum rather than precise because pages may not actually be + physically resident if they correspond to demand-zeroed virtual memory + that has not yet been touched. This is a multiple of the page + size. + + + + + stats.arenas.<i>.dirty_npurge + (uint64_t) + r- + [] + + Number of dirty page purge sweeps performed. + + + + + + stats.arenas.<i>.dirty_nmadvise + (uint64_t) + r- + [] + + Number of madvise() or similar + calls made to purge dirty pages. + + + + + stats.arenas.<i>.dirty_purged + (uint64_t) + r- + [] + + Number of dirty pages purged. + + + + + stats.arenas.<i>.muzzy_npurge + (uint64_t) + r- + [] + + Number of muzzy page purge sweeps performed. + + + + + + stats.arenas.<i>.muzzy_nmadvise + (uint64_t) + r- + [] + + Number of madvise() or similar + calls made to purge muzzy pages. + + + + + stats.arenas.<i>.muzzy_purged + (uint64_t) + r- + [] + + Number of muzzy pages purged. + + + + + stats.arenas.<i>.small.allocated + (size_t) + r- + [] + + Number of bytes currently allocated by small objects. + + + + + + stats.arenas.<i>.small.nmalloc + (uint64_t) + r- + [] + + Cumulative number of times a small allocation was + requested from the arena's bins, whether to fill the relevant tcache if + opt.tcache is + enabled, or to directly satisfy an allocation request + otherwise. + + + + + stats.arenas.<i>.small.ndalloc + (uint64_t) + r- + [] + + Cumulative number of times a small allocation was + returned to the arena's bins, whether to flush the relevant tcache if + opt.tcache is + enabled, or to directly deallocate an allocation + otherwise. + + + + + stats.arenas.<i>.small.nrequests + (uint64_t) + r- + [] + + Cumulative number of allocation requests satisfied by + all bin size classes. + + + + + stats.arenas.<i>.small.nfills + (uint64_t) + r- + [] + + Cumulative number of tcache fills by all small size + classes. + + + + + stats.arenas.<i>.small.nflushes + (uint64_t) + r- + [] + + Cumulative number of tcache flushes by all small size + classes. + + + + + stats.arenas.<i>.large.allocated + (size_t) + r- + [] + + Number of bytes currently allocated by large objects. + + + + + + stats.arenas.<i>.large.nmalloc + (uint64_t) + r- + [] + + Cumulative number of times a large extent was allocated + from the arena, whether to fill the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly satisfy + an allocation request otherwise. + + + + + stats.arenas.<i>.large.ndalloc + (uint64_t) + r- + [] + + Cumulative number of times a large extent was returned + to the arena, whether to flush the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly + deallocate an allocation otherwise. + + + + + stats.arenas.<i>.large.nrequests + (uint64_t) + r- + [] + + Cumulative number of allocation requests satisfied by + all large size classes. + + + + + stats.arenas.<i>.large.nfills + (uint64_t) + r- + [] + + Cumulative number of tcache fills by all large size + classes. + + + + + stats.arenas.<i>.large.nflushes + (uint64_t) + r- + [] + + Cumulative number of tcache flushes by all large size + classes. + + + + + stats.arenas.<i>.bins.<j>.nmalloc + (uint64_t) + r- + [] + + Cumulative number of times a bin region of the + corresponding size class was allocated from the arena, whether to fill + the relevant tcache if opt.tcache is enabled, or + to directly satisfy an allocation request otherwise. + + + + + stats.arenas.<i>.bins.<j>.ndalloc + (uint64_t) + r- + [] + + Cumulative number of times a bin region of the + corresponding size class was returned to the arena, whether to flush the + relevant tcache if opt.tcache is enabled, or + to directly deallocate an allocation otherwise. + + + + + stats.arenas.<i>.bins.<j>.nrequests + (uint64_t) + r- + [] + + Cumulative number of allocation requests satisfied by + bin regions of the corresponding size class. + + + + + stats.arenas.<i>.bins.<j>.curregs + (size_t) + r- + [] + + Current number of regions for this size + class. + + + + + stats.arenas.<i>.bins.<j>.nfills + (uint64_t) + r- + + Cumulative number of tcache fills. + + + + + stats.arenas.<i>.bins.<j>.nflushes + (uint64_t) + r- + + Cumulative number of tcache flushes. + + + + + stats.arenas.<i>.bins.<j>.nslabs + (uint64_t) + r- + [] + + Cumulative number of slabs created. + + + + + stats.arenas.<i>.bins.<j>.nreslabs + (uint64_t) + r- + [] + + Cumulative number of times the current slab from which + to allocate changed. + + + + + stats.arenas.<i>.bins.<j>.curslabs + (size_t) + r- + [] + + Current number of slabs. + + + + + + stats.arenas.<i>.bins.<j>.nonfull_slabs + (size_t) + r- + [] + + Current number of nonfull slabs. + + + + + stats.arenas.<i>.bins.<j>.mutex.{counter} + (counter specific type) r- + [] + + Statistics on + arena.<i>.bins.<j> mutex (arena bin + scope; bin operation related). {counter} is one of + the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.extents.<j>.n{extent_type} + (size_t) + r- + [] + + Number of extents of the given type in this arena in + the bucket corresponding to page size index <j>. The extent type + is one of dirty, muzzy, or retained. + + + + + stats.arenas.<i>.extents.<j>.{extent_type}_bytes + (size_t) + r- + [] + + Sum of the bytes managed by extents of the given type + in this arena in the bucket corresponding to page size index <j>. + The extent type is one of dirty, muzzy, or retained. + + + + + stats.arenas.<i>.lextents.<j>.nmalloc + (uint64_t) + r- + [] + + Cumulative number of times a large extent of the + corresponding size class was allocated from the arena, whether to fill + the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly satisfy + an allocation request otherwise. + + + + + stats.arenas.<i>.lextents.<j>.ndalloc + (uint64_t) + r- + [] + + Cumulative number of times a large extent of the + corresponding size class was returned to the arena, whether to flush the + relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly + deallocate an allocation otherwise. + + + + + stats.arenas.<i>.lextents.<j>.nrequests + (uint64_t) + r- + [] + + Cumulative number of allocation requests satisfied by + large extents of the corresponding size class. + + + + + stats.arenas.<i>.lextents.<j>.curlextents + (size_t) + r- + [] + + Current number of large allocations for this size class. + + + + + + stats.arenas.<i>.mutexes.large.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.large + mutex (arena scope; large allocation related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extent_avail.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extent_avail + mutex (arena scope; extent avail related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_dirty.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_dirty + mutex (arena scope; dirty extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_muzzy.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_muzzy + mutex (arena scope; muzzy extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_retained.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_retained + mutex (arena scope; retained extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.decay_dirty.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.decay_dirty + mutex (arena scope; decay for dirty pages related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.decay_muzzy.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.decay_muzzy + mutex (arena scope; decay for muzzy pages related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.base.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.base + mutex (arena scope; base allocator related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.tcache_list.{counter} + (counter specific type) r- + [] + + Statistics on + arena.<i>.tcache_list mutex (arena scope; + tcache to arena association related). This mutex is expected to be + accessed less often. {counter} is one of the + counters in mutex profiling + counters. + + + + + + HEAP PROFILE FORMAT + Although the heap profiling functionality was originally designed to + be compatible with the + pprof command that is developed as part of the gperftools + package, the addition of per thread heap profiling functionality + required a different heap profile format. The jeprof + command is derived from pprof, with enhancements to + support the heap profile format described here. + + In the following hypothetical heap profile, [...] + indicates elision for the sake of compactness. The following matches the above heap profile, but most +tokens are replaced with <description> to indicate +descriptions of the corresponding fields. / + : : [: ] + [...] + : : [: ] + [...] + : : [: ] + [...] +@ [...] [...] + : : [: ] + : : [: ] + : : [: ] +[...] + +MAPPED_LIBRARIES: +/maps>]]> + + + + DEBUGGING MALLOC PROBLEMS + When debugging, it is a good idea to configure/build jemalloc with + the and + options, and recompile the program with suitable options and symbols for + debugger support. When so configured, jemalloc incorporates a wide variety + of run-time assertions that catch application errors such as double-free, + write-after-free, etc. + + Programs often accidentally depend on uninitialized + memory actually being filled with zero bytes. Junk filling + (see the opt.junk + option) tends to expose such bugs in the form of obviously incorrect + results and/or coredumps. Conversely, zero + filling (see the opt.zero option) eliminates + the symptoms of such bugs. Between these two options, it is usually + possible to quickly detect, diagnose, and eliminate such bugs. + + This implementation does not provide much detail about the problems + it detects, because the performance impact for storing such information + would be prohibitive. + + + DIAGNOSTIC MESSAGES + If any of the memory allocation/deallocation functions detect an + error or warning condition, a message will be printed to file descriptor + STDERR_FILENO. Errors will result in the process + dumping core. If the opt.abort option is set, most + warnings are treated as errors. + + The malloc_message variable allows the programmer + to override the function which emits the text strings forming the errors + and warnings if for some reason the STDERR_FILENO file + descriptor is not suitable for this. + malloc_message() takes the + cbopaque pointer argument that is + NULL unless overridden by the arguments in a call to + malloc_stats_print(), followed by a string + pointer. Please note that doing anything which tries to allocate memory in + this function is likely to result in a crash or deadlock. + + All messages are prefixed by + <jemalloc>: . + + + RETURN VALUES + + Standard API + The malloc() and + calloc() functions return a pointer to the + allocated memory if successful; otherwise a NULL + pointer is returned and errno is set to + ENOMEM. + + The posix_memalign() function + returns the value 0 if successful; otherwise it returns an error value. + The posix_memalign() function will fail + if: + + + EINVAL + + The alignment parameter is + not a power of 2 at least as large as + sizeof(void *). + + + + ENOMEM + + Memory allocation error. + + + + + The aligned_alloc() function returns + a pointer to the allocated memory if successful; otherwise a + NULL pointer is returned and + errno is set. The + aligned_alloc() function will fail if: + + + EINVAL + + The alignment parameter is + not a power of 2. + + + + ENOMEM + + Memory allocation error. + + + + + The realloc() function returns a + pointer, possibly identical to ptr, to the + allocated memory if successful; otherwise a NULL + pointer is returned, and errno is set to + ENOMEM if the error was the result of an + allocation failure. The realloc() + function always leaves the original buffer intact when an error occurs. + + + The free() function returns no + value. + + + Non-standard API + The mallocx() and + rallocx() functions return a pointer to + the allocated memory if successful; otherwise a NULL + pointer is returned to indicate insufficient contiguous memory was + available to service the allocation request. + + The xallocx() function returns the + real size of the resulting resized allocation pointed to by + ptr, which is a value less than + size if the allocation could not be adequately + grown in place. + + The sallocx() function returns the + real size of the allocation pointed to by ptr. + + + The nallocx() returns the real size + that would result from a successful equivalent + mallocx() function call, or zero if + insufficient memory is available to perform the size computation. + + The mallctl(), + mallctlnametomib(), and + mallctlbymib() functions return 0 on + success; otherwise they return an error value. The functions will fail + if: + + + EINVAL + + newp is not + NULL, and newlen is too + large or too small. Alternatively, *oldlenp + is too large or too small; in this case as much data as possible + are read despite the error. + + + ENOENT + + name or + mib specifies an unknown/invalid + value. + + + EPERM + + Attempt to read or write void value, or attempt to + write read-only value. + + + EAGAIN + + A memory allocation failure + occurred. + + + EFAULT + + An interface with side effects failed in some way + not directly related to mallctl*() + read/write processing. + + + + + The malloc_usable_size() function + returns the usable size of the allocation pointed to by + ptr. + + + + ENVIRONMENT + The following environment variable affects the execution of the + allocation functions: + + + MALLOC_CONF + + If the environment variable + MALLOC_CONF is set, the characters it contains + will be interpreted as options. + + + + + + EXAMPLES + To dump core whenever a problem occurs: + ln -s 'abort:true' /etc/malloc.conf + + To specify in the source that only one arena should be automatically + created: + + + + SEE ALSO + madvise + 2, + mmap + 2, + sbrk + 2, + utrace + 2, + alloca + 3, + atexit + 3, + getpagesize + 3 + + + STANDARDS + The malloc(), + calloc(), + realloc(), and + free() functions conform to ISO/IEC + 9899:1990 (ISO C90). + + The posix_memalign() function conforms + to IEEE Std 1003.1-2001 (POSIX.1). + + diff --git a/jemalloc/doc/manpages.xsl.in b/jemalloc/doc/manpages.xsl.in new file mode 100644 index 0000000..88b2626 --- /dev/null +++ b/jemalloc/doc/manpages.xsl.in @@ -0,0 +1,4 @@ + + + + diff --git a/jemalloc/doc/stylesheet.xsl b/jemalloc/doc/stylesheet.xsl new file mode 100644 index 0000000..619365d --- /dev/null +++ b/jemalloc/doc/stylesheet.xsl @@ -0,0 +1,10 @@ + + ansi + + + + + + + + diff --git a/jemalloc/include/jemalloc/internal/arena_externs.h b/jemalloc/include/jemalloc/internal/arena_externs.h new file mode 100644 index 0000000..a4523ae --- /dev/null +++ b/jemalloc/include/jemalloc/internal/arena_externs.h @@ -0,0 +1,104 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H +#define JEMALLOC_INTERNAL_ARENA_EXTERNS_H + +#include "jemalloc/internal/bin.h" +#include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/hook.h" +#include "jemalloc/internal/pages.h" +#include "jemalloc/internal/stats.h" + +extern ssize_t opt_dirty_decay_ms; +extern ssize_t opt_muzzy_decay_ms; + +extern percpu_arena_mode_t opt_percpu_arena; +extern const char *percpu_arena_mode_names[]; + +extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS]; +extern malloc_mutex_t arenas_lock; + +extern size_t opt_oversize_threshold; +extern size_t oversize_threshold; + +void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, + unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms, + ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy); +void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, + size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, + bin_stats_t *bstats, arena_stats_large_t *lstats, + arena_stats_extents_t *estats); +void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); +#ifdef JEMALLOC_JET +size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); +#endif +extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, + size_t usize, size_t alignment, bool *zero); +void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, + extent_t *extent); +void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, size_t oldsize); +void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, size_t oldsize); +ssize_t arena_dirty_decay_ms_get(arena_t *arena); +bool arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); +ssize_t arena_muzzy_decay_ms_get(arena_t *arena); +bool arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); +void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, + bool all); +void arena_reset(tsd_t *tsd, arena_t *arena); +void arena_destroy(tsd_t *tsd, arena_t *arena); +void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, + cache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); +void arena_alloc_junk_small(void *ptr, const bin_info_t *bin_info, + bool zero); + +typedef void (arena_dalloc_junk_small_t)(void *, const bin_info_t *); +extern arena_dalloc_junk_small_t *JET_MUTABLE arena_dalloc_junk_small; + +void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, + szind_t ind, bool zero); +void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, + size_t alignment, bool zero, tcache_t *tcache); +void arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize); +void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + bool slow_path); +void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, bin_t *bin, + szind_t binind, extent_t *extent, void *ptr); +void arena_dalloc_small(tsdn_t *tsdn, void *ptr); +bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, bool zero, size_t *newsize); +void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero, tcache_t *tcache, + hook_ralloc_args_t *hook_args); +dss_prec_t arena_dss_prec_get(arena_t *arena); +bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); +ssize_t arena_dirty_decay_ms_default_get(void); +bool arena_dirty_decay_ms_default_set(ssize_t decay_ms); +ssize_t arena_muzzy_decay_ms_default_get(void); +bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms); +bool arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena, + size_t *old_limit, size_t *new_limit); +unsigned arena_nthreads_get(arena_t *arena, bool internal); +void arena_nthreads_inc(arena_t *arena, bool internal); +void arena_nthreads_dec(arena_t *arena, bool internal); +size_t arena_extent_sn_next(arena_t *arena); +arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +bool arena_init_huge(void); +bool arena_is_huge(unsigned arena_ind); +arena_t *arena_choose_huge(tsd_t *tsd); +bin_t *arena_bin_choose_lock(tsdn_t *tsdn, arena_t *arena, szind_t binind, + unsigned *binshard); +void arena_boot(sc_data_t *sc_data); +void arena_prefork0(tsdn_t *tsdn, arena_t *arena); +void arena_prefork1(tsdn_t *tsdn, arena_t *arena); +void arena_prefork2(tsdn_t *tsdn, arena_t *arena); +void arena_prefork3(tsdn_t *tsdn, arena_t *arena); +void arena_prefork4(tsdn_t *tsdn, arena_t *arena); +void arena_prefork5(tsdn_t *tsdn, arena_t *arena); +void arena_prefork6(tsdn_t *tsdn, arena_t *arena); +void arena_prefork7(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); + +#endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */ diff --git a/jemalloc/include/jemalloc/internal/arena_inlines_a.h b/jemalloc/include/jemalloc/internal/arena_inlines_a.h new file mode 100644 index 0000000..9abf7f6 --- /dev/null +++ b/jemalloc/include/jemalloc/internal/arena_inlines_a.h @@ -0,0 +1,57 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_A_H +#define JEMALLOC_INTERNAL_ARENA_INLINES_A_H + +static inline unsigned +arena_ind_get(const arena_t *arena) { + return base_ind_get(arena->base); +} + +static inline void +arena_internal_add(arena_t *arena, size_t size) { + atomic_fetch_add_zu(&arena->stats.internal, size, ATOMIC_RELAXED); +} + +static inline void +arena_internal_sub(arena_t *arena, size_t size) { + atomic_fetch_sub_zu(&arena->stats.internal, size, ATOMIC_RELAXED); +} + +static inline size_t +arena_internal_get(arena_t *arena) { + return atomic_load_zu(&arena->stats.internal, ATOMIC_RELAXED); +} + +static inline bool +arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { + cassert(config_prof); + + if (likely(prof_interval == 0 || !prof_active_get_unlocked())) { + return false; + } + + return prof_accum_add(tsdn, &arena->prof_accum, accumbytes); +} + +static inline void +percpu_arena_update(tsd_t *tsd, unsigned cpu) { + assert(have_percpu_arena); + arena_t *oldarena = tsd_arena_get(tsd); + assert(oldarena != NULL); + unsigned oldind = arena_ind_get(oldarena); + + if (oldind != cpu) { + unsigned newind = cpu; + arena_t *newarena = arena_get(tsd_tsdn(tsd), newind, true); + assert(newarena != NULL); + + /* Set new arena/tcache associations. */ + arena_migrate(tsd, oldind, newind); + tcache_t *tcache = tcache_get(tsd); + if (tcache != NULL) { + tcache_arena_reassociate(tsd_tsdn(tsd), tcache, + newarena); + } + } +} + +#endif /* JEMALLOC_INTERNAL_ARENA_INLINES_A_H */ diff --git a/jemalloc/include/jemalloc/internal/arena_inlines_b.h b/jemalloc/include/jemalloc/internal/arena_inlines_b.h new file mode 100644 index 0000000..dd92657 --- /dev/null +++ b/jemalloc/include/jemalloc/internal/arena_inlines_b.h @@ -0,0 +1,427 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_B_H +#define JEMALLOC_INTERNAL_ARENA_INLINES_B_H + +#include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" +#include "jemalloc/internal/sc.h" +#include "jemalloc/internal/sz.h" +#include "jemalloc/internal/ticker.h" + +JEMALLOC_ALWAYS_INLINE bool +arena_has_default_hooks(arena_t *arena) { + return (extent_hooks_get(arena) == &extent_hooks_default); +} + +JEMALLOC_ALWAYS_INLINE arena_t * +arena_choose_maybe_huge(tsd_t *tsd, arena_t *arena, size_t size) { + if (arena != NULL) { + return arena; + } + + /* + * For huge allocations, use the dedicated huge arena if both are true: + * 1) is using auto arena selection (i.e. arena == NULL), and 2) the + * thread is not assigned to a manual arena. + */ + if (unlikely(size >= oversize_threshold)) { + arena_t *tsd_arena = tsd_arena_get(tsd); + if (tsd_arena == NULL || arena_is_auto(tsd_arena)) { + return arena_choose_huge(tsd); + } + } + + return arena_choose(tsd, NULL); +} + +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) { + cassert(config_prof); + assert(ptr != NULL); + + /* Static check. */ + if (alloc_ctx == NULL) { + const extent_t *extent = iealloc(tsdn, ptr); + if (unlikely(!extent_slab_get(extent))) { + return large_prof_tctx_get(tsdn, extent); + } + } else { + if (unlikely(!alloc_ctx->slab)) { + return large_prof_tctx_get(tsdn, iealloc(tsdn, ptr)); + } + } + return (prof_tctx_t *)(uintptr_t)1U; +} + +JEMALLOC_ALWAYS_INLINE void +arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, + alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) { + cassert(config_prof); + assert(ptr != NULL); + + /* Static check. */ + if (alloc_ctx == NULL) { + extent_t *extent = iealloc(tsdn, ptr); + if (unlikely(!extent_slab_get(extent))) { + large_prof_tctx_set(tsdn, extent, tctx); + } + } else { + if (unlikely(!alloc_ctx->slab)) { + large_prof_tctx_set(tsdn, iealloc(tsdn, ptr), tctx); + } + } +} + +static inline void +arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) { + cassert(config_prof); + assert(ptr != NULL); + + extent_t *extent = iealloc(tsdn, ptr); + assert(!extent_slab_get(extent)); + + large_prof_tctx_reset(tsdn, extent); +} + +JEMALLOC_ALWAYS_INLINE nstime_t +arena_prof_alloc_time_get(tsdn_t *tsdn, const void *ptr, + alloc_ctx_t *alloc_ctx) { + cassert(config_prof); + assert(ptr != NULL); + + extent_t *extent = iealloc(tsdn, ptr); + /* + * Unlike arena_prof_prof_tctx_{get, set}, we only call this once we're + * sure we have a sampled allocation. + */ + assert(!extent_slab_get(extent)); + return large_prof_alloc_time_get(extent); +} + +JEMALLOC_ALWAYS_INLINE void +arena_prof_alloc_time_set(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx, + nstime_t t) { + cassert(config_prof); + assert(ptr != NULL); + + extent_t *extent = iealloc(tsdn, ptr); + assert(!extent_slab_get(extent)); + large_prof_alloc_time_set(extent, t); +} + +JEMALLOC_ALWAYS_INLINE void +arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) { + tsd_t *tsd; + ticker_t *decay_ticker; + + if (unlikely(tsdn_null(tsdn))) { + return; + } + tsd = tsdn_tsd(tsdn); + decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena)); + if (unlikely(decay_ticker == NULL)) { + return; + } + if (unlikely(ticker_ticks(decay_ticker, nticks))) { + arena_decay(tsdn, arena, false, false); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { + malloc_mutex_assert_not_owner(tsdn, &arena->decay_dirty.mtx); + malloc_mutex_assert_not_owner(tsdn, &arena->decay_muzzy.mtx); + + arena_decay_ticks(tsdn, arena, 1); +} + +/* Purge a single extent to retained / unmapped directly. */ +JEMALLOC_ALWAYS_INLINE void +arena_decay_extent(tsdn_t *tsdn,arena_t *arena, extent_hooks_t **r_extent_hooks, + extent_t *extent) { + size_t extent_size = extent_size_get(extent); + extent_dalloc_wrapper(tsdn, arena, + r_extent_hooks, extent); + if (config_stats) { + /* Update stats accordingly. */ + arena_stats_lock(tsdn, &arena->stats); + arena_stats_add_u64(tsdn, &arena->stats, + &arena->decay_dirty.stats->nmadvise, 1); + arena_stats_add_u64(tsdn, &arena->stats, + &arena->decay_dirty.stats->purged, extent_size >> LG_PAGE); + arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, + extent_size); + arena_stats_unlock(tsdn, &arena->stats); + } +} + +JEMALLOC_ALWAYS_INLINE void * +arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, + tcache_t *tcache, bool slow_path) { + assert(!tsdn_null(tsdn) || tcache == NULL); + + if (likely(tcache != NULL)) { + if (likely(size <= SC_SMALL_MAXCLASS)) { + return tcache_alloc_small(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path); + } + if (likely(size <= tcache_maxclass)) { + return tcache_alloc_large(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path); + } + /* (size > tcache_maxclass) case falls through. */ + assert(size > tcache_maxclass); + } + + return arena_malloc_hard(tsdn, arena, size, ind, zero); +} + +JEMALLOC_ALWAYS_INLINE arena_t * +arena_aalloc(tsdn_t *tsdn, const void *ptr) { + return extent_arena_get(iealloc(tsdn, ptr)); +} + +JEMALLOC_ALWAYS_INLINE size_t +arena_salloc(tsdn_t *tsdn, const void *ptr) { + assert(ptr != NULL); + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true); + assert(szind != SC_NSIZES); + + return sz_index2size(szind); +} + +JEMALLOC_ALWAYS_INLINE size_t +arena_vsalloc(tsdn_t *tsdn, const void *ptr) { + /* + * Return 0 if ptr is not within an extent managed by jemalloc. This + * function has two extra costs relative to isalloc(): + * - The rtree calls cannot claim to be dependent lookups, which induces + * rtree lookup load dependencies. + * - The lookup may fail, so there is an extra branch to check for + * failure. + */ + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + extent_t *extent; + szind_t szind; + if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, false, &extent, &szind)) { + return 0; + } + + if (extent == NULL) { + return 0; + } + assert(extent_state_get(extent) == extent_state_active); + /* Only slab members should be looked up via interior pointers. */ + assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); + + assert(szind != SC_NSIZES); + + return sz_index2size(szind); +} + +static inline void +arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) { + if (config_prof && unlikely(szind < SC_NBINS)) { + arena_dalloc_promoted(tsdn, ptr, NULL, true); + } else { + extent_t *extent = iealloc(tsdn, ptr); + large_dalloc(tsdn, extent); + } +} + +static inline void +arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) { + assert(ptr != NULL); + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + szind_t szind; + bool slab; + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + true, &szind, &slab); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(szind < SC_NSIZES); + assert(slab == extent_slab_get(extent)); + } + + if (likely(slab)) { + /* Small allocation. */ + arena_dalloc_small(tsdn, ptr); + } else { + arena_dalloc_large_no_tcache(tsdn, ptr, szind); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind, + bool slow_path) { + if (szind < nhbins) { + if (config_prof && unlikely(szind < SC_NBINS)) { + arena_dalloc_promoted(tsdn, ptr, tcache, slow_path); + } else { + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind, + slow_path); + } + } else { + extent_t *extent = iealloc(tsdn, ptr); + large_dalloc(tsdn, extent); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + alloc_ctx_t *alloc_ctx, bool slow_path) { + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); + + if (unlikely(tcache == NULL)) { + arena_dalloc_no_tcache(tsdn, ptr); + return; + } + + szind_t szind; + bool slab; + rtree_ctx_t *rtree_ctx; + if (alloc_ctx != NULL) { + szind = alloc_ctx->szind; + slab = alloc_ctx->slab; + assert(szind != SC_NSIZES); + } else { + rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &szind, &slab); + } + + if (config_debug) { + rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); + extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(szind < SC_NSIZES); + assert(slab == extent_slab_get(extent)); + } + + if (likely(slab)) { + /* Small allocation. */ + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, + slow_path); + } else { + arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path); + } +} + +static inline void +arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { + assert(ptr != NULL); + assert(size <= SC_LARGE_MAXCLASS); + + szind_t szind; + bool slab; + if (!config_prof || !opt_prof) { + /* + * There is no risk of being confused by a promoted sampled + * object, so base szind and slab on the given size. + */ + szind = sz_size2index(size); + slab = (szind < SC_NBINS); + } + + if ((config_prof && opt_prof) || config_debug) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &szind, &slab); + + assert(szind == sz_size2index(size)); + assert((config_prof && opt_prof) || slab == (szind < SC_NBINS)); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, + &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(slab == extent_slab_get(extent)); + } + } + + if (likely(slab)) { + /* Small allocation. */ + arena_dalloc_small(tsdn, ptr); + } else { + arena_dalloc_large_no_tcache(tsdn, ptr, szind); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + alloc_ctx_t *alloc_ctx, bool slow_path) { + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); + assert(size <= SC_LARGE_MAXCLASS); + + if (unlikely(tcache == NULL)) { + arena_sdalloc_no_tcache(tsdn, ptr, size); + return; + } + + szind_t szind; + bool slab; + alloc_ctx_t local_ctx; + if (config_prof && opt_prof) { + if (alloc_ctx == NULL) { + /* Uncommon case and should be a static check. */ + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &local_ctx.szind, + &local_ctx.slab); + assert(local_ctx.szind == sz_size2index(size)); + alloc_ctx = &local_ctx; + } + slab = alloc_ctx->slab; + szind = alloc_ctx->szind; + } else { + /* + * There is no risk of being confused by a promoted sampled + * object, so base szind and slab on the given size. + */ + szind = sz_size2index(size); + slab = (szind < SC_NBINS); + } + + if (config_debug) { + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true,