Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow AST builds in code involving large array (e.g. 1000000 elements) #1808

Open
d0j1a1701 opened this issue Oct 19, 2023 · 28 comments
Open
Labels
enhancement New feature or request

Comments

@d0j1a1701
Copy link

I am an algorithmic competition participant, and I have a VSCode workspace where I have organized my code from various online judging systems into folders. The directory tree looks roughly like this:

OI (Workspace Root)
- Codeforces
- - CF001A.cpp
- - CF002B.cpp
- ATCoder
- - abc001_a.cpp
- - abc002_b.cpp
- luogu
- - P1001.cpp
- - P1002.cpp

Clearly, my problem files are independent of each other, and I don't need or want to include the contents of other files in one file. I only need to include system header files like iostream and vector.

However, when my problem repository folder reaches a certain size, I noticed that the response time of clangd becomes significantly slower. Below is a part of the clangd log where it can be observed that many operations take several thousand milliseconds.

I[10:43:16.044] Indexing c++2b standard library in the context of d:/Coding/OI/atcoder/abc261_g.cpp
I[10:43:16.195] Built preamble of size 7253168 for file d:/Coding/OI/atcoder/abc261_g.cpp version 1 in 0.97 seconds
......
I[10:43:18.601] Indexed c++2b standard library: 14142 symbols, 958 filtered
I[10:43:19.203] --> textDocument/publishDiagnostics
I[10:43:19.205] --> reply:textDocument/documentLink(1) 3818 ms, error: Task was cancelled.
[Error - 10:43:19] Request textDocument/documentLink failed.
[object Object]
I[10:43:19.205] --> reply:textDocument/inlayHint(2) 3809 ms, error: Task was cancelled.
I[10:43:19.206] --> reply:textDocument/inlayHint(3) 3801 ms, error: Task was cancelled.
[Error - 10:43:19] Request textDocument/inlayHint failed.
[object Object]
[Error - 10:43:19] Request textDocument/inlayHint failed.
[object Object]
I[10:43:19.207] --> reply:textDocument/semanticTokens/full(5) 3382 ms
I[10:43:19.208] --> reply:textDocument/documentLink(6) 3210 ms
I[10:43:19.209] --> reply:textDocument/documentSymbol(7) 2103 ms
I[10:43:19.210] --> reply:textDocument/inlayHint(8) 1800 ms
I[10:43:19.210] --> reply:textDocument/inlayHint(9) 1800 ms
I[10:43:19.211] --> reply:textDocument/codeAction(11) 793 ms

When I created a workspace with only one file, the performance of clangd returned to normal.

Playground (Workspace Root)
- test1.cpp

I suspect that Clangd scans the entire folder (or even the workspace) of code every time it performs autocompletion (even though I haven't included them). How can I change this behavior?

@d0j1a1701 d0j1a1701 added the enhancement New feature or request label Oct 19, 2023
@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 19, 2023

ADD: The performance issue do not occured in Linux. I don't know why.
clangd.log

@HighCommander4
Copy link

Clangd will only index the project if it contains a compile_commands.json file with entries for every source file in the project.

I assume that's not the case for you, so there should be no index to begin with.

when my problem repository folder reaches a certain size

How many source files are we talking about?

And how many of them are open? Does the slowness persist if you restart vscode (using the workspace with many files), but only open the one file you're working on?

@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 20, 2023

Clangd will only index the project if it contains a compile_commands.json file with entries for every source file in the project.

I assume that's not the case for you, so there should be no index to begin with.

when my problem repository folder reaches a certain size

How many source files are we talking about?

And how many of them are open? Does the slowness persist if you restart vscode (using the workspace with many files), but only open the one file you're working on?

Each source file is between 6-10kb (I use a fixed code template); there are about 50 files in a directory, and the entire workspace has about 250 files; even if I only leave one tab open, the lag issue still persists.

The typical states during lag are "File is queued" and "Parsing Includes," especially "Parsing Includes."

Even after restarting VSCode or clangd, the issue still persists.

@d0j1a1701 d0j1a1701 changed the title Prevent clangd to index the whole workspace. Performance issue. Oct 20, 2023
@d0j1a1701
Copy link
Author

This recording may give you a better understanding of my problem here.

capture.mp4

@HighCommander4
Copy link

The status bar showing "Parsing includes" as you're typing is expected, as clangd reparses the file in response to the edits you're making.

I'm also not seeing anything out of the ordinary in the posted video, but maybe I just don't know what to look for. What operation is taking longer than expected, and at what timestamp in the video is it performed?

One other thing I'll add is that 250 files should not be an issue, even if the project is indexed. I regularly use clangd with projects containing ~10,000 source files, and even with the project being indexed that doesn't really slow down the responsiveness of any editor operations.

@zyn0217
Copy link

zyn0217 commented Oct 23, 2023

I[23:08:12.423] (built by Brecht Sanders) clangd version 16.0.6
I[23:08:12.424] argv[0]: D:\Software\Mingw-w64\bin\clangd.EXE

I've noticed that this is not an official windows clangd release. Looking around the build source, I suspect the slowness you are confronted with relates to the WinLibs threading model. (They're both from the same author, right?)

