Improve runtime of time spanning functor #3587
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR started with the observation that on a large file (about 260 pages) the
PrepareTimeSpanning
was the slowest of all functors - which seemed counterintuitive. The PR improves the functor runtime, especially for larger files:To somehow understand the runtime issue, consider the following example. There are two kind of spanning elements: those that live in one measure and those that extend over several measures.
With functor traversal we will visit start note, end note, tie for the green tie. This is good, since it means that by traversing backwards we can directly resolve endpoints. However, for the red slur we will visit start note, slur, end note. This is bad, since (independent of the traversal direction) we will always miss one endpoint in the first pass. So the slur must be kept in a list for the remaining pass and this is costly since each element in the list is ID compared against each layer element that is visited.
To improve the algorithm, we always pass forward, but collect all time spanning descendants at the begin of each measure. So both the red slur and green tie in the example above are collected before we visit its start and end note. This allows to resolve pretty much all time spanning elements in one go, if they are encoded in a sensible way (i.e. the element is encoded in the measure where it starts).
Open question: we still keep some code to resolve time spanning elements which are encoded outside of a measure (see
VisitFloatingObject
andVisitF
). I simply did not know whether this is possible in MEI.