├── .appveyor.yml ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── Cross.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── roundtrip.rs ├── ci ├── dox.sh └── run.sh ├── jemalloc-ctl ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── rustfmt.toml └── src │ ├── arenas.rs │ ├── config.rs │ ├── error.rs │ ├── keys.rs │ ├── lib.rs │ ├── macros.rs │ ├── opt.rs │ ├── raw.rs │ ├── stats.rs │ ├── stats_print.rs │ └── thread.rs ├── jemalloc-sys ├── Cargo.toml ├── README.md ├── build.rs ├── configure │ ├── VERSION │ └── configure ├── src │ └── lib.rs ├── tests │ ├── malloc_conf_empty.rs │ ├── malloc_conf_set.rs │ └── unprefixed_malloc.rs └── update_jemalloc.md ├── jemallocator-global ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ └── lib.rs ├── src └── lib.rs ├── systest ├── Cargo.toml ├── build.rs └── src │ └── main.rs └── tests ├── background_thread_defaults.rs ├── background_thread_enabled.rs ├── ffi.rs ├── grow_in_place.rs ├── malloctl.rs ├── shrink_in_place.rs ├── smoke.rs ├── smoke_ffi.rs └── usable_size.rs /.appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | # We don't want to do identical comdat folding as it messes up the ability to 3 | # generate lossless backtraces in some cases. This is enabled by rustc by 4 | # default so pass a flag to disable it to ensure our tests work ok. 5 | RUSTFLAGS: -Clink-args=/OPT:NOICF 6 | 7 | matrix: 8 | - TARGET: x86_64-pc-windows-gnu 9 | MSYSTEM: MINGW64 10 | CPU: x86_64 11 | - TARGET: i686-pc-windows-gnu 12 | MSYSTEM: MINGW32 13 | CPU: i686 14 | 15 | matrix: 16 | allow_failures: 17 | - TARGET: x86_64-pc-windows-gnu 18 | - TARGET: i686-pc-windows-gnu 19 | 20 | install: 21 | - git submodule update --init --recursive 22 | - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% 23 | - pacman --noconfirm -Syu mingw-w64-%CPU%-make 24 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 25 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly 26 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 27 | - rustc -vV 28 | - cargo -vV 29 | build: false 30 | test_script: sh ci\run.sh 31 | 32 | branches: 33 | only: 34 | - master 35 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Run a one-line script 13 | run: echo Hello, world! 14 | - name: Run a multi-line script 15 | run: | 16 | echo Add other actions to build, 17 | echo test, and deploy your project. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jemalloc-sys/jemalloc"] 2 | path = jemalloc-sys/jemalloc 3 | url = https://github.com/jemalloc/jemalloc 4 | branch = master -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: nightly 3 | services: docker 4 | 5 | matrix: 6 | include: 7 | # Linux 8 | - name: "aarch64-unknown-linux-gnu" 9 | env: TARGET=aarch64-unknown-linux-gnu NO_JEMALLOC_TESTS=1 10 | - name: "arm-unknown-linux-gnueabi" 11 | env: TARGET=arm-unknown-linux-gnueabi NO_JEMALLOC_TESTS=1 12 | - name: "armv7-unknown-linux-gnueabihf" 13 | env: TARGET=armv7-unknown-linux-gnueabihf NO_JEMALLOC_TESTS=1 14 | - name: "i586-unknown-linux-gnu" 15 | env: TARGET=i586-unknown-linux-gnu 16 | addons: &gcc_multilib 17 | apt: 18 | packages: 19 | - gcc-multilib 20 | - name: "i686-unknown-linux-gnu (nightly)" 21 | env: TARGET=i686-unknown-linux-gnu 22 | addons: *gcc_multilib 23 | - name: "i686-unknown-linux-gnu (beta)" 24 | env: TARGET=i686-unknown-linux-gnu 25 | addons: *gcc_multilib 26 | rust: beta 27 | - name: "i686-unknown-linux-gnu (stable)" 28 | env: TARGET=i686-unknown-linux-gnu 29 | addons: *gcc_multilib 30 | rust: stable 31 | # FIXME: blocked onhttps://github.com/jemalloc/jemalloc/issues/1464 32 | # - name: "i686-unknown-linux-musl" 33 | # env: TARGET=i686-unknown-linux-musl NOBGT=1 NO_JEMALLOC_TESTS=1 34 | - name: "mips-unknown-linux-gnu" 35 | env: TARGET=mips-unknown-linux-gnu NO_JEMALLOC_TESTS=1 36 | - name: "mips64-unknown-linux-gnuabi64" 37 | env: TARGET=mips64-unknown-linux-gnuabi64 NO_JEMALLOC_TESTS=1 38 | - name: "mips64el-unknown-linux-gnuabi64" 39 | env: TARGET=mips64el-unknown-linux-gnuabi64 NO_JEMALLOC_TESTS=1 40 | - name: "mipsel-unknown-linux-gnu" 41 | env: TARGET=mipsel-unknown-linux-gnu NO_JEMALLOC_TESTS=1 42 | - name: "powerpc-unknown-linux-gnu" 43 | env: TARGET=powerpc-unknown-linux-gnu NO_JEMALLOC_TESTS=1 44 | - name: "powerpc64-unknown-linux-gnu" 45 | env: TARGET=powerpc64-unknown-linux-gnu NO_JEMALLOC_TESTS=1 46 | - name: "powerpc64le-unknown-linux-gnu" 47 | env: TARGET=powerpc64le-unknown-linux-gnu NO_JEMALLOC_TESTS=1 48 | - name: "x86_64-unknown-linux-gnu (nightly)" 49 | env: TARGET=x86_64-unknown-linux-gnu VALGRIND=1 JEMALLOC_SYS_VERIFY_CONFIGURE=1 50 | install: rustup component add llvm-tools-preview 51 | addons: &valgrind 52 | apt: 53 | packages: 54 | - valgrind 55 | - autoconf 56 | - name: "x86_64-unknown-linux-gnu (nightly - jemalloc's dev branch)" 57 | env: TARGET=x86_64-unknown-linux-gnu VALGRIND=1 JEMALLOC_SYS_GIT_DEV_BRANCH=1 58 | install: rustup component add llvm-tools-preview 59 | addons: *valgrind 60 | - name: "x86_64-unknown-linux-gnu (beta)" 61 | env: TARGET=x86_64-unknown-linux-gnu VALGRIND=1 62 | rust: beta 63 | install: rustup component add llvm-tools-preview 64 | addons: *valgrind 65 | - name: "x86_64-unknown-linux-gnu (stable)" 66 | env: TARGET=x86_64-unknown-linux-gnu VALGRIND=1 67 | rust: stable 68 | install: rustup component add llvm-tools-preview 69 | addons: *valgrind 70 | - name: "Benchmarks using x86_64-unknown-linux-gnu (nightly)" 71 | env: TARGET=x86_64-unknown-linux-gnu 72 | install: true 73 | script: 74 | - cargo test --bench roundtrip 75 | - cargo test --features=alloc_trait --bench roundtrip 76 | - name: "x86_64-unknown-linux-musl" 77 | env: TARGET=x86_64-unknown-linux-musl NOBGT=1 NO_JEMALLOC_TESTS=1 78 | 79 | # Android 80 | - name: "aarch64-linux-android" 81 | env: TARGET=aarch64-linux-android NO_JEMALLOC_TESTS=1 82 | - name: "x86_64-linux-android" 83 | env: TARGET=x86_64-linux-android 84 | 85 | # OSX 86 | # FIXME: cannot jemalloc tests fail due to: 87 | # https://github.com/jemalloc/jemalloc/issues/1320 88 | # https://github.com/gnzlbg/jemallocator/issues/85 89 | - name: "i686-apple-darwin (nightly)" 90 | env: TARGET=i686-apple-darwin NO_JEMALLOC_TESTS=1 91 | os: osx 92 | osx_image: xcode10 93 | - name: "i686-apple-darwin (beta)" 94 | env: TARGET=i686-apple-darwin NO_JEMALLOC_TESTS=1 95 | os: osx 96 | osx_image: xcode10 97 | rust: beta 98 | - name: "i686-apple-darwin (stable)" 99 | env: TARGET=i686-apple-darwin NO_JEMALLOC_TESTS=1 100 | os: osx 101 | osx_image: xcode10 102 | rust: stable 103 | # FIXME: valgrind fails on OSX 104 | # https://github.com/gnzlbg/jemallocator/issues/86 105 | - name: "x86_64-apple-darwin (nightly)" 106 | env: TARGET=x86_64-apple-darwin NO_JEMALLOC_TESTS=1 JEMALLOC_SYS_VERIFY_CONFIGURE=1 107 | os: osx 108 | osx_image: xcode10 109 | install: rustup component add llvm-tools-preview 110 | - name: "x86_64-apple-darwin (nightly - jemalloc's dev branch)" 111 | env: TARGET=x86_64-apple-darwin NO_JEMALLOC_TESTS=1 JEMALLOC_SYS_GIT_DEV_BRANCH=1 112 | os: osx 113 | osx_image: xcode10 114 | install: rustup component add llvm-tools-preview 115 | - name: "x86_64-apple-darwin (beta)" 116 | env: TARGET=x86_64-apple-darwin NO_JEMALLOC_TESTS=1 117 | os: osx 118 | osx_image: xcode10 119 | rust: beta 120 | install: rustup component add llvm-tools-preview 121 | - name: "x86_64-apple-darwin (stable)" 122 | env: TARGET=x86_64-apple-darwin NO_JEMALLOC_TESTS=1 123 | os: osx 124 | osx_image: xcode10 125 | rust: stable 126 | install: rustup component add llvm-tools-preview 127 | 128 | # TOOLING 129 | - name: "Documentation" 130 | install: true 131 | script: RUSTDOCFLAGS="--cfg jemallocator_docs" cargo doc 132 | deploy: 133 | provider: script 134 | script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) 135 | skip_cleanup: true 136 | on: 137 | branch: master 138 | - name: "rustfmt" 139 | install: true 140 | rust: nightly 141 | script: | 142 | if rustup component add rustfmt-preview ; then 143 | cargo fmt --all -- --check 144 | fi 145 | - name: "clippy" 146 | install: true 147 | rust: nightly 148 | # allow(clippy::all) fails in the syscrate, so we can't use --all here: 149 | script: | 150 | if rustup component add clippy-preview ; then 151 | cargo clippy -p jemalloc-sys -- -D clippy::pedantic 152 | cargo clippy -p jemallocator -- -D clippy::pedantic 153 | cargo clippy -p jemallocator-global -- -D clippy::pedantic 154 | cargo clippy -p jemalloc-ctl -- -D clippy::pedantic 155 | fi 156 | - name: "Shellcheck" 157 | install: true 158 | script: shellcheck ci/*.sh 159 | 160 | install: rustup target add ${TARGET} 161 | script: sh ci/run.sh 162 | notifications: 163 | email: 164 | on_success: never 165 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jemallocator" 3 | # Make sure to update the version in the README as well: 4 | version = "0.3.2" 5 | authors = [ 6 | "Alex Crichton ", 7 | "Gonzalo Brito Gadeschi ", 8 | "Simon Sapin ", 9 | "Steven Fackler " 10 | ] 11 | license = "MIT/Apache-2.0" 12 | readme = "README.md" 13 | keywords = ["allocator", "jemalloc"] 14 | categories = ["memory-management", "api-bindings"] 15 | repository = "https://github.com/gnzlbg/jemallocator" 16 | homepage = "https://github.com/gnzlbg/jemallocator" 17 | documentation = "https://docs.rs/jemallocator" 18 | description = """ 19 | A Rust allocator backed by jemalloc 20 | """ 21 | edition = "2015" 22 | 23 | [badges] 24 | appveyor = { repository = "gnzlbg/jemallocator" } 25 | travis-ci = { repository = "gnzlbg/jemallocator" } 26 | codecov = { repository = "gnzlbg/jemallocator" } 27 | is-it-maintained-issue-resolution = { repository = "gnzlbg/jemallocator" } 28 | is-it-maintained-open-issues = { repository = "gnzlbg/jemallocator" } 29 | maintenance = { status = "actively-developed" } 30 | 31 | [lib] 32 | test = false 33 | bench = false 34 | 35 | [workspace] 36 | members = ["systest", "jemallocator-global", "jemalloc-ctl", "jemalloc-sys" ] 37 | 38 | [dependencies] 39 | jemalloc-sys = { path = "jemalloc-sys", version = "0.3.2", default-features = false } 40 | libc = { version = "^0.2.8", default-features = false } 41 | 42 | [dev-dependencies] 43 | paste = "0.1" 44 | jemalloc-ctl = { path = "jemalloc-ctl", version = "0.3" } 45 | 46 | [features] 47 | default = ["background_threads_runtime_support"] 48 | alloc_trait = [] 49 | profiling = ["jemalloc-sys/profiling"] 50 | debug = ["jemalloc-sys/debug"] 51 | stats = ["jemalloc-sys/stats"] 52 | background_threads_runtime_support = ["jemalloc-sys/background_threads_runtime_support"] 53 | background_threads = ["jemalloc-sys/background_threads"] 54 | unprefixed_malloc_on_supported_platforms = ["jemalloc-sys/unprefixed_malloc_on_supported_platforms"] 55 | disable_initial_exec_tls = ["jemalloc-sys/disable_initial_exec_tls"] 56 | 57 | [package.metadata.docs.rs] 58 | features = [ "alloc_trait" ] 59 | rustdoc-args = [ "--cfg", "jemallocator_docs" ] 60 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build.env] 2 | passthrough = [ 3 | "RUST_BACKTRACE", 4 | "RUST_TEST_THREADS", 5 | "RUST_TEST_NOCAPTURE", 6 | "NO_JEMALLOC_TESTS", 7 | "TERM", 8 | "JEMALLOC_SYS_RUN_JEMALLOC_TESTS", 9 | "JEMALLOC_SYS_VERIFY_CONFIGURE", 10 | "JEMALLOC_SYS_GIT_DEV_BRANCH", 11 | "JEMALLOC_SYS_WITH_MALLOC_CONF", 12 | "JEMALLOC_SYS_WITH_LG_PAGE", 13 | "JEMALLOC_SYS_WITH_LG_HUGEPAGE", 14 | "JEMALLOC_SYS_WITH_LG_QUANTUM", 15 | "JEMALLOC_SYS_WITH_LG_VADDR" 16 | ] -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Crichton 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jemallocator 2 | 3 | [![Travis-CI Status]][travis] [![Appveyor Status]][appveyor] [![Latest Version]][crates.io] [![docs]][docs.rs] 4 | 5 | > Links against `jemalloc` and provides a `Jemalloc` unit type that implements 6 | > the allocator APIs and can be set as the `#[global_allocator]` 7 | 8 | ## Overview 9 | 10 | The `jemalloc` support ecosystem consists of the following crates: 11 | 12 | * `jemalloc-sys`: builds and links against `jemalloc` exposing raw C bindings to it. 13 | * `jemallocator`: provides the `Jemalloc` type which implements the 14 | `GlobalAlloc` and `Alloc` traits. 15 | * `jemalloc-ctl`: high-level wrapper over `jemalloc`'s control and introspection 16 | APIs (the `mallctl*()` family of functions and the _MALLCTL NAMESPACE_)' 17 | 18 | ## Documentation 19 | 20 | * [Latest release (docs.rs)][docs.rs] 21 | * [Master branch][master_docs] 22 | 23 | To use `jemallocator` add it as a dependency: 24 | 25 | ```toml 26 | # Cargo.toml 27 | [dependencies] 28 | 29 | [target.'cfg(not(target_env = "msvc"))'.dependencies] 30 | jemallocator = "0.3.2" 31 | ``` 32 | 33 | To set `jemallocator::Jemalloc` as the global allocator add this to your project: 34 | 35 | ```rust 36 | # main.rs 37 | #[cfg(not(target_env = "msvc"))] 38 | use jemallocator::Jemalloc; 39 | 40 | #[cfg(not(target_env = "msvc"))] 41 | #[global_allocator] 42 | static GLOBAL: Jemalloc = Jemalloc; 43 | ``` 44 | 45 | And that's it! Once you've defined this `static` then jemalloc will be used for 46 | all allocations requested by Rust code in the same program. 47 | 48 | ## Platform support 49 | 50 | The following table describes the supported platforms: 51 | 52 | * `build`: does the library compile for the target? 53 | * `run`: do `jemallocator` and `jemalloc-sys` tests pass on the target? 54 | * `jemalloc`: do `jemalloc`'s tests pass on the target? 55 | * `valgrind`: do the tests pass under valgrind? 56 | 57 | Tier 1 targets are tested on all Rust channels (stable, beta, and nightly). All 58 | other targets are only tested on Rust nightly. 59 | 60 | | Linux targets: | build | run | jemalloc | valgrind | 61 | |-------------------------------------|-----------|---------|--------------|--------------| 62 | | `aarch64-unknown-linux-gnu` | ✓ | ✓ | ✗ | ✗ | 63 | | `arm-unknown-linux-gnueabi` | ✓ | ✓ | ✗ | ✗ | 64 | | `armv7-unknown-linux-gnueabi` | ✓ | ✓ | ✗ | ✗ | 65 | | `i586-unknown-linux-gnu` | ✓ | ✓ | ✓ | ✗ | 66 | | `i686-unknown-linux-gnu` (tier 1) | ✓ | ✓ | ✓ | ✗ | 67 | | `mips-unknown-linux-gnu` | ✓ | ✓ | ✗ | ✗ | 68 | | `mipsel-unknown-linux-musl` | ✓ | ✓ | ✗ | ✗ | 69 | | `mips64-unknown-linux-gnuabi64` | ✓ | ✓ | ✗ | ✗ | 70 | | `mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | ✗ | ✗ | 71 | | `powerpc-unknown-linux-gnu` | ✓ | ✓ | ✗ | ✗ | 72 | | `powerpc64-unknown-linux-gnu` | ✓ | ✓ | ✗ | ✗ | 73 | | `powerpc64le-unknown-linux-gnu` | ✓ | ✓ | ✗ | ✗ | 74 | | `x86_64-unknown-linux-gnu` (tier 1) | ✓ | ✓ | ✓ | ✓ | 75 | | **MacOSX targets:** | **build** | **run** | **jemalloc** | **valgrind** | 76 | | `x86_64-apple-darwin` (tier 1) | ✓ | ✓ | ✗ | ✗ | 77 | | `i686-apple-darwin` (tier 1) | ✓ | ✓ | ✗ | ✗ | 78 | | **Windows targets:** | **build** | **run** | **jemalloc** | **valgrind** | 79 | | `x86_64-pc-windows-msvc` (tier 1) | ✗ | ✗ | ✗ | ✗ | 80 | | `i686-pc-windows-msvc` (tier 1) | ✗ | ✗ | ✗ | ✗ | 81 | | `x86_64-pc-windows-gnu` (tier 1) | ✓ | ✓ | ✗ | ✗ | 82 | | `i686-pc-windows-gnu` (tier 1) | ✓ | ✓ | ✗ | ✗ | 83 | | **Android targets:** | **build** | **run** | **jemalloc** | **valgrind** | 84 | | `aarch64-linux-android` | ✓ | ✓ | ✗ | ✗ | 85 | | `x86_64-linux-android` | ✓ | ✓ | ✓ | ✗ | 86 | 87 | ## Features 88 | 89 | The `jemallocator` crate re-exports the [features of the `jemalloc-sys` 90 | dependency](https://github.com/gnzlbg/jemallocator/blob/master/jemalloc-sys/README.md). 91 | 92 | ## License 93 | 94 | This project is licensed under either of 95 | 96 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 97 | http://www.apache.org/licenses/LICENSE-2.0) 98 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 99 | http://opensource.org/licenses/MIT) 100 | 101 | at your option. 102 | 103 | ## Contribution 104 | 105 | Unless you explicitly state otherwise, any contribution intentionally submitted 106 | for inclusion in `jemallocator` by you, as defined in the Apache-2.0 license, 107 | shall be dual licensed as above, without any additional terms or conditions. 108 | 109 | [travis]: https://travis-ci.com/gnzlbg/jemallocator 110 | [Travis-CI Status]: https://travis-ci.com/gnzlbg/jemallocator.svg?branch=master 111 | [appveyor]: https://ci.appveyor.com/project/gnzlbg/jemallocator/branch/master 112 | [Appveyor Status]: https://ci.appveyor.com/api/projects/status/github/gnzlbg/jemallocator?branch=master&svg=true 113 | [Latest Version]: https://img.shields.io/crates/v/jemallocator.svg 114 | [crates.io]: https://crates.io/crates/jemallocator 115 | [docs]: https://docs.rs/jemallocator/badge.svg 116 | [docs.rs]: https://docs.rs/jemallocator/ 117 | [master_docs]: https://gnzlbg.github.io/jemallocator/jemallocator 118 | -------------------------------------------------------------------------------- /benches/roundtrip.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarks the cost of the different allocation functions by doing a 2 | //! roundtrip (allocate, deallocate). 3 | #![feature(test, allocator_api)] 4 | #![cfg(feature = "alloc_trait")] 5 | 6 | extern crate jemalloc_sys; 7 | extern crate jemallocator; 8 | extern crate libc; 9 | extern crate paste; 10 | extern crate test; 11 | 12 | use jemalloc_sys::MALLOCX_ALIGN; 13 | use jemallocator::Jemalloc; 14 | use libc::c_int; 15 | use std::{ 16 | alloc::{Alloc, Excess, Layout}, 17 | ptr, 18 | }; 19 | use test::Bencher; 20 | 21 | #[global_allocator] 22 | static A: Jemalloc = Jemalloc; 23 | 24 | // FIXME: replace with jemallocator::layout_to_flags 25 | #[cfg(all(any( 26 | target_arch = "arm", 27 | target_arch = "mips", 28 | target_arch = "mipsel", 29 | target_arch = "powerpc" 30 | )))] 31 | const MIN_ALIGN: usize = 8; 32 | #[cfg(all(any( 33 | target_arch = "x86", 34 | target_arch = "x86_64", 35 | target_arch = "aarch64", 36 | target_arch = "powerpc64", 37 | target_arch = "powerpc64le", 38 | target_arch = "mips64", 39 | target_arch = "s390x", 40 | target_arch = "sparc64" 41 | )))] 42 | const MIN_ALIGN: usize = 16; 43 | 44 | fn layout_to_flags(layout: &Layout) -> c_int { 45 | if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { 46 | 0 47 | } else { 48 | MALLOCX_ALIGN(layout.align()) 49 | } 50 | } 51 | 52 | macro_rules! rt { 53 | ($size:expr, $align:expr) => { 54 | paste::item! { 55 | #[bench] 56 | fn [](b: &mut Bencher) { 57 | b.iter(|| unsafe { 58 | use jemalloc_sys as jemalloc; 59 | let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap()); 60 | let ptr = jemalloc::mallocx($size, flags); 61 | test::black_box(ptr); 62 | jemalloc::sdallocx(ptr, $size, flags); 63 | }); 64 | } 65 | 66 | #[bench] 67 | fn [](b: &mut Bencher) { 68 | b.iter(|| unsafe { 69 | use jemalloc_sys as jemalloc; 70 | let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap()); 71 | let ptr = jemalloc::mallocx($size, flags); 72 | test::black_box(ptr); 73 | let rsz = jemalloc::nallocx($size, flags); 74 | test::black_box(rsz); 75 | jemalloc::sdallocx(ptr, rsz, flags); 76 | }); 77 | } 78 | 79 | #[bench] 80 | fn [](b: &mut Bencher) { 81 | b.iter(|| unsafe { 82 | let layout = Layout::from_size_align($size, $align).unwrap(); 83 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 84 | test::black_box(ptr); 85 | Jemalloc.dealloc(ptr, layout); 86 | }); 87 | } 88 | 89 | #[bench] 90 | fn [](b: &mut Bencher) { 91 | b.iter(|| unsafe { 92 | let layout = Layout::from_size_align_unchecked($size, $align); 93 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 94 | test::black_box(ptr); 95 | Jemalloc.dealloc(ptr, layout); 96 | }); 97 | } 98 | 99 | #[bench] 100 | fn [](b: &mut Bencher) { 101 | b.iter(|| unsafe { 102 | let layout = Layout::from_size_align($size, $align).unwrap(); 103 | let Excess(ptr, _) = Jemalloc.alloc_excess(layout.clone()).unwrap(); 104 | test::black_box(ptr); 105 | Jemalloc.dealloc(ptr, layout); 106 | }); 107 | } 108 | 109 | #[bench] 110 | fn [](b: &mut Bencher) { 111 | b.iter(|| unsafe { 112 | let layout = Layout::from_size_align($size, $align).unwrap(); 113 | let Excess(ptr, excess) = Jemalloc.alloc_excess(layout.clone()).unwrap(); 114 | test::black_box(ptr); 115 | test::black_box(excess); 116 | Jemalloc.dealloc(ptr, layout); 117 | }); 118 | } 119 | 120 | #[bench] 121 | fn [](b: &mut Bencher) { 122 | b.iter(|| unsafe { 123 | use jemalloc_sys as jemalloc; 124 | let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap()); 125 | let ptr = jemalloc::mallocx($size, flags | jemalloc::MALLOCX_ZERO); 126 | test::black_box(ptr); 127 | jemalloc::sdallocx(ptr, $size, flags); 128 | }); 129 | } 130 | 131 | #[bench] 132 | fn [](b: &mut Bencher) { 133 | b.iter(|| unsafe { 134 | use jemalloc_sys as jemalloc; 135 | let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap()); 136 | test::black_box(flags); 137 | let ptr = jemalloc::calloc(1, $size); 138 | test::black_box(ptr); 139 | jemalloc::sdallocx(ptr, $size, 0); 140 | }); 141 | } 142 | 143 | #[bench] 144 | fn [](b: &mut Bencher) { 145 | b.iter(|| unsafe { 146 | let layout = Layout::from_size_align($size, $align).unwrap(); 147 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 148 | test::black_box(ptr); 149 | 150 | // navie realloc: 151 | let new_layout = Layout::from_size_align(2 * $size, $align).unwrap(); 152 | let ptr = { 153 | let new_ptr = Jemalloc.alloc(new_layout.clone()).unwrap(); 154 | ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, new_ptr.as_ptr(), layout.size()); 155 | Jemalloc.dealloc(ptr, layout); 156 | new_ptr 157 | }; 158 | test::black_box(ptr); 159 | 160 | Jemalloc.dealloc(ptr, new_layout); 161 | }); 162 | } 163 | 164 | #[bench] 165 | fn [](b: &mut Bencher) { 166 | b.iter(|| unsafe { 167 | let layout = Layout::from_size_align($size, $align).unwrap(); 168 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 169 | test::black_box(ptr); 170 | 171 | let new_layout = Layout::from_size_align(2 * $size, $align).unwrap(); 172 | let ptr = Jemalloc.realloc(ptr, layout, new_layout.size()).unwrap(); 173 | test::black_box(ptr); 174 | 175 | Jemalloc.dealloc(ptr, new_layout); 176 | }); 177 | } 178 | 179 | #[bench] 180 | fn [](b: &mut Bencher) { 181 | b.iter(|| unsafe { 182 | let layout = Layout::from_size_align($size, $align).unwrap(); 183 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 184 | test::black_box(ptr); 185 | 186 | let new_layout = Layout::from_size_align(2 * $size, $align).unwrap(); 187 | let Excess(ptr, _) = Jemalloc 188 | .realloc_excess(ptr, layout, new_layout.size()) 189 | .unwrap(); 190 | test::black_box(ptr); 191 | 192 | Jemalloc.dealloc(ptr, new_layout); 193 | }); 194 | } 195 | 196 | #[bench] 197 | fn [](b: &mut Bencher) { 198 | b.iter(|| unsafe { 199 | let layout = Layout::from_size_align($size, $align).unwrap(); 200 | let ptr = Jemalloc.alloc(layout.clone()).unwrap(); 201 | test::black_box(ptr); 202 | 203 | let new_layout = Layout::from_size_align(2 * $size, $align).unwrap(); 204 | let Excess(ptr, excess) = Jemalloc 205 | .realloc_excess(ptr, layout, new_layout.size()) 206 | .unwrap(); 207 | test::black_box(ptr); 208 | test::black_box(excess); 209 | 210 | Jemalloc.dealloc(ptr, new_layout); 211 | }); 212 | } 213 | 214 | } 215 | }; 216 | ([$($size:expr),*]) => { 217 | $( 218 | rt!($size, 1); 219 | rt!($size, 2); 220 | rt!($size, 4); 221 | rt!($size, 8); 222 | rt!($size, 16); 223 | rt!($size, 32); 224 | )* 225 | } 226 | } 227 | 228 | // Powers of two 229 | mod pow2 { 230 | use super::*; 231 | 232 | rt!([ 233 | 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 234 | 4194304 235 | ]); 236 | 237 | } 238 | 239 | mod even { 240 | use super::*; 241 | 242 | rt!([10, 100, 1000, 10000, 100000, 1000000]); 243 | } 244 | 245 | mod odd { 246 | use super::*; 247 | rt!([9, 99, 999, 9999, 99999, 999999]); 248 | } 249 | 250 | mod primes { 251 | use super::*; 252 | rt!([ 253 | 3, 7, 13, 17, 31, 61, 96, 127, 257, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65537, 254 | 131071, 4194301 255 | ]); 256 | } 257 | -------------------------------------------------------------------------------- /ci/dox.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -ex 4 | 5 | export RUSTDOCFLAGS="--cfg jemallocator_docs" 6 | cargo doc --features alloc_trait 7 | cargo doc -p jemalloc-sys 8 | cargo doc -p jemalloc-ctl 9 | -------------------------------------------------------------------------------- /ci/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -ex 4 | 5 | : "${TARGET?The TARGET environment variable must be set.}" 6 | 7 | echo "Running tests for target: ${TARGET}, Rust version=${TRAVIS_RUST_VERSION}" 8 | export RUST_BACKTRACE=1 9 | export RUST_TEST_THREADS=1 10 | export RUST_TEST_NOCAPTURE=1 11 | export CARGO_CMD=cross 12 | 13 | # FIXME: workaround cargo breaking Travis-CI again: 14 | # https://github.com/rust-lang/cargo/issues/5721 15 | if [ "$TRAVIS" = "true" ] 16 | then 17 | export TERM=dumb 18 | fi 19 | 20 | # Runs jemalloc tests when building jemalloc-sys (runs "make check"): 21 | if [ "${NO_JEMALLOC_TESTS}" = "1" ] 22 | then 23 | echo "jemalloc's tests are not run" 24 | else 25 | export JEMALLOC_SYS_RUN_JEMALLOC_TESTS=1 26 | fi 27 | 28 | # Use cargo on native CI platforms: 29 | case "${TARGET}" in 30 | "x86_64-unknown-linux-gnu") export CARGO_CMD=cargo ;; 31 | *"windows"*) export CARGO_CMD=cargo ;; 32 | *"apple"*) export CARGO_CMD=cargo ;; 33 | esac 34 | 35 | if [ "${CARGO_CMD}" = "cross" ] 36 | then 37 | cargo install cross || echo "cross is already installed" 38 | fi 39 | 40 | if [ "${VALGRIND}" = "1" ] 41 | then 42 | case "${TARGET}" in 43 | "x86_64-unknown-linux-gnu") 44 | export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER=valgrind 45 | ;; 46 | "x86_64-apple-darwin") 47 | export CARGO_TARGET_X86_64_APPLE_DARWIN_RUNNER=valgrind 48 | ;; 49 | *) 50 | echo "Specify how to run valgrind for TARGET=${TARGET}" 51 | exit 1 52 | ;; 53 | esac 54 | fi 55 | 56 | if [ "${TARGET}" = "x86_64-unknown-linux-gnu" ] || [ "${TARGET}" = "x86_64-apple-darwin" ] 57 | then 58 | ${CARGO_CMD} build -vv --target "${TARGET}" 2>&1 | tee build_no_std.txt 59 | 60 | # Check that the no-std builds are not linked against a libc with default 61 | # features or the `use_std` feature enabled: 62 | ! grep -q "default" build_no_std.txt 63 | ! grep -q "use_std" build_no_std.txt 64 | 65 | RUST_SYS_ROOT=$(rustc --target="${TARGET}" --print sysroot) 66 | RUST_LLVM_NM="${RUST_SYS_ROOT}/lib/rustlib/${TARGET}/bin/llvm-nm" 67 | 68 | find target/ -iname '*jemalloc*.rlib' | while read -r rlib; do 69 | echo "${RUST_LLVM_NM} ${rlib}" 70 | ! $RUST_LLVM_NM "${rlib}" | grep "std" 71 | done 72 | fi 73 | 74 | ${CARGO_CMD} test -vv --target "${TARGET}" 75 | 76 | if [ "${JEMALLOC_SYS_GIT_DEV_BRANCH}" = "1" ]; then 77 | # FIXME: profiling tests broken on dev-branch 78 | # https://github.com/jemalloc/jemalloc/issues/1477 79 | : 80 | else 81 | ${CARGO_CMD} test -vv --target "${TARGET}" --features profiling 82 | fi 83 | 84 | ${CARGO_CMD} test -vv --target "${TARGET}" --features debug 85 | ${CARGO_CMD} test -vv --target "${TARGET}" --features stats 86 | if [ "${JEMALLOC_SYS_GIT_DEV_BRANCH}" = "1" ]; then 87 | # FIXME: profiling tests broken on dev-branch 88 | # https://github.com/jemalloc/jemalloc/issues/1477 89 | : 90 | else 91 | ${CARGO_CMD} test -vv --target "${TARGET}" --features 'debug profiling' 92 | fi 93 | 94 | ${CARGO_CMD} test -vv --target "${TARGET}" \ 95 | --features unprefixed_malloc_on_supported_platforms 96 | ${CARGO_CMD} test -vv --target "${TARGET}" --no-default-features 97 | ${CARGO_CMD} test -vv --target "${TARGET}" --no-default-features \ 98 | --features background_threads_runtime_support 99 | 100 | if [ "${NOBGT}" = "1" ] 101 | then 102 | echo "enabling background threads by default at run-time is not tested" 103 | else 104 | ${CARGO_CMD} test -vv --target "${TARGET}" --features background_threads 105 | fi 106 | 107 | ${CARGO_CMD} test -vv --target "${TARGET}" --release 108 | ${CARGO_CMD} test -vv --target "${TARGET}" --manifest-path jemalloc-sys/Cargo.toml 109 | ${CARGO_CMD} test -vv --target "${TARGET}" \ 110 | --manifest-path jemalloc-sys/Cargo.toml \ 111 | --features unprefixed_malloc_on_supported_platforms 112 | 113 | # FIXME: jemalloc-ctl fails in the following targets 114 | case "${TARGET}" in 115 | "i686-unknown-linux-musl") ;; 116 | "x86_64-unknown-linux-musl") ;; 117 | *) 118 | 119 | ${CARGO_CMD} test -vv --target "${TARGET}" \ 120 | --manifest-path jemalloc-ctl/Cargo.toml \ 121 | --no-default-features 122 | # FIXME: cross fails to pass features to jemalloc-ctl 123 | # ${CARGO_CMD} test -vv --target "${TARGET}" \ 124 | # --manifest-path jemalloc-ctl \ 125 | # --no-default-features --features use_std 126 | ;; 127 | esac 128 | 129 | ${CARGO_CMD} test -vv --target "${TARGET}" -p systest 130 | ${CARGO_CMD} test -vv --target "${TARGET}" \ 131 | --manifest-path jemallocator-global/Cargo.toml 132 | ${CARGO_CMD} test -vv --target "${TARGET}" \ 133 | --manifest-path jemallocator-global/Cargo.toml \ 134 | --features force_global_jemalloc 135 | 136 | if [ "${TRAVIS_RUST_VERSION}" = "nightly" ] 137 | then 138 | # The Alloc trait is unstable: 139 | ${CARGO_CMD} test -vv --target "${TARGET}" --features alloc_trait 140 | fi 141 | -------------------------------------------------------------------------------- /jemalloc-ctl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jemalloc-ctl" 3 | version = "0.3.3" 4 | authors = [ 5 | "Steven Fackler ", 6 | "Gonzalo Brito Gadeschi " 7 | ] 8 | license = "MIT/Apache-2.0" 9 | readme = "README.md" 10 | categories = ["memory-management", "api-bindings", "development-tools" ] 11 | keywords = ["allocator", "jemalloc"] 12 | repository = "https://github.com/gnzlbg/jemallocator" 13 | homepage = "https://github.com/gnzlbg/jemallocator" 14 | documentation = "https://docs.rs/jemalloc-ctl" 15 | description = """ 16 | A safe wrapper over jemalloc's control and introspection APIs 17 | """ 18 | 19 | [badges] 20 | appveyor = { repository = "gnzlbg/jemallocator" } 21 | travis-ci = { repository = "gnzlbg/jemallocator" } 22 | codecov = { repository = "gnzlbg/jemallocator" } 23 | is-it-maintained-issue-resolution = { repository = "gnzlbg/jemallocator" } 24 | is-it-maintained-open-issues = { repository = "gnzlbg/jemallocator" } 25 | maintenance = { status = "actively-developed" } 26 | 27 | [dependencies] 28 | jemalloc-sys = { path = "../jemalloc-sys", version = "0.3.2" } 29 | libc = { version = "0.2", default-features = false } 30 | paste = { version = "0.1" } 31 | 32 | [dev-dependencies] 33 | jemallocator = { path = "..", version = "0.3.2" } 34 | 35 | [features] 36 | default = [] 37 | use_std = [ "libc/use_std" ] 38 | 39 | [package.metadata.docs.rs] 40 | rustdoc-args = [ "--cfg", "jemallocator_docs" ] -------------------------------------------------------------------------------- /jemalloc-ctl/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /jemalloc-ctl/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Steven Fackler 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /jemalloc-ctl/README.md: -------------------------------------------------------------------------------- 1 | # jemalloc-ctl 2 | 3 | [![Travis-CI Status]][travis] [![Appveyor Status]][appveyor] [![Latest Version]][crates.io] [![docs]][docs.rs] 4 | 5 | > A safe wrapper over `jemalloc`'s `mallctl*()` control and introspection APIs. 6 | 7 | ## Documentation 8 | 9 | * [Latest release (docs.rs)][docs.rs] 10 | * [master branch`][master_docs] 11 | 12 | ## Platform support 13 | 14 | Supported on all platforms supported by the [`jemallocator`] crate. 15 | 16 | ## Example 17 | 18 | ```no_run 19 | extern crate jemallocator; 20 | extern crate jemalloc_ctl; 21 | 22 | use std::thread; 23 | use std::time::Duration; 24 | use jemalloc_ctl::{stats, epoch}; 25 | 26 | #[global_allocator] 27 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 28 | 29 | fn main() { 30 | // Obtain a MIB for the `epoch`, `stats.allocated`, and 31 | // `atats.resident` keys: 32 | let e = epoch::mib().unwrap(); 33 | let allocated = stats::allocated::mib().unwrap(); 34 | let resident = stats::resident::mib().unwrap(); 35 | 36 | loop { 37 | // Many statistics are cached and only updated 38 | // when the epoch is advanced: 39 | e.advance().unwrap(); 40 | 41 | // Read statistics using MIB key: 42 | let allocated = allocated.read().unwrap(); 43 | let resident = resident.read().unwrap(); 44 | println!("{} bytes allocated/{} bytes resident", allocated, resident); 45 | thread::sleep(Duration::from_secs(10)); 46 | } 47 | } 48 | ``` 49 | 50 | ## License 51 | 52 | This project is licensed under either of 53 | 54 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 55 | http://www.apache.org/licenses/LICENSE-2.0) 56 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 57 | http://opensource.org/licenses/MIT) 58 | 59 | at your option. 60 | 61 | ### Contribution 62 | 63 | Unless you explicitly state otherwise, any contribution intentionally submitted 64 | for inclusion in `jemalloc-ctl` by you, as defined in the Apache-2.0 license, 65 | shall be dual licensed as above, without any additional terms or conditions. 66 | 67 | [`jemallocator`]: https://github.com/gnzlbg/jemallocator 68 | [travis]: https://travis-ci.org/gnzlbg/jemallocator 69 | [Travis-CI Status]: https://travis-ci.org/gnzlbg/jemallocator.svg?branch=master 70 | [appveyor]: https://ci.appveyor.com/project/gnzlbg/jemallocator/branch/master 71 | [Appveyor Status]: https://ci.appveyor.com/api/projects/status/github/gnzlbg/jemallocator?branch=master&svg=true 72 | [Latest Version]: https://img.shields.io/crates/v/jemalloc-ctl.svg 73 | [crates.io]: https://crates.io/crates/jemalloc-ctl 74 | [docs]: https://docs.rs/jemalloc-ctl/badge.svg 75 | [docs.rs]: https://docs.rs/jemalloc-ctl/ 76 | [master_docs]: https://gnzlbg.github.io/jemallocator/jemalloc-ctl 77 | -------------------------------------------------------------------------------- /jemalloc-ctl/rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 79 -------------------------------------------------------------------------------- /jemalloc-ctl/src/arenas.rs: -------------------------------------------------------------------------------- 1 | //! Arena operations. 2 | 3 | option! { 4 | narenas[ str: b"arenas.narenas\0", non_str: 2 ] => libc::c_uint | 5 | ops: r | 6 | docs: 7 | /// Current limit on the number of arenas. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// # extern crate jemallocator; 13 | /// # extern crate jemalloc_ctl; 14 | /// # 15 | /// # #[global_allocator] 16 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 17 | /// # 18 | /// # fn main() { 19 | /// use jemalloc_ctl::arenas; 20 | /// println!("number of arenas: {}", arenas::narenas::read().unwrap()); 21 | /// 22 | /// let arenas_mib = arenas::narenas::mib().unwrap(); 23 | /// println!("number of arenas: {}", arenas_mib.read().unwrap()); 24 | /// # } 25 | /// ``` 26 | mib_docs: /// See [`narenas`]. 27 | } 28 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/config.rs: -------------------------------------------------------------------------------- 1 | //! `jemalloc`'s build-time configuration. 2 | 3 | option! { 4 | malloc_conf[ str: b"config.malloc_conf\0", str: 2 ] => &'static str | 5 | ops: r | 6 | docs: 7 | /// Default run-time options specified during `jemalloc`'s build configuration. 8 | /// 9 | /// The string will be empty unless `--with-malloc-conf` was specified 10 | /// during build configuration. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// # extern crate jemallocator; 16 | /// # extern crate jemalloc_ctl; 17 | /// # 18 | /// # #[global_allocator] 19 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 20 | /// # 21 | /// # fn main() { 22 | /// use jemalloc_ctl::config; 23 | /// let malloc_conf = config::malloc_conf::mib().unwrap(); 24 | /// println!("default malloc conf: {}", malloc_conf.read().unwrap()); 25 | /// # } 26 | /// ``` 27 | mib_docs: /// See [`malloc_conf`]. 28 | } 29 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error type 2 | #![cfg_attr( 3 | feature = "cargo-clippy", 4 | allow(clippy::cast_sign_loss, clippy::cast_possible_wrap) 5 | )] 6 | 7 | use libc::c_int; 8 | use {fmt, num, result}; 9 | 10 | pub trait NonZeroT { 11 | type T; 12 | } 13 | impl NonZeroT for i32 { 14 | type T = num::NonZeroU32; 15 | } 16 | impl NonZeroT for i64 { 17 | type T = num::NonZeroU64; 18 | } 19 | 20 | pub type NonZeroCInt = ::T; 21 | 22 | /// Errors of the `jemalloc_sys::mallct`-family of functions. 23 | /// 24 | /// The `jemalloc-sys` crate: `mallctl`, `mallctlnametomib`, and `mallctlbymib`` 25 | /// functions return `0` on success; otherwise they return an error value. 26 | #[repr(transparent)] 27 | #[derive(Copy, Clone, PartialEq)] 28 | pub struct Error(NonZeroCInt); 29 | 30 | /// Result type 31 | pub type Result = result::Result; 32 | 33 | impl fmt::Debug for Error { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 | let code = self.0.get() as c_int; 36 | match description(code) { 37 | Some(m) => write!(f, "{}", m), 38 | None => write!(f, "Unknown error code: \"{}\".", code), 39 | } 40 | } 41 | } 42 | 43 | impl fmt::Display for Error { 44 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 | ::fmt(self, f) 46 | } 47 | } 48 | 49 | #[cfg(feature = "use_std")] 50 | use std::error::Error as StdError; 51 | 52 | #[cfg(feature = "use_std")] 53 | impl StdError for Error { 54 | fn description(&self) -> &str { 55 | match description(self.0.get() as c_int) { 56 | Some(m) => m, 57 | None => "Unknown error", 58 | } 59 | } 60 | fn cause(&self) -> Option<&dyn StdError> { 61 | None 62 | } 63 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 64 | None 65 | } 66 | } 67 | 68 | fn description(code: c_int) -> Option<&'static str> { 69 | match code { 70 | libc::EINVAL => Some( 71 | "`newp` is not `NULL`, and `newlen` is too large or too \ 72 | small. Alternatively, `*oldlenp` is too large or too \ 73 | small; in this case as much data as possible are read \ 74 | despite the error.", 75 | ), 76 | libc::ENOENT => { 77 | Some("`name` or `mib` specifies an unknown/invalid value.") 78 | } 79 | libc::EPERM => Some( 80 | "Attempt to read or write `void` value, or attempt to \ 81 | write read-only value.", 82 | ), 83 | libc::EAGAIN => Some("A memory allocation failure occurred."), 84 | libc::EFAULT => Some( 85 | "An interface with side effects failed in some way not \ 86 | directly related to `mallctl*()` read/write processing.", 87 | ), 88 | _ => None, 89 | } 90 | } 91 | 92 | pub(crate) fn cvt(ret: c_int) -> Result<()> { 93 | match ret { 94 | 0 => Ok(()), 95 | v => Err(Error(unsafe { NonZeroCInt::new_unchecked(v as _) })), 96 | } 97 | } 98 | 99 | #[cfg(test)] 100 | mod tests { 101 | use super::*; 102 | 103 | #[test] 104 | fn size_of_result_error() { 105 | use mem::size_of; 106 | assert_eq!(size_of::>(), size_of::()); 107 | assert_eq!(size_of::(), size_of::()); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/keys.rs: -------------------------------------------------------------------------------- 1 | //! Key types to index the _MALLCTL NAMESPACE_. 2 | //! 3 | //! The [`Name`] and [`Mib`]/[`MibStr`] types are provided as safe indices into 4 | //! the _MALLCTL NAMESPACE_. These are constructed from null-terminated strings 5 | //! via the [`AsName`] trait. The [`Access`] trait provides provides safe access 6 | //! into the `_MALLCTL NAMESPACE_`. 7 | //! 8 | //! # Example 9 | //! 10 | //! ``` 11 | //! extern crate libc; 12 | //! extern crate jemallocator; 13 | //! extern crate jemalloc_ctl; 14 | //! 15 | //! #[global_allocator] 16 | //! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 17 | //! 18 | //! fn main() { 19 | //! use jemalloc_ctl::{Access, AsName, Name, Mib}; 20 | //! use libc::{c_uint, c_char}; 21 | //! let name = b"arenas.nbins\0".name(); 22 | //! let nbins: c_uint = name.read().unwrap(); 23 | //! let mut mib: Mib<[usize; 4]> = b"arenas.bin.0.size\0".name().mib().unwrap(); 24 | //! for i in 0..4 { 25 | //! mib[2] = i; 26 | //! let bin_size: usize = mib.read().unwrap(); 27 | //! println!("arena bin {} has size {}", i, bin_size); 28 | //! } 29 | //! } 30 | //! ``` 31 | 32 | use error::Result; 33 | use std::str; 34 | use {fmt, ops, raw}; 35 | 36 | /// A `Name` in the _MALLCTL NAMESPACE_. 37 | #[repr(transparent)] 38 | #[derive(PartialEq)] 39 | pub struct Name([u8]); 40 | 41 | /// Converts a null-terminated byte-string into a [`Name`]. 42 | pub trait AsName { 43 | /// Converts a null-terminated byte-string into a [`Name`]. 44 | fn name(&self) -> &Name; 45 | } 46 | 47 | impl AsName for [u8] { 48 | fn name(&self) -> &Name { 49 | use str; 50 | assert!( 51 | !self.is_empty(), 52 | "cannot create Name from empty byte-string" 53 | ); 54 | assert_eq!( 55 | *self.last().unwrap(), 56 | b'\0', 57 | "cannot create Name from non-null-terminated byte-string \"{}\"", 58 | str::from_utf8(self).unwrap() 59 | ); 60 | unsafe { &*(self as *const Self as *const Name) } 61 | } 62 | } 63 | 64 | impl AsName for str { 65 | fn name(&self) -> &Name { 66 | self.as_bytes().name() 67 | } 68 | } 69 | 70 | impl Name { 71 | /// Returns the [`Mib`] of `self`. 72 | pub fn mib(&self) -> Result> { 73 | let mut mib: Mib = Mib::default(); 74 | raw::name_to_mib(&self.0, mib.0.as_mut())?; 75 | Ok(mib) 76 | } 77 | 78 | /// Returns the [`MibStr`] of `self` which is a key whose value is a string. 79 | pub fn mib_str(&self) -> Result> { 80 | assert!( 81 | self.value_type_str(), 82 | "key \"{}\" does not refer to a string", 83 | self 84 | ); 85 | let mut mib: MibStr = MibStr::default(); 86 | raw::name_to_mib(&self.0, mib.0.as_mut())?; 87 | Ok(mib) 88 | } 89 | 90 | /// Returns `true` if `self` is a key in the _MALLCTL NAMESPCE_ referring to 91 | /// a null-terminated string. 92 | pub fn value_type_str(&self) -> bool { 93 | // remove the null-terminator: 94 | let name = self.0.split_at(self.0.len() - 1).0; 95 | if name.is_empty() { 96 | return false; 97 | } 98 | debug_assert_ne!(*name.last().unwrap(), b'\0'); 99 | 100 | match name { 101 | b"version" 102 | | b"config.malloc_conf" 103 | | b"opt.metadata_thp" 104 | | b"opt.dss" 105 | | b"opt.percpu_arena" 106 | | b"opt.stats_print_opts" 107 | | b"opt.junk" 108 | | b"opt.thp" 109 | | b"opt.prof_prefix" 110 | | b"thread.prof.name" 111 | | b"prof.dump" => true, 112 | v if v.starts_with(b"arena.") && v.ends_with(b".dss") => true, 113 | v if v.starts_with(b"stats.arenas.") && v.ends_with(b".dss") => { 114 | true 115 | } 116 | _ => false, 117 | } 118 | } 119 | 120 | /// Returns the name as null-terminated byte-string. 121 | pub fn as_bytes(&self) -> &'static [u8] { 122 | unsafe { &*(self as *const Self as *const [u8]) } 123 | } 124 | } 125 | 126 | impl fmt::Debug for Name { 127 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 128 | use str; 129 | write!(f, "{}", str::from_utf8(&self.0).unwrap()) 130 | } 131 | } 132 | 133 | impl fmt::Display for Name { 134 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 135 | use str; 136 | write!(f, "{}", str::from_utf8(&self.0).unwrap()) 137 | } 138 | } 139 | 140 | /// Management Information Base of a non-string value. 141 | #[repr(transparent)] 142 | #[derive(Copy, Clone, PartialEq, Debug, Default)] 143 | pub struct Mib(T); 144 | 145 | /// Management Information Base of a string value. 146 | #[repr(transparent)] 147 | #[derive(Copy, Clone, PartialEq, Debug, Default)] 148 | pub struct MibStr(T); 149 | 150 | impl AsRef<[usize]> for Mib { 151 | fn as_ref(&self) -> &[usize] { 152 | self.0.as_ref() 153 | } 154 | } 155 | 156 | impl AsMut<[usize]> for Mib { 157 | fn as_mut(&mut self) -> &mut [usize] { 158 | self.0.as_mut() 159 | } 160 | } 161 | 162 | impl ops::Index for Mib { 163 | type Output = usize; 164 | fn index(&self, idx: usize) -> &Self::Output { 165 | &self.0.as_ref()[idx] 166 | } 167 | } 168 | 169 | impl ops::IndexMut for Mib { 170 | fn index_mut(&mut self, idx: usize) -> &mut Self::Output { 171 | &mut self.0.as_mut()[idx] 172 | } 173 | } 174 | 175 | impl ops::Index for MibStr { 176 | type Output = usize; 177 | fn index(&self, idx: usize) -> &Self::Output { 178 | &self.0.as_ref()[idx] 179 | } 180 | } 181 | 182 | impl ops::IndexMut for MibStr { 183 | fn index_mut(&mut self, idx: usize) -> &mut Self::Output { 184 | &mut self.0.as_mut()[idx] 185 | } 186 | } 187 | 188 | /// Safe read access to the _MALLCTL NAMESPACE_. 189 | pub trait Access { 190 | /// Read the key at `self`. 191 | fn read(&self) -> Result; 192 | /// Write `value` at the key `self`. 193 | fn write(&self, value: T) -> Result<()>; 194 | /// Write `value` at the key `self` returning its previous value. 195 | fn update(&self, value: T) -> Result; 196 | } 197 | 198 | macro_rules! impl_access { 199 | ($id:ty) => { 200 | impl Access<$id> for Mib { 201 | fn read(&self) -> Result<$id> { 202 | unsafe { raw::read_mib(self.0.as_ref()) } 203 | } 204 | fn write(&self, value: $id) -> Result<()> { 205 | unsafe { raw::write_mib(self.0.as_ref(), value) } 206 | } 207 | fn update(&self, value: $id) -> Result<$id> { 208 | unsafe { raw::update_mib(self.0.as_ref(), value) } 209 | } 210 | } 211 | impl Access<$id> for Name { 212 | fn read(&self) -> Result<$id> { 213 | unsafe { raw::read(&self.0) } 214 | } 215 | fn write(&self, value: $id) -> Result<()> { 216 | unsafe { raw::write(&self.0, value) } 217 | } 218 | fn update(&self, value: $id) -> Result<$id> { 219 | unsafe { raw::update(&self.0, value) } 220 | } 221 | } 222 | }; 223 | } 224 | 225 | impl_access!(u32); 226 | impl_access!(u64); 227 | impl_access!(isize); 228 | impl_access!(usize); 229 | 230 | impl Access for Mib { 231 | fn read(&self) -> Result { 232 | unsafe { 233 | let v: u8 = raw::read_mib(self.0.as_ref())?; 234 | assert!(v == 0 || v == 1); 235 | Ok(v == 1) 236 | } 237 | } 238 | fn write(&self, value: bool) -> Result<()> { 239 | unsafe { raw::write_mib(self.0.as_ref(), value) } 240 | } 241 | fn update(&self, value: bool) -> Result { 242 | unsafe { 243 | let v: u8 = raw::update_mib(self.0.as_ref(), value as u8)?; 244 | Ok(v == 1) 245 | } 246 | } 247 | } 248 | 249 | impl Access for Name { 250 | fn read(&self) -> Result { 251 | unsafe { 252 | let v: u8 = raw::read(&self.0)?; 253 | assert!(v == 0 || v == 1); 254 | Ok(v == 1) 255 | } 256 | } 257 | fn write(&self, value: bool) -> Result<()> { 258 | unsafe { raw::write(&self.0, value) } 259 | } 260 | fn update(&self, value: bool) -> Result { 261 | unsafe { 262 | let v: u8 = raw::update(&self.0, value as u8)?; 263 | Ok(v == 1) 264 | } 265 | } 266 | } 267 | 268 | impl Access<&'static [u8]> for MibStr { 269 | fn read(&self) -> Result<&'static [u8]> { 270 | // this is safe because the only safe way to construct a `MibStr` is by 271 | // validating that the key refers to a byte-string value 272 | unsafe { raw::read_str_mib(self.0.as_ref()) } 273 | } 274 | fn write(&self, value: &'static [u8]) -> Result<()> { 275 | raw::write_str_mib(self.0.as_ref(), value) 276 | } 277 | fn update(&self, value: &'static [u8]) -> Result<&'static [u8]> { 278 | // this is safe because the only safe way to construct a `MibStr` is by 279 | // validating that the key refers to a byte-string value 280 | unsafe { raw::update_str_mib(self.0.as_ref(), value) } 281 | } 282 | } 283 | 284 | impl Access<&'static [u8]> for Name { 285 | fn read(&self) -> Result<&'static [u8]> { 286 | assert!( 287 | self.value_type_str(), 288 | "the name \"{:?}\" does not refer to a byte string", 289 | self 290 | ); 291 | // this is safe because the key refers to a byte string: 292 | unsafe { raw::read_str(&self.0) } 293 | } 294 | fn write(&self, value: &'static [u8]) -> Result<()> { 295 | assert!( 296 | self.value_type_str(), 297 | "the name \"{:?}\" does not refer to a byte string", 298 | self 299 | ); 300 | raw::write_str(&self.0, value) 301 | } 302 | fn update(&self, value: &'static [u8]) -> Result<&'static [u8]> { 303 | assert!( 304 | self.value_type_str(), 305 | "the name \"{:?}\" does not refer to a byte string", 306 | self 307 | ); 308 | // this is safe because the key refers to a byte string: 309 | unsafe { raw::update_str(&self.0, value) } 310 | } 311 | } 312 | 313 | impl Access<&'static str> for MibStr { 314 | fn read(&self) -> Result<&'static str> { 315 | // this is safe because the only safe way to construct a `MibStr` is by 316 | // validating that the key refers to a byte-string value 317 | let s = unsafe { raw::read_str_mib(self.0.as_ref())? }; 318 | Ok(str::from_utf8(s).unwrap()) 319 | } 320 | fn write(&self, value: &'static str) -> Result<()> { 321 | raw::write_str_mib(self.0.as_ref(), value.as_bytes()) 322 | } 323 | fn update(&self, value: &'static str) -> Result<&'static str> { 324 | // this is safe because the only safe way to construct a `MibStr` is by 325 | // validating that the key refers to a byte-string value 326 | let s = 327 | unsafe { raw::update_str_mib(self.0.as_ref(), value.as_bytes())? }; 328 | Ok(str::from_utf8(s).unwrap()) 329 | } 330 | } 331 | 332 | impl Access<&'static str> for Name { 333 | fn read(&self) -> Result<&'static str> { 334 | assert!( 335 | self.value_type_str(), 336 | "the name \"{:?}\" does not refer to a byte string", 337 | self 338 | ); 339 | // this is safe because the key refers to a byte string: 340 | let s = unsafe { raw::read_str(&self.0)? }; 341 | Ok(str::from_utf8(s).unwrap()) 342 | } 343 | fn write(&self, value: &'static str) -> Result<()> { 344 | assert!( 345 | self.value_type_str(), 346 | "the name \"{:?}\" does not refer to a byte string", 347 | self 348 | ); 349 | raw::write_str(&self.0, value.as_bytes()) 350 | } 351 | fn update(&self, value: &'static str) -> Result<&'static str> { 352 | assert!( 353 | self.value_type_str(), 354 | "the name \"{:?}\" does not refer to a byte string", 355 | self 356 | ); 357 | // this is safe because the key refers to a byte string: 358 | let s = unsafe { raw::update_str(&self.0, value.as_bytes())? }; 359 | Ok(str::from_utf8(s).unwrap()) 360 | } 361 | } 362 | 363 | #[cfg(test)] 364 | mod tests { 365 | use super::{Access, AsName, Mib, MibStr}; 366 | #[test] 367 | fn bool_rw() { 368 | let name = b"thread.tcache.enabled\0".name(); 369 | let tcache: bool = name.read().unwrap(); 370 | 371 | let new_tcache = !tcache; 372 | 373 | name.write(new_tcache).unwrap(); 374 | 375 | let mib: Mib<[usize; 3]> = name.mib().unwrap(); 376 | let r: bool = mib.read().unwrap(); 377 | assert_eq!(r, new_tcache); 378 | } 379 | 380 | #[test] 381 | fn u32_r() { 382 | let name = b"arenas.bin.0.nregs\0".name(); 383 | let v: u32 = name.read().unwrap(); 384 | 385 | let mib: Mib<[usize; 4]> = name.mib().unwrap(); 386 | let r: u32 = mib.read().unwrap(); 387 | assert_eq!(r, v); 388 | } 389 | 390 | #[test] 391 | fn size_t_r() { 392 | let name = b"arenas.lextent.0.size\0".name(); 393 | let v: libc::size_t = name.read().unwrap(); 394 | 395 | let mib: Mib<[usize; 4]> = name.mib().unwrap(); 396 | let r: libc::size_t = mib.read().unwrap(); 397 | assert_eq!(r, v); 398 | } 399 | 400 | #[test] 401 | fn ssize_t_rw() { 402 | let name = b"arenas.dirty_decay_ms\0".name(); 403 | let v: libc::ssize_t = name.read().unwrap(); 404 | name.write(v).unwrap(); 405 | 406 | let mib: Mib<[usize; 2]> = name.mib().unwrap(); 407 | let r: libc::ssize_t = mib.read().unwrap(); 408 | assert_eq!(r, v); 409 | } 410 | 411 | #[test] 412 | fn u64_rw() { 413 | let name = b"epoch\0".name(); 414 | let epoch: u64 = name.read().unwrap(); 415 | name.write(epoch).unwrap(); 416 | 417 | let mib: Mib<[usize; 1]> = name.mib().unwrap(); 418 | let epoch: u64 = mib.read().unwrap(); 419 | mib.write(epoch).unwrap(); 420 | } 421 | 422 | #[test] 423 | fn str_rw() { 424 | let name = b"arena.0.dss\0".name(); 425 | let dss: &'static [u8] = name.read().unwrap(); 426 | name.write(dss).unwrap(); 427 | 428 | let mib: MibStr<[usize; 3]> = name.mib_str().unwrap(); 429 | let dss2: &'static [u8] = mib.read().unwrap(); 430 | mib.write(dss2).unwrap(); 431 | 432 | assert_eq!(dss, dss2); 433 | } 434 | } 435 | 436 | pub trait MibArg: 437 | Copy 438 | + Clone 439 | + PartialEq 440 | + Default 441 | + fmt::Debug 442 | + AsRef<[usize]> 443 | + AsMut<[usize]> 444 | { 445 | } 446 | impl MibArg for T where 447 | T: Copy 448 | + Clone 449 | + PartialEq 450 | + Default 451 | + fmt::Debug 452 | + AsRef<[usize]> 453 | + AsMut<[usize]> 454 | { 455 | } 456 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `jemalloc` control and introspection. 2 | //! 3 | //! `jemalloc` offers a powerful introspection and control interface through the `mallctl` function. 4 | //! It can be used to tune the allocator, take heap dumps, and retrieve statistics. This crate 5 | //! provides a typed API over that interface. 6 | //! 7 | //! While `mallctl` takes a string to specify an operation (e.g. `stats.allocated` or 8 | //! `stats.arenas.15.muzzy_decay_ms`), the overhead of repeatedly parsing those strings is not 9 | //! ideal. Fortunately, `jemalloc` offers the ability to translate the string ahead of time into a 10 | //! "Management Information Base" (MIB) to speed up future lookups. 11 | //! 12 | //! This crate provides a type for each `mallctl` operation. Calling 13 | //! `$op::{read(), write(x), update(x)}` on the type calls `mallctl` with the 14 | //! string-based API. If the operation will be repeatedly performed, a MIB for 15 | //! the operation can be obtained using `$op.mib()`. 16 | //! 17 | //! # Examples 18 | //! 19 | //! Repeatedly printing allocation statistics: 20 | //! 21 | //! ```no_run 22 | //! extern crate jemallocator; 23 | //! extern crate jemalloc_ctl; 24 | //! 25 | //! use std::thread; 26 | //! use std::time::Duration; 27 | //! use jemalloc_ctl::{stats, epoch}; 28 | //! 29 | //! #[global_allocator] 30 | //! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 31 | //! 32 | //! fn main() { 33 | //! loop { 34 | //! // many statistics are cached and only updated when the epoch is advanced. 35 | //! epoch::advance().unwrap(); 36 | //! 37 | //! let allocated = stats::allocated::read().unwrap(); 38 | //! let resident = stats::resident::read().unwrap(); 39 | //! println!("{} bytes allocated/{} bytes resident", allocated, resident); 40 | //! thread::sleep(Duration::from_secs(10)); 41 | //! } 42 | //! } 43 | //! ``` 44 | //! 45 | //! Doing the same with the MIB-based API: 46 | //! 47 | //! ```no_run 48 | //! extern crate jemallocator; 49 | //! extern crate jemalloc_ctl; 50 | //! 51 | //! use std::thread; 52 | //! use std::time::Duration; 53 | //! use jemalloc_ctl::{stats, epoch}; 54 | //! 55 | //! #[global_allocator] 56 | //! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 57 | //! 58 | //! fn main() { 59 | //! let e = epoch::mib().unwrap(); 60 | //! let allocated = stats::allocated::mib().unwrap(); 61 | //! let resident = stats::resident::mib().unwrap(); 62 | //! loop { 63 | //! // many statistics are cached and only updated when the epoch is advanced. 64 | //! e.advance().unwrap(); 65 | //! 66 | //! let allocated = allocated.read().unwrap(); 67 | //! let resident = resident.read().unwrap(); 68 | //! println!("{} bytes allocated/{} bytes resident", allocated, resident); 69 | //! thread::sleep(Duration::from_secs(10)); 70 | //! } 71 | //! } 72 | //! ``` 73 | #![deny(missing_docs, intra_doc_link_resolution_failure)] 74 | #![cfg_attr(not(feature = "use_std"), no_std)] 75 | #![cfg_attr(feature = "cargo-clippy", allow(clippy::module_name_repetitions))] 76 | 77 | extern crate jemalloc_sys; 78 | extern crate libc; 79 | extern crate paste; 80 | 81 | #[cfg(test)] 82 | extern crate jemallocator; 83 | 84 | #[cfg(test)] 85 | #[global_allocator] 86 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 87 | 88 | #[cfg(not(feature = "use_std"))] 89 | use core as std; 90 | use std::{fmt, mem, num, ops, ptr, result, slice, str}; 91 | 92 | #[macro_use] 93 | mod macros; 94 | 95 | pub mod arenas; 96 | pub mod config; 97 | mod error; 98 | mod keys; 99 | pub mod opt; 100 | pub mod raw; 101 | pub mod stats; 102 | #[cfg(feature = "use_std")] 103 | pub mod stats_print; 104 | pub mod thread; 105 | 106 | pub use error::{Error, Result}; 107 | pub use keys::{Access, AsName, Mib, MibStr, Name}; 108 | 109 | option! { 110 | version[ str: b"version\0", str: 1 ] => &'static str | 111 | ops: r | 112 | docs: 113 | /// `jemalloc` version string. 114 | /// 115 | /// # Example 116 | /// 117 | /// ``` 118 | /// # extern crate jemallocator; 119 | /// # extern crate jemalloc_ctl; 120 | /// # 121 | /// # #[global_allocator] 122 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 123 | /// # 124 | /// # fn main() { 125 | /// use jemalloc_ctl::version; 126 | /// println!("jemalloc version {}", version::read().unwrap()); 127 | /// let version_mib = version::mib().unwrap(); 128 | /// println!("jemalloc version {}", version_mib.read().unwrap()); 129 | /// # } 130 | /// ``` 131 | mib_docs: /// See [`version`]. 132 | } 133 | 134 | option! { 135 | background_thread[ str: b"background_thread\0", non_str: 1 ] => bool | 136 | ops: r,w,u | 137 | docs: 138 | /// State of internal background worker threads. 139 | /// 140 | /// When enabled, background threads are created on demand (the number of 141 | /// background threads will be no more than the number of CPUs or active 142 | /// arenas). Threads run periodically and handle purging asynchronously. 143 | /// 144 | /// ``` 145 | /// # extern crate jemallocator; 146 | /// # extern crate jemalloc_ctl; 147 | /// # 148 | /// # #[global_allocator] 149 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 150 | /// # 151 | /// # fn main() { 152 | /// # #[cfg(not(target_os = "macos"))] { 153 | /// # 154 | /// use jemalloc_ctl::background_thread; 155 | /// let bg = background_thread::mib().unwrap(); 156 | /// let s = bg.read().unwrap(); 157 | /// println!("background_threads enabled: {}", s); 158 | /// let p = background_thread::update(!s).unwrap(); 159 | /// println!("background_threads enabled: {} => {}", p, bg.read().unwrap()); 160 | /// assert_eq!(p, s); 161 | /// background_thread::write(s).unwrap(); 162 | /// println!("background_threads enabled: {}", bg.read().unwrap()); 163 | /// assert_eq!(p, s); 164 | /// # 165 | /// # } // #[cfg(..)] 166 | /// # } 167 | /// ``` 168 | mib_docs: /// See [`background_thread`]. 169 | } 170 | 171 | option! { 172 | max_background_threads[ str: b"max_background_threads\0", non_str: 1 ] => libc::size_t | 173 | ops: r, w, u | 174 | docs: 175 | /// Maximum number of background threads that will be created. 176 | /// 177 | /// ``` 178 | /// # extern crate jemallocator; 179 | /// # extern crate jemalloc_ctl; 180 | /// # 181 | /// # #[global_allocator] 182 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 183 | /// # 184 | /// # fn main() { 185 | /// # #[cfg(not(target_os = "macos"))] { 186 | /// # 187 | /// use jemalloc_ctl::max_background_threads; 188 | /// let m = max_background_threads::mib().unwrap(); 189 | /// println!("max_background_threads: {}", m.read().unwrap()); 190 | /// m.write(0).unwrap(); 191 | /// assert_eq!(m.read().unwrap(), 0); 192 | /// # 193 | /// # } // #[cfg(..)] 194 | /// # } 195 | /// ``` 196 | mib_docs: /// See [`max_background_threads`]. 197 | } 198 | 199 | option! { 200 | epoch[ str: b"epoch\0", non_str: 1 ] => u64 | 201 | ops: r, w, u | 202 | docs: 203 | /// `jemalloc` epoch. 204 | /// 205 | /// Many of the statistics tracked by `jemalloc` are cached. The epoch 206 | /// controls when they are refreshed. 207 | /// 208 | /// # Example 209 | /// 210 | /// Advancing the epoch: 211 | /// 212 | /// ``` 213 | /// # extern crate jemallocator; 214 | /// # extern crate jemalloc_ctl; 215 | /// # 216 | /// # #[global_allocator] 217 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 218 | /// # 219 | /// # fn main() { 220 | /// # 221 | /// use jemalloc_ctl::epoch; 222 | /// let e = epoch::mib().unwrap(); 223 | /// let a = e.advance().unwrap(); 224 | /// let b = e.advance().unwrap(); 225 | /// assert_eq!(a + 1, b); 226 | /// 227 | /// let o = e.update(0).unwrap(); 228 | /// assert_eq!(o, e.read().unwrap()); 229 | /// # } 230 | mib_docs: /// See [`epoch`]. 231 | } 232 | 233 | impl epoch { 234 | /// Advances the epoch returning its old value - see [`epoch`]. 235 | pub fn advance() -> ::error::Result { 236 | Self::update(1) 237 | } 238 | } 239 | 240 | impl epoch_mib { 241 | /// Advances the epoch returning its old value - see [`epoch`]. 242 | pub fn advance(self) -> ::error::Result { 243 | self.0.update(1) 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/macros.rs: -------------------------------------------------------------------------------- 1 | //! Utility macros 2 | 3 | macro_rules! types { 4 | ($id:ident[ str: $byte_string:expr, $mib:ty, $name_to_mib:ident ] | 5 | docs: $(#[$doc:meta])* 6 | mib_docs: $(#[$doc_mib:meta])* 7 | ) => { 8 | paste::item! { 9 | $(#[$doc])* 10 | #[allow(non_camel_case_types)] 11 | pub struct $id; 12 | 13 | impl $id { 14 | const NAME: &'static ::keys::Name = { 15 | union U<'a> { 16 | bytes: &'a [u8], 17 | name: &'a ::keys::Name 18 | } 19 | 20 | unsafe { U { bytes: $byte_string }.name } 21 | }; 22 | /// Returns Management Information Base (MIB) 23 | /// 24 | /// This value can be used to access the key without doing string lookup. 25 | pub fn mib() -> ::error::Result<[<$id _mib>]> { 26 | Ok([<$id _mib>](Self::NAME.$name_to_mib()?)) 27 | } 28 | 29 | /// Key [`::keys::Name`]. 30 | pub fn name() -> &'static ::keys::Name { 31 | Self::NAME 32 | } 33 | } 34 | 35 | $(#[$doc_mib])* 36 | #[repr(transparent)] 37 | #[derive(Copy, Clone)] 38 | #[allow(non_camel_case_types)] 39 | pub struct [<$id _mib>](pub ::keys::$mib); 40 | } 41 | }; 42 | } 43 | 44 | /// Read 45 | macro_rules! r { 46 | ($id:ident => $ret_ty:ty) => { 47 | paste::item! { 48 | impl $id { 49 | /// Reads value using string API. 50 | pub fn read() -> ::error::Result<$ret_ty> { 51 | use ::keys::Access; 52 | Self::NAME.read() 53 | } 54 | } 55 | 56 | impl [<$id _mib>] { 57 | /// Reads value using MIB API. 58 | pub fn read(self) -> ::error::Result<$ret_ty> { 59 | use ::keys::Access; 60 | self.0.read() 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | #[test] 66 | #[cfg(not(target_arch = "mips64el"))] 67 | #[allow(unused)] 68 | fn [<$id _read_test>]() { 69 | match stringify!($id) { 70 | "background_thread" | 71 | "max_background_threads" 72 | if cfg!(target_os = "macos") => return, 73 | _ => (), 74 | } 75 | 76 | let a = $id::read().unwrap(); 77 | 78 | let mib = $id::mib().unwrap(); 79 | let b = mib.read().unwrap(); 80 | 81 | #[cfg(feature = "use_std")] 82 | println!( 83 | concat!( 84 | stringify!($id), 85 | " (read): \"{}\" - \"{}\""), 86 | a, b 87 | ); 88 | } 89 | } 90 | }; 91 | } 92 | 93 | /// Write 94 | macro_rules! w { 95 | ($id:ident => $ret_ty:ty) => { 96 | paste::item! { 97 | impl $id { 98 | /// Writes `value` using string API. 99 | pub fn write(value: $ret_ty) -> ::error::Result<()> { 100 | use ::keys::Access; 101 | Self::NAME.write(value) 102 | } 103 | } 104 | 105 | impl [<$id _mib>] { 106 | /// Writes `value` using MIB API. 107 | pub fn write(self, value: $ret_ty) -> ::error::Result<()> { 108 | use ::keys::Access; 109 | self.0.write(value) 110 | } 111 | } 112 | 113 | #[cfg(test)] 114 | #[test] 115 | #[cfg(not(target_arch = "mips64el"))] 116 | fn [<$id _write_test>]() { 117 | match stringify!($id) { 118 | "background_thread" | 119 | "max_background_threads" 120 | if cfg!(target_os = "macos") => return, 121 | _ => (), 122 | } 123 | 124 | let _ = $id::write($ret_ty::default()).unwrap(); 125 | 126 | let mib = $id::mib().unwrap(); 127 | let _ = mib.write($ret_ty::default()).unwrap(); 128 | 129 | #[cfg(feature = "use_std")] 130 | println!( 131 | concat!( 132 | stringify!($id), 133 | " (write): \"{}\""), 134 | $ret_ty::default() 135 | ); 136 | 137 | } 138 | } 139 | }; 140 | } 141 | 142 | /// Update 143 | macro_rules! u { 144 | ($id:ident => $ret_ty:ty) => { 145 | paste::item! { 146 | impl $id { 147 | /// Updates key to `value` returning its old value using string API. 148 | pub fn update(value: $ret_ty) -> ::error::Result<$ret_ty> { 149 | use ::keys::Access; 150 | Self::NAME.update(value) 151 | } 152 | } 153 | 154 | impl [<$id _mib>] { 155 | /// Updates key to `value` returning its old value using MIB API. 156 | pub fn update(self, value: $ret_ty) -> ::error::Result<$ret_ty> { 157 | use ::keys::Access; 158 | self.0.update(value) 159 | } 160 | } 161 | 162 | #[cfg(test)] 163 | #[test] 164 | #[cfg(not(target_arch = "mips64el"))] 165 | #[allow(unused)] 166 | fn [<$id _update_test>]() { 167 | match stringify!($id) { 168 | "background_thread" | 169 | "max_background_threads" 170 | if cfg!(target_os = "macos") => return, 171 | _ => (), 172 | } 173 | 174 | let a = $id::update($ret_ty::default()).unwrap(); 175 | 176 | let mib = $id::mib().unwrap(); 177 | let b = mib.update($ret_ty::default()).unwrap(); 178 | 179 | #[cfg(feature = "use_std")] 180 | println!( 181 | concat!( 182 | stringify!($id), 183 | " (update): (\"{}\", \"{}\") - \"{}\""), 184 | a, b, $ret_ty::default() 185 | ); 186 | } 187 | } 188 | }; 189 | } 190 | 191 | /// Creates a new option 192 | macro_rules! option { 193 | ($id:ident[ str: $byte_string:expr, $mib:ty, $name_to_mib:ident ] => $ret_ty:ty | 194 | ops: $($ops:ident),* | 195 | docs: 196 | $(#[$doc:meta])* 197 | mib_docs: 198 | $(#[$doc_mib:meta])* 199 | ) => { 200 | types! { 201 | $id[ str: $byte_string, $mib, $name_to_mib ] | 202 | docs: $(#[$doc])* 203 | mib_docs: $(#[$doc_mib])* 204 | } 205 | $( 206 | $ops!($id => $ret_ty); 207 | )* 208 | }; 209 | // Non-string option: 210 | ($id:ident[ str: $byte_string:expr, non_str: $mib_len:expr ] => $ret_ty:ty | 211 | ops: $($ops:ident),* | 212 | docs: 213 | $(#[$doc:meta])* 214 | mib_docs: 215 | $(#[$doc_mib:meta])* 216 | ) => { 217 | option! { 218 | $id[ str: $byte_string, Mib<[usize; $mib_len]>, mib ] => $ret_ty | 219 | ops: $($ops),* | 220 | docs: $(#[$doc])* 221 | mib_docs: $(#[$doc_mib])* 222 | } 223 | }; 224 | // String option: 225 | ($id:ident[ str: $byte_string:expr, str: $mib_len:expr ] => $ret_ty:ty | 226 | ops: $($ops:ident),* | 227 | docs: 228 | $(#[$doc:meta])* 229 | mib_docs: 230 | $(#[$doc_mib:meta])* 231 | ) => { 232 | option! { 233 | $id[ str: $byte_string, MibStr<[usize; $mib_len]>, mib_str ] => $ret_ty | 234 | ops: $($ops),* | 235 | docs: $(#[$doc])* 236 | mib_docs: $(#[$doc_mib])* 237 | } 238 | }; 239 | } 240 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/opt.rs: -------------------------------------------------------------------------------- 1 | //! `jemalloc`'s run-time configuration. 2 | //! 3 | //! These settings are controlled by the `MALLOC_CONF` environment variable. 4 | 5 | option! { 6 | abort[ str: b"opt.abort\0", non_str: 2 ] => bool | 7 | ops: r | 8 | docs: 9 | /// Whether `jemalloc` calls `abort(3)` on most warnings. 10 | /// 11 | /// This is disabled by default unless `--enable-debug` was specified during 12 | /// build configuration. 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// # extern crate jemallocator; 18 | /// # extern crate jemalloc_ctl; 19 | /// # 20 | /// # #[global_allocator] 21 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 22 | /// # 23 | /// # fn main() { 24 | /// use jemalloc_ctl::opt; 25 | /// let abort = opt::abort::mib().unwrap(); 26 | /// println!("abort on warning: {}", abort.read().unwrap()); 27 | /// # } 28 | /// ``` 29 | mib_docs: /// See [`abort`]. 30 | } 31 | 32 | option! { 33 | dss[ str: b"opt.dss\0", str: 2 ] => &'static str | 34 | ops: r | 35 | docs: 36 | /// The `dss` (`sbrk(2)`) allocation precedence as related to `mmap(2)` 37 | /// allocation. 38 | /// 39 | /// The following settings are supported if `sbrk(2)` is supported by the 40 | /// operating system: "disabled", "primary", and "secondary"; otherwise only 41 | /// "disabled" is supported. The default is "secondary" if `sbrk(2)` is 42 | /// supported by the operating system; "disabled" otherwise. 43 | /// 44 | /// # Examples 45 | /// 46 | /// ``` 47 | /// # extern crate jemallocator; 48 | /// # extern crate jemalloc_ctl; 49 | /// # 50 | /// # #[global_allocator] 51 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 52 | /// # 53 | /// # fn main() { 54 | /// use jemalloc_ctl::opt; 55 | /// let dss = opt::dss::read().unwrap(); 56 | /// println!("dss priority: {}", dss); 57 | /// # } 58 | /// ``` 59 | mib_docs: /// See [`dss`]. 60 | } 61 | 62 | option! { 63 | narenas[ str: b"opt.narenas\0", non_str: 2 ] => libc::c_uint | 64 | ops: r | 65 | docs: 66 | /// Maximum number of arenas to use for automatic multiplexing of threads 67 | /// and arenas. 68 | /// 69 | /// The default is four times the number of CPUs, or one if there is a 70 | /// single CPU. 71 | /// 72 | /// # Examples 73 | /// 74 | /// ``` 75 | /// # extern crate jemallocator; 76 | /// # extern crate jemalloc_ctl; 77 | /// # 78 | /// # #[global_allocator] 79 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 80 | /// # 81 | /// # fn main() { 82 | /// use jemalloc_ctl::opt; 83 | /// let narenas = opt::narenas::read().unwrap(); 84 | /// println!("number of arenas: {}", narenas); 85 | /// # } 86 | /// ``` 87 | mib_docs: /// See [`narenas`]. 88 | } 89 | 90 | option! { 91 | junk[ str: b"opt.junk\0", str: 2 ] => &'static str | 92 | ops: r | 93 | docs: 94 | /// `jemalloc`'s junk filling mode. 95 | /// 96 | /// Requires `--enable-fill` to have been specified during build 97 | /// configuration. 98 | /// 99 | /// If set to "alloc", each byte of uninitialized allocated memory will be 100 | /// set to `0x5a`. If set to "free", each byte of deallocated memory will be set 101 | /// to `0x5a`. If set to "true", both allocated and deallocated memory will be 102 | /// initialized, and if set to "false" junk filling will be disabled. This is 103 | /// intended for debugging and will impact performance negatively. 104 | /// 105 | /// The default is "false", unless `--enable-debug` was specified during 106 | /// build configuration, in 107 | /// which case the default is "true". 108 | /// 109 | /// # Examples 110 | /// 111 | /// ``` 112 | /// # extern crate jemallocator; 113 | /// # extern crate jemalloc_ctl; 114 | /// # 115 | /// # #[global_allocator] 116 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 117 | /// # 118 | /// # fn main() { 119 | /// use jemalloc_ctl::opt; 120 | /// let junk = opt::junk::read().unwrap(); 121 | /// println!("junk filling: {}", junk); 122 | /// # } 123 | /// ``` 124 | mib_docs: /// See [`junk`]. 125 | } 126 | 127 | option! { 128 | zero[ str: b"opt.zero\0", non_str: 2 ] => bool | 129 | ops: r | 130 | docs: 131 | /// `jemalloc`'s zeroing behavior. 132 | /// 133 | /// Requires `--enable-fill` to have been specified during build 134 | /// configuration. 135 | /// 136 | /// If enabled, `jemalloc` will initialize each byte of uninitialized 137 | /// allocated memory to 0. This is intended for debugging and will impact 138 | /// performance negatively. It is disabled by default. 139 | /// 140 | /// # Examples 141 | /// 142 | /// ``` 143 | /// # extern crate jemallocator; 144 | /// # extern crate jemalloc_ctl; 145 | /// # 146 | /// # #[global_allocator] 147 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 148 | /// # 149 | /// # fn main() { 150 | /// use jemalloc_ctl::opt; 151 | /// let zero = opt::zero::read().unwrap(); 152 | /// println!("zeroing: {}", zero); 153 | /// # } 154 | /// ``` 155 | mib_docs: /// See [`zero`]. 156 | } 157 | 158 | option! { 159 | tcache[ str: b"opt.tcache\0", non_str: 2 ] => bool | 160 | ops: r | 161 | docs: 162 | /// Thread-local allocation caching behavior. 163 | /// 164 | /// Thread-specific caching allows many allocations to be satisfied without 165 | /// performing any thread synchronization, at the cost of increased memory 166 | /// use. This is enabled by default. 167 | /// 168 | /// # Examples 169 | /// 170 | /// ``` 171 | /// # extern crate jemallocator; 172 | /// # extern crate jemalloc_ctl; 173 | /// # 174 | /// # #[global_allocator] 175 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 176 | /// # 177 | /// # fn main() { 178 | /// use jemalloc_ctl::opt; 179 | /// let tcache = opt::tcache::read().unwrap(); 180 | /// println!("thread-local caching: {}", tcache); 181 | /// # } 182 | /// ``` 183 | mib_docs: /// See [`tcache`]. 184 | } 185 | 186 | option! { 187 | lg_tcache_max[ str: b"opt.lg_tcache_max\0", non_str: 2 ] => libc::size_t | 188 | ops: r | 189 | docs: 190 | /// Maximum size class (log base 2) to cache in the thread-specific cache 191 | /// (`tcache`). 192 | /// 193 | /// At a minimum, all small size classes are cached, and at a maximum all 194 | /// large size classes are cached. The default maximum is 32 KiB (2^15). 195 | /// 196 | /// # Examples 197 | /// 198 | /// ``` 199 | /// # extern crate jemallocator; 200 | /// # extern crate jemalloc_ctl; 201 | /// # 202 | /// # #[global_allocator] 203 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 204 | /// # 205 | /// # fn main() { 206 | /// use jemalloc_ctl::opt; 207 | /// let lg_tcache_max = opt::lg_tcache_max::read().unwrap(); 208 | /// println!("max cached allocation size: {}", 1 << lg_tcache_max); 209 | /// # } 210 | /// ``` 211 | mib_docs: /// See [`lg_tcache_max`]. 212 | } 213 | 214 | option! { 215 | background_thread[ str: b"opt.background_thread\0", non_str: 2 ] => bool | 216 | ops: r | 217 | docs: 218 | /// `jemalloc`'s default initialization behavior for background threads. 219 | /// 220 | /// `jemalloc` automatically spawns background worker threads on 221 | /// initialization (first `jemalloc` call) if this option is enabled. By 222 | /// default this option is disabled - `malloc_conf=background_thread:true` 223 | /// changes its default. 224 | /// 225 | /// # Examples 226 | /// 227 | /// ``` 228 | /// # extern crate jemallocator; 229 | /// # extern crate jemalloc_ctl; 230 | /// # 231 | /// # #[global_allocator] 232 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 233 | /// # 234 | /// # fn main() { 235 | /// use jemalloc_ctl::opt; 236 | /// let background_thread = opt::background_thread::read().unwrap(); 237 | /// println!("background threads since initialization: {}", background_thread); 238 | /// # } 239 | /// ``` 240 | mib_docs: /// See [`background_thread`]. 241 | } 242 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/raw.rs: -------------------------------------------------------------------------------- 1 | //! Raw `unsafe` access to the `malloctl` API. 2 | 3 | use error::{cvt, Result}; 4 | use libc::c_char; 5 | use {mem, ptr, slice}; 6 | 7 | /// Translates `name` to a `mib` (Management Information Base) 8 | /// 9 | /// `mib`s are used to avoid repeated name lookups for applications that 10 | /// repeatedly query the same portion of `jemalloc`s `mallctl` namespace. 11 | /// 12 | /// On success, `mib` contains an array of integers. It is possible to pass 13 | /// `mib` with a length smaller than the number of period-separated name 14 | /// components. This results in a partial MIB that can be used as the basis for 15 | /// constructing a complete MIB. 16 | /// 17 | /// For name components that are integers (e.g. the `2` in `arenas.bin.2.size`), 18 | /// the corresponding MIB component will always be that integer. Therefore, it 19 | /// is legitimate to construct code like the following: 20 | /// 21 | /// ``` 22 | /// extern crate libc; 23 | /// extern crate jemallocator; 24 | /// extern crate jemalloc_ctl; 25 | /// 26 | /// #[global_allocator] 27 | /// static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 28 | /// 29 | /// fn main() { 30 | /// use jemalloc_ctl::raw; 31 | /// use libc::{c_uint, c_char}; 32 | /// unsafe { 33 | /// let mut mib = [0; 4]; 34 | /// let nbins: c_uint = raw::read(b"arenas.nbins\0").unwrap(); 35 | /// raw::name_to_mib(b"arenas.bin.0.size\0", &mut mib).unwrap(); 36 | /// for i in 0..4 { 37 | /// mib[2] = i; 38 | /// let bin_size: usize = raw::read_mib(&mut mib).unwrap(); 39 | /// println!("arena bin {} has size {}", i, bin_size); 40 | /// } 41 | /// } 42 | /// } 43 | /// ``` 44 | pub fn name_to_mib(name: &[u8], mib: &mut [usize]) -> Result<()> { 45 | unsafe { 46 | validate_name(name); 47 | 48 | let mut len = mib.len(); 49 | cvt(jemalloc_sys::mallctlnametomib( 50 | name as *const _ as *const c_char, 51 | mib.as_mut_ptr(), 52 | &mut len, 53 | ))?; 54 | assert_eq!(mib.len(), len); 55 | Ok(()) 56 | } 57 | } 58 | 59 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and reads its value. 60 | /// 61 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 62 | /// to a `mib` (Management Information Base). 63 | /// 64 | /// # Safety 65 | /// 66 | /// This function is `unsafe` because it is possible to use it to construct an 67 | /// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The 68 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 69 | /// `u8` can. 70 | pub unsafe fn read_mib(mib: &[usize]) -> Result { 71 | let mut value = MaybeUninit { init: () }; 72 | let mut len = mem::size_of::(); 73 | cvt(jemalloc_sys::mallctlbymib( 74 | mib.as_ptr(), 75 | mib.len(), 76 | &mut value.init as *mut _ as *mut _, 77 | &mut len, 78 | ptr::null_mut(), 79 | 0, 80 | ))?; 81 | assert_eq!(len, mem::size_of::()); 82 | Ok(value.maybe_uninit) 83 | } 84 | 85 | /// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and 86 | /// reads its value. 87 | /// 88 | /// # Safety 89 | /// 90 | /// This function is `unsafe` because it is possible to use it to construct an 91 | /// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The 92 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 93 | /// `u8` can. 94 | pub unsafe fn read(name: &[u8]) -> Result { 95 | validate_name(name); 96 | 97 | let mut value = MaybeUninit { init: () }; 98 | let mut len = mem::size_of::(); 99 | cvt(jemalloc_sys::mallctl( 100 | name as *const _ as *const c_char, 101 | &mut value.init as *mut _ as *mut _, 102 | &mut len, 103 | ptr::null_mut(), 104 | 0, 105 | ))?; 106 | assert_eq!(len, mem::size_of::()); 107 | Ok(value.maybe_uninit) 108 | } 109 | 110 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`. 111 | /// 112 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 113 | /// to a `mib` (Management Information Base). 114 | /// 115 | /// # Safety 116 | /// 117 | /// This function is `unsafe` because it is possible to use it to construct an 118 | /// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The 119 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 120 | /// `u8` can. 121 | pub unsafe fn write_mib(mib: &[usize], mut value: T) -> Result<()> { 122 | cvt(jemalloc_sys::mallctlbymib( 123 | mib.as_ptr(), 124 | mib.len(), 125 | ptr::null_mut(), 126 | ptr::null_mut(), 127 | &mut value as *mut _ as *mut _, 128 | mem::size_of::(), 129 | )) 130 | } 131 | 132 | /// Uses the null-terminated string `name` as the key to the _MALLCTL NAMESPACE_ 133 | /// and writes it `value` 134 | /// 135 | /// # Safety 136 | /// 137 | /// This function is `unsafe` because it is possible to use it to construct an 138 | /// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The 139 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 140 | /// `u8` can. 141 | pub unsafe fn write(name: &[u8], mut value: T) -> Result<()> { 142 | validate_name(name); 143 | 144 | cvt(jemalloc_sys::mallctl( 145 | name as *const _ as *const c_char, 146 | ptr::null_mut(), 147 | ptr::null_mut(), 148 | &mut value as *mut _ as *mut _, 149 | mem::size_of::(), 150 | )) 151 | } 152 | 153 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value` 154 | /// returning its previous value. 155 | /// 156 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 157 | /// to a `mib` (Management Information Base). 158 | /// 159 | /// # Safety 160 | /// 161 | /// This function is `unsafe` because it is possible to use it to construct an 162 | /// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The 163 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 164 | /// `u8` can. 165 | pub unsafe fn update_mib(mib: &[usize], mut value: T) -> Result { 166 | let mut len = mem::size_of::(); 167 | cvt(jemalloc_sys::mallctlbymib( 168 | mib.as_ptr(), 169 | mib.len(), 170 | &mut value as *mut _ as *mut _, 171 | &mut len, 172 | &mut value as *mut _ as *mut _, 173 | len, 174 | ))?; 175 | assert_eq!(len, mem::size_of::()); 176 | Ok(value) 177 | } 178 | 179 | /// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and 180 | /// writes its `value` returning its previous value. 181 | /// 182 | /// # Safety 183 | /// 184 | /// This function is `unsafe` because it is possible to use it to construct an 185 | /// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The 186 | /// sizes of `bool` and `u8` match, but `bool` cannot represent all values that 187 | /// `u8` can. 188 | pub unsafe fn update(name: &[u8], mut value: T) -> Result { 189 | validate_name(name); 190 | 191 | let mut len = mem::size_of::(); 192 | cvt(jemalloc_sys::mallctl( 193 | name as *const _ as *const c_char, 194 | &mut value as *mut _ as *mut _, 195 | &mut len, 196 | &mut value as *mut _ as *mut _, 197 | len, 198 | ))?; 199 | assert_eq!(len, mem::size_of::()); 200 | Ok(value) 201 | } 202 | 203 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and reads its value. 204 | /// 205 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 206 | /// to a `mib` (Management Information Base). 207 | /// 208 | /// # Safety 209 | /// 210 | /// This function is unsafe because if the key does not return a pointer to a 211 | /// null-terminated string the behavior is undefined. 212 | /// 213 | /// For example, a key for a `u64` value can be used to read a pointer on 64-bit 214 | /// platform, where this pointer will point to the address denoted by the `u64`s 215 | /// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer 216 | /// that will not point to a null-terminated string. 217 | /// 218 | /// This function needs to compute the length of the string by looking for the 219 | /// null-terminator: `\0`. This requires reading the memory behind the pointer. 220 | /// 221 | /// If the pointer is invalid (e.g. because it was converted from a `u64` that 222 | /// does not represent a valid address), reading the string to look for `\0` 223 | /// will dereference a non-dereferenceable pointer, which is undefined behavior. 224 | /// 225 | /// If the pointer is valid but it does not point to a null-terminated string, 226 | /// looking for `\0` will read garbage and might end up reading out-of-bounds, 227 | /// which is undefined behavior. 228 | pub unsafe fn read_str_mib(mib: &[usize]) -> Result<&'static [u8]> { 229 | let ptr: *const c_char = read_mib(mib)?; 230 | ptr2str(ptr) 231 | } 232 | 233 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value`. 234 | /// 235 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 236 | /// to a `mib` (Management Information Base). 237 | /// 238 | /// # Panics 239 | /// 240 | /// If `value` is not a non-empty null-terminated string. 241 | pub fn write_str_mib(mib: &[usize], value: &'static [u8]) -> Result<()> { 242 | assert!(!value.is_empty(), "value cannot be empty"); 243 | assert_eq!(*value.last().unwrap(), b'\0'); 244 | // This is safe because `value` will always point to a null-terminated 245 | // string, which makes it safe for all key value types: pointers to 246 | // null-terminated strings, pointers, pointer-sized integers, etc. 247 | unsafe { write_mib(mib, value.as_ptr() as *const c_char) } 248 | } 249 | 250 | /// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and writes its `value` 251 | /// returning its previous value. 252 | /// 253 | /// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`) 254 | /// to a `mib` (Management Information Base). 255 | /// 256 | /// # Safety 257 | /// 258 | /// This function is unsafe because if the key does not return a pointer to a 259 | /// null-terminated string the behavior is undefined. 260 | /// 261 | /// For example, a key for a `u64` value can be used to read a pointer on 64-bit 262 | /// platform, where this pointer will point to the address denoted by the `u64`s 263 | /// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer 264 | /// that will not point to a null-terminated string. 265 | /// 266 | /// This function needs to compute the length of the string by looking for the 267 | /// null-terminator: `\0`. This requires reading the memory behind the pointer. 268 | /// 269 | /// If the pointer is invalid (e.g. because it was converted from a `u64` that 270 | /// does not represent a valid address), reading the string to look for `\0` 271 | /// will dereference a non-dereferenceable pointer, which is undefined behavior. 272 | /// 273 | /// If the pointer is valid but it does not point to a null-terminated string, 274 | /// looking for `\0` will read garbage and might end up reading out-of-bounds, 275 | /// which is undefined behavior. 276 | pub unsafe fn update_str_mib( 277 | mib: &[usize], 278 | value: &'static [u8], 279 | ) -> Result<&'static [u8]> { 280 | let ptr: *const c_char = update_mib(mib, value.as_ptr() as *const c_char)?; 281 | ptr2str(ptr) 282 | } 283 | 284 | /// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and 285 | /// reads its value. 286 | /// 287 | /// # Safety 288 | /// 289 | /// This function is unsafe because if the key does not return a pointer to a 290 | /// null-terminated string the behavior is undefined. 291 | /// 292 | /// For example, a key for a `u64` value can be used to read a pointer on 64-bit 293 | /// platform, where this pointer will point to the address denoted by the `u64`s 294 | /// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer 295 | /// that will not point to a null-terminated string. 296 | /// 297 | /// This function needs to compute the length of the string by looking for the 298 | /// null-terminator: `\0`. This requires reading the memory behind the pointer. 299 | /// 300 | /// If the pointer is invalid (e.g. because it was converted from a `u64` that 301 | /// does not represent a valid address), reading the string to look for `\0` 302 | /// will dereference a non-dereferenceable pointer, which is undefined behavior. 303 | /// 304 | /// If the pointer is valid but it does not point to a null-terminated string, 305 | /// looking for `\0` will read garbage and might end up reading out-of-bounds, 306 | /// which is undefined behavior. 307 | pub unsafe fn read_str(name: &[u8]) -> Result<&'static [u8]> { 308 | let ptr: *const c_char = read(name)?; 309 | ptr2str(ptr) 310 | } 311 | 312 | /// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and 313 | /// writes its `value`. 314 | pub fn write_str(name: &[u8], value: &'static [u8]) -> Result<()> { 315 | assert!(!value.is_empty(), "value cannot be empty"); 316 | assert_eq!(*value.last().unwrap(), b'\0'); 317 | // This is safe because `value` will always point to a null-terminated 318 | // string, which makes it safe for all key value types: pointers to 319 | // null-terminated strings, pointers, pointer-sized integers, etc. 320 | unsafe { write(name, value.as_ptr() as *const c_char) } 321 | } 322 | 323 | /// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and 324 | /// writes its `value` returning its previous value. 325 | /// 326 | /// # Safety 327 | /// 328 | /// This function is unsafe because if the key does not return a pointer to a 329 | /// null-terminated string the behavior is undefined. 330 | /// 331 | /// For example, a key for a `u64` value can be used to read a pointer on 64-bit 332 | /// platform, where this pointer will point to the address denoted by the `u64`s 333 | /// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer 334 | /// that will not point to a null-terminated string. 335 | /// 336 | /// This function needs to compute the length of the string by looking for the 337 | /// null-terminator: `\0`. This requires reading the memory behind the pointer. 338 | /// 339 | /// If the pointer is invalid (e.g. because it was converted from a `u64` that 340 | /// does not represent a valid address), reading the string to look for `\0` 341 | /// will dereference a non-dereferenceable pointer, which is undefined behavior. 342 | /// 343 | /// If the pointer is valid but it does not point to a null-terminated string, 344 | /// looking for `\0` will read garbage and might end up reading out-of-bounds, 345 | /// which is undefined behavior. 346 | pub unsafe fn update_str( 347 | name: &[u8], 348 | value: &'static [u8], 349 | ) -> Result<&'static [u8]> { 350 | let ptr: *const c_char = update(name, value.as_ptr() as *const c_char)?; 351 | ptr2str(ptr) 352 | } 353 | 354 | /// Converts a non-empty null-terminated character string at `ptr` into a valid 355 | /// null-terminated UTF-8 string. 356 | /// 357 | /// # Panics 358 | /// 359 | /// If `ptr.is_null()`. 360 | /// 361 | /// # Safety 362 | /// 363 | /// If `ptr` does not point to a null-terminated character string the behavior 364 | /// is undefined. 365 | unsafe fn ptr2str(ptr: *const c_char) -> Result<&'static [u8]> { 366 | assert!( 367 | !ptr.is_null(), 368 | "attempt to convert a null-ptr to a UTF-8 string" 369 | ); 370 | let len = libc::strlen(ptr); 371 | Ok(slice::from_raw_parts(ptr as *const u8, len + 1)) 372 | } 373 | 374 | fn validate_name(name: &[u8]) { 375 | assert!(!name.is_empty(), "empty byte string"); 376 | assert_eq!( 377 | *name.last().unwrap(), 378 | b'\0', 379 | "non-null terminated byte string" 380 | ); 381 | } 382 | 383 | union MaybeUninit { 384 | init: (), 385 | maybe_uninit: T, 386 | } 387 | 388 | #[cfg(test)] 389 | mod tests { 390 | use super::*; 391 | #[test] 392 | #[cfg(not(target_arch = "mips64el"))] // FIXME: SIGFPE 393 | fn test_ptr2str() { 394 | unsafe { 395 | //{ // This is undefined behavior: 396 | // let cstr = b""; 397 | // let rstr = ptr2str(cstr as *const _ as *const c_char); 398 | // assert!(rstr.is_err()); 399 | // } 400 | { 401 | let cstr = b"\0"; 402 | let rstr = ptr2str(cstr as *const _ as *const c_char); 403 | assert!(rstr.is_ok()); 404 | let rstr = rstr.unwrap(); 405 | assert_eq!(rstr.len(), 1); 406 | assert_eq!(rstr, b"\0"); 407 | } 408 | { 409 | let cstr = b"foo baaar\0"; 410 | let rstr = ptr2str(cstr as *const _ as *const c_char); 411 | assert!(rstr.is_ok()); 412 | let rstr = rstr.unwrap(); 413 | assert_eq!(rstr.len(), b"foo baaar\0".len()); 414 | assert_eq!(rstr, b"foo baaar\0"); 415 | } 416 | } 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/stats.rs: -------------------------------------------------------------------------------- 1 | //! Global allocator statistics. 2 | //! 3 | //! `jemalloc` tracks a wide variety of statistics. Many of them are cached, and 4 | //! only refreshed when the `jemalloc` "epoch" is advanced. See the [`::epoch`] type 5 | //! for more information. 6 | 7 | option! { 8 | allocated[ str: b"stats.allocated\0", non_str: 2 ] => libc::size_t | 9 | ops: r | 10 | docs: 11 | /// Total number of bytes allocated by the application. 12 | /// 13 | /// This statistic is cached, and is only refreshed when the epoch is 14 | /// advanced. See the [`::epoch`] type for more information. 15 | /// 16 | /// This corresponds to `stats.allocated` in jemalloc's API. 17 | /// 18 | /// # Examples 19 | /// 20 | /// ```rust 21 | /// # extern crate jemallocator; 22 | /// # extern crate jemalloc_ctl; 23 | /// # 24 | /// # #[global_allocator] 25 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 26 | /// # 27 | /// # fn main() { 28 | /// use jemalloc_ctl::{epoch, stats}; 29 | /// let e = epoch::mib().unwrap(); 30 | /// let allocated = stats::allocated::mib().unwrap(); 31 | /// 32 | /// let a = allocated.read().unwrap(); 33 | /// let _buf = vec![0; 1024 * 1024]; 34 | /// e.advance().unwrap(); 35 | /// let b = allocated.read().unwrap(); 36 | /// assert!(a < b); 37 | /// # } 38 | /// ``` 39 | mib_docs: /// See [`allocated`]. 40 | } 41 | 42 | option! { 43 | active[ str: b"stats.active\0", non_str: 2 ] => libc::size_t | 44 | ops: r | 45 | docs: 46 | /// Total number of bytes in active pages allocated by the application. 47 | /// 48 | /// This is a multiple of the page size, and greater than or equal to the 49 | /// value returned by [`allocated`]. 50 | /// 51 | /// This statistic is cached, and is only refreshed when the epoch is 52 | /// advanced. See the [`::epoch`] type for more information. 53 | /// 54 | /// This corresponds to `stats.active` in jemalloc's API. 55 | /// 56 | /// # Examples 57 | /// 58 | /// ```rust 59 | /// # extern crate jemallocator; 60 | /// # extern crate jemalloc_ctl; 61 | /// # 62 | /// # #[global_allocator] 63 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 64 | /// # 65 | /// # fn main() { 66 | /// use jemalloc_ctl::{epoch, stats}; 67 | /// let e = epoch::mib().unwrap(); 68 | /// let active = stats::active::mib().unwrap(); 69 | /// 70 | /// let a = active.read().unwrap(); 71 | /// let _buf = vec![0; 1024 * 1024]; 72 | /// e.advance().unwrap(); 73 | /// let b = active.read().unwrap(); 74 | /// assert!(a < b); 75 | /// # } 76 | /// ``` 77 | mib_docs: /// See [`active`]. 78 | } 79 | 80 | option! { 81 | metadata[ str: b"stats.metadata\0", non_str: 2 ] => libc::size_t | 82 | ops: r | 83 | docs: 84 | /// Total number of bytes dedicated to `jemalloc` metadata. 85 | /// 86 | /// This statistic is cached, and is only refreshed when the epoch is 87 | /// advanced. See the [`::epoch`] type for more information. 88 | /// 89 | /// This corresponds to `stats.metadata` in jemalloc's API. 90 | /// 91 | /// # Examples 92 | /// 93 | /// ```rust 94 | /// # extern crate jemallocator; 95 | /// # extern crate jemalloc_ctl; 96 | /// # 97 | /// # #[global_allocator] 98 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 99 | /// # 100 | /// # fn main() { 101 | /// use jemalloc_ctl::{epoch, stats}; 102 | /// let e = epoch::mib().unwrap(); 103 | /// let metadata = stats::metadata::mib().unwrap(); 104 | /// 105 | /// e.advance().unwrap(); 106 | /// let size = metadata.read().unwrap(); 107 | /// println!("{} bytes of jemalloc metadata", size); 108 | /// # } 109 | /// ``` 110 | mib_docs: /// See [`metadata`]. 111 | } 112 | 113 | option! { 114 | resident[ str: b"stats.resident\0", non_str: 2 ] => libc::size_t | 115 | ops: r | 116 | docs: 117 | /// Total number of bytes in physically resident data pages mapped by the 118 | /// allocator. 119 | /// 120 | /// This consists of all pages dedicated to allocator metadata, pages 121 | /// backing active allocations, and unused dirty pages. It may overestimate 122 | /// the true value because pages may not actually be physically resident if 123 | /// they correspond to demand-zeroed virtual memory that has not yet been 124 | /// touched. This is a multiple of the page size, and is larger than the 125 | /// value returned by [`active`]. 126 | /// 127 | /// This statistic is cached, and is only refreshed when the epoch is 128 | /// advanced. See the [`::epoch`] type for more information. 129 | /// 130 | /// This corresponds to `stats.resident` in jemalloc's API. 131 | /// 132 | /// # Examples 133 | /// 134 | /// ```rust 135 | /// # extern crate jemallocator; 136 | /// # extern crate jemalloc_ctl; 137 | /// # 138 | /// # #[global_allocator] 139 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 140 | /// # 141 | /// # fn main() { 142 | /// use jemalloc_ctl::{epoch, stats}; 143 | /// let e = epoch::mib().unwrap(); 144 | /// let resident = stats::resident::mib().unwrap(); 145 | /// 146 | /// e.advance().unwrap(); 147 | /// let size = resident.read().unwrap(); 148 | /// println!("{} bytes of total resident data", size); 149 | /// # } 150 | /// ``` 151 | mib_docs: /// See [`resident`]. 152 | } 153 | 154 | option! { 155 | mapped[ str: b"stats.mapped\0", non_str: 2 ] => libc::size_t | 156 | ops: r | 157 | docs: 158 | /// Total number of bytes in active extents mapped by the allocator. 159 | /// 160 | /// This does not include inactive extents, even those that contain unused 161 | /// dirty pages, so there is no strict ordering between this and the value 162 | /// returned by [`resident`]. This is a multiple of the page size, and is 163 | /// larger than the value returned by [`active`]. 164 | /// 165 | /// This statistic is cached, and is only refreshed when the epoch is 166 | /// advanced. See the [`::epoch`] type for more information. 167 | /// 168 | /// This corresponds to `stats.mapped` in jemalloc's API. 169 | /// 170 | /// # Examples 171 | /// 172 | /// ```rust 173 | /// # extern crate jemallocator; 174 | /// # extern crate jemalloc_ctl; 175 | /// # 176 | /// # #[global_allocator] 177 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 178 | /// # 179 | /// # fn main() { 180 | /// use jemalloc_ctl::{epoch, stats}; 181 | /// let e = epoch::mib().unwrap(); 182 | /// let mapped = stats::mapped::mib().unwrap(); 183 | /// 184 | /// e.advance().unwrap(); 185 | /// let size = mapped.read().unwrap(); 186 | /// println!("{} bytes of total mapped data", size); 187 | /// # } 188 | /// ``` 189 | mib_docs: /// See [`mapped`]. 190 | } 191 | 192 | option! { 193 | retained[ str: b"stats.retained\0", non_str: 2 ] => libc::size_t | 194 | ops: r | 195 | docs: 196 | /// Total number of bytes in virtual memory mappings that were retained 197 | /// rather than being returned to the operating system via e.g. `munmap(2)`. 198 | /// 199 | /// Retained virtual memory is typically untouched, decommitted, or purged, 200 | /// so it has no strongly associated physical memory. Retained memory is 201 | /// excluded from mapped memory statistics, e.g. [`mapped`]. 202 | /// 203 | /// This statistic is cached, and is only refreshed when the epoch is 204 | /// advanced. See the [`::epoch`] type for more information. 205 | /// 206 | /// This corresponds to `stats.retained` in jemalloc's API. 207 | /// 208 | /// # Examples 209 | /// 210 | /// ```rust 211 | /// # extern crate jemallocator; 212 | /// # extern crate jemalloc_ctl; 213 | /// # 214 | /// # #[global_allocator] 215 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 216 | /// # 217 | /// # fn main() { 218 | /// use jemalloc_ctl::{epoch, stats}; 219 | /// let e = epoch::mib().unwrap(); 220 | /// let retained = stats::retained::mib().unwrap(); 221 | /// 222 | /// e.advance().unwrap(); 223 | /// let size = retained.read().unwrap(); 224 | /// println!("{} bytes of total retained data", size); 225 | /// # } 226 | /// ``` 227 | mib_docs: /// See [`retained`]. 228 | } 229 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/stats_print.rs: -------------------------------------------------------------------------------- 1 | //! Bulk statistics output. 2 | 3 | extern crate std; 4 | 5 | use libc::{c_char, c_void}; 6 | use std::any::Any; 7 | use std::ffi::CStr; 8 | use std::io::{self, Write}; 9 | use std::panic::{self, AssertUnwindSafe}; 10 | 11 | /// Statistics configuration. 12 | /// 13 | /// All options default to `false`. 14 | #[derive(Copy, Clone, Default)] 15 | pub struct Options { 16 | /// If set, the output will be JSON-formatted. 17 | /// 18 | /// This corresponds to the `J` character. 19 | pub json_format: bool, 20 | 21 | /// If set, information that never changes during execution will be skipped. 22 | /// 23 | /// This corresponds to the `g` character. 24 | pub skip_constants: bool, 25 | 26 | /// If set, merged information about arenas will be skipped. 27 | /// 28 | /// This corresponds to the `m` character. 29 | pub skip_merged_arenas: bool, 30 | 31 | /// If set, information about individual arenas will be skipped. 32 | /// 33 | /// This corresponds to the `a` character. 34 | pub skip_per_arena: bool, 35 | 36 | /// If set, information about individual size classes for bins will be skipped. 37 | /// 38 | /// This corresponds to the `b` character. 39 | pub skip_bin_size_classes: bool, 40 | 41 | /// If set, information about individual size classes for large objects will be skipped. 42 | /// 43 | /// This corresponds to the `l` character. 44 | pub skip_large_size_classes: bool, 45 | 46 | /// If set, mutex statistics will be skipped. 47 | /// 48 | /// This corresponds to the `x` character. 49 | pub skip_mutex_statistics: bool, 50 | 51 | _p: (), 52 | } 53 | 54 | struct State { 55 | writer: W, 56 | error: io::Result<()>, 57 | panic: Result<(), Box>, 58 | } 59 | 60 | extern "C" fn callback(opaque: *mut c_void, buf: *const c_char) 61 | where 62 | W: Write, 63 | { 64 | unsafe { 65 | let state = &mut *(opaque as *mut State); 66 | if state.error.is_err() || state.panic.is_err() { 67 | return; 68 | } 69 | 70 | let buf = CStr::from_ptr(buf); 71 | match panic::catch_unwind(AssertUnwindSafe(|| { 72 | state.writer.write_all(buf.to_bytes()) 73 | })) { 74 | Ok(Ok(_)) => {} 75 | Ok(Err(e)) => state.error = Err(e), 76 | Err(e) => state.panic = Err(e), 77 | } 78 | } 79 | } 80 | 81 | /// Writes allocator statistics. 82 | /// 83 | /// The information is the same that can be retrieved by the individual lookup methods in this 84 | /// crate, but all done at once. 85 | #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_possible_wrap))] 86 | pub fn stats_print(writer: W, options: Options) -> io::Result<()> 87 | where 88 | W: Write, 89 | { 90 | unsafe { 91 | let mut state = State { 92 | writer, 93 | error: Ok(()), 94 | panic: Ok(()), 95 | }; 96 | let mut opts = [0; 8]; 97 | let mut i = 0; 98 | if options.json_format { 99 | opts[i] = b'J' as c_char; 100 | i += 1; 101 | } 102 | if options.skip_constants { 103 | opts[i] = b'g' as c_char; 104 | i += 1; 105 | } 106 | if options.skip_merged_arenas { 107 | opts[i] = b'm' as c_char; 108 | i += 1; 109 | } 110 | if options.skip_per_arena { 111 | opts[i] = b'a' as c_char; 112 | i += 1; 113 | } 114 | if options.skip_bin_size_classes { 115 | opts[i] = b'b' as c_char; 116 | i += 1; 117 | } 118 | if options.skip_large_size_classes { 119 | opts[i] = b'l' as c_char; 120 | i += 1; 121 | } 122 | if options.skip_mutex_statistics { 123 | opts[i] = b'x' as c_char; 124 | i += 1; 125 | } 126 | opts[i] = 0; 127 | 128 | jemalloc_sys::malloc_stats_print( 129 | Some(callback::), 130 | &mut state as *mut _ as *mut c_void, 131 | opts.as_ptr(), 132 | ); 133 | if let Err(e) = state.panic { 134 | panic::resume_unwind(e); 135 | } 136 | state.error 137 | } 138 | } 139 | 140 | #[cfg(test)] 141 | mod test { 142 | use super::*; 143 | 144 | #[test] 145 | fn basic() { 146 | let mut buf = vec![]; 147 | stats_print(&mut buf, Options::default()).unwrap(); 148 | println!("{}", String::from_utf8(buf).unwrap()); 149 | } 150 | 151 | #[test] 152 | fn all_options() { 153 | let mut buf = vec![]; 154 | let options = Options { 155 | json_format: true, 156 | skip_constants: true, 157 | skip_merged_arenas: true, 158 | skip_per_arena: true, 159 | skip_bin_size_classes: true, 160 | skip_large_size_classes: true, 161 | skip_mutex_statistics: true, 162 | _p: (), 163 | }; 164 | stats_print(&mut buf, options).unwrap(); 165 | println!("{}", String::from_utf8(buf).unwrap()); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /jemalloc-ctl/src/thread.rs: -------------------------------------------------------------------------------- 1 | //! Thread specific operations. 2 | 3 | use error::Result; 4 | use raw::{read, read_mib}; 5 | 6 | option! { 7 | allocatedp[ str: b"thread.allocatedp\0", non_str: 2 ] => *mut u64 | 8 | ops: | 9 | docs: 10 | /// Access to the total number of bytes allocated by the current thread. 11 | /// 12 | /// Unlike [`::stats::allocated`], the value returned by this type is not the 13 | /// number of bytes *currently* allocated, but rather the number of bytes 14 | /// that have *ever* been allocated by this thread. 15 | /// 16 | /// The `read` method doesn't return the value directly, but actually a 17 | /// pointer to the value. This allows for very fast repeated lookup, since 18 | /// there is no function call overhead. The pointer type cannot be sent to 19 | /// other threads, but `allocated::read` can be called on different threads 20 | /// and will return the appropriate pointer for each of them. 21 | /// 22 | /// # Example 23 | /// 24 | /// ``` 25 | /// # extern crate jemallocator; 26 | /// # extern crate jemalloc_ctl; 27 | /// # 28 | /// # #[global_allocator] 29 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 30 | /// # 31 | /// # fn main() { 32 | /// use jemalloc_ctl::thread; 33 | /// let allocated = thread::allocatedp::mib().unwrap(); 34 | /// let allocated = allocated.read().unwrap(); 35 | /// 36 | /// let a = allocated.get(); 37 | /// let buf = vec![0; 1024 * 1024]; 38 | /// let b = allocated.get(); 39 | /// drop( buf); 40 | /// let c = allocated.get(); 41 | /// 42 | /// assert!(a < b); 43 | /// assert_eq!(b, c); 44 | /// # } 45 | /// ``` 46 | mib_docs: /// See [`allocatedp`]. 47 | } 48 | 49 | impl allocatedp { 50 | /// Reads value using string API. 51 | pub fn read() -> Result> { 52 | unsafe { read(Self::name().as_bytes()).map(ThreadLocal) } 53 | } 54 | } 55 | 56 | impl allocatedp_mib { 57 | /// Reads value using MIB API. 58 | pub fn read(&self) -> Result> { 59 | unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) } 60 | } 61 | } 62 | 63 | option! { 64 | deallocatedp[ str: b"thread.deallocatedp\0", non_str: 2 ] => *mut u64 | 65 | ops: | 66 | docs: 67 | /// Access to the total number of bytes deallocated by the current thread. 68 | /// 69 | /// The `read` method doesn't return the value directly, but actually a 70 | /// pointer to the value. This allows for very fast repeated lookup, since 71 | /// there is no function call overhead. The pointer type cannot be sent to 72 | /// other threads, but [`deallocatedp::read`] can be called on different 73 | /// threads and will return the appropriate pointer for each of them. 74 | /// 75 | /// # Example 76 | /// 77 | /// ``` 78 | /// # extern crate jemallocator; 79 | /// # extern crate jemalloc_ctl; 80 | /// # 81 | /// # #[global_allocator] 82 | /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 83 | /// # 84 | /// # fn main() { 85 | /// use jemalloc_ctl::thread; 86 | /// let deallocated = thread::deallocatedp::mib().unwrap(); 87 | /// let deallocated = deallocated.read().unwrap(); 88 | /// 89 | /// let a = deallocated.get(); 90 | /// let buf = vec![0; 1024 * 1024]; 91 | /// let b = deallocated.get(); 92 | /// drop(buf); 93 | /// let c = deallocated.get(); 94 | /// 95 | /// assert_eq!(a, b); 96 | /// assert!(b < c); 97 | /// # } 98 | /// ``` 99 | mib_docs: /// See [`deallocatedp`]. 100 | } 101 | 102 | impl deallocatedp { 103 | /// Reads value using string API. 104 | pub fn read() -> Result> { 105 | unsafe { read(Self::name().as_bytes()).map(ThreadLocal) } 106 | } 107 | } 108 | 109 | impl deallocatedp_mib { 110 | /// Reads value using MIB API. 111 | pub fn read(&self) -> Result> { 112 | unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) } 113 | } 114 | } 115 | 116 | /// A thread-local pointer. 117 | /// 118 | /// It is neither `Sync` nor `Send`. 119 | // NB we need *const here specifically since it's !Sync + !Send 120 | #[repr(transparent)] 121 | #[derive(Copy, Clone)] 122 | pub struct ThreadLocal(*const T); 123 | 124 | impl ThreadLocal 125 | where 126 | T: Copy, 127 | { 128 | /// Returns the current value at the pointer. 129 | #[inline] 130 | pub fn get(self) -> T { 131 | unsafe { *self.0 } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /jemalloc-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jemalloc-sys" 3 | version = "0.3.2" 4 | authors = [ 5 | "Alex Crichton ", 6 | "Gonzalo Brito Gadeschi ", 7 | ] 8 | build = "build.rs" 9 | links = "jemalloc" 10 | license = "MIT/Apache-2.0" 11 | readme = "README.md" 12 | repository = "https://github.com/gnzlbg/jemallocator" 13 | homepage = "https://github.com/gnzlbg/jemallocator" 14 | documentation = "https://docs.rs/jemallocator-sys" 15 | keywords = ["allocator", "jemalloc"] 16 | description = """ 17 | Rust FFI bindings to jemalloc 18 | """ 19 | edition = "2015" 20 | 21 | [badges] 22 | appveyor = { repository = "gnzlbg/jemallocator" } 23 | travis-ci = { repository = "gnzlbg/jemallocator" } 24 | codecov = { repository = "gnzlbg/jemallocator" } 25 | is-it-maintained-issue-resolution = { repository = "gnzlbg/jemallocator" } 26 | is-it-maintained-open-issues = { repository = "gnzlbg/jemallocator" } 27 | maintenance = { status = "actively-developed" } 28 | 29 | [lib] 30 | test = false 31 | bench = false 32 | 33 | [dependencies] 34 | libc = { version = "^0.2.8", default-features = false } 35 | 36 | [build-dependencies] 37 | cc = "^1.0.13" 38 | fs_extra = "^1.1" 39 | 40 | [features] 41 | default = ["background_threads_runtime_support"] 42 | profiling = [] 43 | debug = [] 44 | background_threads_runtime_support = [] 45 | background_threads = [ "background_threads_runtime_support" ] 46 | stats = [] 47 | unprefixed_malloc_on_supported_platforms = [] 48 | disable_initial_exec_tls = [] 49 | 50 | [package.metadata.docs.rs] 51 | rustdoc-args = [ "--cfg", "jemallocator_docs" ] 52 | -------------------------------------------------------------------------------- /jemalloc-sys/README.md: -------------------------------------------------------------------------------- 1 | # jemalloc-sys - Rust bindings to the `jemalloc` C library 2 | 3 | [![Travis-CI Status]][travis] [![Appveyor Status]][appveyor] [![Latest Version]][crates.io] [![docs]][docs.rs] 4 | 5 | > Note: the Rust allocator API is implemented for `jemalloc` in the 6 | > [`jemallocator`](https://crates.io/crates/jemallocator) crate. 7 | 8 | ## Documentation 9 | 10 | * [Latest release (docs.rs)][docs.rs] 11 | * [master branch`][master_docs] 12 | 13 | `jemalloc` is a general purpose memory allocator, its documentation 14 | 15 | can be found here: 16 | 17 | * [API documentation][jemalloc_docs] 18 | * [Wiki][jemalloc_wiki] (design documents, presentations, profiling, debugging, tuning, ...) 19 | 20 | [jemalloc_docs]: http://jemalloc.net/jemalloc.3.html 21 | [jemalloc_wiki]: https://github.com/jemalloc/jemalloc/wiki 22 | 23 | **Current jemalloc version**: 5.1. 24 | 25 | ## Platform support 26 | 27 | See the platform support of the 28 | [`jemallocator`](https://crates.io/crates/jemallocator) crate. 29 | 30 | ## Features 31 | 32 | Most features correspond to `jemalloc` features - the reference is 33 | [`jemalloc/INSTALL.md`][jemalloc_install]. 34 | 35 | ### Cargo features 36 | 37 | This crate provides following cargo feature flags: 38 | 39 | * `profiling` (configure `jemalloc` with `--enable-prof`): Enable heap profiling 40 | and leak detection functionality. See jemalloc's "opt.prof" option 41 | documentation for usage details. When enabled, there are several approaches to 42 | backtracing, and the configure script chooses the first one in the following 43 | list that appears to function correctly: 44 | 45 | * `libunwind` (requires --enable-prof-libunwind) 46 | * `libgcc` (unless --disable-prof-libgcc) 47 | * `gcc intrinsics` (unless --disable-prof-gcc) 48 | 49 | * `stats` (configure `jemalloc` with `--enable-stats`): Enable statistics 50 | gathering functionality. See the `jemalloc`'s "`opt.stats_print`" option 51 | documentation for usage details. 52 | 53 | * `debug` (configure `jemalloc` with `--enable-debug`): Enable assertions and 54 | validation code. This incurs a substantial performance hit, but is very useful 55 | during application development. 56 | 57 | * `background_threads_runtime_support` (enabled by default): enables 58 | background-threads run-time support when building `jemalloc-sys` on some POSIX 59 | targets supported by `jemalloc`. Background threads are disabled at run-time 60 | by default. This option allows dynamically enabling them at run-time. 61 | 62 | * `background_threads` (disabled by default): enables background threads by 63 | default at run-time. When set to true, background threads are created on 64 | demand (the number of background threads will be no more than the number of 65 | CPUs or active arenas). Threads run periodically, and handle purging 66 | asynchronously. When switching off, background threads are terminated 67 | synchronously. Note that after `fork(2)` function, the state in the child 68 | process will be disabled regardless the state in parent process. See 69 | `stats.background_thread` for related stats. `opt.background_thread` can be 70 | used to set the default option. The background thread is only available on 71 | selected pthread-based platforms. 72 | 73 | * `unprefixed_malloc_on_supported_platforms`: when disabled, configure 74 | `jemalloc` with `--with-jemalloc-prefix=_rjem_`. Enabling this causes symbols 75 | like `malloc` to be emitted without a prefix, overriding the ones defined by 76 | libc. This usually causes C and C++ code linked in the same program to use 77 | `jemalloc` as well. On some platforms prefixes are always used because 78 | unprefixing is known to cause segfaults due to allocator mismatches. 79 | 80 | * `disable_initial_exec_tls` (disabled by default): when enabled, jemalloc is 81 | built with the `--disable-initial-exec-tls` option. It disables the 82 | initial-exec TLS model for jemalloc's internal thread-local storage (on those 83 | platforms that support explicit settings). This can allow jemalloc to be 84 | dynamically loaded after program startup (e.g. using dlopen). If you encounter 85 | the error `yourlib.so: cannot allocate memory in static TLS block`, you'll 86 | likely want to enable this. 87 | 88 | ### Environment variables 89 | 90 | `jemalloc` options taking values are passed via environment variables using the 91 | schema `JEMALLOC_SYS_{KEY}=VALUE` where the `KEY` names correspond to the 92 | `./configure` options of `jemalloc` where the words are capitalized and the 93 | hyphens `-` are replaced with underscores `_`(see 94 | [`jemalloc/INSTALL.md`][jemalloc_install]): 95 | 96 | * `JEMALLOC_SYS_WITH_MALLOC_CONF=`: Embed `` as a 97 | run-time options string that is processed prior to the `malloc_conf` global 98 | variable, the `/etc/malloc.conf` symlink, and the `MALLOC_CONF` environment 99 | variable (note: this variable might be prefixed as `_RJEM_MALLOC_CONF`). For 100 | example, to change the default decay time to 30 seconds: 101 | 102 | ``` 103 | JEMALLOC_SYS_WITH_MALLOC_CONF=decay_ms:30000 104 | ``` 105 | 106 | * `JEMALLOC_SYS_WITH_LG_PAGE=`: Specify the base 2 log of the allocator 107 | page size, which must in turn be at least as large as the system page size. By 108 | default the configure script determines the host's page size and sets the 109 | allocator page size equal to the system page size, so this option need not be 110 | specified unless the system page size may change between configuration and 111 | execution, e.g. when cross compiling. 112 | 113 | * `JEMALLOC_SYS_WITH_LG_HUGEPAGE=`: Specify the base 2 log of the 114 | system huge page size. This option is useful when cross compiling, or when 115 | overriding the default for systems that do not explicitly support huge pages. 116 | 117 | 118 | * `JEMALLOC_SYS_WITH_LG_QUANTUM=`: Specify the base 2 log of the 119 | minimum allocation alignment. jemalloc needs to know the minimum alignment 120 | that meets the following C standard requirement (quoted from the April 12, 121 | 2011 draft of the C11 standard): 122 | 123 | > The pointer returned if the allocation succeeds is suitably aligned so that 124 | > it may be assigned to a pointer to any type of object with a fundamental 125 | > alignment requirement and then used to access such an object or an array of 126 | > such objects in the space allocated [...] 127 | 128 | This setting is architecture-specific, and although jemalloc includes known 129 | safe values for the most commonly used modern architectures, there is a 130 | wrinkle related to GNU libc (glibc) that may impact your choice of . On most 131 | modern architectures, this mandates 16-byte alignment (=4), but the glibc 132 | developers chose not to meet this requirement for performance reasons. An old 133 | discussion can be found at https://sourceware.org/bugzilla/show_bug.cgi?id=206 134 | . Unlike glibc, jemalloc does follow the C standard by default (caveat: 135 | jemalloc technically cheats for size classes smaller than the quantum), but 136 | the fact that Linux systems already work around this allocator noncompliance 137 | means that it is generally safe in practice to let jemalloc's minimum 138 | alignment follow glibc's lead. If you specify `JEMALLOC_SYS_WITH_LG_QUANTUM=3` 139 | during configuration, jemalloc will provide additional size classes that are 140 | not 16-byte-aligned (24, 40, and 56). 141 | 142 | * `JEMALLOC_SYS_WITH_LG_VADDR=`: Specify the number of significant 143 | virtual address bits. By default, the configure script attempts to detect 144 | virtual address size on those platforms where it knows how, and picks a 145 | default otherwise. This option may be useful when cross-compiling. 146 | 147 | * `JEMALLOC_SYS_GIT_DEV_BRANCH`: when this environment variable is defined, the 148 | latest commit from `jemalloc`'s dev branch is fetched from 149 | `https://github.com/jemalloc/jemalloc` and built. 150 | 151 | [jemalloc_install]: https://github.com/jemalloc/jemalloc/blob/dev/INSTALL.md#advanced-configuration 152 | 153 | ## License 154 | 155 | This project is licensed under either of 156 | 157 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 158 | http://www.apache.org/licenses/LICENSE-2.0) 159 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 160 | http://opensource.org/licenses/MIT) 161 | 162 | at your option. 163 | 164 | ## Contribution 165 | 166 | Unless you explicitly state otherwise, any contribution intentionally submitted 167 | for inclusion in `jemalloc-sys` by you, as defined in the Apache-2.0 license, 168 | shall be dual licensed as above, without any additional terms or conditions. 169 | 170 | [travis]: https://travis-ci.org/gnzlbg/jemallocator 171 | [Travis-CI Status]: https://travis-ci.org/gnzlbg/jemallocator.svg?branch=master 172 | [appveyor]: https://ci.appveyor.com/project/gnzlbg/jemallocator/branch/master 173 | [Appveyor Status]: https://ci.appveyor.com/api/projects/status/github/gnzlbg/jemallocator?branch=master&svg=true 174 | [Latest Version]: https://img.shields.io/crates/v/jemalloc-sys.svg 175 | [crates.io]: https://crates.io/crates/jemalloc-ctl 176 | [docs]: https://docs.rs/jemalloc-sys/badge.svg 177 | [docs.rs]: https://docs.rs/jemalloc-sys/ 178 | [master_docs]: https://gnzlbg.github.io/jemallocator/jemalloc-sys 179 | -------------------------------------------------------------------------------- /jemalloc-sys/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | extern crate cc; 12 | extern crate fs_extra; 13 | 14 | use std::env; 15 | use std::fs; 16 | use std::fs::File; 17 | use std::path::{Path, PathBuf}; 18 | use std::process::Command; 19 | 20 | // `jemalloc` is known not to work on these targets: 21 | const UNSUPPORTED_TARGETS: &[&str] = &[ 22 | "rumprun", 23 | "bitrig", 24 | "emscripten", 25 | "fuchsia", 26 | "redox", 27 | "wasm32", 28 | ]; 29 | 30 | // `jemalloc-sys` is not tested on these targets in CI: 31 | const UNTESTED_TARGETS: &[&str] = &["openbsd", "msvc"]; 32 | 33 | // `jemalloc`'s background_thread support is known not to work on these targets: 34 | const NO_BG_THREAD_TARGETS: &[&str] = &["musl"]; 35 | 36 | // targets that don't support unprefixed `malloc` 37 | // 38 | // “it was found that the `realpath` function in libc would allocate with libc malloc 39 | // (not jemalloc malloc), and then the standard library would free with jemalloc free, 40 | // causing a segfault.” 41 | // https://github.com/rust-lang/rust/commit/e3b414d8612314e74e2b0ebde1ed5c6997d28e8d 42 | // https://github.com/rust-lang/rust/commit/536011d929ecbd1170baf34e09580e567c971f95 43 | // https://github.com/rust-lang/rust/commit/9f3de647326fbe50e0e283b9018ab7c41abccde3 44 | // https://github.com/rust-lang/rust/commit/ed015456a114ae907a36af80c06f81ea93182a24 45 | const NO_UNPREFIXED_MALLOC: &[&str] = &["android", "dragonfly", "musl", "darwin"]; 46 | 47 | macro_rules! info { 48 | ($($args:tt)*) => { println!($($args)*) } 49 | } 50 | 51 | macro_rules! warning { 52 | ($arg:tt, $($args:tt)*) => { 53 | println!(concat!(concat!("cargo:warning=\"", $arg), "\""), $($args)*) 54 | } 55 | } 56 | 57 | fn main() { 58 | let target = env::var("TARGET").expect("TARGET was not set"); 59 | let host = env::var("HOST").expect("HOST was not set"); 60 | let num_jobs = env::var("NUM_JOBS").expect("NUM_JOBS was not set"); 61 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR was not set")); 62 | let src_dir = env::current_dir().expect("failed to get current directory"); 63 | 64 | info!("TARGET={}", target.clone()); 65 | info!("HOST={}", host.clone()); 66 | info!("NUM_JOBS={}", num_jobs.clone()); 67 | info!("OUT_DIR={:?}", out_dir); 68 | let build_dir = out_dir.join("build"); 69 | info!("BUILD_DIR={:?}", build_dir); 70 | info!("SRC_DIR={:?}", src_dir); 71 | 72 | if UNSUPPORTED_TARGETS.iter().any(|i| target.contains(i)) { 73 | panic!("jemalloc does not support target: {}", target); 74 | } 75 | 76 | if UNTESTED_TARGETS.iter().any(|i| target.contains(i)) { 77 | warning!("jemalloc support for `{}` is untested", target); 78 | } 79 | 80 | let mut use_prefix = 81 | env::var("CARGO_FEATURE_UNPREFIXED_MALLOC_ON_SUPPORTED_PLATFORMS").is_err(); 82 | 83 | if !use_prefix && NO_UNPREFIXED_MALLOC.iter().any(|i| target.contains(i)) { 84 | warning!( 85 | "Unprefixed `malloc` requested on unsupported platform `{}` => using prefixed `malloc`", 86 | target 87 | ); 88 | use_prefix = true; 89 | } 90 | 91 | // this has to occur before the early return when JEMALLOC_OVERRIDE is set 92 | if use_prefix { 93 | println!("cargo:rustc-cfg=prefixed"); 94 | } 95 | 96 | if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") { 97 | info!("jemalloc override set"); 98 | let jemalloc = PathBuf::from(jemalloc); 99 | assert!( 100 | jemalloc.exists(), 101 | "Path to `jemalloc` in `JEMALLOC_OVERRIDE={}` does not exist", 102 | jemalloc.display() 103 | ); 104 | println!( 105 | "cargo:rustc-link-search=native={}", 106 | jemalloc.parent().unwrap().display() 107 | ); 108 | let stem = jemalloc.file_stem().unwrap().to_str().unwrap(); 109 | let name = jemalloc.file_name().unwrap().to_str().unwrap(); 110 | let kind = if name.ends_with(".a") { 111 | "static" 112 | } else { 113 | "dylib" 114 | }; 115 | println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]); 116 | return; 117 | } 118 | 119 | fs::create_dir_all(&build_dir).unwrap(); 120 | // Disable -Wextra warnings - jemalloc doesn't compile free of warnings with 121 | // it enabled: https://github.com/jemalloc/jemalloc/issues/1196 122 | let compiler = cc::Build::new().extra_warnings(false).get_compiler(); 123 | let cflags = compiler 124 | .args() 125 | .iter() 126 | .map(|s| s.to_str().unwrap()) 127 | .collect::>() 128 | .join(" "); 129 | info!("CC={:?}", compiler.path()); 130 | info!("CFLAGS={:?}", cflags); 131 | 132 | assert!(out_dir.exists(), "OUT_DIR does not exist"); 133 | let (jemalloc_repo_dir, run_autoconf) = if env::var("JEMALLOC_SYS_GIT_DEV_BRANCH").is_ok() { 134 | let jemalloc_repo = out_dir.join("jemalloc_repo"); 135 | if jemalloc_repo.exists() { 136 | fs::remove_dir_all(jemalloc_repo.clone()).unwrap(); 137 | } 138 | let mut cmd = Command::new("git"); 139 | cmd.arg("clone") 140 | .arg("--depth=1") 141 | .arg("--branch=dev") 142 | .arg("--") 143 | .arg("https://github.com/jemalloc/jemalloc") 144 | .arg(format!("{}", jemalloc_repo.display())); 145 | run(&mut cmd); 146 | (jemalloc_repo, true) 147 | } else { 148 | (PathBuf::from("jemalloc"), false) 149 | }; 150 | info!("JEMALLOC_REPO_DIR={:?}", jemalloc_repo_dir); 151 | 152 | let jemalloc_src_dir = out_dir.join("jemalloc"); 153 | info!("JEMALLOC_SRC_DIR={:?}", jemalloc_src_dir); 154 | 155 | if jemalloc_src_dir.exists() { 156 | fs::remove_dir_all(jemalloc_src_dir.clone()).unwrap(); 157 | } 158 | 159 | // Copy jemalloc submodule to the OUT_DIR 160 | let mut copy_options = fs_extra::dir::CopyOptions::new(); 161 | copy_options.overwrite = true; 162 | copy_options.copy_inside = true; 163 | fs_extra::dir::copy(&jemalloc_repo_dir, &jemalloc_src_dir, ©_options) 164 | .expect("failed to copy jemalloc source code to OUT_DIR"); 165 | assert!(jemalloc_src_dir.exists()); 166 | 167 | // Configuration files 168 | let config_files = ["configure" /*"VERSION"*/]; 169 | 170 | // Verify that the configuration files are up-to-date 171 | let verify_configure = env::var("JEMALLOC_SYS_VERIFY_CONFIGURE").is_ok(); 172 | if verify_configure || run_autoconf { 173 | info!("Verifying that configuration files in `configure/` are up-to-date... "); 174 | 175 | // The configuration file from the configure/directory should be used. 176 | // The jemalloc git submodule shouldn't contain any configuration files. 177 | assert!( 178 | !jemalloc_src_dir.join("configure").exists(), 179 | "the jemalloc submodule contains configuration files" 180 | ); 181 | 182 | // Run autoconf: 183 | let mut cmd = Command::new("autoconf"); 184 | cmd.current_dir(jemalloc_src_dir.clone()); 185 | run(&mut cmd); 186 | 187 | for f in &config_files { 188 | use std::io::Read; 189 | fn read_content(file_path: &Path) -> String { 190 | assert!( 191 | file_path.exists(), 192 | "config file path `{}` does not exist", 193 | file_path.display() 194 | ); 195 | let mut file = File::open(file_path).expect("file not found"); 196 | let mut content = String::new(); 197 | file.read_to_string(&mut content) 198 | .expect("failed to read file"); 199 | content 200 | } 201 | 202 | if verify_configure { 203 | let current = read_content(&jemalloc_src_dir.join(f)); 204 | let reference = read_content(&Path::new("configure").join(f)); 205 | assert_eq!( 206 | current, reference, 207 | "the current and reference configuration files \"{}\" differ", 208 | f 209 | ); 210 | } 211 | } 212 | } else { 213 | // Copy the configuration files to jemalloc's source directory 214 | for f in &config_files { 215 | fs::copy(Path::new("configure").join(f), jemalloc_src_dir.join(f)) 216 | .expect("failed to copy config file to OUT_DIR"); 217 | } 218 | } 219 | 220 | // Run configure: 221 | let configure = jemalloc_src_dir.join("configure"); 222 | let mut cmd = Command::new("sh"); 223 | cmd.arg( 224 | configure 225 | .to_str() 226 | .unwrap() 227 | .replace("C:\\", "/c/") 228 | .replace("\\", "/"), 229 | ) 230 | .current_dir(&build_dir) 231 | .env("CC", compiler.path()) 232 | .env("CFLAGS", cflags.clone()) 233 | .env("LDFLAGS", cflags.clone()) 234 | .env("CPPFLAGS", cflags.clone()) 235 | .arg("--disable-cxx"); 236 | 237 | if target.contains("ios") { 238 | // newer iOS deviced have 16kb page sizes: 239 | // closed: https://github.com/gnzlbg/jemallocator/issues/68 240 | cmd.arg("--with-lg-page=14"); 241 | } 242 | 243 | // collect `malloc_conf` string: 244 | let mut malloc_conf = String::new(); 245 | 246 | if let Some(bg) = BackgroundThreadSupport::new(&target) { 247 | // `jemalloc` is compiled with background thread run-time support on 248 | // available platforms by default so there is nothing to do to enable 249 | // it. 250 | 251 | if bg.always_enabled { 252 | // Background thread support does not enable background threads at 253 | // run-time, just support for enabling them via run-time configuration 254 | // options (they are disabled by default) 255 | 256 | // The `enable_background_threads` cargo feature forces background 257 | // threads to be enabled at run-time by default: 258 | malloc_conf += "background_thread:true"; 259 | } 260 | } else { 261 | // Background thread run-time support is disabled by 262 | // disabling background threads at compile-time: 263 | malloc_conf += "background_thread:false"; 264 | } 265 | 266 | if let Ok(malloc_conf_opts) = env::var("JEMALLOC_SYS_WITH_MALLOC_CONF") { 267 | malloc_conf += &format!( 268 | "{}{}", 269 | if malloc_conf.is_empty() { "" } else { "," }, 270 | malloc_conf_opts 271 | ); 272 | } 273 | 274 | if !malloc_conf.is_empty() { 275 | info!("--with-malloc-conf={}", malloc_conf); 276 | cmd.arg(format!("--with-malloc-conf={}", malloc_conf)); 277 | } 278 | 279 | if let Ok(lg_page) = env::var("JEMALLOC_SYS_WITH_LG_PAGE") { 280 | info!("--with-lg-page={}", lg_page); 281 | cmd.arg(format!("--with-lg-page={}", lg_page)); 282 | } 283 | 284 | if let Ok(lg_hugepage) = env::var("JEMALLOC_SYS_WITH_LG_HUGEPAGE") { 285 | info!("--with-lg-hugepage={}", lg_hugepage); 286 | cmd.arg(format!("--with-lg-hugepage={}", lg_hugepage)); 287 | } 288 | 289 | if let Ok(lg_quantum) = env::var("JEMALLOC_SYS_WITH_LG_QUANTUM") { 290 | info!("--with-lg-quantum={}", lg_quantum); 291 | cmd.arg(format!("--with-lg-quantum={}", lg_quantum)); 292 | } 293 | 294 | if let Ok(lg_vaddr) = env::var("JEMALLOC_SYS_WITH_LG_VADDR") { 295 | info!("--with-lg-vaddr={}", lg_vaddr); 296 | cmd.arg(format!("--with-lg-vaddr={}", lg_vaddr)); 297 | } 298 | 299 | if use_prefix { 300 | cmd.arg("--with-jemalloc-prefix=_rjem_"); 301 | info!("--with-jemalloc-prefix=_rjem_"); 302 | } 303 | 304 | cmd.arg("--with-private-namespace=_rjem_"); 305 | 306 | if env::var("CARGO_FEATURE_DEBUG").is_ok() { 307 | info!("CARGO_FEATURE_DEBUG set"); 308 | cmd.arg("--enable-debug"); 309 | } 310 | 311 | if env::var("CARGO_FEATURE_PROFILING").is_ok() { 312 | info!("CARGO_FEATURE_PROFILING set"); 313 | cmd.arg("--enable-prof"); 314 | } 315 | 316 | if env::var("CARGO_FEATURE_STATS").is_ok() { 317 | info!("CARGO_FEATURE_STATS set"); 318 | cmd.arg("--enable-stats"); 319 | } 320 | 321 | if env::var("CARGO_FEATURE_DISABLE_INITIAL_EXEC_TLS").is_ok() { 322 | info!("CARGO_FEATURE_DISABLE_INITIAL_EXEC_TLS set"); 323 | cmd.arg("--disable-initial-exec-tls"); 324 | } 325 | 326 | cmd.arg(format!("--host={}", gnu_target(&target))); 327 | cmd.arg(format!("--build={}", gnu_target(&host))); 328 | cmd.arg(format!("--prefix={}", out_dir.display())); 329 | 330 | run(&mut cmd); 331 | 332 | // Make: 333 | let make = make_cmd(&host); 334 | run(Command::new(make) 335 | .current_dir(&build_dir) 336 | .arg("srcroot=../jemalloc/") 337 | .arg("-j") 338 | .arg(num_jobs.clone())); 339 | 340 | if env::var("JEMALLOC_SYS_RUN_JEMALLOC_TESTS").is_ok() { 341 | info!("Building and running jemalloc tests..."); 342 | // Make tests: 343 | run(Command::new(make) 344 | .current_dir(&build_dir) 345 | .arg("srcroot=../jemalloc/") 346 | .arg("-j") 347 | .arg(num_jobs.clone()) 348 | .arg("tests")); 349 | 350 | // Run tests: 351 | run(Command::new(make) 352 | .current_dir(&build_dir) 353 | .arg("srcroot=../jemalloc/") 354 | .arg("check")); 355 | } 356 | 357 | // Make install: 358 | run(Command::new(make) 359 | .current_dir(&build_dir) 360 | .arg("srcroot=../jemalloc/") 361 | .arg("install_lib_static") 362 | .arg("install_include") 363 | .arg("-j") 364 | .arg(num_jobs.clone())); 365 | 366 | println!("cargo:root={}", out_dir.display()); 367 | 368 | // Linkage directives to pull in jemalloc and its dependencies. 369 | // 370 | // On some platforms we need to be sure to link in `pthread` which jemalloc 371 | // depends on, and specifically on android we need to also link to libgcc. 372 | // Currently jemalloc is compiled with gcc which will generate calls to 373 | // intrinsics that are libgcc specific (e.g. those intrinsics aren't present in 374 | // libcompiler-rt), so link that in to get that support. 375 | if target.contains("windows") { 376 | println!("cargo:rustc-link-lib=static=jemalloc"); 377 | } else { 378 | println!("cargo:rustc-link-lib=static=jemalloc_pic"); 379 | } 380 | println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); 381 | if target.contains("android") { 382 | println!("cargo:rustc-link-lib=gcc"); 383 | } else if !target.contains("windows") { 384 | println!("cargo:rustc-link-lib=pthread"); 385 | } 386 | println!("cargo:rerun-if-changed=jemalloc"); 387 | } 388 | 389 | fn run(cmd: &mut Command) { 390 | println!("running: {:?}", cmd); 391 | let status = match cmd.status() { 392 | Ok(status) => status, 393 | Err(e) => panic!("failed to execute command: {}", e), 394 | }; 395 | if !status.success() { 396 | panic!( 397 | "command did not execute successfully: {:?}\n\ 398 | expected success, got: {}", 399 | cmd, status 400 | ); 401 | } 402 | } 403 | 404 | fn gnu_target(target: &str) -> String { 405 | match target { 406 | "i686-pc-windows-msvc" => "i686-pc-win32".to_string(), 407 | "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(), 408 | "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(), 409 | "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(), 410 | "armv7-linux-androideabi" => "arm-linux-androideabi".to_string(), 411 | s => s.to_string(), 412 | } 413 | } 414 | 415 | fn make_cmd(host: &str) -> &'static str { 416 | const GMAKE_HOSTS: &[&str] = &["bitrig", "dragonfly", "freebsd", "netbsd", "openbsd"]; 417 | if GMAKE_HOSTS.iter().any(|i| host.contains(i)) { 418 | "gmake" 419 | } else if host.contains("windows") { 420 | "mingw32-make" 421 | } else { 422 | "make" 423 | } 424 | } 425 | 426 | struct BackgroundThreadSupport { 427 | always_enabled: bool, 428 | } 429 | 430 | impl BackgroundThreadSupport { 431 | fn new(target: &str) -> Option { 432 | let runtime_support = env::var("CARGO_FEATURE_BACKGROUND_THREADS_RUNTIME_SUPPORT").is_ok(); 433 | let always_enabled = env::var("CARGO_FEATURE_BACKGROUND_THREADS").is_ok(); 434 | 435 | if !runtime_support { 436 | assert!( 437 | !always_enabled, 438 | "enabling `background_threads` requires `background_threads_runtime_support`" 439 | ); 440 | return None; 441 | } 442 | 443 | if NO_BG_THREAD_TARGETS.iter().any(|i| target.contains(i)) { 444 | warning!( 445 | "`background_threads_runtime_support` not supported for `{}`", 446 | target 447 | ); 448 | } 449 | 450 | Some(Self { always_enabled }) 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /jemalloc-sys/configure/VERSION: -------------------------------------------------------------------------------- 1 | 5.1.0-0-g61efbda7098de6fe64c362d309824864308c36d4 2 | -------------------------------------------------------------------------------- /jemalloc-sys/tests/malloc_conf_empty.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_sys; 2 | 3 | #[test] 4 | fn malloc_conf_empty() { 5 | unsafe { 6 | assert!(jemalloc_sys::malloc_conf.is_none()); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /jemalloc-sys/tests/malloc_conf_set.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_sys; 2 | extern crate libc; 3 | 4 | union U { 5 | x: &'static u8, 6 | y: &'static libc::c_char, 7 | } 8 | 9 | #[allow(non_upper_case_globals)] 10 | #[cfg_attr(prefixed, export_name = "_rjem_malloc_conf")] 11 | #[cfg_attr(not(prefixed), no_mangle)] 12 | pub static malloc_conf: Option<&'static libc::c_char> = Some(unsafe { 13 | U { 14 | x: &b"stats_print_opts:mdal\0"[0], 15 | } 16 | .y 17 | }); 18 | 19 | #[test] 20 | fn malloc_conf_set() { 21 | unsafe { 22 | assert_eq!(jemalloc_sys::malloc_conf, malloc_conf); 23 | 24 | let mut ptr: *const libc::c_char = std::ptr::null(); 25 | let mut ptr_len: libc::size_t = std::mem::size_of::<*const libc::c_char>() as libc::size_t; 26 | let r = jemalloc_sys::mallctl( 27 | &b"opt.stats_print_opts\0"[0] as *const _ as *const libc::c_char, 28 | &mut ptr as *mut *const _ as *mut libc::c_void, 29 | &mut ptr_len as *mut _, 30 | std::ptr::null_mut(), 31 | 0, 32 | ); 33 | assert_eq!(r, 0); 34 | assert!(!ptr.is_null()); 35 | 36 | let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); 37 | assert!( 38 | s.contains("mdal"), 39 | "opt.stats_print_opts: \"{}\" (len = {})", 40 | s, 41 | s.len() 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jemalloc-sys/tests/unprefixed_malloc.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_sys; 2 | extern crate libc; 3 | 4 | #[cfg(prefixed)] 5 | #[test] 6 | fn malloc_is_prefixed() { 7 | assert_ne!(jemalloc_sys::malloc as usize, libc::malloc as usize) 8 | } 9 | 10 | #[cfg(not(prefixed))] 11 | #[test] 12 | fn malloc_is_overridden() { 13 | assert_eq!(jemalloc_sys::malloc as usize, libc::malloc as usize) 14 | } 15 | -------------------------------------------------------------------------------- /jemalloc-sys/update_jemalloc.md: -------------------------------------------------------------------------------- 1 | # Updating jemalloc 2 | 3 | Updating the `jemalloc` version requires generating new `configure` files, which 4 | requires `autoconf` to be installed. 5 | 6 | To generate the configuration files, go to the `jemalloc` source directory and 7 | run: 8 | 9 | ```shell 10 | autoconf 11 | ``` 12 | -------------------------------------------------------------------------------- /jemallocator-global/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jemallocator-global" 3 | # Make sure to update the version in the readme as well: 4 | version = "0.3.2" 5 | authors = ["Gonzalo Brito Gadeschi "] 6 | edition = "2015" 7 | license = "MIT/Apache-2.0" 8 | readme = "README.md" 9 | keywords = ["allocator", "jemalloc"] 10 | categories = ["memory-management", "api-bindings"] 11 | repository = "https://github.com/gnzlbg/jemallocator" 12 | homepage = "https://github.com/gnzlbg/jemallocator" 13 | documentation = "https://docs.rs/jemallocator-global" 14 | description = """ 15 | Sets `jemalloc` as the `#[global_allocator]` 16 | """ 17 | 18 | [badges] 19 | appveyor = { repository = "gnzlbg/jemallocator" } 20 | travis-ci = { repository = "gnzlbg/jemallocator" } 21 | codecov = { repository = "gnzlbg/jemallocator" } 22 | is-it-maintained-issue-resolution = { repository = "gnzlbg/jemallocator" } 23 | is-it-maintained-open-issues = { repository = "gnzlbg/jemallocator" } 24 | maintenance = { status = "actively-developed" } 25 | 26 | [dependencies] 27 | jemallocator = { version = "0.3.2", path = "..", optional = true } 28 | cfg-if = "0.1" 29 | 30 | [features] 31 | default = [] 32 | # Unconditionally sets jemalloc as the global allocator: 33 | force_global_jemalloc = [ "jemallocator" ] 34 | 35 | # To enable `jemalloc` as the `#[global_allocator]` by default 36 | # for a particular target, white-list the target explicitly here: 37 | 38 | [target.'cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] 39 | jemallocator = { version = "0.3.2", path = "..", optional = false } 40 | 41 | # FIXME: https://github.com/gnzlbg/jemallocator/issues/91 42 | # [target.'cfg(target_os = "windows")'.dependencies] 43 | # jemallocator = { path = ".." } 44 | 45 | # `jemalloc` is known not to work on - see `jemalloc-sys/build.rs`. 46 | # - rumprun 47 | # - bitrig 48 | # - redox 49 | # - fuchsia 50 | # - emscripten 51 | # - wasm32 52 | 53 | -------------------------------------------------------------------------------- /jemallocator-global/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /jemallocator-global/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Crichton 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /jemallocator-global/README.md: -------------------------------------------------------------------------------- 1 | # jemallocator-global 2 | 3 | [![Travis-CI Status]][travis] [![Appveyor Status]][appveyor] [![Latest Version]][crates.io] [![docs]][docs.rs] 4 | 5 | > Sets `jemalloc` as the `#[global allocator]` on targets that support it. 6 | 7 | ## Documentation / usage 8 | 9 | Add it as a dependency: 10 | 11 | ```toml 12 | # Cargo.toml 13 | [dependencies] 14 | jemallocator-global = "0.3.0" 15 | ``` 16 | 17 | and `jemalloc` will be used as the `#[global_allocator]` on targets that support 18 | it. 19 | 20 | ## Cargo features 21 | 22 | * `force_global_jemalloc` (disabled by default): unconditionally sets `jemalloc` 23 | as the `#[global_allocator]`. 24 | 25 | [`jemallocator`]: https://github.com/gnzlbg/jemallocator/ 26 | 27 | ## Platform support 28 | 29 | See [`jemallocator`]'s platform support. 30 | 31 | ## Documentation 32 | 33 | For more information check out the [`jemallocator`] crate. 34 | 35 | ## License 36 | 37 | This project is licensed under either of 38 | 39 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 40 | http://www.apache.org/licenses/LICENSE-2.0) 41 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 42 | http://opensource.org/licenses/MIT) 43 | 44 | at your option. 45 | 46 | ## Contribution 47 | 48 | Unless you explicitly state otherwise, any contribution intentionally submitted 49 | for inclusion in `jemallocator-global` by you, as defined in the Apache-2.0 license, 50 | shall be dual licensed as above, without any additional terms or conditions. 51 | 52 | [travis]: https://travis-ci.org/gnzlbg/jemallocator 53 | [Travis-CI Status]: https://travis-ci.org/gnzlbg/jemallocator.svg?branch=master 54 | [appveyor]: https://ci.appveyor.com/project/gnzlbg/jemallocator/branch/master 55 | [Appveyor Status]: https://ci.appveyor.com/api/projects/status/github/gnzlbg/jemallocator?branch=master&svg=true 56 | [Latest Version]: https://img.shields.io/crates/v/jemallocator-global.svg 57 | [crates.io]: https://crates.io/crates/jemallocator-global 58 | [docs]: https://docs.rs/jemallocator-global/badge.svg 59 | [docs.rs]: https://docs.rs/jemallocator-global/ 60 | 61 | -------------------------------------------------------------------------------- /jemallocator-global/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Sets `jemalloc` as the `#[global_allocator]` on targets that support it. 2 | //! 3 | //! Just add `jemallocator-global` as a dependency: 4 | //! 5 | //! ```toml 6 | //! # Cargo.toml 7 | //! [dependencies] 8 | //! jemallocator-global = "0.3.0" 9 | //! ``` 10 | //! 11 | //! and `jemalloc` will be used as the `#[global_allocator]` on targets that 12 | //! support it. 13 | //! 14 | //! To unconditionally set `jemalloc` as the `#[global_allocator]` enable the 15 | //! `force_global_jemalloc` cargo feature. 16 | 17 | #[macro_use] 18 | extern crate cfg_if; 19 | 20 | cfg_if! { 21 | if #[cfg(any( 22 | feature = "force_global_jemalloc", 23 | target_os = "linux", 24 | target_os = "android", 25 | target_os = "macos", 26 | target_os = "ios", 27 | target_os = "freebsd", 28 | target_os = "openbsd", 29 | target_os = "netbsd" 30 | ))] { 31 | extern crate jemallocator; 32 | 33 | /// Sets `jemalloc` as the `#[global_allocator]`. 34 | #[global_allocator] 35 | pub static JEMALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | // Test that jemallocator-global is enabled automatically in those targets in 42 | // which it should be enabled: 43 | 44 | macro_rules! check { 45 | () => { 46 | #[test] 47 | fn foo() { 48 | let _ = super::JEMALLOC; 49 | } 50 | }; 51 | ($os_name:tt) => { 52 | #[cfg(target_os = $os_name)] 53 | check!(); 54 | }; 55 | ($($os_name:tt),*) => { 56 | $(check!($os_name);)* 57 | } 58 | } 59 | 60 | // If the `force_global_jemalloc` feature is enabled, then it 61 | // should always be set as the global allocator: 62 | #[cfg(feature = "force_global_jemalloc")] 63 | check!(); 64 | 65 | // If the `force_global_jemalloc` feature is not enabled, then in the 66 | // following targets it should be automatically enabled anyways: 67 | #[cfg(not(feature = "force_global_jemalloc"))] 68 | check!("linux", "android", "macos", "ios", "freebsd", "netbsd", "openbsd"); 69 | } 70 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Bindings for jemalloc as an allocator 12 | //! 13 | //! This crate provides bindings to jemalloc as a memory allocator for Rust. 14 | //! This crate mainly exports, one type, `Jemalloc`, which implements the 15 | //! `GlobalAlloc` trait and optionally the `Alloc` trait, 16 | //! and is suitable both as a memory allocator and as a global allocator. 17 | 18 | #![cfg_attr(feature = "alloc_trait", feature(allocator_api))] 19 | #![deny(missing_docs, intra_doc_link_resolution_failure)] 20 | #![no_std] 21 | 22 | extern crate jemalloc_sys; 23 | extern crate libc; 24 | 25 | #[cfg(feature = "alloc_trait")] 26 | use core::alloc::{Alloc, AllocErr, CannotReallocInPlace, Excess}; 27 | use core::alloc::{GlobalAlloc, Layout}; 28 | #[cfg(feature = "alloc_trait")] 29 | use core::ptr::NonNull; 30 | 31 | use libc::{c_int, c_void}; 32 | 33 | // This constant equals _Alignof(max_align_t) and is platform-specific. It 34 | // contains the _maximum_ alignment that the memory allocations returned by the 35 | // C standard library memory allocation APIs (e.g. `malloc`) are guaranteed to 36 | // have. 37 | // 38 | // The memory allocation APIs are required to return memory that can fit any 39 | // object whose fundamental aligment is <= _Alignof(max_align_t). 40 | // 41 | // In C, there are no ZSTs, and the size of all types is a multiple of their 42 | // alignment (size >= align). So for allocations with size <= 43 | // _Alignof(max_align_t), the malloc-APIs return memory whose alignment is 44 | // either the requested size if its a power-of-two, or the next smaller 45 | // power-of-two. 46 | #[cfg(all(any( 47 | target_arch = "arm", 48 | target_arch = "mips", 49 | target_arch = "mipsel", 50 | target_arch = "powerpc" 51 | )))] 52 | const alignof_max_align_t: usize = 8; 53 | #[cfg(all(any( 54 | target_arch = "x86", 55 | target_arch = "x86_64", 56 | target_arch = "aarch64", 57 | target_arch = "powerpc64", 58 | target_arch = "powerpc64le", 59 | target_arch = "mips64", 60 | target_arch = "s390x", 61 | target_arch = "sparc64" 62 | )))] 63 | const alignof_max_align_t: usize = 16; 64 | 65 | /// If `align` is less than `_Alignof(max_align_t)`, and if the requested 66 | /// allocation `size` is larger than the alignment, we are guaranteed to get a 67 | /// suitably aligned allocation by default, without passing extra flags, and 68 | /// this function returns `0`. 69 | /// 70 | /// Otherwise, it returns the alignment flag to pass to the jemalloc APIs. 71 | fn layout_to_flags(align: usize, size: usize) -> c_int { 72 | if align <= alignof_max_align_t && align <= size { 73 | 0 74 | } else { 75 | ffi::MALLOCX_ALIGN(align) 76 | } 77 | } 78 | 79 | // Assumes a condition that always must hold. 80 | macro_rules! assume { 81 | ($e:expr) => { 82 | debug_assert!($e); 83 | if !($e) { 84 | core::hint::unreachable_unchecked(); 85 | } 86 | } 87 | } 88 | 89 | /// Handle to the jemalloc allocator 90 | /// 91 | /// This type implements the `GlobalAllocAlloc` trait, allowing usage a global allocator. 92 | /// 93 | /// When the `alloc_trait` feature of this crate is enabled, it also implements the `Alloc` trait, 94 | /// allowing usage in collections. 95 | #[derive(Copy, Clone, Default, Debug)] 96 | pub struct Jemalloc; 97 | 98 | unsafe impl GlobalAlloc for Jemalloc { 99 | #[inline] 100 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 101 | assume!(layout.size() != 0); 102 | let flags = layout_to_flags(layout.align(), layout.size()); 103 | let ptr = if flags == 0 { 104 | ffi::malloc(layout.size()) 105 | } else { 106 | ffi::mallocx(layout.size(), flags) 107 | }; 108 | ptr as *mut u8 109 | } 110 | 111 | #[inline] 112 | unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 113 | assume!(layout.size() != 0); 114 | let flags = layout_to_flags(layout.align(), layout.size()); 115 | let ptr = if flags == 0 { 116 | ffi::calloc(1, layout.size()) 117 | } else { 118 | ffi::mallocx(layout.size(), flags | ffi::MALLOCX_ZERO) 119 | }; 120 | ptr as *mut u8 121 | } 122 | 123 | #[inline] 124 | unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 125 | assume!(!ptr.is_null()) 126 | assume!(layout.size() != 0); 127 | let flags = layout_to_flags(layout.align(), layout.size()); 128 | ffi::sdallocx(ptr as *mut c_void, layout.size(), flags) 129 | } 130 | 131 | #[inline] 132 | unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 133 | assume!(layout.size() != 0); 134 | assume!(new_size != 0); 135 | let flags = layout_to_flags(layout.align(), new_size); 136 | let ptr = if flags == 0 { 137 | ffi::realloc(ptr as *mut c_void, new_size) 138 | } else { 139 | ffi::rallocx(ptr as *mut c_void, new_size, flags) 140 | }; 141 | ptr as *mut u8 142 | } 143 | } 144 | 145 | #[cfg(feature = "alloc_trait")] 146 | unsafe impl Alloc for Jemalloc { 147 | #[inline] 148 | unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { 149 | NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) 150 | } 151 | 152 | #[inline] 153 | unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { 154 | NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) 155 | } 156 | 157 | #[inline] 158 | unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { 159 | GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) 160 | } 161 | 162 | #[inline] 163 | unsafe fn realloc( 164 | &mut self, 165 | ptr: NonNull, 166 | layout: Layout, 167 | new_size: usize, 168 | ) -> Result, AllocErr> { 169 | NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) 170 | } 171 | 172 | #[inline] 173 | unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { 174 | let flags = layout_to_flags(layout.align(), layout.size()); 175 | let ptr = ffi::mallocx(layout.size(), flags); 176 | if let Some(nonnull) = NonNull::new(ptr as *mut u8) { 177 | let excess = ffi::nallocx(layout.size(), flags); 178 | Ok(Excess(nonnull, excess)) 179 | } else { 180 | Err(AllocErr) 181 | } 182 | } 183 | 184 | #[inline] 185 | unsafe fn realloc_excess( 186 | &mut self, 187 | ptr: NonNull, 188 | layout: Layout, 189 | new_size: usize, 190 | ) -> Result { 191 | let flags = layout_to_flags(layout.align(), new_size); 192 | let ptr = ffi::rallocx(ptr.cast().as_ptr(), new_size, flags); 193 | if let Some(nonnull) = NonNull::new(ptr as *mut u8) { 194 | let excess = ffi::nallocx(new_size, flags); 195 | Ok(Excess(nonnull, excess)) 196 | } else { 197 | Err(AllocErr) 198 | } 199 | } 200 | 201 | #[inline] 202 | fn usable_size(&self, layout: &Layout) -> (usize, usize) { 203 | let flags = layout_to_flags(layout.align(), layout.size()); 204 | unsafe { 205 | let max = ffi::nallocx(layout.size(), flags); 206 | (layout.size(), max) 207 | } 208 | } 209 | 210 | #[inline] 211 | unsafe fn grow_in_place( 212 | &mut self, 213 | ptr: NonNull, 214 | layout: Layout, 215 | new_size: usize, 216 | ) -> Result<(), CannotReallocInPlace> { 217 | let flags = layout_to_flags(layout.align(), new_size); 218 | let usable_size = ffi::xallocx(ptr.cast().as_ptr(), new_size, 0, flags); 219 | if usable_size >= new_size { 220 | Ok(()) 221 | } else { 222 | // `xallocx` returns a size smaller than the requested one to 223 | // indicate that the allocation could not be grown in place 224 | // 225 | // the old allocation remains unaltered 226 | Err(CannotReallocInPlace) 227 | } 228 | } 229 | 230 | #[inline] 231 | unsafe fn shrink_in_place( 232 | &mut self, 233 | ptr: NonNull, 234 | layout: Layout, 235 | new_size: usize, 236 | ) -> Result<(), CannotReallocInPlace> { 237 | if new_size == layout.size() { 238 | return Ok(()); 239 | } 240 | let flags = layout_to_flags(layout.align(), new_size); 241 | let usable_size = ffi::xallocx(ptr.cast().as_ptr(), new_size, 0, flags); 242 | 243 | if usable_size < layout.size() { 244 | // If `usable_size` is smaller than the original size, the 245 | // size-class of the allocation was shrunk to the size-class of 246 | // `new_size`, and it is safe to deallocate the allocation with 247 | // `new_size`: 248 | Ok(()) 249 | } else if usable_size == ffi::nallocx(new_size, flags) { 250 | // If the allocation was not shrunk and the size class of `new_size` 251 | // is the same as the size-class of `layout.size()`, then the 252 | // allocation can be properly deallocated using `new_size` (and also 253 | // using `layout.size()` because the allocation did not change) 254 | 255 | // note: when the allocation is not shrunk, `xallocx` returns the 256 | // usable size of the original allocation, which in this case matches 257 | // that of the requested allocation: 258 | debug_assert_eq!( 259 | ffi::nallocx(new_size, flags), 260 | ffi::nallocx(layout.size(), flags) 261 | ); 262 | Ok(()) 263 | } else { 264 | // If the allocation was not shrunk, but the size-class of 265 | // `new_size` is not the same as that of the original allocation, 266 | // then shrinking the allocation failed: 267 | Err(CannotReallocInPlace) 268 | } 269 | } 270 | } 271 | 272 | /// Return the usable size of the allocation pointed to by ptr. 273 | /// 274 | /// The return value may be larger than the size that was requested during allocation. 275 | /// This function is not a mechanism for in-place `realloc()`; 276 | /// rather it is provided solely as a tool for introspection purposes. 277 | /// Any discrepancy between the requested allocation size 278 | /// and the size reported by this function should not be depended on, 279 | /// since such behavior is entirely implementation-dependent. 280 | /// 281 | /// # Unsafety 282 | /// 283 | /// `ptr` must have been allocated by `Jemalloc` and must not have been freed yet. 284 | pub unsafe fn usable_size(ptr: *const T) -> usize { 285 | ffi::malloc_usable_size(ptr as *const c_void) 286 | } 287 | 288 | /// Raw bindings to jemalloc 289 | mod ffi { 290 | pub use jemalloc_sys::*; 291 | } 292 | -------------------------------------------------------------------------------- /systest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "systest" 3 | version = "0.1.0" 4 | authors = ["Alex Crichton "] 5 | build = "build.rs" 6 | 7 | [dependencies] 8 | jemalloc-sys = { path = "../jemalloc-sys" } 9 | libc = "0.2" 10 | 11 | [build-dependencies] 12 | ctest = "^0.2.6" 13 | -------------------------------------------------------------------------------- /systest/build.rs: -------------------------------------------------------------------------------- 1 | extern crate ctest; 2 | 3 | use std::env; 4 | use std::path::PathBuf; 5 | 6 | fn main() { 7 | let root = PathBuf::from(env::var_os("DEP_JEMALLOC_ROOT").unwrap()); 8 | 9 | let mut cfg = ctest::TestGenerator::new(); 10 | cfg.header("jemalloc/jemalloc.h") 11 | .include(root.join("include")) 12 | .cfg("prefixed", None) 13 | .fn_cname(|rust, link_name| link_name.unwrap_or(rust).to_string()) 14 | .skip_signededness(|c| c.ends_with("_t")); 15 | 16 | if cfg!(target_os = "linux") { 17 | cfg.skip_fn(|f| f == "malloc_usable_size"); 18 | } 19 | 20 | cfg.generate("../jemalloc-sys/src/lib.rs", "all.rs"); 21 | } 22 | -------------------------------------------------------------------------------- /systest/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(bad_style, improper_ctypes, dead_code, unused_imports)] 2 | 3 | extern crate jemalloc_sys; 4 | extern crate libc; 5 | 6 | use std::alloc::System; 7 | 8 | #[global_allocator] 9 | static A: System = System; 10 | 11 | use jemalloc_sys::*; 12 | use libc::{c_char, c_int, c_void}; 13 | 14 | include!(concat!(env!("OUT_DIR"), "/all.rs")); 15 | -------------------------------------------------------------------------------- /tests/background_thread_defaults.rs: -------------------------------------------------------------------------------- 1 | //! Test background threads run-time default settings. 2 | 3 | extern crate jemalloc_ctl; 4 | extern crate jemallocator; 5 | extern crate libc; 6 | 7 | use jemallocator::Jemalloc; 8 | 9 | #[global_allocator] 10 | static A: Jemalloc = Jemalloc; 11 | 12 | // Returns true if background threads are enabled. 13 | fn background_threads() -> bool { 14 | jemalloc_ctl::opt::background_thread::read().unwrap() 15 | } 16 | 17 | #[test] 18 | fn background_threads_runtime_defaults() { 19 | if !cfg!(feature = "background_threads_runtime_support") { 20 | // If the crate was compiled without background thread support, 21 | // then background threads are always disabled at run-time by default: 22 | assert_eq!(background_threads(), false); 23 | return; 24 | } 25 | 26 | if cfg!(feature = "background_threads") { 27 | // The crate was compiled with background-threads enabled by default: 28 | assert_eq!(background_threads(), true); 29 | } else { 30 | // The crate was compiled with background-threads disabled by default: 31 | assert_eq!(background_threads(), false); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/background_thread_enabled.rs: -------------------------------------------------------------------------------- 1 | //! Test enabling / disabling background threads at run-time if the 2 | //! library was compiled with background thread run-time support. 3 | #![cfg(feature = "background_threads_runtime_support")] 4 | #![cfg(not(feature = "unprefixed_malloc_on_supported_platforms"))] 5 | #![cfg(not(target_env = "musl"))] 6 | 7 | extern crate jemalloc_ctl; 8 | extern crate jemallocator; 9 | extern crate libc; 10 | 11 | use jemallocator::Jemalloc; 12 | 13 | #[global_allocator] 14 | static A: Jemalloc = Jemalloc; 15 | 16 | union U { 17 | x: &'static u8, 18 | y: &'static libc::c_char, 19 | } 20 | 21 | // Even if background threads are not enabled at run-time by default 22 | // at configuration time, this enables them. 23 | #[allow(non_upper_case_globals)] 24 | #[export_name = "_rjem_malloc_conf"] 25 | pub static malloc_conf: Option<&'static libc::c_char> = Some(unsafe { 26 | U { 27 | x: &b"background_thread:true\0"[0], 28 | } 29 | .y 30 | }); 31 | 32 | #[test] 33 | fn background_threads_enabled() { 34 | // Background threads are unconditionally enabled at run-time by default. 35 | assert_eq!(jemalloc_ctl::opt::background_thread::read().unwrap(), true); 36 | } 37 | -------------------------------------------------------------------------------- /tests/ffi.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_sys as ffi; 2 | extern crate jemallocator; 3 | extern crate libc; 4 | 5 | use std::mem; 6 | use std::ptr; 7 | 8 | use jemallocator::Jemalloc; 9 | use libc::{c_char, c_void}; 10 | 11 | #[global_allocator] 12 | static A: Jemalloc = Jemalloc; 13 | 14 | #[test] 15 | fn test_basic_alloc() { 16 | unsafe { 17 | let exp_size = ffi::nallocx(100, 0); 18 | assert!(exp_size >= 100); 19 | 20 | let mut ptr = ffi::mallocx(100, 0); 21 | assert!(!ptr.is_null()); 22 | assert_eq!(exp_size, ffi::malloc_usable_size(ptr)); 23 | ptr = ffi::rallocx(ptr, 50, 0); 24 | let size = ffi::xallocx(ptr, 30, 20, 0); 25 | assert!(size >= 50); 26 | ffi::sdallocx(ptr, 50, 0); 27 | } 28 | } 29 | 30 | #[test] 31 | fn test_mallctl() { 32 | let ptr = unsafe { ffi::mallocx(100, 0) }; 33 | let mut allocated: usize = 0; 34 | let mut val_len = mem::size_of_val(&allocated); 35 | let field = "stats.allocated\0"; 36 | let mut code; 37 | code = unsafe { 38 | ffi::mallctl( 39 | field.as_ptr() as *const _, 40 | &mut allocated as *mut _ as *mut c_void, 41 | &mut val_len, 42 | ptr::null_mut(), 43 | 0, 44 | ) 45 | }; 46 | assert_eq!(code, 0); 47 | assert!(allocated > 0); 48 | 49 | let mut mib = [0, 0]; 50 | let mut mib_len = 2; 51 | code = unsafe { 52 | ffi::mallctlnametomib(field.as_ptr() as *const _, mib.as_mut_ptr(), &mut mib_len) 53 | }; 54 | assert_eq!(code, 0); 55 | let mut allocated_by_mib = 0; 56 | let code = unsafe { 57 | ffi::mallctlbymib( 58 | mib.as_ptr(), 59 | mib_len, 60 | &mut allocated_by_mib as *mut _ as *mut c_void, 61 | &mut val_len, 62 | ptr::null_mut(), 63 | 0, 64 | ) 65 | }; 66 | assert_eq!(code, 0); 67 | assert_eq!(allocated_by_mib, allocated); 68 | 69 | unsafe { ffi::sdallocx(ptr, 100, 0) }; 70 | } 71 | 72 | #[test] 73 | fn test_stats() { 74 | struct PrintCtx { 75 | called_times: usize, 76 | } 77 | 78 | extern "C" fn write_cb(ctx: *mut c_void, _: *const c_char) { 79 | let print_ctx = unsafe { &mut *(ctx as *mut PrintCtx) }; 80 | print_ctx.called_times += 1; 81 | } 82 | 83 | let mut ctx = PrintCtx { called_times: 0 }; 84 | unsafe { 85 | ffi::malloc_stats_print( 86 | Some(write_cb), 87 | &mut ctx as *mut _ as *mut c_void, 88 | ptr::null(), 89 | ); 90 | } 91 | assert_ne!( 92 | ctx.called_times, 0, 93 | "print should be triggered at lease once." 94 | ); 95 | } 96 | -------------------------------------------------------------------------------- /tests/grow_in_place.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "alloc_trait", feature(allocator_api))] 2 | 3 | extern crate jemallocator; 4 | use jemallocator::Jemalloc; 5 | 6 | #[global_allocator] 7 | static A: Jemalloc = Jemalloc; 8 | 9 | #[test] 10 | #[cfg(feature = "alloc_trait")] 11 | fn shrink_in_place() { 12 | unsafe { 13 | use std::alloc::{Alloc, Layout}; 14 | 15 | // allocate 7 bytes which end up in the 8 byte size-class as long as 16 | // jemalloc's default size classes are used: 17 | let orig_sz = 7; 18 | let orig_l = Layout::from_size_align(orig_sz, 1).unwrap(); 19 | let ptr = Jemalloc.alloc(orig_l).unwrap(); 20 | 21 | // try to grow it in place by 1 byte - it should grow without problems: 22 | let new_sz = orig_sz + 1; 23 | assert!(Jemalloc.grow_in_place(ptr, orig_l, new_sz).is_ok()); 24 | let new_l = Layout::from_size_align(orig_sz + 1, 1).unwrap(); 25 | 26 | // trying to do it again fails because it would require moving the 27 | // allocation to a different size class which jemalloc's xallocx does not 28 | // do: 29 | let new_sz = new_sz + 1; 30 | assert!(Jemalloc.grow_in_place(ptr, new_l, new_sz).is_err()); 31 | 32 | Jemalloc.dealloc(ptr, new_l) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/malloctl.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_ctl; 2 | extern crate jemallocator; 3 | extern crate libc; 4 | 5 | use jemalloc_ctl::{Access, AsName}; 6 | use jemallocator::Jemalloc; 7 | use std::alloc::{GlobalAlloc, Layout}; 8 | 9 | #[global_allocator] 10 | static A: Jemalloc = Jemalloc; 11 | 12 | #[test] 13 | fn smoke() { 14 | let layout = Layout::from_size_align(100, 8).unwrap(); 15 | unsafe { 16 | let ptr = Jemalloc.alloc(layout.clone()); 17 | assert!(!ptr.is_null()); 18 | Jemalloc.dealloc(ptr, layout); 19 | } 20 | } 21 | 22 | #[test] 23 | fn ctl_get_set() { 24 | let epoch: u64 = "epoch\0".name().read().unwrap(); 25 | assert!(epoch > 0); 26 | "epoch\0".name().write(epoch).unwrap(); 27 | } 28 | 29 | #[test] 30 | #[should_panic] 31 | fn ctl_panic_empty_get() { 32 | let _: u64 = "".name().read().unwrap(); 33 | } 34 | 35 | #[test] 36 | #[should_panic] 37 | fn ctl_panic_empty_set() { 38 | let epoch: u64 = "epoch\0".name().read().unwrap(); 39 | "".name().write(epoch).unwrap(); 40 | } 41 | 42 | #[test] 43 | #[should_panic] 44 | fn ctl_panic_non_null_terminated_get() { 45 | let _: u64 = "epoch".name().read().unwrap(); 46 | } 47 | 48 | #[test] 49 | #[should_panic] 50 | fn ctl_panic_non_null_terminated_set() { 51 | let epoch: u64 = "epoch\0".name().read().unwrap(); 52 | "epoch".name().write(epoch).unwrap(); 53 | } 54 | -------------------------------------------------------------------------------- /tests/shrink_in_place.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "alloc_trait", feature(allocator_api))] 2 | 3 | extern crate jemallocator; 4 | 5 | use jemallocator::Jemalloc; 6 | 7 | #[global_allocator] 8 | static A: Jemalloc = Jemalloc; 9 | 10 | #[test] 11 | #[cfg(feature = "alloc_trait")] 12 | fn shrink_in_place() { 13 | unsafe { 14 | use std::alloc::{Alloc, Layout}; 15 | 16 | // allocate a "large" block of memory: 17 | let orig_sz = 10 * 4096; 18 | let orig_l = Layout::from_size_align(orig_sz, 1).unwrap(); 19 | let ptr = Jemalloc.alloc(orig_l).unwrap(); 20 | 21 | // try to shrink it in place to 1 byte - if this succeeds, 22 | // the size-class of the new allocation should be different 23 | // than that of the original allocation: 24 | let new_sz = 1; 25 | if let Ok(()) = Jemalloc.shrink_in_place(ptr, orig_l, new_sz) { 26 | // test that deallocating with the new layout succeeds: 27 | let new_l = Layout::from_size_align(new_sz, 1).unwrap(); 28 | Jemalloc.dealloc(ptr, new_l); 29 | } else { 30 | // if shrink in place failed - deallocate with the old layout 31 | Jemalloc.dealloc(ptr, orig_l); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/smoke.rs: -------------------------------------------------------------------------------- 1 | extern crate jemallocator; 2 | 3 | use jemallocator::Jemalloc; 4 | use std::alloc::{GlobalAlloc, Layout}; 5 | 6 | #[global_allocator] 7 | static A: Jemalloc = Jemalloc; 8 | 9 | #[test] 10 | fn smoke() { 11 | let mut a = Vec::new(); 12 | a.push(3); 13 | } 14 | 15 | /// https://github.com/rust-lang/rust/issues/45955 16 | #[test] 17 | fn overaligned() { 18 | let size = 8; 19 | let align = 16; // greater than size 20 | let iterations = 100; 21 | unsafe { 22 | let pointers: Vec<_> = (0..iterations) 23 | .map(|_| { 24 | let ptr = Jemalloc.alloc(Layout::from_size_align(size, align).unwrap()); 25 | assert!(!ptr.is_null()); 26 | ptr 27 | }) 28 | .collect(); 29 | for &ptr in &pointers { 30 | assert_eq!( 31 | (ptr as usize) % align, 32 | 0, 33 | "Got a pointer less aligned than requested" 34 | ) 35 | } 36 | 37 | // Clean up 38 | for &ptr in &pointers { 39 | Jemalloc.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/smoke_ffi.rs: -------------------------------------------------------------------------------- 1 | extern crate jemalloc_sys; 2 | extern crate jemallocator; 3 | 4 | // Work around https://github.com/gnzlbg/jemallocator/issues/19 5 | #[global_allocator] 6 | static A: jemallocator::Jemalloc = jemallocator::Jemalloc; 7 | 8 | #[test] 9 | fn smoke() { 10 | unsafe { 11 | let ptr = jemalloc_sys::malloc(4); 12 | *(ptr as *mut u32) = 0xDECADE; 13 | assert_eq!(*(ptr as *mut u32), 0xDECADE); 14 | jemalloc_sys::free(ptr); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/usable_size.rs: -------------------------------------------------------------------------------- 1 | extern crate jemallocator; 2 | 3 | use jemallocator::Jemalloc; 4 | 5 | #[global_allocator] 6 | static A: Jemalloc = Jemalloc; 7 | 8 | #[test] 9 | fn smoke() { 10 | let a = Box::new(3_u32); 11 | assert!(unsafe { jemallocator::usable_size(&*a) } >= 4); 12 | } 13 | --------------------------------------------------------------------------------