diff --git a/src/main/scala/leon/LeonContext.scala b/src/main/scala/leon/LeonContext.scala
index 633ba2d4e28cd15ed728d1516d87a5bd2a52ca6e..8eea31aa7b604f4cae1da2091038be6af6557e17 100644
--- a/src/main/scala/leon/LeonContext.scala
+++ b/src/main/scala/leon/LeonContext.scala
@@ -16,5 +16,5 @@ case class LeonContext(
   settings: Settings = Settings(),
   options: Seq[LeonOption] = Seq(),
   files: Seq[File] = Seq(),
-  timers: TimerCollections = new TimerCollections
+  timers: TimerStorage = new TimerStorage
 )
diff --git a/src/main/scala/leon/Main.scala b/src/main/scala/leon/Main.scala
index 1b7377975e4a6c6a0e8309d0cc36dc1f4a345262..461db366c4f1908c7a16d66acef3dad19f77866f 100644
--- a/src/main/scala/leon/Main.scala
+++ b/src/main/scala/leon/Main.scala
@@ -222,8 +222,6 @@ object Main {
   }
 
   def main(args : Array[String]) {
-    val timer     = new Timer().start
-
     val argsl = args.toList
 
     // By default we add --library from Main
@@ -256,12 +254,10 @@ object Main {
     try {
       ctx.interruptManager.registerSignalHandler()
 
-      ctx.timers.get("Leon Opts") += timer
-
       // Compute leon pipeline
       val pipeline = computePipeline(ctx.settings)
 
-      timer.restart
+      val timer = ctx.timers.total.start()
 
       // Run pipeline
       pipeline.run(ctx)(args.toList) match {
@@ -274,16 +270,10 @@ object Main {
         case _ =>
       }
 
-      ctx.timers.get("Leon Run") += timer
+      timer.stop()
 
       ctx.reporter.whenDebug(DebugSectionTimers) { debug =>
-        debug("-"*80)
-        debug("Times:")
-        debug("-"*80)
-        for ((name, swc) <- ctx.timers.getAll.toSeq.sortBy(_._1)) {
-          debug(swc.toString)
-        }
-        debug("-"*80)
+        ctx.timers.outputTable(debug)
       }
 
     } catch {
diff --git a/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala b/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala
index 6200332b87cf6388e1c2d0edcf062e4f983c02af..c91b5582694d8ca7a6a1bd5e2b0915e55974b1c0 100644
--- a/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala
+++ b/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala
@@ -18,6 +18,7 @@ object ExtractionPhase extends LeonPhase[List[String], Program] {
   implicit val debug = DebugSectionTrees
 
   def run(ctx: LeonContext)(args: List[String]): Program = {
+    val timer = ctx.timers.frontend.start()
 
     val settings = new NSCSettings
 
@@ -55,11 +56,14 @@ object ExtractionPhase extends LeonPhase[List[String], Program] {
       //   )
       // }
 
+
       val compiler = new ScalaCompiler(settings, ctx)
       val run = new compiler.Run
       run.compile(command.files)
 
 
+      timer.stop()
+
       val pgm = Program(FreshIdentifier("__program"), compiler.leonExtraction.modules)
       ctx.reporter.debug(pgm.asString(ctx))
       pgm
diff --git a/src/main/scala/leon/solvers/EnumerationSolver.scala b/src/main/scala/leon/solvers/EnumerationSolver.scala
index 39203125c95d2fff859a5046d21180d7b2b37398..79a7dba86fd9ec953ebefde0f386194e67c146a7 100644
--- a/src/main/scala/leon/solvers/EnumerationSolver.scala
+++ b/src/main/scala/leon/solvers/EnumerationSolver.scala
@@ -47,6 +47,7 @@ class EnumerationSolver(val context: LeonContext, val program: Program) extends
   private var modelMap = Map[Identifier, Expr]()
 
   def check: Option[Boolean] = {
+    val timer = context.timers.solvers.enum.check.start()
     val res = try {
       datagen = Some(new VanuatooDataGen(context, program))
       if (interrupted) {
@@ -71,6 +72,7 @@ class EnumerationSolver(val context: LeonContext, val program: Program) extends
         None
     }
     datagen = None
+    timer.stop()
     res
   }
 
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index 06a94d7ddf23ac487ea74c758960d4e71c7097bc..077602062d66da678af1d8294efb38180f36e89c 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -181,7 +181,8 @@ trait AbstractZ3Solver
   var isInitialized = false
   protected[leon] def initZ3() {
     if (!isInitialized) {
-      val initTime     = new Timer().start
+      val timer = context.timers.solvers.z3.init.start()
+
       counter = 0
 
       z3 = new Z3Context(z3cfg)
@@ -199,8 +200,7 @@ trait AbstractZ3Solver
 
       isInitialized = true
 
-      initTime.stop
-      context.timers.get("Z3Solver init") += initTime
+      timer.stop()
     }
   }
 
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index e220314d5bdfb387f3ff3581dd04ff4f8c9abb2f..208f8f18c30a5d1de382edb60dcf2243f83178fc 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -414,9 +414,11 @@ class FairZ3Solver(val context : LeonContext, val program: Program)
       //reporter.debug("Unroll.  Assumptions:\n"+unrollingBank.z3CurrentZ3Blockers.mkString("  &&  "))
       //reporter.debug("Userland Assumptions:\n"+assumptionsAsZ3.mkString("  &&  "))
 
+      val timer = context.timers.solvers.z3.check.start()
       solver.push() // FIXME: remove when z3 bug is fixed
       val res = solver.checkAssumptions((assumptionsAsZ3 ++ unrollingBank.z3CurrentZ3Blockers) :_*)
       solver.pop()  // FIXME: remove when z3 bug is fixed
+      timer.stop()
 
       reporter.debug(" - Finished search with blocked literals")
 
@@ -503,9 +505,11 @@ class FairZ3Solver(val context : LeonContext, val program: Program)
               reporter.debug(" - Running search without blocked literals (w/o lucky test)")
             }
 
+            val timer = context.timers.solvers.z3.check.start()
             solver.push() // FIXME: remove when z3 bug is fixed
             val res2 = solver.checkAssumptions(assumptionsAsZ3 : _*)
             solver.pop()  // FIXME: remove when z3 bug is fixed
+            timer.stop
 
             res2 match {
               case Some(false) =>
diff --git a/src/main/scala/leon/synthesis/SimpleSearch.scala b/src/main/scala/leon/synthesis/SimpleSearch.scala
index 8f4ebf4ea526d97997f4d00cdf594c939a6f8ea5..35f7f1ce5a91fd72562d902489322d5f4899ace1 100644
--- a/src/main/scala/leon/synthesis/SimpleSearch.scala
+++ b/src/main/scala/leon/synthesis/SimpleSearch.scala
@@ -149,9 +149,9 @@ class SimpleSearch(synth: Synthesizer,
 
 
   def searchStep() {
-    val t = new Timer().start
+    val timer = synth.context.timers.synthesis.nextLeaf.start()
     val nl = nextLeaf()
-    synth.context.timers.get("Synthesis NextLeaf") += t
+    timer.stop()
 
     nl match {
       case Some(l)  =>
@@ -159,15 +159,15 @@ class SimpleSearch(synth: Synthesizer,
           case al: g.AndLeaf =>
             val sub = expandAndTask(al.task)
 
-            t.restart
+            val timer = synth.context.timers.synthesis.expand.start()
             onExpansion(al, sub)
-            synth.context.timers.get("Synthesis Expand") += t
+            timer.stop()
           case ol: g.OrLeaf =>
             val sub = expandOrTask(ol.task)
 
-            t.restart
+            val timer = synth.context.timers.synthesis.expand.start()
             onExpansion(ol, sub)
-            synth.context.timers.get("Synthesis Expand") += t
+            timer.stop()
         }
       case None =>
         stop()
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index 643855a771d1144a45cb8ddbadb020065e969c21..238c893e8dbd3e9a2b9be4c5feeae00cd8ab9f19 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -41,18 +41,11 @@ class Synthesizer(val context : LeonContext,
         }
       }
 
-    val ts = System.currentTimeMillis()
+    val t = context.timers.synthesis.search.start()
 
     val res = search.search()
 
-    search match {
-      case pr: ParallelSearch =>
-        context.timers.add(pr.expandTimers)
-        context.timers.add(pr.sendWorkTimers)
-      case _ =>
-    }
-
-    val diff = System.currentTimeMillis()-ts
+    val diff = t.stop()
     reporter.info("Finished in "+diff+"ms")
 
     if (options.generateDerivationTrees) {
diff --git a/src/main/scala/leon/synthesis/search/AndOrGraphParallelSearch.scala b/src/main/scala/leon/synthesis/search/AndOrGraphParallelSearch.scala
index f486d385de7eda29aea50452858d20296070340d..75124787eed709931876c1ac7d060d83fe720944 100644
--- a/src/main/scala/leon/synthesis/search/AndOrGraphParallelSearch.scala
+++ b/src/main/scala/leon/synthesis/search/AndOrGraphParallelSearch.scala
@@ -22,9 +22,6 @@ abstract class AndOrGraphParallelSearch[WC,
 
   var system: ActorSystem = _
 
-  val sendWorkTimers = new TimerCollection("Synthesis-par SendWork")
-  val expandTimers   = new TimerCollection("Synthesis-par Expand")
-
   def search(): Option[(S, Boolean)] = {
     system = ActorSystem("ParallelSearch")
 
@@ -96,8 +93,6 @@ abstract class AndOrGraphParallelSearch[WC,
 
       assert(idleWorkers.size > 0)
 
-      val t = new Timer().start
-
       getNextLeaves(idleWorkers, workingWorkers) match {
         case Nil =>
           if (workingWorkers.isEmpty) {
@@ -118,8 +113,6 @@ abstract class AndOrGraphParallelSearch[WC,
             }
           }
       }
-
-      sendWorkTimers += t
     }
 
     context.setReceiveTimeout(10.seconds)
@@ -136,9 +129,7 @@ abstract class AndOrGraphParallelSearch[WC,
       case WorkerAndTaskDone(w, res) =>
         workers.get(w) match {
           case Some(Some(l: g.AndLeaf)) =>
-            val t = new Timer().start
             onExpansion(l, res)
-            expandTimers += t
             workers += w -> None
           case _ =>
         }
@@ -147,9 +138,7 @@ abstract class AndOrGraphParallelSearch[WC,
       case WorkerOrTaskDone(w, res) =>
         workers.get(w) match {
           case Some(Some(l: g.OrLeaf)) =>
-            val t = new Timer().start
             onExpansion(l, res)
-            expandTimers += t
             workers += w -> None
           case _ =>
         }
diff --git a/src/main/scala/leon/utils/Timer.scala b/src/main/scala/leon/utils/Timer.scala
index 8dc3c54c3f51107e13ac273b840cd005aa73f8ee..842a508b14a8c6b933450bf9505d87e0d347df5b 100644
--- a/src/main/scala/leon/utils/Timer.scala
+++ b/src/main/scala/leon/utils/Timer.scala
@@ -3,42 +3,13 @@
 package leon
 package utils
 
-class TimerCollection(val name: String) {
-  var min: Long = 0L
-  var tot: Long = 0L
-  var max: Long = 0L
-  var n: Int = 0
-
-  def +=(sw: Timer) = synchronized { 
-    val ms = sw.getMillis
-    if(n == 0 || ms < min) {
-      min = ms
-    }
-    if(n == 0 || ms > max) {
-      max = ms
-    }
-    n   += 1
-    tot += ms
-  }
-
-  override def toString = {
-    if (n == 0) {
-      "%-30s    N/A".format(name+":")
-    } else if (n > 1) {
-      "%-30s %6d ms (min: %d, avg: %d, max: %d, n: %d)".format(name+":", tot, min, tot/n, max, n)
-    } else {
-      "%-30s %6d ms".format(name+":", tot)
-    }
-  }
-
-  def getMillis = tot
-}
+import scala.language.dynamics
 
 /** Implements a timer for profiling purposes */
-class Timer(name: String = "Timer") {
+class Timer() {
   var beginning: Long = 0L
   var end: Long = 0L
-  var acc: Long = 0L
+  var runs: List[Long] = Nil
 
   def start: this.type = {
     beginning = System.currentTimeMillis
@@ -46,45 +17,148 @@ class Timer(name: String = "Timer") {
     this
   }
 
-  def restart: this.type = { 
+  def restart: this.type = {
     beginning = 0L
     end = 0L
-    acc = 0L
+    runs = Nil
 
     start
   }
 
-  def stop {
-    end        = System.currentTimeMillis
-    acc       += (end - beginning)
-    beginning  = 0L
+  def stop = {
+    end         = System.currentTimeMillis
+    runs      ::= (end - beginning)
+    beginning   = 0L
+    runs.head
   }
 
-  def getMillis: Long = {
-    if (isRunning) {
-      acc + (System.currentTimeMillis-beginning)
+  def isRunning = beginning != 0L
+
+  override def toString = {
+    val n = runs.size
+
+    if (n == 0) {
+      "N/A"
+    } else if (n > 1) {
+      val tot = runs.sum
+      val min = runs.min
+      val max = runs.max
+
+      "(min: %3d, avg: %3d, max: %3d, n: %3d) %6d ms".format(min, tot/n, max, n, tot)
     } else {
-      acc
+      val tot = runs.sum
+
+      "%6d ms".format(tot)
     }
   }
+}
 
-  def isRunning = beginning != 0L
+class TimerStorage extends Dynamic {
+  var keys    = List[String]()
+  var fields  = Map[String, TimerStorage]()
+  var selfTimer: Option[Timer] = None
+
+  def get(name: String): TimerStorage = {
+    fields.get(name) match {
+      case Some(t) =>
+        t
+
+      case None =>
+        val t = new TimerStorage()
+        fields += name -> t
+        keys ::= name
+        t
+    }
+  }
 
-  override def toString = "%20s: %5d%sms".format(name, getMillis, if (isRunning) "..." else "")
-}
+  private def isLastKeys(n: String) = Some(n) == keys.headOption
 
-class TimerCollections {
-  private var all = Map[String, TimerCollection]()
+  def selectDynamic(name: String): TimerStorage = get(name)
 
-  def get(name: String): TimerCollection = all.getOrElse(name, {
-    val sw = new TimerCollection(name)
-    all += name -> sw
-    sw
-  })
 
-  def add(swc: TimerCollection) {
-    all += swc.name -> swc
+  def start() = {
+    if (selfTimer.isEmpty) {
+      selfTimer = Some(new Timer)
+    }
+    selfTimer.get.start
+
+    this
+  }
+
+  def stop() = {
+    selfTimer.get.stop
   }
 
-  def getAll = all
+  def outputTable(printer: String => Unit) = {
+    import utils.ASCIITables._
+
+    var table = Table("Timers")
+
+    table += Row(Seq(
+        Cell("name"),
+        Cell("min"),
+        Cell("avg"),
+        Cell("max"),
+        Cell("n"),
+        Cell("total")
+      ))
+    table += Separator
+
+    var closed = Set[TimerStorage]()
+
+    def output(ts: TimerStorage, path: List[(TimerStorage, String)]): Unit = {
+      val indent = path.map { case (from, name) =>
+        if (closed(from)) {
+          "  "
+        } else if (from.isLastKeys(name)) {
+          closed += from
+          "â”” "
+        } else {
+          "├ "
+        }
+      }.reverse.mkString
+
+      (path, ts.selfTimer) match {
+        case ((_, name) :: _, Some(t)) =>
+          val n   = t.runs.size
+          val tot = t.runs.sum
+
+          val (min: String, avg: String, max: String, total: String) = if (n == 0) {
+            ("", "", "", "N/A")
+          } else if (n > 1) {
+            val min = t.runs.min
+            val max = t.runs.max
+            val avg = tot/n
+            (f"$min%d", f"$avg%d", f"$max%d", f"$tot%d")
+          } else {
+            ("", "", "", f"$tot%d")
+          }
+
+          table += Row(Seq(
+            Cell(indent+name),
+            Cell(min),
+            Cell(avg),
+            Cell(max),
+            Cell(n),
+            Cell(tot)
+          ))
+        case ((_, name) :: _, None) =>
+          table += Row(Seq(
+            Cell(indent+name, 6)
+          ))
+        case _ =>
+
+      }
+
+      ts.keys.reverse.map(n => n -> ts.fields(n)).foreach { case (name, nts) =>
+        output(nts, (ts -> name) :: path)
+      }
+    }
+
+    if (fields.nonEmpty) {
+      output(this, Nil)
+    }
+
+    printer(table.render)
+  }
 }