performance counters infrastructure
This commit is contained in:
+3
@@ -66,6 +66,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
|
||||
@Argument(value = "Xno-optimize", description = "Disable optimizations")
|
||||
public boolean noOptimize;
|
||||
|
||||
@Argument(value = "Xreport-perf", description = "Report detailed performance statistics")
|
||||
public boolean reportPerf;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String executableScriptFileName() {
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.cli.jvm;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
@@ -37,6 +39,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||
import org.jetbrains.kotlin.config.Services;
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.cache.IncrementalCacheProvider;
|
||||
import org.jetbrains.kotlin.resolve.AnalyzerScriptParameter;
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter;
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths;
|
||||
import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir;
|
||||
import org.jetbrains.kotlin.utils.PathUtil;
|
||||
@@ -44,14 +47,17 @@ import org.jetbrains.kotlin.utils.PathUtil;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.base.Predicates.in;
|
||||
import static org.jetbrains.kotlin.cli.common.ExitCode.*;
|
||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.*;
|
||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.addJavaSourceRoot;
|
||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.addJvmClasspathRoots;
|
||||
import static org.jetbrains.kotlin.config.ConfigPackage.addKotlinSourceRoot;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
private final long initStartNanos = System.nanoTime();
|
||||
|
||||
public static void main(String... args) {
|
||||
doMain(new K2JVMCompiler(), args);
|
||||
@@ -72,7 +78,7 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
messageCollector.report(CompilerMessageSeverity.LOGGING,
|
||||
"Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION);
|
||||
|
||||
CompilerConfiguration configuration = new CompilerConfiguration();
|
||||
final CompilerConfiguration configuration = new CompilerConfiguration();
|
||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector);
|
||||
|
||||
IncrementalCacheProvider incrementalCacheProvider = services.get(IncrementalCacheProvider.class);
|
||||
@@ -163,6 +169,7 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
jar = null;
|
||||
outputDir = null;
|
||||
}
|
||||
final KotlinCoreEnvironment environment;
|
||||
|
||||
if (arguments.module != null) {
|
||||
MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector, in(CompilerMessageSeverity.VERBOSE));
|
||||
@@ -175,21 +182,33 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
}
|
||||
|
||||
File directory = new File(arguments.module).getAbsoluteFile().getParentFile();
|
||||
|
||||
CompilerConfiguration compilerConfiguration = KotlinToJVMBytecodeCompiler
|
||||
.createCompilerConfiguration(configuration, moduleScript.getModules(), directory);
|
||||
environment = createCoreEnvironment(rootDisposable, compilerConfiguration);
|
||||
|
||||
KotlinToJVMBytecodeCompiler.compileModules(
|
||||
configuration, moduleScript.getModules(), directory, jar, arguments.includeRuntime
|
||||
);
|
||||
environment, configuration, moduleScript.getModules(), directory, jar, arguments.includeRuntime);
|
||||
}
|
||||
else if (arguments.script) {
|
||||
List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size());
|
||||
KotlinCoreEnvironment environment =
|
||||
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||
environment = createCoreEnvironment(rootDisposable, configuration);
|
||||
KotlinToJVMBytecodeCompiler.compileAndExecuteScript(configuration, paths, environment, scriptArgs);
|
||||
}
|
||||
else {
|
||||
KotlinCoreEnvironment environment =
|
||||
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||
environment = createCoreEnvironment(rootDisposable, configuration);
|
||||
KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime);
|
||||
}
|
||||
|
||||
if (arguments.reportPerf) {
|
||||
PerformanceCounter.Companion.report(new Function1<String, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(String s) {
|
||||
reportPerf(environment.getConfiguration(), s);
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
catch (CompilationException e) {
|
||||
@@ -199,6 +218,23 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
}
|
||||
}
|
||||
|
||||
private KotlinCoreEnvironment createCoreEnvironment(
|
||||
@NotNull Disposable rootDisposable,
|
||||
@NotNull CompilerConfiguration configuration) {
|
||||
KotlinCoreEnvironment result = KotlinCoreEnvironment.createForProduction(
|
||||
rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||
|
||||
long initNanos = System.nanoTime() - initStartNanos;
|
||||
reportPerf(configuration, "Compiler initialized in " + TimeUnit.NANOSECONDS.toMillis(initNanos) + " ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void reportPerf(CompilerConfiguration configuration, String message) {
|
||||
MessageCollector collector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
|
||||
assert collector != null;
|
||||
collector.report(CompilerMessageSeverity.INFO, "PERF: " + message, CompilerMessageLocation.NO_LOCATION);
|
||||
}
|
||||
|
||||
private static void putAdvancedOptions(@NotNull CompilerConfiguration configuration, @NotNull K2JVMCompilerArguments arguments) {
|
||||
configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions);
|
||||
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions);
|
||||
|
||||
+24
-16
@@ -29,12 +29,14 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
import java.util.ArrayList
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
public class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager)
|
||||
: CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
|
||||
|
||||
private val perfCounter = PerformanceCounter("Find Java class")
|
||||
private var index: JvmDependenciesIndex by Delegates.notNull()
|
||||
|
||||
public fun initIndex(packagesCache: JvmDependenciesIndex) {
|
||||
@@ -42,9 +44,11 @@ public class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager)
|
||||
}
|
||||
|
||||
public override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? {
|
||||
val classNameWithInnerClasses = classId.getRelativeClassName().asString()
|
||||
return index.findClass(classId) { dir, type ->
|
||||
findClassGivenPackage(searchScope, dir, classNameWithInnerClasses, type)
|
||||
return perfCounter.time {
|
||||
val classNameWithInnerClasses = classId.getRelativeClassName().asString()
|
||||
index.findClass(classId) { dir, type ->
|
||||
findClassGivenPackage(searchScope, dir, classNameWithInnerClasses, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,22 +62,26 @@ public class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager)
|
||||
}
|
||||
|
||||
override fun findClasses(qName: String, scope: GlobalSearchScope): Array<PsiClass> {
|
||||
val classIdAsTopLevelClass = qName.toSafeTopLevelClassId() ?: return super<CoreJavaFileManager>.findClasses(qName, scope)
|
||||
return perfCounter.time {
|
||||
val classIdAsTopLevelClass = qName.toSafeTopLevelClassId() ?: return@time super<CoreJavaFileManager>.findClasses(qName, scope)
|
||||
|
||||
val result = ArrayList<PsiClass>()
|
||||
val classNameWithInnerClasses = classIdAsTopLevelClass.getRelativeClassName().asString()
|
||||
index.traverseDirectoriesInPackage(classIdAsTopLevelClass.getPackageFqName()) { dir, rootType ->
|
||||
val psiClass = findClassGivenPackage(scope, dir, classNameWithInnerClasses, rootType)
|
||||
if (psiClass != null) {
|
||||
result.add(psiClass)
|
||||
val result = ArrayList<PsiClass>()
|
||||
val classNameWithInnerClasses = classIdAsTopLevelClass.getRelativeClassName().asString()
|
||||
index.traverseDirectoriesInPackage(classIdAsTopLevelClass.getPackageFqName()) { dir, rootType ->
|
||||
val psiClass = findClassGivenPackage(scope, dir, classNameWithInnerClasses, rootType)
|
||||
if (psiClass != null) {
|
||||
result.add(psiClass)
|
||||
}
|
||||
// traverse all
|
||||
true
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
super<CoreJavaFileManager>.findClasses(qName, scope)
|
||||
}
|
||||
else {
|
||||
result.toTypedArray()
|
||||
}
|
||||
// traverse all
|
||||
true
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
return super<CoreJavaFileManager>.findClasses(qName, scope)
|
||||
}
|
||||
return result.toArray<PsiClass>(arrayOfNulls<PsiClass>(result.size()))
|
||||
}
|
||||
|
||||
override fun findPackage(packageName: String): PsiPackage? {
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.openapi.fileTypes.PlainTextFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.FileContextProvider
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
@@ -86,6 +87,7 @@ import java.io.File
|
||||
import java.util.ArrayList
|
||||
import java.util.Comparator
|
||||
import kotlin.platform.platformStatic
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
public class KotlinCoreEnvironment private(
|
||||
parentDisposable: Disposable,
|
||||
@@ -157,6 +159,14 @@ public class KotlinCoreEnvironment private(
|
||||
public val project: Project
|
||||
get() = projectEnvironment.getProject()
|
||||
|
||||
public val sourceLinesOfCode: Int by Delegates.lazy { countLinesOfCode(sourceFiles) }
|
||||
|
||||
public fun countLinesOfCode(sourceFiles: List<JetFile>): Int =
|
||||
sourceFiles.sumBy {
|
||||
val text = it.getText()
|
||||
StringUtil.getLineBreakCount(it.getText()) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1)
|
||||
}
|
||||
|
||||
private fun addExternalAnnotationsRoot(path: File) {
|
||||
if (!path.exists()) {
|
||||
report(WARNING, "Annotations path entry points to a non-existent location: " + path)
|
||||
|
||||
+36
-35
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.cli.jvm.compiler;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
@@ -35,6 +33,7 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
import org.jetbrains.kotlin.cli.common.modules.Module;
|
||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsPackage;
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JVMConfigurationKeys;
|
||||
import org.jetbrains.kotlin.codegen.*;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -55,6 +54,7 @@ import org.jetbrains.kotlin.resolve.BindingTraceContext;
|
||||
import org.jetbrains.kotlin.resolve.ScriptNameUtil;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM;
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter;
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths;
|
||||
|
||||
import java.io.File;
|
||||
@@ -64,6 +64,7 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.*;
|
||||
import static org.jetbrains.kotlin.config.ConfigPackage.addKotlinSourceRoots;
|
||||
@@ -110,6 +111,7 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
|
||||
public static boolean compileModules(
|
||||
@NotNull KotlinCoreEnvironment environment,
|
||||
@NotNull CompilerConfiguration configuration,
|
||||
@NotNull List<Module> chunk,
|
||||
@NotNull File directory,
|
||||
@@ -118,39 +120,25 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
) {
|
||||
Map<Module, ClassFileFactory> outputFiles = Maps.newHashMap();
|
||||
|
||||
CompilerConfiguration compilerConfiguration = createCompilerConfiguration(configuration, chunk, directory);
|
||||
|
||||
Disposable parentDisposable = Disposer.newDisposable();
|
||||
KotlinCoreEnvironment environment = null;
|
||||
try {
|
||||
environment = KotlinCoreEnvironment
|
||||
.createForProduction(parentDisposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||
|
||||
AnalysisResult result = analyze(environment);
|
||||
if (result == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result.throwIfError();
|
||||
|
||||
for (Module module : chunk) {
|
||||
List<JetFile> jetFiles = CompileEnvironmentUtil.getJetFiles(
|
||||
environment.getProject(), getAbsolutePaths(directory, module), new Function1<String, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(String s) {
|
||||
throw new IllegalStateException("Should have been checked before: " + s);
|
||||
}
|
||||
}
|
||||
);
|
||||
GenerationState generationState =
|
||||
generate(environment, result, jetFiles, module.getModuleName(), new File(module.getOutputDirectory()));
|
||||
outputFiles.put(module, generationState.getFactory());
|
||||
}
|
||||
AnalysisResult result = analyze(environment);
|
||||
if (result == null) {
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
if (environment != null) {
|
||||
Disposer.dispose(parentDisposable);
|
||||
}
|
||||
|
||||
result.throwIfError();
|
||||
|
||||
for (Module module : chunk) {
|
||||
List<JetFile> jetFiles = CompileEnvironmentUtil.getJetFiles(
|
||||
environment.getProject(), getAbsolutePaths(directory, module), new Function1<String, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(String s) {
|
||||
throw new IllegalStateException("Should have been checked before: " + s);
|
||||
}
|
||||
}
|
||||
);
|
||||
GenerationState generationState =
|
||||
generate(environment, result, jetFiles, module.getModuleName(), new File(module.getOutputDirectory()));
|
||||
outputFiles.put(module, generationState.getFactory());
|
||||
}
|
||||
|
||||
for (Module module : chunk) {
|
||||
@@ -160,7 +148,7 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static CompilerConfiguration createCompilerConfiguration(
|
||||
public static CompilerConfiguration createCompilerConfiguration(
|
||||
@NotNull CompilerConfiguration base,
|
||||
@NotNull List<Module> chunk,
|
||||
@NotNull File directory
|
||||
@@ -309,6 +297,7 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
MessageCollector collector = environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
|
||||
assert collector != null;
|
||||
|
||||
long analysisStart = PerformanceCounter.Companion.currentThreadCpuTime();
|
||||
AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(collector);
|
||||
analyzerWithCompilerReport.analyzeAndReport(
|
||||
environment.getSourceFiles(), new Function0<AnalysisResult>() {
|
||||
@@ -328,6 +317,10 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
);
|
||||
long analysisNanos = PerformanceCounter.Companion.currentThreadCpuTime() - analysisStart;
|
||||
String message = "Analyzed " + environment.getSourceFiles().size() + " files (" +
|
||||
environment.getSourceLinesOfCode() + " lines) in " + TimeUnit.NANOSECONDS.toMillis(analysisNanos) + " ms";
|
||||
K2JVMCompiler.reportPerf(environment.getConfiguration(), message);
|
||||
|
||||
AnalysisResult result = analyzerWithCompilerReport.getAnalysisResult();
|
||||
assert result != null : "AnalysisResult should be non-null, compiling: " + environment.getSourceFiles();
|
||||
@@ -381,7 +374,15 @@ public class KotlinToJVMBytecodeCompiler {
|
||||
diagnosticHolder,
|
||||
outputDirectory
|
||||
);
|
||||
long generationStart = PerformanceCounter.Companion.currentThreadCpuTime();
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION);
|
||||
|
||||
long generationNanos = PerformanceCounter.Companion.currentThreadCpuTime() - generationStart;
|
||||
String message = "Generated " + sourceFiles.size() + " files (" +
|
||||
environment.countLinesOfCode(sourceFiles) + " lines) in " + TimeUnit.NANOSECONDS.toMillis(generationNanos) + " ms";
|
||||
K2JVMCompiler.reportPerf(environment.getConfiguration(), message);
|
||||
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(
|
||||
new FilteredJvmDiagnostics(
|
||||
diagnosticHolder.getBindingContext().getDiagnostics(),
|
||||
|
||||
Reference in New Issue
Block a user