Commit 3bb3560a authored by Noric Couderc's avatar Noric Couderc
Browse files

Refactoring: Use PAPICounter type instead of strings

We use the PAPICounter type for specifying list of counters and stuff,
instead of the map of strings. This makes the code _MUCH BETTER_.
parent 4640a21f
......@@ -25,6 +25,7 @@ class CounterSpecification(strings : List<String>) {
/**
* All the hardware performance counters
*/
val allCounters =
sortedMapOf(
"PAPI_L1_DCM" to Constants.PAPI_L1_DCM,
......
......@@ -8,6 +8,7 @@ import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parameters.types.int
import se.lth.cs.*
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.papicounters.PapiTracerRunner
import se.lth.cs.timing.StopWatchRunner
import java.io.File
......@@ -80,9 +81,14 @@ class PapiCommandLine : CliktCommand() {
"SOFTWARE-COUNTERS" -> SyntheticBenchmarkHistPrinter(writer, methodOutputFormat)
"FEATURE-VECTORS" -> {
val runner = if (debugMode) {
MockupPapiRunner(numberRuns, CounterSpecification.fromFile(countersFile))
MockupPapiRunner(numberRuns,
listOf(PAPICounter("PAPI_TOT_CYC"),
PAPICounter("PAPI_TOT_INS")
))
} else {
PapiTracerRunner(numberRuns, CounterSpecification.fromFile(countersFile))}
val spec = CounterSpecification.fromFile(countersFile)
val counters = spec.currentSpec.keys.map { PAPICounter(it) }
PapiTracerRunner(numberRuns, counters)}
SyntheticBenchmarkFeaturePrinter(writer, runner,
methodOutputFormat, normalizeFeatures)
......
......@@ -16,7 +16,19 @@ class PAPICounter(val counter : String) : Feature {
return "UNKNOWN"
}
fun toConstant(): Int? {
fun isSpecial(): Boolean {
return counter in listOf("PAPI_TOT_CYC", "PAPI_TOT_INS")
}
fun toPAPIConstant(): Int? {
return CounterSpecification.allCounters.get(counter)
}
fun toHexa() : String {
return String.format("0x%x", this.toPAPIConstant())
}
override fun equals(other: Any?): Boolean {
return other is PAPICounter && other.counter == counter
}
}
\ No newline at end of file
......@@ -6,37 +6,29 @@ import se.lth.cs.timing.OperationType
interface PapiBenchmarkAnalyzer {
class RunSpec(val numRuns: Int,
val counters : List<String>,
val counters : List<PAPICounter>,
val eventSet: EventSet,
val syntheticBenchmark: BCBenchmarkPackage<*>) {
fun specialCounters(): List<String> {
return listOf<String>("PAPI_TOT_CYC", "PAPI_TOT_INS")
}
private fun isSpecial(counter : String) : Boolean {
return specialCounters().contains(counter)
}
/**
Tells you if a RunSpec can be sampled in one single pass
for that, the counters have to be 2 counters + (optionally) PAPI_TOT_CYC and PAPI_TOT_INS
*/
fun canBeSampled(): Boolean {
return counters.filter { ! this.isSpecial(it) }.size <= 2
return counters.filter { ! it.isSpecial() }.size <= 2
}
}
data class BenchmarkRunSample(val counter : String, var value : Double)
data class BenchmarkRunSample(val counter : PAPICounter, var value : Double)
class BenchmarkRunData(val benchmark : BCBenchmarkPackage<*>,
val iteration : Int,
val samples : List<BenchmarkRunSample>,
val cyclesPerOpType : Map<OperationType, Double>) {
fun normalizationCounter(): String {
return "PAPI_TOT_CYC"
fun normalizationCounter(): PAPICounter {
return PAPICounter("PAPI_TOT_CYC")
}
fun normalized(): BenchmarkRunData {
......
......@@ -4,31 +4,30 @@ import org.openjdk.jmh.infra.Blackhole
import papi.EventSet
import papi.Papi
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.papicounters.PapiBenchmarkAnalyzer
import se.lth.cs.timing.OperationType
import java.io.FileWriter
open class PapiRunner(val numRuns: Int, counters: CounterSpecification) : PapiBenchmarkAnalyzer {
open class PapiRunner(val numRuns: Int, val counters: List<PAPICounter>) : PapiBenchmarkAnalyzer {
init {
Papi.init()
}
val counterSpec = counters
protected var blackhole = Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.")
/**
* Empty benchmark:
* Test to see if the results are stable.
*/
fun emptyBenchmark(): MutableMap<String, List<Long>> {
fun emptyBenchmark(): Map<PAPICounter, List<Long>> {
// For each counter,
// we store the values for each run (10 runs)
var data: MutableMap<String, List<Long>> = mutableMapOf()
var data: MutableMap<PAPICounter, List<Long>> = mutableMapOf()
for (kvp in counterSpec.currentSpec) {
val evset = EventSet.create(kvp.value)
for (counter in counters) {
val evset = EventSet.create(counter.toPAPIConstant()!!)
val current: MutableList<Long> = mutableListOf()
......@@ -50,9 +49,9 @@ open class PapiRunner(val numRuns: Int, counters: CounterSpecification) : PapiBe
val currentData = evset.counters
current.addAll(currentData.toList())
}
data.set(kvp.key, current)
data.set(counter, current)
}
return data
return data.toMap()
}
/**
......@@ -62,11 +61,10 @@ open class PapiRunner(val numRuns: Int, counters: CounterSpecification) : PapiBe
// Let's say we want to minimize the counter change
// We put it in the outer loop
val specification = mutableListOf<PapiBenchmarkAnalyzer.RunSpec>()
val counterNames = counterSpec.getCounterNames()
val counterValues = counterSpec.getCounterValues()
val counterValues = counters.map { it.toPAPIConstant()!! }
val eventSet = EventSet.create(*counterValues.toIntArray())
for (b in syntheticBenchmarks) {
specification.add(PapiBenchmarkAnalyzer.RunSpec(numRuns, counterNames, eventSet, b))
specification.add(PapiBenchmarkAnalyzer.RunSpec(numRuns, counters, eventSet, b))
}
return specification.toList()
}
......@@ -111,16 +109,15 @@ open class PapiRunner(val numRuns: Int, counters: CounterSpecification) : PapiBe
* Present in the counter specification we have.
*/
@Deprecated("Used only in tests??")
fun runApplication(app: BCBenchmarkPackage<*>) : Map<String, List<Long>> {
fun runApplication(app: BCBenchmarkPackage<*>) : Map<PAPICounter, List<Long>> {
// We will write the aggregators to nowhere
val writer = FileWriter("/dev/null")
// We get integers for all the counters.
val counters = counterSpec.currentSpec
var result = mutableMapOf<String, List<Long>>()
for (counter in counters.keys) {
val counterId = counterSpec.getCounter(counter)
val evset = EventSet.create(counterId!!)
var result = mutableMapOf<PAPICounter, List<Long>>()
for (counter in counters) {
val counterId = counter.toPAPIConstant()!!
val evset = EventSet.create(counterId)
val samples = mutableListOf<Long>()
for (run in 0 until numRuns) {
// We do the measurements
......@@ -196,7 +193,7 @@ open class PapiRunner(val numRuns: Int, counters: CounterSpecification) : PapiBe
/**
* A mockup class which returns deterministic results when you "run" a spec.
*/
class MockupPapiRunner(numRuns : Int, counters : CounterSpecification) : PapiRunner(numRuns, counters) {
class MockupPapiRunner(numRuns : Int, counters : List<PAPICounter>) : PapiRunner(numRuns, counters) {
override fun runSpec(spec : PapiBenchmarkAnalyzer.RunSpec) : List<PapiBenchmarkAnalyzer.BenchmarkRunData> {
// We map the counters to integers
// val counterToInt = mapOf<String, Long>(
......
......@@ -23,7 +23,7 @@ import java.lang.RuntimeException
* The tracing collections allow to get more information (breakdown of the features per each method
* instead of each run)
*/
class PapiTracerRunner(numRuns : Int, counters : CounterSpecification) : PapiRunner(numRuns, counters) {
class PapiTracerRunner(numRuns : Int, counters : List<PAPICounter>) : PapiRunner(numRuns, counters) {
private fun createTracerCollection(bench: BCBenchmarkPackage<*>): Any? {
// Sometimes we used a tracer collection, we want to replace it anyway.
......@@ -99,8 +99,8 @@ class PapiTracerRunner(numRuns : Int, counters : CounterSpecification) : PapiRun
fun runIterations(spec : PapiBenchmarkAnalyzer.RunSpec) : List<List<TraceRecord>> {
val counters = spec.counters
.filter { ! spec.specialCounters().contains(it) } // These are active by default.
.map { counterSpec.getCounter(it)!! }
.filter { ! it.isSpecial() } // These are active by default.
.map { it.toPAPIConstant()!! }
when (counters.size) {
1 -> Tracer.setCounters(counters.first())
......@@ -148,7 +148,7 @@ class PapiTracerRunner(numRuns : Int, counters : CounterSpecification) : PapiRun
val g = analyzeOutput(it)
// Get features present in this iteration.
val counterSamples = spec.counters.map { counter ->
val featureNumber = String.format("0x%x", counterSpec.getCounter(counter))
val featureNumber = counter.toHexa()
val allocationSites = g.predecessors(featureNumber)
// There should be only one when we run the benchmarks
......@@ -180,7 +180,7 @@ class PapiTracerRunner(numRuns : Int, counters : CounterSpecification) : PapiRun
val siteToCycles = mutableMapOf<OperationType, Int>()
val featureNumber = String.format("0x%x", counterSpec.getCounter("PAPI_TOT_CYC"))
val featureNumber = PAPICounter("PAPI_TOT_CYC").toHexa()
// We need to total number of cycles for each alloc site / operation type
for (record in iteration) {
......
......@@ -10,6 +10,7 @@ import se.lth.cs.CounterSpecification;
import se.lth.cs.PapiRunner;
import se.lth.cs.bcgen.*;
import se.lth.cs.SyntheticBenchmarkGeneration.*;
import se.lth.cs.papicounters.PAPICounter;
import se.lth.cs.papicounters.PapiBenchmarkAnalyzer;
import java.io.File;
......@@ -30,7 +31,9 @@ public class PapiRunnerTest {
public void setup() {
File papiAvailableCounters = new File("../papi_avail");
Assertions.assertTrue(papiAvailableCounters.exists());
runner = new PapiRunner(10, new CounterSpecification(listOf("PAPI_L1_DCM", "PAPI_TOT_CYC", "PAPI_BR_MSP")));
runner = new PapiRunner(10, listOf(new PAPICounter("PAPI_L1_DCM"),
new PAPICounter("PAPI_TOT_CYC"),
new PAPICounter("PAPI_BR_MSP")));
}
/**
* Tests that all performance counters can be put in an eventSet
......@@ -76,7 +79,10 @@ public class PapiRunnerTest {
100
);
List<String> counters = listOf("PAPI_BR_MSP", "PAPI_L1_DCM", "PAPI_TOT_CYC");
List<PAPICounter> counters = listOf(
new PAPICounter("PAPI_BR_MSP"),
new PAPICounter("PAPI_L1_DCM"),
new PAPICounter("PAPI_TOT_CYC"));
List<PapiRunner.BenchmarkRunData> data = runner.runApplications(syntheticBenchmarks);
......@@ -98,10 +104,10 @@ public class PapiRunnerTest {
public void testPapiRunBenchmark() throws PapiException {
BCBenchmarkPackage<Map<Object, Object>> bench = BCBenchmarkPackage.MAP(0, 100, 0, new HashMap());
Map<String, List<Long>> results = runner.runApplication(bench);
Map<PAPICounter, List<Long>> results = runner.runApplication(bench);
Assertions.assertFalse(results.isEmpty());
for (String k : results.keySet()) {
Assertions.assertFalse(results.get(k).isEmpty());
for (PAPICounter c : results.keySet()) {
Assertions.assertFalse(results.get(c).isEmpty());
}
}
......@@ -163,7 +169,7 @@ public class PapiRunnerTest {
for (PapiBenchmarkAnalyzer.RunSpec r : specs) {
Assertions.assertEquals(
runner.getCounterSpec().getCounterNames(),
runner.getCounters(),
r.getCounters()
);
......
......@@ -10,6 +10,7 @@ import se.lth.cs.SyntheticBenchmarkFeaturePrinter
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.bcgen.MethodSelectionStrategyLoader
import se.lth.cs.bcgen.MethodSelectionType
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.timing.MockupStopWatchRunner
import java.io.StringReader
import java.io.StringWriter
......@@ -17,20 +18,16 @@ import java.lang.Float.parseFloat
import java.nio.file.Paths
class SyntheticBenchmarkFeaturePrinterTest {
val specString = """
PAPI_L1_DCM
PAPI_L2_DCM
PAPI_TOT_CYC
PAPI_TOT_INS
""".trimIndent()
val specReader = StringReader(specString)
val counterSpec = CounterSpecification.fromReader(specReader)
val counters = listOf(
"PAPI_L1_DCM",
"PAPI_L2_DCM",
"PAPI_TOT_CYC",
"PAPI_TOT_INS").map { PAPICounter(it) }
val methodOutputFormat = "JAVA-STANDARD-FORMAT"
val normalizeFeatures = false
val papiRunner = MockupPapiRunner( 3, counterSpec)
val papiRunner = MockupPapiRunner( 3, counters)
@Test
fun testEmptyBenchmark() {
......@@ -71,7 +68,7 @@ class SyntheticBenchmarkFeaturePrinterTest {
// (not like the hardware features, whose value change with each run)
// So we need to multiply the number of benchmarks by the number of hardware features to get
// the rest.
Assertions.assertEquals(recordsExpected.size + (benchmarkNum * counterSpec.currentSpec.size),
Assertions.assertEquals(recordsExpected.size + (benchmarkNum * counters.size),
recordsActual.size)
// We check the software features are the same.
......@@ -355,7 +352,7 @@ class SyntheticBenchmarkFeaturePrinterTest {
val sw = StringWriter()
val syntheticBenchmarkFeaturePrinter = SyntheticBenchmarkFeaturePrinter(sw,
PapiRunner(100, counterSpec),
PapiRunner(100, counters),
methodOutputFormat,
true)
......
......@@ -9,6 +9,7 @@ import papi.Papi
import se.lth.cs.CounterSpecification
import se.lth.cs.CounterSpecification.Companion.fromFile
import se.lth.cs.bcgen.BCBenchmarkPackage
import se.lth.cs.papicounters.PAPICounter
import se.lth.cs.papicounters.PapiBenchmarkAnalyzer
import se.lth.cs.papicounters.PapiTracerRunner
import se.lth.cs.smartmodules.tracer.Tracer
......@@ -121,8 +122,8 @@ class TracingCollectionRunnerTest {
fun setup() {
val papiAvailableCounters = File("../papi_avail")
Assertions.assertTrue(papiAvailableCounters.exists())
val specification = CounterSpecification(listOf("PAPI_TOT_CYC", "PAPI_TOT_INS", "PAPI_L1_DCM"))
runner = PapiTracerRunner(10, specification)
val counters = listOf("PAPI_TOT_CYC", "PAPI_TOT_INS", "PAPI_L1_DCM").map { PAPICounter(it) }
runner = PapiTracerRunner(10, counters)
}
@Test
......@@ -141,7 +142,7 @@ class TracingCollectionRunnerTest {
Assertions.assertEquals(benches.get(0), t.benchmark)
Assertions.assertTrue(t.iteration < runner!!.numRuns)
Assertions.assertEquals(
runner!!.counterSpec.getCounterNames().toSet(),
runner!!.counters.toSet() ,
t.samples.map { it.counter }.toSet())
}
}
......@@ -151,7 +152,8 @@ class TracingCollectionRunnerTest {
fun testRunSpec(seed : Long) {
val bench = BCBenchmarkPackage.LIST(seed, 10, 0, ArrayList<Int>())
val spec = PapiBenchmarkAnalyzer.RunSpec(10, listOf("PAPI_TOT_CYC"),
val spec = PapiBenchmarkAnalyzer.RunSpec(10,
listOf(PAPICounter("PAPI_TOT_CYC")),
EventSet.create(Constants.PAPI_TOT_CYC),
bench)
......@@ -162,7 +164,7 @@ class TracingCollectionRunnerTest {
for (iteration in iterations) {
for (sample in iteration.samples) {
Assertions.assertEquals("PAPI_TOT_CYC", sample.counter)
Assertions.assertEquals(PAPICounter("PAPI_TOT_CYC"), sample.counter)
Assertions.assertTrue(sample.value > 0)
Assertions.assertTrue(sample.value < 1000000)
}
......
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