alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (HashSpeedTest.scala)

This example Scala source code file (HashSpeedTest.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

a, array, array, hash, int, int, list, list, murmurhash3, serializable, set, string, unit, unit

The Scala HashSpeedTest.scala source code

object HashSpeedTest {
  import System.{nanoTime => now}

  def time[A](f: => A) = {
    val t0 = now
    val ans = f
    (ans, now - t0)
  }
  def ptime[A](f: => A) = {
    val (ans,dt) = time(f)
    printf("Elapsed: %.3f\n",dt*1e-9)
    ans
  }

  object HashHist {
    var enabled = true
    val counts = new collection.mutable.HashMap[Int,Int]
    def add (i: Int) { if (enabled) counts(i) = counts.get(i).getOrElse(0)+1 }
    def resultAndReset = {
      var s = 0L
      var o = 0L
      var m = 0
      counts.valuesIterator.foreach(i => {
        s += i
        if (i>0) o += 1
        if (i>m) m = i
      })
      counts.clear
      (s,o,m)
    }
  }

  def report(s: String,res: (Long,Long,Int)) {
    println("Hash quality of "+s)
    printf("  %5.2f%% of entries are collisions\n",100*(res._1 - res._2).toDouble/res._1)
    printf("  Max of %d entries mapped to the same value\n",res._3)
  }

  // If you have MurmurHash3 installed, uncomment below (and in main)
  import scala.util.{MurmurHash3 => MH3}
  val justCountString: String => Unit = str => {
    var s,i = 0
    while (i < str.length) { s += str.charAt(i); i += 1 }
    HashHist.add(s)
  }
  val defaultHashString: String => Unit = str => HashHist.add(str.hashCode)
  val murmurHashString: String => Unit = str => HashHist.add(MH3.stringHash(str))
  def makeCharStrings = {
    val a = new Array[Byte](4)
    val buffer = new collection.mutable.ArrayBuffer[String]
    var i: Int = 'A'
    while (i <= 'Z') {
      a(0) = (i&0xFF).toByte
      var j: Int = 'a'
      while (j <= 'z') {
        a(1) = (j&0xFF).toByte
        var k: Int = 'A'
        while (k <= 'z') {
          a(2) = (k&0xFF).toByte
          var l: Int = 'A'
          while (l <= 'z') {
            a(3) = (l&0xFF).toByte
            buffer += new String(a)
            l += 1
          }
          k += 1
        }
        j += 1
      }
      i += 1
    }
    buffer.toArray
  }
  def hashCharStrings(ss: Array[String], hash: String => Unit) {
    var i = 0
    while (i < ss.length) {
      hash(ss(i))
      i += 1
    }
  }
  
  def justCountList: List[List[Int]] => Unit = lli => {
    var s = 0
    lli.foreach(_.foreach(s += _))
    HashHist.add(s)
  }
  def defaultHashList: List[List[Int]] => Unit = lli => HashHist.add(lli.hashCode)
  def makeBinaryLists = {
    def singleLists(depth: Int): List[List[Int]] = {
      if (depth <= 0) List(Nil)
      else {
        val set = singleLists(depth-1)
        val longest = set filter (_.length == depth-1)
        set ::: (longest.map(0 :: _)) ::: (longest.map(1 :: _))
      }
    }
    val buffer = new collection.mutable.ArrayBuffer[List[List[Int]]]
    val blocks = singleLists(4).toArray
    buffer += List(Nil)
    var i = 0
    while (i < blocks.length) {
      val li = blocks(i) :: Nil
      buffer += li
      var j = 0
      while (j < blocks.length) {
        val lj = blocks(j) :: li
        buffer += lj
        var k = 0
        while (k < blocks.length) {
          val lk = blocks(k) :: lj
          buffer += lk
          var l = 0
          while (l < blocks.length) {
            val ll = blocks(l) :: lk
            buffer += ll
            l += 1
          }
          k += 1
        }
        j += 1
      }
      i += 1
    }
    buffer.toArray
  }
  def hashBinaryLists(ls: Array[List[List[Int]]], hash: List[List[Int]] => Unit) {
    var i = 0
    while (i < ls.length) {
      hash(ls(i))
      i += 1
    }
  }

  def justCountSets: Set[Int] => Unit = si => {
    var s = 0
    si.foreach(s += _)
    HashHist.add(s)
  }
  def defaultHashSets: Set[Int] => Unit = si => HashHist.add(si.hashCode)
  def makeIntSets = {
    def sets(depth: Int): List[Set[Int]] = {
      if (depth <= 0) List(Set.empty[Int])
      else {
        val set = sets(depth-1)
        set ::: set.map(_ + depth)
      }
    }
    sets(20).toArray
  }
  def hashIntSets(ss: Array[Set[Int]], hash: Set[Int] => Unit) {
    var i = 0
    while (i < ss.length) {
      hash(ss(i))
      i += 1
    }
  }

  def defaultHashTuples: (Product with Serializable) => Unit = p => HashHist.add(p.hashCode)
  def makeNestedTuples = {
    val basic = Array(
      (0,0),
      (0,1),
      (1,0),
      (1,1),
      (0,0,0),
      (0,0,1),
      (0,1,0),
      (1,0,0),
      (0,0,0,0),
      (0,0,0,0,0),
      (false,false),
      (true,false),
      (false,true),
      (true,true),
      (0.7,true,"fish"),
      ((),true,'c',400,9.2,"galactic")
    )
    basic ++
    (for (i <- basic; j <- basic) yield (i,j)) ++
    (for (i <- basic; j <- basic; k <- basic) yield (i,j,k)) ++
    (for (i <- basic; j <- basic; k <- basic) yield ((i,j),k)) ++
    (for (i <- basic; j <- basic; k <- basic) yield (i,(j,k))) ++
    (for (i <- basic; j <- basic; k <- basic; l <- basic) yield (i,j,k,l)) ++
    (for (i <- basic; j <- basic; k <- basic; l <- basic) yield ((i,j),(k,l))) ++
    (for (i <- basic; j <- basic; k <- basic; l <- basic) yield (i,(j,k,l))) ++
    (for (i <- basic; j <- basic; k <- basic; l <- basic; m <- basic) yield (i,j,k,l,m)) ++
    (for (i <- basic; j <- basic; k <- basic; l <- basic; m <- basic) yield (i,(j,(k,(l,m)))))
  }
  def hashNestedTuples(ts: Array[Product with Serializable], hash: (Product with Serializable) => Unit) {
    var i = 0
    while (i < ts.length) {
      hash(ts(i))
      i += 1
    }
  }

  def findSpeed[A](n: Int, h: (Array[A],A=>Unit)=>Unit, aa: Array[A], f: A=>Unit) = {
    (time { for (i <- 1 to n) { h(aa,f) } }._2, aa.length.toLong*n)
  }

  def reportSpeed[A](repeats: Int, xs: List[(String, ()=>(Long,Long))]) {
    val tn = Array.fill(xs.length)((0L,0L))
    for (j <- 1 to repeats) {
      for ((l,i) <- xs zipWithIndex) {
        val x = l._2()
        tn(i) = (tn(i)._1 + x._1, tn(i)._2 + x._2)
      }
    }
    for (((t,n),(title,_)) <- (tn zip xs)) {
      val rate = (n*1e-6)/(t*1e-9)
      printf("Hash rate for %s: %4.2f million/second\n",title,rate)
    }
  }

  def main(args: Array[String]) {
    val bl = makeBinaryLists
    val is = makeIntSets
    val nt = makeNestedTuples
    // Uncomment the following for string stats if MurmurHash3 available
    val cs = makeCharStrings
    report("Java String hash for strings",{ hashCharStrings(cs,defaultHashString); HashHist.resultAndReset })
    report("MurmurHash3 for strings",{ hashCharStrings(cs,murmurHashString); HashHist.resultAndReset })
    HashHist.enabled = false
    reportSpeed(3, List(
       ("Java string hash", () => findSpeed[String](30, (x, y) => hashCharStrings(x, y),cs,defaultHashString)),
       ("MurmurHash3 string hash", () => findSpeed[String](30,(x, y) => hashCharStrings(x, y),cs,murmurHashString))
    ))
    // reportSpeed("Java string hash",30,hashCharStrings.tupled,cs,defaultHashString)
    // reportSpeed("MurmurHash3 string hash",30,hashCharStrings.tupled,cs,murmurHashString)
    HashHist.enabled = true
    report("lists of binary int lists",{ hashBinaryLists(bl,defaultHashList); HashHist.resultAndReset })
    report("small integer sets",{ hashIntSets(is,defaultHashSets); HashHist.resultAndReset })
    report("small nested tuples",{ hashNestedTuples(nt,defaultHashTuples); HashHist.resultAndReset })
    HashHist.enabled = false
    reportSpeed(3,List(
      ("lists of lists of binary ints", () => findSpeed(20,hashBinaryLists,bl,defaultHashList)),
      ("small integer sets", () => findSpeed(10,hashIntSets,is,defaultHashSets)),
      ("small nested tuples", () => findSpeed(5,hashNestedTuples,nt,defaultHashTuples))
    ))
  }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala HashSpeedTest.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.