Commit beae7432 authored by Noric Couderc's avatar Noric Couderc
Browse files

Merge branch 'master' of git.cs.lth.se:noricc/jbrainy

parents f54e0301 a2619d25
......@@ -12,6 +12,7 @@ import se.lth.cs.papicounters.MockupPapiTracerRunner
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.papicounters.PapiTracerRunner
import se.lth.cs.util.brainyFeatures
import se.lth.cs.util.normalize
import java.io.File
import java.io.FileReader
import java.io.FileWriter
......@@ -87,7 +88,7 @@ class PapiCommandLine : CliktCommand() {
PapiTracerRunner()
}
val features = brainyFeatures()
val features = if (normalizeFeatures) { normalize(brainyFeatures()).checked() } else { brainyFeatures().checked() }
SyntheticBenchmarkExperimentPrinter(writer,
methodOutputFormat,
numberRuns, features,
......
......@@ -14,9 +14,12 @@ class EventSetBuilder : FeatureVisitor {
override fun visitPAPICounter(c: PAPICounter) {
// If the counter is de-activated we skip it
if (c.isActive) {
counterSet.add(c)
if (!c.isSupported()) {
val msg = "Creating eventSet for single counter $c failed: is it available on this machine?"
throw RuntimeException(msg)
}
counterSet.add(c)
}
override fun visitConstant(constantFeature: ConstantFeature) {
......@@ -43,7 +46,7 @@ class EventSetBuilder : FeatureVisitor {
private var eventSet : EventSet? = null
override fun visitFeatureSet(featureSet: FeatureSet) {
for (f in featureSet.features) {
for (f in featureSet) {
f.accept(this)
}
......
......@@ -9,17 +9,11 @@ import se.lth.cs.util.FeatureVisitor
import java.lang.RuntimeException
class PAPICounter(val counter : String) : Feature() {
init {
check()
}
fun isValid(): Boolean {
return CounterSpecification.allCounters.contains(counter)
}
var isActive : Boolean = false
fun check() {
override fun isSupported(): Boolean {
Papi.init()
try {
val eventSet = EventSet.create(this.toPAPIConstant()!!)
......@@ -31,12 +25,9 @@ class PAPICounter(val counter : String) : Feature() {
// }
// eventSet.stop()
// eventSet.destroy()
isActive = true
return true
} catch (e : PapiException) {
val msg = "Creating eventSet for single counter $counter failed: is it available on this machine? Deactivating..."
System.err.println("[WARNING]: $msg")
isActive = false
return false
}
}
......
......@@ -12,9 +12,19 @@ class Experiment(val numberIterations : Int,
val features : FeatureSet,
val papiRunner : PapiTracerRunner) : FeatureVisitor {
data class Result(val iterationNumber : Int,
val benchmark : BCBenchmarkPackage<*>,
val values : Map<Feature, Double>)
inner class Result(val iterationNumber : Int,
val benchmark : BCBenchmarkPackage<*>,
val values : Map<Feature, Double>) {
/**
* Returns only the features we specified in the feature set
* If feature F1 requires F2, but F2 is not explicitly requested
* we omit it.
*/
fun strict() : Result {
return Result(iterationNumber, benchmark,
values.filterKeys { it in features } )
}
}
fun getIterations(): List<List<PapiTracerRunner.TraceRecord>> {
val eventSetBuilder = EventSetBuilder()
......@@ -33,7 +43,7 @@ class Experiment(val numberIterations : Int,
}
fun run() : List<Result> {
if (features.features.isEmpty()) { return listOf() }
if (features.isEmpty()) { return listOf() }
val iterations = getIterations()
......@@ -46,6 +56,7 @@ class Experiment(val numberIterations : Int,
// specific iteration!
features.accept(this)
val values = currentIterationResults.toMap()
results.add(Result(iterationNumber, benchmark, values))
iterationNumber++
}
......@@ -58,9 +69,6 @@ class Experiment(val numberIterations : Int,
var currentIterationResults : MutableMap<Feature, Double> = mutableMapOf()
override fun visitPAPICounter(c: PAPICounter) {
if (!c.isActive) {
return
}
if (currentIterationResults.containsKey(c)) {
return
}
......@@ -105,7 +113,7 @@ class Experiment(val numberIterations : Int,
}
override fun visitFeatureSet(featureSet: FeatureSet) {
for (f in featureSet.features) {
for (f in featureSet) {
f.accept(this)
}
}
......
......@@ -42,6 +42,10 @@ abstract class Feature {
abstract fun featureType() : Feature.Type
abstract fun accept(visitor : FeatureVisitor)
open fun isSupported() : Boolean {
return true
}
}
/**
......@@ -96,7 +100,7 @@ class CostFeature(val opType : OperationType) : Feature() {
}
}
class FeatureRatio(val f1 : Feature, val f2 : Feature) : Feature() {
open class FeatureRatio(val f1 : Feature, val f2 : Feature) : Feature() {
override fun featureType(): Type {
return Type.RATIO
}
......@@ -108,6 +112,10 @@ class FeatureRatio(val f1 : Feature, val f2 : Feature) : Feature() {
override fun toString(): String {
return "%s / %s".format(f1.toString(), f2.toString())
}
override fun isSupported(): Boolean {
return f1.isSupported() && f2.isSupported()
}
}
class MethodInvocations(val method : String, val methodPrintFormat : String) : Feature() {
......@@ -151,25 +159,32 @@ class TotalMethodInvocations() : Feature() {
}
/**
* This is how we normalize some features,
* by taking the ratio with some others:
* example: Normalize PAPI_L1_DCM by PAPI_TOT_CYC
* is just dividing
* Normalized features are features, except you divide them
* by a normalization features.
*
* They are, not printed the same way as feature ratios, though.
*/
fun normalize(f : Feature, n : Feature): Feature {
return FeatureRatio(f, n)
class NormalizedFeature(f : Feature, n : Feature) : FeatureRatio(f, n) {
override fun featureType(): Type {
return f1.featureType()
}
override fun toString(): String {
return "$f1 (normalized by $f2)"
}
}
fun defaultNormalize(f : Feature) : Feature? {
fun defaultNormalize(f : Feature) : Feature {
if (f.featureType() == Feature.Type.SOFTWARE) {
return normalize(f, TotalMethodInvocations())
return NormalizedFeature(f, TotalMethodInvocations())
}
if (f.featureType() == Feature.Type.HARDWARE) {
return normalize(f, PAPICounter("PAPI_TOT_CYC"))
return NormalizedFeature(f, PAPICounter("PAPI_TOT_CYC"))
}
return null
// When we don't know, we just return the feature as-is.
return f
}
/**
......@@ -178,26 +193,72 @@ fun defaultNormalize(f : Feature) : Feature? {
* (For example: Create ONE papi event set for the
* whole of the features)
*/
class FeatureSet(val features : List<Feature>) {
class FeatureSet(vararg features : Feature) : ArrayList<Feature>() {
init {
for (f in features) {
this.add(f)
}
}
/**
* Returns a subset of features which should be supported by the current machine!
*/
fun checked() : FeatureSet {
val featuresChecked = this.partition { it.isSupported() }
System.err.println("[WARNING]: Some features have been dropped, they are not supported on this machine: ${featuresChecked.second}")
return FeatureSet(*featuresChecked.first.toTypedArray())
}
fun accept(visitor : FeatureVisitor) {
visitor.visitFeatureSet(this)
}
}
/**
* We normalize a featureSet by applying normalization on all the features!
*/
// TODO: This could be a method
fun normalize(featureSet : FeatureSet): FeatureSet {
val features = featureSet.map { defaultNormalize(it) }.toTypedArray()
return FeatureSet(*features)
}
fun cacheLineSizeFeature(): HardwareConstantFeature? {
val processBuilder = ProcessBuilder()
processBuilder.command("getconf", "LEVEL1_DCACHE_LINESIZE")
val process = processBuilder.start()
val input = process.inputStream
val lines = input.bufferedReader().lines()
// "orElse(null)" :C
val cacheSize : HardwareConstantFeature? = lines.findFirst().map { Integer.parseInt(it) }
.map { HardwareConstantFeature("Cache Block Size", it.toDouble()) }.orElse(null)
return cacheSize
}
fun brainyFeatures() : FeatureSet {
// We need to get the cache block size on this machine
val dataSizeFeature = SoftwareConstantFeature("Data Size", Integer.BYTES.toDouble())
val cacheSize = cacheLineSizeFeature()
val sizesRatioFeature = if (cacheSize == null) { dataSizeFeature }
else {
FeatureRatio(
dataSizeFeature,
cacheSize
)
}
return FeatureSet(
se.lth.cs.listOf(PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_L1_DCM"),
FeatureRatio(
PAPICounter("PAPI_L1_DCM"),
PAPICounter("PAPI_L1_DCA")
),
FeatureRatio(
SoftwareConstantFeature("Data Size", Integer.BYTES.toDouble()),
// Type "getconf -a | grep "CACHE" to find this.
// TODO: Make this automatic
HardwareConstantFeature("Cache Block Size", 64.0)
),
sizesRatioFeature,
FeatureRatio(
PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_BR_CN")
......@@ -205,5 +266,5 @@ fun brainyFeatures() : FeatureSet {
CostFeature(OperationType.SEARCH),
CostFeature(OperationType.ITERATE),
CostFeature(OperationType.INSERT),
CostFeature(OperationType.DELETE)))
CostFeature(OperationType.DELETE))
}
......@@ -35,7 +35,7 @@ class EventSetBuilderTest {
PAPICounter("PAPI_L1_DCM")
)
val spec = FeatureSet(counters)
val spec = FeatureSet(*counters.toTypedArray())
val builder = EventSetBuilder()
spec.accept(builder)
......@@ -48,9 +48,9 @@ class EventSetBuilderTest {
val features = listOf(
CostFeature(OperationType.INSERT),
PAPICounter("PAPI_L1_DCM")
)
).toTypedArray()
val spec = FeatureSet(features)
val spec = FeatureSet(*features)
val builder = EventSetBuilder()
spec.accept(builder)
......@@ -76,9 +76,9 @@ class EventSetBuilderTest {
CostFeature(OperationType.INSERT),
CostFeature(OperationType.DELETE)
)
)
).toTypedArray()
val spec = FeatureSet(features)
val spec = FeatureSet(*features)
val builder = EventSetBuilder()
spec.accept(builder)
......@@ -97,13 +97,12 @@ class EventSetBuilderTest {
fun testEventBuildInvalidEvents() {
val features = listOf(
PAPICounter("PAPI_L1_DCM"),
PAPICounter("PAPI_L1_DCA"))
PAPICounter("PAPI_L1_DCA")).toTypedArray()
val spec = FeatureSet(features)
val spec = FeatureSet(*features)
// Oh no! empty list of PAPI events!
val builder = EventSetBuilder()
spec.accept(builder)
// Assertions.assertThrows(RuntimeException::class.java, { spec.accept(builder) })
Assertions.assertThrows(RuntimeException::class.java) { spec.accept(builder) }
}
}
\ No newline at end of file
......@@ -16,7 +16,7 @@ class ExperimentTest {
fun testExperimentNoFeatures() {
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val exp = Experiment(10, bench, FeatureSet(listOf()), runner)
val exp = Experiment(10, bench, FeatureSet(), runner)
val results = exp.run()
Assertions.assertTrue(results.isEmpty())
......@@ -26,9 +26,7 @@ class ExperimentTest {
fun testExperiment1() {
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val exp = Experiment(10, bench,
FeatureSet(
listOf(PAPICounter("PAPI_TOT_CYC"))
),
FeatureSet(PAPICounter("PAPI_TOT_CYC")),
runner
)
......@@ -59,11 +57,9 @@ class ExperimentTest {
val exp = Experiment(10, bench,
FeatureSet(
listOf(
PAPICounter("PAPI_TOT_INS"),
costPerDelete,
cacheMissRate
)
PAPICounter("PAPI_TOT_INS"),
costPerDelete,
cacheMissRate
),
runner
)
......@@ -84,15 +80,38 @@ class ExperimentTest {
fun testExperimentBrainyFeatures() {
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val features = brainyFeatures()
val features = brainyFeatures().checked()
val exp = Experiment(10, bench, features,runner)
val results = exp.run()
for (iteration in results) {
Assertions.assertEquals(bench, iteration.benchmark)
Assertions.assertTrue(iteration.values.values.all { it > 0 })
}
}
@Test
fun cacheSizeFeatures() {
val f = cacheLineSizeFeature()
Assertions.assertFalse(f == null)
}
@Test
fun testNormalizationBrainyFeatures() {
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val features = normalize(brainyFeatures()).checked()
val exp = Experiment(10, bench, features,runner)
val results = exp.run()
for (iteration in results) {
Assertions.assertEquals(bench, iteration.benchmark)
Assertions.assertTrue(features.containsAll(iteration.strict().values.keys))
Assertions.assertTrue(iteration.values.values.all { it > 0 })
Assertions.assertTrue(iteration.strict().values.values.all { it <= 1.0 })
}
}
}
\ No newline at end of file
......@@ -20,10 +20,8 @@ class SyntheticBenchmarkExperimentPrinterTest {
fun testNoBenchmarks() {
val writer = StringWriter()
val features = FeatureSet(
listOf(
PAPICounter("PAPI_TOT_CYC"),
MethodInvocations("java.util.List.add", "JAVA-STANDARD-FORMAT")
)
PAPICounter("PAPI_TOT_CYC"),
MethodInvocations("java.util.List.add", "JAVA-STANDARD-FORMAT")
)
val printer = SyntheticBenchmarkExperimentPrinter(writer,
"",
......@@ -41,11 +39,9 @@ class SyntheticBenchmarkExperimentPrinterTest {
fun testListBenchmarks() {
val writer = StringWriter()
val features = FeatureSet(
listOf(
PAPICounter("PAPI_TOT_CYC"),
CostFeature(OperationType.INSERT),
MethodInvocations("runAdd", "JAVA-STANDARD-FORMAT")
)
PAPICounter("PAPI_TOT_CYC"),
CostFeature(OperationType.INSERT),
MethodInvocations("runAdd", "JAVA-STANDARD-FORMAT")
)
val printer = SyntheticBenchmarkExperimentPrinter(writer,
"",
......
Supports Markdown
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