Browse files

Performance improvements for cli json report and minor refactoring (#724


Major change:
* Identified hotspot in `JsonElem.hashCode` because it hashes children recursively. Hence simplified hashing scheme, reducing CPU time on `JsonReport.apply()` from 64.7 sec to 2.5 sec

Other minor changes:
* Make `JsonRequirement` use immutable classes
* Simplify `JsonRequirement` composition
  • Loading branch information...
wisechengyi committed Jan 1, 2018
1 parent c8fa463 commit 5da2210d7fa15e95608dc9fe396aa4d364702115
@@ -716,12 +716,12 @@ class Helper(
a.isOptional && notFound
val artifactToFile: collection.mutable.Map[String, File] = collection.mutable.Map()
val files0 = results.collect {
val artifactToFile = results.collect {
case (artifact: Artifact, \/-(f)) =>
artifactToFile.put(artifact.url, f)
(artifact.url, f)
val files0 = artifactToFile.values.toSeq
@@ -769,9 +769,9 @@ class Helper(
val artifacts: Seq[(Dependency, Artifact)] = res.dependencyArtifacts
val jsonReq = JsonPrintRequirement(artifactToFile, depToArtifacts, conflictResolutionForRoots)
val jsonReq = JsonPrintRequirement(artifactToFile, depToArtifacts)
val roots =, artifacts, Option(jsonReq), res, printExclusions = verbosityLevel >= 1, excluded = false, colors = false))
val jsonStr = JsonReport(roots, jsonReq.conflictResolutionForRoots)(_.children, _.reconciledVersionStr, _.requestedVersionStr, _.downloadedFiles)
val jsonStr = JsonReport(roots, conflictResolutionForRoots)(_.children, _.reconciledVersionStr, _.requestedVersionStr, _.downloadedFiles)
val pw = new PrintWriter(new File(jsonOutputFile))
@@ -1,17 +1,18 @@
package coursier.cli.util
import java.util.Objects
import coursier.Artifact
import coursier.core.{Attributes, Dependency, Resolution}
import coursier.util.Print
import scala.collection.mutable
import scala.collection.parallel.ParSeq
import argonaut._
import Argonaut._
import argonaut._, Argonaut._
final case class JsonPrintRequirement(fileByArtifact: collection.mutable.Map[String, File], depToArtifacts: Map[Dependency, Vector[Artifact]], conflictResolutionForRoots: Map[String, String])
final case class JsonPrintRequirement(fileByArtifact: Map[String, File], depToArtifacts: Map[Dependency, Vector[Artifact]])
final case class DepNode(coord: String, files: Vector[(String, String)], dependencies: Set[String])
@@ -163,4 +164,11 @@ final case class JsonElem(dep: Dependency,, artifacts, jsonPrintRequirement, resolution, colors, printExclusions, excluded = false)) ++
(if (printExclusions) excluded else Nil)
* Override the hashcode to explicitly exclude `children`, because children will result in recursive hash on
* children's children, causing performance issue. Hash collision should be rare, but when that happens, the
* default equality check should take of the recursive aspect of `children`.
override def hashCode(): Int = Objects.hash(dep, requestedVersionStr, reconciledVersion, downloadedFiles)

0 comments on commit 5da2210

Please sign in to comment.