Optimize AliasAnalysis hotspot (#8701)

`scopeFor` is a real hotspot that hasn't been particularly optimized. By using iterator and a simple variable instead of a list and checking its length I was able to get 10% speedup.
Note that it seems tempting to throw the exception within the loop but that seems to create a less optimized code.

# Important Notes
I'm consistently getting ~10% speedup on a hello world example (with standard libraries).

For example I'm no longer seeing 20ms spent in `scopeFor` and most of them are below 10ms:
![Screenshot from 2024-01-08 12-15-30](https://github.com/enso-org/enso/assets/292128/033ece07-eb15-45b5-971f-417bf9f17ef7)

Before
![Screenshot from 2024-01-08 12-17-32](https://github.com/enso-org/enso/assets/292128/3848d7c2-0fe8-4951-b222-c8f40d2daf01)

After
![Screenshot from 2024-01-08 12-17-09](https://github.com/enso-org/enso/assets/292128/524496f5-3cf0-47f4-8b05-edd330080b14)
This commit is contained in:
Hubert Plociniczak 2024-01-11 16:49:39 +01:00 committed by GitHub
parent fc0361f502
commit a94cad6bfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1010,16 +1010,10 @@ case object AliasAnalysis extends IRPass {
def resolveLocalUsage(
occurrence: Graph.Occurrence.Use
): Option[Graph.Link] = {
scopeFor(occurrence.id) match {
case Some(scope) =>
scope.resolveUsage(occurrence) match {
case Some(link) =>
links += link
Some(link)
case None => None
}
case None => None
}
scopeFor(occurrence.id).flatMap(_.resolveUsage(occurrence).map { link =>
links += link
link
})
}
/** Resolves any links for the given usage of a symbol, assuming the symbol
@ -1457,20 +1451,35 @@ case object AliasAnalysis extends IRPass {
def scopeFor(id: Graph.Id): Option[Scope] = {
val possibleCandidates = occurrences.filter(o => o.id == id)
if (possibleCandidates.size == 1) {
Some(this)
} else if (possibleCandidates.isEmpty) {
val childCandidates = childScopes.map(_.scopeFor(id)).collect {
case Some(scope) => scope
}
if (childCandidates.length == 1) {
Some(childCandidates.head)
} else if (childCandidates.isEmpty) {
if (possibleCandidates.isEmpty) {
if (childScopes.isEmpty) {
None
} else {
throw new CompilerError(s"ID $id defined in multiple scopes.")
var childCandidate: Scope = null
val iter = childScopes.iterator
var moreThanOne = false
while (iter.hasNext && !moreThanOne) {
iter.next().scopeFor(id) match {
case Some(s) =>
if (childCandidate == null) {
childCandidate = s
} else {
moreThanOne = true
}
case None =>
}
}
if (childCandidate == null) {
None
} else if (moreThanOne) {
throw new CompilerError(s"ID $id defined in multiple scopes.")
} else {
Some(childCandidate)
}
}
} else if (possibleCandidates.size == 1) {
Some(this)
} else {
throw new CompilerError(s"Multiple occurrences found for ID $id.")
}