:wave: I’m noticing some performance / memory regr...
# eap
y
👋 I’m noticing some performance / memory regression in Kotlin 2.0.20-RC2 compared to 2.0.10 in our CI benchmarks. Here are some high-level stats, Kotlin build report in 🧵
Copy code
| Stat                                | 2.0.10               | 2.0.20-RC2          | Diff   |
|-------------------------------------|----------------------|---------------------|--------|
| Peak memory usage (G1GC)            | 6.7 GiB/8 GiB (84.7%)| 7.9 GiB/8 GiB (99.4%)| 17.36% |
| Overall build time                  | 28m 54.257s          | 31m 11.100s         | 7.89%  |
| Execution time                      | 20m 23.815s          | 22m 55.517s         | 12.40% |
| Execution time (critical path)      | 16m 54.052s          | 19m 0.971s          | 12.52% |
| KotlinCompile                       | 25m 22.511s          | 31m 33.161s         | 24.34% |
| KotlinCompile (critical path)       | 2m 10.669s           | 2m 51.676s          | 31.30% |
| KspTaskJvm                          | 9m 51.438s           | 15m 13.355s         | 54.57% |
| KspTaskJvm (critical path)          | 47.956s              | 56.815s             | 18.46% |
| KaptGenerateStubTask                | 8m 33.081s           | 9m 38.056s          | 12.82% |
| KaptGenerateStubTask (critical path)| 1m 3.876s            | 1m 12.567s          | 13.61% |
| KaptWithoutKotlincTask              | 8m 47.751s           | 10m 36.795s         | 21.25% |
| KaptWithoutKotlincTask (critical path)| 49.884s            | 1m 6.280s           | 32.94% |
😬 1
youtrack 1
1
Kotlin build report (2.0.10):
Copy code
Gradle start parameters:
  tasks = [app:assembleDebug, app:bundleRelease, app-rewards:assembleDebug, app-rewards:bundleRelease]
  excluded tasks = []
  current dir = /home/circleci/repo
  project properties args = [enableFirebasePerformance: , enableDynatrace: ]
  system properties args = []

Time metrics:
  Total Gradle task time: 5,858.89 s
  Spent time before task action: 113.20 s
  Task action before worker execution: 71.58 s
  Run compilation in Gradle worker: 2,121.70 s
    Clear jar cache: 0.69 s
    Clear output: 0.01 s
    Connect to Kotlin daemon: 13.06 s
    Calculate output size: 0.76 s
    Run compilation: 1,632.00 s
      Non incremental compilation in daemon: 474.29 s
      Incremental compilation in daemon: 1,624.15 s
        Store build info: 0.00 s
        Clear outputs on rebuild: 0.00 s
        Update caches: 7.34 s
        Sources compilation round: 1,526.16 s
          Compiler initialization time: 26.56 s
          Compiler code analysis: 818.16 s
          Compiler IR translation: 281.40 s
          Compiler code generation: 396.67 s
            Compiler IR lowering: 187.10 s
            Compiler IR generation: 209.36 s
        Write history file: 0.01 s
        Shrink and save current classpath snapshot after compilation: 25.36 s
          Shrink current classpath snapshot non-incrementally: 24.07 s
            Load current classpath snapshot: 5.01 s
          Save shrunk current classpath snapshot: 0.58 s
  Start gradle worker: 81.91 s

Size metrics:
  Total size of the cache directory: 576.4 MB
    ABI snapshot size: 23.6 KB
  Increase memory usage: 116.3 GB
  Total memory usage at the end of build: 2,013.1 GB
  Total compiler iteration: 493
    Number of lines analyzed: 3131058
    Number of lines for code generation: 1997318
    Analysis lines per second: 1538797
    Code generation lines per second: 1635668
    Compiler IR translation line number: 1997318
    Compiler IR lowering line number: 1997318
    Compiler IR generation line number: 1997318
  Number of times classpath snapshot is shrunk and saved after compilation: 493
    Number of classpath entries: 51607
    Size of classpath snapshot: 4.8 GB
    Size of shrunk classpath snapshot: 124.2 MB
  Number of times classpath snapshot is loaded: 493
    Number of cache hits when loading classpath entry snapshots: 49386
    Number of cache misses when loading classpath entry snapshots: 2221
  Start time of task action: 40095-09-10T12:23:27

Build attributes:
  REBUILD_REASON:
    Incremental compilation is not enabled(205)
    Unknown Gradle changes(493)

Total time for Kotlin tasks: 1,937.20 s (33.1 % of all tasks time)
Kotlin build report (2.0.20-RC2):
Copy code
Gradle start parameters:
  tasks = [app:assembleDebug, app:bundleRelease, app-rewards:assembleDebug, app-rewards:bundleRelease]
  excluded tasks = []
  current dir = /home/circleci/repo
  project properties args = [enableFirebasePerformance: , enableDynatrace: ]
  system properties args = []

