Add logging with time measurement to script dependencies caching and caches updating
This commit is contained in:
+77
-49
@@ -20,6 +20,8 @@ import com.intellij.openapi.components.ServiceManager
|
|||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.management.ManagementFactory
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
import kotlin.concurrent.read
|
import kotlin.concurrent.read
|
||||||
import kotlin.concurrent.write
|
import kotlin.concurrent.write
|
||||||
@@ -63,69 +65,88 @@ class KotlinScriptExternalImportsProviderImpl(
|
|||||||
// optimized for initial caching, additional handling of possible duplicates to save a call to distinct
|
// optimized for initial caching, additional handling of possible duplicates to save a call to distinct
|
||||||
// returns list of cached files
|
// returns list of cached files
|
||||||
override fun <TF: Any> cacheExternalImports(files: Iterable<TF>): Iterable<TF> = cacheLock.write {
|
override fun <TF: Any> cacheExternalImports(files: Iterable<TF>): Iterable<TF> = cacheLock.write {
|
||||||
val uncached = hashSetOf<String>()
|
var filesCount = 0
|
||||||
files.mapNotNull { file ->
|
var additionsCount = 0
|
||||||
val path = getFilePath(file)
|
val (res, time) = measureThreadTimeMillis {
|
||||||
if (isValidFile(file) && !cache.containsKey(path) && !uncached.contains(path)) {
|
val uncached = hashSetOf<String>()
|
||||||
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
|
files.mapNotNull { file ->
|
||||||
if (scriptDef != null) {
|
filesCount += 1
|
||||||
val deps = scriptDef.getDependenciesFor(file, project, null)
|
val path = getFilePath(file)
|
||||||
if (deps != null) {
|
if (isValidFile(file) && !cache.containsKey(path) && !uncached.contains(path)) {
|
||||||
log.info("[kts] cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")
|
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
|
||||||
|
if (scriptDef != null) {
|
||||||
|
val deps = scriptDef.getDependenciesFor(file, project, null)
|
||||||
|
if (deps != null) {
|
||||||
|
log.info("[kts] cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")
|
||||||
|
}
|
||||||
|
cache.put(path, deps)
|
||||||
|
additionsCount += 1
|
||||||
|
file
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uncached.add(path)
|
||||||
|
null
|
||||||
}
|
}
|
||||||
cache.put(path, deps)
|
|
||||||
file
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uncached.add(path)
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
else null
|
||||||
}
|
}
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
|
log.info("[kts] cache creation: $filesCount checked, $additionsCount added (in ${time}ms)")
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized for update, no special duplicates handling
|
// optimized for update, no special duplicates handling
|
||||||
// returns files with valid script definition (or deleted from cache - which in fact should have script def too)
|
// returns files with valid script definition (or deleted from cache - which in fact should have script def too)
|
||||||
// TODO: this is the badly designed contract, since it mixes the entities, but these files are needed on the calling site now. Find out other solution
|
// TODO: this is the badly designed contract, since it mixes the entities, but these files are needed on the calling site now. Find out other solution
|
||||||
override fun <TF: Any> updateExternalImportsCache(files: Iterable<TF>): Iterable<TF> = cacheLock.write {
|
override fun <TF: Any> updateExternalImportsCache(files: Iterable<TF>): Iterable<TF> = cacheLock.write {
|
||||||
files.mapNotNull { file ->
|
var filesCount = 0
|
||||||
val path = getFilePath(file)
|
var updatesCount = 0
|
||||||
if (!isValidFile(file)) {
|
val (res, time) = measureThreadTimeMillis {
|
||||||
if (cache.remove(path) != null) {
|
files.mapNotNull { file ->
|
||||||
log.debug("[kts] removed deps for file $path")
|
filesCount += 1
|
||||||
file
|
val path = getFilePath(file)
|
||||||
} // cleared
|
if (!isValidFile(file)) {
|
||||||
else {
|
if (cache.remove(path) != null) {
|
||||||
null // unknown
|
log.debug("[kts] removed deps for file $path")
|
||||||
}
|
updatesCount += 1
|
||||||
}
|
file
|
||||||
else {
|
} // cleared
|
||||||
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
|
else {
|
||||||
if (scriptDef != null) {
|
null // unknown
|
||||||
val oldDeps = cache[path]
|
|
||||||
val deps = scriptDef.getDependenciesFor(file, project, oldDeps)
|
|
||||||
when {
|
|
||||||
deps != null && (oldDeps == null ||
|
|
||||||
!deps.classpath.isSamePathListAs(oldDeps.classpath) || !deps.sources.isSamePathListAs(oldDeps.sources)) -> {
|
|
||||||
// changed or new
|
|
||||||
log.info("[kts] updated/new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")
|
|
||||||
cache.put(path, deps)
|
|
||||||
}
|
|
||||||
deps != null -> {
|
|
||||||
// same as before
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if (cache.remove(path) != null) {
|
|
||||||
log.debug("[kts] removed deps for $path")
|
|
||||||
} // cleared
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
file
|
|
||||||
}
|
}
|
||||||
else null // not a script
|
else {
|
||||||
|
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
|
||||||
|
if (scriptDef != null) {
|
||||||
|
val oldDeps = cache[path]
|
||||||
|
val deps = scriptDef.getDependenciesFor(file, project, oldDeps)
|
||||||
|
when {
|
||||||
|
deps != null && (oldDeps == null ||
|
||||||
|
!deps.classpath.isSamePathListAs(oldDeps.classpath) || !deps.sources.isSamePathListAs(oldDeps.sources)) -> {
|
||||||
|
// changed or new
|
||||||
|
log.info("[kts] updated/new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}")
|
||||||
|
cache.put(path, deps)
|
||||||
|
}
|
||||||
|
deps != null -> {
|
||||||
|
// same as before
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (cache.remove(path) != null) {
|
||||||
|
log.debug("[kts] removed deps for $path")
|
||||||
|
} // cleared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatesCount += 1
|
||||||
|
file
|
||||||
|
}
|
||||||
|
else null // not a script
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (updatesCount > 0) {
|
||||||
|
log.info("[kts] cache update check: $filesCount checked, $updatesCount updated (in ${time}ms)")
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidateCaches() {
|
override fun invalidateCaches() {
|
||||||
@@ -160,3 +181,10 @@ private fun Iterable<File>.isSamePathListAs(other: Iterable<File>): Boolean =
|
|||||||
}
|
}
|
||||||
!(first.hasNext() || second.hasNext())
|
!(first.hasNext() || second.hasNext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun<T> measureThreadTimeMillis(body: () -> T): Pair<T, Long> {
|
||||||
|
val mxBeans = ManagementFactory.getThreadMXBean()
|
||||||
|
val startTime = mxBeans.currentThreadCpuTime
|
||||||
|
val res = body()
|
||||||
|
return res to TimeUnit.NANOSECONDS.toMillis(mxBeans.currentThreadCpuTime - startTime)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user