Skip to content

Avoid clearing binary and library caches between KSP rounds - #3235

Open
cushon wants to merge 1 commit into
google:mainfrom
cushon:optimize-ksp-cache-eviction
Open

cushon wants to merge 1 commit into
google:mainfrom
cushon:optimize-ksp-cache-eviction

Conversation

@cushon

@cushon cushon commented Sep 30, 2026

Copy link
Copy Markdown

In dropCaches(), KSP previously called publishGlobalModuleStateModificationEvent(),
KaSessionProvider.getInstance(project).clearCaches(), psiManager.dropResolveCaches(),
psiManager.dropPsiCaches(), and KSObjectCacheManager.clear() on each round.

KSP rounds only add newly generated source files to KaSourceModule and do
not mutate binary libraries or dependencies (KaLibraryModule). Calling
publishGlobalModuleStateModificationEvent() forces Analysis API and FIR
to discard all binary/library symbol provider and Java class caches, which then
have to be recomputed from scratch in every subsequent round.

Switching to publishGlobalSourceModuleStateModificationEvent() preserves
library caches across rounds while properly invalidating source module caches.
Additionally:

  • KaSessionProvider.getInstance(project).clearCaches() is redundant because
    KaSessionProvider already subscribes to KotlinModificationEvent and
    clears caches when modification events are published.
  • psiManager.dropResolveCaches() is redundant because
    psiManager.dropPsiCaches() already calls dropResolveCaches().

In `dropCaches()`, KSP previously called `publishGlobalModuleStateModificationEvent()`,
`KaSessionProvider.getInstance(project).clearCaches()`, `psiManager.dropResolveCaches()`,
`psiManager.dropPsiCaches()`, and `KSObjectCacheManager.clear()` on each round.

KSP rounds only add newly generated source files to `KaSourceModule` and do
not mutate binary libraries or dependencies (`KaLibraryModule`). Calling
`publishGlobalModuleStateModificationEvent()` forces Analysis API and FIR
to discard all binary/library symbol provider and Java class caches, which then
have to be recomputed from scratch in every subsequent round.

Switching to `publishGlobalSourceModuleStateModificationEvent()` preserves
library caches across rounds while properly invalidating source module caches.
Additionally:
- `KaSessionProvider.getInstance(project).clearCaches()` is redundant because
  `KaSessionProvider` already subscribes to `KotlinModificationEvent` and
  clears caches when modification events are published.
- `psiManager.dropResolveCaches()` is redundant because
  `psiManager.dropPsiCaches()` already calls `dropResolveCaches()`.
@cushon

cushon commented Sep 30, 2026

Copy link
Copy Markdown
Author

There's some more context including benchmark results in internal bug b/567808367, I am seeing a ~9% wall time improvement for one large KSP action from this.

@jaschdoc jaschdoc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Reducing the number of manual calls is a good idea. Before I approve, I just want to ask @hfmehmed, do you see any problems with not clearing library caches in KMP setups? If we have commonMain and a terminal compilation task, how does KSP run now? Is processing run on commonMain first and its sources and generated sources available to the terminal compilation task as a library?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants