Jobs.scala 13 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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
package de.tu_darmstadt.cs.esa.tapasco.jobs
import  de.tu_darmstadt.cs.esa.tapasco.base._
import  de.tu_darmstadt.cs.esa.tapasco.dse._
import  de.tu_darmstadt.cs.esa.tapasco.base.builder._
import  de.tu_darmstadt.cs.esa.tapasco.task._
import  de.tu_darmstadt.cs.esa.tapasco.activity.hls._
import  de.tu_darmstadt.cs.esa.tapasco.activity.composers._
import  de.tu_darmstadt.cs.esa.tapasco.filemgmt.FileAssetManager
import  executors._
import  java.nio.file._

/**
 * Abstract base class of jobs in TPC:
 * Every macro activity of TPC has its own Job structure, which contains the
 * arguments relevant to the activity. Each one has a Json represenation and
 * can be read and written to Json outputs.
 * @param job String identifier of the job, e.g., "hls".
 **/
sealed abstract class Job(val job: String) {
  def execute(implicit exe: Executor[this.type], cfg: Configuration, tsk: Tasks): Boolean =
    exe.execute(this)(cfg, tsk)
}

/**
 * The BulkImport jobs imports a list of IP-XACT cores specified in a import
 * list (given as a comma-separated values [CSV] file).
 * @param csvFile Path to CSV file.
 **/
final case class BulkImportJob(csvFile: Path) extends Job("bulkimport")

/**
 * The Compose job performs a single threadpool composition (i.e., synthesis
 * of a complete hardware architecture + bitstream generation). No design
 * space exploration is performed, the composition is attempted as-is with
 * a fixed design frequency. Composition is performed for each [[base.Target]],
 * i.e., each combination of [[base.Architecture]] and [[base.Platform]] given.
 * @param composition Composition to synthesize micro-architecture for.
 * @param designFrequency Operating frequency of PEs in the design.
 * @param implementation Composer Implementation (e.g., Vivado).
 * @param _architectures Name list of [[base.Architecture]] instances.
 * @param _platforms Name list of [[base.Platform]] instances.
 * @param features List of [[base.Feature]] configurations for the design (opt.).
 * @param debugMode Debug mode name (opt.).
 **/
final case class ComposeJob(
    composition: Composition,
    designFrequency: Heuristics.Frequency,
    private val _implementation: String,
    private val _architectures: Option[Seq[String]] = None,
    private val _platforms: Option[Seq[String]] = None,
    features: Option[Seq[Feature]] = None,
    debugMode: Option[String] = None) extends Job("compose") {
  /** Returns the selected composer tool implementation. */
  lazy val implementation: Composer.Implementation = Composer.Implementation(_implementation)

  /** Returns the list of [[base.Architecture]] instances selected in this job. */
  def architectures: Set[Architecture] =
    FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)

  /** Returns the list of [[base.Platform]] instances selected in this job. */
  def platforms: Set[Platform] =
    FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)

  /** Returns a list of [[base.Target]]s selected in this job. */
  def targets: Seq[Target] =
    for { a <- architectures.toSeq.sortBy(_.name); p <- platforms.toSeq.sortBy(_.name) } yield Target(a, p)
}

/**
 * The CoreStatistics job outputs a comma-separated values (CSV) file which
 * summarizes the synthesis results for each [[base.Core]]. Data includes max.
 * operating frequency, area utilization and runtimes in clock cycles (if
 * available).
 * @param prefix Prefix for output file names: Each [[base.Target]] generates a
                 separate output file; `prefix` may include paths.
 * @param _architectures Name list of [[base.Architecture]] instances.
 * @param _platforms Name list of [[base.Platform]] instances.
 **/
final case class CoreStatisticsJob(
    prefix: Option[String] = None,
    private val _architectures: Option[Seq[String]] = None,
    private val _platforms: Option[Seq[String]] = None) extends Job("corestats") {
  /** Returns the list of [[base.Architecture]] instances selected in this job. */
  def architectures: Set[Architecture] =
    FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)

  /** Returns the list of [[base.Platform]] instances selected in this job. */
  def platforms: Set[Platform] =
    FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)
}

