From 246eceb830ec1efb43a9b02424637c1e6b6a978b Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 29 Mar 2013 13:15:30 +0100 Subject: Optimization: avoid isDirectory call in DirectoryClassPath traversal If we just established that the given path is a File or a Directory, we don't need to go straight back to disk to re-check. Background: When profiling an application that was using the interpreter to compile a script, a lot of time was reported in exists / isDirectory / isFile. For the record, I happened to be profiling on Windows. Turns out some of these calls are redundant, this commit and the subsequent eliminate two sources thereof. Here's an example of how it helps: Taking a Hello, Akka! application, and compiling it with the compiler and library on a directory classpath (ie, using build/quick): class HelloActor extends Actor { def receive = { case "hello" => println("hello back at you") case _ => println("huh?") } } object Main extends App { val system = ActorSystem("HelloSystem") // default Actor constructor val helloActor = system.actorOf(Props[HelloActor], name = "helloactor") helloActor ! "hello" helloActor ! "buenos dias" } % qbin/scalac -Ystatistics -classpath ~/.ivy2/cache/com.typesafe.akka/akka-actor_2.10/jars/akka-actor_2.10-2.1.1.jar:/Users/jason/.ivy2/cache/com.typesafe/config/bundles/config-1.0.0.jar sandbox/test.scala 2>&1 | grep File Before ---------------------------------- File.isFile calls : 7620 File.isDirectory calls : 8348 File.exists calls : 5770 After ---------------------------------- File.isFile calls : 7620 File.isDirectory calls : 2319 File.exists calls : 5770 --- src/compiler/scala/tools/nsc/util/ClassPath.scala | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index aa4128f1a7..7f9b81e1ec 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -281,11 +281,24 @@ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[Ab private def traverse() = { val classBuf = immutable.Vector.newBuilder[ClassRep] val packageBuf = immutable.Vector.newBuilder[DirectoryClassPath] - dir foreach { f => - if (!f.isDirectory && validClassFile(f.name)) - classBuf += ClassRep(Some(f), None) - else if (f.isDirectory && validPackage(f.name)) - packageBuf += new DirectoryClassPath(f, context) + dir foreach { + f => + // Optimization: We assume the file was not changed since `dir` called + // `Path.apply` and categorized existent files as `Directory` + // or `File`. + val isDirectory = f match { + case pf: io.PlainFile => pf.givenPath match { + case _: io.Directory => true + case _: io.File => false + case _ => f.isDirectory + } + case _ => + f.isDirectory + } + if (!isDirectory && validClassFile(f.name)) + classBuf += ClassRep(Some(f), None) + else if (isDirectory && validPackage(f.name)) + packageBuf += new DirectoryClassPath(f, context) } (packageBuf.result(), classBuf.result()) } -- cgit v1.2.3