summaryrefslogtreecommitdiffstats
path: root/vendor/perf-event
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/perf-event
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/perf-event')
-rw-r--r--vendor/perf-event/.cargo-checksum.json1
-rw-r--r--vendor/perf-event/Cargo.lock24
-rw-r--r--vendor/perf-event/Cargo.toml26
-rw-r--r--vendor/perf-event/LICENSE-APACHE201
-rw-r--r--vendor/perf-event/LICENSE-MIT23
-rw-r--r--vendor/perf-event/README.md45
-rw-r--r--vendor/perf-event/TODO.org2
-rwxr-xr-xvendor/perf-event/coverage.sh17
-rw-r--r--vendor/perf-event/examples/big-group.rs72
-rw-r--r--vendor/perf-event/examples/group.rs45
-rw-r--r--vendor/perf-event/examples/insns-for-pid.rs27
-rw-r--r--vendor/perf-event/examples/println-cpi.rs22
-rw-r--r--vendor/perf-event/examples/println.rs15
-rw-r--r--vendor/perf-event/src/events.rs321
-rw-r--r--vendor/perf-event/src/lib.rs1043
-rw-r--r--vendor/perf-event/wrapper.h20
16 files changed, 1904 insertions, 0 deletions
diff --git a/vendor/perf-event/.cargo-checksum.json b/vendor/perf-event/.cargo-checksum.json
new file mode 100644
index 000000000..6227f9408
--- /dev/null
+++ b/vendor/perf-event/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"ffee78a24c58d4f3c188bf811ed237259da3d6e7e4985ea1537b049e95fa7882","Cargo.toml":"a1fb1bb3738b7261b434ce43382582029fca06afbffd107aefea5c7f33648dca","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"c1344e75a67a817b375cbdc47acb63776fc3c73a1820cf4782306cae0840c4f1","TODO.org":"9bba41063f48330b4060ac37744495a8d5a03fefa15290a1fe3c783f78321477","coverage.sh":"499e0ba26d5b1402d2de552afde9c93a010055dbc534c21ed4a1bd19e4829f52","examples/big-group.rs":"0410be6da09fdd9d8f94420bd6f7e54fd15167c40738042fc1057ec1853af523","examples/group.rs":"88e608c1c9bae244cb6b418c6c70d2c89c98225791e98b043c9a20374e9bd280","examples/insns-for-pid.rs":"076b2b9bb5ab56d9a4b543088e9f4213f97cfcb18cf6fffa5ac9e511ca424edd","examples/println-cpi.rs":"1fae9a436af127314828f647ae846ab30683b70de8838d837ffff44e9c15a7a7","examples/println.rs":"98503038ba2bd155a76a440593ce082e5a176cdb479f865c843f4b960e4c815a","src/events.rs":"51d3b151633e938ceeabf863408890295cd8a8168b384f612d009c9b3c5cf4c4","src/lib.rs":"e099d00a7cec768429ae28769dd42ad812b90e3297eb8fa4af1bcbaf799a7277","wrapper.h":"2291357bf1a2dd75892322253f0a6fc93ea6cb0ba363e689bf0354dbda10d550"},"package":"5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66"} \ No newline at end of file
diff --git a/vendor/perf-event/Cargo.lock b/vendor/perf-event/Cargo.lock
new file mode 100644
index 000000000..e807dc90f
--- /dev/null
+++ b/vendor/perf-event/Cargo.lock
@@ -0,0 +1,24 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "libc"
+version = "0.2.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
+
+[[package]]
+name = "perf-event"
+version = "0.4.7"
+dependencies = [
+ "libc",
+ "perf-event-open-sys",
+]
+
+[[package]]
+name = "perf-event-open-sys"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66f37842e29d92d05872a3c0271ba6717842695ecb896cb2e147a825c804b207"
+dependencies = [
+ "libc",
+]
diff --git a/vendor/perf-event/Cargo.toml b/vendor/perf-event/Cargo.toml
new file mode 100644
index 000000000..ed684cc4c
--- /dev/null
+++ b/vendor/perf-event/Cargo.toml
@@ -0,0 +1,26 @@
+# 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 believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "perf-event"
+version = "0.4.7"
+authors = ["Jim Blandy <jimb@red-bean.com>"]
+description = "A Rust interface to Linux performance monitoring"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/jimblandy/perf-event.git"
+[dependencies.libc]
+version = "0.2"
+
+[dependencies.perf-event-open-sys]
+version = "1.0"
diff --git a/vendor/perf-event/LICENSE-APACHE b/vendor/perf-event/LICENSE-APACHE
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/perf-event/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/perf-event/LICENSE-MIT b/vendor/perf-event/LICENSE-MIT
new file mode 100644
index 000000000..31aa79387
--- /dev/null
+++ b/vendor/perf-event/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/perf-event/README.md b/vendor/perf-event/README.md
new file mode 100644
index 000000000..9848ca226
--- /dev/null
+++ b/vendor/perf-event/README.md
@@ -0,0 +1,45 @@
+## perf-event: a Rust interface to Linux performance monitoring
+
+*This is a nascent project. Tests are lacking. The design may change.*
+
+This uses the Linux [`perf_event_open`][man] API to access performance monitoring
+hardware and software. Use `Builder` to create a perf event counter, then use
+`enable` and `disable` to start and stop counting. Call `read` to get your
+count.
+
+For example, this counts the number of cycles used by the call to `println!`.
+Try adjusting the length of the vector to see the cycle count change.
+
+ use perf_event::Builder;
+
+ fn main() -> std::io::Result<()> {
+ let mut counter = Builder::new().build()?;
+
+ let vec = (0..=51).collect::<Vec<_>>();
+
+ counter.enable()?;
+ println!("{:?}", vec);
+ counter.disable()?;
+
+ println!("{} instructions retired", counter.read()?);
+
+ Ok(())
+ }
+
+Since we don't specify what sort of event we want to count, `Builder` defaults
+to `PERF_COUNT_HW_INSTRUCTIONS` events, whose documentation says:
+
+> Retired instructions. Be careful, these can be affected by various issues,
+> most notably hardware interrupt counts.
+
+The `examples` directory includes programs that count other sorts of events.
+
+[man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+
+## See also
+
+The [`perfcnt`] crate provides more extensive coverage of the Linux
+`perf_event_open` API than this crate. However, `perfcnt` does not build on
+stable Rust.
+
+[`perfcnt`]: https://crates.io/crates/perfcnt
diff --git a/vendor/perf-event/TODO.org b/vendor/perf-event/TODO.org
new file mode 100644
index 000000000..24d7e53df
--- /dev/null
+++ b/vendor/perf-event/TODO.org
@@ -0,0 +1,2 @@
+- write Counter::new; use in examples
+- raw Event: just provide type, config, config1, config2 values, as read from sysfs
diff --git a/vendor/perf-event/coverage.sh b/vendor/perf-event/coverage.sh
new file mode 100755
index 000000000..de8d66051
--- /dev/null
+++ b/vendor/perf-event/coverage.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+cargo +nightly clean
+export RUSTFLAGS="\
+ -Zprofile \
+ -Ccodegen-units=1 \
+ -Copt-level=0 \
+ -Clink-dead-code \
+ -Coverflow-checks=off \
+"
+export CARGO_INCREMENTAL=0
+
+cargo +nightly test
+
+grcov ./target/debug/ -s . -t html --llvm --branch --ignore-not-existing -o ./target/debug/coverage/
+
+xdg-open target/debug/coverage/index.html
diff --git a/vendor/perf-event/examples/big-group.rs b/vendor/perf-event/examples/big-group.rs
new file mode 100644
index 000000000..73b557827
--- /dev/null
+++ b/vendor/perf-event/examples/big-group.rs
@@ -0,0 +1,72 @@
+use perf_event::{Builder, Group};
+use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
+
+fn main() -> std::io::Result<()> {
+ const ACCESS: Cache = Cache {
+ which: WhichCache::L1D,
+ operation: CacheOp::READ,
+ result: CacheResult::ACCESS,
+ };
+ const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
+
+ let mut group = Group::new()?;
+ let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
+ let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
+ let branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_INSTRUCTIONS).build()?;
+ let missed_branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_MISSES).build()?;
+ let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
+ let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
+
+ // Note that if you add more counters than you actually have hardware for,
+ // the kernel will time-slice them, which means you may get no coverage for
+ // short measurements. See the documentation.
+ //
+ // On my machine, this program won't collect any data unless I disable the
+ // NMI watchdog, as described in the documentation for `Group`. My machine
+ // has four counters, and this program tries to use all of them, but the NMI
+ // watchdog uses one up.
+
+ let mut vec = (0..=100000).collect::<Vec<_>>();
+
+ group.enable()?;
+ vec.sort();
+ println!("{:?}", &vec[0..10]);
+ group.disable()?;
+
+ let counts = group.read()?;
+
+ println!("enabled for {}ns, actually running for {}ns",
+ counts.time_enabled(),
+ counts.time_running());
+
+ if counts.time_running() == 0 {
+ println!("Group was never running; no results available.");
+ return Ok(());
+ }
+
+ if counts.time_running() < counts.time_enabled() {
+ println!("Counts cover only a portion of the execution.");
+ }
+
+ println!("L1D cache misses/references: {} / {} ({:.0}%)",
+ counts[&miss_counter],
+ counts[&access_counter],
+ (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0);
+
+ println!("branch prediction misses/total: {} / {} ({:.0}%)",
+ counts[&missed_branches],
+ counts[&branches],
+ (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0);
+
+ println!("{} instructions, {} cycles ({:.2} cpi)",
+ counts[&insns],
+ counts[&cycles],
+ counts[&cycles] as f64 / counts[&insns] as f64);
+
+ // You can iterate over a `Counts` value:
+ for (id, value) in &counts {
+ println!("Counter id {} has value {}", id, value);
+ }
+
+ Ok(())
+}
diff --git a/vendor/perf-event/examples/group.rs b/vendor/perf-event/examples/group.rs
new file mode 100644
index 000000000..0312485c9
--- /dev/null
+++ b/vendor/perf-event/examples/group.rs
@@ -0,0 +1,45 @@
+use perf_event::{Builder, Group};
+use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
+
+fn main() -> std::io::Result<()> {
+ const ACCESS: Cache = Cache {
+ which: WhichCache::L1D,
+ operation: CacheOp::READ,
+ result: CacheResult::ACCESS,
+ };
+ const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
+
+ let mut group = Group::new()?;
+ let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
+ let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
+ let branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_INSTRUCTIONS).build()?;
+ let missed_branches = Builder::new().group(&mut group).kind(Hardware::BRANCH_MISSES).build()?;
+
+ // Note that if you add more counters than you actually have hardware for,
+ // the kernel will time-slice them, which means you may get no coverage for
+ // short measurements. See the documentation.
+
+ let vec = (0..=51).collect::<Vec<_>>();
+
+ group.enable()?;
+ println!("{:?}", vec);
+ group.disable()?;
+
+ let counts = group.read()?;
+ println!("L1D cache misses/references: {} / {} ({:.0}%)",
+ counts[&miss_counter],
+ counts[&access_counter],
+ (counts[&miss_counter] as f64 / counts[&access_counter] as f64) * 100.0);
+
+ println!("branch prediction misses/total: {} / {} ({:.0}%)",
+ counts[&missed_branches],
+ counts[&branches],
+ (counts[&missed_branches] as f64 / counts[&branches] as f64) * 100.0);
+
+ // You can iterate over a `Counts` value:
+ for (id, value) in &counts {
+ println!("Counter id {} has value {}", id, value);
+ }
+
+ Ok(())
+}
diff --git a/vendor/perf-event/examples/insns-for-pid.rs b/vendor/perf-event/examples/insns-for-pid.rs
new file mode 100644
index 000000000..09d4ef36d
--- /dev/null
+++ b/vendor/perf-event/examples/insns-for-pid.rs
@@ -0,0 +1,27 @@
+use libc::pid_t;
+use perf_event::Builder;
+use perf_event::events::Hardware;
+use std::thread::sleep;
+use std::time::Duration;
+
+fn main() -> std::io::Result<()> {
+ let pid: pid_t = std::env::args()
+ .nth(1)
+ .expect("Usage: insns-for-pid PID")
+ .parse()
+ .expect("Usage: insns-for-pid PID");
+
+ let mut insns = Builder::new()
+ .observe_pid(pid)
+ .kind(Hardware::BRANCH_INSTRUCTIONS)
+ .build()?;
+
+ // Count instructions in PID for five seconds.
+ insns.enable()?;
+ sleep(Duration::from_secs(5));
+ insns.disable()?;
+
+ println!("instructions in last five seconds: {}", insns.read()?);
+
+ Ok(())
+}
diff --git a/vendor/perf-event/examples/println-cpi.rs b/vendor/perf-event/examples/println-cpi.rs
new file mode 100644
index 000000000..31d24f640
--- /dev/null
+++ b/vendor/perf-event/examples/println-cpi.rs
@@ -0,0 +1,22 @@
+fn main() -> std::io::Result<()> {
+ use perf_event::{Builder, Group};
+ use perf_event::events::Hardware;
+
+ let mut group = Group::new()?;
+ let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
+ let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
+
+ let vec = (0..=51).collect::<Vec<_>>();
+
+ group.enable()?;
+ println!("{:?}", vec);
+ group.disable()?;
+
+ let counts = group.read()?;
+ println!("cycles / instructions: {} / {} ({:.2} cpi)",
+ counts[&cycles],
+ counts[&insns],
+ (counts[&cycles] as f64 / counts[&insns] as f64));
+
+ Ok(())
+}
diff --git a/vendor/perf-event/examples/println.rs b/vendor/perf-event/examples/println.rs
new file mode 100644
index 000000000..8760e3dcd
--- /dev/null
+++ b/vendor/perf-event/examples/println.rs
@@ -0,0 +1,15 @@
+use perf_event::Builder;
+
+fn main() -> std::io::Result<()> {
+ let mut counter = Builder::new().build()?;
+
+ let vec = (0..=51).collect::<Vec<_>>();
+
+ counter.enable()?;
+ println!("{:?}", vec);
+ counter.disable()?;
+
+ println!("{} instructions retired", counter.read()?);
+
+ Ok(())
+}
diff --git a/vendor/perf-event/src/events.rs b/vendor/perf-event/src/events.rs
new file mode 100644
index 000000000..1309ab0c7
--- /dev/null
+++ b/vendor/perf-event/src/events.rs
@@ -0,0 +1,321 @@
+//! Events we can monitor or count.
+//!
+//! There are three general categories of event:
+//!
+//! - [`Hardware`] events are counted by the processor itself. This
+//! includes things like clock cycles, instructions retired, and cache and
+//! branch prediction statistics.
+//!
+//! - [`Software`] events are counted by the kernel. This includes things
+//! like context switches, page faults, and so on.
+//!
+//! - [`Cache`] events offer a more detailed view of the processor's cache
+//! counters. You can select which level of the cache hierarchy to observe,
+//! discriminate between data and instruction caches, and so on.
+//!
+//! The `Event` type is just an enum with a variant for each of the above types,
+//! which all implement `Into<Event>`.
+//!
+//! Linux supports many more kinds of events than this module covers, including
+//! events specific to particular make and model of processor, and events that
+//! are dynamically registered by drivers and kernel modules. If something you
+//! want is missing, think about the best API to expose it, and submit a pull
+//! request!
+//!
+//! [`Hardware`]: enum.Hardware.html
+//! [`Software`]: enum.Software.html
+//! [`Cache`]: struct.Cache.html
+
+#![allow(non_camel_case_types)]
+use perf_event_open_sys::bindings as bindings;
+
+/// Any sort of event. This is a sum of the [`Hardware`],
+/// [`Software`], and [`Cache`] types, which all implement
+/// `Into<Event>`.
+///
+/// [`Hardware`]: enum.Hardware.html
+/// [`Software`]: enum.Software.html
+/// [`Cache`]: struct.Cache.html
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum Event {
+ #[allow(missing_docs)]
+ Hardware(Hardware),
+
+ #[allow(missing_docs)]
+ Software(Software),
+
+ #[allow(missing_docs)]
+ Cache(Cache),
+}
+
+impl Event {
+ pub(crate) fn as_type(&self) -> bindings::perf_type_id {
+ match self {
+ Event::Hardware(_) => bindings::perf_type_id_PERF_TYPE_HARDWARE,
+ Event::Software(_) => bindings::perf_type_id_PERF_TYPE_SOFTWARE,
+ Event::Cache(_) => bindings::perf_type_id_PERF_TYPE_HW_CACHE,
+ }
+ }
+
+ pub(crate) fn as_config(self) -> u64 {
+ match self {
+ Event::Hardware(hw) => hw as _,
+ Event::Software(sw) => sw as _,
+ Event::Cache(cache) => cache.as_config(),
+ }
+ }
+}
+
+/// Hardware counters.
+///
+/// These are counters implemented by the processor itself. Such counters vary
+/// from one architecture to the next, and even different models within a
+/// particular architecture will often change the way they expose this data.
+/// This is a selection of portable names for values that can be obtained on a
+/// wide variety of systems.
+///
+/// Each variant of this enum corresponds to a particular `PERF_COUNT_HW_`...
+/// value supported by the [`perf_event_open`][man] system call.
+///
+/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+#[repr(u32)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Hardware {
+ /// Total cycles. Be wary of what happens during CPU frequency scaling.
+ CPU_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_CPU_CYCLES,
+
+ /// Retired instructions. Be careful, these can be affected by various
+ /// issues, most notably hardware interrupt counts.
+ INSTRUCTIONS = bindings::perf_hw_id_PERF_COUNT_HW_INSTRUCTIONS,
+
+ /// Cache accesses. Usually this indicates Last Level Cache accesses but
+ /// this may vary depending on your CPU. This may include prefetches and
+ /// coherency messages; again this depends on the design of your CPU.
+ CACHE_REFERENCES = bindings::perf_hw_id_PERF_COUNT_HW_CACHE_REFERENCES,
+
+ /// Cache misses. Usually this indicates Last Level Cache misses; this is
+ /// intended to be used in conjunction with the
+ /// PERF_COUNT_HW_CACHE_REFERENCES event to calculate cache miss rates.
+ CACHE_MISSES = bindings::perf_hw_id_PERF_COUNT_HW_CACHE_MISSES,
+
+ /// Retired branch instructions. Prior to Linux 2.6.35, this used the wrong
+ /// event on AMD processors.
+ BRANCH_INSTRUCTIONS = bindings::perf_hw_id_PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
+
+ /// Mispredicted branch instructions.
+ BRANCH_MISSES = bindings::perf_hw_id_PERF_COUNT_HW_BRANCH_MISSES,
+
+ /// Bus cycles, which can be different from total cycles.
+ BUS_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_BUS_CYCLES,
+
+ /// Stalled cycles during issue. (since Linux 3.0)
+ STALLED_CYCLES_FRONTEND = bindings::perf_hw_id_PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
+
+ /// Stalled cycles during retirement. (since Linux 3.0)
+ STALLED_CYCLES_BACKEND = bindings::perf_hw_id_PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
+
+ /// Total cycles; not affected by CPU frequency scaling. (since Linux 3.3)
+ REF_CPU_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_REF_CPU_CYCLES,
+}
+
+impl From<Hardware> for Event {
+ fn from(hw: Hardware) -> Event {
+ Event::Hardware(hw)
+ }
+}
+
+/// Software counters, implemented by the kernel.
+///
+/// Each variant of this enum corresponds to a particular `PERF_COUNT_SW_`...
+/// value supported by the [`perf_event_open`][man] system call.
+///
+/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+#[repr(u32)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Software {
+ /// This reports the CPU clock, a high-resolution per-CPU timer.
+ CPU_CLOCK = bindings::perf_sw_ids_PERF_COUNT_SW_CPU_CLOCK,
+
+ /// This reports a clock count specific to the task that is running.
+ TASK_CLOCK = bindings::perf_sw_ids_PERF_COUNT_SW_TASK_CLOCK,
+
+ /// This reports the number of page faults.
+ PAGE_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS,
+
+ /// This counts context switches. Until Linux 2.6.34, these were all
+ /// reported as user-space events, after that they are reported as happening
+ /// in the kernel.
+ CONTEXT_SWITCHES = bindings::perf_sw_ids_PERF_COUNT_SW_CONTEXT_SWITCHES,
+
+ /// This reports the number of times the process has migrated to a new CPU.
+ CPU_MIGRATIONS = bindings::perf_sw_ids_PERF_COUNT_SW_CPU_MIGRATIONS,
+
+ /// This counts the number of minor page faults. These did not require disk
+ /// I/O to handle.
+ PAGE_FAULTS_MIN = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS_MIN,
+
+ /// This counts the number of major page faults. These required disk I/O to
+ /// handle.
+ PAGE_FAULTS_MAJ = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS_MAJ,
+
+ /// (since Linux 2.6.33) This counts the number of alignment faults. These
+ /// happen when unaligned memory accesses happen; the kernel can handle
+ /// these but it reduces performance. This happens only on some
+ /// architectures (never on x86).
+ ALIGNMENT_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_ALIGNMENT_FAULTS,
+
+ /// (since Linux 2.6.33) This counts the number of emulation faults. The
+ /// kernel sometimes traps on unimplemented instructions and emulates them
+ /// for user space. This can negatively impact performance.
+ EMULATION_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_EMULATION_FAULTS,
+
+ /// (since Linux 3.12) This is a placeholder event that counts nothing.
+ /// Informational sample record types such as mmap or comm must be
+ /// associated with an active event. This dummy event allows gathering such
+ /// records without requiring a counting event.
+ DUMMY = bindings::perf_sw_ids_PERF_COUNT_SW_DUMMY,
+}
+
+impl From<Software> for Event {
+ fn from(hw: Software) -> Event {
+ Event::Software(hw)
+ }
+}
+
+/// A cache event.
+///
+/// A cache event has three identifying characteristics:
+///
+/// - which cache to observe ([`which`])
+///
+/// - what sort of request it's handling ([`operation`])
+///
+/// - whether we want to count all cache accesses, or just misses
+/// ([`result`]).
+///
+/// For example, to measure the L1 data cache's miss rate:
+///
+/// # use perf_event::{Builder, Group};
+/// # use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
+/// # fn main() -> std::io::Result<()> {
+/// // A `Cache` value representing L1 data cache read accesses.
+/// const ACCESS: Cache = Cache {
+/// which: WhichCache::L1D,
+/// operation: CacheOp::READ,
+/// result: CacheResult::ACCESS,
+/// };
+///
+/// // A `Cache` value representing L1 data cache read misses.
+/// const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
+///
+/// // Construct a `Group` containing the two new counters, from which we
+/// // can get counts over matching periods of time.
+/// let mut group = Group::new()?;
+/// let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
+/// let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
+/// # Ok(()) }
+///
+/// [`which`]: enum.WhichCache.html
+/// [`operation`]: enum.CacheOp.html
+/// [`result`]: enum.CacheResult.html
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Cache {
+ /// Which cache is being monitored? (data, instruction, ...)
+ pub which: WhichCache,
+
+ /// What operation is being monitored? (read, write, etc.)
+ pub operation: CacheOp,
+
+ /// All accesses, or just misses?
+ pub result: CacheResult,
+}
+
+impl From<Cache> for Event {
+ fn from(hw: Cache) -> Event {
+ Event::Cache(hw)
+ }
+}
+
+impl Cache {
+ fn as_config(&self) -> u64 {
+ self.which as u64 |
+ ((self.operation as u64) << 8) |
+ ((self.result as u64) << 16)
+ }
+}
+
+/// A cache whose events we would like to count.
+///
+/// This is used in the `Cache` type as part of the identification of a cache
+/// event. Each variant here corresponds to a particular
+/// `PERF_COUNT_HW_CACHE_...` constant supported by the [`perf_event_open`][man]
+/// system call.
+///
+/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+#[repr(u32)]
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum WhichCache {
+ /// for measuring Level 1 Data Cache
+ L1D = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_L1D,
+
+ /// for measuring Level 1 Instruction Cache
+ L1I = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_L1I,
+
+ /// for measuring Last-Level Cache
+ LL = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_LL,
+
+ /// for measuring the Data TLB
+ DTLB = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_DTLB,
+
+ /// for measuring the Instruction TLB
+ ITLB = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_ITLB,
+
+ /// for measuring the branch prediction unit
+ BPU = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_BPU,
+
+ /// (since Linux 3.1) for measuring local memory accesses
+ NODE = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_NODE,
+}
+
+/// What sort of cache operation we would like to observe.
+///
+/// This is used in the `Cache` type as part of the identification of a cache
+/// event. Each variant here corresponds to a particular
+/// `PERF_COUNT_HW_CACHE_OP_...` constant supported by the
+/// [`perf_event_open`][man] system call.
+///
+/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+#[repr(u32)]
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum CacheOp {
+ /// Read accesses.
+ READ = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_READ,
+
+ /// Write accesses.
+ WRITE = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_WRITE,
+
+ /// Prefetch accesses.
+ PREFETCH = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_PREFETCH,
+}
+
+#[repr(u32)]
+/// What sort of cache result we're interested in observing.
+///
+/// `ACCESS` counts the total number of operations performed on the cache,
+/// whereas `MISS` counts only those requests that the cache could not satisfy.
+/// Treating `MISS` as a fraction of `ACCESS` gives you the cache's miss rate.
+///
+/// This is used used in the `Cache` type as part of the identification of a
+/// cache event. Each variant here corresponds to a particular
+/// `PERF_COUNT_HW_CACHE_RESULT_...` constant supported by the
+/// [`perf_event_open`][man] system call.
+///
+/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum CacheResult {
+ /// to measure accesses
+ ACCESS = bindings::perf_hw_cache_op_result_id_PERF_COUNT_HW_CACHE_RESULT_ACCESS,
+
+ /// to measure misses
+ MISS = bindings::perf_hw_cache_op_result_id_PERF_COUNT_HW_CACHE_RESULT_MISS,
+}
diff --git a/vendor/perf-event/src/lib.rs b/vendor/perf-event/src/lib.rs
new file mode 100644
index 000000000..abc66bfab
--- /dev/null
+++ b/vendor/perf-event/src/lib.rs
@@ -0,0 +1,1043 @@
+//! A performance monitoring API for Linux.
+//!
+//! This crate provides access to processor and kernel counters for things like
+//! instruction completions, cache references and misses, branch predictions,
+//! context switches, page faults, and so on.
+//!
+//! For example, to compare the number of clock cycles elapsed with the number
+//! of instructions completed during one call to `println!`:
+//!
+//! use perf_event::{Builder, Group};
+//! use perf_event::events::Hardware;
+//!
+//! fn main() -> std::io::Result<()> {
+//! // A `Group` lets us enable and disable several counters atomically.
+//! let mut group = Group::new()?;
+//! let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
+//! let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
+//!
+//! let vec = (0..=51).collect::<Vec<_>>();
+//!
+//! group.enable()?;
+//! println!("{:?}", vec);
+//! group.disable()?;
+//!
+//! let counts = group.read()?;
+//! println!("cycles / instructions: {} / {} ({:.2} cpi)",
+//! counts[&cycles],
+//! counts[&insns],
+//! (counts[&cycles] as f64 / counts[&insns] as f64));
+//!
+//! Ok(())
+//! }
+//!
+//! This crate is built on top of the Linux [`perf_event_open`][man] system
+//! call; that documentation has the authoritative explanations of exactly what
+//! all the counters mean.
+//!
+//! There are two main types for measurement:
+//!
+//! - A [`Counter`] is an individual counter. Use [`Builder`] to
+//! construct one.
+//!
+//! - A [`Group`] is a collection of counters that can be enabled and
+//! disabled atomically, so that they cover exactly the same period of
+//! execution, allowing meaningful comparisons of the individual values.
+//!
+//! If you're familiar with the kernel API already:
+//!
+//! - A `Builder` holds the arguments to a `perf_event_open` call:
+//! a `struct perf_event_attr` and a few other fields.
+//!
+//! - `Counter` and `Group` objects are just event file descriptors, together
+//! with their kernel id numbers, and some other details you need to
+//! actually use them. They're different types because they yield different
+//! types of results, and because you can't retrieve a `Group`'s counts
+//! without knowing how many members it has.
+//!
+//! ### Call for PRs
+//!
+//! Linux's `perf_event_open` API can report all sorts of things this crate
+//! doesn't yet understand: stack traces, logs of executable and shared library
+//! activity, tracepoints, kprobes, uprobes, and so on. And beyond the counters
+//! in the kernel header files, there are others that can only be found at
+//! runtime by consulting `sysfs`, specific to particular processors and
+//! devices. For example, modern Intel processors have counters that measure
+//! power consumption in Joules.
+//!
+//! If you find yourself in need of something this crate doesn't support, please
+//! consider submitting a pull request.
+//!
+//! [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+
+#![deny(missing_docs)]
+
+use events::Event;
+use libc::pid_t;
+use perf_event_open_sys as sys;
+use perf_event_open_sys::bindings::perf_event_attr;
+use std::fs::File;
+use std::io::{self, Read};
+use std::os::raw::{c_int, c_uint, c_ulong};
+use std::os::unix::io::{AsRawFd, FromRawFd};
+
+pub mod events;
+
+/// A counter for one kind of kernel or hardware event.
+///
+/// A `Counter` represents a single performance monitoring counter. You select
+/// what sort of event you'd like to count when the `Counter` is created, then
+/// you can enable and disable the counter, call its [`read`] method to
+/// retrieve the current count, and reset it to zero.
+///
+/// A `Counter`'s value is always a `u64`.
+///
+/// For example, this counts the number of instructions retired (completed)
+/// during a call to `println!`.
+///
+/// use perf_event::Builder;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut counter = Builder::new().build()?;
+///
+/// let vec = (0..=51).collect::<Vec<_>>();
+///
+/// counter.enable()?;
+/// println!("{:?}", vec);
+/// counter.disable()?;
+///
+/// println!("{} instructions retired", counter.read()?);
+///
+/// Ok(())
+/// }
+///
+/// It is often useful to count several different quantities over the same
+/// period of time. For example, if you want to measure the average number of
+/// clock cycles used per instruction, you must count both clock cycles and
+/// instructions retired, for the same range of execution. The [`Group`] type
+/// lets you enable, disable, read, and reset any number of counters
+/// simultaneously.
+///
+/// When a counter is dropped, its kernel resources are freed along with it.
+///
+/// Internally, a `Counter` is just a wrapper around an event file descriptor.
+///
+/// [`read`]: Counter::read
+pub struct Counter {
+ /// The file descriptor for this counter, returned by `perf_event_open`.
+ ///
+ /// When a `Counter` is dropped, this `File` is dropped, and the kernel
+ /// removes the counter from any group it belongs to.
+ file: File,
+
+ /// The unique id assigned to this counter by the kernel.
+ id: u64,
+}
+
+/// A builder for [`Counter`]s.
+///
+/// There are dozens of parameters that influence a `Counter`'s behavior.
+/// `Builder` lets you construct a `Counter` by specifying only those parameters
+/// for which you don't want the default value.
+///
+/// A freshly built `Counter` is disabled. To begin counting events, you must
+/// call [`enable`] on the `Counter` or the `Group` to which it belongs.
+///
+/// Internally, a `Builder` is just a wrapper around the kernel's
+/// `struct perf_event_attr` type. See the [perf_event_open(2)] man page for details.
+///
+/// For example, if you want a `Counter` for instructions retired by the current
+/// process, those are `Builder`'s defaults, so you need only write:
+///
+/// # use perf_event::Builder;
+/// # fn main() -> std::io::Result<()> {
+/// let mut insns = Builder::new().build()?;
+/// # Ok(()) }
+///
+/// The [`kind`] method lets you specify what sort of event you want to
+/// count. So if you'd rather count branch instructions:
+///
+/// # use perf_event::Builder;
+/// # use perf_event::events::Hardware;
+/// # fn main() -> std::io::Result<()> {
+/// let mut insns = Builder::new()
+/// .kind(Hardware::BRANCH_INSTRUCTIONS)
+/// .build()?;
+/// # Ok(()) }
+///
+/// The [`group`] method lets you gather individual counters into `Group`
+/// that can be enabled or disabled atomically:
+///
+/// # use perf_event::{Builder, Group};
+/// # use perf_event::events::Hardware;
+/// # fn main() -> std::io::Result<()> {
+/// let mut group = Group::new()?;
+/// let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
+/// let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
+/// # Ok(()) }
+///
+/// Other methods let you select:
+///
+/// - specific processes or cgroups to observe
+/// - specific CPU cores to observe
+///
+/// `Builder` supports only a fraction of the many knobs and dials Linux offers,
+/// but hopefully it will acquire methods to support more of them as time goes
+/// on.
+///
+/// [`enable`]: Counter::enable
+/// [`kind`]: Builder::kind
+/// [`group`]: Builder::group
+/// [perf_event_open(2)]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
+pub struct Builder<'a> {
+ attrs: perf_event_attr,
+ who: EventPid<'a>,
+ cpu: Option<usize>,
+ group: Option<&'a mut Group>,
+}
+
+#[derive(Debug)]
+enum EventPid<'a> {
+ /// Monitor the calling process.
+ ThisProcess,
+
+ /// Monitor the given pid.
+ Other(pid_t),
+
+ /// Monitor members of the given cgroup.
+ CGroup(&'a File),
+}
+
+/// A group of counters that can be managed as a unit.
+///
+/// A `Group` represents a group of [`Counter`]s that can be enabled,
+/// disabled, reset, or read as a single atomic operation. This is necessary if
+/// you want to compare counter values, produce ratios, and so on, since those
+/// operations are only meaningful on counters that cover exactly the same
+/// period of execution.
+///
+/// A `Counter` is placed in a group when it is created, by calling the
+/// `Builder`'s [`group`] method. A `Group`'s [`read`] method returns values
+/// of all its member counters at once as a [`Counts`] value, which can be
+/// indexed by `Counter` to retrieve a specific value.
+///
+/// For example, the following program computes the average number of cycles
+/// used per instruction retired for a call to `println!`:
+///
+/// # fn main() -> std::io::Result<()> {
+/// use perf_event::{Builder, Group};
+/// use perf_event::events::Hardware;
+///
+/// let mut group = Group::new()?;
+/// let cycles = Builder::new().group(&mut group).kind(Hardware::CPU_CYCLES).build()?;
+/// let insns = Builder::new().group(&mut group).kind(Hardware::INSTRUCTIONS).build()?;
+///
+/// let vec = (0..=51).collect::<Vec<_>>();
+///
+/// group.enable()?;
+/// println!("{:?}", vec);
+/// group.disable()?;
+///
+/// let counts = group.read()?;
+/// println!("cycles / instructions: {} / {} ({:.2} cpi)",
+/// counts[&cycles],
+/// counts[&insns],
+/// (counts[&cycles] as f64 / counts[&insns] as f64));
+/// # Ok(()) }
+///
+/// The lifetimes of `Counter`s and `Group`s are independent: placing a
+/// `Counter` in a `Group` does not take ownership of the `Counter`, nor must
+/// the `Counter`s in a group outlive the `Group`. If a `Counter` is dropped, it
+/// is simply removed from its `Group`, and omitted from future results. If a
+/// `Group` is dropped, its individual counters continue to count.
+///
+/// Enabling or disabling a `Group` affects each `Counter` that belongs to it.
+/// Subsequent reads from the `Counter` will not reflect activity while the
+/// `Group` was disabled, unless the `Counter` is re-enabled individually.
+///
+/// A `Group` and its members must all observe the same tasks and cpus; mixing
+/// these makes building the `Counter` return an error. Unfortunately, there is
+/// no way at present to specify a `Group`'s task and cpu, so you can only use
+/// `Group` on the calling task. If this is a problem, please file an issue.
+///
+/// Internally, a `Group` is just a wrapper around an event file descriptor.
+///
+/// ## Limits on group size
+///
+/// Hardware counters are implemented using special-purpose registers on the
+/// processor, of which there are only a fixed number. (For example, an Intel
+/// high-end laptop processor from 2015 has four such registers per virtual
+/// processor.) Without using groups, if you request more hardware counters than
+/// the processor can actually support, a complete count isn't possible, but the
+/// kernel will rotate the processor's real registers amongst the measurements
+/// you've requested to at least produce a sample.
+///
+/// But since the point of a counter group is that its members all cover exactly
+/// the same period of time, this tactic can't be applied to support large
+/// groups. If the kernel cannot schedule a group, its counters remain zero. I
+/// think you can detect this situation by comparing the group's [`time_enabled`]
+/// and [`time_running`] values. It might also be useful to set the `pinned` bit,
+/// which puts the counter in an error state if it's not able to be put on the
+/// CPU; see [#10].
+///
+/// According to the `perf_list(1)` man page, you may be able to free up a
+/// hardware counter by disabling the kernel's NMI watchdog, which reserves one
+/// for detecting kernel hangs:
+///
+/// ```ignore
+/// $ echo 0 > /proc/sys/kernel/nmi_watchdog
+/// ```
+///
+/// You can reenable the watchdog when you're done like this:
+///
+/// ```ignore
+/// $ echo 1 > /proc/sys/kernel/nmi_watchdog
+/// ```
+///
+/// [`group`]: Builder::group
+/// [`read`]: Group::read
+/// [`#5`]: https://github.com/jimblandy/perf-event/issues/5
+/// [`#10`]: https://github.com/jimblandy/perf-event/issues/10
+/// [`time_enabled`]: Counts::time_enabled
+/// [`time_running`]: Counts::time_running
+pub struct Group {
+ /// The file descriptor for this counter, returned by `perf_event_open`.
+ /// This counter itself is for the dummy software event, so it's not
+ /// interesting.
+ file: File,
+
+ /// The unique id assigned to this group by the kernel. We only use this for
+ /// assertions.
+ id: u64,
+
+ /// An upper bound on the number of Counters in this group. This lets us
+ /// allocate buffers of sufficient size for for PERF_FORMAT_GROUP reads.
+ ///
+ /// There's no way to ask the kernel how many members a group has. And if we
+ /// pass a group read a buffer that's too small, the kernel won't just
+ /// return a truncated result; it returns ENOSPC and leaves the buffer
+ /// untouched. So the buffer just has to be large enough.
+ ///
+ /// Since we're borrowed while building group members, adding members can
+ /// increment this counter. But it's harder to decrement it when a member
+ /// gets dropped: we don't require that a Group outlive its members, so they
+ /// can't necessarily update their `Group`'s count from a `Drop` impl. So we
+ /// just increment, giving us an overestimate, and then correct the count
+ /// when we actually do a read.
+ ///
+ /// This includes the dummy counter for the group itself.
+ max_members: usize
+}
+
+/// A collection of counts from a [`Group`] of counters.
+///
+/// This is the type returned by calling [`read`] on a [`Group`].
+/// You can index it with a reference to a specific `Counter`:
+///
+/// # fn main() -> std::io::Result<()> {
+/// # use perf_event::{Builder, Group};
+/// # let mut group = Group::new()?;
+/// # let cycles = Builder::new().group(&mut group).build()?;
+/// # let insns = Builder::new().group(&mut group).build()?;
+/// let counts = group.read()?;
+/// println!("cycles / instructions: {} / {} ({:.2} cpi)",
+/// counts[&cycles],
+/// counts[&insns],
+/// (counts[&cycles] as f64 / counts[&insns] as f64));
+/// # Ok(()) }
+///
+/// Or you can iterate over the results it contains:
+///
+/// # fn main() -> std::io::Result<()> {
+/// # use perf_event::Group;
+/// # let counts = Group::new()?.read()?;
+/// for (id, value) in &counts {
+/// println!("Counter id {} has value {}", id, value);
+/// }
+/// # Ok(()) }
+///
+/// The `id` values produced by this iteration are internal identifiers assigned
+/// by the kernel. You can use the [`Counter::id`] method to find a
+/// specific counter's id.
+///
+/// For some kinds of events, the kernel may use timesharing to give all
+/// counters access to scarce hardware registers. You can see how long a group
+/// was actually running versus the entire time it was enabled using the
+/// `time_enabled` and `time_running` methods:
+///
+/// # fn main() -> std::io::Result<()> {
+/// # use perf_event::{Builder, Group};
+/// # let mut group = Group::new()?;
+/// # let insns = Builder::new().group(&mut group).build()?;
+/// # let counts = group.read()?;
+/// let scale = counts.time_enabled() as f64 /
+/// counts.time_running() as f64;
+/// for (id, value) in &counts {
+/// print!("Counter id {} has value {}",
+/// id, (*value as f64 * scale) as u64);
+/// if scale > 1.0 {
+/// print!(" (estimated)");
+/// }
+/// println!();
+/// }
+///
+/// # Ok(()) }
+///
+/// [`read`]: Group::read
+pub struct Counts {
+ // Raw results from the `read`.
+ data: Vec<u64>
+}
+
+/// The value of a counter, along with timesharing data.
+///
+/// Some counters are implemented in hardware, and the processor can run
+/// only a fixed number of them at a time. If more counters are requested
+/// than the hardware can support, the kernel timeshares them on the
+/// hardware.
+///
+/// This struct holds the value of a counter, together with the time it was
+/// enabled, and the proportion of that for which it was actually running.
+#[repr(C)]
+pub struct CountAndTime {
+ /// The counter value.
+ ///
+ /// The meaning of this field depends on how the counter was configured when
+ /// it was built; see ['Builder'].
+ pub count: u64,
+
+ /// How long this counter was enabled by the program, in nanoseconds.
+ pub time_enabled: u64,
+
+ /// How long the kernel actually ran this counter, in nanoseconds.
+ ///
+ /// If `time_enabled == time_running`, then the counter ran for the entire
+ /// period it was enabled, without interruption. Otherwise, the counter
+ /// shared the underlying hardware with others, and you should prorate its
+ /// value accordingly.
+ pub time_running: u64,
+}
+
+impl<'a> EventPid<'a> {
+ // Return the `pid` arg and the `flags` bits representing `self`.
+ fn as_args(&self) -> (pid_t, u32) {
+ match self {
+ EventPid::ThisProcess => (0, 0),
+ EventPid::Other(pid) => (*pid, 0),
+ EventPid::CGroup(file) =>
+ (file.as_raw_fd(), sys::bindings::PERF_FLAG_PID_CGROUP),
+ }
+ }
+}
+
+impl<'a> Default for Builder<'a> {
+ fn default() -> Builder<'a> {
+
+ let mut attrs = perf_event_attr::default();
+
+ // Setting `size` accurately will not prevent the code from working
+ // on older kernels. The module comments for `perf_event_open_sys`
+ // explain why in far too much detail.
+ attrs.size = std::mem::size_of::<perf_event_attr>() as u32;
+
+ attrs.set_disabled(1);
+ attrs.set_exclude_kernel(1); // don't count time in kernel
+ attrs.set_exclude_hv(1); // don't count time in hypervisor
+
+ // Request data for `time_enabled` and `time_running`.
+ attrs.read_format |= sys::bindings::perf_event_read_format_PERF_FORMAT_TOTAL_TIME_ENABLED as u64 |
+ sys::bindings::perf_event_read_format_PERF_FORMAT_TOTAL_TIME_RUNNING as u64;
+
+ let kind = Event::Hardware(events::Hardware::INSTRUCTIONS);
+ attrs.type_ = kind.as_type();
+ attrs.config = kind.as_config();
+
+ Builder {
+ attrs,
+ who: EventPid::ThisProcess,
+ cpu: None,
+ group: None,
+ }
+ }
+}
+
+impl<'a> Builder<'a> {
+ /// Return a new `Builder`, with all parameters set to their defaults.
+ pub fn new() -> Builder<'a> {
+ Builder::default()
+ }
+
+ /// Observe the calling process. (This is the default.)
+ pub fn observe_self(mut self) -> Builder<'a> {
+ self.who = EventPid::ThisProcess;
+ self
+ }
+
+ /// Observe the process with the given process id. This requires
+ /// [`CAP_SYS_PTRACE`][man-capabilities] capabilities.
+ ///
+ /// [man-capabilities]: http://man7.org/linux/man-pages/man7/capabilities.7.html
+ pub fn observe_pid(mut self, pid: pid_t) -> Builder<'a> {
+ self.who = EventPid::Other(pid);
+ self
+ }
+
+ /// Observe code running in the given [cgroup][man-cgroups] (container). The
+ /// `cgroup` argument should be a `File` referring to the cgroup's directory
+ /// in the cgroupfs filesystem.
+ ///
+ /// [man-cgroups]: http://man7.org/linux/man-pages/man7/cgroups.7.html
+ pub fn observe_cgroup(mut self, cgroup: &'a File) -> Builder<'a> {
+ self.who = EventPid::CGroup(cgroup);
+ self
+ }
+
+ /// Observe only code running on the given CPU core.
+ pub fn one_cpu(mut self, cpu: usize) -> Builder<'a> {
+ self.cpu = Some(cpu);
+ self
+ }
+
+ /// Observe code running on any CPU core. (This is the default.)
+ pub fn any_cpu(mut self) -> Builder<'a> {
+ self.cpu = None;
+ self
+ }
+
+ /// Set whether this counter is inherited by new threads.
+ ///
+ /// When this flag is set, this counter observes activity in new threads
+ /// created by any thread already being observed.
+ ///
+ /// By default, the flag is unset: counters are not inherited, and observe
+ /// only the threads specified when they are created.
+ ///
+ /// This flag cannot be set if the counter belongs to a `Group`. Doing so
+ /// will result in an error when the counter is built. This is a kernel
+ /// limitation.
+ pub fn inherit(mut self, inherit: bool) -> Builder<'a> {
+ let flag = if inherit { 1 } else { 0 };
+ self.attrs.set_inherit(flag);
+ self
+ }
+
+ /// Count events of the given kind. This accepts an [`Event`] value,
+ /// or any type that can be converted to one, so you can pass [`Hardware`],
+ /// [`Software`] and [`Cache`] values directly.
+ ///
+ /// The default is to count retired instructions, or
+ /// `Hardware::INSTRUCTIONS` events.
+ ///
+ /// For example, to count level 1 data cache references and misses, pass the
+ /// appropriate `events::Cache` values:
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// use perf_event::{Builder, Group};
+ /// use perf_event::events::{Cache, CacheOp, CacheResult, WhichCache};
+ ///
+ /// const ACCESS: Cache = Cache {
+ /// which: WhichCache::L1D,
+ /// operation: CacheOp::READ,
+ /// result: CacheResult::ACCESS,
+ /// };
+ /// const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
+ ///
+ /// let mut group = Group::new()?;
+ /// let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
+ /// let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
+ /// # Ok(()) }
+ ///
+ /// [`Hardware`]: events::Hardware
+ /// [`Software`]: events::Software
+ /// [`Cache`]: events::Cache
+ pub fn kind<K: Into<Event>>(mut self, kind: K) -> Builder<'a> {
+ let kind = kind.into();
+ self.attrs.type_ = kind.as_type();
+ self.attrs.config = kind.as_config();
+ self
+ }
+
+ /// Place the counter in the given [`Group`]. Groups allow a set of counters
+ /// to be enabled, disabled, or read as a single atomic operation, so that
+ /// the counts can be usefully compared.
+ ///
+ /// [`Group`]: struct.Group.html
+ pub fn group(mut self, group: &'a mut Group) -> Builder<'a> {
+ self.group = Some(group);
+
+ // man page: "Members of a group are usually initialized with disabled
+ // set to zero."
+ self.attrs.set_disabled(0);
+
+ self
+ }
+
+ /// Construct a [`Counter`] according to the specifications made on this
+ /// `Builder`.
+ ///
+ /// A freshly built `Counter` is disabled. To begin counting events, you
+ /// must call [`enable`] on the `Counter` or the `Group` to which it belongs.
+ ///
+ /// If the `Builder` requests features that the running kernel does not
+ /// support, it returns `Err(e)` where `e.kind() == ErrorKind::Other` and
+ /// `e.raw_os_error() == Some(libc::E2BIG)`.
+ ///
+ /// Unfortunately, problems in counter configuration are detected at this
+ /// point, by the kernel, not earlier when the offending request is made on
+ /// the `Builder`. The kernel's returned errors are not always helpful.
+ ///
+ /// [`Counter`]: struct.Counter.html
+ /// [`enable`]: struct.Counter.html#method.enable
+ pub fn build(mut self) -> std::io::Result<Counter> {
+ let cpu = match self.cpu {
+ Some(cpu) => cpu as c_int,
+ None => -1,
+ };
+ let (pid, flags) = self.who.as_args();
+ let group_fd = match self.group {
+ Some(ref mut g) => {
+ g.max_members += 1;
+ g.file.as_raw_fd() as c_int
+ }
+ None => -1,
+ };
+
+ let file = unsafe {
+ File::from_raw_fd(check_raw_syscall(|| {
+ sys::perf_event_open(&mut self.attrs, pid, cpu, group_fd, flags as c_ulong)
+ })?)
+ };
+
+ // If we're going to be part of a Group, retrieve the ID the kernel
+ // assigned us, so we can find our results in a Counts structure. Even
+ // if we're not part of a group, we'll use it in `Debug` output.
+ let mut id = 0_64;
+ check_errno_syscall(|| unsafe {
+ sys::ioctls::ID(file.as_raw_fd(), &mut id)
+ })?;
+
+ Ok(Counter { file, id, })
+ }
+}
+
+impl Counter {
+ /// Return this counter's kernel-assigned unique id.
+ ///
+ /// This can be useful when iterating over [`Counts`].
+ ///
+ /// [`Counts`]: struct.Counts.html
+ pub fn id(&self) -> u64 {
+ self.id
+ }
+
+ /// Allow this `Counter` to begin counting its designated event.
+ ///
+ /// This does not affect whatever value the `Counter` had previously; new
+ /// events add to the current count. To clear a `Counter`, use the
+ /// [`reset`] method.
+ ///
+ /// Note that `Group` also has an [`enable`] method, which enables all
+ /// its member `Counter`s as a single atomic operation.
+ ///
+ /// [`reset`]: #method.reset
+ /// [`enable`]: struct.Group.html#method.enable
+ pub fn enable(&mut self) -> io::Result<()> {
+ check_errno_syscall(|| unsafe {
+ sys::ioctls::ENABLE(self.file.as_raw_fd(), 0)
+ }).map(|_| ())
+ }
+
+ /// Make this `Counter` stop counting its designated event. Its count is
+ /// unaffected.
+ ///
+ /// Note that `Group` also has a [`disable`] method, which disables all
+ /// its member `Counter`s as a single atomic operation.
+ ///
+ /// [`disable`]: struct.Group.html#method.disable
+ pub fn disable(&mut self) -> io::Result<()> {
+ check_errno_syscall(|| unsafe {
+ sys::ioctls::DISABLE(self.file.as_raw_fd(), 0)
+ }).map(|_| ())
+ }
+
+ /// Reset the value of this `Counter` to zero.
+ ///
+ /// Note that `Group` also has a [`reset`] method, which resets all
+ /// its member `Counter`s as a single atomic operation.
+ ///
+ /// [`reset`]: struct.Group.html#method.reset
+ pub fn reset(&mut self) -> io::Result<()> {
+ check_errno_syscall(|| unsafe {
+ sys::ioctls::RESET(self.file.as_raw_fd(), 0)
+ }).map(|_| ())
+ }
+
+ /// Return this `Counter`'s current value as a `u64`.
+ ///
+ /// Consider using the [`read_count_and_time`] method instead of this one. Some
+ /// counters are implemented in hardware, and the processor can support only
+ /// a certain number running at a time. If more counters are requested than
+ /// the hardware can support, the kernel timeshares them on the hardware.
+ /// This method gives you no indication whether this has happened;
+ /// `read_count_and_time` does.
+ ///
+ /// Note that `Group` also has a [`read`] method, which reads all
+ /// its member `Counter`s' values at once.
+ ///
+ /// [`read`]: Group::read
+ /// [`read_count_and_time`]: Counter::read_count_and_time
+ pub fn read(&mut self) -> io::Result<u64> {
+ Ok(self.read_count_and_time()?.count)
+ }
+
+ /// Return this `Counter`'s current value and timesharing data.
+ ///
+ /// Some counters are implemented in hardware, and the processor can run
+ /// only a fixed number of them at a time. If more counters are requested
+ /// than the hardware can support, the kernel timeshares them on the
+ /// hardware.
+ ///
+ /// This method returns a [`CountAndTime`] struct, whose `count` field holds
+ /// the counter's value, and whose `time_enabled` and `time_running` fields
+ /// indicate how long you had enabled the counter, and how long the counter
+ /// was actually scheduled on the processor. This lets you detect whether
+ /// the counter was timeshared, and adjust your use accordingly. Times
+ /// are reported in nanoseconds.
+ ///
+ /// # use perf_event::Builder;
+ /// # fn main() -> std::io::Result<()> {
+ /// # let mut counter = Builder::new().build()?;
+ /// let cat = counter.read_count_and_time()?;
+ /// if cat.time_running == 0 {
+ /// println!("No data collected.");
+ /// } else if cat.time_running < cat.time_enabled {
+ /// // Note: this way of scaling is accurate, but `u128` division
+ /// // is usually implemented in software, which may be slow.
+ /// println!("{} instructions (estimated)",
+ /// (cat.count as u128 *
+ /// cat.time_enabled as u128 / cat.time_running as u128) as u64);
+ /// } else {
+ /// println!("{} instructions", cat.count);
+ /// }
+ /// # Ok(()) }
+ ///
+ /// Note that `Group` also has a [`read`] method, which reads all
+ /// its member `Counter`s' values at once.
+ ///
+ /// [`read`]: Group::read
+ pub fn read_count_and_time(&mut self) -> io::Result<CountAndTime> {
+ let mut buf = [0_u64; 3];
+ self.file.read_exact(u64::slice_as_bytes_mut(&mut buf))?;
+
+ let cat = CountAndTime {
+ count: buf[0],
+ time_enabled: buf[1],
+ time_running: buf[2],
+ };
+
+ // Does the kernel ever return nonsense?
+ assert!(cat.time_running <= cat.time_enabled);
+
+ Ok(cat)
+ }
+}
+
+impl std::fmt::Debug for Counter {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(fmt, "Counter {{ fd: {}, id: {} }}",
+ self.file.as_raw_fd(), self.id)
+ }
+}
+
+impl Group {
+ /// Construct a new, empty `Group`.
+ #[allow(unused_parens)]
+ pub fn new() -> io::Result<Group> {
+ // Open a placeholder perf counter that we can add other events to.
+ let mut attrs = perf_event_attr::default();
+ attrs.size = std::mem::size_of::<perf_event_attr>() as u32;
+ attrs.type_ = sys::bindings::perf_type_id_PERF_TYPE_SOFTWARE;
+ attrs.config = sys::bindings::perf_sw_ids_PERF_COUNT_SW_DUMMY as u64;
+ attrs.set_disabled(1);
+ attrs.set_exclude_kernel(1);
+ attrs.set_exclude_hv(1);
+
+ // Arrange to be able to identify the counters we read back.
+ attrs.read_format = (sys::bindings::perf_event_read_format_PERF_FORMAT_TOTAL_TIME_ENABLED |
+ sys::bindings::perf_event_read_format_PERF_FORMAT_TOTAL_TIME_RUNNING |
+ sys::bindings::perf_event_read_format_PERF_FORMAT_ID |
+ sys::bindings::perf_event_read_format_PERF_FORMAT_GROUP) as u64;
+
+ let file = unsafe {
+ File::from_raw_fd(check_raw_syscall(|| {
+ sys::perf_event_open(&mut attrs, 0, -1, -1, 0)
+ })?)
+ };
+
+ // Retrieve the ID the kernel assigned us.
+ let mut id = 0_64;
+ check_errno_syscall(|| unsafe {
+ sys::ioctls::ID(file.as_raw_fd(), &mut id)
+ })?;
+
+ Ok(Group { file, id, max_members: 1 })
+ }
+
+ /// Allow all `Counter`s in this `Group` to begin counting their designated
+ /// events, as a single atomic operation.
+ ///
+ /// This does not affect whatever values the `Counter`s had previously; new
+ /// events add to the current counts. To clear the `Counter`s, use the
+ /// [`reset`] method.
+ ///
+ /// [`reset`]: #method.reset
+ pub fn enable(&mut self) -> io::Result<()> {
+ self.generic_ioctl(sys::ioctls::ENABLE)
+ }
+
+ /// Make all `Counter`s in this `Group` stop counting their designated
+ /// events, as a single atomic operation. Their counts are unaffected.
+ pub fn disable(&mut self) -> io::Result<()> {
+ self.generic_ioctl(sys::ioctls::DISABLE)
+ }
+
+ /// Reset all `Counter`s in this `Group` to zero, as a single atomic operation.
+ pub fn reset(&mut self) -> io::Result<()> {
+ self.generic_ioctl(sys::ioctls::RESET)
+ }
+
+ /// Perform some group ioctl.
+ ///
+ /// `f` must be a syscall that sets `errno` and returns `-1` on failure.
+ fn generic_ioctl(&mut self, f: unsafe fn(c_int, c_uint) -> c_int) -> io::Result<()> {
+ check_errno_syscall(|| unsafe {
+ f(self.file.as_raw_fd(),
+ sys::bindings::perf_event_ioc_flags_PERF_IOC_FLAG_GROUP)
+ }).map(|_| ())
+ }
+
+ /// Return the values of all the `Counter`s in this `Group` as a [`Counts`]
+ /// value.
+ ///
+ /// A `Counts` value is a map from specific `Counter`s to their values. You
+ /// can find a specific `Counter`'s value by indexing:
+ ///
+ /// ```ignore
+ /// let mut group = Group::new()?;
+ /// let counter1 = Builder::new().group(&mut group).kind(...).build()?;
+ /// let counter2 = Builder::new().group(&mut group).kind(...).build()?;
+ /// ...
+ /// let counts = group.read()?;
+ /// println!("Rhombus inclinations per taxi medallion: {} / {} ({:.0}%)",
+ /// counts[&counter1],
+ /// counts[&counter2],
+ /// (counts[&counter1] as f64 / counts[&counter2] as f64) * 100.0);
+ /// ```
+ ///
+ /// [`Counts`]: struct.Counts.html
+ pub fn read(&mut self) -> io::Result<Counts> {
+ // Since we passed `PERF_FORMAT_{ID,GROUP,TOTAL_TIME_{ENABLED,RUNNING}}`,
+ // the data we'll read has the form:
+ //
+ // struct read_format {
+ // u64 nr; /* The number of events */
+ // u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
+ // u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
+ // struct {
+ // u64 value; /* The value of the event */
+ // u64 id; /* if PERF_FORMAT_ID */
+ // } values[nr];
+ // };
+ let mut data = vec![0_u64; 3 + 2 * self.max_members];
+ self.file.read(u64::slice_as_bytes_mut(&mut data))?;
+
+ let counts = Counts { data };
+
+ // CountsIter assumes that the group's dummy count appears first.
+ assert_eq!(counts.nth_ref(0).0, self.id);
+
+ // Does the kernel ever return nonsense?
+ assert!(counts.time_running() <= counts.time_enabled());
+
+ // Update `max_members` for the next read.
+ self.max_members = counts.len();
+
+ Ok(counts)
+ }
+}
+
+impl std::fmt::Debug for Group {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(fmt, "Group {{ fd: {}, id: {} }}",
+ self.file.as_raw_fd(), self.id)
+ }
+}
+
+impl Counts {
+ /// Return the number of counters this `Counts` holds results for.
+ pub fn len(&self) -> usize {
+ self.data[0] as usize
+ }
+
+ /// Return the number of nanoseconds the `Group` was enabled that
+ /// contributed to this `Counts`' contents.
+ pub fn time_enabled(&self) -> u64 {
+ self.data[1]
+ }
+
+ /// Return the number of nanoseconds the `Group` was actually collecting
+ /// counts that contributed to this `Counts`' contents.
+ pub fn time_running(&self) -> u64 {
+ self.data[2]
+ }
+
+ /// Return a range of indexes covering the count and id of the `n`'th counter.
+ fn nth_index(n: usize) -> std::ops::Range<usize> {
+ let base = 3 + 2 * n;
+ base .. base + 2
+ }
+
+ /// Return the id and count of the `n`'th counter. This returns a reference
+ /// to the count, for use by the `Index` implementation.
+ fn nth_ref(&self, n: usize) -> (u64, &u64) {
+ let id_val = &self.data[Counts::nth_index(n)];
+
+ // (id, &value)
+ (id_val[1], &id_val[0])
+ }
+}
+
+/// An iterator over the counter values in a [`Counts`], returned by
+/// [`Group::read`].
+///
+/// Each item is a pair `(id, &value)`, where `id` is the number assigned to the
+/// counter by the kernel (see `Counter::id`), and `value` is that counter's
+/// value.
+///
+/// [`Counts`]: struct.Counts.html
+/// [`Counter::id`]: struct.Counter.html#method.id
+/// [`Group::read`]: struct.Group.html#method.read
+pub struct CountsIter<'c> {
+ counts: &'c Counts,
+ next: usize
+}
+
+impl<'c> Iterator for CountsIter<'c> {
+ type Item = (u64, &'c u64);
+ fn next(&mut self) -> Option<(u64, &'c u64)> {
+ if self.next >= self.counts.len() {
+ return None;
+ }
+ let result = self.counts.nth_ref(self.next);
+ self.next += 1;
+ return Some(result);
+ }
+}
+
+impl<'c> IntoIterator for &'c Counts {
+ type Item = (u64, &'c u64);
+ type IntoIter = CountsIter<'c>;
+ fn into_iter(self) -> CountsIter<'c> {
+ CountsIter {
+ counts: self,
+ next: 1, // skip the `Group` itself, it's just a dummy.
+ }
+ }
+}
+
+impl Counts {
+ /// Return the value recorded for `member` in `self`, or `None` if `member`
+ /// is not present.
+ ///
+ /// If you know that `member` is in the group, you can simply index:
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// # use perf_event::{Builder, Group};
+ /// # let mut group = Group::new()?;
+ /// # let cycle_counter = Builder::new().group(&mut group).build()?;
+ /// # let counts = group.read()?;
+ /// let cycles = counts[&cycle_counter];
+ /// # Ok(()) }
+ pub fn get(&self, member: &Counter) -> Option<&u64> {
+ self.into_iter()
+ .find(|&(id, _)| id == member.id)
+ .map(|(_, value)| value)
+ }
+
+ /// Return an iterator over the counts in `self`.
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// # use perf_event::Group;
+ /// # let counts = Group::new()?.read()?;
+ /// for (id, value) in &counts {
+ /// println!("Counter id {} has value {}", id, value);
+ /// }
+ /// # Ok(()) }
+ ///
+ /// Each item is a pair `(id, &value)`, where `id` is the number assigned to
+ /// the counter by the kernel (see `Counter::id`), and `value` is that
+ /// counter's value.
+ pub fn iter(&self) -> CountsIter {
+ <&Counts as IntoIterator>::into_iter(self)
+ }
+}
+
+impl std::ops::Index<&Counter> for Counts {
+ type Output = u64;
+ fn index(&self, index: &Counter) -> &u64 {
+ self.get(index).unwrap()
+ }
+}
+
+impl std::fmt::Debug for Counts {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fmt.debug_map().entries(self.into_iter()).finish()
+ }
+}
+
+unsafe trait SliceAsBytesMut: Sized {
+ fn slice_as_bytes_mut(slice: &mut [Self]) -> &mut [u8] {
+ unsafe {
+ std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8,
+ std::mem::size_of_val(slice))
+ }
+ }
+}
+
+unsafe impl SliceAsBytesMut for u64 { }
+
+/// Produce an `io::Result` from a raw system call.
+///
+/// A 'raw' system call is one that reports failure by returning negated raw OS
+/// error value.
+fn check_raw_syscall<F>(f: F) -> io::Result<c_int>
+where F: FnOnce() -> c_int
+{
+ let result = f();
+ if result < 0 {
+ Err(io::Error::from_raw_os_error(-result))
+ } else {
+ Ok(result)
+ }
+}
+
+/// Produce an `io::Result` from an errno-style system call.
+///
+/// An 'errno-style' system call is one that reports failure by returning -1 and
+/// setting the C `errno` value when an error occurs.
+fn check_errno_syscall<F, R>(f: F) -> io::Result<R>
+where F: FnOnce() -> R,
+ R: PartialOrd + Default
+{
+ let result = f();
+ if result < R::default() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(result)
+ }
+}
+
+#[test]
+fn simple_build() {
+ Builder::new().build().expect("Couldn't build default Counter");
+}
diff --git a/vendor/perf-event/wrapper.h b/vendor/perf-event/wrapper.h
new file mode 100644
index 000000000..b60268317
--- /dev/null
+++ b/vendor/perf-event/wrapper.h
@@ -0,0 +1,20 @@
+// This file is consumed by bindgen, called from our build.rs file.
+
+#include <linux/perf_event.h>
+#include <asm/unistd.h>
+
+// bindgen won't capture
+enum perf_event_ioctls {
+ ENABLE = PERF_EVENT_IOC_ENABLE,
+ DISABLE = PERF_EVENT_IOC_DISABLE,
+ REFRESH = PERF_EVENT_IOC_REFRESH,
+ RESET = PERF_EVENT_IOC_RESET,
+ PERIOD = PERF_EVENT_IOC_PERIOD,
+ SET_OUTPUT = PERF_EVENT_IOC_SET_OUTPUT,
+ SET_FILTER = PERF_EVENT_IOC_SET_FILTER,
+ ID = PERF_EVENT_IOC_ID,
+ SET_BPF = PERF_EVENT_IOC_SET_BPF,
+ PAUSE_OUTPUT = PERF_EVENT_IOC_PAUSE_OUTPUT,
+ QUERY_BPF = PERF_EVENT_IOC_QUERY_BPF,
+ MODIFY_ATTRIBUTES = PERF_EVENT_IOC_MODIFY_ATTRIBUTES,
+};