Skip to content

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

Merged
merged 3 commits into from
Sep 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ object Config {
/** Initial size of superId table */
final val InitialSuperIdsSize = 4096

/** Initial capacity of uniques HashMap */
final val initialUniquesCapacity = 40000
/** Initial capacity of uniques HashMap.
* Note: This MUST BE a power of two to work with util.HashSet
*/
final val initialUniquesCapacity = 65536

/** How many recursive calls to NamedType#underlying are performed before logging starts. */
final val LogPendingUnderlyingThreshold = 50
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.

/** a faster version of cs1 intersect cs2 */
def intersect(cs1: List[ClassSymbol], cs2: List[ClassSymbol]): List[ClassSymbol] = {
val cs2AsSet = new util.HashSet[ClassSymbol](100)
val cs2AsSet = new util.HashSet[ClassSymbol](128)
cs2.foreach(cs2AsSet.addEntry)
cs1.filter(cs2AsSet.contains)
}
Expand Down
13 changes: 10 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/TreeTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,16 @@ object TreeTransforms {
*/
class NXTransformations {

private def hasRedefinedMethod(cls: Class[_], name: String): Boolean =
if (cls.getDeclaredMethods.exists(_.getName == name)) cls != classOf[TreeTransform]
else hasRedefinedMethod(cls.getSuperclass, name)
private def hasRedefinedMethod(cls: Class[_], name: String): Boolean = {
val clsMethods = cls.getDeclaredMethods
var i = clsMethods.length - 1
while (i >= 0) {
if (clsMethods(i).getName == name)
return cls != classOf[TreeTransform]
i -= 1
}
hasRedefinedMethod(cls.getSuperclass, name)
}
Copy link
Contributor

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.


/** Create an index array `next` of size one larger than the size of `transforms` such that
* for each index i, `next(i)` is the smallest index j such that
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/util/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dotty.tools.dotc.util

/** A hash set that allows some privileged protected access to its internals
*/
class HashSet[T >: Null <: AnyRef](initialCapacity: Int, loadFactor: Float = 0.25f) extends Set[T] {
class HashSet[T >: Null <: AnyRef](powerOfTwoInitialCapacity: Int, loadFactor: Float = 0.25f) extends Set[T] {
private var used: Int = _
private var limit: Int = _
private var table: Array[AnyRef] = _
Expand All @@ -20,11 +20,11 @@ class HashSet[T >: Null <: AnyRef](initialCapacity: Int, loadFactor: Float = 0.2
/** Remove all elements from this set and set back to initial configuration */
def clear(): Unit = {
used = 0
allocate(initialCapacity)
allocate(powerOfTwoInitialCapacity)
}

/** Turn hashode `x` into a table index */
private def index(x: Int): Int = math.abs(x % table.length)
/** Turn hashcode `x` into a table index */
private def index(x: Int): Int = x & (table.length - 1)

/** Hashcode, can be overridden */
def hash(x: T): Int = x.hashCode
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/util/Stats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import collection.mutable
}

@inline
def record(fn: String, n: Int = 1) =
def record(fn: => String, n: => Int = 1) =
Copy link
Contributor

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.

Copy link
Member Author

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?

if (enabled) doRecord(fn, n)

private def doRecord(fn: String, n: Int) =
Expand Down