However, I could not 100% conclude on this since I don't have a mingw-w64 installed nor enough knowledge on the windows threading model. One suggestion I could give is, why don't have a try with the official windows release? It is theoretically compatible with your msys / mingw terminal and should be a drop-in replacement for the clangd.exe you're using.

(And please let us know if the laggy behavior persists or disappears. :)

@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 26, 2023

I[23:08:12.423] (built by Brecht Sanders) clangd version 16.0.6
I[23:08:12.424] argv[0]: D:\Software\Mingw-w64\bin\clangd.EXE

I've noticed that this is not an official windows clangd release. Looking around the build source, I suspect the slowness you are confronted with relates to the WinLibs threading model. (They're both from the same author, right?)

However, I could not 100% conclude on this since I don't have a mingw-w64 installed nor enough knowledge on the windows threading model. One suggestion I could give is, why don't have a try with the official windows release? It is theoretically compatible with your msys / mingw terminal and should be a drop-in replacement for the clangd.exe you're using.

(And please let us know if the laggy behavior persists or disappears. :)

Yes! I'm using WinLibs. (MinGW-W64 x86_64-ucrt-mcf-seh)

But the official clangd.exe is using MSVC headers, how can i configure it to use GCC headers from WinLibs?

@zyn0217
Copy link

zyn0217 commented Oct 27, 2023

But the official clangd.exe is using MSVC headers, how can i configure it to use GCC headers from WinLibs?

One typical way is to have clangd extract the include paths from gcc using the --query-driver option. You may have to place the configuration file under your workspace (or a user directory, %LocalAppData%\clangd\ for windows.) with the fragment Compiler whose value matches the argument you've passed into --query-driver, i.e., the path to your winlib gcc compiler. (Also note that use the upper case drive letter at the moment; we've several bug reports on windows here.)

@d0j1a1701
Copy link
Author

But the official clangd.exe is using MSVC headers, how can i configure it to use GCC headers from WinLibs?

One typical way is to have clangd extract the include paths from gcc using the --query-driver option. You may have to place the configuration file under your workspace (or a user directory, %LocalAppData%\clangd\ for windows.) with the fragment Compiler whose value matches the argument you've passed into --query-driver, i.e., the path to your winlib gcc compiler. (Also note that use the upper case drive letter at the moment; we've several bug reports on windows here.)

I edited my Compiler fragment but nothing changed.

