Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ringbuf: Add event counters #1621

Merged
merged 18 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/gimlet/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

fn main() {
build_util::expose_target_board();
build_util::expose_m_profile();
build_util::expose_m_profile().unwrap();
}
6 changes: 3 additions & 3 deletions build/util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub fn has_feature(s: &str) -> bool {
///
/// This will set one of `cfg(armv6m)`, `cfg(armv7m)`, or `cfg(armv8m)`
/// depending on the value of the `TARGET` environment variable.
pub fn expose_m_profile() {
pub fn expose_m_profile() -> Result<()> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was necessary because I added an examples/ dir to ringbuf, and the cargo test run on CI for the host target attempts to build examples as well as running tests. Since ringbuf depends on static_cell (and now, on armv6m-atomic-hack as well), building ringbuf calls expose_m_profile, which panics on x86_64 build hosts. Therefore, I've changed this method to return a Result instead, which the libs that can reasonably be built for x86_64 (ringbuf, static-cell, armv6m-atomic-hack) turn into a warning, as we only need to determine ARM profile for ARM targets, while the crates that only build for ARM unwrap, maintaining the previous behavior of failing the build if built for a non-ARM target.

This, unfortunately, required changing a bunch of build scritps as well. Sorry about the big diff!

let target = crate::target();

if target.starts_with("thumbv6m") {
Expand All @@ -67,9 +67,9 @@ pub fn expose_m_profile() {
} else if target.starts_with("thumbv8m") {
println!("cargo:rustc-cfg=armv8m");
} else {
println!("Don't know the target {}", target);
std::process::exit(1);
bail!("Don't know the target {target}");
}
Ok(())
}

/// Returns the `HUBRIS_BOARD` envvar, if set.
Expand Down
4 changes: 2 additions & 2 deletions drv/gimlet-seq-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ include!(concat!(env!("OUT_DIR"), "/i2c_config.rs"));
)]
mod payload;

