feat(runtime): trace visual cache sizes

This commit is contained in:
2026-07-18 13:28:27 +04:00
parent 2474e48020
commit 564edf0bc1
4 changed files with 146 additions and 32 deletions
+4 -1
View File
@@ -1093,6 +1093,9 @@ mod tests {
request_count: 64, request_count: 64,
graph_node_count: 128, graph_node_count: 128,
graph_edge_count: 192, graph_edge_count: 192,
wear_cache_entries: 8,
material_cache_entries: 16,
texture_cache_entries: 32,
}, },
)?; )?;
let progress = std::fs::read_to_string(&path).map_err(|err| err.to_string())?; let progress = std::fs::read_to_string(&path).map_err(|err| err.to_string())?;
@@ -1100,7 +1103,7 @@ mod tests {
assert_eq!( assert_eq!(
progress, progress,
"Starting\telapsed_ms=0\nGraphVisualMaterials\telapsed_ms=12\nGraphVisualMaterialRequests { request_count: 64, graph_node_count: 128, graph_edge_count: 192 }\telapsed_ms=34\n" "Starting\telapsed_ms=0\nGraphVisualMaterials\telapsed_ms=12\nGraphVisualMaterialRequests { request_count: 64, graph_node_count: 128, graph_edge_count: 192, wear_cache_entries: 8, material_cache_entries: 16, texture_cache_entries: 32 }\telapsed_ms=34\n"
); );
Ok(()) Ok(())
} }
+115 -30
View File
@@ -52,6 +52,7 @@ const VISUAL_DEPENDENCY_PROGRESS_INTERVAL: usize = 64;
type WearValidationCache = type WearValidationCache =
HashMap<(NormalizedPath, Vec<u8>), Result<fparkan_material::WearTable, String>>; HashMap<(NormalizedPath, Vec<u8>), Result<fparkan_material::WearTable, String>>;
type TextureValidationCache = HashMap<Vec<u8>, Result<(), String>>;
/// Canonical terrain archive paths derived from a mission land reference. /// Canonical terrain archive paths derived from a mission land reference.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
@@ -483,6 +484,17 @@ pub enum VisualDependencyPhase {
Texture, Texture,
} }
/// Validation-cache entries retained while expanding visual dependencies.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct VisualDependencyCacheCounts {
/// Distinct WEAR archive/name keys resolved so far.
pub wear_entries: usize,
/// Distinct MAT0 raw names resolved so far.
pub material_entries: usize,
/// Distinct TEXM archive/name keys resolved so far.
pub texture_entries: usize,
}
/// Throttled visual-dependency expansion progress. /// Throttled visual-dependency expansion progress.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct VisualDependencyProgress { pub struct VisualDependencyProgress {
@@ -494,6 +506,8 @@ pub struct VisualDependencyProgress {
pub graph_node_count: usize, pub graph_node_count: usize,
/// Resource graph edges materialized before this request is resolved. /// Resource graph edges materialized before this request is resolved.
pub graph_edge_count: usize, pub graph_edge_count: usize,
/// Validation-cache entries retained before this request is resolved.
pub cache_entries: VisualDependencyCacheCounts,
} }
/// Errors raised while preparing CPU-side assets. /// Errors raised while preparing CPU-side assets.
@@ -1241,10 +1255,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
wear_requests = wear_requests.saturating_add(1); wear_requests = wear_requests.saturating_add(1);
report_visual_dependency_progress( report_visual_dependency_progress(
&mut on_progress, &mut on_progress,
VisualDependencyPhase::Wear, VisualDependencyProgress {
wear_requests, phase: VisualDependencyPhase::Wear,
graph.nodes.len(), request_count: wear_requests,
graph.edges.len(), graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(),
cache_entries: visual_dependency_cache_counts(
&wear_validation,
&material_validation,
&diffuse_texture_validation,
&lightmap_texture_validation,
),
},
); );
match resolve_wear_table_cached(repository, mesh, &mut wear_validation) { match resolve_wear_table_cached(repository, mesh, &mut wear_validation) {
Ok(table) => { Ok(table) => {
@@ -1289,15 +1311,29 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
request_count: material_requests, request_count: material_requests,
graph_node_count: graph.nodes.len(), graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(), graph_edge_count: graph.edges.len(),
cache_entries: visual_dependency_cache_counts(
&wear_validation,
&material_validation,
&diffuse_texture_validation,
&lightmap_texture_validation,
),
}); });
for (material_index, _entry) in table.entries.iter().enumerate() { for (material_index, _entry) in table.entries.iter().enumerate() {
material_requests = material_requests.saturating_add(1); material_requests = material_requests.saturating_add(1);
report_visual_dependency_progress( report_visual_dependency_progress(
&mut on_progress, &mut on_progress,
VisualDependencyPhase::Material, VisualDependencyProgress {
material_requests, phase: VisualDependencyPhase::Material,
graph.nodes.len(), request_count: material_requests,
graph.edges.len(), graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(),
cache_entries: visual_dependency_cache_counts(
&wear_validation,
&material_validation,
&diffuse_texture_validation,
&lightmap_texture_validation,
),
},
); );
let Ok(material_index) = u16::try_from(material_index) else { let Ok(material_index) = u16::try_from(material_index) else {
push_visual_failure( push_visual_failure(
@@ -1347,10 +1383,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
texture_requests = texture_requests.saturating_add(1); texture_requests = texture_requests.saturating_add(1);
report_visual_dependency_progress( report_visual_dependency_progress(
&mut on_progress, &mut on_progress,
VisualDependencyPhase::Texture, VisualDependencyProgress {
texture_requests, phase: VisualDependencyPhase::Texture,
graph.nodes.len(), request_count: texture_requests,
graph.edges.len(), graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(),
cache_entries: visual_dependency_cache_counts(
&wear_validation,
&material_validation,
&diffuse_texture_validation,
&lightmap_texture_validation,
),
},
); );
report.texture_request_count += 1; report.texture_request_count += 1;
match resolve_texm_validation_cached( match resolve_texm_validation_cached(
@@ -1415,10 +1459,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
texture_requests = texture_requests.saturating_add(1); texture_requests = texture_requests.saturating_add(1);
report_visual_dependency_progress( report_visual_dependency_progress(
&mut on_progress, &mut on_progress,
VisualDependencyPhase::Texture, VisualDependencyProgress {
texture_requests, phase: VisualDependencyPhase::Texture,
graph.nodes.len(), request_count: texture_requests,
graph.edges.len(), graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(),
cache_entries: visual_dependency_cache_counts(
&wear_validation,
&material_validation,
&diffuse_texture_validation,
&lightmap_texture_validation,
),
},
); );
report.lightmap_request_count += 1; report.lightmap_request_count += 1;
match resolve_texm_validation_cached( match resolve_texm_validation_cached(
@@ -1484,18 +1536,29 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
fn report_visual_dependency_progress( fn report_visual_dependency_progress(
on_progress: &mut impl FnMut(VisualDependencyProgress), on_progress: &mut impl FnMut(VisualDependencyProgress),
phase: VisualDependencyPhase, progress: VisualDependencyProgress,
request_count: usize,
graph_node_count: usize,
graph_edge_count: usize,
) { ) {
if request_count == 1 || request_count.is_multiple_of(VISUAL_DEPENDENCY_PROGRESS_INTERVAL) { if progress.request_count == 1
on_progress(VisualDependencyProgress { || progress
phase, .request_count
request_count, .is_multiple_of(VISUAL_DEPENDENCY_PROGRESS_INTERVAL)
graph_node_count, {
graph_edge_count, on_progress(progress);
}); }
}
fn visual_dependency_cache_counts(
wear_validation: &WearValidationCache,
material_validation: &HashMap<Vec<u8>, Result<ResolvedMaterial, String>>,
diffuse_texture_validation: &TextureValidationCache,
lightmap_texture_validation: &TextureValidationCache,
) -> VisualDependencyCacheCounts {
VisualDependencyCacheCounts {
wear_entries: wear_validation.len(),
material_entries: material_validation.len(),
texture_entries: diffuse_texture_validation
.len()
.saturating_add(lightmap_texture_validation.len()),
} }
} }
@@ -2336,10 +2399,17 @@ mod tests {
for request_count in 1..=129 { for request_count in 1..=129 {
report_visual_dependency_progress( report_visual_dependency_progress(
&mut |event| progress.push(event), &mut |event| progress.push(event),
VisualDependencyPhase::Texture, VisualDependencyProgress {
phase: VisualDependencyPhase::Texture,
request_count, request_count,
37, graph_node_count: 37,
41, graph_edge_count: 41,
cache_entries: VisualDependencyCacheCounts {
wear_entries: 3,
material_entries: 5,
texture_entries: 7,
},
},
); );
} }
@@ -2351,18 +2421,33 @@ mod tests {
request_count: 1, request_count: 1,
graph_node_count: 37, graph_node_count: 37,
graph_edge_count: 41, graph_edge_count: 41,
cache_entries: VisualDependencyCacheCounts {
wear_entries: 3,
material_entries: 5,
texture_entries: 7,
},
}, },
VisualDependencyProgress { VisualDependencyProgress {
phase: VisualDependencyPhase::Texture, phase: VisualDependencyPhase::Texture,
request_count: 64, request_count: 64,
graph_node_count: 37, graph_node_count: 37,
graph_edge_count: 41, graph_edge_count: 41,
cache_entries: VisualDependencyCacheCounts {
wear_entries: 3,
material_entries: 5,
texture_entries: 7,
},
}, },
VisualDependencyProgress { VisualDependencyProgress {
phase: VisualDependencyPhase::Texture, phase: VisualDependencyPhase::Texture,
request_count: 128, request_count: 128,
graph_node_count: 37, graph_node_count: 37,
graph_edge_count: 41, graph_edge_count: 41,
cache_entries: VisualDependencyCacheCounts {
wear_entries: 3,
material_entries: 5,
texture_entries: 7,
},
}, },
] ]
); );
+18
View File
@@ -133,6 +133,12 @@ pub enum MissionLoadPhase {
graph_node_count: usize, graph_node_count: usize,
/// Graph edges materialized before the request. /// Graph edges materialized before the request.
graph_edge_count: usize, graph_edge_count: usize,
/// Distinct WEAR validation keys retained before the request.
wear_cache_entries: usize,
/// Distinct MAT0 validation keys retained before the request.
material_cache_entries: usize,
/// Distinct TEXM validation keys retained before the request.
texture_cache_entries: usize,
}, },
/// Validate TEXM documents while expanding visual dependencies. /// Validate TEXM documents while expanding visual dependencies.
GraphVisualTextures, GraphVisualTextures,
@@ -144,6 +150,12 @@ pub enum MissionLoadPhase {
graph_node_count: usize, graph_node_count: usize,
/// Graph edges materialized before the request. /// Graph edges materialized before the request.
graph_edge_count: usize, graph_edge_count: usize,
/// Distinct WEAR validation keys retained before the request.
wear_cache_entries: usize,
/// Distinct MAT0 validation keys retained before the request.
material_cache_entries: usize,
/// Distinct TEXM validation keys retained before the request.
texture_cache_entries: usize,
}, },
/// Prepare all reachable visual/resource dependencies. /// Prepare all reachable visual/resource dependencies.
Assets, Assets,
@@ -747,6 +759,9 @@ fn load_mission_with_options_and_progress(
request_count: progress.request_count, request_count: progress.request_count,
graph_node_count: progress.graph_node_count, graph_node_count: progress.graph_node_count,
graph_edge_count: progress.graph_edge_count, graph_edge_count: progress.graph_edge_count,
wear_cache_entries: progress.cache_entries.wear_entries,
material_cache_entries: progress.cache_entries.material_entries,
texture_cache_entries: progress.cache_entries.texture_entries,
}) })
} }
VisualDependencyPhase::Texture => { VisualDependencyPhase::Texture => {
@@ -754,6 +769,9 @@ fn load_mission_with_options_and_progress(
request_count: progress.request_count, request_count: progress.request_count,
graph_node_count: progress.graph_node_count, graph_node_count: progress.graph_node_count,
graph_edge_count: progress.graph_edge_count, graph_edge_count: progress.graph_edge_count,
wear_cache_entries: progress.cache_entries.wear_entries,
material_cache_entries: progress.cache_entries.material_entries,
texture_cache_entries: progress.cache_entries.texture_entries,
}) })
} }
}; };
+8
View File
@@ -1133,6 +1133,14 @@ probe recorded MAT0 request 3 at 52 nodes / 51 edges and request 4 at 55 nodes
they do not change traversal order, node or edge identities, provenance, they do not change traversal order, node or edge identities, provenance,
validation, cache semantics, or rendering. validation, cache semantics, or rendering.
The same throttled snapshots now retain the number of distinct validation-cache
keys for WEAR, MAT0, and TEXM before the request. In a fresh 50-second Part 2
probe, MAT0 request 3 recorded cache counts 2 / 3 / 3 and request 4 recorded
3 / 4 / 4, while the graph moved from 52 / 51 to 55 / 54 nodes / edges. The
counts distinguish cache growth from graph growth without adding per-request
file writes or asserting which parser, archive I/O operation, or allocation
caused the elapsed interval.
`fparkan-game --load-progress` now initializes its file with `Starting` and `fparkan-game --load-progress` now initializes its file with `Starting` and
appends each later mission-load event instead of replacing the prior line. A appends each later mission-load event instead of replacing the prior line. A
bounded probe can therefore retain both MAT0 and TEXM request milestones even bounded probe can therefore retain both MAT0 and TEXM request milestones even