Time metrics:
  Total Gradle task time: 7,051.49 s
  Spent time before task action: 263.34 s
  Task action before worker execution: 90.20 s
  Run compilation in Gradle worker: 2,652.15 s
    Clear jar cache: 1.23 s
    Clear output: 0.18 s
    Connect to Kotlin daemon: 25.11 s
    Calculate output size: 0.92 s
    Run compilation: 2,012.70 s
      Non incremental compilation in daemon: 609.93 s
      Incremental compilation in daemon: 2,003.89 s
        Store build info: 0.32 s
        Clear outputs on rebuild: 0.01 s
        Update caches: 8.10 s
        Sources compilation round: 1,883.45 s
          Compiler initialization time: 31.89 s
          Compiler code analysis: 983.71 s
          Compiler IR translation: 399.33 s
          Compiler code generation: 464.83 s
            Compiler IR lowering: 225.20 s
            Compiler IR generation: 239.45 s
        Write history file: 0.03 s
        Shrink and save current classpath snapshot after compilation: 27.78 s
          Shrink current classpath snapshot non-incrementally: 25.72 s
            Load current classpath snapshot: 5.56 s
          Save shrunk current classpath snapshot: 1.32 s
  Start gradle worker: 55.79 s

Size metrics:
  Total size of the cache directory: 576.4 MB
    ABI snapshot size: 23.6 KB
  Increase memory usage: 96.2 GB
  Total memory usage at the end of build: 1,563.7 GB
  Total compiler iteration: 493
    Number of lines analyzed: 3131058
    Number of lines for code generation: 1997318
    Analysis lines per second: 1290518
    Code generation lines per second: 1415086
    Compiler IR translation line number: 1997318
    Compiler IR lowering line number: 1997318
    Compiler IR generation line number: 1997318
  Number of times classpath snapshot is shrunk and saved after compilation: 493
    Number of classpath entries: 51607
    Size of classpath snapshot: 4.8 GB
    Size of shrunk classpath snapshot: 124.1 MB
  Number of times classpath snapshot is loaded: 493
    Number of cache hits when loading classpath entry snapshots: 49995
    Number of cache misses when loading classpath entry snapshots: 1612
  Start time of task action: 40095-09-10T06:13:50

Build attributes:
  REBUILD_REASON:
    Incremental compilation is not enabled(205)
    Unknown Gradle changes(493)

Total time for Kotlin tasks: 2,384.36 s (33.8 % of all tasks time)
• The most obvious difference seems to be memory consumption. • I haven’t done any local benchmarks with Gradle profiler yet • We’re still using ksp1 and kapt3
I can share full kotlin build reports and build scans if it helps.
a
Hey, > Peak memory usage Is it the memory usage measured on the Gradle daemon or the Kotlin daemon process?
t
@Yang Thank you! Could you please create a ticket in YT and add all the necessary information there.
y
> Is it the memory usage measured on the Gradle daemon or the Kotlin daemon process? It’s Gradle daemon’s memory usage from build scan.
https://youtrack.jetbrains.com/issue/KT-70713/Performance-regression-in-Kotlin-2.0.20-RC2 I’ve shared the kotlin build reports and build scan urls privately.
thank you color 1
a
@Yang is it possible for you to share the project? or maybe heap dumps of Gradle daemon and Kotlin daemon on both versions
t
@Yang Could you please tell me if there was such a problem on previous EAP releases 2.0.20?
y
@Alexander.Likhachev unfortunately the project is proprietary. I’ll try to get the heap dumps.
@Tatiana Bogdanova [JetBrains] I only saw a noticeable regression in 2.0.20-RC2. Previous beta and RC were roughly the same as the baseline so I didn’t pay attention to perf.
thank you color 1
I generated the heap dumps and shared the ones for kotlin daemons. Interestingly the difference between 2.0.20 and 2.0.10 is not as big as the previous runs. I’ve uploaded new kotlin build reports and build scans.
thank you color 1
k
Have you stopped the Gradle and Kotlin daemons between runs?
y
These are on ephemeral CI runners.
🆗 1
BTW any idea how I can share the 4g heap dumps for Gradle daemon?
t
https://uploads.jetbrains.com/ and write here upload id
thank you color 1
y
Upload id: 2024_08_20_87yMvtQLW8Z8eA4SZGJRt9
I’ve done some more investigation and it looks like this might be a false report: https://youtrack.jetbrains.com/issue/KT-70713/Performance-regression-in-Kotlin-2.0.20-RC2#focus=Comments-27-10364400.0-0
t
the sweat spot is about 10g
Interesting. Do you really need such amount of heap size for both Gradle and Kotlin daemons? How many Gradle subprojects your project has? And do you have some "fat" subproject with more than 10_000 LoC?
y
214 projects, and yes we do have quite a few fat projects
t
for 214 projects I would reduce Gradle daemon heap size
y
I’ve tried to allocate different amount of heap for Kotlin vs Gradle many times in the past, but in our CI build it almost makes no difference
t
still it could just occupy memory on developers machines 🙂 I would propose to run clean build without build cache and fresh Gradle daemon. And then check Gradle build scan heap size consumption - this should indicate how much heap size it is needed for worst case scenario
y
these are CI builds with build cache explicitly disabled to simulate the worst case
The build also runs r8 minification for 2 apps at the end so half of time it doesn’t even need the Kotlin daemon