DesignSpaceExplorationTask.scala 6.99 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
// Copyright (C) 2017 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco.  If not, see <http://www.gnu.org/licenses/>.
//
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package de.tu_darmstadt.cs.esa.tapasco.task
import  de.tu_darmstadt.cs.esa.tapasco.itapasco.common._
import  de.tu_darmstadt.cs.esa.tapasco.dse._
import  de.tu_darmstadt.cs.esa.tapasco.dse.log._
import  de.tu_darmstadt.cs.esa.tapasco.base._
import  de.tu_darmstadt.cs.esa.tapasco.filemgmt._
import  de.tu_darmstadt.cs.esa.tapasco.activity.composers.Composer
import  de.tu_darmstadt.cs.esa.tapasco.dse.{DesignSpace, Heuristics}
import  de.tu_darmstadt.cs.esa.tapasco.itapasco.common.LogFileTracker
import  java.nio.file.Paths

/** Interface for design space exploration tasks. */
trait ExplorationTask extends Task {
  /** Returns the design space exploration object. */
  def exploration: Exploration
}

/**
 * Internal implementation of the design space exploration task.
 * @param m Model to associate with.
 * @param logFile File name for main log file of this DSE.
 * @param onComplete Callback function on completion.
 **/
private class DesignSpaceExplorationTask(
    composition: Composition,
    target: Target,
    dimensions: DesignSpace.Dimensions,
    designFrequency: Heuristics.Frequency,
    heuristic: Heuristics.Heuristic,
    batchSize: Int,
    basePath: Option[String],
    features: Option[Seq[Feature]],
    logFile: Option[String],
    debugMode: Option[String],
53
54
    val onComplete: Boolean => Unit,
    val deleteOnFail: Boolean = false)
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    (implicit cfg: Configuration, tsk: Tasks) extends Task with LogTracking with ExplorationTask {
  private[this] val _logger = de.tu_darmstadt.cs.esa.tapasco.Logging.logger(getClass)
  /** Internal representation of result. **/
  private[this] var _result: Option[(DesignSpace.Element, Composer.Result)] = None
  private[this] val _bp = basePath map (p => Paths.get(p).toAbsolutePath) getOrElse {
    val shortDate = java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(java.time.LocalDateTime.now())
    val dsepath = FileAssetManager.TAPASCO_HOME.resolve(
      "DSE_%s".format(shortDate).replace(" ", "_").replace("/", "-").replace(":","-")
    ).normalize()
    java.nio.file.Files.createDirectories(dsepath.resolve("bd"))
    dsepath
  }
  // use implicit Configuration via UserConfigurationModel
  private implicit val _cfg: Configuration = cfg.compositionDir(_bp.resolve("bd"))

  /** @inheritdoc */
  val exploration = Exploration(
    composition,
    dimensions,
    target,
    designFrequency,
    batchSize,
    _bp,
78
79
    debugMode,
    deleteOnFail
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  )(_cfg, tsk)

  /**
   * Launches the design space exploration.
   **/
  def job: Boolean = {
    // flag dse as running
    DesignSpaceExplorationTask.started(this)
    // setup a log file appender to log progress
    val appender = logFile map { LogFileTracker.setupLogFileAppender _ }
    try {
      // internal logfile is located in subdirectory for this exploration
      val logfile = new ExplorationLog
      exploration += logfile
      // run DSE (this may take a while)
      val result = exploration.start()
      // fetch result, if any
      _result = result map { r => (r._1, r._2) }
      // flush and close the logfile
      ExplorationLog.toFile(logfile, "%s/dse.json".format(exploration.basePath))(_cfg)
      // log the result
      _logger.info("DSE%s run %s for %s finished, result: %s;{}".format(dimensions, composition, target, result.nonEmpty),
          result map ( res =>
            (" best result: %s @ %1.3f, bitstream file: '%s', logfile: '%s', utilization report: '%s', " +
            "timing report: '%s', power report: '%s'").format(
              res._1.composition,
              res._1.frequency,
              res._2.bit getOrElse "",
              res._2.log map (_.file) getOrElse "",
              res._2.util map (_.file) getOrElse "",
              res._2.timing map (_.file) getOrElse "",
              res._2.power map (_.file) getOrElse "")) getOrElse "")
      // return success, if result is not empty
      result.nonEmpty
    } catch { case ex: Throwable =>
      _logger.error("exception: {}, stacktrace: {}", ex: Any, ex.getStackTrace mkString "\n": Any)
      false
    } finally {
      FileAssetManager.start()
      DesignSpaceExplorationTask.finished(this)
      // stop logfile appender
      appender map { LogFileTracker.stopLogFileAppender _ }
    }
  }

  override def canStart: Boolean = ! DesignSpaceExplorationTask.running

  /** @inheritdoc */
  def description: String = "Design Space Exploration"
  /** @inheritdoc */
  def logFiles: Set[String] = Set(logFile.toString)
  /** Result of the design space exploration: the 'winner'. */
  def explorationResult: Option[(DesignSpace.Element, Composer.Result)] = _result
  // Resources for scheduling: None
  val cpus = 0
  val memory = 0
  val licences = Map[String, Int]()
}

/**
 * Companion object for DesignSpaceExplorationTask: Factory method.
 **/
object DesignSpaceExplorationTask {
  /** Currently running instance of task. **/
  private var _task: Option[DesignSpaceExplorationTask] = None

  /** Notification that the given DSE task has started. */
  private def started(t: DesignSpaceExplorationTask) = _task.synchronized {
    require(_task.isEmpty, "must not launch multiple DSEs at once")
    _task = Some(t)
  }

  /** Returns true, if a DSE task is currently running. */
  private def running: Boolean = _task.synchronized { _task.nonEmpty }

  /** Notification that the given DSE task has finished. */
  private def finished(t: DesignSpaceExplorationTask) = _task.synchronized {
    assert(t.equals(_task.get))
    _task = None
  }

  // scalastyle:off parameter.number
  def apply(composition: Composition,
            target: Target,
            dimensions: DesignSpace.Dimensions,
            designFrequency: Heuristics.Frequency,
            heuristic: Heuristics.Heuristic,
            batchSize: Int,
            basePath: Option[String],
            features: Option[Seq[Feature]],
            logFile: Option[String],
            debugMode: Option[String],
172
173
            onComplete: Boolean => Unit,
            deleteOnFail: Boolean = false)
174
175
176
177
178
179
180
181
182
183
184
185
           (implicit cfg: Configuration, tsk: Tasks): ExplorationTask = {
    new DesignSpaceExplorationTask(
        composition,
        target,
        dimensions,
        designFrequency,
        heuristic,
        batchSize,
        basePath,
        features,
        logFile,
        debugMode,
186
187
        onComplete,
        deleteOnFail)
188
189
190
  }
  // scalastyle:on parameter.number
}