-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Various performance optimizations #3214
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
Conversation
When `Stats.enabled` is false, `Stats.record` should be free, but before this commit this wasn't the case: since the `n` passed to `record` was by-value, it had to be evaluated, this is very expensive for calls like: record("retained typed trees after typer", unit.tpdTree.treeSize) Before this commit, we got after inlining: val n = unit.tpdTree.treeSize Now we get: def n = unit.tpdTree.treeSize it'd be even nicer if we didn't generate anything at all, but this shouldn't have much impact on running time.
(I found this performance issue by using https://github.com/jvm-profiling-tools/async-profiler) |
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3214/ to see the changes. Benchmarks is based on merge(s) with master |
I went ahead and did some more optimizations while I was at it :). |
Using "%" to find the index of an entry in the backing array is expensive, by restricting our backing array size to be a power of two we can use "&" instead. This is similar to what we do in the implementation of MutableScope (note: should we try to avoid code duplication between util.HashSet and MutableScope?).
This showed up while doing some CPU profiling,
2e18f11
to
c47f0c2
Compare
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3214/ to see the changes. Benchmarks is based on merge(s) with master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to follow up on hasRedefinedMethod
. Otherwise LGTM.
i -= 1 | ||
} | ||
hasRedefinedMethod(cls.getSuperclass, name) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why this method shows up as hot. It should only be called during initialization when we compute the tree transformers. How often is the method called? Back of the envelope calculation: 100 phases * 50 methods, i.e. 5000? If its significantly more than that there's something we have overlooked.
@@ -21,7 +21,7 @@ import collection.mutable | |||
} | |||
|
|||
@inline | |||
def record(fn: String, n: Int = 1) = | |||
def record(fn: => String, n: => Int = 1) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One can do even better by using two overloaded versions of record
and no default argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how, could you give more details?
No description provided.