[mod] reduced memory footprint of output and reset everything after a run

- instead of copying the output, a vector indicates if a time is done
 - a full run has to be consumed by the output before the next
This commit is contained in:
2020-01-29 01:19:10 -06:00
parent 5748b8272a
commit bd24002ee1
5 changed files with 35 additions and 14 deletions

View File

@@ -28,7 +28,7 @@ object Main {
//lib.evalUtil.time("par", parlist.par.map({_ => Thread.sleep(10); 2})) //lib.evalUtil.time("par", parlist.par.map({_ => Thread.sleep(10); 2}))
//lib.evalUtil.time("ser", parlist.map({_ => Thread.sleep(10); 2})) //lib.evalUtil.time("ser", parlist.map({_ => Thread.sleep(10); 2}))
//startSimulation()
} }
def startSimulation(): Unit = { def startSimulation(): Unit = {
@@ -42,6 +42,7 @@ object Main {
outputThread.start() outputThread.start()
simulator.start() simulator.start()
outputThread.join() outputThread.join()
sharedMemory.outputReset()
} }
} }

View File

@@ -1,15 +1,22 @@
package scim.components package scim.components
import scim.datastruct.{Cell, Group, SensorResult, SharedMemory} import scim.datastruct.{Cell, Group, SensorResult, SharedMemory, Time, Truth}
class Output(sharedMemory: SharedMemory) extends Runnable { class Output(sharedMemory: SharedMemory) extends Runnable {
def run(): Unit = { def run(): Unit = {
val output = sharedMemory.output val outputBroadcast = sharedMemory.output
(0 until output.size, output).zipped.foreach((time, result) => outputData(time, result.watch())) val duration = sharedMemory.config.duration
def outputHelper(time: Time): Unit = {
outputBroadcast(time.time).watch()
outputData(time, sharedMemory.getResult(time), sharedMemory.getTruth(time))
}
Vector.tabulate(sharedMemory.config.duration)(t => Time(t, duration)).foreach(outputHelper)
} }
def outputData(time: Int, output: Map[Cell, Map[Group, Vector[SensorResult]]]): Unit = { def outputData(time: Time, sensors: Map[Cell, Map[Group, Vector[SensorResult]]], groundTruths: Map[Cell, Map[Group, Truth]]): Unit = {
println("TICK: " + time) println("TICK: " + time)
println(output) println(sensors)
println(groundTruths)
} }
} }

View File

@@ -40,7 +40,7 @@ class Simulation(config: Configuration) {
cells.foreach(simCell) cells.foreach(simCell)
} }
// broadcast the results // broadcast the results
output(time.time).broadcast(sensorResults) output(time.time).broadcast(true)
} }
private def simGroups(time: Time, cell: Cell, groups: Map[Group, List[(Group, Sensor, Option[GroundTruth])]], prevTruths: Map[Group, Truth], resultTruths: Map[Group, Truth], resultSensors: Map[Group, Vector[SensorResult]]): Unit = { private def simGroups(time: Time, cell: Cell, groups: Map[Group, List[(Group, Sensor, Option[GroundTruth])]], prevTruths: Map[Group, Truth], resultTruths: Map[Group, Truth], resultSensors: Map[Group, Vector[SensorResult]]): Unit = {

View File

@@ -2,6 +2,7 @@ package scim.datastruct
import scim.lib.ConcurrentBroadcast.BroadcastObject import scim.lib.ConcurrentBroadcast.BroadcastObject
import scim.lib.simulation._ import scim.lib.simulation._
import scala.collection.parallel.ForkJoinTaskSupport import scala.collection.parallel.ForkJoinTaskSupport
// configuration // configuration
@@ -21,23 +22,30 @@ case class Time(time: Int, duration: Int){
case class SharedMemory(sensor: Map[Time, Map[Cell, Map[Group, Vector[SensorResult]]]], case class SharedMemory(sensor: Map[Time, Map[Cell, Map[Group, Vector[SensorResult]]]],
groundTruth: Map[Time, Map[Cell, Map[Group, Truth]]], groundTruth: Map[Time, Map[Cell, Map[Group, Truth]]],
config: SimulationConfig, config: SimulationConfig,
output: Vector[BroadcastObject[Map[Cell, Map[Group, Vector[SensorResult]]]]]) { output: Vector[BroadcastObject[Boolean]]) {
// This could be spatially optimized to have a function to invoke a new simulation tick // This could be spatially optimized to have a function to invoke a new simulation tick
// a template of Map[SensorID, SensorResult] would have to be kept and deep copied when // a template of Map[Cell, Map[Group, Vector[SensorResult]]] would have to be kept and deep copied when
// another tick is simulated. this won't work for ground truth, as it may already be defined // another tick is simulated. this won't work for ground truth, as it may already be defined
// through the configuration. it can however be deleted once it is no longer required, tho this seems // through the configuration throughout the entire simulation. it can however be deleted once it is no longer
// to be rather unbeneficial, as the space was already preallocated. Sensors however could be replaced // required, tho this seems to be rather unbeneficial, as the space was already preallocated.
// or deleted, depending if a buffer or list is used. // Sensors however could be replaced or deleted, depending if a buffer or list is used. in a producer/consumer manner
def getTruth(time: Time, cell: Cell, group: Group): Truth = { def getTruth(time: Time, cell: Cell, group: Group): Truth = {
groundTruth(time)(cell)(group) groundTruth(time)(cell)(group)
} }
def getTruth(time: Time): Map[Cell, Map[Group, Truth]] = {
groundTruth(time)
}
def getResult(time: Time, cell: Cell, group: Group): Vector[SensorResult] = { def getResult(time: Time, cell: Cell, group: Group): Vector[SensorResult] = {
sensor(time)(cell)(group) sensor(time)(cell)(group)
} }
def getAllResults(time: Time): Map[Cell, Map[Group, Vector[SensorResult]]] = { def getResult(time: Time): Map[Cell, Map[Group, Vector[SensorResult]]] = {
sensor(time) sensor(time)
} }
def outputReset(): Unit = {
sensor.foreach(kv => kv._2.foreach(kv2 => kv2._2.foreach(kv3 => kv3._2.foreach(res => res.reset()))))
groundTruth.foreach(kv => kv._2.foreach(kv2 => kv2._2.foreach(kv3 => kv3._2.reset())))
output.foreach(e => e.broadcastReset())
}
} }
abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) { abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) {
@@ -50,6 +58,9 @@ abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) {
def exists: Boolean = { def exists: Boolean = {
!broadcastObject.peak().isEmpty !broadcastObject.peak().isEmpty
} }
def reset(): Unit = {
broadcastObject.broadcastReset()
}
} }
case class SimulationBehaviours(functions: Map[String, SimulationBehaviour]) { case class SimulationBehaviours(functions: Map[String, SimulationBehaviour]) {
def get(name: String): Option[SimulationBehaviour] = { def get(name: String): Option[SimulationBehaviour] = {

View File

@@ -63,6 +63,8 @@ object ScalaLocks {
object ConcurrentBroadcast { object ConcurrentBroadcast {
// WARNING: Type A should be immutable and not hold any mutable data
// could add a clone/copy when retrieving for AnyRef types
class BroadcastObject[A](default: Option[A] = None) { class BroadcastObject[A](default: Option[A] = None) {
import ScalaLocks._ import ScalaLocks._