[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("ser", parlist.map({_ => Thread.sleep(10); 2}))
//startSimulation()
}
def startSimulation(): Unit = {
@@ -42,6 +42,7 @@ object Main {
outputThread.start()
simulator.start()
outputThread.join()
sharedMemory.outputReset()
}
}

View File

@@ -1,15 +1,22 @@
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 {
def run(): Unit = {
val output = sharedMemory.output
(0 until output.size, output).zipped.foreach((time, result) => outputData(time, result.watch()))
val outputBroadcast = sharedMemory.output
val duration = sharedMemory.config.duration
def outputHelper(time: Time): Unit = {
outputBroadcast(time.time).watch()
outputData(time, sharedMemory.getResult(time), sharedMemory.getTruth(time))
}
def outputData(time: Int, output: Map[Cell, Map[Group, Vector[SensorResult]]]): Unit = {
Vector.tabulate(sharedMemory.config.duration)(t => Time(t, duration)).foreach(outputHelper)
}
def outputData(time: Time, sensors: Map[Cell, Map[Group, Vector[SensorResult]]], groundTruths: Map[Cell, Map[Group, Truth]]): Unit = {
println("TICK: " + time)
println(output)
println(sensors)
println(groundTruths)
}
}

View File

@@ -40,7 +40,7 @@ class Simulation(config: Configuration) {
cells.foreach(simCell)
}
// 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 = {

View File

@@ -2,6 +2,7 @@ package scim.datastruct
import scim.lib.ConcurrentBroadcast.BroadcastObject
import scim.lib.simulation._
import scala.collection.parallel.ForkJoinTaskSupport
// configuration
@@ -21,23 +22,30 @@ case class Time(time: Int, duration: Int){
case class SharedMemory(sensor: Map[Time, Map[Cell, Map[Group, Vector[SensorResult]]]],
groundTruth: Map[Time, Map[Cell, Map[Group, Truth]]],
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
// 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
// through the configuration. it can however be deleted once it is no longer required, tho this seems
// to be rather unbeneficial, as the space was already preallocated. Sensors however could be replaced
// or deleted, depending if a buffer or list is used.
// through the configuration throughout the entire simulation. it can however be deleted once it is no longer
// required, tho this seems to be rather unbeneficial, as the space was already preallocated.
// 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 = {
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] = {
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)
}
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]) {
@@ -50,6 +58,9 @@ abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) {
def exists: Boolean = {
!broadcastObject.peak().isEmpty
}
def reset(): Unit = {
broadcastObject.broadcastReset()
}
}
case class SimulationBehaviours(functions: Map[String, SimulationBehaviour]) {
def get(name: String): Option[SimulationBehaviour] = {

View File

@@ -63,6 +63,8 @@ object ScalaLocks {
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) {
import ScalaLocks._