343 lines
13 KiB
Markdown
343 lines
13 KiB
Markdown
## Profiling the compiler
|
|
|
|
### Profiling with Async profiler
|
|
|
|
IDEA Ultimate contains an Async sampling profiler.
|
|
As of IDEA 2018.3 Async sampling profiler is still an experimental feature, so use Ctrl-Alt-Shift-/ on Linux,
|
|
Cmd-Alt-Shift-/ on macOS to activate it. Then start compilation in CLI with `--no-daemon` and
|
|
`-Porg.gradle.workers.max=1` flags (running Gradle task with the profiler doesn't seem to work properly) and attach
|
|
to the running process using "Run/Attach Profiler to Local Process" menu item.
|
|
|
|
Select "K2NativeKt" or "org.jetbrains.kotlin.cli.utilities.MainKt" process.
|
|
On completion profiler will produce flame diagram which could be navigated with the mouse
|
|
(click-drag moves, wheel scales). More RAM in IDE (>4G) could be helpful when analyzing longer runs.
|
|
As Async is a sampling profiler, to get sensible coverage longer runs are important.
|
|
|
|
### Profiling with YourKit
|
|
|
|
Unlike Async profiler in IDEA, YourKit can work as an exact profiler and provide complete coverage
|
|
of all methods along with exact invocation counters.
|
|
|
|
Install the YourKit profiler for your platform from https://www.yourkit.com/java/profiler.
|
|
Set AGENT variable to the JVMTI agent provided by YourKit, like
|
|
|
|
export AGENT=/Applications/YourKit-Java-Profiler-2018.04.app/Contents/Resources/bin/mac/libyjpagent.jnilib
|
|
|
|
To profile standard library compilation:
|
|
|
|
./gradlew -PstdLibJvmArgs="-agentpath:$AGENT=probe_disable=*,listen=all,tracing" dist
|
|
|
|
To profile platform libraries start build of proper target like this:
|
|
|
|
./gradlew -PplatformLibsJvmArgs="-agentpath:$AGENT=probe_disable=*,listen=all,tracing" ios_arm64PlatformLibs
|
|
|
|
To profile standalone code compilation use:
|
|
|
|
JAVA_OPTS="-agentpath:$AGENT=probe_disable=*,listen=all,tracing" ./dist/bin/konanc file.kt
|
|
|
|
Then attach to the desired application in YourKit GUI and use CPU tab to inspect CPU consuming methods.
|
|
Saving the trace may be needed for more analysis. Adjusting `-Xmx` in `$HOME/.yjp/ui.ini` could help
|
|
with the big traces.
|
|
|
|
To perform memory profiling follow the steps above, and after attachment to the running process
|
|
use "Start Object Allocation Recording" button. See https://www.yourkit.com/docs/java/help/allocations.jsp for more details.
|
|
|
|
## Compiler Gradle options
|
|
|
|
There are several gradle flags one can use for Konan build.
|
|
|
|
* **-Pbuild_flags** passes flags to the compiler used to build stdlib
|
|
|
|
./gradlew -Pbuild_flags="--disable lower_inline --print_ir" stdlib
|
|
|
|
* **-Pshims** compiles LLVM interface with tracing "shims". Allowing one
|
|
to trace the LLVM calls from the compiler.
|
|
Make sure to rebuild the project.
|
|
|
|
./gradlew -Pshims=true dist
|
|
|
|
## Compiler environment variables
|
|
|
|
* **KONAN_DATA_DIR** changes `.konan` local data directory location (`$HOME/.konan` by default). Works both with cli compiler and gradle plugin
|
|
|
|
## Testing
|
|
|
|
### Compiler integration tests
|
|
|
|
To run blackbox compiler tests from JVM Kotlin use (takes time):
|
|
|
|
./gradlew run_external
|
|
|
|
To update the blackbox compiler tests set TeamCity build number in `gradle.properties`:
|
|
|
|
testKotlinVersion=<build number>
|
|
|
|
* **-Pfilter** allows one to choose test files to run.
|
|
|
|
./gradlew -Pfilter=overflowLong.kt run_external
|
|
|
|
* **-Pprefix** allows one to choose external test directories to run. Only tests from directories with given prefix will be executed.
|
|
|
|
./gradlew -Pprefix=build_external_compiler_codegen_box_cast run_external
|
|
|
|
* **-Ptest_flags** passes flags to the compiler used to compile tests
|
|
|
|
./gradlew -Ptest_flags="--time" backend.native:tests:array0
|
|
|
|
* **-Ptest_target** specifies cross target for a test run.
|
|
|
|
./gradlew -Ptest_target=raspberrypi backend.native:tests:array0
|
|
|
|
* **-Premote=user@host** sets remote test execution login/hostname. Good for cross compiled tests.
|
|
|
|
./gradlew -Premote=kotlin@111.22.33.444 backend.native:tests:run
|
|
|
|
* **-Ptest_verbose** enables printing compiler args and other helpful information during a test execution.
|
|
|
|
./gradlew -Ptest_verbose :backend.native:tests:mpp_optional_expectation
|
|
|
|
* **-Ptest_two_stage** enables two-stage compilation of tests. If two-stage compilation is enabled, test sources are compiled into a klibrary
|
|
and then a final native binary is produced from this klibrary using the -Xinclude compiler flag.
|
|
|
|
./gradlew -Ptest_two_stage backend.native:tests:array0
|
|
|
|
* **-Ptest_with_cache_kind=static|dynamic** enables using caches during testing.
|
|
|
|
### Runtime unit tests
|
|
|
|
To run runtime unit tests on the host machine for both mimalloc and the standard allocator:
|
|
|
|
./gradlew hostRuntimeTests
|
|
|
|
To run tests for only one of these two allocators, run `hostStdAllocRuntimeTests` or `hostMimallocRuntimeTests`.
|
|
|
|
We use [Google Test](https://github.com/google/googletest) to execute the runtime unit tests. The build automatically fetches
|
|
the specified Google Test revision to `runtime/googletest`. It is possible to manually modify the downloaded GTest sources for debug
|
|
purposes; the build will not overwrite them by default.
|
|
|
|
To forcibly redownload Google Test when running tests, use the corresponding project property:
|
|
|
|
./gradlew hostRuntimeTests -Prefresh-gtest
|
|
|
|
or run the `downloadGTest` task directly with the `--refresh` CLI key:
|
|
|
|
./gradlew downloadGTest --refresh
|
|
|
|
To use a local GTest copy instead of the downloaded one, add the following line to `runtime/build.gradle.kts`:
|
|
|
|
googletest.useLocalSources("<path to local GTest sources>")
|
|
|
|
## Performance measurement
|
|
|
|
Firstly, it's necessary to build analyzer tool to have opportunity to compare different performance results:
|
|
|
|
cd tools/benchmarksAnalyzer
|
|
../../gradlew build
|
|
|
|
To measure performance of Kotlin/Native compiler on existing benchmarks:
|
|
|
|
cd performance
|
|
../gradlew :konanRun
|
|
|
|
**NOTE**: **konanRun** task needs built compiler and libs. To test against working tree make sure to run
|
|
|
|
./gradlew dist distPlatformLibs
|
|
|
|
before **konanRun**
|
|
|
|
**konanRun** task can be run separately for one/several benchmark applications:
|
|
|
|
cd performance
|
|
../gradlew :cinterop:konanRun
|
|
|
|
**konanRun** task has parameter `filter` which allows to run only some subset of benchmarks:
|
|
|
|
cd performance
|
|
../gradlew :cinterop:konanRun --filter=struct,macros
|
|
|
|
Or you can use `filterRegex` if you want to specify the filter as regexes:
|
|
|
|
cd performance
|
|
../gradlew :ring:konanRun --filterRegex=String.*,Loop.*
|
|
|
|
There us also verbose mode to follow progress of running benchmarks
|
|
|
|
cd performance
|
|
../gradlew :cinterop:konanRun --verbose
|
|
|
|
> Task :performance:cinterop:konanRun
|
|
[DEBUG] Warm up iterations for benchmark macros
|
|
[DEBUG] Running benchmark macros
|
|
...
|
|
|
|
There are also tasks for running benchmarks on JVM (pay attention, some benchmarks e.g. cinterop benchmarks can't be run on JVM)
|
|
|
|
cd performance
|
|
../gradlew :jvmRun
|
|
|
|
Files with results of benchmarks run are saved in `performance/build/nativeReport.json` for konanRun and `jvmReport.json` for jvmRun.
|
|
You can change the output filename by setting the `nativeJson` property for konanRun and `jvmJson` for jvmRun:
|
|
|
|
cd performance
|
|
../gradlew :ring:konanRun --filter=String.*,Loop.* -PnativeJson=stringsAndLoops.json
|
|
|
|
You can use the `compilerArgs` property to pass flags to the compiler used to compile the benchmarks:
|
|
|
|
cd performance
|
|
../gradlew :konanRun -PcompilerArgs="--time -g"
|
|
|
|
To compare different results run benchmarksAnalyzer tool:
|
|
|
|
cd tools/benchmarksAnalyzer/build/bin/<target>/benchmarksAnalyzerReleaseExecutable/
|
|
./benchmarksAnalyzer.kexe <file1> <file2>
|
|
|
|
Tool has several renders which allow produce output report in different forms (text, html, etc.). To set up render use flag `--render/-r`.
|
|
Output can be redirected to file with flag `--output/-o`.
|
|
To get detailed information about supported options, please use `--help/-h`.
|
|
|
|
Analyzer tool can compare both local files and files placed on Artifactory/TeamCity.
|
|
|
|
File description stored on Artifactory
|
|
|
|
artifactory:<build number>:<target (Linux|Windows10|MacOSX)>:<filename>
|
|
|
|
Example
|
|
|
|
artifactory:1.2-dev-7942:Windows10:nativeReport.json
|
|
|
|
File description stored on TeamCity
|
|
|
|
teamcity:<build locator>:<filename>
|
|
|
|
Example
|
|
|
|
teamcity:id:42491947:nativeReport.json
|
|
|
|
Pay attention, user and password information(with flag `-u <username>:<password>`) should be provided to get data from TeamCity.
|
|
|
|
## Composite build and testing
|
|
|
|
If you have a fix spanning both Kotlin and Kotlin/native workspaces you need to be able to test Kotlin/Native composite build. Here's how to do it manually:
|
|
|
|
### Have a composite build with the proper Kotlin tag.
|
|
|
|
Find the version of Kotlin the current native is guaranteed to build with.
|
|
The version is specified in `kotlin-native/gradle.properties`. For example:
|
|
```
|
|
kotlinVersion=1.3.70-dev-1526
|
|
```
|
|
Checkout `kotlin` workspace to tag `build-1.3.70-dev-1526`. Make sure its path ends with `.../kotlin`.
|
|
Otherwise issues will arise.
|
|
Direct `kotlin-native` build to the kotlin with `kotlinProjectPath` in native's `gradle.properties`.
|
|
|
|
Now you have the kotlin + kotlin-native combination that is known to build.
|
|
Apply your fix on top of both workspaces and run
|
|
```
|
|
$ ./gradlew dist
|
|
```
|
|
|
|
in `kotlin-native` to check the buildability.
|
|
|
|
### Testing native
|
|
|
|
For a quick check use:
|
|
```
|
|
$ ./gradlew sanity 2>&1 | tee log
|
|
```
|
|
|
|
For a longer, more thorough testing build the complete build. Make sure you are running it on a macOS.
|
|
|
|
|
|
Have a complete build:
|
|
|
|
```
|
|
$ ./gradlew bundle # includes dist as its part
|
|
```
|
|
|
|
then run two test sets:
|
|
|
|
```
|
|
$ ./gradlew backend.native:tests:run 2>&1 | tee log
|
|
|
|
$ ./gradlew backend.native:tests:runExternal -Ptest_two_stage=true 2>&1 | tee log
|
|
|
|
```
|
|
|
|
## LLVM
|
|
|
|
See [BUILDING_LLVM.md](BUILDING_LLVM.md) if you want to build and use your own LLVM distribution
|
|
instead of provided one.
|
|
|
|
### Using different LLVM distributions as part of Kotlin/Native compilation pipeline.
|
|
|
|
`llvmHome.<HOST_NAME>` variable in `<distribution_location>/konan/konan.properties` controls
|
|
which LLVM distribution Kotlin/Native will use in its compilation pipeline.
|
|
You can replace its value with either `$llvm.<HOST_NAME>.{dev, user}` to use one of predefined distributions
|
|
or pass an absolute to your own distribution.
|
|
Don't forget to set `llvmVersion.<HOST_NAME>` to the version of your LLVM distribution.
|
|
|
|
#### Example. Using LLVM from an absolute path.
|
|
Assuming LLVM distribution is installed at `/usr` path, one can specify a path to it
|
|
with the `-Xoverride-konan-properties` option:
|
|
```
|
|
konanc main.kt -Xoverride-konan-properties=llvmHome.linux_x64=/usr
|
|
```
|
|
|
|
### Playing with compilation pipeline.
|
|
|
|
Following compiler phases control different parts of LLVM pipeline:
|
|
1. `LinkBitcodeDependencies`. Linkage of produced bitcode with runtime and some other dependencies.
|
|
2. `BitcodeOptimization`. Running LLVM optimization pipeline.
|
|
3. `ObjectFiles`. Compilation of bitcode with Clang.
|
|
|
|
For example, pass `-Xdisable-phases=BitcodeOptimization` to skip optimization pipeline.
|
|
Note that disabling `LinkBitcodeDependencies` or `ObjectFiles` will break compilation pipeline.
|
|
|
|
Compiler takes options for Clang from [konan.properties](konan/konan.properties) file
|
|
by combining `clangFlags.<TARGET>` and `clang<Noopt/Opt/Debug>Flags.<TARGET>` properties.
|
|
Use `-Xoverride-konan-properties=<key_1=value_1; ...;key_n=value_n>` flag to override default values.
|
|
|
|
Please note:
|
|
1. Kotlin Native passes bitcode files to Clang instead of C or C++, so many flags won't work.
|
|
2. `-cc1 -emit-obj` should be passed because Kotlin/Native calls linker by itself.
|
|
3. Use `clang -cc1 -help` to see a list of available options.
|
|
|
|
Another useful compiler option is `-Xtemporary-files-dir=<PATH>` which allows
|
|
to specify a directory for intermediate compiler artifacts like bitcode and object files.
|
|
|
|
#### Example 1. Bitcode right after IR to Bitcode translation.
|
|
```shell script
|
|
konanc main.kt -produce bitcode -o bitcode.bc
|
|
```
|
|
|
|
#### Example 2. Bitcode after LLVM optimizations.
|
|
```shell script
|
|
konanc main.kt -Xtemporary-files-dir=<PATH> -o <OUTPUT_NAME>
|
|
```
|
|
`<PATH>/<OUTPUT_NAME>.kt.bc` will contain bitcode after LLVM optimization pipeline.
|
|
|
|
#### Example 3. Replace predefined LLVM pipeline with Clang options.
|
|
```shell script
|
|
CLANG_FLAGS="clangFlags.macos_x64=-cc1 -emit-obj;clangNooptFlags.macos_x64=-O2"
|
|
konanc main.kt -Xdisable-phases=BitcodeOptimization -Xoverride-konan-properties="$CLANG_FLAGS"
|
|
```
|
|
|
|
## Running Clang the same way Kotlin/Native compiler does
|
|
|
|
Kotlin/Native compiler (including `cinterop` tool) has machinery that manages LLVM, Clang and native SDKs for supported targets
|
|
and runs bundled Clang with proper arguments.
|
|
To utilize this machinery, use `$dist/bin/run_konan clang $tool $target $arguments`, e.g.
|
|
```
|
|
$dist/bin/run_konan clang clang ios_arm64 1.c
|
|
```
|
|
will print and run the following command:
|
|
```
|
|
~/.konan/dependencies/clang-llvm-apple-8.0.0-darwin-macos/bin/clang \
|
|
-B/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin \
|
|
-fno-stack-protector -stdlib=libc++ -arch arm64 \
|
|
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.5.sdk \
|
|
-miphoneos-version-min=9.0 1.c
|
|
```
|
|
|
|
The similar helper is available for LLVM tools, `$dist/bin/run_konan llvm $tool $arguments`.
|