perf: performance improvments

- switch to BTreeMap for consistant ordering of fields (less UI updates)
- cache calls to expensive getters in the vm via witha Proxy on
  DeviceRefs
- have DeviceMixin explicitly subscribe to device property changes to
  limit updates
- split fields into seperate componate to avoid rerender of other
  components
- speedup ic10emu_wasm DeviceRef::get_slots by only calling serde once.

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-04-25 20:38:03 -07:00
parent 2480a08ada
commit cfa240c579
16 changed files with 427 additions and 212 deletions

View File

@@ -13,6 +13,7 @@ use types::{Registers, Stack};
use std::{cell::RefCell, rc::Rc, str::FromStr};
use itertools::Itertools;
// use std::iter::FromIterator;
// use itertools::Itertools;
use wasm_bindgen::prelude::*;
@@ -86,17 +87,9 @@ impl DeviceRef {
serde_wasm_bindgen::to_value(&self.device.borrow().get_fields(&self.vm.borrow())).unwrap()
}
#[wasm_bindgen(getter, skip_typescript)]
pub fn slots(&self) -> Vec<JsValue> {
self.device
.borrow()
.slots
.iter()
.map(|slot| {
let flat_slot: types::Slot = slot.into();
serde_wasm_bindgen::to_value(&flat_slot).unwrap()
})
.collect_vec()
#[wasm_bindgen(getter)]
pub fn slots(&self) -> types::Slots {
types::Slots::from_iter(self.device.borrow().slots.iter())
}
#[wasm_bindgen(getter, skip_typescript)]
@@ -490,9 +483,17 @@ impl VMRef {
}
#[wasm_bindgen(js_name = "setSlotOccupant", skip_typescript)]
pub fn set_slot_occupant(&self, id: u32, index: usize, template: JsValue) -> Result<(), JsError> {
pub fn set_slot_occupant(
&self,
id: u32,
index: usize,
template: JsValue,
) -> Result<(), JsError> {
let template: SlotOccupantTemplate = serde_wasm_bindgen::from_value(template)?;
Ok(self.vm.borrow_mut().set_slot_occupant(id, index, template)?)
Ok(self
.vm
.borrow_mut()
.set_slot_occupant(id, index, template)?)
}
#[wasm_bindgen(js_name = "removeSlotOccupant")]

View File

@@ -1,8 +1,9 @@
#![allow(non_snake_case)]
// use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::BTreeMap;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use tsify::Tsify;
@@ -18,14 +19,16 @@ pub struct Stack(#[serde_as(as = "[_; 512]")] pub [f64; 512]);
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Registers(#[serde_as(as = "[_; 18]")] pub [f64; 18]);
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde_as]
#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct SlotOccupant {
pub id: u32,
pub prefab_hash: i32,
pub quantity: u32,
pub max_quantity: u32,
pub damage: f64,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
pub fields: BTreeMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
}
impl From<&ic10emu::device::SlotOccupant> for SlotOccupant {
@@ -41,11 +44,13 @@ impl From<&ic10emu::device::SlotOccupant> for SlotOccupant {
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde_as]
#[derive(Tsify, Debug, Clone, Default, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Slot {
pub typ: ic10emu::device::SlotType,
pub occupant: Option<SlotOccupant>,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
pub fields: BTreeMap<ic10emu::grammar::SlotLogicType, ic10emu::device::LogicField>,
}
impl From<&ic10emu::device::Slot> for Slot {
@@ -58,6 +63,17 @@ impl From<&ic10emu::device::Slot> for Slot {
}
}
#[serde_as]
#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Slots(pub Vec<Slot>);
impl<'a> FromIterator<&'a ic10emu::device::Slot> for Slots {
fn from_iter<T: IntoIterator<Item = &'a ic10emu::device::Slot>>(iter: T) -> Self {
Slots(iter.into_iter().map(|slot| slot.into()).collect_vec())
}
}
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));
// #[serde_as]

View File

@@ -7,19 +7,19 @@ export interface LogicField {
export type LogicFields = Map<LogicType, LogicField>;
export type SlotLogicFields = Map<SlotLogicType, LogicField>;
export interface SlotOccupant {
readonly id: number;
readonly prefab_hash: number;
readonly quantity: number;
readonly max_quantity: number;
readonly damage: number;
readonly fields: SlotLogicFields;
}
export interface Slot {
readonly typ: SlotType;
readonly occupant: SlotOccupant | undefined;
readonly fields: SlotLogicFields;
}
// export interface SlotOccupant {
// readonly id: number;
// readonly prefab_hash: number;
// readonly quantity: number;
// readonly max_quantity: number;
// readonly damage: number;
// readonly fields: SlotLogicFields;
// }
// export interface Slot {
// readonly typ: SlotType;
// readonly occupant: SlotOccupant | undefined;
// readonly fields: SlotLogicFields;
// }
export type Reagents = Map<string, Map<number, number>>;