@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.compilerRunner.JpsKotlinLogger
2020import java.io.File
2121import java.net.InetAddress
2222import java.util.*
23- import kotlin.collections.ArrayList
23+ import java.util.concurrent.ConcurrentHashMap
24+ import java.util.concurrent.ConcurrentLinkedQueue
2425
2526interface JpsBuilderMetricReporter : BuildMetricsReporter <JpsBuildTime , JpsBuildPerformanceMetric > {
2627 fun flush (context : CompileContext ): JpsCompileStatisticsData
@@ -34,7 +35,7 @@ class JpsBuilderMetricReporterImpl(
3435 chunk : ModuleChunk ,
3536 private val reporter : BuildMetricsReporterImpl <JpsBuildTime , JpsBuildPerformanceMetric >,
3637 private val label : String? = null ,
37- private val kotlinVersion : String = " kotlin_version"
38+ private val kotlinVersion : String = " kotlin_version" ,
3839) :
3940 JpsBuilderMetricReporter , BuildMetricsReporter <JpsBuildTime , JpsBuildPerformanceMetric > by reporter {
4041
@@ -90,13 +91,20 @@ class JpsBuilderMetricReporterImpl(
9091
9192}
9293
93- // TODO test UserDataHolder in CompileContext to store CompileStatisticsData.Build or KotlinBuilderMetric
94- class JpsStatisticsReportService {
94+ sealed class JpsStatisticsReportService {
95+ companion object {
96+ fun create (): JpsStatisticsReportService {
97+ val fileReportSettings = initFileReportSettings()
98+ val httpReportSettings = initHttpReportSettings()
9599
96- private val fileReportSettings: FileReportSettings ? = initFileReportSettings()
97- private val httpReportSettings: HttpReportSettings ? = initHttpReportSettings()
100+ return if (fileReportSettings == null && httpReportSettings == null ) {
101+ DummyJpsStatisticsReportService
102+ } else {
103+ JpsStatisticsReportServiceImpl (fileReportSettings, httpReportSettings)
104+ }
105+
106+ }
98107
99- companion object {
100108 private fun initFileReportSettings (): FileReportSettings ? {
101109 return System .getProperty(" kotlin.build.report.file.output_dir" )?.let { FileReportSettings (File (it)) }
102110 }
@@ -111,36 +119,76 @@ class JpsStatisticsReportService {
111119 }
112120 }
113121
114- private val buildMetrics = HashMap <String , JpsBuilderMetricReporter >()
115- private val finishedModuleBuildMetrics = ArrayList <JpsBuilderMetricReporter >()
122+ abstract fun <T > reportMetrics (chunk : ModuleChunk , metric : JpsBuildTime , action : () -> T ): T
123+ abstract fun buildStarted (context : CompileContext )
124+ abstract fun buildFinish (context : CompileContext )
125+
126+ abstract fun moduleBuildFinished (chunk : ModuleChunk , context : CompileContext )
127+ abstract fun moduleBuildStarted (chunk : ModuleChunk )
128+ }
129+
130+
131+ object DummyJpsStatisticsReportService : JpsStatisticsReportService() {
132+ override fun <T > reportMetrics (chunk : ModuleChunk , metric : JpsBuildTime , action : () -> T ): T {
133+ return action()
134+ }
135+
136+ override fun buildStarted (context : CompileContext ) {}
137+ override fun buildFinish (context : CompileContext ) {}
138+ override fun moduleBuildFinished (chunk : ModuleChunk , context : CompileContext ) {}
139+ override fun moduleBuildStarted (chunk : ModuleChunk ) {}
140+
141+ }
142+
143+ class JpsStatisticsReportServiceImpl (
144+ private val fileReportSettings : FileReportSettings ? ,
145+ httpReportSettings : HttpReportSettings ? ,
146+ ) : JpsStatisticsReportService() {
147+
148+ private val buildMetrics = ConcurrentHashMap <String , JpsBuilderMetricReporter >()
149+ private val finishedModuleBuildMetrics = ConcurrentLinkedQueue <JpsBuilderMetricReporter >()
116150 private val log = Logger .getInstance(" #org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService" )
117151 private val loggerAdapter = JpsKotlinLogger (log)
118152 private val httpService = httpReportSettings?.let { HttpReportService (it.url, it.user, it.password) }
119153
120- fun moduleBuildStarted (chunk : ModuleChunk ) {
154+ override fun moduleBuildStarted (chunk : ModuleChunk ) {
121155 val moduleName = chunk.name
122- if (buildMetrics[moduleName] != null ) {
123- log.warn(" Service already initialized for context" )
156+ val jpsReporter = JpsBuilderMetricReporterImpl (chunk, BuildMetricsReporterImpl ())
157+ if (buildMetrics.putIfAbsent(moduleName, jpsReporter) != jpsReporter) {
158+ log.warn(" Service already initialized for $moduleName module" )
124159 return
125160 }
126- log.info(" JpsStatisticsReportService: Service started" )
127- buildMetrics[moduleName] = JpsBuilderMetricReporterImpl (chunk, BuildMetricsReporterImpl ())
161+ log.debug(" JpsStatisticsReportService: Build started for $moduleName module" )
128162 }
129163
164+ private fun getMetricReporter (chunk : ModuleChunk ): JpsBuilderMetricReporter ? {
165+ val moduleName = chunk.name
166+ return getMetricReporter(moduleName)
167+ }
130168
131- fun moduleBuildFinished (chunk : ModuleChunk , context : CompileContext ) {
169+ private fun getMetricReporter (moduleName : String ): JpsBuilderMetricReporter ? {
170+ val metricReporter = buildMetrics[moduleName]
171+ if (metricReporter == null ) {
172+ // At some point log should be changed to exception
173+ log.warn(" Service hasn't initialized for $moduleName module" )
174+ return null
175+ }
176+ return metricReporter
177+ }
178+
179+ override fun moduleBuildFinished (chunk : ModuleChunk , context : CompileContext ) {
132180 val moduleName = chunk.name
133181 val metrics = buildMetrics.remove(moduleName)
134182 if (metrics == null ) {
135- log.warn(" Service hasn't initialized for context " )
183+ log.warn(" Service hasn't initialized for $moduleName module " )
136184 return
137185 }
138- log.info (" JpsStatisticsReportService: Service finished " )
186+ log.debug (" JpsStatisticsReportService: Build started for $moduleName module " )
139187 metrics.buildFinish(chunk, context)
140188 finishedModuleBuildMetrics.add(metrics)
141189 }
142190
143- fun buildFinish (context : CompileContext ) {
191+ override fun buildFinish (context : CompileContext ) {
144192 val compileStatisticsData = finishedModuleBuildMetrics.map { it.flush(context) }
145193 httpService?.sendData(compileStatisticsData, loggerAdapter)
146194 fileReportSettings?.also {
@@ -151,23 +199,12 @@ class JpsStatisticsReportService {
151199 }
152200 }
153201
154-
155- fun <T > reportMetrics (chunk : ModuleChunk , metric : JpsBuildTime , action : () -> T ): T {
156- val moduleName = chunk.name
157- val metrics = buildMetrics[moduleName]
158- if (metrics == null ) {
159- log.warn(" Service hasn't initialized for context" )
160- return action.invoke()
161- }
162- log.info(" JpsStatisticsReportService: report metrics" )
163- return metrics.measure(metric, action)
202+ override fun <T > reportMetrics (chunk : ModuleChunk , metric : JpsBuildTime , action : () -> T ): T {
203+ return getMetricReporter(chunk)?.measure(metric, action) ? : action.invoke()
164204 }
165205
166- fun buildStarted (context : CompileContext ) {
167- loggerAdapter.info(" Build started for $context " )
206+ override fun buildStarted (context : CompileContext ) {
207+ loggerAdapter.info(" Build started for $context with enabled build metric reports. " )
168208 }
169209
170- }
171-
172-
173-
210+ }
0 commit comments