From 628666e4ce54b47cdc19cd2d04e28b05fefd613d Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 18 Jan 2025 09:39:20 +0000 Subject: [PATCH] Check if a graph path already exists before adding one Checking if a path exists is where sorting spends most of its time, and it gets slower the more edges the graph has, so avoid adding an edge between two plugins if there's already a path between them. This improves sorting performance by 19%. This doesn't add any additional path checks, as all the specific and hardcoded edges need to be added to ensure their validity (by then checking for cycles), and tie-breaking is more complicated so is worth dealing with separately. --- src/api/sorting/plugin_graph.cpp | 24 ++++++++++++++++++++++-- src/api/sorting/plugin_graph.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/api/sorting/plugin_graph.cpp b/src/api/sorting/plugin_graph.cpp index bb425c93..f572bb5f 100644 --- a/src/api/sorting/plugin_graph.cpp +++ b/src/api/sorting/plugin_graph.cpp @@ -259,7 +259,7 @@ private: for (const auto& toVertex : toPlugins) { const auto& toPlugin = pluginGraph_->GetPlugin(toVertex); - if (!pluginGraph_->PathExists(toVertex, fromVertex)) { + if (!pluginGraph_->PathExistsInEitherDirection(toVertex, fromVertex)) { const auto involvesUserMetadata = groupPathInvolvesUserMetadata || fromPlugin.IsGroupUserMetadata() || toPlugin.IsGroupUserMetadata(); @@ -738,6 +738,26 @@ bool PluginGraph::PathExists(const vertex_t& fromVertex, return loot::FindPath(graph_, fromVertex, toVertex, visitor); } +bool PluginGraph::PathExistsInEitherDirection(const vertex_t& vertex, + const vertex_t& otherVertex) { + if (pathsCache_.IsPathCached(vertex, otherVertex) || + pathsCache_.IsPathCached(otherVertex, vertex)) { + return true; + } + + { + PathCacher visitor(pathsCache_, vertex, otherVertex); + + if (loot::FindPath(graph_, vertex, otherVertex, visitor)) { + return true; + } + } + + PathCacher visitor(pathsCache_, otherVertex, vertex); + + return loot::FindPath(graph_, otherVertex, vertex, visitor); +} + std::optional> PluginGraph::FindPath( const vertex_t& fromVertex, const vertex_t& toVertex) { @@ -1032,7 +1052,7 @@ void PluginGraph::AddOverlapEdges() { const auto fromVertex = thisPluginLoadsFirst ? vertex : otherVertex; const auto toVertex = thisPluginLoadsFirst ? otherVertex : vertex; - if (!PathExists(toVertex, fromVertex)) { + if (!PathExistsInEitherDirection(toVertex, fromVertex)) { AddEdge(fromVertex, toVertex, edgeType); } else if (logger) { logger->debug( diff --git a/src/api/sorting/plugin_graph.h b/src/api/sorting/plugin_graph.h index 70bf23d9..7e28c833 100644 --- a/src/api/sorting/plugin_graph.h +++ b/src/api/sorting/plugin_graph.h @@ -90,6 +90,8 @@ public: bool EdgeExists(const vertex_t& fromVertex, const vertex_t& toVertex); bool PathExists(const vertex_t& fromVertex, const vertex_t& toVertex); + bool PathExistsInEitherDirection(const vertex_t& vertex, + const vertex_t& otherVertex); std::optional> FindPath(const vertex_t& fromVertex, const vertex_t& toVertex);