/**
 * The DesignSpaceExploration job launches a _design space exploration (DSE)_:
 * Starting from the `initialComposition`, the design is varied according to
 * the selected `dimensions`, e.g., if frequency variation is enabled, the
 * DSE will attempt to find the highest frequency where composition succeeds
 * (timing closure). The design space can be spanned with area utilization
 * (i.e., more instances of the [[base.Core]]s), design frequency and alternatives
 * (i.e., switching between alternative implementations of a [[base.Kernel]]).
 * This design space will be ordered by the selected [[dse.Heuristics]]
 * implementation, which encodes an optimization goal (e.g., overall job
 * throughput, high area utilization, or others).
 * The DSE will the generate _batches of [[ComposeJob]]s_ to iterate over the
 * design space with descending heuristics value and stop as soon as a
 * successful design was found. This design will be close to optimal w.r.t.
 * to given heuristic.
 * @param initialComposition Composition to start with.
 * @param initialFrequency Design frequency to start with.
 * @param dimensions [[dse.DesignSpace.Dimensions]] selected for this DSE.
 * @param heuristic Heuristic function to order the design space by.
 * @param batchSize Size of the batches (must be > 0).
 * @param basePath Optional base path for all output files generated by DSE.
 * @param _architectures Name filter for target [[base.Architecture]]s (optional).
 * @param _platforms Name filter for target [[base.Platform]]s (optional).
 * @param features List of [[base.Feature]] configurations (optional).
 * @param debugMode Debug mode name (opt.).
 **/
final case class DesignSpaceExplorationJob(
    initialComposition: Composition,
    initialFrequency: Heuristics.Frequency,
    dimensions: DesignSpace.Dimensions,
    heuristic: Heuristics.Heuristic,
    batchSize: Int,
    basePath: Option[Path] = None,
    private val _architectures: Option[Seq[String]] = None,
    private val _platforms: Option[Seq[String]] = None,
    features: Option[Seq[Feature]] = None,
    debugMode: Option[String] = None) extends Job("dse") {
147
148
149
150
151
152
153
154
  private final val logger = de.tu_darmstadt.cs.esa.tapasco.Logging.logger(getClass)
  // warn if dimensions are completely empty
  dimensions match {
    case DesignSpace.Dimensions(false, false, false) =>
      logger.warn("no dimensions enabled in exploration job - consider using a compose job instead")
    case _ => ()
  }

155
156
157
158
159
  /** Returns the list of [[base.Architecture]] instances selected in this job. */
  def architectures: Set[Architecture] =
    FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)

  /** Returns the name filter for [[base.Architecture]] instances. */
Jens Korinth's avatar
Jens Korinth committed
160
  def architectureNames: Option[Seq[String]] = _architectures
161
162
163
164
165
166

  /** Returns the list of [[base.Platform]] instances selected in this job. */
  def platforms: Set[Platform] =
    FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)

  /** Returns the name filter for [[base.Platform]] instances. */
Jens Korinth's avatar
Jens Korinth committed
167
  def platformNames: Option[Seq[String]] = _platforms
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

  /** Returns the first target (alphabetically Arch - Platform). */
  def target: Target = targets.head

  /** Returns the list of target selected in this job. */
  def targets: Seq[Target] = for {
    a <- architectures.toSeq.sortBy(_.name)
    p <- platforms.toSeq.sortBy(_.name)
  } yield Target(a, p)
}

/**
 * The HighLevelSynthesis job executes an external high-level synthesis tool to
 * generate [[base.Core]] instances from a [[base.Kernel]] definition, which in turn can
 * then be used in composition of a threadpool. Will execute once for each
 * [[base.Kernel]] and [[base.Target]], i.e., each combination of [[base.Platform]] and
 * [[base.Architecture]] selected for the job.
 * @param _implementation External tool to use, see [[activity.hls.HighLevelSynthesizer.Implementation]].
 * @param _architectures Name list of [[base.Architecture]] instances.
 * @param _platforms Name list of [[base.Platform]] instances.
 * @param _kernels Name list of [[base.Kernel]] instances to synthesize.
 **/