I[21:55:19.742] clangd version 17.0.3 (https://github.com/llvm/llvm-project 888437e1b60011b8a375dd30928ec925b448da57)
I[21:55:19.743] Features: windows+grpc
I[21:55:19.743] PID: 11700
I[21:55:19.743] Working directory: d:\Coding\OI
I[21:55:19.743] argv[0]: D:\Software\Mingw-w64\bin\clangd.EXE
I[21:55:19.749] Starting LSP over stdin/stdout
I[21:55:19.749] <-- initialize(0)
I[21:55:19.752] --> reply:initialize(0) 2 ms
I[21:55:19.754] <-- initialized
I[21:55:19.759] <-- textDocument/didOpen
I[21:55:19.762] --> textDocument/publishDiagnostics
I[21:55:19.763] Failed to find compilation database for d:\Coding\OI\luogu\P1640.cpp
I[21:55:19.763] ASTWorker building file d:\Coding\OI\luogu\P1640.cpp version 1 with command clangd fallback
[d:\Coding\OI\luogu]
"D:\\Software\\Mingw-w64\\bin\\g++" --driver-mode=g++ -xc++ -Wall -Wextra -Wno-unused-variable -std=gnu++2b "-resource-dir=D:\\Software\\Mingw-w64\\lib\\clang\\17" -- "d:\\Coding\\OI\\luogu\\P1640.cpp"
I[21:55:19.790] --> textDocument/clangd.fileStatus
I[21:55:19.911] <-- $/setTrace
I[21:55:19.911] unhandled notification $/setTrace
......

I[21:56:00.710] <-- textDocument/didOpen
I[21:56:00.711] Failed to find compilation database for d:\Coding\OI\luogu\P7506.cpp
I[21:56:00.711] ASTWorker building file d:\Coding\OI\luogu\P7506.cpp version 1 with command clangd fallback
[d:\Coding\OI\luogu]
"D:\\Software\\Mingw-w64\\bin\\g++" --driver-mode=g++ -xc++ -Wall -Wextra -Wno-unused-variable -std=gnu++2b "-resource-dir=D:\\Software\\Mingw-w64\\lib\\clang\\17" -- "d:\\Coding\\OI\\luogu\\P7506.cpp"
I[21:56:00.717] --> textDocument/clangd.fileStatus

config.yaml in %LocalAppData%\clangd\

If:
  PathMatch: .*\.cpp

CompileFlags:
  Add: [-xc++, -Wall, -Wextra, -Wno-unused-variable, -std=gnu++2b]
  Compiler: g++
  CompilationDatabase: None

Diagnostics:
  ClangTidy:
    Add: [performance*,bugprone*]
    Remove: [bugprone-narrowing-conversions,bugprone-use-after-move]
  UnusedIncludes: Strict

InlayHints:
  Enabled: Yes
  ParameterNames: Yes
  DeducedTypes: Yes
  Designators: No

---
If:
  PathMatch: .*\.c
CompileFlags:
  Add: [-xc, -Wall,-Wextra,-Wno-unused-variable,-std=C23]
  Compiler: gcc
  CompilationDatabase: None

@zyn0217
Copy link

zyn0217 commented Oct 27, 2023

I edited my Compiler fragment but nothing changed.

I might have overlooked something, but it seems that you're not running clangd with the --query-driver option. That being said, if your winlib gcc is located in D:\Software\Mingw-w64\bin\gcc.exe, then you have to tell your LSP client (e.g., vscode) to invoke the clangd with such a path:

D:\Software\Mingw-w64\bin\clangd.exe --query-driver="D:\Software\Mingw-w64\bin\gcc.exe"

Then make sure there are respective fragments in config.yaml:

CompileFlags:
  Add: ...
  Compiler: D:\Software\Mingw-w64\bin\gcc.exe

@d0j1a1701
Copy link
Author

I specified the --query-driver parameter in the clangd plugin of VSCode, and now it can recognize the WinLibs header files correctly. I will continue testing to determine if there is any lag. Thank you for your help!

@d0j1a1701 d0j1a1701 reopened this Oct 28, 2023
@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 28, 2023

The problem still exists, it's just that this time it's stuck at "Parsing Includes, parsing main file".

Every time I input a character, clangd takes about 2-3 seconds to respond with error messages and suggestions.

I[10:07:51.399] --> textDocument/clangd.fileStatus
I[10:07:51.852] <-- textDocument/semanticTokens/full/delta(913)
I[10:07:51.921] <-- textDocument/inlayHint(914)
I[10:07:51.921] <-- textDocument/inlayHint(915)
I[10:07:52.177] <-- textDocument/documentLink(916)
I[10:07:53.212] --> textDocument/publishDiagnostics
I[10:07:53.215] --> reply:textDocument/documentSymbol(912) 2010 ms
I[10:07:53.215] --> reply:textDocument/semanticTokens/full/delta(913) 1363 ms
I[10:07:53.215] --> reply:textDocument/inlayHint(914) 1294 ms
I[10:07:53.216] --> reply:textDocument/inlayHint(915) 1294 ms
I[10:07:53.216] --> reply:textDocument/documentLink(916) 1039 ms

@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 28, 2023

I believe it is not an issue with the Winlibs thread model, because when I switched the entire toolchain to MSYS2 (ucrt-gcc13-clang17), the problem still persisted

@zyn0217
Copy link

zyn0217 commented Oct 28, 2023

I[10:07:53.215] --> reply:textDocument/documentSymbol(912) 2010 ms
I[10:07:53.215] --> reply:textDocument/semanticTokens/full/delta(913) 1363 ms
I[10:07:53.215] --> reply:textDocument/inlayHint(914) 1294 ms
I[10:07:53.216] --> reply:textDocument/inlayHint(915) 1294 ms
I[10:07:53.216] --> reply:textDocument/documentLink(916) 1039 ms

This is, indeed, outrageously slow. For comparison, these actions usually take less than 10 ms on my Linux machine, even when I'm editing a medium-sized file with approx 1k ~ 2k lines. Let me setup a windows environment and see if I can reproduce it.

@HighCommander4 Shall we transfer this issue to the server repo?

@zyn0217
Copy link

zyn0217 commented Oct 28, 2023

So I can now reproduce the slowness. I've set up a windows dev with mingw-w64 gcc and clangd 17.0.2, and recovered the original code from the log above:

#include <iostream>
#include <vector>
using namespace std;
/* d0j1a_1701 FastIO full ver. 4.2 */
//#define FIO //缓存模式 请勿在交互题开启
struct IO {
#ifdef FIO
	const static int BUFSIZE = 1 << 20;
	char buf[BUFSIZE], obuf[BUFSIZE], *p1, *p2, *pp;
	inline char getchar() {
		return (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, BUFSIZE, stdin), p1 == p2) ? EOF : *p1++);
	}
	inline void putchar(char x) {
		((pp - obuf == BUFSIZE && (fwrite(obuf, 1, BUFSIZE, stdout), pp = obuf)), *pp = x, pp++);
	}
	inline IO &flush() {
		fwrite(obuf, 1, pp - obuf, stdout);
		fflush(stdout);
		return *this;
	}
	IO() {
		p1 = buf, p2 = buf, pp = obuf;
	}
	~IO() {
		flush();
	}
#else
	int (*getchar)() = &::getchar;
	int (*putchar)(int) = &::putchar;
	inline IO &flush() {
		fflush(stdout);
		return *this;
	};
#endif
	string sep = " ";
	int k = 2;
	template < typename Tp, typename std::enable_if < std::is_integral<Tp>::value || std::is_same<Tp, __int128_t>::value >::type * = nullptr >
	inline int read(Tp &s) {
		int f = 1;
		char ch = getchar();
		s = 0;
		while(!isdigit(ch) && ch != EOF)	f = (ch == '-' ? -1 : 1), ch = getchar();
		while(isdigit(ch))	s = s * 10 + (ch ^ 48), ch = getchar();
		s *= f;
		return ch != EOF;
	}
	template<typename Tp, typename enable_if<is_floating_point<Tp>::value>::type * = nullptr>
	inline int read(Tp &s) {
		int f = 1;
		char ch = getchar();
		s = 0;
		while(!isdigit(ch) && ch != EOF && ch != '.')	f = (ch == '-' ? -1 : 1), ch = getchar();
		while(isdigit(ch))	s = s * 10 + (ch ^ 48), ch = getchar();
		if(ch == EOF)	return false;
		if(ch == '.') {
			Tp eps = 0.1;
			ch = getchar();
			while(isdigit(ch))	s = s + (ch ^ 48) * eps, ch = getchar(), eps /= 10;
		}
		s *= f;
		return ch != EOF;
	}
	inline int read(char &c) {
		char ch = getchar();
		c = EOF;
		while(isspace(ch) && ch != EOF) ch = getchar();
		if(ch != EOF) c = ch;
		return c != EOF;
	}
	inline int read(char *c) {
		char ch = getchar(), *s = c;
		while(isspace(ch) && ch != EOF) ch = getchar();
		while(!isspace(ch) && ch != EOF) *(c++) = ch, ch = getchar();
		*c = '\\0';
		return s != c;
	}
	inline int read(string &s) {
		s.clear();
		char ch = getchar();
		while(isspace(ch) && ch != EOF) ch = getchar();
		while(!isspace(ch) && ch != EOF) s += ch, ch = getchar();
		return s.size() > 0;
	}
	inline int getline(char *c, const char &ed = '\\n') {
		char ch = getchar(), *s = c;
		while(ch != ed && ch != EOF)	*(c++) = ch, ch = getchar();
		*c = '\\0';
		return s != c;
	}
	inline int getline(string &s, const char &ed = '\\n') {
		s.clear();
		char ch = getchar();
		while(ch != ed && ch != EOF)	s += ch, ch = getchar();
		return s.size() > 0;
	}
	template<typename Tp = int>
	inline Tp read() {
		Tp x;
		read(x);
		return x;
	}
	template<typename Tp, typename... Ts>
	int read(Tp &x, Ts &...val) {
		return read(x) && read(val...);
	}
	template<typename Tp, typename enable_if<is_integral<Tp>::value>::type * = nullptr>
	IO & write(Tp x) {
		if(x < 0)	putchar('-'), x = -x;
		static char sta[20];
		int top = 0;
		do sta[top++] = x % 10 + '0', x /= 10;
		while(x);
		while(top)
			putchar(sta[--top]);
		return *this;
	}
	inline IO &write(const string &str) {
		for(char ch : str) putchar(ch);
		return *this;
	}
	inline IO &write(const char *str) {
		while(*str != '\0')	putchar(*(str++));
		return *this;
	}
	inline IO &write(char *str) {
		return write((const char *)str);
	}
	inline IO &write(const char &ch) {
		return putchar(ch), *this;
	}
	template<typename Tp, typename enable_if<is_floating_point<Tp>::value>::type * = nullptr>inline IO & write(Tp x) {
		if(x > 1e18 || x < -1e18) {
			write("[Floating point overflow]");
			throw;
		}
		if(x < 0)	putchar('-'), x = -x;
		const static long long pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 100000000000000000, 100000000000000000};
		const auto &n = pow10[k];
		long long whole = (int)x;
		double tmp = (x - whole) * n;
		long long frac = tmp;
		double diff = tmp - frac;
		if(diff > 0.5) {
			++frac;
			if(frac >= n)	frac = 0, ++whole;
		} else if(diff == 0.5 && ((frac == 0U) || (frac & 1U))) ++frac;
		write(whole);
		if(k == 0U) {
			diff = x - (double)whole;
			if((!(diff < 0.5) || (diff > 0.5)) && (whole & 1))
				++whole;
		} else {
			putchar('.');
			static char sta[20];
			int count = k, top = 0;
			while(frac) {
				sta[top++] = frac % 10 + '0';
				frac /= 10, count--;
			}
			while(count--) putchar('0');
			while(top) putchar(sta[--top]);
		}
		return *this;
	}
	template<typename Tp, typename... Ts>
	inline IO &write(Tp x, Ts... val) {
		write(x);
		write(sep);
		write(val...);
		return *this;
	}
	template<typename... Ts>
	inline IO &writeln(Ts... val) {
		write(val...);
		putchar('\n');
		return *this;
	}
	inline IO &writeln(void) {
		putchar('\n');
		return *this;
	}
	template<typename Tp>
	inline IO &writeWith(Tp x, const string &s = " ") {
		write(x), write(s);
		return *this;
	}
	inline IO &setsep(const string &s) {
		return sep = s, *this;
	}
	inline IO &setprec(const int &K) {
		return k = K, *this;
	}
} io;
vector<pair<int, int> > edges[100010];
int n;
int main() {
	io.read(n);
	for(int i = 1, u, v, w; i <= n; i++)
		io.read(u, v, w);

        edges[0].^  // The code completion takes long to respond here!
	system("pause");
	return 0;
}

I can clearly observe the slowness while typing something ordinary such as accessing a std::vector, as the log reveals:

I[13:27:15.956] ASTWorker building file f:\clangd-17.0.2\clangd_17.0.2\bin\main.cpp version 106 with command 
[F:\clangd-17.0.2\clangd_17.0.2\bin\]
"C:\\msys64\\mingw64\\bin\\g++.exe" --driver-mode=g++ -std=c++20 -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0 -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0/x86_64-w64-mingw32 -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0/backward -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include -isystem C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include-fixed --target=x86_64-w64-mingw32 "-resource-dir=F:\\clangd-17.0.2\\clangd_17.0.2\\lib\\clang\\17" -- "f:\\clangd-17.0.2\\clangd_17.0.2\\bin\\main.cpp"
I[13:27:15.958] --> textDocument/clangd.fileStatus
I[13:27:16.164] <-- textDocument/codeAction(463)
I[13:27:16.164] <-- $/cancelRequest
I[13:27:17.071] --> textDocument/publishDiagnostics
I[13:27:17.072] --> reply:textDocument/codeAction(459) 2127 ms, error: Task was cancelled.
[Error - 1:27:17 PM] Request textDocument/codeAction failed.
[object Object]
I[13:27:17.074] --> reply:textDocument/documentSymbol(460) 1755 ms
I[13:27:17.074] --> reply:textDocument/documentLink(461) 1650 ms
I[13:27:17.074] --> reply:textDocument/inlayHint(462) 1401 ms
I[13:27:17.074] --> reply:textDocument/codeAction(463) 910 ms
I[13:27:17.074] --> textDocument/clangd.fileStatus
I[13:27:17.236] <-- textDocument/semanticTokens/full/delta(464)
I[13:27:17.239] --> reply:textDocument/semanticTokens/full/delta(464) 2 ms
I[13:27:17.239] --> textDocument/clangd.fileStatus
I[13:27:17.331] <-- textDocument/codeAction(465)

