Skip to content

Commit

Permalink
feat(util): add cache padding inhibitor (#192)
Browse files Browse the repository at this point in the history
@jamesmunns' PR  #161 added a feature for disabling cache padding in
`cordyceps`. however, `mycelium-util` and `maitake` also cache pad some
values. this branch adds similar feature flags to those crates.

in `mycelium-util`, the flag controls the public `CachePadded` type,
which is used both internally and in `maitake`. in `maiktake`, the
feature just forwards to both `mycelium-util` and `cordyceps`' feature
flags.

Signed-off-by: Eliza Weisman <[email protected]>
  • Loading branch information
hawkw authored Jun 4, 2022
1 parent f89727d commit 0ba37ac
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 50 deletions.
3 changes: 2 additions & 1 deletion maitake/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ links = "maitake"

[features]
default = ["alloc"]
alloc = []
alloc = ["cordyceps/alloc"]
no-cache-pad = ["mycelium-util/no-cache-pad", "cordyceps/no-cache-pad"]

[dependencies]
mycelium-bitfield = { path = "../bitfield" }
Expand Down
2 changes: 2 additions & 0 deletions maitake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ The following features are available (this list is incomplete; you can help by [
| Feature | Default | Explanation |
| :--- | :--- | :--- |
| `alloc` | `true` | Enables [`liballoc`] dependency |
| `no-cache-pad` | `false` | Inhibits cache padding for the [`CachePadded`] struct. When this feature is NOT enabled, the size will be determined based on target platform. |

[`liballoc`]: https://doc.rust-lang.org/alloc/
[`CachePadded`]: https://mycelium.elizas.website/mycelium_util/sync/struct.cachepadded
3 changes: 3 additions & 0 deletions util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ version = "0.1.0"
authors = ["Eliza Weisman <[email protected]>"]
edition = "2018"
rust-version = "1.61.0"
readme = "README.md"

# See more keys and their definitions at
# https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = []
alloc = ["cordyceps/alloc"]
no-cache-pad = ["cordyceps/no-cache-pad"]

[dependencies]
tracing = { git = "https://github.com/tokio-rs/tracing", default_features = false, features = ["attributes"] }
Expand Down
19 changes: 19 additions & 0 deletions util/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# mycelium-util

a "standard library for programming in the [mycelium] kernel and related
libraries.

## features

The following features are available (this list is incomplete; you can help by [expanding it].)

[expanding it]: https://github.com/hawkw/mycelium/edit/main/util/README.md

| Feature | Default | Explanation |
| :--- | :--- | :--- |
| `no-cache-pad` | `false` | Inhibits cache padding for the [`CachePadded`] struct. When this feature is NOT enabled, the size will be determined based on target platform. |
| `alloc` | `false` | Enables [`liballoc`] dependency |

[mycelium]: https://mycelium.elizas.website
[`CachePadded`]: https://mycelium.elizas.website/mycelium_util/sync/struct.cachepadded
[`liballoc`]: https://doc.rust-lang.org/alloc/
3 changes: 1 addition & 2 deletions util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! A "standard library" for programming in the Mycelium kernel and related
//! libraries.
#![cfg_attr(docsrs, doc = include_str!("../README.md"))]
#![cfg_attr(target_os = "none", no_std)]
#![allow(unused_unsafe)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg, doc_cfg_hide))]
Expand Down
49 changes: 2 additions & 47 deletions util/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ pub mod once;
pub mod spin;
pub use self::once::{InitOnce, Lazy};

use core::{
fmt,
ops::{Deref, DerefMut},
};

mod cache_pad;
pub use self::cache_pad::CachePadded;
pub mod hint {
#[cfg(not(loom))]
pub use core::hint::spin_loop;
Expand All @@ -30,14 +27,6 @@ pub(crate) struct Backoff {
max: u8,
}

#[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))]
#[cfg_attr(
not(any(target_arch = "x86_64", target_arch = "aarch64")),
repr(align(64))
)]
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
pub struct CachePadded<T>(T);

// === impl Backoff ===

impl Backoff {
Expand Down Expand Up @@ -76,37 +65,3 @@ impl Default for Backoff {
Self::new()
}
}

// === impl CachePadded ===

impl<T> CachePadded<T> {
pub const fn new(value: T) -> Self {
Self(value)
}

pub fn into_inner(self) -> T {
self.0
}
}

impl<T> Deref for CachePadded<T> {
type Target = T;

#[inline]
fn deref(&self) -> &T {
&self.0
}
}

impl<T> DerefMut for CachePadded<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}

impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
108 changes: 108 additions & 0 deletions util/src/sync/cache_pad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use core::{
fmt,
ops::{Deref, DerefMut},
};

pub use self::inner::CachePadded;

/// When configured not to pad to cache alignment, just provide a no-op wrapper struct
/// This feature is useful for platforms with no data cache, such as many Cortex-M
/// targets.
#[cfg(feature = "no-cache-pad")]
mod inner {
/// Aligns the wrapped value to the size of a cache line.
///
/// This is used to avoid [false sharing] for values that may be
/// accessed concurrently.
///
/// # Size/Alignment
///
/// The size and alignment of this type depends on the target architecture,
/// and on whether or not the `no-cache-pad` feature flag is enabled.
///
/// When the `no-cache-pad` crate feature flag is enabled, this is simply a
/// no-op wrapper struct. This is intended for use on useful for platforms
/// with no data cache, such as many Cortex-M targets.
///
/// In other cases, this type is always aligned to the size of a cache line,
/// based on the target architecture. On `x86_64`/`aarch64`, a cache line is
/// 128 bytes. On all other targets, a cache line is assumed to 64 bytes
/// long. This type's size will always be a multiple of the cache line size;
/// if the wrapped type is longer than the alignment of a cache line, then
/// this type will be padded to multiple cache lines.
///
/// [false sharing]: https://en.wikipedia.org/wiki/False_sharing
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
pub struct CachePadded<T>(pub(super) T);
}

/// When not inhibited, determine cache alignment based on target architecture.
/// Align to 128 bytes on 64-bit x86/ARM targets, otherwise align to 64 bytes.
#[cfg(not(feature = "no-cache-pad"))]
mod inner {
/// Aligns the wrapped value to the size of a cache line.
///
/// This is used to avoid [false sharing] for values that may be
/// accessed concurrently.
///
/// # Size/Alignment
///
/// The size and alignment of this type depends on the target architecture,
/// and on whether or not the `no-cache-pad` feature flag is enabled.
///
/// When the `no-cache-pad` crate feature flag is enabled, this is simply a
/// no-op wrapper struct. This is intended for use on useful for platforms
/// with no data cache, such as many Cortex-M targets.
///
/// In other cases, this type is always aligned to the size of a cache line,
/// based on the target architecture. On `x86_64`/`aarch64`, a cache line is
/// 128 bytes. On all other targets, a cache line is assumed to 64 bytes
/// long. This type's size will always be a multiple of the cache line size;
/// if the wrapped type is longer than the alignment of a cache line, then
/// this type will be padded to multiple cache lines.
///
/// [false sharing]: https://en.wikipedia.org/wiki/False_sharing
#[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))]
#[cfg_attr(
not(any(target_arch = "x86_64", target_arch = "aarch64")),
repr(align(64))
)]
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
pub struct CachePadded<T>(pub(super) T);
}

// === impl CachePadded ===

impl<T> CachePadded<T> {
/// Pads `value` to the length of a cache line.
pub const fn new(value: T) -> Self {
Self(value)
}

/// Unwraps the inner value and returns it.
pub fn into_inner(self) -> T {
self.0
}
}

impl<T> Deref for CachePadded<T> {
type Target = T;

#[inline]
fn deref(&self) -> &T {
&self.0
}
}

impl<T> DerefMut for CachePadded<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}

impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

0 comments on commit 0ba37ac

Please sign in to comment.