final case class HighLevelSynthesisJob(
    private val _implementation: String,
    private val _architectures: Option[Seq[String]] = None,
    private val _platforms: Option[Seq[String]] = None,
    private val _kernels: Option[Seq[String]] = None) extends Job("hls") {
  /** Returns the selected HLS tool implementation. */
  lazy val implementation: HighLevelSynthesizer.Implementation = HighLevelSynthesizer.Implementation(_implementation)

  /** Returns the list of [[base.Architecture]] instances selected in this job. */
  def architectures: Set[Architecture] =
    FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)

  /** Returns the list of [[base.Platform]] instances selected in this job. */
  def platforms: Set[Platform] =
    FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)

  /** Returns the list of [[base.Kernel]] instances selected in this job. */
  def kernels: Set[Kernel] =
    FileAssetManager.entities.kernels filter (k => _kernels map (_.contains(k.name)) getOrElse true)
}

/**
 * The Import job takes an external IP-XACT IP core in a .zip file and imports
 * into the TPC library for use in compositions of threadpools. To facilitate
 * design space exploration, the core will be evaluated, i.e., out-of-context
 * synthesis + place-and-route will be performed to generate estimates for
 * area utilization and max. operating frequency. Optionally, average clock
 * cycle counts for a job execution can also be provided (otherwise 1 clock
 * cycle is assumed as a fallback). If reports are found within the .zip, or
 * in the TPC core library at the directory for the core, evaluation will be
 * skipped and the values from the reports will be used directly.
 * The core will be imported for each [[base.Target]], i.e., combination of
 * [[base.Architecture]] and [[base.Platform]] selected for this job.
 * @param zipFile Path to the .zip file.
 * @param id Identifier for the [[base.Kernel]] that is implemented by this IP
             core (must be > 0).
 * @param description Description of the core (optional).
 * @param averageClockCycles Clock cycles in an average job (optional).
228
 * @param skipEvaluation Do not perform evaluation (optional).
229
 * @param synthOptions Optional parameters for synth_design.
230
231
 * @param _architectures Name list of [[base.Architecture]] instances.
 * @param _platforms Name list of [[base.Platform]] instances.
232
 * @param _optimization Positive integer optimization level.
233
234
235
236
237
238
 **/
final case class ImportJob(
    zipFile: Path,
    id: Kernel.Id,
    description: Option[String] = None,
    averageClockCycles: Option[Int] = None,
239
    skipEvaluation: Option[Boolean] = None,
240
    synthOptions: Option[String] = None,
241
    private val _architectures: Option[Seq[String]] = None,
242
243
    private val _platforms: Option[Seq[String]] = None,
    private val _optimization: Option[Int] = None) extends Job("import") {
244
245
246
247
248
249
250
  /** Returns the list of [[base.Architecture]] instances selected in this job. */
  def architectures: Set[Architecture] =
    FileAssetManager.entities.architectures filter (a => _architectures map (_.contains(a.name)) getOrElse true)

  /** Returns the list of [[base.Platform]] instances selected in this job. */
  def platforms: Set[Platform] =
    FileAssetManager.entities.platforms filter (p => _platforms map (_.contains(p.name)) getOrElse true)
251
252
253

  /** Returns the optimization level. */
  def optimization: Int = _optimization getOrElse 0
254
255
256
257
258
259
260
261
262
}

object BulkImportJob extends Builds[BulkImportJob]
object ComposeJob extends Builds[ComposeJob]
object CoreStatisticsJob extends Builds[CoreStatisticsJob]
object ImportJob extends Builds[ImportJob]
object HighLevelSynthesisJob extends Builds[HighLevelSynthesisJob]
object DesignSpaceExplorationJob extends Builds[DesignSpaceExplorationJob]
object Job extends Builds[Job]