Initial API
This commit is contained in:
205
api/src/main/kotlin/data/Loader.kt
Normal file
205
api/src/main/kotlin/data/Loader.kt
Normal file
@ -0,0 +1,205 @@
|
||||
package com.jaytux.simd.data
|
||||
|
||||
import com.fleeksoft.ksoup.Ksoup
|
||||
import com.jaytux.simd.data.IntrinsicInstructions.xed
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import org.jetbrains.exposed.sql.batchInsert
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import java.io.File
|
||||
import org.json.JSONObject
|
||||
|
||||
object Loader {
|
||||
data class XmlIntrinsic(val name: String, val tech: String, val retType: String, val retVar: String?, val args: List<Pair<String, String>>, val desc: String, val op: String?, val insn: List<Triple<String, String, String?>>, val cpuid: String?, val category: String)
|
||||
|
||||
data class XmlData(
|
||||
val types: Set<String>, val techs: Set<String>, val cpuids: Set<String>, val categories: Set<String>,
|
||||
val intrinsics: List<XmlIntrinsic>
|
||||
)
|
||||
|
||||
data class Performance(val latency: Float?, val throughput: Float?)
|
||||
|
||||
data class JsonData(val platforms: Set<String>, val data: Map<String, Map<String, Performance>>)
|
||||
|
||||
suspend fun loadXml(xmlFile: String): XmlData = coroutineScope {
|
||||
val xml = Ksoup.parseXml(File(xmlFile).readText(Charsets.UTF_8))
|
||||
|
||||
val cppTypes = mutableSetOf<String>()
|
||||
val techs = mutableSetOf<String>()
|
||||
val cpuids = mutableSetOf<String>()
|
||||
val categories = mutableSetOf<String>()
|
||||
val intrins = mutableListOf<XmlIntrinsic>()
|
||||
|
||||
val errors = mutableListOf<String>()
|
||||
|
||||
xml.getElementsByTag("intrinsic").forEachIndexed { i, it ->
|
||||
val name = it.attribute("name")?.value
|
||||
if(name == null) {
|
||||
errors += "Missing name attribute in intrinsic element"
|
||||
return@forEachIndexed
|
||||
}
|
||||
val tech = it.attribute("tech")?.value
|
||||
if(tech == null) {
|
||||
errors += "Missing tech attribute for intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
val ret = it.getElementsByTag("return").firstOrNull()
|
||||
if(ret == null) {
|
||||
errors += "Missing return element for intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
val retType = ret.attribute("type")?.value
|
||||
if(retType == null) {
|
||||
errors += "Missing type attribute for return element in intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
val retVar = ret.attribute("varname")?.value
|
||||
|
||||
val args = mutableListOf<Pair<String, String>>()
|
||||
it.getElementsByTag("parameter").forEachIndexed { i, p ->
|
||||
val argName = p.attribute("varname")?.value
|
||||
val type = p.attribute("type")?.value
|
||||
|
||||
if(type != null && type == "void") return@forEachIndexed //ignore
|
||||
|
||||
if(argName == null) {
|
||||
errors += "Missing varname attribute for parameter $i in intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
if(type == null) {
|
||||
errors += "Missing type attribute for parameter $argName in intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
cppTypes += type
|
||||
args += argName to type
|
||||
}
|
||||
|
||||
val desc = it.getElementsByTag("description").firstOrNull()?.text()
|
||||
if(desc == null) {
|
||||
errors += "Missing description element for intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
val op = it.getElementsByTag("operation").firstOrNull()?.text()
|
||||
|
||||
val insn = mutableListOf<Triple<String, String, String?>>()
|
||||
it.getElementsByTag("instruction").forEachIndexed { i, ins ->
|
||||
val insnName = ins.attribute("xed")?.value ?: ins.attribute("name")?.value
|
||||
if(insnName == null) {
|
||||
errors += "Missing both xed and name attribute for instruction $i in intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
val insnMnemonic = ins.attribute("name")?.value
|
||||
if(insnMnemonic == null) {
|
||||
errors += "Missing name attribute for instruction $insnName in intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
val insnForm = ins.attribute("form")?.value
|
||||
insn += Triple(insnName, insnMnemonic, insnForm)
|
||||
}
|
||||
|
||||
val cpuid = it.getElementsByTag("cpuid").firstOrNull()?.text()
|
||||
|
||||
val category = it.getElementsByTag("category").firstOrNull()?.text()
|
||||
if(category == null) {
|
||||
errors += "Missing category element for intrinsic $name"
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
val intrinsic = XmlIntrinsic(name, tech, retType, retVar, args, desc, op, insn, cpuid, category)
|
||||
intrins += intrinsic
|
||||
techs += tech
|
||||
cpuid?.let { c -> cpuids += c }
|
||||
categories += category
|
||||
cppTypes += retType
|
||||
}
|
||||
|
||||
if(errors.isNotEmpty()) {
|
||||
errors.forEach { System.err.println(it) }
|
||||
throw Exception("XML file is (partially) invalid")
|
||||
}
|
||||
|
||||
XmlData(types = cppTypes, techs = techs, cpuids = cpuids, categories = categories, intrinsics = intrins)
|
||||
}
|
||||
|
||||
suspend fun loadJson(jsonFile: String): JsonData = coroutineScope {
|
||||
val json = File(jsonFile).readText(Charsets.UTF_8)
|
||||
val schema = JSONObject(json)
|
||||
val pSet = mutableSetOf<String>()
|
||||
val res = mutableMapOf<String, MutableMap<String, Performance>>()
|
||||
|
||||
schema.keys().forEach { opcode ->
|
||||
val pMap = mutableMapOf<String, Performance>()
|
||||
val platforms = schema.getJSONArray(opcode)
|
||||
for (i in 0 until platforms.length()) {
|
||||
val platform = platforms.getJSONObject(i)
|
||||
|
||||
platform.keys().forEach { k ->
|
||||
pSet += k
|
||||
val latency = platform.getJSONObject(k).getString("l").toFloatOrNull()
|
||||
val throughput = platform.getJSONObject(k).getString("t").toFloatOrNull()
|
||||
pMap += k to Performance(latency, throughput)
|
||||
}
|
||||
}
|
||||
res += opcode to pMap
|
||||
}
|
||||
|
||||
JsonData(pSet, res)
|
||||
}
|
||||
|
||||
suspend fun importToDb(xml: XmlData, json: JsonData) = coroutineScope {
|
||||
val db = Database.db
|
||||
transaction {
|
||||
val techMap = xml.techs.associateWith { tech -> Tech.new { name = tech } }
|
||||
val typeMap = xml.types.associateWith { type -> CppType.new { name = type } }
|
||||
val catMap = xml.categories.associateWith { cat -> Category.new { name = cat } }
|
||||
val cpuidMap = xml.cpuids.associateWith { cpuid -> CPUID.new { name = cpuid } }
|
||||
val platformMap = json.platforms.associateWith { platform -> Platform.new { name = platform } }
|
||||
|
||||
xml.intrinsics.forEach { intr ->
|
||||
val dbIn = Intrinsic.new {
|
||||
mnemonic = intr.name
|
||||
returnType = typeMap[intr.retType] ?: throw Exception("Type ${intr.retType} not found")
|
||||
returnVar = intr.retVar
|
||||
description = intr.desc
|
||||
operations = intr.op
|
||||
category = catMap[intr.category] ?: throw Exception("Category ${intr.category} not found")
|
||||
cpuid = intr.cpuid?.let { cpuidMap[it] ?: throw Exception("CPUID ${intr.cpuid} not found") }
|
||||
tech = techMap[intr.tech] ?: throw Exception("Tech ${intr.tech} not found")
|
||||
}
|
||||
|
||||
intr.args.forEachIndexed { i, arg ->
|
||||
IntrinsicArgument.new {
|
||||
intrinsic = dbIn
|
||||
name = arg.first
|
||||
type = typeMap[arg.second] ?: throw Exception("Type ${arg.second} not found")
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
intr.insn.forEach { insn ->
|
||||
val dbInsn = IntrinsicInstruction.new {
|
||||
intrinsic = dbIn
|
||||
xed = insn.first
|
||||
mnemonic = insn.second
|
||||
insn.third?.let { form = it }
|
||||
}
|
||||
|
||||
json.data[insn.first]?.forEach { (pl, perf) ->
|
||||
val dbPl = platformMap[pl] ?: throw Exception("Platform $pl not found")
|
||||
Performances.insert {
|
||||
it[instruction] = dbInsn.id
|
||||
it[platform] = dbPl.id
|
||||
it[latency] = perf.latency
|
||||
it[throughput] = perf.throughput
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user