Skip to content

Commit

Permalink
Replace (Par)TrieMap with ConcurrentHashMap in IncOptimizer
Browse files Browse the repository at this point in the history
- Reduces residual retained size of the IncOptimizer on the test suite
  from 166MB to 144MB.
- ~10% batch speedup on the optimizer.
  • Loading branch information
gzm0 committed Apr 6, 2024
1 parent 308236f commit d3c42e1
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,20 @@ package org.scalajs.linker.frontend.optimizer

import scala.annotation.tailrec

import scala.collection.concurrent.TrieMap
import scala.collection.parallel.mutable.{ParTrieMap, ParArray}
import scala.collection.parallel.mutable.ParArray
import scala.collection.parallel._

import java.util.concurrent.atomic._

private[optimizer] object ParCollOps extends AbsCollOps {
type Map[K, V] = TrieMap[K, V]
type ParMap[K, V] = ParTrieMap[K, V]
type AccMap[K, V] = TrieMap[K, Addable[V]]
type ParIterable[V] = ParArray[V]
type Addable[V] = AtomicReference[List[V]]

def emptyAccMap[K, V]: AccMap[K, V] = TrieMap.empty
def emptyMap[K, V]: Map[K, V] = TrieMap.empty
def emptyParMap[K, V]: ParMap[K, V] = ParTrieMap.empty
def parThreshold: Long = 1 // max parallelism

def emptyParIterable[V]: ParIterable[V] = ParArray.empty
def emptyAddable[V]: Addable[V] = new AtomicReference[List[V]](Nil)

// Operations on ParMap
def isEmpty[K, V](map: ParMap[K, V]): Boolean = map.isEmpty
def forceGet[K, V](map: ParMap[K, V], k: K): V = map(k)
def get[K, V](map: ParMap[K, V], k: K): Option[V] = map.get(k)
def put[K, V](map: ParMap[K, V], k: K, v: V): Unit = map.put(k, v)
def remove[K, V](map: ParMap[K, V], k: K): Option[V] = map.remove(k)

def retain[K, V](map: ParMap[K, V])(p: (K, V) => Boolean): Unit = {
map.foreach { case (k, v) =>
if (!p(k, v))
map.remove(k)
}
}

def valuesForeach[K, V, U](map: ParMap[K, V])(f: V => U): Unit =
map.values.foreach(f)

// Operations on AccMap
def acc[K, V](map: AccMap[K, V], k: K, v: V): Unit =
add(map.getOrElseUpdate(k, emptyAddable), v)

def getAcc[K, V](map: AccMap[K, V], k: K): ParIterable[V] =
map.get(k).fold(emptyParIterable[V])(finishAdd(_))

def parFlatMapKeys[A, B](map: AccMap[A, _])(f: A => Option[B]): ParIterable[B] =
map.keys.flatMap(f(_)).toParArray

// Operations on ParIterable
def prepAdd[V](it: ParIterable[V]): Addable[V] =
new AtomicReference(it.toList)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,15 @@ package org.scalajs.linker.frontend.optimizer

import language.higherKinds

import scala.collection.mutable

private[optimizer] trait AbsCollOps {
type Map[K, V] <: mutable.Map[K, V]
type ParMap[K, V] <: AnyRef
type AccMap[K, V] <: AnyRef
type ParIterable[V] <: AnyRef
type Addable[V] <: AnyRef

def emptyAccMap[K, V]: AccMap[K, V]
def emptyMap[K, V]: Map[K, V]
def emptyParMap[K, V]: ParMap[K, V]
def parThreshold: Long

def emptyParIterable[V]: ParIterable[V]
def emptyAddable[V]: Addable[V]

// Operations on ParMap
def isEmpty[K, V](map: ParMap[K, V]): Boolean
def forceGet[K, V](map: ParMap[K, V], k: K): V
def get[K, V](map: ParMap[K, V], k: K): Option[V]
def put[K, V](map: ParMap[K, V], k: K, v: V): Unit
def remove[K, V](map: ParMap[K, V], k: K): Option[V]
def retain[K, V](map: ParMap[K, V])(p: (K, V) => Boolean): Unit
def valuesForeach[K, V, U](map: ParMap[K, V])(f: V => U): Unit

// Operations on AccMap
def acc[K, V](map: AccMap[K, V], k: K, v: V): Unit
def getAcc[K, V](map: AccMap[K, V], k: K): ParIterable[V]
def parFlatMapKeys[A, B](map: AccMap[A, _])(f: A => Option[B]): ParIterable[B]

// Operations on ParIterable
def prepAdd[V](it: ParIterable[V]): Addable[V]
def add[V](addable: Addable[V], v: V): Unit
Expand Down

0 comments on commit d3c42e1

Please sign in to comment.