From 335e866176616f53f5f29a8dfa20ae8fc02843f9 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Wed, 21 Sep 2016 13:05:22 -0700 Subject: [PATCH] [unittest] Parallelize UnitTestSuite (#319) * [unittest] Parallelize UnitTestSuite so all tests have their own timer, runs until all finish or any timeout. Adds SimpleTimer. * [util] Timer spacing cleanup * [unittest] Remove Config reference to UnitTestTimeout --- src/main/scala/groundtest/Generator.scala | 6 +-- src/main/scala/groundtest/Regression.scala | 4 +- src/main/scala/uncore/devices/Rom.scala | 1 - src/main/scala/uncore/tilelink2/Fuzzer.scala | 2 +- src/main/scala/unittest/Configs.scala | 2 - src/main/scala/unittest/UnitTest.scala | 45 ++++++------------ src/main/scala/util/Timer.scala | 49 ++++++++++++++------ 7 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/main/scala/groundtest/Generator.scala b/src/main/scala/groundtest/Generator.scala index f32fd14d..221bb7eb 100644 --- a/src/main/scala/groundtest/Generator.scala +++ b/src/main/scala/groundtest/Generator.scala @@ -6,7 +6,7 @@ import uncore.devices.NTiles import uncore.constants._ import junctions._ import rocket._ -import util.Timer +import util.SimpleTimer import scala.util.Random import cde.{Parameters, Field} @@ -59,7 +59,7 @@ class UncachedTileLinkGenerator(id: Int) when (io.mem.grant.fire()) { sending := Bool(true) } when (req_wrap) { state := Mux(state === s_put, s_get, s_finished) } - val timeout = Timer(genTimeout, io.mem.acquire.fire(), io.mem.grant.fire()) + val timeout = SimpleTimer(genTimeout, io.mem.acquire.fire(), io.mem.grant.fire()) assert(!timeout, s"Uncached generator ${id} timed out waiting for grant") io.status.finished := (state === s_finished) @@ -132,7 +132,7 @@ class HellaCacheGenerator(id: Int) val status = new GroundTestStatus } - val timeout = Timer(genTimeout, io.mem.req.fire(), io.mem.resp.valid) + val timeout = SimpleTimer(genTimeout, io.mem.req.fire(), io.mem.resp.valid) assert(!timeout, s"Cached generator ${id} timed out waiting for response") io.status.timeout.valid := timeout io.status.timeout.bits := UInt(id) diff --git a/src/main/scala/groundtest/Regression.scala b/src/main/scala/groundtest/Regression.scala index 3eb37eed..42b1ac72 100644 --- a/src/main/scala/groundtest/Regression.scala +++ b/src/main/scala/groundtest/Regression.scala @@ -6,7 +6,7 @@ import uncore.constants._ import uncore.agents._ import uncore.util._ import junctions.HasAddrMapParameters -import util.{ParameterizedBundle, Timer} +import util.{ParameterizedBundle, SimpleTimer} import rocket.HellaCacheIO import cde.{Parameters, Field} @@ -760,7 +760,7 @@ class RegressionTest(implicit p: Parameters) extends GroundTest()(p) { } when (start) { start := Bool(false) } - val timeout = Timer(5000, start, cur_finished) + val timeout = SimpleTimer(5000, start, cur_finished) assert(!timeout, "Regression timed out") io.status.finished := all_done diff --git a/src/main/scala/uncore/devices/Rom.scala b/src/main/scala/uncore/devices/Rom.scala index 2986f85c..937c6a89 100644 --- a/src/main/scala/uncore/devices/Rom.scala +++ b/src/main/scala/uncore/devices/Rom.scala @@ -81,7 +81,6 @@ class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module } class ROMSlaveTest(implicit p: Parameters) extends UnitTest { - implicit val testName = "ROMSlaveTest" val romdata = Seq( BigInt("01234567deadbeef", 16), BigInt("ab32fee8d00dfeed", 16)) diff --git a/src/main/scala/uncore/tilelink2/Fuzzer.scala b/src/main/scala/uncore/tilelink2/Fuzzer.scala index 77efc7d4..233572a9 100644 --- a/src/main/scala/uncore/tilelink2/Fuzzer.scala +++ b/src/main/scala/uncore/tilelink2/Fuzzer.scala @@ -254,7 +254,7 @@ class TLFuzzRAM extends LazyModule } } -class TLFuzzRAMTest extends UnitTest { +class TLFuzzRAMTest extends UnitTest(500000) { val dut = Module(LazyModule(new TLFuzzRAM).module) io.finished := dut.io.finished } diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index 8daac49e..e11a4430 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -20,7 +20,6 @@ class WithJunctionsUnitTests extends Config( Module(new junctions.NastiMemoryDemuxTest()(p)), Module(new junctions.HastiTest()(p))) } - case UnitTestTimeout => 50000 case _ => throw new CDEMatchError }) @@ -37,7 +36,6 @@ class WithUncoreUnitTests extends Config( Module(new uncore.devices.TileLinkRAMTest()(p)), Module(new uncore.tilelink2.TLFuzzRAMTest)) } - case UnitTestTimeout => 500000 case _ => throw new CDEMatchError }) diff --git a/src/main/scala/unittest/UnitTest.scala b/src/main/scala/unittest/UnitTest.scala index e8d82373..1103cf30 100644 --- a/src/main/scala/unittest/UnitTest.scala +++ b/src/main/scala/unittest/UnitTest.scala @@ -2,7 +2,7 @@ package unittest import Chisel._ import cde.{Field, Parameters} -import util.Timer +import util.SimpleTimer trait HasUnitTestIO { val io = new Bundle { @@ -11,14 +11,16 @@ trait HasUnitTestIO { } } -abstract class UnitTest extends Module with HasUnitTestIO { - when (io.start) { - printf(s"Started UnitTest ${this.getClass.getSimpleName}\n") - } +abstract class UnitTest(val timeout: Int = 4096) extends Module with HasUnitTestIO { + val testName = this.getClass.getSimpleName + + when (io.start) { printf(s"Started UnitTest $testName\n") } + + val timed_out = SimpleTimer(timeout, io.start, io.finished) + assert(!timed_out, s"UnitTest $testName timed out") } case object UnitTests extends Field[Parameters => Seq[UnitTest]] -case object UnitTestTimeout extends Field[Int] class UnitTestSuite(implicit p: Parameters) extends Module { val io = new Bundle { @@ -27,33 +29,14 @@ class UnitTestSuite(implicit p: Parameters) extends Module { val tests = p(UnitTests)(p) - val s_idle :: s_start :: s_wait :: s_done :: Nil = Enum(Bits(), 4) + val s_idle :: s_start :: s_busy :: s_done :: Nil = Enum(Bits(), 4) val state = Reg(init = s_idle) - val test_idx = Reg(init = UInt(0, log2Up(tests.size))) - val test_finished = Vec(tests.map(_.io.finished)) + val tests_finished = Vec(tests.map(_.io.finished)).reduce(_&&_) - when (state === s_idle) { state := s_start } - when (state === s_start) { state := s_wait } - when (state === s_wait && test_finished(test_idx)) { - state := s_start - test_idx := test_idx + UInt(1) - state := Mux(test_idx === UInt(tests.size - 1), s_done, s_start) - } - - val timer = Module(new Timer(p(UnitTestTimeout), tests.size)) - timer.io.start.valid := Bool(false) - timer.io.stop.valid := Bool(false) - - tests.zipWithIndex.foreach { case (mod, i) => - mod.io.start := (state === s_start) && test_idx === UInt(i) - when (test_idx === UInt(i)) { - timer.io.start.valid := mod.io.start - timer.io.start.bits := UInt(i) - timer.io.stop.valid := mod.io.finished - timer.io.stop.bits := UInt(i) - } - } + tests.foreach { _.io.start := (state === s_start) } io.finished := (state === s_done) - assert(!timer.io.timeout.valid, "UnitTest timed out") + when (state === s_idle) { state := s_start } + when (state === s_start) { state := s_busy } + when (state === s_busy && tests_finished) { state := s_done } } diff --git a/src/main/scala/util/Timer.scala b/src/main/scala/util/Timer.scala index c0c48eeb..7a78904b 100644 --- a/src/main/scala/util/Timer.scala +++ b/src/main/scala/util/Timer.scala @@ -18,17 +18,14 @@ class Timer(initCount: Int, maxInflight: Int) extends Module { val countdown = Reg(UInt(width = log2Up(initCount))) val active = inflight.reduce(_ || _) - when (active) { - countdown := countdown - UInt(1) - } + when (active) { countdown := countdown - UInt(1) } when (io.start.valid) { inflight(io.start.bits) := Bool(true) countdown := UInt(initCount - 1) } - when (io.stop.valid) { - inflight(io.stop.bits) := Bool(false) - } + + when (io.stop.valid) { inflight(io.stop.bits) := Bool(false) } io.timeout.valid := countdown === UInt(0) && active io.timeout.bits := PriorityEncoder(inflight) @@ -37,18 +34,41 @@ class Timer(initCount: Int, maxInflight: Int) extends Module { "Timer stop for transaction that's not inflight") } -object Timer { +/** Simplified Timer with a statically-specified period. + * Can be stopped repeatedly, even when not active. + */ +class SimpleTimer(initCount: Int) extends Module { + val io = new Bundle { + val start = Bool(INPUT) + val stop = Bool(INPUT) + val timeout = Bool(OUTPUT) + } + + val countdown = Reg(UInt(width = log2Up(initCount))) + val active = Reg(Bool()) + + when (active) { countdown := countdown - UInt(1) } + + when (io.start) { + active := Bool(true) + countdown := UInt(initCount - 1) + } + + when (io.stop) { active := Bool(false) } + + io.timeout := countdown === UInt(0) && active +} + +object SimpleTimer { def apply(initCount: Int, start: Bool, stop: Bool): Bool = { - val timer = Module(new Timer(initCount, 1)) - timer.io.start.valid := start - timer.io.start.bits := UInt(0) - timer.io.stop.valid := stop - timer.io.stop.bits := UInt(0) - timer.io.timeout.valid + val timer = Module(new SimpleTimer(initCount)) + timer.io.start := start + timer.io.stop := stop + timer.io.timeout } } -/** Timer with a statically-specified period. */ +/** Timer with a dynamically-specified period. */ class DynamicTimer(w: Int) extends Module { val io = new Bundle { val start = Bool(INPUT) @@ -71,4 +91,3 @@ class DynamicTimer(w: Int) extends Module { io.timeout := countdown === UInt(0) && active } -