mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
Instrument asset loading and processing. (#12988)
# Objective As described in #12467, Bevy does not have any spans for any of the tasks scheduled onto the IO and async compute task pools. ## Solution Instrument all asset loads and asset processing. Since this change is restricted to asset tasks, it does not completely solve #12467, but it does mean we can record the asset path in the trace. ![image](https://github.com/bevyengine/bevy/assets/8494645/59faee63-1f69-40af-bf47-312c4d67d1e2) --- ## Changelog Tracing will now include spans for asset loading and asset processing.
This commit is contained in:
parent
da2ba8a43c
commit
e3f55d6dfc
4 changed files with 76 additions and 1 deletions
|
@ -16,6 +16,7 @@ embedded_watcher = ["file_watcher"]
|
||||||
multi-threaded = ["bevy_tasks/multi-threaded"]
|
multi-threaded = ["bevy_tasks/multi-threaded"]
|
||||||
asset_processor = []
|
asset_processor = []
|
||||||
watch = []
|
watch = []
|
||||||
|
trace = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app", version = "0.14.0-dev" }
|
bevy_app = { path = "../bevy_app", version = "0.14.0-dev" }
|
||||||
|
|
|
@ -20,6 +20,11 @@ use crate::{
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_tasks::IoTaskPool;
|
use bevy_tasks::IoTaskPool;
|
||||||
use bevy_utils::tracing::{debug, error, trace, warn};
|
use bevy_utils::tracing::{debug, error, trace, warn};
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
use bevy_utils::{
|
||||||
|
tracing::{info_span, instrument::Instrument},
|
||||||
|
ConditionalSendFuture,
|
||||||
|
};
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet};
|
||||||
use futures_io::ErrorKind;
|
use futures_io::ErrorKind;
|
||||||
use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt};
|
use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt};
|
||||||
|
@ -479,6 +484,8 @@ impl AssetProcessor {
|
||||||
/// Register a new asset processor.
|
/// Register a new asset processor.
|
||||||
pub fn register_processor<P: Process>(&self, processor: P) {
|
pub fn register_processor<P: Process>(&self, processor: P) {
|
||||||
let mut process_plans = self.data.processors.write();
|
let mut process_plans = self.data.processors.write();
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
let processor = InstrumentedAssetProcessor(processor);
|
||||||
process_plans.insert(std::any::type_name::<P>(), Arc::new(processor));
|
process_plans.insert(std::any::type_name::<P>(), Arc::new(processor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1031,6 +1038,37 @@ impl AssetProcessorData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
struct InstrumentedAssetProcessor<T>(T);
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
impl<T: Process> Process for InstrumentedAssetProcessor<T> {
|
||||||
|
type Settings = T::Settings;
|
||||||
|
type OutputLoader = T::OutputLoader;
|
||||||
|
|
||||||
|
fn process<'a>(
|
||||||
|
&'a self,
|
||||||
|
context: &'a mut ProcessContext,
|
||||||
|
meta: AssetMeta<(), Self>,
|
||||||
|
writer: &'a mut crate::io::Writer,
|
||||||
|
) -> impl ConditionalSendFuture<
|
||||||
|
Output = Result<<Self::OutputLoader as crate::AssetLoader>::Settings, ProcessError>,
|
||||||
|
> {
|
||||||
|
// Change the processor type for the `AssetMeta`, which works because we share the `Settings` type.
|
||||||
|
let meta = AssetMeta {
|
||||||
|
meta_format_version: meta.meta_format_version,
|
||||||
|
processed_info: meta.processed_info,
|
||||||
|
asset: meta.asset,
|
||||||
|
};
|
||||||
|
let span = info_span!(
|
||||||
|
"asset processing",
|
||||||
|
processor = std::any::type_name::<T>(),
|
||||||
|
asset = context.path().to_string(),
|
||||||
|
);
|
||||||
|
self.0.process(context, meta, writer).instrument(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The (successful) result of processing an asset
|
/// The (successful) result of processing an asset
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ProcessResult {
|
pub enum ProcessResult {
|
||||||
|
|
|
@ -5,6 +5,11 @@ use crate::{
|
||||||
use async_broadcast::RecvError;
|
use async_broadcast::RecvError;
|
||||||
use bevy_tasks::IoTaskPool;
|
use bevy_tasks::IoTaskPool;
|
||||||
use bevy_utils::tracing::{error, warn};
|
use bevy_utils::tracing::{error, warn};
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
use bevy_utils::{
|
||||||
|
tracing::{info_span, instrument::Instrument},
|
||||||
|
ConditionalSendFuture,
|
||||||
|
};
|
||||||
use bevy_utils::{HashMap, TypeIdMap};
|
use bevy_utils::{HashMap, TypeIdMap};
|
||||||
use std::{any::TypeId, sync::Arc};
|
use std::{any::TypeId, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -30,6 +35,8 @@ impl AssetLoaders {
|
||||||
let loader_asset_type = TypeId::of::<L::Asset>();
|
let loader_asset_type = TypeId::of::<L::Asset>();
|
||||||
let loader_asset_type_name = std::any::type_name::<L::Asset>();
|
let loader_asset_type_name = std::any::type_name::<L::Asset>();
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
let loader = InstrumentedAssetLoader(loader);
|
||||||
let loader = Arc::new(loader);
|
let loader = Arc::new(loader);
|
||||||
|
|
||||||
let (loader_index, is_new) =
|
let (loader_index, is_new) =
|
||||||
|
@ -41,7 +48,7 @@ impl AssetLoaders {
|
||||||
|
|
||||||
if is_new {
|
if is_new {
|
||||||
let mut duplicate_extensions = Vec::new();
|
let mut duplicate_extensions = Vec::new();
|
||||||
for extension in loader.extensions() {
|
for extension in AssetLoader::extensions(&*loader) {
|
||||||
let list = self
|
let list = self
|
||||||
.extension_to_loaders
|
.extension_to_loaders
|
||||||
.entry((*extension).into())
|
.entry((*extension).into())
|
||||||
|
@ -292,6 +299,34 @@ impl MaybeAssetLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
struct InstrumentedAssetLoader<T>(T);
|
||||||
|
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
impl<T: AssetLoader> AssetLoader for InstrumentedAssetLoader<T> {
|
||||||
|
type Asset = T::Asset;
|
||||||
|
type Settings = T::Settings;
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn load<'a>(
|
||||||
|
&'a self,
|
||||||
|
reader: &'a mut crate::io::Reader,
|
||||||
|
settings: &'a Self::Settings,
|
||||||
|
load_context: &'a mut crate::LoadContext,
|
||||||
|
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>> {
|
||||||
|
let span = info_span!(
|
||||||
|
"asset loading",
|
||||||
|
loader = std::any::type_name::<T>(),
|
||||||
|
asset = load_context.asset_path().to_string(),
|
||||||
|
);
|
||||||
|
self.0.load(reader, settings, load_context).instrument(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extensions(&self) -> &[&str] {
|
||||||
|
self.0.extensions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -12,6 +12,7 @@ categories = ["game-engines", "graphics", "gui", "rendering"]
|
||||||
[features]
|
[features]
|
||||||
trace = [
|
trace = [
|
||||||
"bevy_app/trace",
|
"bevy_app/trace",
|
||||||
|
"bevy_asset?/trace",
|
||||||
"bevy_core_pipeline?/trace",
|
"bevy_core_pipeline?/trace",
|
||||||
"bevy_ecs/trace",
|
"bevy_ecs/trace",
|
||||||
"bevy_log/trace",
|
"bevy_log/trace",
|
||||||
|
|
Loading…
Reference in a new issue