Commit 331d0f50 authored by Carsten Heinz's avatar Carsten Heinz Committed by Lukas Sommer

Remove power report

Fixes #62
parent 1e7ce497
......@@ -190,15 +190,6 @@ report_timing_summary -quiet -datasheet -file @@REPORT_TIMING@@
# report utilization
report_utilization -quiet -file @@REPORT_UTILIZATION@@
# recalculate achieved frequency and set new period (for realistic power values)
set wns [tapasco::get_wns_from_timing_report @@REPORT_TIMING@@]
if {$wns < 0} {
create_clock -name clk -period [expr "$period - $wns"] $clock_ports
}
# report power
report_power -quiet -file @@REPORT_POWER@@
# extract AXI interfaces
# requires a block design
set bd [create_bd_design bd]
......
......@@ -251,7 +251,6 @@ namespace eval platform {
report_timing_summary -warn_on_violation -file timing.txt
report_utilization -file utilization.txt
report_utilization -file utilization_userlogic.txt -cells [get_cells -hierarchical -filter {NAME =~ *target_ip_*}]
report_power -file power.txt
set wns [tapasco::get_wns_from_timing_report "timing.txt"]
if {$wns >= -0.3} {
write_bitstream -force "${bitstreamname}.bit"
......
......@@ -40,12 +40,10 @@ object CoreStatistics {
FileAssetManager.targetForReport(r.file).equals(target)
} map (path => CoreReports(
path,
PowerReport(path.file.resolveSibling("power.rpt")),
TimingReport(path.file.resolveSibling("timing.rpt")))))
private final case class CoreReports(
synth: SynthesisReport,
power: Option[PowerReport],
timing: Option[TimingReport]
)
......@@ -56,7 +54,6 @@ object CoreStatistics {
e.synth.file,
dumpArea(e.synth),
dumpClocks(e.synth),
dumpPower(e.power),
dumpAvgClockCycles(e.synth),
dumpMaxDelayPath(e.timing)) mkString "," } mkString NL)
fw.close()
......@@ -76,14 +73,6 @@ object CoreStatistics {
r.timing.map(_.targetPeriod).getOrElse("")
) mkString ","
private def dumpPower(pr: Option[PowerReport]): String = pr match {
case Some(r) => Seq(r.totalOnChipPower.getOrElse(""),
r.dynamicPower.getOrElse(""),
r.staticPower.getOrElse(""),
r.confidenceLevel.getOrElse("")) mkString ","
case _ => Seq("","","","") mkString ","
}
private def dumpAvgClockCycles(r: SynthesisReport): String =
Core.from(r.file.getParent.resolveSibling("core.json")) map { cd =>
Seq(cd.averageClockCycles.getOrElse(""),
......@@ -101,7 +90,6 @@ object CoreStatistics {
private final val HEADER = Seq(
"Core", "Slices", "Slices (%)", "LUT", "LUT (%)", "FF", "FF (%)",
"DSP", "DSP (%)", "BRAM", "BRAM (%)", "AchievedClockPeriod", "TargetClockPeriod",
"Total On-Chip Power (W)", "Dynamic Power (W)", "Device Static Power (W)", "Power Confidence Level",
"Average Runtime (clock cycles)", "Jobs / s",
"Max Delay Path Slack", "Max Delay Path Source", "Max Delay Path Destination"
) mkString ","
......
......@@ -66,7 +66,6 @@ object EvaluateIP {
private final class Files(zipFile: Path, reportFile: Path) {
lazy val rpt_timing = reportFile.resolveSibling("timing.rpt")
lazy val rpt_util = reportFile.resolveSibling("utilization.rpt")
lazy val rpt_power = reportFile.resolveSibling("power.rpt")
lazy val rpt_port = reportFile.resolveSibling("port.rpt")
lazy val s_dcp = reportFile.resolveSibling("out-of-context_synth.dcp")
lazy val i_dcp = reportFile.resolveSibling("out-of-context_impl.dcp")
......@@ -156,7 +155,6 @@ object EvaluateIP {
"PERIOD" -> targetPeriod.toString,
"REPORT_TIMING" -> files.rpt_timing.toString,
"REPORT_UTILIZATION" -> files.rpt_util.toString,
"REPORT_POWER" -> files.rpt_power.toString,
"REPORT_PORT" -> files.rpt_port.toString,
"SYNTH_CHECKPOINT" -> files.s_dcp.toString,
"IMPL_CHECKPOINT" -> files.i_dcp.toString,
......
......@@ -89,8 +89,7 @@ object Composer {
bit: Option[String] = None,
log: Option[ComposerLog] = None,
util: Option[UtilizationReport] = None,
timing: Option[TimingReport] = None,
power: Option[PowerReport] = None
timing: Option[TimingReport] = None
)
/** Result of the external process execution. **/
......
......@@ -93,19 +93,19 @@ class VivadoComposer()(implicit cfg: Configuration) extends Composer {
// check retcode
if (r == InterruptibleProcess.TIMEOUT_RETCODE) {
logger.error("Vivado timeout for %s in '%s'".format(files.runName, files.outdir))
Composer.Result(Timeout, log = files.log, util = None, timing = None, power = None)
Composer.Result(Timeout, log = files.log, util = None, timing = None)
} else if (r != 0) {
logger.error("Vivado finished with non-zero exit code: %d for %s in '%s'"
.format(r, files.runName, files.outdir))
Composer.Result(files.log map (_.result) getOrElse OtherError, log = files.log,
util = None, timing = None, power = None)
util = None, timing = None)
} else {
// check for timing failure
if (files.tim.isEmpty) {
throw new Exception("could not parse timing report: '%s'".format(files.timFile.toString))
} else {
Composer.Result(checkTimingFailure(files), Some(files.bitFile.toString),
files.log, files.util, files.tim, files.pwr)
files.log, files.util, files.tim)
}
}
}
......@@ -228,11 +228,9 @@ object VivadoComposer {
lazy val tclFile: Path = outdir.resolve("%s.tcl".format(t.pd.name))
lazy val bitFile: Path = logFile.resolveSibling("%s.bit".format(Composer.mkProjectName(c, t, f)))
lazy val runName: String = "%s with %s[F=%1.3f]".format(logformat(c), t, f)
lazy val pwrFile: Path = logFile.resolveSibling("power.txt")
lazy val timFile: Path = logFile.resolveSibling("timing.txt")
lazy val utilFile: Path = logFile.resolveSibling("utilization.txt")
lazy val log = ComposerLog(logFile)
lazy val pwr = PowerReport(pwrFile)
lazy val tim = TimingReport(timFile)
lazy val util = UtilizationReport(utilFile)
}
......
......@@ -44,13 +44,12 @@ package object json {
}
private def mkComposerResult(r: ComposeResult, bit: Option[String], log: Option[String], util: Option[String],
timing: Option[String], power: Option[String]) = Composer.Result(
timing: Option[String]) = Composer.Result(
r,
bit,
log flatMap (f => ComposerLog(Paths.get(f))),
util flatMap (f => UtilizationReport(Paths.get(f))),
timing flatMap (f => TimingReport(Paths.get(f))),
power flatMap (f => PowerReport(Paths.get(f)))
timing flatMap (f => TimingReport(Paths.get(f)))
)
private def wrComposerResult(r: Composer.Result) = (
......@@ -58,8 +57,7 @@ package object json {
r.bit,
r.log map (_.file.toString),
r.util map (_.file.toString),
r.timing map (_.file.toString),
r.power map (_.file.toString)
r.timing map (_.file.toString)
)
implicit val composerResultFormat: Format[Composer.Result] = (
......@@ -67,7 +65,6 @@ package object json {
(JsPath \ "Bitstream").formatNullable[String] ~
(JsPath \ "Log").formatNullable[String] ~
(JsPath \ "UtilizationReport").formatNullable[String] ~
(JsPath \ "TimingReport").formatNullable[String] ~
(JsPath \ "PowerReport").formatNullable[String]
(JsPath \ "TimingReport").formatNullable[String]
) (mkComposerResult _, wrComposerResult _)
}
......@@ -24,7 +24,7 @@ import java.nio.file._
/**
* A ReportManager maintains caches for different report types in a common base
* directory: Currently co-simulation, timing, power and synthesis reports
* directory: Currently co-simulation, timing and synthesis reports
* are supported, each in an [[EntityCache]] of their own.
*
* To react on changes, the basePathListener and directoryListener values
......@@ -77,23 +77,6 @@ class ReportManager(var _base: Path) extends Publisher {
files.headOption flatMap { f => _cosimReportCache.apply(f).head }
}
/** Returns all PowerReports. **/
def powerReports: Set[PowerReport] = _powerReportCache.entities
/** Returns PowerReport for given core and target. **/
def powerReport(name: String, target: Target): Option[PowerReport] =
powerReport(name, target.ad.name, target.pd.name)
/** Returns PowerReport for given core and Architecture/Platform combination. **/
def powerReport(name: String, archName: String, platformName: String): Option[PowerReport] = {
val bp = _base.resolve(name).resolve(archName).resolve(platformName)
_logger.trace("looking for PowerReport of {}@{}@{} in {}", name, archName, platformName, bp)
val files = _powerReportCache.files filter (f => f.startsWith(bp))
if (files.size > 1) {
_logger.warn("found more than one PowerReport of {}@{}@{} in {}: {}",
name, archName, platformName, bp, files)
}
files.headOption flatMap { f => _powerReportCache.apply(f).head }
}
/** Returns all SynthesisReports. **/
def synthReports: Set[SynthesisReport] = _synthReportCache.entities
/** Returns SynthesisReport for given core and target. **/
......@@ -132,9 +115,6 @@ class ReportManager(var _base: Path) extends Publisher {
/** EntityCache instance for CoSimReports. **/
private val _cosimReportCache = EntityCache(Set(_base),
"""_cosim.rpt$""".r.unanchored, CoSimReport.apply _)
/** EntityCache instance for PowerReports. **/
private val _powerReportCache = EntityCache(Set(_base),
"""power.rpt$""".r.unanchored, PowerReport.apply _)
/** EntityCache instance for SynthesisReports. **/
private val _synthReportCache = EntityCache(Set(_base),
"""_export.xml$""".r.unanchored, SynthesisReport.apply _)
......@@ -145,7 +125,6 @@ class ReportManager(var _base: Path) extends Publisher {
/** Internal seq of report caches. **/
private val _reportCaches: Seq[EntityCache[_]] = Seq(
_cosimReportCache,
_powerReportCache,
_synthReportCache,
_timingReportCache
)
......@@ -162,9 +141,6 @@ class ReportManager(var _base: Path) extends Publisher {
osw.append("<<ReportEntityCache: CoSim>>").append(NL)
EntityCache.dump(_cosimReportCache, osw)
osw.append(NL)
osw.append("<<ReportEntityCache: Power>>").append(NL)
EntityCache.dump(_powerReportCache, osw)
osw.append(NL)
osw.append("<<ReportEntityCache: Synth>>").append(NL)
EntityCache.dump(_synthReportCache, osw)
osw.append(NL)
......
......@@ -47,7 +47,6 @@ private object ReportPanel {
def mkData(r: Report): Array[Array[Any]] = r match {
case cr: CoSimReport => mkData(cr)
case pr: PowerReport => mkData(pr)
case sr: SynthesisReport => mkData(sr)
case tr: TimingReport => mkData(tr)
case ur: UtilizationReport => mkData(ur)
......@@ -76,14 +75,6 @@ private object ReportPanel {
Array("Max. Interval (clock cycles)", cr.interval.max)
)
def mkData(pr: PowerReport): Array[Array[Any]] = Array(
Array("File", pr.file.toString),
Array("Total on-chip power (W)", pr.totalOnChipPower getOrElse "N/A"),
Array("Dynamic power (W)", pr.dynamicPower getOrElse "N/A"),
Array("Static power (W)", pr.staticPower getOrElse "N/A"),
Array("Confidence Level", pr.confidenceLevel getOrElse "")
)
def mkData(tr: TimingReport): Array[Array[Any]] = Array(
Array("File", tr.file.toString),
Array("Worst negative slack (ns)", tr.worstNegativeSlack),
......
......@@ -114,7 +114,6 @@ class ExplorationGraphController extends ViewController {
_logger.trace("{} -> {}", n: Any, cr)
cr.util foreach { Reports += _ }
cr.timing foreach { Reports += _ }
cr.power foreach { Reports += _ }
}}
case _ => {}
}
......@@ -159,8 +158,7 @@ class ExplorationGraphController extends ViewController {
* Reports can simply be added by [[Reports.+=]], [[Reports.++=]], [[Reports.-=]]
* and [[Reports.--=]] methods, will be matched to their panel automatically
* based on the type of report.
* @note supports currently [[reports.SynthesisReport]], [[reports.TimingReport]],
* [[reports.PowerReport]]
* @note supports currently [[reports.SynthesisReport]], [[reports.TimingReport]]
*/
object Reports {
private val _reports = scala.collection.mutable.Set[Report]()
......@@ -170,7 +168,6 @@ class ExplorationGraphController extends ViewController {
r match {
case sr: SynthesisReport => egp.reportPanel(0).report = sr
case tr: TimingReport => egp.reportPanel(1).report = tr
case pr: PowerReport => egp.reportPanel(2).report = pr
case _ => {}
}
}
......
......@@ -45,7 +45,7 @@ object ReportViewer extends SimpleSwingApplication {
*/
def loadReport(filename: String): Option[Report] = {
val fn = Paths.get(filename)
lazy val rs: Stream[Option[Report]] = Stream.empty :+ CoSimReport(fn) :+ PowerReport(fn) :+ SynthesisReport(fn) :+
lazy val rs: Stream[Option[Report]] = Stream.empty :+ CoSimReport(fn) :+ SynthesisReport(fn) :+
TimingReport(fn) :+ UtilizationReport(fn)
rs collectFirst { case Some(r) => r }
}
......
//
// Copyright (C) 2014 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/>.
//
/**
* @file PowerReport.scala
* @brief Model for parsing and evaluating power reports in Vivado format.
* @authors J. Korinth, TU Darmstadt (jk@esa.cs.tu-darmstadt.de)
**/
package de.tu_darmstadt.cs.esa.tapasco.reports
import java.nio.file.Path
import scala.io.Source
/** Co-Simulation Report model. **/
final case class PowerReport(
override val file: Path,
totalOnChipPower: Option[Double],
dynamicPower: Option[Double],
staticPower: Option[Double],
confidenceLevel: Option[String]) extends Report(file) {
require( Seq(totalOnChipPower, dynamicPower, staticPower, confidenceLevel) map (_.nonEmpty) reduce (_ || _),
"need at least one valid measurement in power report")
}
object PowerReport {
private[this] val logger = de.tu_darmstadt.cs.esa.tapasco.Logging.logger(this.getClass)
private final val STR_TOCP = "Total On-Chip Power (W)"
private final val STR_DYNP = "Dynamic (W)"
private final val STR_STAP = "Device Static (W)"
private final val STR_CONF = "Confidence Level"
private final val STR_FILTERS = Seq(STR_TOCP, STR_DYNP, STR_STAP, STR_CONF)
/** Produce PowerReport instance from file. **/
def apply(sr: Path): Option[PowerReport] = try {
val matches =
Source.fromFile(sr.toString)
.getLines
.map (_.split("\\|") map (_.trim))
.filter (l => l.length > 2 && STR_FILTERS.contains(l(1)))
.map (l => (l(1), l(2)))
Some(PowerReport(sr,
(matches filter (l => l._1.equals(STR_TOCP)) toSeq).headOption map(_._2.toDouble),
(matches filter (l => l._1.equals(STR_DYNP)) toSeq).headOption map(_._2.toDouble),
(matches filter (l => l._1.equals(STR_STAP)) toSeq).headOption map(_._2.toDouble),
(matches filter (l => l._1.equals(STR_CONF)) toSeq).headOption map(_._2)
))
} catch { case e: Exception => {
logger.warn(Seq("Could not extract power data from ", sr, ": ", e) mkString)
None
}}
}
......@@ -77,7 +77,7 @@ class ComposeTask(composition: Composition,
_logger.trace("_composerResult = {}", _composerResult: Any)
_logger.info(("compose run %s@%2.3f MHz for %s finished, result: %s, bitstream file: '%s', " +
"logfile: '%s', utilization report: '%s', timing report: '%s', power report: '%s'").format(
"logfile: '%s', utilization report: '%s', timing report: '%s'").format(
composition: Any,
designFrequency,
target,
......@@ -85,8 +85,7 @@ class ComposeTask(composition: Composition,
_composerResult flatMap (_.bit) getOrElse "",
_composerResult flatMap (_.log map (_.file)) getOrElse "",
_composerResult flatMap (_.util map (_.file)) getOrElse "",
_composerResult flatMap (_.timing map (_.file)) getOrElse "",
_composerResult flatMap (_.power map (_.file)) getOrElse ""))
_composerResult flatMap (_.timing map (_.file)) getOrElse ""))
LogFileTracker.stopLogFileAppender(appender)
val result = (_composerResult map (_.result) getOrElse false) == ComposeResult.Success
......@@ -170,7 +169,6 @@ object ComposeTask {
private final val RE_RESULT = """compose run .*result: ([^,]+)""".r.unanchored
private final val RE_LOG = """compose run .*result: \S+.*logfile: '([^']+)'""".r.unanchored
private final val RE_TIMING = """compose run .*result: \S+.*timing report: '([^']+)'""".r.unanchored
private final val RE_POWER = """compose run .*result: \S+.*power report: '([^']+)'""".r.unanchored
private final val RE_UTIL = """compose run .*result: \S+.*utilization report: '([^']+)'""".r.unanchored
private final val RE_RRANDOM = """(?i)(random|r(?:nd)?)""".r
private final val RE_RPLACER = """(?i)(placer|p(?:lc)?)""".r
......@@ -190,10 +188,6 @@ object ComposeTask {
logger.trace("log path: {}", mkpath(m))
ComposerLog(mkpath(m))
})
val power = RE_POWER.findFirstMatchIn(lines) flatMap (m => {
logger.trace("power path: {}", mkpath(m))
PowerReport(mkpath(m))
})
val util = RE_UTIL.findFirstMatchIn(lines) flatMap (m => {
logger.trace("utilization path: {}", mkpath(m))
UtilizationReport(mkpath(m))
......@@ -202,8 +196,8 @@ object ComposeTask {
logger.trace("timing path: {}", mkpath(m))
TimingReport(mkpath(m))
})
logger.debug("result = {}, llog = {}, power = {}, util = {}, timing = {}", result, llog, power, util, timing)
result map (r => Composer.Result(r, log = llog, power = power, util = util, timing = timing))
logger.debug("result = {}, llog = {}, util = {}, timing = {}", result, llog, util, timing)
result map (r => Composer.Result(r, log = llog, util = util, timing = timing))
}
// scalastyle:off magic.number
......
......@@ -101,14 +101,13 @@ private class DesignSpaceExplorationTask(
_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(
"timing 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 "")
res._2.timing map (_.file) getOrElse "")) getOrElse "")
// return success, if result is not empty
result.nonEmpty
} catch { case ex: Throwable =>
......
......@@ -37,12 +37,11 @@ object LogFormatter {
"%s[F=%3.3f] with (h = %3.5f)".format(logformat(de.composition), de.frequency, de.h)
def logformat(ce: Composer.Result): String =
"%s, logfile: '%s', utilization report: '%s', timing report: '%s', power report: '%s'"
"%s, logfile: '%s', utilization report: '%s', timing report: '%s'"
.format(ce.result,
ce.log map (_.file.toString) getOrElse "",
ce.util map (_.file.toString) getOrElse "",
ce.timing map (_.file.toString) getOrElse "",
ce.power map (_.file.toString) getOrElse "")
ce.timing map (_.file.toString) getOrElse "")
def logformat(cs: Seq[Composition.Entry]): String = "[%s]".format(cs map (logformat _) mkString ", ")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment