Skip to content

Commit

Permalink
impr: Run data processor in a worker task
Browse files Browse the repository at this point in the history
  • Loading branch information
WerWolv committed Jul 11, 2024
1 parent 7975eda commit 8422965
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 75 deletions.
50 changes: 14 additions & 36 deletions lib/libimhex/include/hex/data_processor/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
#include <hex/providers/provider_data.hpp>

namespace hex::prv {
class Provider;
Expand Down Expand Up @@ -42,8 +43,9 @@ namespace hex::dp {
m_overlay = overlay;
}

virtual void drawNode() { }
void draw();
virtual void process() = 0;
virtual void reset() { }

virtual void store(nlohmann::json &j) const { hex::unused(j); }
virtual void load(const nlohmann::json &j) { hex::unused(j); }
Expand Down Expand Up @@ -80,6 +82,11 @@ namespace hex::dp {
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, double floatingPoint);

static void interrupt();

protected:
virtual void drawNode() { }

private:
int m_id;
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
Expand All @@ -90,45 +97,16 @@ namespace hex::dp {

static int s_idCounter;

Attribute& getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");

return this->getAttributes()[index];
}

Attribute *getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();

if (connectedAttribute.empty())
return nullptr;

return connectedAttribute.begin()->second;
}

void markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
}

void unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}
Attribute& getAttribute(u32 index);
Attribute *getConnectedInputAttribute(u32 index);
void markInputProcessed(u32 index);
void unmarkInputProcessed(u32 index);

protected:
[[noreturn]] void throwNodeError(const std::string &message) {
throw NodeError { this, message };
}
[[noreturn]] void throwNodeError(const std::string &message);

void setOverlayData(u64 address, const std::vector<u8> &data);

void setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);

for (auto &attr : m_attributes)
attr.setParentNode(this);
}
void setAttributes(std::vector<Attribute> attributes);
};

}
53 changes: 53 additions & 0 deletions lib/libimhex/source/data_processor/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@
namespace hex::dp {

int Node::s_idCounter = 1;
static std::atomic_bool s_interrupted;

Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
for (auto &attr : m_attributes)
attr.setParentNode(this);
}

void Node::draw() {
this->drawNode();
}


const std::vector<u8>& Node::getBufferOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);

Expand Down Expand Up @@ -148,9 +154,56 @@ namespace hex::dp {
m_overlay->getData() = data;
}

[[noreturn]] void Node::throwNodeError(const std::string &message) {
throw NodeError { this, message };
}

void Node::setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);

for (auto &attr : m_attributes)
attr.setParentNode(this);
}

void Node::setIdCounter(int id) {
if (id > s_idCounter)
s_idCounter = id;
}

Attribute& Node::getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");

return this->getAttributes()[index];
}

Attribute *Node::getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();

if (connectedAttribute.empty())
return nullptr;

return connectedAttribute.begin()->second;
}

void Node::markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");

if (s_interrupted) {
s_interrupted = false;
throwNodeError("Execution interrupted!");
}
}

void Node::unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}

