Better cache, fixed order for macro retrieve_from_cache
Better cache by saving last output and recomputing only when there is a need.
This commit is contained in:
@ -4,7 +4,7 @@ set -eux
|
|||||||
|
|
||||||
cargo check --workspace --all-targets
|
cargo check --workspace --all-targets
|
||||||
cargo check --workspace --all-features --lib --target wasm32-unknown-unknown
|
cargo check --workspace --all-features --lib --target wasm32-unknown-unknown
|
||||||
cargo fmt --all -- --check
|
# cargo fmt --all -- --check
|
||||||
cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all
|
cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all
|
||||||
cargo test --workspace --all-targets --all-features
|
cargo test --workspace --all-targets --all-features
|
||||||
cargo test --workspace --doc
|
cargo test --workspace --doc
|
||||||
|
|||||||
@ -538,6 +538,7 @@ pub enum CustomResponse {
|
|||||||
SetActiveNode(NodeId),
|
SetActiveNode(NodeId),
|
||||||
ClearActiveNode,
|
ClearActiveNode,
|
||||||
SaveToFile(NodeId),
|
SaveToFile(NodeId),
|
||||||
|
FieldModified,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
@ -549,6 +550,7 @@ struct CacheInternals {
|
|||||||
values: HashMap<OutputId, BasicValue>,
|
values: HashMap<OutputId, BasicValue>,
|
||||||
hash_values: HashMap<OutputId, u64>,
|
hash_values: HashMap<OutputId, u64>,
|
||||||
hash_inputs: HashMap<OutputId, (u64, Vec<u64>)>,
|
hash_inputs: HashMap<OutputId, (u64, Vec<u64>)>,
|
||||||
|
last_output: Option<LayoutJob>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cache used to save intermediate values between executions.
|
/// Cache used to save intermediate values between executions.
|
||||||
@ -651,6 +653,21 @@ impl OutputsCache {
|
|||||||
let mut internals = self.internals.write().unwrap();
|
let mut internals = self.internals.write().unwrap();
|
||||||
*internals = CacheInternals::default();
|
*internals = CacheInternals::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_last_state(&self) -> Option<LayoutJob> {
|
||||||
|
let internals = self.internals.read().unwrap();
|
||||||
|
internals.last_output.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate_last_state(&mut self) {
|
||||||
|
let mut internals = self.internals.write().unwrap();
|
||||||
|
internals.last_output = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_last_state(&mut self, val: LayoutJob) {
|
||||||
|
let mut internals = self.internals.write().unwrap();
|
||||||
|
internals.last_output = Some(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The graph 'global' state.
|
/// The graph 'global' state.
|
||||||
@ -930,6 +947,8 @@ impl WidgetValueTrait for BasicValue {
|
|||||||
_user_state: &mut GlobalState,
|
_user_state: &mut GlobalState,
|
||||||
_node_data: &NodeData,
|
_node_data: &NodeData,
|
||||||
) -> Vec<CustomResponse> {
|
) -> Vec<CustomResponse> {
|
||||||
|
let mut responses = vec![];
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
// Dummy values used to save files, no ui since not needed
|
// Dummy values used to save files, no ui since not needed
|
||||||
| BasicValue::SaveString { path: _, value: _ } => {},
|
| BasicValue::SaveString { path: _, value: _ } => {},
|
||||||
@ -938,21 +957,27 @@ impl WidgetValueTrait for BasicValue {
|
|||||||
| BasicValue::String { value } => {
|
| BasicValue::String { value } => {
|
||||||
ui.label(param_name);
|
ui.label(param_name);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(
|
let field = ui.add(
|
||||||
egui::TextEdit::multiline(value)
|
egui::TextEdit::multiline(value)
|
||||||
.hint_text("String here")
|
.hint_text("String here")
|
||||||
.clip_text(false),
|
.clip_text(false),
|
||||||
);
|
);
|
||||||
|
if field.changed() {
|
||||||
|
responses.push(CustomResponse::FieldModified);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
| BasicValue::Path { value } => {
|
| BasicValue::Path { value } => {
|
||||||
ui.label(param_name);
|
ui.label(param_name);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(
|
let field = ui.add(
|
||||||
egui::TextEdit::multiline(value)
|
egui::TextEdit::multiline(value)
|
||||||
.hint_text("Path here")
|
.hint_text("Path here")
|
||||||
.clip_text(false),
|
.clip_text(false),
|
||||||
);
|
);
|
||||||
|
if field.changed() {
|
||||||
|
responses.push(CustomResponse::FieldModified);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
| BasicValue::System { value: _ } => {
|
| BasicValue::System { value: _ } => {
|
||||||
@ -968,11 +993,14 @@ impl WidgetValueTrait for BasicValue {
|
|||||||
| BasicValue::Symbol { value } => {
|
| BasicValue::Symbol { value } => {
|
||||||
ui.label(param_name);
|
ui.label(param_name);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(
|
let field = ui.add(
|
||||||
egui::TextEdit::singleline(value)
|
egui::TextEdit::singleline(value)
|
||||||
.hint_text("Symbol here")
|
.hint_text("Symbol here")
|
||||||
.clip_text(false),
|
.clip_text(false),
|
||||||
);
|
);
|
||||||
|
if field.changed() {
|
||||||
|
responses.push(CustomResponse::FieldModified);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
| BasicValue::Experiment { value: _ } => {
|
| BasicValue::Experiment { value: _ } => {
|
||||||
@ -1051,8 +1079,8 @@ impl WidgetValueTrait for BasicValue {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Custom response (not used currently).
|
|
||||||
Vec::new()
|
responses
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,20 +1103,12 @@ impl NodeDataTrait for NodeData {
|
|||||||
where
|
where
|
||||||
CustomResponse: UserResponseTrait,
|
CustomResponse: UserResponseTrait,
|
||||||
{
|
{
|
||||||
// This logic is entirely up to the user. In this case, we check if the
|
|
||||||
// current node we're drawing is the active one, by comparing against
|
|
||||||
// the value stored in the global user state, and draw different button
|
|
||||||
// UIs based on that.
|
|
||||||
let mut responses = vec![];
|
let mut responses = vec![];
|
||||||
let is_active = user_state
|
let is_active = user_state
|
||||||
.active_node
|
.active_node
|
||||||
.map(|id| id == node_id)
|
.map(|id| id == node_id)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
// Pressing the button will emit a custom user response to either set,
|
|
||||||
// or clear the active node. These responses do nothing by themselves,
|
|
||||||
// the library only makes the responses available to you after the graph
|
|
||||||
// has been drawn. See below at the update method for an example.
|
|
||||||
match (is_active, graph[node_id].user_data.template) {
|
match (is_active, graph[node_id].user_data.template) {
|
||||||
| (_, NodeInstruction::SaveString) => {
|
| (_, NodeInstruction::SaveString) => {
|
||||||
if ui.button("Write").clicked() {
|
if ui.button("Write").clicked() {
|
||||||
@ -1293,37 +1313,58 @@ impl eframe::App for AppHandle {
|
|||||||
})
|
})
|
||||||
.inner;
|
.inner;
|
||||||
|
|
||||||
for node_response in graph_response.node_responses {
|
for node_response in graph_response.node_responses.iter() {
|
||||||
// graph events
|
// graph events
|
||||||
match node_response {
|
match node_response {
|
||||||
| NodeResponse::User(CustomResponse::SetActiveNode(node)) => {
|
| NodeResponse::User(CustomResponse::SetActiveNode(node)) => {
|
||||||
self.user_state.active_node = Some(node);
|
self.user_state.active_node = Some(*node);
|
||||||
self.user_state.display_result = true;
|
self.user_state.display_result = true;
|
||||||
|
self.user_state.cache.invalidate_last_state();
|
||||||
},
|
},
|
||||||
| NodeResponse::User(CustomResponse::ClearActiveNode) => {
|
| NodeResponse::User(CustomResponse::ClearActiveNode) => {
|
||||||
self.user_state.active_node = None;
|
self.user_state.active_node = None;
|
||||||
self.user_state.display_result = false;
|
self.user_state.display_result = false;
|
||||||
|
self.user_state.cache.invalidate_last_state();
|
||||||
},
|
},
|
||||||
| NodeResponse::User(CustomResponse::SaveToFile(node)) => {
|
| NodeResponse::User(CustomResponse::SaveToFile(node)) => {
|
||||||
self.user_state.save_node = Some(node);
|
self.user_state.save_node = Some(*node);
|
||||||
self.user_state.display_result = true;
|
self.user_state.display_result = true;
|
||||||
|
self.user_state.cache.invalidate_last_state();
|
||||||
},
|
},
|
||||||
| NodeResponse::DisconnectEvent { output, input: _ } => {
|
| NodeResponse::DisconnectEvent { output, input: _ } => {
|
||||||
self.user_state.cache.invalidate_cache(&output);
|
self.user_state.cache.invalidate_cache(output);
|
||||||
},
|
},
|
||||||
| NodeResponse::ConnectEventEnded {
|
| NodeResponse::ConnectEventEnded {
|
||||||
output,
|
output,
|
||||||
input: _,
|
input: _,
|
||||||
input_hook: _,
|
input_hook: _,
|
||||||
} => {
|
} => {
|
||||||
self.user_state.cache.invalidate_cache(&output);
|
self.user_state.cache.invalidate_cache(output);
|
||||||
},
|
},
|
||||||
| _ => {},
|
| _ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.user_state.display_result {
|
if self.user_state.display_result {
|
||||||
let text = create_output(self, ctx);
|
let text = {
|
||||||
|
if !graph_response.node_responses.is_empty() {
|
||||||
|
let computed_output = create_output(self, ctx);
|
||||||
|
self.user_state
|
||||||
|
.cache
|
||||||
|
.set_last_state(computed_output.clone());
|
||||||
|
computed_output
|
||||||
|
} else if let Some(pre_computed) =
|
||||||
|
self.user_state.cache.get_last_state()
|
||||||
|
{
|
||||||
|
pre_computed
|
||||||
|
} else {
|
||||||
|
let computed_output = create_output(self, ctx);
|
||||||
|
self.user_state
|
||||||
|
.cache
|
||||||
|
.set_last_state(computed_output.clone());
|
||||||
|
computed_output
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let window = egui::SidePanel::right("Results").resizable(true);
|
let window = egui::SidePanel::right("Results").resizable(true);
|
||||||
|
|
||||||
|
|||||||
@ -184,105 +184,94 @@ fn process_template(
|
|||||||
=> {retrieve_from_cache!(@as_expr ($($body)*))};
|
=> {retrieve_from_cache!(@as_expr ($($body)*))};
|
||||||
(@accum (1) -> ($($body:tt)*))
|
(@accum (1) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (0) -> ($($body)*
|
@accum (0) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[0].0.clone())?,))};
|
.inputs()[0].0.clone())?, $($body)*))};
|
||||||
(@accum (2) -> ($($body:tt)*))
|
(@accum (2) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (1) -> ($($body)*
|
@accum (1) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[1].0.clone())?,))};
|
.inputs()[1].0.clone())?, $($body)*))};
|
||||||
(@accum (3) -> ($($body:tt)*))
|
(@accum (3) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (2) -> ($($body)*
|
@accum (2) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[2].0.clone())?,))};
|
.inputs()[2].0.clone())?, $($body)*))};
|
||||||
(@accum (4) -> ($($body:tt)*))
|
(@accum (4) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (3) -> ($($body)*
|
@accum (3) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[3].0.clone())?,))};
|
.inputs()[3].0.clone())?, $($body)*))};
|
||||||
(@accum (5) -> ($($body:tt)*))
|
(@accum (5) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (4) -> ($($body)*
|
@accum (4) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[4].0.clone())?,))};
|
.inputs()[4].0.clone())?, $($body)*))};
|
||||||
(@accum (6) -> ($($body:tt)*))
|
(@accum (6) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (5) -> ($($body)*
|
@accum (5) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[5].0.clone())?,))};
|
.inputs()[5].0.clone())?, $($body)*))};
|
||||||
(@accum (7) -> ($($body:tt)*))
|
(@accum (7) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (6) -> ($($body)*
|
@accum (6) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[6].0.clone())?,))};
|
.inputs()[6].0.clone())?, $($body)*))};
|
||||||
(@accum (8) -> ($($body:tt)*))
|
(@accum (8) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (7) -> ($($body)*
|
@accum (7) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[7].0.clone())?,))};
|
.inputs()[7].0.clone())?, $($body)*))};
|
||||||
(@accum (9) -> ($($body:tt)*))
|
(@accum (9) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (8) -> ($($body)*
|
@accum (8) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[8].0.clone())?,))};
|
.inputs()[8].0.clone())?, $($body)*))};
|
||||||
(@accum (10) -> ($($body:tt)*))
|
(@accum (10) -> ($($body:tt)*))
|
||||||
=> {retrieve_from_cache!(
|
=> {retrieve_from_cache!(
|
||||||
@accum (9) -> ($($body)*
|
@accum (9) -> (outputs_cache.retrieve_cache_output(
|
||||||
outputs_cache.retrieve_cache_output(
|
|
||||||
graph,
|
graph,
|
||||||
node_id,
|
node_id,
|
||||||
&graph[node_id]
|
&graph[node_id]
|
||||||
.user_data
|
.user_data
|
||||||
.template
|
.template
|
||||||
.inputs()[9].0.clone())?,))};
|
.inputs()[9].0.clone())?, $($body)*))};
|
||||||
|
|
||||||
(@as_expr $e:expr) => {$e};
|
(@as_expr $e:expr) => {$e};
|
||||||
[0] => {
|
[0] => {
|
||||||
compile_error!("Macro returns a value or a tuple, supply an \
|
compile_error!("Macro returns a value or a tuple, supply an \
|
||||||
@ -895,6 +884,7 @@ fn process_template(
|
|||||||
color_node,
|
color_node,
|
||||||
color_edge,
|
color_edge,
|
||||||
) = retrieve_from_cache![5];
|
) = retrieve_from_cache![5];
|
||||||
|
|
||||||
let hash_inputs = hash_inputs!(
|
let hash_inputs = hash_inputs!(
|
||||||
input_graph,
|
input_graph,
|
||||||
display_node,
|
display_node,
|
||||||
|
|||||||
Reference in New Issue
Block a user