Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inline compilation benchmarks and Improve searching Graph.Link performance #9520

Merged
merged 7 commits into from
Mar 28, 2024

Conversation

hubertp
Copy link
Collaborator

@hubertp hubertp commented Mar 22, 2024

Pull Request Description

As benchmarks show, a significant amount of time is spent traversing Set of Graph.Links. That's unfortunate and unnecessary. We can equally keep helper maps that make search constant time.

Fixed inline compilation benchmarks by properly cleaning up scopes after runs.

Closes #9237.

Important Notes

Things like
Screenshot from 2024-03-22 11-23-01
Screenshot from 2024-03-22 11-13-19
are all gone. There is plenty of it those are just samples.

Benchmarks are back in order:

[info] # Warmup Iteration   1: 2.702 ms/op
[info] # Warmup Iteration   2: 3.080 ms/op
[info] # Warmup Iteration   3: 2.818 ms/op
[info] # Warmup Iteration   4: 3.334 ms/op
[info] # Warmup Iteration   5: 2.448 ms/op
[info] # Warmup Iteration   6: 2.583 ms/op
[info] Iteration   1: 2.908 ms/op
[info] Iteration   2: 2.915 ms/op
[info] Iteration   3: 2.774 ms/op
[info] Iteration   4: 2.601 ms/op
[info] Result "org.enso.compiler.benchmarks.inline.InlineCompilerBenchmark.longExpression":
[info]   2.799 ±(99.9%) 0.953 ms/op [Average]
[info]   (min, avg, max) = (2.601, 2.799, 2.915), stdev = 0.148
[info]   CI (99.9%): [1.846, 3.753] (assumes normal distribution)

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.

As benchmarks show, a significant amount of time is spent traversing
`Set` of `Graph.Link`s. That's unfortunate and unnecessary. We can
equally keep helper maps that make search constant time.
@hubertp hubertp changed the title Improve performance for searching Graph.Link Improve searching Graph.Link performance Mar 22, 2024
@hubertp hubertp added the CI: No changelog needed Do not require a changelog entry for this PR. label Mar 22, 2024
var rootScope: Graph.Scope = new Graph.Scope()
private var links: Set[Graph.Link] = Set()
private var sourceLinks: Map[Graph.Id, Set[Graph.Link]] = new HashMap()
private var targetLinks: Map[Graph.Id, Set[Graph.Link]] = new HashMap()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an implementation of serialization logic for the Graph

@org.openide.util.lookup.ServiceProvider(service = Persistance.class)
public static final class PersistAliasAnalysisGraph extends Persistance<Graph> {
public PersistAliasAnalysisGraph() {
super(Graph.class, false, 1268);
}

Please make sure that it works correctly with the newly added fields and probably update the serialization id

Copy link
Collaborator Author

@hubertp hubertp Mar 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should work correctly as I'm reproducing sourceLinks and targetLinks from links when deserialized. I'm not serializing those fields as there is no need for that (links continues to be serialized).

@hubertp hubertp requested a review from 4e6 March 23, 2024 19:08
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see a speedup. Some comments related to the code left inline.

var rootScope: Graph.Scope = new Graph.Scope()
var links: Set[Graph.Link] = Set()
var nextIdCounter = 0
var rootScope: Graph.Scope = new Graph.Scope()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If initXyz is better pattern than calling g.rootScope_$eq(rootScope); - then rootScope could be made private as well, possibly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried and looks like a lot more stuff depends on it being public. I tried to keep the PR succinct for now.

@@ -129,7 +155,10 @@ sealed class Graph extends Serializable {
* @return a list of links in which `id` occurs
*/
def linksFor(id: Graph.Id): Set[Graph.Link] = {
links.filter(l => l.source == id || l.target == id)
sourceLinks.getOrElse(id, Set.empty[Graph.Link]) ++ targetLinks.getOrElse(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great finding. Good fix. Thank you.

}
}

def getLinks(): Set[Graph.Link] = links
Copy link
Member

@JaroslavTulach JaroslavTulach Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to remove the links field all together and just compute the links from sourceLinks and targetLinks? The logic between initLinks and getLinks & co. would be simpler and possibly getLinks() isn't on critical path. Otherwise the inconsistency must have been caught somewhere, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like that links is the source of truth and sourceLinks/targetLinks serve as aux indexes for quicker access. It also simplifies serde.

Treat InlineContext as a closeable resource, to ensure that benchmarks
properly cleanup.
The problem was that the number of scopes has been steadily increasing
with every benchmark run. Traversing such additional scopes took time,
hence exponential blow up in run times.
@hubertp
Copy link
Collaborator Author

hubertp commented Mar 27, 2024

With the last change the inline compilation benchmarks are back in order:

[info] # Warmup Iteration   1: 2.702 ms/op
[info] # Warmup Iteration   2: 3.080 ms/op
[info] # Warmup Iteration   3: 2.818 ms/op
[info] # Warmup Iteration   4: 3.334 ms/op
[info] # Warmup Iteration   5: 2.448 ms/op
[info] # Warmup Iteration   6: 2.583 ms/op
[info] Iteration   1: 2.908 ms/op
[info] Iteration   2: 2.915 ms/op
[info] Iteration   3: 2.774 ms/op
[info] Iteration   4: 2.601 ms/op
[info] Result "org.enso.compiler.benchmarks.inline.InlineCompilerBenchmark.longExpression":
[info]   2.799 ±(99.9%) 0.953 ms/op [Average]
[info]   (min, avg, max) = (2.601, 2.799, 2.915), stdev = 0.148
[info]   CI (99.9%): [1.846, 3.753] (assumes normal distribution)

@hubertp hubertp changed the title Improve searching Graph.Link performance Fix inline compilation benchmarks and Improve searching Graph.Link performance Mar 27, 2024
@hubertp hubertp added the CI: Ready to merge This PR is eligible for automatic merge label Mar 28, 2024
@hubertp hubertp added the CI: Clean build required CI runners will be cleaned before and after this PR is built. label Mar 28, 2024
@mergify mergify bot merged commit 1c724a4 into develop Mar 28, 2024
37 of 41 checks passed
@mergify mergify bot deleted the wip/hubert/compiler-inline-perf branch March 28, 2024 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Clean build required CI runners will be cleaned before and after this PR is built. CI: No changelog needed Do not require a changelog entry for this PR. CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Analyze and improve the performance of inline compilation
4 participants