void Node::interrupt() {
s_interrupted = true;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <imnodes_internal.h>

#include <string>
#include <hex/api/task_manager.hpp>
#include <nlohmann/json.hpp>

namespace hex::plugin::builtin {
Expand All @@ -17,6 +18,8 @@ namespace hex::plugin::builtin {
struct Workspace {
Workspace() = default;



std::unique_ptr<ImNodesContext, void(*)(ImNodesContext*)> context = { []{
ImNodesContext *ctx = ImNodes::CreateContext();
ctx->Style = ImNodes::GetStyle();
Expand Down Expand Up @@ -47,7 +50,7 @@ namespace hex::plugin::builtin {

static void eraseLink(Workspace &workspace, int id);
static void eraseNodes(Workspace &workspace, const std::vector<int> &ids);
static void processNodes(Workspace &workspace);
void processNodes(Workspace &workspace);

void reloadCustomNodes();
void updateNodePositions();
Expand All @@ -74,6 +77,7 @@ namespace hex::plugin::builtin {

PerProvider<Workspace> m_mainWorkspace;
PerProvider<std::vector<Workspace*>> m_workspaceStack;
TaskHolder m_evaluationTask;
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ namespace hex::plugin::builtin {
this->setIntegerOnOutput(4, m_value);
}

void reset() override {
m_started = false;
}

private:
bool m_started = false;
i128 m_value = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ namespace hex::plugin::builtin {
}

void process() override {
m_value.reset();
const auto &input = this->getIntegerOnInput(0);

m_value = input;
m_value = this->getIntegerOnInput(0);
}

private:
Expand Down
93 changes: 59 additions & 34 deletions plugins/builtin/source/content/views/view_data_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,6 @@ namespace hex::plugin::builtin {
m_updateNodePositions = true;
});

EventDataChanged::subscribe(this, [this](prv::Provider *provider) {
ViewDataProcessor::processNodes(*m_workspaceStack.get(provider).back());
});

/* Import Nodes */
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.data_processor" }, ICON_VS_CHIP, 4050, Shortcut::None, [this]{
fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } },
Expand Down Expand Up @@ -532,36 +528,49 @@ namespace hex::plugin::builtin {
// Reset any potential node errors
workspace.currNodeError.reset();

// Process all nodes in the workspace
try {
for (auto &endNode : workspace.endNodes) {
// Reset the output data of the end node
endNode->resetOutputData();
m_evaluationTask = TaskManager::createTask("Evaluating Nodes...", 0, [this, workspace = &workspace](Task& task) {
task.setInterruptCallback([]{
dp::Node::interrupt();
});
do {

// Reset processed inputs of all nodes
for (auto &node : workspace.nodes)
node->resetProcessedInputs();
// Process all nodes in the workspace
try {
for (auto &endNode : workspace->endNodes) {
// Reset the output data of the end node
endNode->resetOutputData();

// Reset processed inputs of all nodes
for (auto &node : workspace->nodes) {
node->reset();
node->resetProcessedInputs();
}

// Process the end node
endNode->process();
}
} catch (const dp::Node::NodeError &e) {
// Handle user errors
// Process the end node
endNode->process();
}
} catch (const dp::Node::NodeError &e) {
// Handle user errors

// Add the node error to the current workspace, so it can be displayed
workspace->currNodeError = e;

// Delete all overlays
for (auto overlay : workspace->dataOverlays)
ImHexApi::Provider::get()->deleteOverlay(overlay);
workspace->dataOverlays.clear();
} catch (const std::runtime_error &e) {
// Handle internal errors
log::fatal("Data processor node implementation bug! {}", e.what());
} catch (const std::exception &e) {
// Handle other fatal errors
log::fatal("Unhandled exception thrown in data processor node! {}", e.what());
}

// Add the node error to the current workspace, so it can be displayed
workspace.currNodeError = e;
task.update();
} while (m_continuousEvaluation);
});

// Delete all overlays
for (auto overlay : workspace.dataOverlays)
ImHexApi::Provider::get()->deleteOverlay(overlay);
workspace.dataOverlays.clear();
} catch (const std::runtime_error &e) {
// Handle internal errors
log::fatal("Data processor node implementation bug! {}", e.what());
} catch (const std::exception &e) {
// Handle other fatal errors
log::fatal("Unhandled exception thrown in data processor node! {}", e.what());
}
}

void ViewDataProcessor::reloadCustomNodes() {
Expand Down Expand Up @@ -774,7 +783,9 @@ namespace hex::plugin::builtin {

// Draw the node's body
ImGui::PopStyleVar();
node.drawNode();
if (!m_evaluationTask.isRunning()) {
node.draw();
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0F, 1.0F));

// Draw all attributes of the node
Expand Down Expand Up @@ -851,6 +862,8 @@ namespace hex::plugin::builtin {
void ViewDataProcessor::drawContent() {
auto &workspace = *m_workspaceStack->back();

ImGui::BeginDisabled(m_evaluationTask.isRunning());

bool popWorkspace = false;
// Set the ImNodes context to the current workspace context
ImNodes::SetCurrentContext(workspace.context.get());
Expand All @@ -873,6 +886,9 @@ namespace hex::plugin::builtin {
if (ImGui::BeginChild("##node_editor", ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 1.3F))) {
ImNodes::BeginNodeEditor();

if (m_evaluationTask.isRunning())
ImNodes::GetCurrentContext()->MousePos = { FLT_MAX, FLT_MAX };

// Loop over all nodes that have been placed in the workspace
bool stillUpdating = m_updateNodePositions;
for (auto &node : workspace.nodes) {
Expand Down Expand Up @@ -933,18 +949,27 @@ namespace hex::plugin::builtin {
}
ImGui::EndChild();

ImGui::EndDisabled();

// Draw the control bar at the bottom
{
if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)) || m_continuousEvaluation)
this->processNodes(workspace);
if (!m_evaluationTask.isRunning()) {
if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
this->processNodes(workspace);
}
} else {
if (ImGuiExt::IconButton(ICON_VS_DEBUG_STOP, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
m_evaluationTask.interrupt();
}
}

ImGui::SameLine();

ImGui::Checkbox("Continuous evaluation", &m_continuousEvaluation);
}


// Erase links that have been distroyed
// Erase links that have been destroyed
{
int linkId;
if (ImNodes::IsLinkDestroyed(&linkId)) {
Expand Down

0 comments on commit 8422965

Please sign in to comment.