Skip to content

Commit 5e2a8ca

Browse files
authored
Merge pull request #202 from JoshRosen/Invoker-map-lookup-performance-improvements
Reduce performance overhead of map lookups in Invoker.invoked()
2 parents 0b7ece6 + 4626fd8 commit 5e2a8ca

File tree

1 file changed

+19
-6
lines changed
  • scalac-scoverage-runtime/shared/src/main/scala/scoverage

1 file changed

+19
-6
lines changed

scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import scoverage.Platform._
77
object Invoker {
88

99
private val MeasurementsPrefix = "scoverage.measurements."
10-
private val threadFiles = new ThreadLocal[ThreadSafeMap[String, FileWriter]]
11-
private val ids = ThreadSafeMap.empty[(String, Int), Any]
10+
private val threadFiles = new ThreadLocal[mutable.HashMap[String, FileWriter]]
11+
12+
// For each data directory we maintain a thread-safe set tracking the ids that we've already
13+
// seen and recorded. We're using a map as a set, so we only care about its keys and can ignore
14+
// its values.
15+
private val dataDirToIds = ThreadSafeMap.empty[String, ThreadSafeMap[Int, Any]]
1216

1317
/**
1418
* We record that the given id has been invoked by appending its id to the coverage
@@ -31,18 +35,27 @@ object Invoker {
3135
// times since for coverage we only care about 1 or more, (it just slows things down to
3236
// do it more than once), anything we can do to help is good. This helps especially with code
3337
// that is executed many times quickly, eg tight loops.
34-
if (!ids.contains(dataDir, id)) {
38+
if (!dataDirToIds.contains(dataDir)) {
39+
// Guard against SI-7943: "TrieMap method getOrElseUpdate is not thread-safe".
40+
dataDirToIds.synchronized {
41+
if (!dataDirToIds.contains(dataDir)) {
42+
dataDirToIds(dataDir) = ThreadSafeMap.empty[Int, Any]
43+
}
44+
}
45+
}
46+
val ids = dataDirToIds(dataDir)
47+
if (!ids.contains(id)) {
3548
// Each thread writes to a separate measurement file, to reduce contention
3649
// and because file appends via FileWriter are not atomic on Windows.
3750
var files = threadFiles.get()
3851
if (files == null) {
39-
files = ThreadSafeMap.empty[String, FileWriter]
52+
files = mutable.HashMap.empty[String, FileWriter]
4053
threadFiles.set(files)
4154
}
4255
val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true))
43-
writer.append(id.toString + '\n').flush()
56+
writer.append(Integer.toString(id)).append("\n").flush()
4457

45-
ids.put((dataDir, id), ())
58+
ids.put(id, ())
4659
}
4760
}
4861

0 commit comments

Comments
 (0)