"'YourPlugin' might be slowing things down" reported when invoking the IDE's SynchronizeAction from the EDT

I had a user report a “…might be slowing things down” freeze stack traces with the following:

Freeze in EDT for 15 seconds
Sampled time: 7400ms, sampling rate: 100ms, GC time: 332ms (3%), Class loading: 0%

com.intellij.diagnostic.Freeze
    at java.base@21.0.6/java.lang.Object.wait0(Native Method)
    at java.base@21.0.6/java.lang.Object.wait(Object.java:366)
    at java.base@21.0.6/java.lang.Object.wait(Object.java:339)
    at com.intellij.openapi.application.impl.RunSuspend.await(RunSuspend.kt:36)
    at com.intellij.openapi.application.impl.RunSuspendKt.runSuspend(RunSuspend.kt:14)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.getWritePermit(AnyThreadWriteThreadingSupport.kt:688)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.startWrite$lambda$7(AnyThreadWriteThreadingSupport.kt:416)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport$$Lambda/0x000000d001bf5010.invoke(Unknown Source)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.measureWriteLock(AnyThreadWriteThreadingSupport.kt:562)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.startWrite(AnyThreadWriteThreadingSupport.kt:416)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteAction(AnyThreadWriteThreadingSupport.kt:387)
    at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteAction(AnyThreadWriteThreadingSupport.kt:383)
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:907)
    at com.intellij.openapi.application.WriteAction.run(WriteAction.java:84)
    at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.doSaveDocument(FileDocumentManagerImpl.java:386)
    at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveDocuments(FileDocumentManagerImpl.java:303)
    at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:278)
    at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:271)
    at com.intellij.ide.actions.SynchronizeAction.actionPerformed(SynchronizeAction.java:16)
    at com.intellij.openapi.actionSystem.ex.ActionUtil.doPerformActionOrShowPopup(ActionUtil.kt:374)
    at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks$lambda$7(ActionUtil.kt:343)
    at com.intellij.openapi.actionSystem.ex.ActionUtil$$Lambda/0x000000d00371ed28.run(Unknown Source)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.performWithActionCallbacks(ActionManagerImpl.kt:1173)
    at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.kt:342)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImplKt.doPerformAction$lambda$1(ActionManagerImpl.kt:1334)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImplKt$$Lambda/0x000000d00371e8a8.run(Unknown Source)
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:109)
    at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:98)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImplKt.doPerformAction(ActionManagerImpl.kt:1318)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImplKt.tryToExecuteNow(ActionManagerImpl.kt:1371)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImplKt.access$tryToExecuteNow(ActionManagerImpl.kt:1)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.tryToExecute(ActionManagerImpl.kt:1224)
    at com.illuminatedcloud.intellij.util.IcFileUtil.lambda$synchronizeFiles$8(SourceFile:723)

Now this is a situation where my plugin has generated an extensive set of project-specific TypeScript type definitions into the project directory structure that will be used as a TypeScript library, and it then needs to force the IDE to refresh the VFS so that it sees all of those library files.

In this specific situation, I found that just performing a refresh of VFS wasn’t working consistently, but if I then explicitly used File | Reload All from Disk, it caught up properly. As a result, I just added a method, IcFileUtil#synchronizeFiles(), that calls the following (simplified for sake of example) from the EDT just as if the user had explicitly triggered that action:

DumService.getInstance(project).smartInvokeLater(() ->
    ActionManager.getInstance().execute(ActionManager.getInstance().getAction(IdeActions.ACTION_SYNCHRONIZE), ...);
);

So this leads to two questions:

First, is there perhaps a better way to do what I’m needing to do here, i.e., refreshing VFS 100% reliably when I know that files have changed that need to be refreshed for the project to operate properly? I’m wondering if perhaps I should be calling VirtualFileManager#refreshFileWithoutFileWatcher(true) just as SynchronizeAction does.

UPDATE: It looks like calling SaveAndSyncHandler.getInstance().refreshOpenFiles() on the EDT followed by VirtualFileManager.getInstance().refreshWithoutFileWatcher(true) on a BGT may do the trick. That avoids SynchronizeAction’s FileDocumentManager.getInstance().saveAllDocuments() call that’s the main culprit in the stack trace above, and that’s not needed in this scenario anyway.

Second, how does the line gets drawn between third-party plugin behavior and core IDE behavior when attributing “…might be slowing things down” to one or the other? Yes, the stack trace for this thread technically goes through my plugin, but in this case, that EDT task logic is literally just using the IDE’s ActionManager to execute an IDE action.

Don’t get me wrong…I’m finding this information exceptionally useful and am actively using it to address as many of these types of behaviors as possible in my plugin, but for something like this, if I’m unable to find a reliable alternative for refreshing the VFS consistently, I’m concerned that such a confidence-shattering message might continue to be presented to users of my plugin for something not entirely under my control. Hopefully that concern makes sense…

Hi! Could you please share more/all thread-dumps for the report. The cause is a bit unclear to me from the one EDT trace since it was waiting for write action

Unfortunately that’s the only portion that the end user provided. I’ll ask if he can provide more details if/when it happens again…though hopefully it won’t with the changes I’ve made to avoid the need for the write lock since it’s no longer trying to commit all uncommitted documents just to refresh VFS.

Check the directory threadDumps-freeze at the timestamp of the slow log. Should give you a full thread dump and you can see which thread holds the lock.

At least that could be a way to investigate it.

Yeah, I’d asked the end user for the full thread dump at the same time stamp, but this happened late last week and the user hasn’t responded. My guess is that I’ll only get a full thread dump if/when this happens again.

1 Like

Will be nice if the default error reporter could attach a full thread dump, at least when we have this kind of error.

1 Like

100% agreed since that’s what’s being requested to diagnose the total thread state anyway.