@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.compilerRunner.JpsKotlinLogger
20
20
import java.io.File
21
21
import java.net.InetAddress
22
22
import java.util.*
23
- import kotlin.collections.ArrayList
23
+ import java.util.concurrent.ConcurrentHashMap
24
+ import java.util.concurrent.ConcurrentLinkedQueue
24
25
25
26
interface JpsBuilderMetricReporter : BuildMetricsReporter <JpsBuildTime , JpsBuildPerformanceMetric > {
26
27
fun flush (context : CompileContext ): JpsCompileStatisticsData
@@ -34,7 +35,7 @@ class JpsBuilderMetricReporterImpl(
34
35
chunk : ModuleChunk ,
35
36
private val reporter : BuildMetricsReporterImpl <JpsBuildTime , JpsBuildPerformanceMetric >,
36
37
private val label : String? = null ,
37
- private val kotlinVersion : String = " kotlin_version"
38
+ private val kotlinVersion : String = " kotlin_version" ,
38
39
) :
39
40
JpsBuilderMetricReporter , BuildMetricsReporter <JpsBuildTime , JpsBuildPerformanceMetric > by reporter {
40
41
@@ -90,13 +91,20 @@ class JpsBuilderMetricReporterImpl(
90
91
91
92
}
92
93
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()
95
99
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
+ }
98
107
99
- companion object {
100
108
private fun initFileReportSettings (): FileReportSettings ? {
101
109
return System .getProperty(" kotlin.build.report.file.output_dir" )?.let { FileReportSettings (File (it)) }
102
110
}
@@ -111,36 +119,76 @@ class JpsStatisticsReportService {
111
119
}
112
120
}
113
121
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 >()
116
150
private val log = Logger .getInstance(" #org.jetbrains.kotlin.jps.statistic.KotlinBuilderReportService" )
117
151
private val loggerAdapter = JpsKotlinLogger (log)
118
152
private val httpService = httpReportSettings?.let { HttpReportService (it.url, it.user, it.password) }
119
153
120
- fun moduleBuildStarted (chunk : ModuleChunk ) {
154
+ override fun moduleBuildStarted (chunk : ModuleChunk ) {
121
155
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" )
124
159
return
125
160
}
126
- log.info(" JpsStatisticsReportService: Service started" )
127
- buildMetrics[moduleName] = JpsBuilderMetricReporterImpl (chunk, BuildMetricsReporterImpl ())
161
+ log.debug(" JpsStatisticsReportService: Build started for $moduleName module" )
128
162
}
129
163
164
+ private fun getMetricReporter (chunk : ModuleChunk ): JpsBuilderMetricReporter ? {
165
+ val moduleName = chunk.name
166
+ return getMetricReporter(moduleName)
167
+ }
130
168
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 ) {
132
180
val moduleName = chunk.name
133
181
val metrics = buildMetrics.remove(moduleName)
134
182
if (metrics == null ) {
135
- log.warn(" Service hasn't initialized for context " )
183
+ log.warn(" Service hasn't initialized for $moduleName module " )
136
184
return
137
185
}
138
- log.info (" JpsStatisticsReportService: Service finished " )
186
+ log.debug (" JpsStatisticsReportService: Build started for $moduleName module " )
139
187
metrics.buildFinish(chunk, context)
140
188
finishedModuleBuildMetrics.add(metrics)
141
189
}
142
190
143
- fun buildFinish (context : CompileContext ) {
191
+ override fun buildFinish (context : CompileContext ) {
144
192
val compileStatisticsData = finishedModuleBuildMetrics.map { it.flush(context) }
145
193
httpService?.sendData(compileStatisticsData, loggerAdapter)
146
194
fileReportSettings?.also {
@@ -151,23 +199,12 @@ class JpsStatisticsReportService {
151
199
}
152
200
}
153
201
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()
164
204
}
165
205
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. " )
168
208
}
169
209
170
- }
171
-
172
-
173
-
210
+ }
0 commit comments