Import 'tikv-jemallocator' crate
Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
For Build Team: go/ab-third-party-imports
Bug: http://b/340345793
Test: m tikv_jemallocator
Change-Id: I5cbb3556434f954c1eb327f3cbdf76e77ed2c990
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..4910c12
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,26 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file after the first "rust_*" or "genrule" module
+// because the changes will be overridden on upgrade.
+// Content before the first "rust_*" or "genrule" module is preserved.
+
+package {
+ default_visibility: ["//visibility:private"],
+}
+
+rust_library_host {
+ name: "libtikv_jemallocator",
+ crate_name: "tikv_jemallocator",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.5.4",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ features: [
+ "background_threads_runtime_support",
+ "default",
+ ],
+ rustlibs: [
+ "liblibc",
+ "libtikv_jemalloc_sys",
+ ],
+ visibility: ["//external/n2:__subpackages__"],
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..9f259df
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,89 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "tikv-jemallocator"
+version = "0.5.4"
+authors = [
+ "Alex Crichton <[email protected]>",
+ "Gonzalo Brito Gadeschi <[email protected]>",
+ "Simon Sapin <[email protected]>",
+ "Steven Fackler <[email protected]>",
+ "The TiKV Project Developers",
+]
+description = """
+A Rust allocator backed by jemalloc
+"""
+homepage = "https://github.com/tikv/jemallocator"
+documentation = "https://docs.rs/jemallocator"
+readme = "README.md"
+keywords = [
+ "allocator",
+ "jemalloc",
+]
+categories = [
+ "memory-management",
+ "api-bindings",
+]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/tikv/jemallocator"
+
+[package.metadata.docs.rs]
+features = []
+rustdoc-args = [
+ "--cfg",
+ "jemallocator_docs",
+]
+
+[lib]
+test = false
+bench = false
+
+[dependencies.libc]
+version = "^0.2.8"
+default-features = false
+
+[dependencies.tikv-jemalloc-sys]
+version = "0.5.0"
+default-features = false
+
+[dev-dependencies.paste]
+version = "1"
+
+[dev-dependencies.tikv-jemalloc-ctl]
+version = "0.5.0"
+
+[features]
+alloc_trait = []
+background_threads = ["tikv-jemalloc-sys/background_threads"]
+background_threads_runtime_support = ["tikv-jemalloc-sys/background_threads_runtime_support"]
+debug = ["tikv-jemalloc-sys/debug"]
+default = ["background_threads_runtime_support"]
+disable_initial_exec_tls = ["tikv-jemalloc-sys/disable_initial_exec_tls"]
+profiling = ["tikv-jemalloc-sys/profiling"]
+stats = ["tikv-jemalloc-sys/stats"]
+unprefixed_malloc_on_supported_platforms = ["tikv-jemalloc-sys/unprefixed_malloc_on_supported_platforms"]
+
+[badges.codecov]
+repository = "tikv/jemallocator"
+
+[badges.is-it-maintained-issue-resolution]
+repository = "tikv/jemallocator"
+
+[badges.is-it-maintained-open-issues]
+repository = "tikv/jemallocator"
+
+[badges.maintenance]
+status = "actively-developed"
+
+[badges.travis-ci]
+repository = "tikv/jemallocator"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..010b99c
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,56 @@
+[package]
+name = "tikv-jemallocator"
+# Make sure to update the version in the README as well:
+version = "0.5.4"
+authors = [
+ "Alex Crichton <[email protected]>",
+ "Gonzalo Brito Gadeschi <[email protected]>",
+ "Simon Sapin <[email protected]>",
+ "Steven Fackler <[email protected]>",
+ "The TiKV Project Developers",
+]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+keywords = ["allocator", "jemalloc"]
+categories = ["memory-management", "api-bindings"]
+repository = "https://github.com/tikv/jemallocator"
+homepage = "https://github.com/tikv/jemallocator"
+documentation = "https://docs.rs/jemallocator"
+description = """
+A Rust allocator backed by jemalloc
+"""
+edition = "2018"
+
+[badges]
+travis-ci = { repository = "tikv/jemallocator" }
+codecov = { repository = "tikv/jemallocator" }
+is-it-maintained-issue-resolution = { repository = "tikv/jemallocator" }
+is-it-maintained-open-issues = { repository = "tikv/jemallocator" }
+maintenance = { status = "actively-developed" }
+
+[lib]
+test = false
+bench = false
+
+[dependencies]
+tikv-jemalloc-sys = { path = "../jemalloc-sys", version = "0.5.0", default-features = false }
+libc = { version = "^0.2.8", default-features = false }
+
+[dev-dependencies]
+paste = "1"
+tikv-jemalloc-ctl = { path = "../jemalloc-ctl", version = "0.5.0" }
+
+[features]
+default = ["background_threads_runtime_support"]
+alloc_trait = []
+profiling = ["tikv-jemalloc-sys/profiling"]
+debug = ["tikv-jemalloc-sys/debug"]
+stats = ["tikv-jemalloc-sys/stats"]
+background_threads_runtime_support = ["tikv-jemalloc-sys/background_threads_runtime_support"]
+background_threads = ["tikv-jemalloc-sys/background_threads"]
+unprefixed_malloc_on_supported_platforms = ["tikv-jemalloc-sys/unprefixed_malloc_on_supported_platforms"]
+disable_initial_exec_tls = ["tikv-jemalloc-sys/disable_initial_exec_tls"]
+
+[package.metadata.docs.rs]
+features = []
+rustdoc-args = [ "--cfg", "jemallocator_docs" ]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..39e0ed6
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..3d85c01
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,21 @@
+name: "tikv-jemallocator"
+description: "()"
+third_party {
+ identifier {
+ type: "crates.io"
+ value: "tikv-jemallocator"
+ }
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/tikv-jemallocator/tikv-jemallocator-0.5.4.crate"
+ primary_source: true
+ }
+ version: "0.5.4"
+ # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 5
+ day: 16
+ }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..083b8a3
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+include platform/prebuilts/rust:main:/OWNERS
+include platform/build/soong:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e9e13e6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,97 @@
+# tikv-jemallocator
+
+[![ci]][github actions] [![Latest Version]][crates.io] [![docs]][docs.rs]
+
+This project is the successor of [jemallocator](https://github.com/gnzlbg/jemallocator).
+
+The project is also published as `jemallocator` for historical reasons. The two crates are the same except names. For new projects, it's recommended to use `tikv-xxx` versions instead.
+
+> Links against `jemalloc` and provides a `Jemalloc` unit type that implements
+> the allocator APIs and can be set as the `#[global_allocator]`
+
+## Overview
+
+The `jemalloc` support ecosystem consists of the following crates:
+
+* `tikv-jemalloc-sys`: builds and links against `jemalloc` exposing raw C bindings to it.
+* `tikv-jemallocator`: provides the `Jemalloc` type which implements the
+ `GlobalAlloc` and `Alloc` traits.
+* `tikv-jemalloc-ctl`: high-level wrapper over `jemalloc`'s control and introspection
+ APIs (the `mallctl*()` family of functions and the _MALLCTL NAMESPACE_)'
+
+## Documentation
+
+* [Latest release (docs.rs)][docs.rs]
+
+To use `tikv-jemallocator` add it as a dependency:
+
+```toml
+# Cargo.toml
+[dependencies]
+
+[target.'cfg(not(target_env = "msvc"))'.dependencies]
+tikv-jemallocator = "0.5"
+```
+
+To set `tikv_jemallocator::Jemalloc` as the global allocator add this to your project:
+
+```rust
+# main.rs
+#[cfg(not(target_env = "msvc"))]
+use tikv_jemallocator::Jemalloc;
+
+#[cfg(not(target_env = "msvc"))]
+#[global_allocator]
+static GLOBAL: Jemalloc = Jemalloc;
+```
+
+And that's it! Once you've defined this `static` then jemalloc will be used for
+all allocations requested by Rust code in the same program.
+
+## Platform support
+
+The following table describes the supported platforms:
+
+* `build`: does the library compile for the target?
+* `run`: do `tikv-jemallocator` and `tikv-jemalloc-sys` tests pass on the target?
+* `jemalloc`: do `tikv-jemalloc`'s tests pass on the target?
+
+Tier 1 targets are tested on all Rust channels (stable, beta, and nightly). All
+other targets are only tested on Rust nightly.
+
+| Linux targets: | build | run | jemalloc |
+|-------------------------------------|-----------|---------|--------------|
+| `aarch64-unknown-linux-gnu` | ✓ | ✓ | ✗ |
+| `powerpc64le-unknown-linux-gnu` | ✓ | ✓ | ✗ |
+| `x86_64-unknown-linux-gnu` (tier 1) | ✓ | ✓ | ✓ |
+| **MacOSX targets:** | **build** | **run** | **jemalloc** |
+| `x86_64-apple-darwin` (tier 1) | ✓ | ✓ | ✗ |
+
+## Features
+
+The `tikv-jemallocator` crate re-exports the [features of the `tikv-jemalloc-sys`
+dependency](https://github.com/tikv/jemallocator/blob/master/jemalloc-sys/README.md).
+
+## License
+
+This project is licensed under either of
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
+ http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or
+ http://opensource.org/licenses/MIT)
+
+at your option.
+
+## Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in `tikv-jemallocator` by you, as defined in the Apache-2.0 license,
+shall be dual licensed as above, without any additional terms or conditions.
+
+[Latest Version]: https://img.shields.io/crates/v/tikv-jemallocator.svg
+[crates.io]: https://crates.io/crates/tikv-jemallocator
+[docs]: https://docs.rs/tikv-jemallocator/badge.svg
+[docs.rs]: https://docs.rs/tikv-jemallocator/
+[ci]: https://github.com/tikv/jemallocator/actions/workflows/main.yml/badge.svg
+[github actions]: https://github.com/tikv/jemallocator/actions
diff --git a/benches/roundtrip.rs b/benches/roundtrip.rs
new file mode 100644
index 0000000..30f7bf4
--- /dev/null
+++ b/benches/roundtrip.rs
@@ -0,0 +1,253 @@
+//! Benchmarks the cost of the different allocation functions by doing a
+//! roundtrip (allocate, deallocate).
+#![feature(test, allocator_api)]
+#![cfg(feature = "alloc_trait")]
+
+extern crate test;
+
+use jemallocator::Jemalloc;
+use libc::c_int;
+use std::{
+ alloc::{Alloc, Excess, Layout},
+ ptr,
+};
+use test::Bencher;
+use tikv_jemalloc_sys::MALLOCX_ALIGN;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+// FIXME: replace with jemallocator::layout_to_flags
+#[cfg(all(any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mipsel",
+ target_arch = "powerpc"
+)))]
+const MIN_ALIGN: usize = 8;
+#[cfg(all(any(
+ target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "powerpc64",
+ target_arch = "powerpc64le",
+ target_arch = "loongarch64",
+ target_arch = "mips64",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "sparc64"
+)))]
+const MIN_ALIGN: usize = 16;
+
+fn layout_to_flags(layout: &Layout) -> c_int {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ 0
+ } else {
+ MALLOCX_ALIGN(layout.align())
+ }
+}
+
+macro_rules! rt {
+ ($size:expr, $align:expr) => {
+ paste::paste! {
+ #[bench]
+ fn [<rt_mallocx_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ use jemalloc_sys as jemalloc;
+ let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
+ let ptr = jemalloc::mallocx($size, flags);
+ test::black_box(ptr);
+ jemalloc::sdallocx(ptr, $size, flags);
+ });
+ }
+
+ #[bench]
+ fn [<rt_mallocx_nallocx_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ use jemalloc_sys as jemalloc;
+ let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
+ let ptr = jemalloc::mallocx($size, flags);
+ test::black_box(ptr);
+ let rsz = jemalloc::nallocx($size, flags);
+ test::black_box(rsz);
+ jemalloc::sdallocx(ptr, rsz, flags);
+ });
+ }
+
+ #[bench]
+ fn [<rt_alloc_layout_checked_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+ Jemalloc.dealloc(ptr, layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_alloc_layout_unchecked_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align_unchecked($size, $align);
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+ Jemalloc.dealloc(ptr, layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_alloc_excess_unused_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let Excess(ptr, _) = Jemalloc.alloc_excess(layout.clone()).unwrap();
+ test::black_box(ptr);
+ Jemalloc.dealloc(ptr, layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_alloc_excess_used_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let Excess(ptr, excess) = Jemalloc.alloc_excess(layout.clone()).unwrap();
+ test::black_box(ptr);
+ test::black_box(excess);
+ Jemalloc.dealloc(ptr, layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_mallocx_zeroed_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ use jemalloc_sys as jemalloc;
+ let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
+ let ptr = jemalloc::mallocx($size, flags | jemalloc::MALLOCX_ZERO);
+ test::black_box(ptr);
+ jemalloc::sdallocx(ptr, $size, flags);
+ });
+ }
+
+ #[bench]
+ fn [<rt_calloc_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ use jemalloc_sys as jemalloc;
+ let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
+ test::black_box(flags);
+ let ptr = jemalloc::calloc(1, $size);
+ test::black_box(ptr);
+ jemalloc::sdallocx(ptr, $size, 0);
+ });
+ }
+
+ #[bench]
+ fn [<rt_realloc_naive_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+
+ // navie realloc:
+ let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
+ let ptr = {
+ let new_ptr = Jemalloc.alloc(new_layout.clone()).unwrap();
+ ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, new_ptr.as_ptr(), layout.size());
+ Jemalloc.dealloc(ptr, layout);
+ new_ptr
+ };
+ test::black_box(ptr);
+
+ Jemalloc.dealloc(ptr, new_layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_realloc_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+
+ let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
+ let ptr = Jemalloc.realloc(ptr, layout, new_layout.size()).unwrap();
+ test::black_box(ptr);
+
+ Jemalloc.dealloc(ptr, new_layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_realloc_excess_unused_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+
+ let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
+ let Excess(ptr, _) = Jemalloc
+ .realloc_excess(ptr, layout, new_layout.size())
+ .unwrap();
+ test::black_box(ptr);
+
+ Jemalloc.dealloc(ptr, new_layout);
+ });
+ }
+
+ #[bench]
+ fn [<rt_realloc_excess_used_size_ $size _align_ $align>](b: &mut Bencher) {
+ b.iter(|| unsafe {
+ let layout = Layout::from_size_align($size, $align).unwrap();
+ let ptr = Jemalloc.alloc(layout.clone()).unwrap();
+ test::black_box(ptr);
+
+ let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
+ let Excess(ptr, excess) = Jemalloc
+ .realloc_excess(ptr, layout, new_layout.size())
+ .unwrap();
+ test::black_box(ptr);
+ test::black_box(excess);
+
+ Jemalloc.dealloc(ptr, new_layout);
+ });
+ }
+
+ }
+ };
+ ([$($size:expr),*]) => {
+ $(
+ rt!($size, 1);
+ rt!($size, 2);
+ rt!($size, 4);
+ rt!($size, 8);
+ rt!($size, 16);
+ rt!($size, 32);
+ )*
+ }
+}
+
+// Powers of two
+mod pow2 {
+ use super::*;
+
+ rt!([
+ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072,
+ 4194304
+ ]);
+}
+
+mod even {
+ use super::*;
+
+ rt!([10, 100, 1000, 10000, 100000, 1000000]);
+}
+
+mod odd {
+ use super::*;
+ rt!([9, 99, 999, 9999, 99999, 999999]);
+}
+
+mod primes {
+ use super::*;
+ rt!([
+ 3, 7, 13, 17, 31, 61, 96, 127, 257, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65537,
+ 131071, 4194301
+ ]);
+}
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..bd465d2
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,14 @@
+{
+ "package": {
+ "tikv-jemallocator": {
+ "device_supported": false
+ }
+ },
+ "module_visibility": {
+ "libtikv_jemallocator": [
+ "//external/n2:__subpackages__"
+ ]
+ },
+ "run_cargo": false,
+ "tests": false
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..165660e
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,292 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Bindings for jemalloc as an allocator
+//!
+//! This crate provides bindings to jemalloc as a memory allocator for Rust.
+//! This crate mainly exports, one type, `Jemalloc`, which implements the
+//! `GlobalAlloc` trait and optionally the `Alloc` trait,
+//! and is suitable both as a memory allocator and as a global allocator.
+
+#![cfg_attr(feature = "alloc_trait", feature(allocator_api))]
+// TODO: rename the following lint on next minor bump
+#![allow(renamed_and_removed_lints)]
+#![deny(missing_docs, broken_intra_doc_links)]
+#![no_std]
+
+#[cfg(feature = "alloc_trait")]
+use core::alloc::{Alloc, AllocErr, CannotReallocInPlace, Excess};
+use core::alloc::{GlobalAlloc, Layout};
+#[cfg(feature = "alloc_trait")]
+use core::ptr::NonNull;
+
+use libc::{c_int, c_void};
+
+// This constant equals _Alignof(max_align_t) and is platform-specific. It
+// contains the _maximum_ alignment that the memory allocations returned by the
+// C standard library memory allocation APIs (e.g. `malloc`) are guaranteed to
+// have.
+//
+// The memory allocation APIs are required to return memory that can fit any
+// object whose fundamental aligment is <= _Alignof(max_align_t).
+//
+// In C, there are no ZSTs, and the size of all types is a multiple of their
+// alignment (size >= align). So for allocations with size <=
+// _Alignof(max_align_t), the malloc-APIs return memory whose alignment is
+// either the requested size if its a power-of-two, or the next smaller
+// power-of-two.
+#[cfg(any(
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mipsel",
+ target_arch = "powerpc"
+))]
+const ALIGNOF_MAX_ALIGN_T: usize = 8;
+#[cfg(any(
+ target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "powerpc64",
+ target_arch = "powerpc64le",
+ target_arch = "loongarch64",
+ target_arch = "mips64",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "sparc64"
+))]
+const ALIGNOF_MAX_ALIGN_T: usize = 16;
+
+/// If `align` is less than `_Alignof(max_align_t)`, and if the requested
+/// allocation `size` is larger than the alignment, we are guaranteed to get a
+/// suitably aligned allocation by default, without passing extra flags, and
+/// this function returns `0`.
+///
+/// Otherwise, it returns the alignment flag to pass to the jemalloc APIs.
+fn layout_to_flags(align: usize, size: usize) -> c_int {
+ if align <= ALIGNOF_MAX_ALIGN_T && align <= size {
+ 0
+ } else {
+ ffi::MALLOCX_ALIGN(align)
+ }
+}
+
+// Assumes a condition that always must hold.
+macro_rules! assume {
+ ($e:expr) => {
+ debug_assert!($e);
+ if !($e) {
+ core::hint::unreachable_unchecked();
+ }
+ };
+}
+
+/// Handle to the jemalloc allocator
+///
+/// This type implements the `GlobalAllocAlloc` trait, allowing usage a global allocator.
+///
+/// When the `alloc_trait` feature of this crate is enabled, it also implements the `Alloc` trait,
+/// allowing usage in collections.
+#[derive(Copy, Clone, Default, Debug)]
+pub struct Jemalloc;
+
+unsafe impl GlobalAlloc for Jemalloc {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ assume!(layout.size() != 0);
+ let flags = layout_to_flags(layout.align(), layout.size());
+ let ptr = if flags == 0 {
+ ffi::malloc(layout.size())
+ } else {
+ ffi::mallocx(layout.size(), flags)
+ };
+ ptr as *mut u8
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ assume!(layout.size() != 0);
+ let flags = layout_to_flags(layout.align(), layout.size());
+ let ptr = if flags == 0 {
+ ffi::calloc(1, layout.size())
+ } else {
+ ffi::mallocx(layout.size(), flags | ffi::MALLOCX_ZERO)
+ };
+ ptr as *mut u8
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ assume!(!ptr.is_null());
+ assume!(layout.size() != 0);
+ let flags = layout_to_flags(layout.align(), layout.size());
+ ffi::sdallocx(ptr as *mut c_void, layout.size(), flags)
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ assume!(layout.size() != 0);
+ assume!(new_size != 0);
+ let flags = layout_to_flags(layout.align(), new_size);
+ let ptr = if flags == 0 {
+ ffi::realloc(ptr as *mut c_void, new_size)
+ } else {
+ ffi::rallocx(ptr as *mut c_void, new_size, flags)
+ };
+ ptr as *mut u8
+ }
+}
+
+#[cfg(feature = "alloc_trait")]
+unsafe impl Alloc for Jemalloc {
+ #[inline]
+ unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
+ GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+ }
+
+ #[inline]
+ unsafe fn realloc(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+ let flags = layout_to_flags(layout.align(), layout.size());
+ let ptr = ffi::mallocx(layout.size(), flags);
+ if let Some(nonnull) = NonNull::new(ptr as *mut u8) {
+ let excess = ffi::nallocx(layout.size(), flags);
+ Ok(Excess(nonnull, excess))
+ } else {
+ Err(AllocErr)
+ }
+ }
+
+ #[inline]
+ unsafe fn realloc_excess(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<Excess, AllocErr> {
+ let flags = layout_to_flags(layout.align(), new_size);
+ let ptr = ffi::rallocx(ptr.cast().as_ptr(), new_size, flags);
+ if let Some(nonnull) = NonNull::new(ptr as *mut u8) {
+ let excess = ffi::nallocx(new_size, flags);
+ Ok(Excess(nonnull, excess))
+ } else {
+ Err(AllocErr)
+ }
+ }
+
+ #[inline]
+ fn usable_size(&self, layout: &Layout) -> (usize, usize) {
+ let flags = layout_to_flags(layout.align(), layout.size());
+ unsafe {
+ let max = ffi::nallocx(layout.size(), flags);
+ (layout.size(), max)
+ }
+ }
+
+ #[inline]
+ unsafe fn grow_in_place(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<(), CannotReallocInPlace> {
+ let flags = layout_to_flags(layout.align(), new_size);
+ let usable_size = ffi::xallocx(ptr.cast().as_ptr(), new_size, 0, flags);
+ if usable_size >= new_size {
+ Ok(())
+ } else {
+ // `xallocx` returns a size smaller than the requested one to
+ // indicate that the allocation could not be grown in place
+ //
+ // the old allocation remains unaltered
+ Err(CannotReallocInPlace)
+ }
+ }
+
+ #[inline]
+ unsafe fn shrink_in_place(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<(), CannotReallocInPlace> {
+ if new_size == layout.size() {
+ return Ok(());
+ }
+ let flags = layout_to_flags(layout.align(), new_size);
+ let usable_size = ffi::xallocx(ptr.cast().as_ptr(), new_size, 0, flags);
+
+ if usable_size < layout.size() {
+ // If `usable_size` is smaller than the original size, the
+ // size-class of the allocation was shrunk to the size-class of
+ // `new_size`, and it is safe to deallocate the allocation with
+ // `new_size`:
+ Ok(())
+ } else if usable_size == ffi::nallocx(new_size, flags) {
+ // If the allocation was not shrunk and the size class of `new_size`
+ // is the same as the size-class of `layout.size()`, then the
+ // allocation can be properly deallocated using `new_size` (and also
+ // using `layout.size()` because the allocation did not change)
+
+ // note: when the allocation is not shrunk, `xallocx` returns the
+ // usable size of the original allocation, which in this case matches
+ // that of the requested allocation:
+ debug_assert_eq!(
+ ffi::nallocx(new_size, flags),
+ ffi::nallocx(layout.size(), flags)
+ );
+ Ok(())
+ } else {
+ // If the allocation was not shrunk, but the size-class of
+ // `new_size` is not the same as that of the original allocation,
+ // then shrinking the allocation failed:
+ Err(CannotReallocInPlace)
+ }
+ }
+}
+
+/// Return the usable size of the allocation pointed to by ptr.
+///
+/// The return value may be larger than the size that was requested during allocation.
+/// This function is not a mechanism for in-place `realloc()`;
+/// rather it is provided solely as a tool for introspection purposes.
+/// Any discrepancy between the requested allocation size
+/// and the size reported by this function should not be depended on,
+/// since such behavior is entirely implementation-dependent.
+///
+/// # Safety
+///
+/// `ptr` must have been allocated by `Jemalloc` and must not have been freed yet.
+pub unsafe fn usable_size<T>(ptr: *const T) -> usize {
+ ffi::malloc_usable_size(ptr as *const c_void)
+}
+
+/// Raw bindings to jemalloc
+mod ffi {
+ pub use tikv_jemalloc_sys::*;
+}
diff --git a/tests/background_thread_defaults.rs b/tests/background_thread_defaults.rs
new file mode 100644
index 0000000..0fa7798
--- /dev/null
+++ b/tests/background_thread_defaults.rs
@@ -0,0 +1,23 @@
+//! Test background threads run-time default settings.
+
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+// Returns true if background threads are enabled.
+fn background_threads() -> bool {
+ tikv_jemalloc_ctl::opt::background_thread::read().unwrap()
+}
+
+#[test]
+fn background_threads_runtime_defaults() {
+ if !cfg!(feature = "background_threads_runtime_support") {
+ // If the crate was compiled without background thread support,
+ // then background threads are always disabled at run-time by default:
+ assert!(!background_threads());
+ return;
+ }
+
+ assert_eq!(background_threads(), cfg!(feature = "background_threads"));
+}
diff --git a/tests/background_thread_enabled.rs b/tests/background_thread_enabled.rs
new file mode 100644
index 0000000..76d286d
--- /dev/null
+++ b/tests/background_thread_enabled.rs
@@ -0,0 +1,32 @@
+//! Test enabling / disabling background threads at run-time if the
+//! library was compiled with background thread run-time support.
+#![cfg(feature = "background_threads_runtime_support")]
+#![cfg(not(feature = "unprefixed_malloc_on_supported_platforms"))]
+#![cfg(not(target_env = "musl"))]
+
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+union U {
+ x: &'static u8,
+ y: &'static libc::c_char,
+}
+
+// Even if background threads are not enabled at run-time by default
+// at configuration time, this enables them.
+#[allow(non_upper_case_globals)]
+#[export_name = "_rjem_malloc_conf"]
+pub static malloc_conf: Option<&'static libc::c_char> = Some(unsafe {
+ U {
+ x: &b"background_thread:true\0"[0],
+ }
+ .y
+});
+
+#[test]
+fn background_threads_enabled() {
+ // Background threads are unconditionally enabled at run-time by default.
+ assert!(tikv_jemalloc_ctl::opt::background_thread::read().unwrap(),);
+}
diff --git a/tests/ffi.rs b/tests/ffi.rs
new file mode 100644
index 0000000..8269370
--- /dev/null
+++ b/tests/ffi.rs
@@ -0,0 +1,93 @@
+extern crate tikv_jemalloc_sys as ffi;
+
+use std::mem;
+use std::ptr;
+
+use libc::{c_char, c_void};
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+fn test_basic_alloc() {
+ unsafe {
+ let exp_size = ffi::nallocx(100, 0);
+ assert!(exp_size >= 100);
+
+ let mut ptr = ffi::mallocx(100, 0);
+ assert!(!ptr.is_null());
+ assert_eq!(exp_size, ffi::malloc_usable_size(ptr));
+ ptr = ffi::rallocx(ptr, 50, 0);
+ let size = ffi::xallocx(ptr, 30, 20, 0);
+ assert!(size >= 50);
+ ffi::sdallocx(ptr, 50, 0);
+ }
+}
+
+#[test]
+fn test_mallctl() {
+ let ptr = unsafe { ffi::mallocx(100, 0) };
+ let mut allocated: usize = 0;
+ let mut val_len = mem::size_of_val(&allocated);
+ let field = "stats.allocated\0";
+ let mut code;
+ code = unsafe {
+ ffi::mallctl(
+ field.as_ptr() as *const _,
+ &mut allocated as *mut _ as *mut c_void,
+ &mut val_len,
+ ptr::null_mut(),
+ 0,
+ )
+ };
+ assert_eq!(code, 0);
+ assert!(allocated > 0);
+
+ let mut mib = [0, 0];
+ let mut mib_len = 2;
+ code = unsafe {
+ ffi::mallctlnametomib(field.as_ptr() as *const _, mib.as_mut_ptr(), &mut mib_len)
+ };
+ assert_eq!(code, 0);
+ let mut allocated_by_mib = 0;
+ let code = unsafe {
+ ffi::mallctlbymib(
+ mib.as_ptr(),
+ mib_len,
+ &mut allocated_by_mib as *mut _ as *mut c_void,
+ &mut val_len,
+ ptr::null_mut(),
+ 0,
+ )
+ };
+ assert_eq!(code, 0);
+ assert_eq!(allocated_by_mib, allocated);
+
+ unsafe { ffi::sdallocx(ptr, 100, 0) };
+}
+
+#[test]
+fn test_stats() {
+ struct PrintCtx {
+ called_times: usize,
+ }
+
+ extern "C" fn write_cb(ctx: *mut c_void, _: *const c_char) {
+ let print_ctx = unsafe { &mut *(ctx as *mut PrintCtx) };
+ print_ctx.called_times += 1;
+ }
+
+ let mut ctx = PrintCtx { called_times: 0 };
+ unsafe {
+ ffi::malloc_stats_print(
+ Some(write_cb),
+ &mut ctx as *mut _ as *mut c_void,
+ ptr::null(),
+ );
+ }
+ assert_ne!(
+ ctx.called_times, 0,
+ "print should be triggered at lease once."
+ );
+}
diff --git a/tests/grow_in_place.rs b/tests/grow_in_place.rs
new file mode 100644
index 0000000..ca245e2
--- /dev/null
+++ b/tests/grow_in_place.rs
@@ -0,0 +1,33 @@
+#![cfg_attr(feature = "alloc_trait", feature(allocator_api))]
+
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+#[cfg(feature = "alloc_trait")]
+fn shrink_in_place() {
+ unsafe {
+ use std::alloc::{Alloc, Layout};
+
+ // allocate 7 bytes which end up in the 8 byte size-class as long as
+ // jemalloc's default size classes are used:
+ let orig_sz = 7;
+ let orig_l = Layout::from_size_align(orig_sz, 1).unwrap();
+ let ptr = Jemalloc.alloc(orig_l).unwrap();
+
+ // try to grow it in place by 1 byte - it should grow without problems:
+ let new_sz = orig_sz + 1;
+ assert!(Jemalloc.grow_in_place(ptr, orig_l, new_sz).is_ok());
+ let new_l = Layout::from_size_align(orig_sz + 1, 1).unwrap();
+
+ // trying to do it again fails because it would require moving the
+ // allocation to a different size class which jemalloc's xallocx does not
+ // do:
+ let new_sz = new_sz + 1;
+ assert!(Jemalloc.grow_in_place(ptr, new_l, new_sz).is_err());
+
+ Jemalloc.dealloc(ptr, new_l)
+ }
+}
diff --git a/tests/malloctl.rs b/tests/malloctl.rs
new file mode 100644
index 0000000..155608b
--- /dev/null
+++ b/tests/malloctl.rs
@@ -0,0 +1,49 @@
+use std::alloc::{GlobalAlloc, Layout};
+use tikv_jemalloc_ctl::{Access, AsName};
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+fn smoke() {
+ let layout = Layout::from_size_align(100, 8).unwrap();
+ unsafe {
+ let ptr = Jemalloc.alloc(layout);
+ assert!(!ptr.is_null());
+ Jemalloc.dealloc(ptr, layout);
+ }
+}
+
+#[test]
+fn ctl_get_set() {
+ let epoch: u64 = "epoch\0".name().read().unwrap();
+ assert!(epoch > 0);
+ "epoch\0".name().write(epoch).unwrap();
+}
+
+#[test]
+#[should_panic]
+fn ctl_panic_empty_get() {
+ let _: u64 = "".name().read().unwrap();
+}
+
+#[test]
+#[should_panic]
+fn ctl_panic_empty_set() {
+ let epoch: u64 = "epoch\0".name().read().unwrap();
+ "".name().write(epoch).unwrap();
+}
+
+#[test]
+#[should_panic]
+fn ctl_panic_non_null_terminated_get() {
+ let _: u64 = "epoch".name().read().unwrap();
+}
+
+#[test]
+#[should_panic]
+fn ctl_panic_non_null_terminated_set() {
+ let epoch: u64 = "epoch\0".name().read().unwrap();
+ "epoch".name().write(epoch).unwrap();
+}
diff --git a/tests/shrink_in_place.rs b/tests/shrink_in_place.rs
new file mode 100644
index 0000000..ae43268
--- /dev/null
+++ b/tests/shrink_in_place.rs
@@ -0,0 +1,32 @@
+#![cfg_attr(feature = "alloc_trait", feature(allocator_api))]
+
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+#[cfg(feature = "alloc_trait")]
+fn shrink_in_place() {
+ unsafe {
+ use std::alloc::{Alloc, Layout};
+
+ // allocate a "large" block of memory:
+ let orig_sz = 10 * 4096;
+ let orig_l = Layout::from_size_align(orig_sz, 1).unwrap();
+ let ptr = Jemalloc.alloc(orig_l).unwrap();
+
+ // try to shrink it in place to 1 byte - if this succeeds,
+ // the size-class of the new allocation should be different
+ // than that of the original allocation:
+ let new_sz = 1;
+ if let Ok(()) = Jemalloc.shrink_in_place(ptr, orig_l, new_sz) {
+ // test that deallocating with the new layout succeeds:
+ let new_l = Layout::from_size_align(new_sz, 1).unwrap();
+ Jemalloc.dealloc(ptr, new_l);
+ } else {
+ // if shrink in place failed - deallocate with the old layout
+ Jemalloc.dealloc(ptr, orig_l);
+ }
+ }
+}
diff --git a/tests/smoke.rs b/tests/smoke.rs
new file mode 100644
index 0000000..69b8c42
--- /dev/null
+++ b/tests/smoke.rs
@@ -0,0 +1,41 @@
+use std::alloc::{GlobalAlloc, Layout};
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+fn smoke() {
+ let mut a = Vec::new();
+ a.reserve(1);
+ a.push(3);
+}
+
+/// https://github.com/rust-lang/rust/issues/45955
+#[test]
+fn overaligned() {
+ let size = 8;
+ let align = 16; // greater than size
+ let iterations = 100;
+ unsafe {
+ let pointers: Vec<_> = (0..iterations)
+ .map(|_| {
+ let ptr = Jemalloc.alloc(Layout::from_size_align(size, align).unwrap());
+ assert!(!ptr.is_null());
+ ptr
+ })
+ .collect();
+ for &ptr in &pointers {
+ assert_eq!(
+ (ptr as usize) % align,
+ 0,
+ "Got a pointer less aligned than requested"
+ )
+ }
+
+ // Clean up
+ for &ptr in &pointers {
+ Jemalloc.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
+ }
+ }
+}
diff --git a/tests/smoke_ffi.rs b/tests/smoke_ffi.rs
new file mode 100644
index 0000000..311ce34
--- /dev/null
+++ b/tests/smoke_ffi.rs
@@ -0,0 +1,13 @@
+// Work around https://github.com/gnzlbg/jemallocator/issues/19
+#[global_allocator]
+static A: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
+
+#[test]
+fn smoke() {
+ unsafe {
+ let ptr = tikv_jemalloc_sys::malloc(4);
+ *(ptr as *mut u32) = 0xDECADE;
+ assert_eq!(*(ptr as *mut u32), 0xDECADE);
+ tikv_jemalloc_sys::free(ptr);
+ }
+}
diff --git a/tests/usable_size.rs b/tests/usable_size.rs
new file mode 100644
index 0000000..2aa15de
--- /dev/null
+++ b/tests/usable_size.rs
@@ -0,0 +1,10 @@
+use tikv_jemallocator::Jemalloc;
+
+#[global_allocator]
+static A: Jemalloc = Jemalloc;
+
+#[test]
+fn smoke() {
+ let a = Box::new(3_u32);
+ assert!(unsafe { tikv_jemallocator::usable_size(&*a) } >= 4);
+}