Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tapasco
tapasco
Commits
b758d4fc
Commit
b758d4fc
authored
May 17, 2019
by
Lukas Sommer
Browse files
Merge branch 'feature/issue30-consider-slots-dse' into develop
parents
62596420
cfe59f6e
Pipeline
#1242
passed with stages
in 192 minutes and 56 seconds
Changes
9
Pipelines
1
Show whitespace changes
Inline
Side-by-side
common/evaluate_ip.tcl.template
View file @
b758d4fc
...
...
@@ -199,5 +199,17 @@ if {$wns < 0} {
# report power
report_power -quiet -file @@REPORT_POWER@@
# extract AXI interfaces
# requires a block design
set bd [create_bd_design bd]
set pe [create_bd_cell pe -vlnv @@VLNV@@]
set interfaces_file [open @@REPORT_PORT@@ "w"]
puts @@REPORT_PORT@@
set axi_master_ports [tapasco::get_aximm_interfaces $pe "Master"]
set axi_slave_ports [tapasco::get_aximm_interfaces $pe "Slave"]
puts $interfaces_file "AXI_MASTER_PORTS\t[llength $axi_master_ports]"
puts $interfaces_file "AXI_SLAVE_PORTS\t[llength $axi_slave_ports]"
close $interfaces_file
# done!
exit
common/ip_report.xml.template
View file @
b758d4fc
...
...
@@ -23,4 +23,9 @@
<AchievedClockPeriod>@@MIN_PERIOD@@</AchievedClockPeriod>
</TimingReport>
<PortReport>
<NumMasters>@@MASTERS@@</NumMasters>
<NumSlaves>@@SLAVES@@</NumSlaves>
</PortReport>
</profile>
report-examples/correct-port.rpt
0 → 100644
View file @
b758d4fc
AXI_MASTER_PORTS 42
AXI_SLAVE_PORTS 25
src/main/scala/tapasco/activity/EvaluateIP.scala
View file @
b758d4fc
...
...
@@ -67,6 +67,7 @@ object EvaluateIP {
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"
)
lazy
val
zip
=
zipFile
...
...
@@ -121,7 +122,8 @@ object EvaluateIP {
logger
.
trace
(
"%s: Vivado finished successfully"
.
format
(
runPrefix
))
val
ur
=
UtilizationReport
(
files
.
rpt_util
).
get
val
dpd
=
TimingReport
(
files
.
rpt_timing
).
get
.
dataPathDelay
writeXMLReport
(
reportFile
,
ur
,
dpd
,
targetPeriod
)
val
portReport
=
PortReport
(
files
.
rpt_port
).
get
writeXMLReport
(
reportFile
,
ur
,
dpd
,
targetPeriod
,
portReport
.
numMasters
,
portReport
.
numSlaves
)
logger
.
info
(
"{} finished successfully, report in {}"
,
runPrefix
:
Any
,
reportFile
)
// clean up files on exit
deleteOnExit
(
files
.
baseDir
.
toFile
)
...
...
@@ -155,6 +157,7 @@ object EvaluateIP {
"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
,
"OPTIMIZATION"
->
optimization
.
toString
,
...
...
@@ -177,7 +180,7 @@ object EvaluateIP {
* @param targetPeriod Target operating period.
**/
private
def
writeXMLReport
(
reportFile
:
Path
,
ur
:
UtilizationReport
,
dataPathDelay
:
Double
,
targetPeriod
:
Double
)
:
Unit
=
{
targetPeriod
:
Double
,
masters
:
Int
,
slaves
:
Int
)
:
Unit
=
{
val
needles
=
scala
.
collection
.
mutable
.
Map
[
String
,
String
](
"SLICE"
->
ur
.
used
.
SLICE
.
toString
,
"SLICES"
->
ur
.
available
.
SLICE
.
toString
,
...
...
@@ -190,7 +193,9 @@ object EvaluateIP {
"DSP"
->
ur
.
used
.
DSP
.
toString
,
"DSPS"
->
ur
.
available
.
DSP
.
toString
,
"PERIOD"
->
targetPeriod
.
toString
,
"MIN_PERIOD"
->
dataPathDelay
.
toString
"MIN_PERIOD"
->
dataPathDelay
.
toString
,
"MASTERS"
->
masters
.
toString
,
"SLAVES"
->
slaves
.
toString
)
// write final report
...
...
src/main/scala/tapasco/dse/DesignSpace.scala
View file @
b758d4fc
...
...
@@ -40,8 +40,10 @@ package de.tu_darmstadt.cs.esa.tapasco.dse
import
de.tu_darmstadt.cs.esa.tapasco.base._
import
de.tu_darmstadt.cs.esa.tapasco.filemgmt.FileAssetManager
import
de.tu_darmstadt.cs.esa.tapasco.util.LogFormatter._
import
java.nio.file.
{
Paths
}
import
java.nio.file.Paths
import
Heuristics._
import
de.tu_darmstadt.cs.esa.tapasco.util.SlotOccupation
class
DesignSpace
(
bd
:
Composition
,
...
...
@@ -80,34 +82,40 @@ class DesignSpace(
val
cores
=
bd
.
composition
flatMap
(
ce
=>
FileAssetManager
.
entities
.
core
(
ce
.
kernel
,
target
))
val
srs
=
cores
flatMap
{
c
:
Core
=>
FileAssetManager
.
reports
.
synthReport
(
c
.
name
,
target
)
}
val
areaEstimates
=
srs
flatMap
(
_
.
area
)
val
slotOccupations
=
srs
map
(
r
=>
SlotOccupation
(
r
.
slaves
.
get
,
target
.
pd
.
slotCount
))
val
targetUtil
=
target
.
pd
.
targetUtilization
.
toDouble
logger
.
trace
(
"target util = "
+
targetUtil
)
def
slotUtil
(
counts
:
Seq
[
Int
])
:
SlotOccupation
=
(
slotOccupations
zip
counts
).
map
(
o
=>
o
.
_1
*
o
.
_2
).
reduce
(
_
+
_
)
// check if there is any feasible composition
if
(
minCounts
.
reduce
(
_
+
_
)
>
target
.
pd
.
slotCount
)
{
if
(
!
slotUtil
(
minCounts
).
isFeasible
)
{
throw
new
Exception
(
"Composition infeasible! Exceeds maximal slot count of "
+
target
.
pd
.
slotCount
+
" for "
+
target
+
"."
+
NL
+
bd
)
}
def
areaUtil
(
counts
:
Seq
[
Int
])
=
(
areaEstimates
zip
counts
)
map
(
a
=>
a
.
_1
*
a
.
_2
)
reduce
(
_
+
_
)
val
currUtil
=
areaUtil
(
minCounts
).
utilization
def
areaUtil
(
counts
:
Seq
[
Int
])
=
(
areaEstimates
zip
counts
)
map
(
a
=>
a
.
_1
*
a
.
_2
)
reduce
(
_
+
_
)
// compute number of steps
val
currUtil
=
areaUtil
(
minCounts
).
utilization
val
df
:
Int
=
Seq
(
java
.
lang
.
Math
.
round
((
targetUtil
-
currUtil
)
/
currUtil
).
toInt
,
1
).
max
val
currSlots
=
slotUtil
(
minCounts
).
slots
val
targetSlots
=
target
.
pd
.
slotCount
val
sf
:
Int
=
Math
.
max
(
Math
.
round
(
targetSlots
.
toDouble
/
currSlots
.
toDouble
),
1
).
toInt
val
steps
=
Math
.
min
(
sf
,
df
)
logger
.
trace
(
"minCounts = "
+
minCounts
+
" currUtil = "
+
currUtil
)
// compute feasible sequences as multiples of minCounts
val
seqs
=
(
for
(
i
<-
df
to
1
by
-
1
)
yield
minCounts
map
(
n
=>
i
*
n
))
filter
(
c
=>
areaUtil
(
c
).
isFeasible
)
val
seqs
=
(
for
(
i
<-
steps
to
1
by
-
1
)
yield
minCounts
map
(
n
=>
i
*
n
))
filter
(
c
=>
areaUtil
(
c
).
isFeasible
&&
slotUtil
(
c
).
isFeasible
)
logger
.
trace
(
"number of feasible counts: "
+
seqs
.
length
)
if
(
seqs
.
length
==
0
)
{
if
(
seqs
.
isEmpty
)
{
logger
.
warn
(
"No feasible composition found; please check starting composition ratios: "
+
NL
+
bd
)
}
// make sequence of CompositionEntries
val
ces
=
for
{
s
<-
seqs
filter
(
_
.
reduce
(
_
+
_
)
<=
target
.
pd
.
slotCount
)
s
<-
seqs
filter
(
_
.
sum
<=
target
.
pd
.
slotCount
)
}
yield
bd
.
composition
.
map
(
_
.
kernel
)
zip
s
map
(
x
=>
Composition
.
Entry
(
x
.
_1
,
x
.
_2
))
// make full composition
...
...
@@ -123,7 +131,7 @@ class DesignSpace(
feasibleAlternatives
(
bd
)
map
(
feasibleCompositions
(
_
))
reduce
(
_
++
_
)
lazy
val
enumerate
:
Seq
[
DesignSpace.Element
]
=
(
for
{
bd
<-
compositions
(
bd
)
;
bd
<-
compositions
(
bd
)
f
<-
feasibleFreqs
(
bd
)
}
yield
DesignSpace
.
Element
(
bd
,
f
,
heuristic
(
bd
,
f
,
target
)(
cfg
)))
sortBy
(
_
.
h
)
reverse
...
...
@@ -162,7 +170,7 @@ object DesignSpace {
val
cores
=
bd
.
composition
flatMap
(
ce
=>
FileAssetManager
.
entities
.
core
(
ce
.
kernel
,
target
))
val
srs
=
cores
flatMap
{
c
:
Core
=>
FileAssetManager
.
reports
.
synthReport
(
c
.
name
,
target
)
}
val
cps
=
srs
flatMap
(
_
.
timing
)
map
(
_
.
clockPeriod
)
val
fmax
=
if
(
cps
.
length
>
0
)
1000.0
/
cps
.
max
else
Double
.
PositiveInfinity
val
fmax
=
if
(
cps
.
nonEmpty
)
1000.0
/
cps
.
max
else
Double
.
PositiveInfinity
target
.
pd
.
supportedFrequencies
map
(
_
.
toDouble
)
filter
(
_
<=
fmax
)
sortWith
(
_
>
_
)
}
...
...
@@ -172,39 +180,45 @@ object DesignSpace {
val
cores
=
bd
.
composition
flatMap
(
ce
=>
FileAssetManager
.
entities
.
core
(
ce
.
kernel
,
target
))
val
srs
=
cores
flatMap
{
c
:
Core
=>
FileAssetManager
.
reports
.
synthReport
(
c
.
name
,
target
)
}
val
areaEstimates
=
srs
flatMap
(
_
.
area
)
val
slotOccupations
=
srs
map
(
r
=>
SlotOccupation
(
r
.
slaves
.
get
,
target
.
pd
.
slotCount
))
val
targetUtil
=
target
.
pd
.
targetUtilization
.
toDouble
logger
.
trace
(
"target util = "
+
targetUtil
)
def
slotUtil
(
counts
:
Seq
[
Int
])
:
SlotOccupation
=
(
slotOccupations
zip
counts
).
map
(
o
=>
o
.
_1
*
o
.
_2
).
reduce
(
_
+
_
)
// check if there is any feasible composition
if
((
minCounts
fold
0
)
(
_
+
_
)
>
target
.
pd
.
slotCount
)
{
if
(
!
slotUtil
(
minCounts
).
isFeasible
)
{
throw
new
Exception
(
"Composition infeasible! Exceeds maximal slot count of "
+
target
.
pd
.
slotCount
+
" for "
+
target
+
"."
+
NL
+
bd
)
}
def
areaUtil
(
counts
:
Seq
[
Int
])
=
(
areaEstimates
zip
counts
)
map
(
a
=>
a
.
_1
*
a
.
_2
)
reduce
(
_
+
_
)
val
currUtil
=
areaUtil
(
minCounts
).
utilization
def
areaUtil
(
counts
:
Seq
[
Int
])
=
(
areaEstimates
zip
counts
)
map
(
a
=>
a
.
_1
*
a
.
_2
)
reduce
(
_
+
_
)
// compute number of steps
val
currUtil
=
areaUtil
(
minCounts
).
utilization
val
df
:
Int
=
Seq
(
java
.
lang
.
Math
.
round
((
targetUtil
-
currUtil
)
/
currUtil
).
toInt
,
1
).
max
val
currSlots
=
slotUtil
(
minCounts
).
slots
val
targetSlots
=
target
.
pd
.
slotCount
val
sf
:
Int
=
Math
.
max
(
Math
.
round
(
targetSlots
.
toDouble
/
currSlots
.
toDouble
),
1
).
toInt
val
steps
=
Math
.
min
(
sf
,
df
)
logger
.
trace
(
"minCounts = "
+
minCounts
+
" currUtil = "
+
currUtil
)
// compute feasible sequences as multiples of minCounts
val
seqs
=
(
for
(
i
<-
df
to
1
by
-
1
)
yield
minCounts
map
(
n
=>
i
*
n
))
filter
(
c
=>
areaUtil
(
c
).
isFeasible
)
val
seqs
=
(
for
(
i
<-
steps
to
1
by
-
1
)
yield
minCounts
map
(
n
=>
i
*
n
))
filter
(
c
=>
areaUtil
(
c
).
isFeasible
&&
slotUtil
(
c
).
isFeasible
)
logger
.
trace
(
"number of feasible counts: "
+
seqs
.
length
)
if
(
seqs
.
length
==
0
)
{
if
(
seqs
.
isEmpty
)
{
logger
.
warn
(
"No feasible composition found; please check starting composition ratios: "
+
NL
+
bd
)
}
// make sequence of CompositionEntries
val
ces
=
for
{
s
<-
seqs
filter
(
_
.
reduce
(
_
+
_
)
<=
target
.
pd
.
slotCount
)
s
<-
seqs
filter
(
_
.
sum
<=
target
.
pd
.
slotCount
)
}
yield
bd
.
composition
.
map
(
_
.
kernel
)
zip
s
map
(
x
=>
Composition
.
Entry
(
x
.
_1
,
x
.
_2
))
// make full composition
ces
map
(
Composition
(
Paths
.
get
(
"N/A"
),
Some
(
"Generated composition."
),
_
))
}
else
{
Seq
()
Seq
.
empty
}
}
src/main/scala/tapasco/reports/PortReport.scala
0 → 100644
View file @
b758d4fc
package
de.tu_darmstadt.cs.esa.tapasco.reports
import
java.nio.file.Path
import
de.tu_darmstadt.cs.esa.tapasco.util.SequenceMatcher
import
scala.io.Source
final
case
class
PortReport
(
override
val
file
:
Path
,
numMasters
:
Int
,
numSlaves
:
Int
)
extends
Report
(
file
)
object
PortReport
{
private
[
this
]
val
logger
=
de
.
tu_darmstadt
.
cs
.
esa
.
tapasco
.
Logging
.
logger
(
this
.
getClass
)
def
apply
(
pr
:
Path
)
:
Option
[
PortReport
]
=
extract
(
pr
)
private
def
masterPortMatcher
:
SequenceMatcher
[
Int
]
=
new
SequenceMatcher
[
Int
](
"""AXI_MASTER_PORTS\s+(\d+)"""
.
r
)(
true
,
ms
=>
ms
.
head
.
group
(
1
).
toInt
)
private
def
slavePortMatcher
:
SequenceMatcher
[
Int
]
=
new
SequenceMatcher
[
Int
](
"""AXI_SLAVE_PORTS\s+(\d+)"""
.
r
)(
true
,
ms
=>
ms
.
head
.
group
(
1
).
toInt
)
private
def
extract
(
pr
:
Path
)
:
Option
[
PortReport
]
=
try
{
val
numMasters
=
masterPortMatcher
val
numSlaves
=
slavePortMatcher
val
source
=
Source
.
fromFile
(
pr
.
toString
)
source
.
getLines
foreach
{
line
=>
numMasters
.
update
(
line
)
numSlaves
.
update
(
line
)
}
if
(
numMasters
.
matched
&&
numSlaves
.
matched
){
Some
(
PortReport
(
pr
,
numMasters
.
result
.
get
,
numSlaves
.
result
.
get
))
}
else
{
None
}
}
catch
{
case
e
:
Exception
=>
logger
.
warn
(
"Could not extract port information from %s: %s"
.
format
(
pr
,
e
))
None
}
}
src/main/scala/tapasco/reports/SynthesisReport.scala
View file @
b758d4fc
...
...
@@ -30,9 +30,11 @@ import java.nio.file.Path
final
case
class
SynthesisReport
(
override
val
file
:
Path
,
area
:
Option
[
AreaEstimate
],
timing
:
Option
[
TimingEstimate
])
extends
Report
(
file
)
{
timing
:
Option
[
TimingEstimate
],
masters
:
Option
[
Int
],
slaves
:
Option
[
Int
])
extends
Report
(
file
)
{
require
(
file
.
toFile
.
exists
,
"file %s does not exist"
.
format
(
file
.
toString
))
require
(
area
.
nonEmpty
||
timing
.
nonEmpty
,
"no synthesis results found in %s"
.
format
(
file
.
toString
))
require
(
area
.
nonEmpty
||
timing
.
nonEmpty
||
masters
.
nonEmpty
||
slaves
.
nonEmpty
,
"no synthesis results found in %s"
.
format
(
file
.
toString
))
}
object
SynthesisReport
{
...
...
@@ -50,8 +52,8 @@ object SynthesisReport {
val
ff
:
Integer
=
((
xml
\\
"AreaReport"
\\
e
\\
"FF"
)
text
).
toInt
val
dsp
:
Integer
=
((
xml
\\
"AreaReport"
\\
e
\\
"DSP"
)
text
).
toInt
val
bram
:
Integer
=
((
xml
\\
"AreaReport"
\\
e
\\
"BRAM"
)
text
).
toInt
new
ResourcesEstimate
(
slice
,
lut
,
ff
,
dsp
,
bram
)
}).
grouped
(
2
).
map
(
x
=>
new
AreaEstimate
(
x
.
head
,
x
.
tail
.
head
)).
toList
.
headOption
ResourcesEstimate
(
slice
,
lut
,
ff
,
dsp
,
bram
)
}).
grouped
(
2
).
map
(
x
=>
AreaEstimate
(
x
.
head
,
x
.
tail
.
head
)).
toList
.
headOption
}
catch
{
case
e
:
Exception
=>
logger
.
warn
(
"parsing utilization report failed: "
+
e
);
None
}
/** Extracts the timing estimation from the given synthesis report file.
...
...
@@ -64,9 +66,19 @@ object SynthesisReport {
((
xml
\\
"TimingReport"
\\
"TargetClockPeriod"
)
text
).
toDouble
))
}
catch
{
case
e
:
Exception
=>
logger
.
warn
(
"parsing timing report failed: "
+
e
);
None
}
def
extractMasterPorts
(
sr
:
Path
)
:
Option
[
Int
]
=
try
{
val
xml
=
scala
.
xml
.
XML
.
loadFile
(
sr
.
toAbsolutePath
.
toString
)
Some
(((
xml
\\
"PortReport"
\\
"NumMasters"
)
text
).
toInt
)
}
catch
{
case
e
:
Exception
=>
logger
.
warn
(
"parsing port report failed: %s"
.
format
(
e
));
None
}
def
extractSlavePorts
(
sr
:
Path
)
:
Option
[
Int
]
=
try
{
val
xml
=
scala
.
xml
.
XML
.
loadFile
(
sr
.
toAbsolutePath
.
toString
)
Some
(((
xml
\\
"PortReport"
\\
"NumSlaves"
)
text
).
toInt
)
}
catch
{
case
e
:
Exception
=>
logger
.
warn
(
"parsing port report failed: %s"
.
format
(
e
));
None
}
/** Produce SynthesisReport instance from file. **/
def
apply
(
sr
:
Path
)
:
Option
[
SynthesisReport
]
=
catchAllDefault
(
None
:
Option
[
SynthesisReport
],
"failed to read synthesis report %s: "
.
format
(
sr
.
toString
))
{
Some
(
SynthesisReport
(
sr
,
extractArea
(
sr
),
extractTiming
(
sr
)))
Some
(
SynthesisReport
(
sr
,
extractArea
(
sr
),
extractTiming
(
sr
)
,
extractMasterPorts
(
sr
),
extractSlavePorts
(
sr
)
))
}
}
src/main/scala/tapasco/util/AreaEstimate.scala
View file @
b758d4fc
...
...
@@ -90,3 +90,17 @@ final case class AreaEstimate(
def
isFeasible
:
Boolean
=
List
(
slice
,
lut
,
ff
,
dsp
,
bram
).
map
(
x
=>
x
<=
100.0
).
reduce
(
_
&&
_
)
def
compare
(
that
:
AreaEstimate
)
:
Int
=
this
.
resources
compare
that
.
resources
}
/**
* Occupation of slots of a hardware design
* @param slots Number of occupied slots
* @param available Number of available slots
*/
final
case
class
SlotOccupation
(
slots
:
Int
,
available
:
Int
)
extends
Ordered
[
SlotOccupation
]
{
override
def
toString
:
String
=
"SlotOccupation: %d/%d\n"
.
format
(
slots
,
available
)
def
*
(
n
:
Int
)
:
SlotOccupation
=
SlotOccupation
(
slots
*
n
,
available
)
def
+
(
s
:
SlotOccupation
)
:
SlotOccupation
=
SlotOccupation
(
slots
+
s
.
slots
,
available
)
def
isFeasible
:
Boolean
=
slots
<=
available
override
def
compare
(
that
:
SlotOccupation
)
:
Int
=
this
.
slots
compare
that
.
slots
}
src/test/scala/tapasco/reports/PortReportSpec.scala
0 → 100644
View file @
b758d4fc
package
de.tu_darmstadt.cs.esa.tapasco.reports
import
java.nio.file.Paths
import
org.scalatest.
{
FlatSpec
,
Matchers
}
class
PortReportSpec
extends
FlatSpec
with
Matchers
{
val
reportPath
=
Paths
.
get
(
"report-examples"
).
toAbsolutePath
"A missing PortReport file"
should
"result in None"
in
{
PortReport
(
reportPath
.
resolve
(
"missing.rpt"
))
shouldBe
empty
}
"An invalid PortReport file"
should
"result in None"
in
{
PortReport
(
reportPath
.
resolve
(
"correct-timing.rpt"
))
shouldBe
empty
}
"A correct PortReport file"
should
"be parsed to Some(PortReport)"
in
{
PortReport
(
reportPath
.
resolve
(
"correct-port.rpt"
))
should
not
be
empty
}
"A correct PortReport file"
should
"be parsed correctly"
in
{
val
pr
=
PortReport
(
reportPath
.
resolve
(
"correct-port.rpt"
))
pr
should
not
be
empty
pr
.
get
.
numMasters
shouldBe
42
pr
.
get
.
numSlaves
shouldBe
25
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment