scalameta / metals

Scala language server with rich IDE features 🚀

Home Page:https://scalameta.org/metals/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Formatting (i.e. using Scalafmt) is unnecessarily slow

crt-31 opened this issue · comments

Describe the bug

When using VSCode and doing the textDocument/formatting task, it is very slow on our large codebase. It should be super fast as it is when we run scalafmt from commandline.

Doing some investigation, it seems the issue lies on this call where the code is trying to obtain the projectRoot path, but it does a whole lot of (seemingly unecessary) processing like reading the database and determine builtools. In particular, it appears to perform the buildtool.digest() which is pretty slow on our large codebase.

val projectRoot = optProjectRoot.getOrElse(folder)

Expected behavior

It seems like the projectRoot (and build tools) should have already been figured out and don't need to be recalculated during a Format routine.

Hopefully this can be fixed soon so we can have super fast formatting.

Operating system

Windows

Editor/Extension

VS Code

Version of Metals

v1.2.2

Extra context or search terms

No response

Thanks for reporting! This seems super curious, it should be cached and and not an issue at all. Do you see it being recalculated every time?

commented

This is not fixed. I just tried latest code (as of 6/27/23) and the issue still remains.

We no longer recalculate build tools when formatting so it should be good, maybe that was not the reason for it being slow then?

I did another fix, but it would be good to see if what you're seeing is even related here.

commented

Tried your changes, still happening.
I think the problem is that its unecessarily calling the BuildTool.Digest function when it tries to get BuildTool object.

Here's the callstack

MavenBuildTool.digest(AbsolutePath): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\builds\MavenBuildTool.scala:61)
BuildTool.digestWithRetry(AbsolutePath,int): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\builds\BuildTool.scala:18)
BuildTool.digestWithRetry$(BuildTool,AbsolutePath,int): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\builds\BuildTool.scala:13)
MavenBuildTool.digestWithRetry(AbsolutePath,int): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\builds\MavenBuildTool.scala:9)
ProjectMetalsLspService.isCompatibleVersion(BuildTool): BuildTool$Verified (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\ProjectMetalsLspService.scala:809)
ProjectMetalsLspService.$anonfun$buildTool$3(ProjectMetalsLspService,BuildTool): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\ProjectMetalsLspService.scala:794)
ProjectMetalsLspService$$Lambda$1497/0x0000000801197988.apply(Object): Object (Unknown Source:-1)
Option.flatMap(Function1): Option (file:\\C:\Users\user\AppData\Local\Coursier\cache\v1\https\maven.local.com\artifactory\maven2\org\scala-lang\scala-library\2.13.10\scala-library-2.13.10-sources.jar!\scala\Option.scala:283)
ProjectMetalsLspService.$anonfun$buildTool$1(ProjectMetalsLspService,String): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\ProjectMetalsLspService.scala:793)
ProjectMetalsLspService$$Lambda$1495/0x0000000801196630.apply(Object): Object (Unknown Source:-1)
Option.flatMap(Function1): Option (file:\\C:\Users\user\AppData\Local\Coursier\cache\v1\https\maven.local.com\artifactory\maven2\org\scala-lang\scala-library\2.13.10\scala-library-2.13.10-sources.jar!\scala\Option.scala:283)
ProjectMetalsLspService.buildTool(): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\ProjectMetalsLspService.scala:792)
ProjectMetalsLspService.optProjectRoot(): Option (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\ProjectMetalsLspService.scala:439)
MetalsLspService.$anonfun$formatting$1(MetalsLspService,DocumentFormattingParams,CancelToken): Future (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\MetalsLspService.scala:1064)
MetalsLspService$$Lambda$5123/0x000000080198bdf0.apply(Object): Object (Unknown Source:-1)
CancelTokens$.future(Function1,ExecutionContextExecutorService): CompletableFuture (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\CancelTokens.scala:38)
MetalsLspService.formatting(DocumentFormattingParams): CompletableFuture (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\MetalsLspService.scala:1059)
WorkspaceLspService.formatting(DocumentFormattingParams): CompletableFuture (c:\SDKs\metals-main\metals\src\main\scala\scala\meta\internal\metals\WorkspaceLspService.scala:462)

Ach, good catch! #6561 should help then