From 554840f9b5cd30a8e3209cb18bdf9925f364cc68 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sun, 25 Feb 2018 13:51:50 -0800 Subject: A few attempts at micro-optimizing the current hot spots --- core/src/mill/define/Module.scala | 31 +++++++++++++++++-------------- core/src/mill/eval/Evaluator.scala | 22 +++++++++++++++------- core/src/mill/eval/Result.scala | 4 +++- core/src/mill/util/Logger.scala | 2 +- 4 files changed, 36 insertions(+), 23 deletions(-) (limited to 'core/src') diff --git a/core/src/mill/define/Module.scala b/core/src/mill/define/Module.scala index 93537f76..0f8e96ce 100644 --- a/core/src/mill/define/Module.scala +++ b/core/src/mill/define/Module.scala @@ -56,22 +56,25 @@ object Module{ lazy val millModuleLine = outer.millOuterCtx.lineNum def reflect[T: ClassTag] = { - outer - .getClass - .getMethods - .filter(!_.getName.contains('$')) - .filter(_.getParameterCount == 0) - .filter(x => (x.getModifiers & Modifier.STATIC) == 0) - .filter(implicitly[ClassTag[T]].runtimeClass isAssignableFrom _.getReturnType) - .map(_.invoke(outer).asInstanceOf[T]) + val runtimeCls = implicitly[ClassTag[T]].runtimeClass + for{ + m <- outer.getClass.getMethods + if + !m.getName.contains('$') && + m.getParameterCount == 0 && + (m.getModifiers & Modifier.STATIC) == 0 && + runtimeCls.isAssignableFrom(m.getReturnType) + } yield m.invoke(outer).asInstanceOf[T] + } def reflectNames[T: ClassTag] = { - outer - .getClass - .getMethods - .filter(x => (x.getModifiers & Modifier.STATIC) == 0) - .filter(implicitly[ClassTag[T]].runtimeClass isAssignableFrom _.getReturnType) - .map(_.getName) + val runtimeCls = implicitly[ClassTag[T]].runtimeClass + for{ + m <- outer.getClass.getMethods + if + (m.getModifiers & Modifier.STATIC) == 0 && + runtimeCls.isAssignableFrom(m.getReturnType) + } yield m.getName } // For some reason, this fails to pick up concrete `object`s nested directly within // another top-level concrete `object`. This is fine for now, since Mill's Ammonite diff --git a/core/src/mill/eval/Evaluator.scala b/core/src/mill/eval/Evaluator.scala index 57d39a24..42015c6f 100644 --- a/core/src/mill/eval/Evaluator.scala +++ b/core/src/mill/eval/Evaluator.scala @@ -32,7 +32,7 @@ case class Evaluator[T](outPath: Path, log: Logger, classLoaderSig: Seq[(Path, Long)] = Evaluator.classLoaderSig, workerCache: mutable.Map[Segments, (Int, Any)] = mutable.Map.empty){ - + val classLoaderSignHash = classLoaderSig.hashCode() def evaluate(goals: Agg[Task[_]]): Evaluator.Results = { mkdir(outPath) @@ -82,7 +82,12 @@ case class Evaluator[T](outPath: Path, for (((terminal, group), i) <- sortedGroups.items().zipWithIndex){ // Increment the counter message by 1 to go from 1/10 to 10/10 instead of 0/10 to 9/10 val counterMsg = (i+1) + "/" + sortedGroups.keyCount - val (newResults, newEvaluated) = evaluateGroupCached(terminal, group, results, counterMsg) + val (newResults, newEvaluated) = evaluateGroupCached( + terminal, + group, + results, + counterMsg) + for(ev <- newEvaluated){ evaluated.append(ev) } @@ -114,13 +119,16 @@ case class Evaluator[T](outPath: Path, results: collection.Map[Task[_], Result[(Any, Int)]], counterMsg: String): (collection.Map[Task[_], Result[(Any, Int)]], Seq[Task[_]]) = { + val externalInputsHash = scala.util.hashing.MurmurHash3.orderedHash( + group.items.flatMap(_.inputs).filter(!group.contains(_)) + .flatMap(results(_).asSuccess.map(_.value._2)) + ) - val externalInputs = group.items.flatMap(_.inputs).filter(!group.contains(_)).toVector + val sideHashes = scala.util.hashing.MurmurHash3.orderedHash( + group.toIterator.map(_.sideHash) + ) - val inputsHash = - externalInputs.map(results(_).map(_._2)).hashCode + - group.toIterator.map(_.sideHash).toVector.hashCode() + - classLoaderSig.hashCode() + val inputsHash = externalInputsHash + sideHashes + classLoaderSignHash terminal match{ case Left(task) => diff --git a/core/src/mill/eval/Result.scala b/core/src/mill/eval/Result.scala index 690c5d30..d0400599 100644 --- a/core/src/mill/eval/Result.scala +++ b/core/src/mill/eval/Result.scala @@ -2,14 +2,16 @@ package mill.eval sealed trait Result[+T]{ def map[V](f: T => V): Result[V] + def asSuccess: Option[Result.Success[T]] = None } object Result{ implicit def create[T](t: => T): Result[T] = { try Success(t) catch { case e: Throwable => Exception(e, new OuterStack(new java.lang.Exception().getStackTrace)) } } - case class Success[T](value: T) extends Result[T]{ + case class Success[+T](value: T) extends Result[T]{ def map[V](f: T => V) = Result.Success(f(value)) + override def asSuccess = Some(this) } case object Skipped extends Result[Nothing]{ def map[V](f: Nothing => V) = this diff --git a/core/src/mill/util/Logger.scala b/core/src/mill/util/Logger.scala index 55ea84cc..714b9add 100644 --- a/core/src/mill/util/Logger.scala +++ b/core/src/mill/util/Logger.scala @@ -136,7 +136,7 @@ case class FileLogger(colored: Boolean, file: Path) extends Logger { def info(s: String) = outputStream.println(s) def error(s: String) = outputStream.println(s) def ticker(s: String) = outputStream.println(s) - val inStream: InputStream = new ByteArrayInputStream(Array()) + val inStream: InputStream = DummyInputStream override def close() = { if (outputStreamUsed) outputStream.close() -- cgit v1.2.3