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

Added Experiment type

This can replace the PapiRunner family of classes.
It just gathers all your features nicely, in a lost less code!

Added some tests too!
parent 97eaf508
package se.lth.cs.util
class Experiment {
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.papicounters.EventSetBuilder
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.papicounters.PapiBenchmarkAnalyzer
import se.lth.cs.papicounters.PapiTracerRunner
import se.lth.cs.timing.OperationTypeTable
class Experiment(val numberIterations : Int,
val benchmark : BCBenchmarkPackage<*>,
val features : FeatureSet) : FeatureVisitor {
fun run(availableCounters : List<PAPICounter>) : List<Map<Feature, Double>> {
if (features.features.isEmpty()) { return listOf() }
val eventSetBuilder = EventSetBuilder(availableCounters)
eventSetBuilder.visitFeatureSet(features)
val counters = eventSetBuilder.getCounterSet()
val papiRunner = PapiTracerRunner(numberIterations, counters.toList())
val evSet = eventSetBuilder.getEventSet()
val iterations = papiRunner.runIterations(
PapiBenchmarkAnalyzer.RunSpec(numberIterations, counters.toList(), evSet, benchmark)
)
var results = mutableListOf<Map<Feature, Double>>()
for (i in iterations) {
currentIteration = i
currentIterationResults = mutableMapOf()
// We aggregate all our features for that
// specific iteration!
features.accept(this)
results.add(currentIterationResults.toMap())
}
return results.toList()
}
var currentIteration : List<PapiTracerRunner.TraceRecord> = listOf()
var currentIterationResults : MutableMap<Feature, Double> = mutableMapOf()
override fun visitPAPICounter(c: PAPICounter) {
val values = currentIteration.filter { it.featureName == c.toHexa() }
.map { it.featureValue }
currentIterationResults[c] = values.sum().toDouble()
}
override fun visitConstant(constantFeature: ConstantFeature) {
currentIterationResults[constantFeature] = constantFeature.value
}
override fun visitCost(costFeature: CostFeature) {
costFeature.counter.accept(this)
val sum = currentIteration.filter {
val methodType = OperationTypeTable.getType(it.method)
val rightMethodType = methodType.map { opType ->
opType == costFeature.opType
}.orElse(false)
val rightCounter = it.featureName == costFeature.counter.toHexa()
rightMethodType && rightCounter
}.sumBy { it.featureValue }
currentIterationResults[costFeature] = sum.toDouble()
}
override fun visitRatio(featureRatio: FeatureRatio) {
featureRatio.f1.accept(this)
featureRatio.f2.accept(this)
val f1Value = currentIterationResults[featureRatio.f1]!!
val f2Value = currentIterationResults[featureRatio.f2]!!
currentIterationResults[featureRatio] = f1Value / f2Value
}
override fun visitFeatureSet(featureSet: FeatureSet) {
for (f in featureSet.features) {
f.accept(this)
}
}
override fun visitMethodInvocations(methodInvocations: MethodInvocations) {
val invokes = benchmark.methodHistogram()[methodInvocations.method]!!
currentIterationResults[methodInvocations] = invokes.toDouble()
}
override fun visitTotalMethodInvocations(totalMethodInvocations: TotalMethodInvocations) {
currentIterationResults[totalMethodInvocations] = benchmark.traceSize.toDouble()
}
}
\ No newline at end of file
......@@ -46,7 +46,7 @@ abstract class Feature {
* Constant features are usually machine-specific,
* like cache block size!
*/
class ConstantFeature(val name : String, val value : Int) : Feature() {
class ConstantFeature(val name : String, val value : Double) : Feature() {
override fun featureType(): Type {
// HAHA, this depends!
TODO("Not yet implemented")
......@@ -66,7 +66,7 @@ class ConstantFeature(val name : String, val value : Int) : Feature() {
/** This is a feature where we measure the number of cycles
* for some class of operations on the collection
*/
class CostFeature(val opType : OperationType) : Feature() {
class CostFeature(val opType : OperationType, val counter : PAPICounter) : Feature() {
override fun featureType(): Type {
return Type.HARDWARE
}
......@@ -157,6 +157,7 @@ class FeatureSet(val features : List<Feature>) {
}
fun brainyFeatures() : FeatureSet {
val totCycles = PAPICounter("PAPI_TOT_CYC")
return FeatureSet(
se.lth.cs.listOf(PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_L1_DCM"),
......@@ -165,17 +166,17 @@ fun brainyFeatures() : FeatureSet {
PAPICounter("PAPI_L1_DCA")
),
FeatureRatio(
ConstantFeature("Data Size", Integer.BYTES),
ConstantFeature("Data Size", Integer.BYTES.toDouble()),
// Type "getconf -a | grep "CACHE" to find this.
// TODO: Make this automatic
ConstantFeature("Cache Block Size", 64)
ConstantFeature("Cache Block Size", 64.0)
),
FeatureRatio(
PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_BR_CN")
),
CostFeature(OperationType.SEARCH),
CostFeature(OperationType.ITERATE),
CostFeature(OperationType.INSERT),
CostFeature(OperationType.DELETE)))
CostFeature(OperationType.SEARCH, totCycles),
CostFeature(OperationType.ITERATE, totCycles),
CostFeature(OperationType.INSERT, totCycles),
CostFeature(OperationType.DELETE, totCycles)))
}
......@@ -45,7 +45,7 @@ class EventSetBuilderTest {
@Test
fun testEventBuilderCost() {
val features = listOf(
CostFeature(OperationType.INSERT),
CostFeature(OperationType.INSERT, PAPICounter("PAPI_TOT_CYC")),
PAPICounter("PAPI_L1_DCM")
)
......@@ -72,8 +72,8 @@ class EventSetBuilderTest {
PAPICounter("PAPI_L2_DCA")
),
FeatureRatio(
CostFeature(OperationType.INSERT),
CostFeature(OperationType.DELETE)
CostFeature(OperationType.INSERT, PAPICounter("PAPI_TOT_CYC")),
CostFeature(OperationType.DELETE, PAPICounter("PAPI_TOT_CYC"))
)
)
......
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.timing.OperationType
import se.lth.cs.util.*
class ExperimentTest {
@Test
fun testExperimentNoFeatures() {
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val exp = Experiment(10, bench, FeatureSet(listOf()))
val results = exp.run(listOf())
Assertions.assertTrue(results.isEmpty())
}
@Test
fun testExperiment1() {
val available = listOf(PAPICounter("PAPI_TOT_CYC"),
PAPICounter("PAPI_TOT_INS")
)
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val exp = Experiment(10, bench,
FeatureSet(
listOf(PAPICounter("PAPI_TOT_CYC"))
)
)
val results = exp.run(available)
Assertions.assertEquals(10, results.size)
Assertions.assertEquals(setOf(PAPICounter("PAPI_TOT_CYC")),
results.flatMap{ it.keys }.toSet())
}
@Test
fun testExperiment2() {
// This time, with more complicated features
val available = listOf(
PAPICounter("PAPI_L2_DCM"),
PAPICounter("PAPI_L2_DCA"),
PAPICounter("PAPI_TOT_CYC"),
PAPICounter("PAPI_TOT_INS")
)
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val cacheMissRate = FeatureRatio(
PAPICounter("PAPI_L2_DCM"),
PAPICounter("PAPI_L2_DCA")
)
val costPerDelete = CostFeature(
OperationType.DELETE,
PAPICounter("PAPI_TOT_CYC"))
val exp = Experiment(10, bench,
FeatureSet(
listOf(
PAPICounter("PAPI_TOT_INS"),
costPerDelete,
cacheMissRate
)
)
)
val results = exp.run(available)
for (iteration in results) {
Assertions.assertTrue(iteration.containsKey(PAPICounter("PAPI_TOT_INS")))
Assertions.assertTrue(iteration.containsKey(costPerDelete))
Assertions.assertTrue(iteration.containsKey(costPerDelete.counter))
Assertions.assertTrue(iteration.containsKey(cacheMissRate))
Assertions.assertTrue(iteration.containsKey(cacheMissRate.f1))
Assertions.assertTrue(iteration.containsKey(cacheMissRate.f2))
}
}
@Disabled("PAPI_L1_DCA was not available on my machine, so it wouldn't work")
@Test
fun testExperimentBrainyFeatures() {
val available = listOf(
PAPICounter("PAPI_L1_DCM"),
PAPICounter("PAPI_L1_DCA"),
PAPICounter("PAPI_BR_CN"),
PAPICounter("PAPI_L2_DCM"),
PAPICounter("PAPI_BR_MSP"),
PAPICounter("PAPI_L2_DCA"),
PAPICounter("PAPI_TOT_CYC"),
PAPICounter("PAPI_TOT_INS")
)
val bench = BCBenchmarkPackage.LIST(1234, 100, 0, ArrayList<Int>())
val exp = Experiment(10, bench, brainyFeatures())
val results = exp.run(available)
Assertions.assertEquals(listOf<Map<Feature, Double>>(), results)
}
}
\ No newline at end of file
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