[Commonizer] Stats collector: support aggregated stats

This commit is contained in:
Dmitriy Dolovov
2020-06-15 11:44:22 +07:00
parent f7ceacb15c
commit 205510863a
13 changed files with 438 additions and 202 deletions
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.descriptors.commonizer
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
class Parameters(
val statsCollector: StatsCollector? = null
) {
@@ -7,11 +7,11 @@ package org.jetbrains.kotlin.descriptors.commonizer.builder
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.StatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.Target
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirRootNode
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.dimension
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.indexOfCommon
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroup
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroupMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule
@@ -10,18 +10,20 @@ internal class BooleanOptionType(
description: String,
mandatory: Boolean
) : OptionType<Boolean>(alias, description, mandatory) {
private val trueTokens = setOf("1", "on", "yes", "true")
private val falseTokens = setOf("0", "off", "no", "false")
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<Boolean> {
val value = rawValue.toLowerCase().let {
when (it) {
in trueTokens -> true
in falseTokens -> false
in TRUE_TOKENS -> true
in FALSE_TOKENS -> false
else -> onError("Invalid boolean value: $it")
}
}
return Option(this, value)
}
companion object {
private val TRUE_TOKENS = setOf("1", "on", "yes", "true")
private val FALSE_TOKENS = setOf("0", "off", "no", "false")
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.cli
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType
internal object StatsTypeOptionType : OptionType<StatsType>("log-stats", DESCRIPTION, mandatory = false) {
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<StatsType> {
val value = StatsType.values().firstOrNull { it.name.equals(rawValue, ignoreCase = true) }
?: onError("Invalid stats type: $rawValue")
return Option(this, value)
}
}
private val DESCRIPTION = buildString {
StatsType.values().joinTo(this) {
val item = "\"${it.name.toLowerCase()}\""
if (it == StatsType.NONE) "$item (default)" else item
}
append(";\nlog commonization stats")
}
@@ -28,7 +28,7 @@ internal enum class TaskType(
"Boolean (default false);\nwhether to copy Kotlin/Native endorsed libraries to the destination",
mandatory = false
),
BooleanOptionType("log-stats", "Boolean (default false); Log commonization stats", mandatory = false)
StatsTypeOptionType
),
::NativeDistributionCommonize
),
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.cli
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -44,7 +45,7 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
val copyStdlib = getOptional<Boolean, BooleanOptionType> { it == "copy-stdlib" } ?: false
val copyEndorsedLibs = getOptional<Boolean, BooleanOptionType> { it == "copy-endorsed-libs" } ?: false
val withStats = getOptional<Boolean, BooleanOptionType> { it == "log-stats" } ?: false
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
val descriptionSuffix = estimateLibrariesCount(distribution, targets)?.let { " ($it items)" } ?: ""
val description = "${logPrefix}Preparing commonized Kotlin/Native libraries for targets $targets$descriptionSuffix"
@@ -57,7 +58,7 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
destination = destination,
copyStdlib = copyStdlib,
copyEndorsedLibs = copyEndorsedLibs,
withStats = withStats,
statsType = statsType,
logger = CliLoggerAdapter(2)
).run()
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.*
import org.jetbrains.kotlin.descriptors.commonizer.Target
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType.*
import org.jetbrains.kotlin.descriptors.commonizer.stats.AggregatedStatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.stats.FileStatsOutput
import org.jetbrains.kotlin.descriptors.commonizer.stats.RawStatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark
import org.jetbrains.kotlin.descriptors.konan.NATIVE_STDLIB_MODULE_NAME
import org.jetbrains.kotlin.konan.library.*
@@ -37,9 +41,13 @@ class NativeDistributionCommonizer(
private val destination: File,
private val copyStdlib: Boolean,
private val copyEndorsedLibs: Boolean,
private val withStats: Boolean,
private val statsType: StatsType,
private val logger: Logger
) {
enum class StatsType {
RAW, AGGREGATED, NONE
}
fun run() {
checkPreconditions()
@@ -123,7 +131,11 @@ class NativeDistributionCommonizer(
}
private fun commonize(librariesByTargets: Map<InputTarget, NativeDistributionLibraries>): Result {
val statsCollector = if (withStats) NativeStatsCollector(targets, destination) else null
val statsCollector = when (statsType) {
RAW -> RawStatsCollector(targets, FileStatsOutput(destination, "raw"))
AGGREGATED -> AggregatedStatsCollector(targets, FileStatsOutput(destination, "aggregated"))
NONE -> null
}
statsCollector.use {
val parameters = Parameters(statsCollector).apply {
librariesByTargets.forEach { (target, libraries) ->
@@ -1,188 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.konan
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS
import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_ENTRY
import org.jetbrains.kotlin.descriptors.commonizer.StatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.utils.firstNonNull
import org.jetbrains.kotlin.descriptors.commonizer.utils.fqNameWithTypeParameters
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import java.io.File
/**
* Allows printing commonization statistics to the file system.
*
* File format: text, "|"-separated columns.
*
* Header row: "FQ Name|Extension Receiver|Parameter Names|Parameter Types|Declaration Type|common|<platform1>|<platform2>[|<platformN>...]"
*
* Possible values for "Declaration Type":
* - MODULE
* - CLASS
* - INTERFACE
* - OBJECT
* - COMPANION_OBJECT
* - ENUM_CLASS
* - ENUM_ENTRY
* - TYPE_ALIAS
* - CLASS_CONSTRUCTOR
* - FUN
* - VAL
*
* Possible values for "common" column:
* - L = declaration lifted up to common fragment
* - E = successfully commonized, expect declaration generated
* - "-" = no common declaration
*
* Possible values for each target platform column:
* - A = successfully commonized, actual declaration generated
* - O = not commonized, the declaration is as in the original library
* - "-" = no such declaration in the original library (or declaration has been lifted up)
*
* Example of output:
FQ Name|Extension Receiver|Parameter Names|Parameter Types|Declaration Type|common|macos_x64|ios_x64
<SystemConfiguration>||||MODULE|E|A|A
platform.SystemConfiguration.SCPreferencesContext||||CLASS|E|A|A
platform.SystemConfiguration.SCPreferencesContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext||||CLASS|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCDynamicStoreRefVar||||TYPE_ALIAS|-|O|O
platform.SystemConfiguration.SCVLANInterfaceRef||||TYPE_ALIAS|-|O|O
*/
class NativeStatsCollector(
private val targets: List<KonanTarget>,
destination: File
) : StatsCollector {
init {
destination.mkdirs()
}
private val writer = destination.resolve("plain_stats.csv").printWriter()
private var headerWritten = false
override fun logStats(output: List<DeclarationDescriptor?>) {
if (!headerWritten) {
headerWritten = true
writeHeader()
}
val firstNotNull = output.firstNonNull()
val lastIsNull = output.last() == null
val row = buildString {
appendName(firstNotNull)
append(SEPARATOR)
append(firstNotNull.declarationType) // readable declaration type
append(SEPARATOR)
var isLiftedUp = !lastIsNull
val platformItems = StringBuilder().apply {
for (index in 0 until output.size - 1) {
append(SEPARATOR)
append(
when {
output[index] == null -> '-' // absent
lastIsNull -> 'O' // original (not commonized)
else -> {
isLiftedUp = false
'A' // actual (commonized)
}
}
)
}
}
append(
when {
isLiftedUp -> 'L'
lastIsNull -> '-'
else -> 'E'
}
) // common
append(platformItems)
}
writer.println(row)
}
override fun close() = writer.close()
private fun writeHeader() {
val row = buildString {
append("FQ Name")
append(SEPARATOR)
append("Extension Receiver")
append(SEPARATOR)
append("Parameter Names")
append(SEPARATOR)
append("Parameter Types")
append(SEPARATOR)
append("Declaration Type")
append(SEPARATOR)
append("common")
targets.forEach { target ->
append(SEPARATOR)
append(target.name)
}
}
writer.println(row)
}
companion object {
private const val SEPARATOR = '|'
@Suppress("NOTHING_TO_INLINE")
private inline fun StringBuilder.appendName(descriptor: DeclarationDescriptor) {
// name
append(if (descriptor is ModuleDescriptor) descriptor.name.asString() else descriptor.fqNameSafe.asString())
append(SEPARATOR)
// extension receiver
if (descriptor is PropertyDescriptor || descriptor is SimpleFunctionDescriptor) {
append((descriptor as CallableDescriptor).extensionReceiverParameter?.type?.fqNameWithTypeParameters.orEmpty())
}
append(SEPARATOR)
if (descriptor is ConstructorDescriptor || descriptor is SimpleFunctionDescriptor) {
// parameter names
(descriptor as FunctionDescriptor).valueParameters.joinTo(this) { it.name.asString() }
append(SEPARATOR)
// parameter types
descriptor.valueParameters.joinTo(this) { it.type.fqNameWithTypeParameters }
} else {
append(SEPARATOR)
}
}
private inline val DeclarationDescriptor.topLevelnessPrefix: String
get() = if (DescriptorUtils.isTopLevelDeclaration(this)) "TOP-LEVEL " else "NESTED "
private inline val DeclarationDescriptor.declarationType: String
get() = when (this) {
is ClassDescriptor -> when {
isCompanionObject -> "COMPANION_OBJECT"
kind == ENUM_CLASS || kind == ENUM_ENTRY -> kind.toString()
else -> topLevelnessPrefix + kind.toString()
}
is TypeAliasDescriptor -> "TYPE_ALIAS"
is ClassConstructorDescriptor -> "CLASS_CONSTRUCTOR"
is FunctionDescriptor -> topLevelnessPrefix + "FUN"
is PropertyDescriptor -> topLevelnessPrefix + if (isConst) "CONST-VAL" else "VAL"
is ModuleDescriptor -> "MODULE"
else -> "UNKNOWN: ${this::class.java}"
}
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.stats.AggregatedStatsCollector.AggregatedStatsRow
import org.jetbrains.kotlin.descriptors.commonizer.stats.RawStatsCollector.CommonDeclarationStatus.*
import org.jetbrains.kotlin.konan.target.KonanTarget
class AggregatedStatsCollector(
targets: List<KonanTarget>,
private val output: StatsOutput
) : StatsCollector {
private val aggregatingOutput = AggregatingOutput()
private val wrappedCollector = RawStatsCollector(targets, aggregatingOutput)
override fun logStats(result: List<DeclarationDescriptor?>) {
wrappedCollector.logStats(result)
}
override fun close() {
output.writeHeader(AggregatedStatsHeader)
aggregatingOutput.aggregatedStats.keys.sortedBy { it }.forEach { key ->
val row = aggregatingOutput.aggregatedStats.getValue(key)
output.writeRow(row)
}
output.close()
wrappedCollector.close()
}
object AggregatedStatsHeader : StatsOutput.StatsHeader {
private val headerItems = listOf(
"Declaration Type",
"Lifted Up",
"Lifted Up, %%",
"Commonized",
"Commonized, %%",
"Missed in s. targets",
"Missed in s. targets, %%",
"Failed: Other",
"Failed: Other, %%",
"Total"
)
override fun toList(): List<String> = headerItems
}
class AggregatedStatsRow(
private val declarationType: DeclarationType
) : StatsOutput.StatsRow {
var liftedUp: Int = 0
var successfullyCommonized: Int = 0
var failedBecauseAbsent: Int = 0
var failedOther: Int = 0
override fun toList(): List<String> {
val total = liftedUp + successfullyCommonized + failedBecauseAbsent + failedOther
fun fraction(amount: Int): Double = if (total > 0) amount.toDouble() / total else 0.0
return listOf(
declarationType.alias,
liftedUp.toString(),
fraction(liftedUp).toString(),
successfullyCommonized.toString(),
fraction(successfullyCommonized).toString(),
failedBecauseAbsent.toString(),
fraction(failedBecauseAbsent).toString(),
failedOther.toString(),
fraction(failedOther).toString(),
total.toString()
)
}
}
}
@Suppress("MoveVariableDeclarationIntoWhen")
private class AggregatingOutput : StatsOutput {
val aggregatedStats = HashMap<DeclarationType, AggregatedStatsRow>()
override fun writeHeader(header: StatsOutput.StatsHeader) {
check(header is RawStatsCollector.RawStatsHeader)
// do nothing
}
override fun writeRow(row: StatsOutput.StatsRow) {
check(row is RawStatsCollector.RawStatsRow)
val aggregatedStatsRow = aggregatedStats.computeIfAbsent(row.declarationType, ::AggregatedStatsRow)
when (row.common) {
LIFTED_UP -> aggregatedStatsRow.liftedUp++
EXPECT -> aggregatedStatsRow.successfullyCommonized++
ABSENT -> {
if (row.platform.any { it == RawStatsCollector.PlatformDeclarationStatus.ABSENT }) {
aggregatedStatsRow.failedBecauseAbsent++
} else {
aggregatedStatsRow.failedOther++
}
}
}
}
override fun close() = Unit
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
enum class DeclarationType(val alias: String) {
TOP_LEVEL_CONST_VAL("TOP-LEVEL CONST-VAL"),
TOP_LEVEL_VAL("TOP-LEVEL VAL"),
TOP_LEVEL_FUN("TOP-LEVEL FUN"),
TOP_LEVEL_CLASS("TOP-LEVEL CLASS"),
CLASS_CONSTRUCTOR("CLASS_CONSTRUCTOR"),
NESTED_VAL("NESTED VAL"),
NESTED_FUN("NESTED FUN"),
NESTED_CLASS("NESTED CLASS"),
NESTED_INTERFACE("NESTED INTERFACE"),
COMPANION_OBJECT("COMPANION_OBJECT"),
TOP_LEVEL_INTERFACE("TOP-LEVEL INTERFACE"),
TYPE_ALIAS("TYPE_ALIAS"),
ENUM_ENTRY("ENUM_ENTRY"),
ENUM_CLASS("ENUM_CLASS"),
MODULE("MODULE"),
UNKNOWN("UNKNOWN");
companion object {
val DeclarationDescriptor.declarationType: DeclarationType
get() = when (this) {
is ClassDescriptor -> {
if (isCompanionObject) {
COMPANION_OBJECT
} else when (kind) {
ClassKind.ENUM_CLASS -> ENUM_CLASS
ClassKind.ENUM_ENTRY -> ENUM_ENTRY
ClassKind.INTERFACE -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_INTERFACE else NESTED_INTERFACE
else -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_CLASS else NESTED_CLASS
}
}
is TypeAliasDescriptor -> TYPE_ALIAS
is ClassConstructorDescriptor -> CLASS_CONSTRUCTOR
is FunctionDescriptor -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_FUN else NESTED_FUN
is PropertyDescriptor -> if (DescriptorUtils.isTopLevelDeclaration(this)) {
if (isConst) TOP_LEVEL_CONST_VAL else TOP_LEVEL_VAL
} else NESTED_VAL
is ModuleDescriptor -> MODULE
else -> UNKNOWN
}
}
}
@@ -0,0 +1,168 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.stats.DeclarationType.Companion.declarationType
import org.jetbrains.kotlin.descriptors.commonizer.utils.firstNonNull
import org.jetbrains.kotlin.descriptors.commonizer.utils.fqNameWithTypeParameters
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
/**
* Allows printing commonization statistics to the file system.
*
* Output format is defined in [RawStatsCollector.output].
*
* Header row: "FQ Name, Extension Receiver, Parameter Names, Parameter Types, Declaration Type, common, <platform1>, <platform2> [<platformN>...]"
*
* Possible values for "Declaration Type":
* - MODULE
* - CLASS
* - INTERFACE
* - OBJECT
* - COMPANION_OBJECT
* - ENUM_CLASS
* - ENUM_ENTRY
* - TYPE_ALIAS
* - CLASS_CONSTRUCTOR
* - FUN
* - VAL
*
* Possible values for "common" column:
* - L = declaration lifted up to common fragment
* - E = successfully commonized, expect declaration generated
* - "-" = no common declaration
*
* Possible values for each target platform column:
* - A = successfully commonized, actual declaration generated
* - O = not commonized, the declaration is as in the original library
* - "-" = no such declaration in the original library (or declaration has been lifted up)
*
* Example of output:
FQ Name|Extension Receiver|Parameter Names|Parameter Types|Declaration Type|common|macos_x64|ios_x64
<SystemConfiguration>||||MODULE|E|A|A
platform.SystemConfiguration.SCPreferencesContext||||CLASS|E|A|A
platform.SystemConfiguration.SCPreferencesContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext||||CLASS|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCDynamicStoreRefVar||||TYPE_ALIAS|-|O|O
platform.SystemConfiguration.SCVLANInterfaceRef||||TYPE_ALIAS|-|O|O
*/
class RawStatsCollector(
private val targets: List<KonanTarget>,
private val output: StatsOutput
) : StatsCollector {
private var headerWritten = false
override fun logStats(result: List<DeclarationDescriptor?>) {
if (!headerWritten) {
writeHeader()
headerWritten = true
}
val firstNotNull = result.firstNonNull()
val lastIsNull = result.last() == null
val statsRow = RawStatsRow(
dimension = targets.size,
fqName = if (firstNotNull is ModuleDescriptor) firstNotNull.name.asString() else firstNotNull.fqNameSafe.asString(),
declarationType = firstNotNull.declarationType
)
// extension receiver
if (firstNotNull is PropertyDescriptor || firstNotNull is SimpleFunctionDescriptor) {
statsRow.extensionReceiver =
(firstNotNull as CallableDescriptor).extensionReceiverParameter?.type?.fqNameWithTypeParameters.orEmpty()
}
if (firstNotNull is ConstructorDescriptor || firstNotNull is SimpleFunctionDescriptor) {
val functionDescriptor = (firstNotNull as FunctionDescriptor)
// parameter names
statsRow.parameterNames = functionDescriptor.valueParameters.joinToString { it.name.asString() }
// parameter types
statsRow.parameterTypes = functionDescriptor.valueParameters.joinToString { it.type.fqNameWithTypeParameters }
}
var isLiftedUp = !lastIsNull
for (index in 0 until result.size - 1) {
statsRow.platform += when {
result[index] == null -> PlatformDeclarationStatus.ABSENT
lastIsNull -> PlatformDeclarationStatus.ORIGINAL
else -> {
isLiftedUp = false
PlatformDeclarationStatus.ACTUAL
}
}
}
statsRow.common = when {
isLiftedUp -> CommonDeclarationStatus.LIFTED_UP
lastIsNull -> CommonDeclarationStatus.ABSENT
else -> CommonDeclarationStatus.EXPECT
}
output.writeRow(statsRow)
}
override fun close() {
output.close()
}
private fun writeHeader() {
output.writeHeader(RawStatsHeader(targets.map { it.name }))
}
class RawStatsHeader(
private val targetNames: List<String>
) : StatsOutput.StatsHeader {
override fun toList(): List<String> = mutableListOf<String>().apply {
this += "FQ Name"
this += "Extension Receiver"
this += "Parameter Names"
this += "Parameter Types"
this += "Declaration Type"
this += "common"
this += targetNames
}
}
class RawStatsRow(
dimension: Int,
val fqName: String,
val declarationType: DeclarationType
) : StatsOutput.StatsRow {
var extensionReceiver: String = ""
var parameterNames: String = ""
var parameterTypes: String = ""
lateinit var common: CommonDeclarationStatus
val platform: MutableList<PlatformDeclarationStatus> = ArrayList(dimension)
override fun toList(): List<String> = mutableListOf<String>().apply {
this += fqName
this += extensionReceiver
this += parameterNames
this += parameterTypes
this += declarationType.alias
this += common.alias.toString()
platform.forEach { this += it.alias.toString() }
}
}
enum class CommonDeclarationStatus(val alias: Char) {
LIFTED_UP('L'),
EXPECT('E'),
ABSENT('-')
}
enum class PlatformDeclarationStatus(val alias: Char) {
ACTUAL('A'),
ORIGINAL('O'),
ABSENT('-')
}
}
@@ -1,13 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer
package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import java.io.Closeable
interface StatsCollector : Closeable {
fun logStats(output: List<DeclarationDescriptor?>)
fun logStats(result: List<DeclarationDescriptor?>)
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.stats
import java.io.Closeable
import java.io.File
import java.io.PrintWriter
interface StatsOutput : Closeable {
interface StatsHeader {
fun toList(): List<String>
}
interface StatsRow {
fun toList(): List<String>
}
fun writeHeader(header: StatsHeader)
fun writeRow(row: StatsRow)
}
class FileStatsOutput(directory: File, baseName: String) : StatsOutput {
init {
directory.mkdirs()
}
private val writer: PrintWriter = directory.resolve("${baseName}_stats.csv").printWriter()
private var width: Int = 0
override fun writeHeader(header: StatsOutput.StatsHeader) {
check(width == 0)
val headerItems = header.toList()
require(headerItems.isNotEmpty())
width = headerItems.size
headerItems.joinTo(writer, separator = "|", postfix = "\n")
}
override fun writeRow(row: StatsOutput.StatsRow) {
check(width > 0)
val rowItems = row.toList()
require(rowItems.size == width)
rowItems.joinTo(writer, separator = "|", postfix = "\n")
}
override fun close() {
writer.close()
}
}