Merge 00f06f9c51
into f964ee1e3a
This commit is contained in:
commit
f9cc7d102a
124
crates/bevy_pbr/src/diagnostic.rs
Normal file
124
crates/bevy_pbr/src/diagnostic.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
use core::{
|
||||||
|
any::{type_name, Any, TypeId},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bevy_app::{Plugin, PreUpdate};
|
||||||
|
use bevy_diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
|
||||||
|
use bevy_ecs::{resource::Resource, system::Res};
|
||||||
|
use bevy_platform::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||||
|
use bevy_render::{Extract, ExtractSchedule, RenderApp};
|
||||||
|
|
||||||
|
use crate::{Material, MaterialBindGroupAllocators};
|
||||||
|
|
||||||
|
pub struct MaterialAllocatorDiagnosticPlugin<M: Material> {
|
||||||
|
suffix: &'static str,
|
||||||
|
_phantom: PhantomData<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material> MaterialAllocatorDiagnosticPlugin<M> {
|
||||||
|
pub fn new(suffix: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
suffix,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material> Default for MaterialAllocatorDiagnosticPlugin<M> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
suffix: " materials",
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material> MaterialAllocatorDiagnosticPlugin<M> {
|
||||||
|
/// Get the [`DiagnosticPath`] for slab count
|
||||||
|
pub fn slabs_diagnostic_path() -> DiagnosticPath {
|
||||||
|
DiagnosticPath::from_components(["material_allocator_slabs", type_name::<M>()])
|
||||||
|
}
|
||||||
|
/// Get the [`DiagnosticPath`] for total slabs size
|
||||||
|
pub fn slabs_size_diagnostic_path() -> DiagnosticPath {
|
||||||
|
DiagnosticPath::from_components(["material_allocator_slabs_size", type_name::<M>()])
|
||||||
|
}
|
||||||
|
/// Get the [`DiagnosticPath`] for material allocations
|
||||||
|
pub fn allocations_diagnostic_path() -> DiagnosticPath {
|
||||||
|
DiagnosticPath::from_components(["material_allocator_allocations", type_name::<M>()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material> Plugin for MaterialAllocatorDiagnosticPlugin<M> {
|
||||||
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
|
app.register_diagnostic(
|
||||||
|
Diagnostic::new(Self::slabs_diagnostic_path()).with_suffix(" slabs"),
|
||||||
|
)
|
||||||
|
.register_diagnostic(
|
||||||
|
Diagnostic::new(Self::slabs_size_diagnostic_path()).with_suffix(" bytes"),
|
||||||
|
)
|
||||||
|
.register_diagnostic(
|
||||||
|
Diagnostic::new(Self::allocations_diagnostic_path()).with_suffix(self.suffix),
|
||||||
|
)
|
||||||
|
.init_resource::<MaterialAllocatorMeasurements<M>>()
|
||||||
|
.add_systems(PreUpdate, add_material_allocator_measurement::<M>);
|
||||||
|
|
||||||
|
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
|
render_app.add_systems(ExtractSchedule, measure_allocator::<M>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Resource)]
|
||||||
|
struct MaterialAllocatorMeasurements<M: Material> {
|
||||||
|
slabs: AtomicUsize,
|
||||||
|
slabs_size: AtomicUsize,
|
||||||
|
allocations: AtomicU64,
|
||||||
|
_phantom: PhantomData<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material> Default for MaterialAllocatorMeasurements<M> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
slabs: AtomicUsize::default(),
|
||||||
|
slabs_size: AtomicUsize::default(),
|
||||||
|
allocations: AtomicU64::default(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_material_allocator_measurement<M: Material>(
|
||||||
|
mut diagnostics: Diagnostics,
|
||||||
|
measurements: Res<MaterialAllocatorMeasurements<M>>,
|
||||||
|
) {
|
||||||
|
diagnostics.add_measurement(
|
||||||
|
&MaterialAllocatorDiagnosticPlugin::<M>::slabs_diagnostic_path(),
|
||||||
|
|| measurements.slabs.load(Ordering::Relaxed) as f64,
|
||||||
|
);
|
||||||
|
diagnostics.add_measurement(
|
||||||
|
&MaterialAllocatorDiagnosticPlugin::<M>::slabs_size_diagnostic_path(),
|
||||||
|
|| measurements.slabs_size.load(Ordering::Relaxed) as f64,
|
||||||
|
);
|
||||||
|
diagnostics.add_measurement(
|
||||||
|
&MaterialAllocatorDiagnosticPlugin::<M>::allocations_diagnostic_path(),
|
||||||
|
|| measurements.allocations.load(Ordering::Relaxed) as f64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_allocator<M: Material + Any>(
|
||||||
|
measurements: Extract<Res<MaterialAllocatorMeasurements<M>>>,
|
||||||
|
allocators: Res<MaterialBindGroupAllocators>,
|
||||||
|
) {
|
||||||
|
if let Some(allocator) = allocators.get(&TypeId::of::<M>()) {
|
||||||
|
measurements
|
||||||
|
.slabs
|
||||||
|
.store(allocator.slab_count(), Ordering::Relaxed);
|
||||||
|
measurements
|
||||||
|
.slabs_size
|
||||||
|
.store(allocator.slabs_size(), Ordering::Relaxed);
|
||||||
|
measurements
|
||||||
|
.allocations
|
||||||
|
.store(allocator.allocations(), Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ mod cluster;
|
|||||||
mod components;
|
mod components;
|
||||||
pub mod decal;
|
pub mod decal;
|
||||||
pub mod deferred;
|
pub mod deferred;
|
||||||
|
pub mod diagnostic;
|
||||||
mod extended_material;
|
mod extended_material;
|
||||||
mod fog;
|
mod fog;
|
||||||
mod light_probe;
|
mod light_probe;
|
||||||
|
@ -590,6 +590,45 @@ impl MaterialBindGroupAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get number of allocated slabs for bindless material, returns 0 if it is
|
||||||
|
/// [`Self::NonBindless`].
|
||||||
|
pub fn slab_count(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Bindless(bless) => bless.slabs.len(),
|
||||||
|
Self::NonBindless(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get total size of slabs allocated for bindless material, returns 0 if it is
|
||||||
|
/// [`Self::NonBindless`].
|
||||||
|
pub fn slabs_size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Bindless(bless) => bless
|
||||||
|
.slabs
|
||||||
|
.iter()
|
||||||
|
.flat_map(|slab| {
|
||||||
|
slab.data_buffers
|
||||||
|
.iter()
|
||||||
|
.map(|(_, buffer)| buffer.buffer.len())
|
||||||
|
})
|
||||||
|
.sum(),
|
||||||
|
Self::NonBindless(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get number of bindless material allocations in slabs, returns 0 if it is
|
||||||
|
/// [`Self::NonBindless`].
|
||||||
|
pub fn allocations(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
Self::Bindless(bless) => bless
|
||||||
|
.slabs
|
||||||
|
.iter()
|
||||||
|
.map(|slab| u64::from(slab.allocated_resource_count))
|
||||||
|
.sum(),
|
||||||
|
Self::NonBindless(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialBindlessIndexTable {
|
impl MaterialBindlessIndexTable {
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
use bevy_app::{Plugin, PreUpdate};
|
||||||
|
use bevy_diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
|
||||||
|
use bevy_ecs::{resource::Resource, system::Res};
|
||||||
|
use bevy_platform::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
use crate::{mesh::allocator::MeshAllocator, Extract, ExtractSchedule, RenderApp};
|
||||||
|
|
||||||
|
/// Number of meshes allocated by the allocator
|
||||||
|
static MESH_ALLOCATOR_SLABS: DiagnosticPath = DiagnosticPath::const_new("mesh_allocator_slabs");
|
||||||
|
|
||||||
|
/// Total size of all slabs
|
||||||
|
static MESH_ALLOCATOR_SLABS_SIZE: DiagnosticPath =
|
||||||
|
DiagnosticPath::const_new("mesh_allocator_slabs_size");
|
||||||
|
|
||||||
|
/// Number of meshes allocated into slabs
|
||||||
|
static MESH_ALLOCATOR_ALLOCATIONS: DiagnosticPath =
|
||||||
|
DiagnosticPath::const_new("mesh_allocator_allocations");
|
||||||
|
|
||||||
|
pub struct MeshAllocatorDiagnosticPlugin;
|
||||||
|
|
||||||
|
impl MeshAllocatorDiagnosticPlugin {
|
||||||
|
/// Get the [`DiagnosticPath`] for slab count
|
||||||
|
pub fn slabs_diagnostic_path() -> &'static DiagnosticPath {
|
||||||
|
&MESH_ALLOCATOR_SLABS
|
||||||
|
}
|
||||||
|
/// Get the [`DiagnosticPath`] for total slabs size
|
||||||
|
pub fn slabs_size_diagnostic_path() -> &'static DiagnosticPath {
|
||||||
|
&MESH_ALLOCATOR_SLABS_SIZE
|
||||||
|
}
|
||||||
|
/// Get the [`DiagnosticPath`] for mesh allocations
|
||||||
|
pub fn allocations_diagnostic_path() -> &'static DiagnosticPath {
|
||||||
|
&MESH_ALLOCATOR_ALLOCATIONS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for MeshAllocatorDiagnosticPlugin {
|
||||||
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
|
app.register_diagnostic(
|
||||||
|
Diagnostic::new(MESH_ALLOCATOR_SLABS.clone()).with_suffix(" slabs"),
|
||||||
|
)
|
||||||
|
.register_diagnostic(
|
||||||
|
Diagnostic::new(MESH_ALLOCATOR_SLABS_SIZE.clone()).with_suffix(" bytes"),
|
||||||
|
)
|
||||||
|
.register_diagnostic(
|
||||||
|
Diagnostic::new(MESH_ALLOCATOR_ALLOCATIONS.clone()).with_suffix(" meshes"),
|
||||||
|
)
|
||||||
|
.init_resource::<MeshAllocatorMeasurements>()
|
||||||
|
.add_systems(PreUpdate, add_mesh_allocator_measurement);
|
||||||
|
|
||||||
|
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
|
render_app.add_systems(ExtractSchedule, measure_allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Resource)]
|
||||||
|
struct MeshAllocatorMeasurements {
|
||||||
|
slabs: AtomicUsize,
|
||||||
|
slabs_size: AtomicU64,
|
||||||
|
allocations: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_mesh_allocator_measurement(
|
||||||
|
mut diagnostics: Diagnostics,
|
||||||
|
measurements: Res<MeshAllocatorMeasurements>,
|
||||||
|
) {
|
||||||
|
diagnostics.add_measurement(&MESH_ALLOCATOR_SLABS, || {
|
||||||
|
measurements.slabs.load(Ordering::Relaxed) as f64
|
||||||
|
});
|
||||||
|
diagnostics.add_measurement(&MESH_ALLOCATOR_SLABS_SIZE, || {
|
||||||
|
measurements.slabs_size.load(Ordering::Relaxed) as f64
|
||||||
|
});
|
||||||
|
diagnostics.add_measurement(&MESH_ALLOCATOR_ALLOCATIONS, || {
|
||||||
|
measurements.allocations.load(Ordering::Relaxed) as f64
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_allocator(
|
||||||
|
measurements: Extract<Res<MeshAllocatorMeasurements>>,
|
||||||
|
allocator: Res<MeshAllocator>,
|
||||||
|
) {
|
||||||
|
measurements
|
||||||
|
.slabs
|
||||||
|
.store(allocator.slab_count(), Ordering::Relaxed);
|
||||||
|
measurements
|
||||||
|
.slabs_size
|
||||||
|
.store(allocator.slabs_size(), Ordering::Relaxed);
|
||||||
|
measurements
|
||||||
|
.allocations
|
||||||
|
.store(allocator.allocations(), Ordering::Relaxed);
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
//! For more info, see [`RenderDiagnosticsPlugin`].
|
//! For more info, see [`RenderDiagnosticsPlugin`].
|
||||||
|
|
||||||
pub(crate) mod internal;
|
pub(crate) mod internal;
|
||||||
|
mod mesh_allocator_diagnostic_plugin;
|
||||||
|
mod render_asset_diagnostic_plugin;
|
||||||
#[cfg(feature = "tracing-tracy")]
|
#[cfg(feature = "tracing-tracy")]
|
||||||
mod tracy_gpu;
|
mod tracy_gpu;
|
||||||
|
|
||||||
@ -16,6 +18,10 @@ use crate::{renderer::RenderAdapterInfo, RenderApp};
|
|||||||
use self::internal::{
|
use self::internal::{
|
||||||
sync_diagnostics, DiagnosticsRecorder, Pass, RenderDiagnosticsMutex, WriteTimestamp,
|
sync_diagnostics, DiagnosticsRecorder, Pass, RenderDiagnosticsMutex, WriteTimestamp,
|
||||||
};
|
};
|
||||||
|
pub use self::{
|
||||||
|
mesh_allocator_diagnostic_plugin::MeshAllocatorDiagnosticPlugin,
|
||||||
|
render_asset_diagnostic_plugin::RenderAssetDiagnosticPlugin,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{RenderDevice, RenderQueue};
|
use super::{RenderDevice, RenderQueue};
|
||||||
|
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
use core::{any::type_name, marker::PhantomData};
|
||||||
|
|
||||||
|
use bevy_app::{Plugin, PreUpdate};
|
||||||
|
use bevy_diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
|
||||||
|
use bevy_ecs::{resource::Resource, system::Res};
|
||||||
|
use bevy_platform::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
render_asset::{RenderAsset, RenderAssets},
|
||||||
|
Extract, ExtractSchedule, RenderApp,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct RenderAssetDiagnosticPlugin<A: RenderAsset> {
|
||||||
|
suffix: &'static str,
|
||||||
|
_phantom: PhantomData<A>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: RenderAsset> RenderAssetDiagnosticPlugin<A> {
|
||||||
|
pub fn new(suffix: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
suffix,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_asset_diagnostic_path() -> DiagnosticPath {
|
||||||
|
DiagnosticPath::from_components(["render_asset", type_name::<A>()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: RenderAsset> Plugin for RenderAssetDiagnosticPlugin<A> {
|
||||||
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
|
app.register_diagnostic(
|
||||||
|
Diagnostic::new(Self::render_asset_diagnostic_path()).with_suffix(self.suffix),
|
||||||
|
)
|
||||||
|
.init_resource::<RenderAssetMeasurements<A>>()
|
||||||
|
.add_systems(PreUpdate, add_render_asset_measurement::<A>);
|
||||||
|
|
||||||
|
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
|
render_app.add_systems(ExtractSchedule, measure_render_asset::<A>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Resource)]
|
||||||
|
struct RenderAssetMeasurements<A: RenderAsset> {
|
||||||
|
assets: AtomicUsize,
|
||||||
|
_phantom: PhantomData<A>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: RenderAsset> Default for RenderAssetMeasurements<A> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
assets: AtomicUsize::default(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_render_asset_measurement<A: RenderAsset>(
|
||||||
|
mut diagnostics: Diagnostics,
|
||||||
|
measurements: Res<RenderAssetMeasurements<A>>,
|
||||||
|
) {
|
||||||
|
diagnostics.add_measurement(
|
||||||
|
&RenderAssetDiagnosticPlugin::<A>::render_asset_diagnostic_path(),
|
||||||
|
|| measurements.assets.load(Ordering::Relaxed) as f64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_render_asset<A: RenderAsset>(
|
||||||
|
measurements: Extract<Res<RenderAssetMeasurements<A>>>,
|
||||||
|
assets: Res<RenderAssets<A>>,
|
||||||
|
) {
|
||||||
|
measurements
|
||||||
|
.assets
|
||||||
|
.store(assets.iter().count(), Ordering::Relaxed);
|
||||||
|
}
|
@ -172,6 +172,15 @@ enum Slab {
|
|||||||
LargeObject(LargeObjectSlab),
|
LargeObject(LargeObjectSlab),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Slab {
|
||||||
|
pub fn buffer_size(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
Self::General(gs) => gs.buffer.as_ref().map(|buffer| buffer.size()).unwrap_or(0),
|
||||||
|
Self::LargeObject(lo) => lo.buffer.as_ref().map(|buffer| buffer.size()).unwrap_or(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A resizable slab that can contain multiple objects.
|
/// A resizable slab that can contain multiple objects.
|
||||||
///
|
///
|
||||||
/// This is the normal type of slab used for objects that are below the
|
/// This is the normal type of slab used for objects that are below the
|
||||||
@ -409,6 +418,20 @@ impl MeshAllocator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the number of allocated slabs
|
||||||
|
pub fn slab_count(&self) -> usize {
|
||||||
|
self.slabs.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the total size of all allocated slabs
|
||||||
|
pub fn slabs_size(&self) -> u64 {
|
||||||
|
self.slabs.iter().map(|slab| slab.1.buffer_size()).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocations(&self) -> usize {
|
||||||
|
self.mesh_id_to_index_slab.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a slab and a mesh with data located with it, returns the buffer
|
/// Given a slab and a mesh with data located with it, returns the buffer
|
||||||
/// and range of that mesh data within the slab.
|
/// and range of that mesh data within the slab.
|
||||||
fn mesh_slice_in_slab(
|
fn mesh_slice_in_slab(
|
||||||
|
16
release-content/release-notes/render-assets-diagnostics.md
Normal file
16
release-content/release-notes/render-assets-diagnostics.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Render Assets diagnostics
|
||||||
|
authors: ["@hukasu"]
|
||||||
|
pull_requests: [19311]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
Create diagnostics plugins `MeshAllocatorDiagnosticPlugin`, `MaterialAllocatorDiagnosticPlugin` and `RenderAssetDiagnosticPlugin`
|
||||||
|
that collect measurements related to `MeshAllocator`s, `MaterialBindGroupAllocator`, and `RenderAssets` respectively.
|
||||||
|
|
||||||
|
`MeshAllocatorDiagnosticPlugin` and `MaterialDiagnosticPlugin` measure the number of slabs, the total size of memory
|
||||||
|
allocated by the slabs, and the number of objects allocated in the slabs. Only bindless materials use slabs for their
|
||||||
|
allocations, non-bindless materials return 0 for all of them.
|
||||||
|
|
||||||
|
`RenderAssetDiagnosticsPlugin` measure the number of assets in `RenderAssets<T>`.
|
@ -13,12 +13,19 @@ impl Prepare for TestCommand {
|
|||||||
let jobs = args.build_jobs();
|
let jobs = args.build_jobs();
|
||||||
let test_threads = args.test_threads();
|
let test_threads = args.test_threads();
|
||||||
|
|
||||||
|
let jobs_ref = &jobs;
|
||||||
vec![PreparedCommand::new::<Self>(
|
vec![PreparedCommand::new::<Self>(
|
||||||
|
cmd!(
|
||||||
|
sh,
|
||||||
|
"cargo test --workspace --lib --bins --tests {no_fail_fast...} {jobs_ref...} -- {test_threads...}"
|
||||||
|
),
|
||||||
|
"Please fix failing tests in output above.",
|
||||||
|
),PreparedCommand::new::<Self>(
|
||||||
cmd!(
|
cmd!(
|
||||||
sh,
|
sh,
|
||||||
// `--benches` runs each benchmark once in order to verify that they behave
|
// `--benches` runs each benchmark once in order to verify that they behave
|
||||||
// correctly and do not panic.
|
// correctly and do not panic.
|
||||||
"cargo test --workspace --lib --bins --tests --benches {no_fail_fast...} {jobs...} -- {test_threads...}"
|
"cargo test --benches {no_fail_fast...} {jobs_ref...}"
|
||||||
),
|
),
|
||||||
"Please fix failing tests in output above.",
|
"Please fix failing tests in output above.",
|
||||||
)]
|
)]
|
||||||
|
Loading…
Reference in New Issue
Block a user