Commit Graph
3957 Commits
Author SHA1 Message Date
Oliver Hamlet b18b70f36a Update libloadorder to 18.2.0 2025-02-01 19:25:38 +00:00
Oliver Hamlet 2fa7b919ec Update spdlog to 1.15.1 2025-02-01 19:25:19 +00:00
Oliver Hamlet 1a8f1a0e0a Update fmt to 11.1.3 2025-02-01 19:25:19 +00:00
Oliver Hamlet afdafa492e Fix typo in doc comment 2025-02-01 19:25:19 +00:00
Oliver Hamlet 0fd1b82fb4 Remove test for a logging callback that goes out of scope
I've never understood why this appeared to work, but I've seen this test fail twice due to SEH exceptions in the past week, so it's better off removed. Nothing should be relying on this working (and LOOT doesn't).
2025-01-31 18:06:17 +00:00
Oliver Hamlet 6a32b63c6d Add a gamePath field to CommonGameTestFixture 2025-01-29 20:43:30 +00:00
Oliver Hamlet 553a189b9a Replace mention of BOOST_ROOT 2025-01-26 16:16:02 +00:00
Oliver Hamlet 794e796de8 Fix initialising GroupsPathVisitor::finishedVertices_ 2025-01-21 20:54:35 +00:00
Oliver Hamlet af28706210 Introduce ComparableFilename abstraction
It's a typedef that's std::wstring on Windows and icu::UnicodeString on Linux, to simplify calling CompareFilenames() with cached pre-converted strings.
2025-01-21 20:54:35 +00:00
Oliver Hamlet c3921497e6 Minor refactor of group edge code 2025-01-21 19:56:25 +00:00
Oliver Hamlet 1532c932af Update sorting doc to reflect groups changes 2025-01-18 22:29:50 +00:00
Oliver Hamlet 858a82ba50 Prioritise DFSes from the group graph roots with the longest paths
This means that when there's a potential cycle, it's more likely that an earlier group will have its effect applied than a later group.
2025-01-18 22:28:14 +00:00
Oliver Hamlet 511fa94889 Tidy up GroupsVisitor
A lot of the comments and some of the code were leftovers from an earlier, slightly different approach.
2025-01-18 20:31:31 +00:00
Oliver Hamlet 3df560646d Skip second BFS when checking for paths in both direction
It's actually significantly faster to just check if the path you're
trying to create has already been cached than to check if it actually
already exists. This improves sorting performance by 15%.
2025-01-18 10:29:05 +00:00
Oliver Hamlet 628666e4ce 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.
2025-01-18 09:39:20 +00:00
Oliver HamletandOliver Hamlet 0a61358b19 Don't add edges from fully processed group plugins twice
This improves sorting performance by 5%.
2025-01-17 23:40:13 +00:00
Oliver HamletandOliver Hamlet 997631667f Overhaul how group edges are added during sorting
The new logic is conceptually simpler, with fewer special cases to
handle. Unlike the old implementation, the new approach avoids cycles.

It basically does depth-first searches through the group graph, adding
edges from each group's plugins to the plugins in the group's
successors.

This involved reversing the direction of edges in the group graph, as
this switches the logic from trying to find predecessors to trying to
successors: the new direction matches that of plugin graph edges, so
it's less confusing.

I can't think of a situation in which the iteration order of plugins
within a group matters. I tested it manually with my test load order of
~1600 plugins, and saw no difference when the order was randomly
shuffled. I've added a test case but it's a relatively simple scenario
and there may be a more complex scenario where it would matter that I
haven't thought of.

A buffer is used to hold the plugins in the previous groups in the
current path, because that's noticeably faster than just recording the
path and looking up the plugins for each group in the path. It does
duplicate the group vectors, but that's an insignificant amount of
memory used.

The new approach has a negative performance impact, with sorting now 15%
slower than before.

A more efficient solution could be to implement a custom DFS algorithm
that doesn't stop when it reaches a vertex it's already visited (which
would be fine since the graph has already been validated to be acyclic),
as then only the root vertices would need to be searched from.
2025-01-17 23:36:02 +00:00
Oliver Hamlet 60da16e9d0 Move MergeGroups() 2025-01-17 23:13:13 +00:00
Oliver HamletandOliver Hamlet 86cdff1f21 Rework how groups are obtained when adding group edges
Pass the groups graph in and derived everything from it. This
duplicates a little work between the two plugin graphs (the group
vertex map and group predecessors map could be shared), but the group
graph is generally small enough that it doesn't seem to be significant.
2025-01-17 23:13:13 +00:00
Oliver Hamlet 885c6fd2be Sort groups metadata by name before building the groups graph
So that the graph vertices and edges have a consistent order independent of the order that the metadata is defined in.

This is less of a concern than for plugins because the order of the metadata is something that the author controls, but having the metadata order matter could be surprising and doesn't seem useful.
2025-01-17 23:13:12 +00:00
Oliver Hamlet defe94f2e3 Check for cycles as part of building the group graph 2025-01-17 22:34:19 +00:00
Oliver Hamlet 1b01b44102 Refactor building the group graph 2025-01-17 22:34:17 +00:00
Oliver Hamlet aeca443b9a Pass vectors by reference 2025-01-17 21:25:23 +00:00
Oliver Hamlet 3f4319afea Cache plugins' master flag
Avoiding the overhead of checking with esplugin improves sorting performance by 5%.
2025-01-17 20:18:34 +00:00
Oliver Hamlet 9104620ef8 Use boost::container::deque instead of std::deque
This improves sorting performance by 31%.
2025-01-17 20:18:34 +00:00