diff options
Diffstat (limited to 'vendor/countme')
-rw-r--r-- | vendor/countme/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/countme/Cargo.lock | 168 | ||||
-rw-r--r-- | vendor/countme/Cargo.toml | 48 | ||||
-rw-r--r-- | vendor/countme/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/countme/LICENSE-MIT | 23 | ||||
-rw-r--r-- | vendor/countme/README.md | 21 | ||||
-rw-r--r-- | vendor/countme/examples/bench.rs | 69 | ||||
-rw-r--r-- | vendor/countme/examples/bench_single_thread.rs | 77 | ||||
-rw-r--r-- | vendor/countme/examples/print_at_exit.rs | 11 | ||||
-rw-r--r-- | vendor/countme/src/imp.rs | 175 | ||||
-rw-r--r-- | vendor/countme/src/lib.rs | 193 |
11 files changed, 987 insertions, 0 deletions
diff --git a/vendor/countme/.cargo-checksum.json b/vendor/countme/.cargo-checksum.json new file mode 100644 index 000000000..21af6b7a5 --- /dev/null +++ b/vendor/countme/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"4101e28468b7a3c7a051247ff0d55ea1f2ba58e303857a7a4d3bbaef5caf31cc","Cargo.toml":"5ba3effabbc65115689252c397fb98adb04ac0174819612ecc4e754cea3acf1b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8a8a5d00072b2f1c99a47b50e45cd2604485d1ce1b242eb7dd2895d4c8ca8625","examples/bench.rs":"a081e78268bdfd452840aa23d607bdfac0f57197ca6af35a5832e888fa59ddd2","examples/bench_single_thread.rs":"3e39d60ccb10cbd2905eaa154592af7024c690432f62f09b8211f9d601b39ab0","examples/print_at_exit.rs":"86ace893845110a7035a6aaab71c43640729f374a4be8224e9c559c6fe52f457","src/imp.rs":"dee6f26cd36f8c4062371349f7ff6091aff236edf3e4cccf3d898386dcf0f5bd","src/lib.rs":"c993efcdef9eed3c149f19d2429c59849381c7f61b264741c4ca1696de918974"},"package":"7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"}
\ No newline at end of file diff --git a/vendor/countme/Cargo.lock b/vendor/countme/Cargo.lock new file mode 100644 index 000000000..102108341 --- /dev/null +++ b/vendor/countme/Cargo.lock @@ -0,0 +1,168 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "countme" +version = "3.0.1" +dependencies = [ + "dashmap", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "dashmap" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +dependencies = [ + "cfg-if", + "num_cpus", + "parking_lot", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "redox_syscall" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" diff --git a/vendor/countme/Cargo.toml b/vendor/countme/Cargo.toml new file mode 100644 index 000000000..675dea03a --- /dev/null +++ b/vendor/countme/Cargo.toml @@ -0,0 +1,48 @@ +# 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 = "countme" +version = "3.0.1" +authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"] +exclude = [".github/", "bors.toml", "rustfmt.toml"] +description = "Counts the number of live instances of types" +categories = ["development-tools::profiling"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/matklad/countme" + +[[example]] +name = "print_at_exit" +required-features = ["print_at_exit"] + +[[example]] +name = "bench" +required-features = ["enable"] + +[[example]] +name = "bench_single_thread" +required-features = ["enable"] +[dependencies.dashmap] +version = "5.0" +optional = true + +[dependencies.once_cell] +version = "1.5" +optional = true + +[dependencies.rustc-hash] +version = "1.1" +optional = true + +[features] +enable = ["dashmap", "once_cell", "rustc-hash"] +print_at_exit = ["enable"] diff --git a/vendor/countme/LICENSE-APACHE b/vendor/countme/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/countme/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/vendor/countme/LICENSE-MIT b/vendor/countme/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/vendor/countme/LICENSE-MIT @@ -0,0 +1,23 @@ +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/vendor/countme/README.md b/vendor/countme/README.md new file mode 100644 index 000000000..42f3c7ea8 --- /dev/null +++ b/vendor/countme/README.md @@ -0,0 +1,21 @@ +A library to quickly get the live/total/max counts of allocated instances. + +```rust +#[derive(Default)] +struct Widget { + _c: countme::Count<Self>, + ... +} + +let w1 = Widget::default(); +let w2 = Widget::default(); +let w3 = Widget::default(); +drop(w1); + +let counts = countme::get::<Widget>(); +assert_eq!(counts.live, 2); +assert_eq!(counts.max_live, 3); +assert_eq!(counts.total, 3); + +eprintln!("{}", countme::get_all()); +``` diff --git a/vendor/countme/examples/bench.rs b/vendor/countme/examples/bench.rs new file mode 100644 index 000000000..1f9cc967f --- /dev/null +++ b/vendor/countme/examples/bench.rs @@ -0,0 +1,69 @@ +use std::thread; + +use countme::{get, Count}; + +#[derive(Default)] +struct Foo { + _c: Count<Self>, +} + +#[derive(Default)] +struct Bar { + _c: Count<Self>, + _x: i32, +} + +mod deeply { + pub(crate) mod nested { + pub(crate) mod module { + use countme::Count; + + #[derive(Default)] + pub(crate) struct Quux { + _c: Count<Self>, + } + } + } +} + +fn main() { + countme::enable(true); + let t = std::time::Instant::now(); + let n = 5; + let m = 1_000_000; + + let mut threads = Vec::new(); + for _ in 0..n { + threads.push(thread::spawn(move || { + for _ in 0..m { + Foo::default(); + } + })); + threads.push(thread::spawn(move || { + let mut xs = Vec::with_capacity(m); + for _ in 0..m { + xs.push(Bar::default()) + } + })); + threads.push(thread::spawn(move || { + for _ in 0..m { + deeply::nested::module::Quux::default(); + } + })); + } + for t in threads { + t.join().unwrap(); + } + + let foo = get::<Foo>(); + assert_eq!(foo.total, m * n); + assert!(foo.max_live >= 1); + assert_eq!(foo.live, 0); + + let bar = get::<Bar>(); + assert_eq!(bar.total, m * n); + assert!(bar.max_live >= m); + assert_eq!(bar.live, 0); + + println!("{:?}", t.elapsed()); +} diff --git a/vendor/countme/examples/bench_single_thread.rs b/vendor/countme/examples/bench_single_thread.rs new file mode 100644 index 000000000..ac147f861 --- /dev/null +++ b/vendor/countme/examples/bench_single_thread.rs @@ -0,0 +1,77 @@ +use countme::{get, Count}; + +#[derive(Default)] +struct Foo { + _c: Count<Self>, +} + +#[derive(Default)] +struct Bar { + _c: Count<Self>, + _x: i32, +} + +mod deeply { + pub(crate) mod nested { + pub(crate) mod module { + use countme::Count; + + #[derive(Default)] + pub(crate) struct Quux { + _c: Count<Self>, + } + } + } +} + +fn main() { + countme::enable(true); + let t = std::time::Instant::now(); + let n = 6; + let m = 2_000_000; + + for _ in 0..n { + for _ in 0..m { + Foo::default(); + } + + let mut xs = Vec::with_capacity(m); + for _ in 0..m { + xs.push(Bar::default()) + } + + for _ in 0..m { + deeply::nested::module::Quux::default(); + } + + let fs = [ + || drop(Foo::default()), + || drop(Bar::default()), + || drop(deeply::nested::module::Quux::default()), + || { + #[derive(Default)] + struct Local(Count<Self>); + + Local::default(); + }, + ]; + for i in 0..m { + fs[i % 4](); + } + } + + let foo = get::<Foo>(); + assert_eq!(foo.total, m * n + (m * n / 4)); + assert_eq!(foo.max_live, 1); + assert_eq!(foo.live, 0); + + let bar = get::<Bar>(); + assert_eq!(bar.total, m * n + (m * n / 4)); + + // FIXME: why +1? This seems like a bug + // overreporting by 1 is not significant, but anyway + assert_eq!(bar.max_live, m + 1); + assert_eq!(bar.live, 0); + + println!("{:?}", t.elapsed()); +} diff --git a/vendor/countme/examples/print_at_exit.rs b/vendor/countme/examples/print_at_exit.rs new file mode 100644 index 000000000..fd51e2288 --- /dev/null +++ b/vendor/countme/examples/print_at_exit.rs @@ -0,0 +1,11 @@ +#[derive(Default)] +struct Widget { + _t: countme::Count<Self>, +} + +fn main() { + let w1 = Widget::default(); + let _w2 = Widget::default(); + drop(w1); + let _w3 = Widget::default(); +} diff --git a/vendor/countme/src/imp.rs b/vendor/countme/src/imp.rs new file mode 100644 index 000000000..c1ace0da7 --- /dev/null +++ b/vendor/countme/src/imp.rs @@ -0,0 +1,175 @@ +use std::{ + any::{type_name, TypeId}, + cell::RefCell, + collections::HashMap, + hash::BuildHasherDefault, + os::raw::c_int, + sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed}, + sync::Arc, +}; + +use dashmap::DashMap; +use once_cell::sync::OnceCell; +use rustc_hash::FxHasher; + +use crate::{AllCounts, Counts}; + +static ENABLE: AtomicBool = AtomicBool::new(cfg!(feature = "print_at_exit")); + +type GlobalStore = DashMap<TypeId, Arc<Store>, BuildHasherDefault<FxHasher>>; + +#[inline] +fn global_store() -> &'static GlobalStore { + static MAP: OnceCell<GlobalStore> = OnceCell::new(); + MAP.get_or_init(|| { + if cfg!(feature = "print_at_exit") { + extern "C" { + fn atexit(f: extern "C" fn()) -> c_int; + } + extern "C" fn print_at_exit() { + eprint!("{}", get_all()); + } + unsafe { + atexit(print_at_exit); + } + } + + GlobalStore::default() + }) +} + +thread_local! { + static LOCAL: RefCell<HashMap<TypeId, Arc<Store>, BuildHasherDefault<FxHasher>>> = RefCell::default(); +} + +pub(crate) fn enable(yes: bool) { + ENABLE.store(yes, Relaxed); +} + +#[inline] +fn enabled() -> bool { + ENABLE.load(Relaxed) +} + +#[inline] +pub(crate) fn dec<T: 'static>() { + if enabled() { + do_dec(TypeId::of::<T>()) + } +} +#[inline(never)] +fn do_dec(key: TypeId) { + LOCAL.with(|local| { + // Fast path: we have needed store in thread local map + if let Some(store) = local.borrow().get(&key) { + store.dec(); + return; + } + + let global = global_store(); + + // Slightly slower: we don't have needed store in our thread local map, + // but some other thread has already initialized the needed store in the global map + if let Some(store) = global.get(&key) { + let store = store.value(); + local.borrow_mut().insert(key, Arc::clone(store)); + store.inc(); + return; + } + + // We only decrement counter after incremenrting it, so this line is unreachable + }) +} + +#[inline] +pub(crate) fn inc<T: 'static>() { + if enabled() { + do_inc(TypeId::of::<T>(), type_name::<T>()) + } +} +#[inline(never)] +fn do_inc(key: TypeId, name: &'static str) { + LOCAL.with(|local| { + // Fast path: we have needed store in thread local map + if let Some(store) = local.borrow().get(&key) { + store.inc(); + return; + } + + let global = global_store(); + + let copy = match global.get(&key) { + // Slightly slower path: we don't have needed store in our thread local map, + // but some other thread has already initialized the needed store in the global map + Some(store) => { + let store = store.value(); + store.inc(); + Arc::clone(store) + } + // Slow path: we are the first to initialize both global and local maps + None => { + let store = global + .entry(key) + .or_insert_with(|| Arc::new(Store { name, ..Store::default() })) + .downgrade(); + let store = store.value(); + + store.inc(); + Arc::clone(store) + } + }; + + local.borrow_mut().insert(key, copy); + }); +} + +pub(crate) fn get<T: 'static>() -> Counts { + do_get(TypeId::of::<T>()) +} +fn do_get(key: TypeId) -> Counts { + global_store().entry(key).or_default().value().read() +} + +pub(crate) fn get_all() -> AllCounts { + let mut entries = global_store() + .iter() + .map(|entry| { + let store = entry.value(); + (store.type_name(), store.read()) + }) + .collect::<Vec<_>>(); + entries.sort_by_key(|(name, _counts)| *name); + AllCounts { entries } +} + +#[derive(Default)] +struct Store { + total: AtomicUsize, + max_live: AtomicUsize, + live: AtomicUsize, + name: &'static str, +} + +impl Store { + fn inc(&self) { + self.total.fetch_add(1, Relaxed); + let live = self.live.fetch_add(1, Relaxed) + 1; + self.max_live.fetch_max(live, Relaxed); + } + + fn dec(&self) { + self.live.fetch_sub(1, Relaxed); + } + + fn read(&self) -> Counts { + Counts { + total: self.total.load(Relaxed), + max_live: self.max_live.load(Relaxed), + live: self.live.load(Relaxed), + } + } + + fn type_name(&self) -> &'static str { + self.name + } +} diff --git a/vendor/countme/src/lib.rs b/vendor/countme/src/lib.rs new file mode 100644 index 000000000..f89e63c5b --- /dev/null +++ b/vendor/countme/src/lib.rs @@ -0,0 +1,193 @@ +//! A library to quickly get the live/total/max counts of allocated instances. +//! +//! # Example +//! +//! ``` +//! # if cfg!(not(feature = "enable")) { return; } +//! +//! #[derive(Default)] +//! struct Widget { +//! _c: countme::Count<Self>, +//! } +//! +//! countme::enable(true); +//! +//! let w1 = Widget::default(); +//! let w2 = Widget::default(); +//! let w3 = Widget::default(); +//! drop(w1); +//! +//! let counts = countme::get::<Widget>(); +//! assert_eq!(counts.live, 2); +//! assert_eq!(counts.max_live, 3); +//! assert_eq!(counts.total, 3); +//! +//! eprintln!("{}", countme::get_all()); +//! ``` +//! +//! # Configuration +//! +//! By default, the implementation compiles to no-ops. Therefore it is possible +//! to include `Count` fields into library types. +//! +//! The `enable` cargo feature ungates the counting code. The feature can be +//! enabled anywhere in the crate graph. +//! +//! At run-time, the counters are controlled with [`enable`] function. Counting +//! is enabled by default if `print_at_exit` feature is enabled. Otherwise +//! counting is disabled by default. Call `enable(true)` early in `main` to enable: +//! +//! ```rust +//! fn main() { +//! countme::enable(std::env::var("COUNTME").is_ok()); +//! } +//! ``` +//! +//! The code is optimized for the case where counting is not enabled at runtime +//! (counting is a relaxed load and a branch to a function call). +//! +//! The `print_at_exit` Cargo feature uses `atexit` call to print final counts +//! before the program exits (it also enables counting at runtime). Use it only +//! when you can't modify the main to print counts -- `atexit` is not guaranteed +//! to work with rust's runtime. +#[cfg(feature = "enable")] +mod imp; + +use std::{fmt, marker::PhantomData}; + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[non_exhaustive] +pub struct Counts { + /// The total number of tokens created. + pub total: usize, + /// The historical maximum of the `live` count. + pub max_live: usize, + /// The number of tokens which were created, but are not destroyed yet. + pub live: usize, +} + +/// Store this inside your struct as `_c: countme::Count<Self>`. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Count<T: 'static> { + ghost: PhantomData<fn(T)>, +} + +impl<T: 'static> Default for Count<T> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<T: 'static> Clone for Count<T> { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} + +impl<T: 'static> Count<T> { + /// Create new `Count`, incrementing the corresponding count. + #[inline] + pub fn new() -> Count<T> { + #[cfg(feature = "enable")] + imp::inc::<T>(); + Count { ghost: PhantomData } + } +} + +impl<T: 'static> Drop for Count<T> { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "enable")] + imp::dec::<T>(); + } +} + +/// Enable or disable counting at runtime. +/// +/// Counting is enabled by default if `print_at_exit` feature is enabled. +/// Otherwise counting is disabled by default. +/// +/// If neither `enable` nor `print_at_exit` features are enabled, then this function is noop. +pub fn enable(_yes: bool) { + #[cfg(feature = "enable")] + imp::enable(_yes); +} + +/// Returns the counts for the `T` type. +#[inline] +pub fn get<T: 'static>() -> Counts { + #[cfg(feature = "enable")] + { + return imp::get::<T>(); + } + #[cfg(not(feature = "enable"))] + { + return Counts::default(); + } +} + +/// Returns a collection of counts for all types. +pub fn get_all() -> AllCounts { + #[cfg(feature = "enable")] + { + return imp::get_all(); + } + #[cfg(not(feature = "enable"))] + { + return AllCounts::default(); + } +} + +/// A collection of counts for all types. +#[derive(Default, Clone, Debug)] +pub struct AllCounts { + entries: Vec<(&'static str, Counts)>, +} + +impl fmt::Display for AllCounts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn sep(mut n: usize) -> String { + let mut groups = Vec::new(); + while n >= 1000 { + groups.push(format!("{:03}", n % 1000)); + n /= 1000; + } + groups.push(n.to_string()); + groups.reverse(); + groups.join("_") + } + + if self.entries.is_empty() { + return if cfg!(feature = "enable") { + writeln!(f, "all counts are zero") + } else { + writeln!(f, "counts are disabled") + }; + } + let max_width = + self.entries.iter().map(|(name, _count)| name.chars().count()).max().unwrap_or(0); + for (name, counts) in &self.entries { + writeln!( + f, + "{:<max_width$} {:>12} {:>12} {:>12}", + name, + sep(counts.total), + sep(counts.max_live), + sep(counts.live), + max_width = max_width + )?; + } + writeln!( + f, + "{:<max_width$} {:>12} {:>12} {:>12}", + "", + "total", + "max_live", + "live", + max_width = max_width + )?; + Ok(()) + } +} |