Skip to content

Commit 9dec544

Browse files
author
Akos Kitta
committed
feat: preference to limit thread count of the LS
Added a new preference (`arduino.language.asyncWorkers`) to control the number of async workers used by `clangd`. Users can use fine tune the `clangd` thread count to overcome excessive CPU usage. Ref: arduino/arduino-language-server#177 Signed-off-by: Akos Kitta <[email protected]>
1 parent dda7770 commit 9dec544

File tree

5 files changed

+60
-10
lines changed

5 files changed

+60
-10
lines changed

arduino-ide-extension/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,13 @@
169169
],
170170
"arduino": {
171171
"arduino-cli": {
172-
"version": "0.35.1"
172+
"version": "0.35.2"
173173
},
174174
"arduino-fwuploader": {
175175
"version": "2.4.1"
176176
},
177177
"arduino-language-server": {
178-
"version": "0.7.5"
178+
"version": "0.7.6"
179179
},
180180
"clangd": {
181181
"version": "14.0.0"

arduino-ide-extension/src/browser/arduino-preferences.ts

+15
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export function isMonitorWidgetDockPanel(
5454
return arg === 'bottom' || arg === 'right';
5555
}
5656

57+
export const defaultAsyncWorkers = 0 as const;
58+
export const minAsyncWorkers = defaultAsyncWorkers;
59+
export const maxAsyncWorkers = 8 as const;
60+
5761
type StrictPreferenceSchemaProperties<T extends object> = {
5862
[p in keyof T]: PreferenceSchemaProperty;
5963
};
@@ -79,6 +83,16 @@ const properties: ArduinoPreferenceSchemaProperties = {
7983
),
8084
default: false,
8185
},
86+
'arduino.language.asyncWorkers': {
87+
type: 'number',
88+
description: nls.localize(
89+
'arduino/preferences/language.asyncWorkers',
90+
'Number of async workers used by the Arduino Language Server (clangd). Background index also uses this many workers. The minimum value is 0, and the maximum is 8. When it is 0, the language server uses all available cores. The default value is 0.'
91+
),
92+
minimum: minAsyncWorkers,
93+
maximum: maxAsyncWorkers,
94+
default: defaultAsyncWorkers,
95+
},
8296
'arduino.compile.verbose': {
8397
type: 'boolean',
8498
description: nls.localize(
@@ -298,6 +312,7 @@ export const ArduinoConfigSchema: PreferenceSchema = {
298312
export interface ArduinoConfiguration {
299313
'arduino.language.log': boolean;
300314
'arduino.language.realTimeDiagnostics': boolean;
315+
'arduino.language.asyncWorkers': number;
301316
'arduino.compile.verbose': boolean;
302317
'arduino.compile.experimental': boolean;
303318
'arduino.compile.revealRange': ErrorRevealStrategy;

arduino-ide-extension/src/browser/contributions/ino-language.ts

+41-7
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@ import { inject, injectable } from '@theia/core/shared/inversify';
66
import { Mutex } from 'async-mutex';
77
import {
88
ArduinoDaemon,
9-
assertSanitizedFqbn,
109
BoardIdentifier,
1110
BoardsService,
1211
ExecutableService,
12+
assertSanitizedFqbn,
1313
isBoardIdentifierChangeEvent,
1414
sanitizeFqbn,
1515
} from '../../common/protocol';
16-
import { CurrentSketch } from '../sketches-service-client-impl';
16+
import {
17+
defaultAsyncWorkers,
18+
maxAsyncWorkers,
19+
minAsyncWorkers,
20+
} from '../arduino-preferences';
21+
import { BoardsDataStore } from '../boards/boards-data-store';
1722
import { BoardsServiceProvider } from '../boards/boards-service-provider';
1823
import { HostedPluginEvents } from '../hosted/hosted-plugin-events';
1924
import { NotificationCenter } from '../notification-center';
25+
import { CurrentSketch } from '../sketches-service-client-impl';
2026
import { SketchContribution, URI } from './contribution';
21-
import { BoardsDataStore } from '../boards/boards-data-store';
2227

2328
interface DaemonAddress {
2429
/**
@@ -76,6 +81,10 @@ interface StartLanguageServerParams {
7681
* If `true`, the logging is not forwarded to the _Output_ view via the language client.
7782
*/
7883
readonly silentOutput?: boolean;
84+
/**
85+
* Number of async workers used by `clangd`. Background index also uses this many workers. If `0`, `clangd` uses all available cores. It's `0` by default.
86+
*/
87+
readonly jobs?: number;
7988
}
8089

8190
/**
@@ -137,6 +146,7 @@ export class InoLanguage extends SketchContribution {
137146
switch (preferenceName) {
138147
case 'arduino.language.log':
139148
case 'arduino.language.realTimeDiagnostics':
149+
case 'arduino.language.asyncWorkers':
140150
forceRestart();
141151
}
142152
}
@@ -168,9 +178,12 @@ export class InoLanguage extends SketchContribution {
168178
}
169179
}),
170180
]);
171-
this.boardsServiceProvider.ready.then(() =>
172-
start(this.boardsServiceProvider.boardsConfig.selectedBoard)
173-
);
181+
Promise.all([
182+
this.boardsServiceProvider.ready,
183+
this.preferences.ready,
184+
]).then(() => {
185+
start(this.boardsServiceProvider.boardsConfig.selectedBoard);
186+
});
174187
}
175188

176189
onStop(): void {
@@ -230,11 +243,16 @@ export class InoLanguage extends SketchContribution {
230243
// NOOP
231244
return;
232245
}
233-
this.logger.info(`Starting language server: ${fqbnWithConfig}`);
234246
const log = this.preferences.get('arduino.language.log');
235247
const realTimeDiagnostics = this.preferences.get(
236248
'arduino.language.realTimeDiagnostics'
237249
);
250+
const jobs = this.getAsyncWorkersPreferenceSafe();
251+
this.logger.info(
252+
`Starting language server: ${fqbnWithConfig}${
253+
jobs ? ` (async worker count: ${jobs})` : ''
254+
}`
255+
);
238256
let currentSketchPath: string | undefined = undefined;
239257
if (log) {
240258
const currentSketch = await this.sketchServiceClient.currentSketch();
@@ -273,6 +291,7 @@ export class InoLanguage extends SketchContribution {
273291
},
274292
realTimeDiagnostics,
275293
silentOutput: true,
294+
jobs,
276295
}),
277296
]);
278297
} catch (e) {
@@ -283,6 +302,21 @@ export class InoLanguage extends SketchContribution {
283302
release();
284303
}
285304
}
305+
// The Theia preference UI validation is bogus.
306+
// To restrict the number of jobs to a valid value.
307+
private getAsyncWorkersPreferenceSafe(): number {
308+
const jobs = this.preferences.get(
309+
'arduino.language.asyncWorkers',
310+
defaultAsyncWorkers
311+
);
312+
if (jobs < minAsyncWorkers) {
313+
return minAsyncWorkers;
314+
}
315+
if (jobs > maxAsyncWorkers) {
316+
return maxAsyncWorkers;
317+
}
318+
return jobs;
319+
}
286320

287321
private async start(
288322
params: StartLanguageServerParams

electron-app/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@
196196
"theiaPlugins": {
197197
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
198198
"vscode-arduino-api": "https://github.com/dankeboy36/vscode-arduino-api/releases/download/0.1.2/vscode-arduino-api-0.1.2.vsix",
199-
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.1.1.vsix",
199+
"vscode-arduino-tools": "https://github.com/kittaakos/vscode-arduino-tools/raw/arduino/arduino-language-server%23177-VSIX/build-artifacts/vscode-arduino-tools-0.1.2.vsix",
200200
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
201201
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",
202202
"cortex-debug": "https://downloads.arduino.cc/marus25.cortex-debug/marus25.cortex-debug-1.5.1.vsix",

i18n/en.json

+1
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@
385385
"invalid.editorFontSize": "Invalid editor font size. It must be a positive integer.",
386386
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
387387
"invalid.theme": "Invalid theme.",
388+
"language.asyncWorkers": "Number of async workers used by the Arduino Language Server (clangd). Background index also uses this many workers. The minimum value is 0, and the maximum is 8. When it is 0, the language server uses all available cores. The default value is 0.",
388389
"language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.",
389390
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
390391
"manualProxy": "Manual proxy configuration",

0 commit comments

Comments
 (0)