#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, ringbuf::Count)]
enum Trace {
Ice40Rails(bool, bool),
IdentValid(bool),
Expand Down Expand Up @@ -112,7 +112,7 @@ enum Trace {
None,
}

ringbuf!(Trace, 128, Trace::None);
counted_ringbuf!(Trace, 128, Trace::None);

#[export_name = "main"]
fn main() -> ! {
Expand Down
5 changes: 4 additions & 1 deletion lib/armv6m-atomic-hack/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

fn main() {
build_util::expose_m_profile();
match build_util::expose_m_profile() {
Ok(_) => (),
Err(e) => println!("cargo:warn={e}"),
}
}
7 changes: 7 additions & 0 deletions lib/ringbuf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ edition = "2021"
# To disable a ring buffer (but leave it otherwise present), enable the
# "disabled" feature
disabled = []
# Enable deriving the `Count` trait
derive = ["ringbuf-macros"]
default = ["derive"]

[dependencies]
static-cell = { path = "../static-cell" }
ringbuf-macros = { path = "macros", optional = true }

[target.'cfg(target_arch = "arm")'.dependencies]
armv6m-atomic-hack = { path = "../armv6m-atomic-hack" }

[lib]
test = false
Expand Down
48 changes: 48 additions & 0 deletions lib/ringbuf/examples/counts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Demonstrates the use of `counted_ringbuf!` and friends.
hawkw marked this conversation as resolved.
Show resolved Hide resolved
//!
//! This example is primarily intended to be used with `cargo expand` to show
//! the macro-generated code for `#[derive(ringbuf::Count)]` and friends.
use ringbuf::*;

#[derive(ringbuf::Count, Debug, Copy, Clone, PartialEq, Eq)]
pub enum Event {
NothingHappened,
SomethingHappened,
SomethingElse(u32),
SecretThirdThing { secret: () },
}

counted_ringbuf!(Event, 16, Event::NothingHappened);
counted_ringbuf!(MY_NAMED_RINGBUF, Event, 16, Event::NothingHappened);

ringbuf!(NON_COUNTED_RINGBUF, Event, 16, Event::NothingHappened);

pub fn example() {
ringbuf_entry!(Event::SomethingHappened);
ringbuf_entry!(NON_COUNTED_RINGBUF, Event::SomethingHappened);
}

pub fn example_named() {
ringbuf_entry!(MY_NAMED_RINGBUF, Event::SomethingElse(420));
}

pub mod nested {
use super::Event;

ringbuf::counted_ringbuf!(Event, 16, Event::NothingHappened);

pub fn example() {
ringbuf::ringbuf_entry!(Event::SomethingHappened);
ringbuf::ringbuf_entry_root!(Event::SomethingElse(666));
ringbuf::ringbuf_entry_root!(
MY_NAMED_RINGBUF,
Event::SecretThirdThing { secret: () }
);
}
}

fn main() {}
12 changes: 12 additions & 0 deletions lib/ringbuf/macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "ringbuf-macros"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.78"
quote = "1.0.35"
syn = "2.0.48"
99 changes: 99 additions & 0 deletions lib/ringbuf/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate proc_macro;
hawkw marked this conversation as resolved.
Show resolved Hide resolved
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::{quote, ToTokens};
use syn::{parse_macro_input, DeriveInput};

/// Derives an implementation of the `ringbuf::Count` trait for the annotated
/// `enum` type.
///
/// Note that this macro can currently only be used on `enum` types.
#[proc_macro_derive(Count)]
pub fn derive_count(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
match gen_count_impl(input) {
Ok(tokens) => tokens.to_token_stream().into(),
Err(err) => err.to_compile_error().into(),
}
}

fn gen_count_impl(input: DeriveInput) -> Result<impl ToTokens, syn::Error> {
let name = &input.ident;
let data_enum = match input.data {
syn::Data::Enum(ref data_enum) => data_enum,
_ => {
return Err(syn::Error::new_spanned(
input,
"`ringbuf::Count` can only be derived for enums",
));
}
};
let variants = &data_enum.variants;
let len = variants.len();
let mut variant_names = Vec::with_capacity(len);
let mut variant_patterns = Vec::with_capacity(len);
for variant in variants {
let ident = &variant.ident;
variant_patterns.push(match variant.fields {
syn::Fields::Unit => quote! { #name::#ident => &counters.#ident },
syn::Fields::Named(_) => {
quote! { #name::#ident { .. } => &counters.#ident }
}
syn::Fields::Unnamed(_) => {
quote! { #name::#ident(..) => &counters.#ident }
}
});
variant_names.push(ident.clone());
}
let counts_ty = counts_ty(name);
let code = quote! {
#[doc = concat!(" Ringbuf entry total counts for [`", stringify!(#name), "`].")]
#[allow(nonstandard_style)]
pub struct #counts_ty {
#(
#[doc = concat!(
" The total number of times a [`",
stringify!(#name), "::", stringify!(#variant_names),
"`] entry"
)]
#[doc = " has been recorded by this ringbuf."]
pub #variant_names: core::sync::atomic::AtomicU32
),*
}

#[automatically_derived]
impl ringbuf::Count for #name {
type Counters = #counts_ty;

// This is intended for use in a static initializer, so the fact that every
// time the constant is used it will be a different instance is not a
// problem --- in fact, it's the desired behavior.
//
// `declare_interior_mutable_const` is really Not My Favorite Clippy
// Lint...
#[allow(clippy::declare_interior_mutable_const)]
const NEW_COUNTERS: #counts_ty = #counts_ty {
#(#variant_names: core::sync::atomic::AtomicU32::new(0)),*
};

fn count(&self, counters: &Self::Counters) {
#[cfg(all(target_arch = "arm", armv6m))]
use ringbuf::rmv6m_atomic_hack::AtomicU32Ext;

let counter = match self {
#(#variant_patterns),*
};
counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
}
};
Ok(code)
}

fn counts_ty(ident: &Ident) -> Ident {
Ident::new(&format!("{ident}Counts"), Span::call_site())
}
Loading
Loading