mirror of
https://github.com/sbt/sbt.git
synced 2026-10-06 18:14:04 +02:00
Drop INode settings evaluator in favor of direct evaluation.
Raw evaluation time goes up, but overall startup time goes down. On the sbt build, raw evaluation time goes from 1.8 s to 2.0 s but overall startup from 12.2 s to 11.6 s. Warm evaluation time goes from 0.25 to 0.5 s, but overall reload time is less affected. Presumably the reason for this is class loading and jit times.
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
package sbt
|
||||
|
||||
import java.lang.Runnable
|
||||
import java.util.concurrent.{atomic, Executor, LinkedBlockingQueue}
|
||||
import atomic.{AtomicBoolean, AtomicInteger}
|
||||
import Types.{:+:, ConstK, Id}
|
||||
|
||||
abstract class EvaluateSettings[Scope]
|
||||
{
|
||||
protected val init: Init[Scope]
|
||||
import init._
|
||||
protected def compiledSettings: Seq[Compiled[_]]
|
||||
|
||||
private[this] val static = PMap.empty[ScopedKey, INode]
|
||||
private[this] val allScopes: Set[Scope] = compiledSettings.map(_.key.scope).toSet
|
||||
private[this] def getStatic[T](key: ScopedKey[T]): INode[T] = static get key getOrElse sys.error("Illegal reference to key " + key)
|
||||
|
||||
private[this] val transform: Initialize ~> INode = new (Initialize ~> INode) { def apply[T](i: Initialize[T]): INode[T] = i match {
|
||||
case k: Keyed[s, T] => single(getStatic(k.scopedKey), k.transform)
|
||||
case a: Apply[k,T] => new MixedNode[k,T]( a.alist.transform[Initialize, INode](a.inputs, transform), a.f, a.alist)
|
||||
case b: Bind[s,T] => new BindNode[s,T]( transform(b.in), x => transform(b.f(x)))
|
||||
case init.StaticScopes => constant(() => allScopes.asInstanceOf[T]) // can't convince scalac that StaticScopes => T == Set[Scope]
|
||||
case v: Value[T] => constant(v.value)
|
||||
case t: TransformCapture => constant(() => t.f)
|
||||
case o: Optional[s,T] => o.a match {
|
||||
case None => constant( () => o.f(None) )
|
||||
case Some(i) => single[s,T](transform(i), x => o.f(Some(x)))
|
||||
}
|
||||
}}
|
||||
private[this] lazy val roots: Seq[INode[_]] = compiledSettings flatMap { cs =>
|
||||
(cs.settings map { s =>
|
||||
val t = transform(s.init)
|
||||
static(s.key) = t
|
||||
t
|
||||
}): Seq[INode[_]]
|
||||
}
|
||||
|
||||
def run(implicit delegates: Scope => Seq[Scope]): Settings[Scope] =
|
||||
{
|
||||
roots.foreach( _.value )
|
||||
getResults(delegates)
|
||||
}
|
||||
private[this] def getResults(implicit delegates: Scope => Seq[Scope]) =
|
||||
(empty /: static.toTypedSeq) { case (ss, static.TPair(key, node)) =>
|
||||
if(key.key.isLocal) ss else ss.set(key.scope, key.key, node.value)
|
||||
}
|
||||
|
||||
private[this] sealed abstract class INode[T]
|
||||
{
|
||||
final lazy val value: T = {
|
||||
val v = evaluate
|
||||
if(v == null) sys.error("Setting value cannot be null: " + keyString)
|
||||
v
|
||||
}
|
||||
|
||||
override def toString = getClass.getName + ": " + keyString
|
||||
|
||||
private[this] def keyString =
|
||||
(static.toSeq.flatMap { case (key, value) => if(value eq this) init.showFullKey(key) :: Nil else Nil }).headOption getOrElse "non-static"
|
||||
|
||||
protected def evaluate: T
|
||||
}
|
||||
private[this] val getValue = new (INode ~> Id) { def apply[T](i: INode[T]): T = i.value }
|
||||
private[this] def constant[T](f: () => T): INode[T] = new MixedNode[ConstK[Unit]#l, T]((), _ => f(), AList.empty)
|
||||
private[this] def single[S,T](in: INode[S], f: S => T): INode[T] = new MixedNode[ ({ type l[L[x]] = L[S] })#l, T](in, f, AList.single[S])
|
||||
private[this] final class BindNode[S,T](in: INode[S], f: S => INode[T]) extends INode[T]
|
||||
{
|
||||
protected def evaluate: T = f(in.value).value
|
||||
}
|
||||
private[this] final class MixedNode[K[L[x]], T](in: K[INode], f: K[Id] => T, alist: AList[K]) extends INode[T]
|
||||
{
|
||||
protected def evaluate: T = f( alist.transform(in, getValue) )
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,11 @@ trait Init[Scope]
|
||||
private[this] final def nextDefaultID(): Long = nextID.incrementAndGet()
|
||||
|
||||
|
||||
def emptyScopes(scopes: Set[Scope])(implicit delegates: Scope => Seq[Scope]): Settings[Scope] =
|
||||
{
|
||||
val m = (Map.empty[Scope, AttributeMap] /: scopes) { case (m, s) => m.updated(s, AttributeMap.empty) }
|
||||
new Settings0(m, delegates)
|
||||
}
|
||||
def empty(implicit delegates: Scope => Seq[Scope]): Settings[Scope] = new Settings0(Map.empty, delegates)
|
||||
def asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) {
|
||||
def apply[T](k: ScopedKey[T]): T = getValue(s, k)
|
||||
@@ -182,11 +187,14 @@ trait Init[Scope]
|
||||
|
||||
private[this] def applyInits(ordered: Seq[Compiled[_]])(implicit delegates: Scope => Seq[Scope]): Settings[Scope] =
|
||||
{
|
||||
val eval: EvaluateSettings[Scope] = new EvaluateSettings[Scope] {
|
||||
override val init: Init.this.type = Init.this
|
||||
def compiledSettings = ordered
|
||||
val allScopes: Set[Scope] = ordered.map(_.key.scope).toSet
|
||||
|
||||
(emptyScopes(allScopes) /: ordered) { case (settings, ss) =>
|
||||
(settings /: ss.settings) { case (intersettings, s) =>
|
||||
val value = s.init.evaluate(intersettings)
|
||||
intersettings.set(s.key.scope, s.key.key, value)
|
||||
}
|
||||
}
|
||||
eval.run
|
||||
}
|
||||
|
||||
def showUndefined(u: Undefined, validKeys: Seq[ScopedKey[_]], delegates: Scope => Seq[Scope])(implicit display: Show[ScopedKey[_]]): String =
|
||||
|
||||
Reference in New Issue
Block a user