mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 02:56:17 -10:00
perf: intern gameplay projection strings and verify resource overrides
This commit is contained in:
1 parent
cf837118e9
commit
cd61e11b56
5 files changed
+265
-15
No files matched your search
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"scope": "Assets + block facts + behaviours loader only; excludes full startup",
|
||||
"resources": ".local/horizon-client/26.3",
|
||||
"repeats": 5,
|
||||
"comparison": "historical cf837118 release binary",
|
||||
"reference_binary": "target/release/examples/shared_json_startup_profile-cf837118",
|
||||
"metrics": {
|
||||
"baseline": {
|
||||
"phase_ms": {
|
||||
"median": 1462.003,
|
||||
"samples": [
|
||||
1639.999,
|
||||
1506.864,
|
||||
1429.844,
|
||||
1462.003,
|
||||
1346.061
|
||||
]
|
||||
},
|
||||
"total_ms": {
|
||||
"median": 1922.795,
|
||||
"samples": [
|
||||
3383.516,
|
||||
1990.554,
|
||||
1912.354,
|
||||
1922.795,
|
||||
1777.912
|
||||
]
|
||||
},
|
||||
"cpu_ms": {
|
||||
"median": 1961.459,
|
||||
"samples": [
|
||||
2419.086,
|
||||
2021.457,
|
||||
1951.587,
|
||||
1961.459,
|
||||
1839.984
|
||||
]
|
||||
},
|
||||
"peak_rss_kib": {
|
||||
"median": 820912,
|
||||
"samples": [
|
||||
819956,
|
||||
821052,
|
||||
820912,
|
||||
821792,
|
||||
820424
|
||||
]
|
||||
}
|
||||
},
|
||||
"pr607": {
|
||||
"phase_ms": {
|
||||
"median": 486.715,
|
||||
"samples": [
|
||||
460.738,
|
||||
442.013,
|
||||
623.053,
|
||||
486.715,
|
||||
550.652
|
||||
]
|
||||
},
|
||||
"total_ms": {
|
||||
"median": 948.089,
|
||||
"samples": [
|
||||
923.057,
|
||||
935.599,
|
||||
1109.64,
|
||||
948.089,
|
||||
1052.546
|
||||
]
|
||||
},
|
||||
"cpu_ms": {
|
||||
"median": 968.424,
|
||||
"samples": [
|
||||
928.489,
|
||||
946.932,
|
||||
1128.431,
|
||||
968.424,
|
||||
1079.642
|
||||
]
|
||||
},
|
||||
"peak_rss_kib": {
|
||||
"median": 351796,
|
||||
"samples": [
|
||||
351796,
|
||||
351844,
|
||||
351536,
|
||||
351532,
|
||||
351988
|
||||
]
|
||||
}
|
||||
},
|
||||
"cf837118": {
|
||||
"phase_ms": {
|
||||
"median": 474.268,
|
||||
"samples": [
|
||||
443.122,
|
||||
474.268,
|
||||
520.497,
|
||||
433.525,
|
||||
532.058
|
||||
]
|
||||
},
|
||||
"total_ms": {
|
||||
"median": 945.87,
|
||||
"samples": [
|
||||
934.722,
|
||||
945.87,
|
||||
1006.539,
|
||||
888.201,
|
||||
1032.6
|
||||
]
|
||||
},
|
||||
"cpu_ms": {
|
||||
"median": 953.668,
|
||||
"samples": [
|
||||
941.957,
|
||||
953.668,
|
||||
1029.122,
|
||||
903.574,
|
||||
1065.025
|
||||
]
|
||||
},
|
||||
"peak_rss_kib": {
|
||||
"median": 274476,
|
||||
"samples": [
|
||||
273448,
|
||||
274844,
|
||||
274476,
|
||||
274556,
|
||||
274252
|
||||
]
|
||||
}
|
||||
},
|
||||
"current": {
|
||||
"phase_ms": {
|
||||
"median": 445.924,
|
||||
"samples": [
|
||||
472.165,
|
||||
427.797,
|
||||
419.288,
|
||||
445.924,
|
||||
524.211
|
||||
]
|
||||
},
|
||||
"total_ms": {
|
||||
"median": 999.669,
|
||||
"samples": [
|
||||
999.669,
|
||||
892.616,
|
||||
1051.427,
|
||||
940.595,
|
||||
1112.158
|
||||
]
|
||||
},
|
||||
"cpu_ms": {
|
||||
"median": 1001.24,
|
||||
"samples": [
|
||||
1001.24,
|
||||
887.874,
|
||||
1051.732,
|
||||
951.495,
|
||||
1132.208
|
||||
]
|
||||
},
|
||||
"peak_rss_kib": {
|
||||
"median": 267604,
|
||||
"samples": [
|
||||
267716,
|
||||
267920,
|
||||
267448,
|
||||
267604,
|
||||
267344
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"builds": {
|
||||
"current": "release example built at cf837118 + current uncommitted delta in PR #607 worktree",
|
||||
"historical": "release example built at exact cf837118 commit, with same Cargo release profile and shared dependency target"
|
||||
},
|
||||
"mode_commits": {
|
||||
"baseline": "independent loader algorithm at e422bd13, executed in current binary",
|
||||
"pr607": "shared early construction algorithm at a01d47f2, executed in current binary",
|
||||
"cf837118": "exact historical binary at cf837118, deferred mode",
|
||||
"current": "current PR worktree, deferred mode with interned strings"
|
||||
},
|
||||
"limitations": "Loader-only (Assets + BlockFacts + Behaviours), no full client startup or first-frame timing. Same release profile but different compilation contexts for historical binary; hardware activity and cache warmth vary. CPU and elapsed differences between cf837118 and current are mixed and may be noise. Peak RSS is whole-process Linux ru_maxrss."
|
||||
}
|
||||
@@ -9,9 +9,11 @@ use std::{path::Path, time::Instant};
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let root = args.next().ok_or("expected resource directory")?;
|
||||
let mode = args.next().ok_or("expected baseline, pr607 or shared")?;
|
||||
let mode = args
|
||||
.next()
|
||||
.ok_or("expected baseline, pr607, shared or deferred")?;
|
||||
if !["baseline", "pr607", "shared", "deferred"].contains(&mode.as_str()) {
|
||||
return Err("expected baseline, pr607 or shared".into());
|
||||
return Err("expected baseline, pr607, shared or deferred".into());
|
||||
}
|
||||
let root = Path::new(&root);
|
||||
let total = Instant::now();
|
||||
|
||||
@@ -117,16 +117,24 @@ pub struct GameplayProjection {
|
||||
emission: u64,
|
||||
dampening: u64,
|
||||
hardness: f64,
|
||||
push: Box<str>,
|
||||
push: Arc<str>,
|
||||
volume: f64,
|
||||
pitch: f64,
|
||||
place: Box<str>,
|
||||
break_sound: Box<str>,
|
||||
fall: Box<str>,
|
||||
place: Arc<str>,
|
||||
break_sound: Arc<str>,
|
||||
fall: Arc<str>,
|
||||
}
|
||||
|
||||
impl GameplayProjection {
|
||||
fn from_entry(entry: &decode::Entry<'_>) -> Self {
|
||||
fn from_entry(entry: &decode::Entry<'_>, strings: &mut HashMap<String, Arc<str>>) -> Self {
|
||||
fn intern(strings: &mut HashMap<String, Arc<str>>, value: &str) -> Arc<str> {
|
||||
if let Some(existing) = strings.get(value) {
|
||||
return Arc::clone(existing);
|
||||
}
|
||||
let value_arc: Arc<str> = Arc::from(value);
|
||||
strings.insert(value.to_owned(), Arc::clone(&value_arc));
|
||||
value_arc
|
||||
}
|
||||
const FLAGS: [&str; 11] = [
|
||||
"replaceable",
|
||||
"random_ticks",
|
||||
@@ -147,12 +155,12 @@ impl GameplayProjection {
|
||||
emission: entry.unsigned("emission"),
|
||||
dampening: entry.unsigned("dampening"),
|
||||
hardness: entry.number("hardness"),
|
||||
push: entry.text("push").into(),
|
||||
push: intern(strings, entry.text("push")),
|
||||
volume: entry.sound_number("volume"),
|
||||
pitch: entry.sound_number("pitch"),
|
||||
place: entry.sound_id("place").into(),
|
||||
break_sound: entry.sound_id("break").into(),
|
||||
fall: entry.sound_id("fall").into(),
|
||||
place: intern(strings, entry.sound_id("place")),
|
||||
break_sound: intern(strings, entry.sound_id("break")),
|
||||
fall: intern(strings, entry.sound_id("fall")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,7 +247,11 @@ impl BlockFacts {
|
||||
behaviours: &Value,
|
||||
) -> Result<(Self, Vec<GameplayProjection>)> {
|
||||
Self::load_with_callback(root, registry, behaviours, |entries| {
|
||||
Ok(entries.iter().map(GameplayProjection::from_entry).collect())
|
||||
let mut strings = HashMap::new();
|
||||
Ok(entries
|
||||
.iter()
|
||||
.map(|entry| GameplayProjection::from_entry(entry, &mut strings))
|
||||
.collect())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -349,6 +349,35 @@ fn independent_reloads_read_changed_behaviour_json_and_report_invalid_files() {
|
||||
);
|
||||
assert!(horizon_world::level::Behaviours::load(registry, &scratch).is_ok());
|
||||
|
||||
// Override one exported state bit at the same path and verify that a later
|
||||
// independent and paired read sees it while the original resource root does not.
|
||||
let mut changed: serde_json::Value = serde_json::from_slice(&original).unwrap();
|
||||
let original_bits = changed["states"][0][1].as_u64().unwrap();
|
||||
changed["states"][0][1] = (original_bits ^ 1).into();
|
||||
fs::write(
|
||||
scratch.join("block-behaviours.json"),
|
||||
serde_json::to_vec(&changed).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let changed_pair = BlockFacts::load_pair(&scratch, registry).unwrap();
|
||||
let changed_independent = BlockFacts::load(&scratch, registry).unwrap();
|
||||
let base_facts = BlockFacts::load(&base, registry).unwrap();
|
||||
let state = horizon_world::registry::BlockStateId(0);
|
||||
assert_ne!(
|
||||
changed_pair.0.get(state).legacy_solid,
|
||||
base_facts.get(state).legacy_solid
|
||||
);
|
||||
assert_eq!(
|
||||
changed_pair.0.get(state).legacy_solid,
|
||||
changed_independent.get(state).legacy_solid
|
||||
);
|
||||
// The world loader sees the same overridden legacy solidity flag.
|
||||
let changed_world = horizon_world::level::Behaviours::load(registry, &scratch).unwrap();
|
||||
assert_eq!(
|
||||
changed_world.facts(state).flags & 1 != 0,
|
||||
changed_pair.0.get(state).legacy_solid
|
||||
);
|
||||
|
||||
fs::write(scratch.join("block-behaviours.json"), b"{").unwrap();
|
||||
assert!(BlockFacts::load_pair(&scratch, registry).is_err());
|
||||
assert!(BlockFacts::load(&scratch, registry).is_err());
|
||||
|
||||
@@ -40,6 +40,8 @@ def main():
|
||||
parser.add_argument("--binary", type=Path, default=Path("target/release/examples/shared_json_startup_profile"))
|
||||
parser.add_argument("--resources", type=Path, default=Path(".local/horizon-client/26.3"))
|
||||
parser.add_argument("--repeats", type=int, default=5)
|
||||
parser.add_argument("--reference-binary", type=Path,
|
||||
help="Release binary built from cf837118; compare its deferred mode against current")
|
||||
parser.add_argument("--output", type=Path)
|
||||
args = parser.parse_args()
|
||||
if args.repeats < 1:
|
||||
@@ -47,14 +49,31 @@ def main():
|
||||
binary, resources = args.binary.resolve(), args.resources.resolve()
|
||||
if not binary.is_file() or not resources.is_dir():
|
||||
parser.error("binary or resources missing; build the example and prepare resources first")
|
||||
samples = {"baseline": [], "pr607": [], "shared": [], "deferred": []}
|
||||
if args.reference_binary:
|
||||
reference = args.reference_binary.resolve()
|
||||
if not reference.is_file():
|
||||
parser.error("reference binary missing")
|
||||
modes = ["baseline", "pr607", "cf837118", "current"]
|
||||
commands = {
|
||||
"baseline": (binary, "baseline"),
|
||||
"pr607": (binary, "pr607"),
|
||||
"cf837118": (reference, "deferred"),
|
||||
"current": (binary, "deferred"),
|
||||
}
|
||||
else:
|
||||
modes = ["baseline", "pr607", "shared", "deferred"]
|
||||
commands = {mode: (binary, mode) for mode in modes}
|
||||
samples = {mode: [] for mode in modes}
|
||||
for i in range(args.repeats):
|
||||
for mode in (("baseline", "pr607", "shared", "deferred") if i % 2 == 0 else ("deferred", "shared", "pr607", "baseline")):
|
||||
samples[mode].append(run(binary, resources, mode))
|
||||
for mode in (modes if i % 2 == 0 else list(reversed(modes))):
|
||||
executable, binary_mode = commands[mode]
|
||||
samples[mode].append(run(executable, resources, binary_mode))
|
||||
result = {
|
||||
"scope": "Assets + block facts + behaviours loader only; excludes full startup",
|
||||
"resources": str(resources),
|
||||
"repeats": args.repeats,
|
||||
"comparison": "historical cf837118 release binary" if args.reference_binary else "same binary loading modes",
|
||||
"reference_binary": str(args.reference_binary) if args.reference_binary else None,
|
||||
"metrics": {mode: {key: {"median": round(statistics.median(row[key] for row in rows), 3),
|
||||
"samples": [round(row[key], 3) for row in rows]}
|
||||
for key in rows[0]} for mode, rows in samples.items()},
|
||||
|
||||
Reference in new issue
Block a user