Skip to content

Commit e3f55d6

Browse files
authored
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.
1 parent da2ba8a commit e3f55d6

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

crates/bevy_asset/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ embedded_watcher = ["file_watcher"]
1616
multi-threaded = ["bevy_tasks/multi-threaded"]
1717
asset_processor = []
1818
watch = []
19+
trace = []
1920

2021
[dependencies]
2122
bevy_app = { path = "../bevy_app", version = "0.14.0-dev" }

crates/bevy_asset/src/processor/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ use crate::{
2020
use bevy_ecs::prelude::*;
2121
use bevy_tasks::IoTaskPool;
2222
use bevy_utils::tracing::{debug, error, trace, warn};
23+
#[cfg(feature = "trace")]
24+
use bevy_utils::{
25+
tracing::{info_span, instrument::Instrument},
26+
ConditionalSendFuture,
27+
};
2328
use bevy_utils::{HashMap, HashSet};
2429
use futures_io::ErrorKind;
2530
use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt};
@@ -479,6 +484,8 @@ impl AssetProcessor {
479484
/// Register a new asset processor.
480485
pub fn register_processor<P: Process>(&self, processor: P) {
481486
let mut process_plans = self.data.processors.write();
487+
#[cfg(feature = "trace")]
488+
let processor = InstrumentedAssetProcessor(processor);
482489
process_plans.insert(std::any::type_name::<P>(), Arc::new(processor));
483490
}
484491

@@ -1031,6 +1038,37 @@ impl AssetProcessorData {
10311038
}
10321039
}
10331040

1041+
#[cfg(feature = "trace")]
1042+
struct InstrumentedAssetProcessor<T>(T);
1043+
1044+
#[cfg(feature = "trace")]
1045+
impl<T: Process> Process for InstrumentedAssetProcessor<T> {
1046+
type Settings = T::Settings;
1047+
type OutputLoader = T::OutputLoader;
1048+
1049+
fn process<'a>(
1050+
&'a self,
1051+
context: &'a mut ProcessContext,
1052+
meta: AssetMeta<(), Self>,
1053+
writer: &'a mut crate::io::Writer,
1054+
) -> impl ConditionalSendFuture<
1055+
Output = Result<<Self::OutputLoader as crate::AssetLoader>::Settings, ProcessError>,
1056+
> {
1057+
// Change the processor type for the `AssetMeta`, which works because we share the `Settings` type.
1058+
let meta = AssetMeta {
1059+
meta_format_version: meta.meta_format_version,
1060+
processed_info: meta.processed_info,
1061+
asset: meta.asset,
1062+
};
1063+
let span = info_span!(
1064+
"asset processing",
1065+
processor = std::any::type_name::<T>(),
1066+
asset = context.path().to_string(),
1067+
);
1068+
self.0.process(context, meta, writer).instrument(span)
1069+
}
1070+
}
1071+
10341072
/// The (successful) result of processing an asset
10351073
#[derive(Debug, Clone)]
10361074
pub enum ProcessResult {

crates/bevy_asset/src/server/loaders.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ use crate::{
55
use async_broadcast::RecvError;
66
use bevy_tasks::IoTaskPool;
77
use bevy_utils::tracing::{error, warn};
8+
#[cfg(feature = "trace")]
9+
use bevy_utils::{
10+
tracing::{info_span, instrument::Instrument},
11+
ConditionalSendFuture,
12+
};
813
use bevy_utils::{HashMap, TypeIdMap};
914
use std::{any::TypeId, sync::Arc};
1015
use thiserror::Error;
@@ -30,6 +35,8 @@ impl AssetLoaders {
3035
let loader_asset_type = TypeId::of::<L::Asset>();
3136
let loader_asset_type_name = std::any::type_name::<L::Asset>();
3237

38+
#[cfg(feature = "trace")]
39+
let loader = InstrumentedAssetLoader(loader);
3340
let loader = Arc::new(loader);
3441

3542
let (loader_index, is_new) =
@@ -41,7 +48,7 @@ impl AssetLoaders {
4148

4249
if is_new {
4350
let mut duplicate_extensions = Vec::new();
44-
for extension in loader.extensions() {
51+
for extension in AssetLoader::extensions(&*loader) {
4552
let list = self
4653
.extension_to_loaders
4754
.entry((*extension).into())
@@ -292,6 +299,34 @@ impl MaybeAssetLoader {
292299
}
293300
}
294301

302+
#[cfg(feature = "trace")]
303+
struct InstrumentedAssetLoader<T>(T);
304+
305+
#[cfg(feature = "trace")]
306+
impl<T: AssetLoader> AssetLoader for InstrumentedAssetLoader<T> {
307+
type Asset = T::Asset;
308+
type Settings = T::Settings;
309+
type Error = T::Error;
310+
311+
fn load<'a>(
312+
&'a self,
313+
reader: &'a mut crate::io::Reader,
314+
settings: &'a Self::Settings,
315+
load_context: &'a mut crate::LoadContext,
316+
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>> {
317+
let span = info_span!(
318+
"asset loading",
319+
loader = std::any::type_name::<T>(),
320+
asset = load_context.asset_path().to_string(),
321+
);
322+
self.0.load(reader, settings, load_context).instrument(span)
323+
}
324+
325+
fn extensions(&self) -> &[&str] {
326+
self.0.extensions()
327+
}
328+
}
329+
295330
#[cfg(test)]
296331
mod tests {
297332
use std::{

crates/bevy_internal/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ categories = ["game-engines", "graphics", "gui", "rendering"]
1212
[features]
1313
trace = [
1414
"bevy_app/trace",
15+
"bevy_asset?/trace",
1516
"bevy_core_pipeline?/trace",
1617
"bevy_ecs/trace",
1718
"bevy_log/trace",

0 commit comments

Comments
 (0)