I've also performed the same edit action on my Linux machine, and the time cost looks much more reasonable.

I[13:27:22.725] ASTWorker building file /tmp/slowness.cpp version 20 with command clangd fallback
[/tmp]
/usr/local/bin/clang -resource-dir=/repo/llvm-project-Build/Build/lib/clang/18 -- /tmp/slowness.cpp
I[13:27:22.726] --> textDocument/clangd.fileStatus
I[13:27:22.759] --> textDocument/publishDiagnostics
I[13:27:22.761] --> textDocument/clangd.fileStatus
I[13:27:22.882] <-- textDocument/foldingRange(19100)
I[13:27:22.883] --> reply:textDocument/foldingRange(19100) 0 ms
I[13:27:22.995] <-- textDocument/semanticTokens/full/delta(19101)
I[13:27:22.997] --> reply:textDocument/semanticTokens/full/delta(19101) 1 ms
I[13:27:22.997] --> textDocument/clangd.fileStatus
I[13:27:23.028] <-- textDocument/documentSymbol(19102)
I[13:27:23.029] --> reply:textDocument/documentSymbol(19102) 1 ms
I[13:27:23.029] --> textDocument/clangd.fileStatus
I[13:27:23.033] <-- textDocument/codeAction(19103)
I[13:27:23.033] --> reply:textDocument/codeAction(19103) 0 ms
I[13:27:23.033] --> textDocument/clangd.fileStatus
I[13:27:23.675] <-- textDocument/documentLink(19104)
I[13:27:23.675] --> reply:textDocument/documentLink(19104) 0 ms
I[13:27:23.675] --> textDocument/clangd.fileStatus
I[13:27:23.924] <-- textDocument/inlayHint(19105)
I[13:27:23.924] --> reply:textDocument/inlayHint(19105) 0 ms
I[13:27:23.924] --> textDocument/clangd.fileStatus

@zyn0217
Copy link

zyn0217 commented Oct 28, 2023

The sluggish responsiveness on code completion sheerly disappears if I reduce the array size to a smaller number, like 10.

vector<pair<int, int> > edges[100010];

to

vector<pair<int, int> > edges[10];

And why can't it be replicated on other platforms?

@zyn0217
Copy link

zyn0217 commented Oct 28, 2023

Simplified code snippet:

struct S {
  int data;
  void *ptr;
} s[1000000]; // Note the size here

int main() {
  s[0].^
}

One can observe the responsiveness latency cliff by adding one more 0 to the array size.

I recalled that we had a similar bug report on the fixed array size, llvm/llvm-project#63562. I'm not sure if it is the same, though.


Note that the same workaround mentioned in that issue applies too: use the standard prior to c++20.

CompileFlags:
  Add: [-std=c++17]

@d0j1a1701
Copy link
Author

Note that the same workaround mentioned in that issue applies too: use the standard prior to c++20. 请注意,同样的解决方法也适用于该问题:使用 C++20 之前的标准。

CompileFlags:
  Add: [-std=c++17]

Okay, I will use C++ 17 until the issue is resolved. I wish you smooth debugging and a prompt resolution to the problem.

@d0j1a1701
Copy link
Author

d0j1a1701 commented Oct 28, 2023

I remember that there was a similar bug in clangd before, where for extremely large struct static arrays like this, clangd would attempt to allocate all the memory at once, resulting in a significant memory usage. Perhaps it could be related to that?

struct S {
int data;
void *ptr;
} s[1000000];

@d0j1a1701
Copy link
Author

@zyn0217 I conducted the same test in Ubuntu LTS on WSL2 and found that this issue also exists in clangd on WSL2. The test code is the minimal reproducible code you provided.

I[14:42:44.483] Ubuntu clangd version 17.0.3 (++20231017073404+888437e1b600-1~exp1~20231017073515.55)
I[14:42:44.483] Features: linux+grpc
I[14:42:44.483] PID: 1335
I[14:42:44.484] Working directory: /mnt/d/coding/OI
......
I[14:43:32.333] --> reply:textDocument/codeAction(36) 1127 ms
I[14:43:32.333] --> reply:textDocument/semanticTokens/full/delta(38) 926 ms
I[14:43:32.333] --> reply:textDocument/documentSymbol(39) 851 ms

@zyn0217
Copy link

zyn0217 commented Oct 28, 2023

Perhaps it could be related to that?

Maybe. I don't have an available nightly build for Windows at the time, so it's hard to tell if this has been resolved recently. (The commit that issue links to does not appear to be cherry-picked to the 17.0.x branch, so I assume we won't see the fix until clangd 18, which ought to be rolled out in the 2024H1.)


and found that this issue also exists in clangd on WSL2.

Unfortunately, I can reproduce this as well, using a recently-built version of clangd on Linux. ;)

@d0j1a1701
Copy link
Author

Okay. However, the memory issue I mentioned probably occurred between 2020 and 2021.

@HighCommander4 HighCommander4 transferred this issue from clangd/vscode-clangd Oct 30, 2023
@HighCommander4
Copy link

@HighCommander4 Shall we transfer this issue to the server repo?

Transferred.

@HighCommander4 HighCommander4 changed the title Performance issue. Slow AST builds in code involving large array (e.g. 1000000 elements) Oct 30, 2023
@HighCommander4
Copy link

Some other bugs we have on file about code involving large arrays: #967, #1087 .

@d0j1a1701
Copy link
Author

Problem still NOT resolved with clangd 18.1.3(LLVM-Mingw Project)
image

#include <iostream>
using namespace std;
pair<int, int> arr[100000010];
int main() { return 0; }

@d0j1a1701
Copy link
Author

And the problem occured even if using "-std=c++17".

@kierankihn
Copy link

I met the same problem.

clangd will become very slow when I define a large array of std::pair

This problem only occurs on std::pair

I am using clangd 18.1.3 with ubuntu 22.04

@kierankihn
Copy link

In my case, clangd only consumes a lot of CPU but doesn't consume much memory.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants