Add completion benchmark to check completion speed

This commit is contained in:
Simon Ogorodnik
2017-07-08 02:56:26 +03:00
parent dfef1f4921
commit bc5872dd8f
9 changed files with 422 additions and 3 deletions
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.completion
import kotlinx.coroutines.experimental.channels.ConflatedChannel
interface CompletionBenchmarkSink {
fun onCompletionStarted(completionSession: CompletionSession)
fun onCompletionEnded(completionSession: CompletionSession)
fun onFirstFlush(completionSession: CompletionSession)
companion object {
fun enableAndGet(): Impl = Impl().also { _instance = it }
fun disable() {
_instance.let { (it as? Impl)?.channel?.close() }
_instance = Empty
}
val instance get() = _instance
private var _instance: CompletionBenchmarkSink = Empty
}
private object Empty : CompletionBenchmarkSink {
override fun onCompletionStarted(completionSession: CompletionSession) {}
override fun onCompletionEnded(completionSession: CompletionSession) {}
override fun onFirstFlush(completionSession: CompletionSession) {}
}
class Impl : CompletionBenchmarkSink {
private val pendingSessions = mutableListOf<CompletionSession>()
private lateinit var results: CompletionBenchmarkResults
val channel = ConflatedChannel<CompletionBenchmarkResults>()
override fun onCompletionStarted(completionSession: CompletionSession) = synchronized(this) {
if (pendingSessions.isEmpty())
results = CompletionBenchmarkResults()
pendingSessions += completionSession
}
override fun onCompletionEnded(completionSession: CompletionSession) = synchronized(this) {
pendingSessions -= completionSession
if (pendingSessions.isEmpty()) {
results.onEnd()
channel.offer(results)
}
}
override fun onFirstFlush(completionSession: CompletionSession) = synchronized(this) {
results.onFirstFlush()
}
fun reset() = synchronized(this) {
pendingSessions.clear()
}
class CompletionBenchmarkResults {
var start: Long = System.currentTimeMillis()
var firstFlush: Long = 0
var full: Long = 0
fun onFirstFlush() {
if (firstFlush == 0L)
firstFlush = System.currentTimeMillis() - start
}
fun onEnd() {
full = System.currentTimeMillis() - start
}
}
}
}
@@ -78,6 +78,10 @@ abstract class CompletionSession(
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper,
resultSet: CompletionResultSet
) {
init {
CompletionBenchmarkSink.instance.onCompletionStarted(this)
}
protected val position = parameters.position
protected val file = position.containingFile as KtFile
protected val resolutionFacade = file.getResolutionFacade()
@@ -140,7 +144,7 @@ abstract class CompletionSession(
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter(), (file as? KtCodeFragment)?.extraCompletionFilter)
LookupElementsCollector(this, prefixMatcher, parameters, resultSet, createSorter(), (file as? KtCodeFragment)?.extraCompletionFilter)
}
protected val searchScope: GlobalSearchScope = getResolveScope(parameters.originalFile as KtFile)
@@ -199,6 +203,14 @@ abstract class CompletionSession(
}
fun complete(): Boolean {
return try {
_complete()
} finally {
CompletionBenchmarkSink.instance.onCompletionEnded(this)
}
}
private fun _complete(): Boolean {
// we restart completion when prefix becomes "get" or "set" to ensure that properties get lower priority comparing to get/set functions (see KT-12299)
val prefixPattern = StandardPatterns.string().with(object : PatternCondition<String>("get or set prefix") {
override fun accepts(prefix: String, context: ProcessingContext?) = prefix == "get" || prefix == "set"
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import java.util.*
class LookupElementsCollector(
private val session: CompletionSession,
private val prefixMatcher: PrefixMatcher,
private val completionParameters: CompletionParameters,
resultSet: CompletionResultSet,
@@ -50,8 +51,11 @@ class LookupElementsCollector(
var isResultEmpty: Boolean = true
private set
fun flushToResultSet() {
if (!elements.isEmpty()) {
CompletionBenchmarkSink.instance.onFirstFlush(session)
resultSet.addAllElements(elements)
elements.clear()
isResultEmpty = false