[Commonizer] Stats collector: support aggregated stats
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
|
||||
|
||||
class Parameters(
|
||||
val statsCollector: StatsCollector? = null
|
||||
) {
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+7
-5
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -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
|
||||
),
|
||||
|
||||
+3
-2
@@ -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()
|
||||
|
||||
|
||||
+14
-2
@@ -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) ->
|
||||
|
||||
-188
@@ -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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
+110
@@ -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
|
||||
}
|
||||
+52
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -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('-')
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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?>)
|
||||
}
|
||||
+53
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user