Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ca23e0f

Browse files
fstasiAlberto Iannaccone
and
Alberto Iannaccone
authored
Improve Serial Monitor Performances (#524)
* wip * experimenting with websockets * WIP frontend performances * rewrote monitor print lines logic * truncate serial monitor output * split monitor widget in different files to improve readability and testability * serial monitor style and perfo * fix serial-monitor-messages box height * removed react autosizer * add unit tests for monitor utils (#522) * wip tests * test monitor utils * fix scroll issue Co-authored-by: Alberto Iannaccone <a.iannaccone@arduino.cc>
1 parent 7f8b227 commit ca23e0f

15 files changed

+908
-448
lines changed

‎arduino-ide-extension/package.json‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"test:watch": "mocha --watch --watch-files lib \"./lib/test/**/*.test.js\""
1919
},
2020
"dependencies": {
21-
"@grpc/grpc-js": "^1.1.1",
21+
"@grpc/grpc-js": "^1.3.7",
2222
"@theia/application-package": "next",
2323
"@theia/core": "next",
2424
"@theia/editor": "next",
@@ -64,6 +64,7 @@
6464
"fuzzy": "^0.1.3",
6565
"glob": "^7.1.6",
6666
"google-protobuf": "^3.11.4",
67+
"grpc": "^1.24.11",
6768
"hash.js": "^1.1.7",
6869
"is-valid-path": "^0.1.1",
6970
"js-yaml": "^3.13.1",
@@ -78,6 +79,7 @@
7879
"react-disable": "^0.1.0",
7980
"react-select": "^3.0.4",
8081
"react-tabs": "^3.1.2",
82+
"react-window": "^1.8.6",
8183
"semver": "^7.3.2",
8284
"string-natural-compare": "^2.0.3",
8385
"temp": "^0.9.1",
@@ -89,6 +91,7 @@
8991
"@types/chai": "^4.2.7",
9092
"@types/chai-string": "^1.4.2",
9193
"@types/mocha": "^5.2.7",
94+
"@types/react-window": "^1.8.5",
9295
"chai": "^4.2.0",
9396
"chai-string": "^1.5.0",
9497
"decompress": "^4.2.0",
@@ -97,6 +100,7 @@
97100
"download": "^7.1.0",
98101
"grpc_tools_node_protoc_ts": "^4.1.0",
99102
"mocha": "^7.0.0",
103+
"mockdate": "^3.0.5",
100104
"moment": "^2.24.0",
101105
"protoc": "^1.0.4",
102106
"shelljs": "^0.8.3",

‎arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -397,27 +397,28 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
397397
createWidget: () => context.container.get(MonitorWidget),
398398
}));
399399
// Frontend binding for the serial monitor service
400+
// bind(MonitorServiceClient)
401+
// .toDynamicValue((context) => {
402+
// const client = context.container.get(MonitorServiceClientImpl);
403+
// WebSocketConnectionProvider.createProxy(
404+
// context.container,
405+
// MonitorServicePath,
406+
// client
407+
// );
408+
// return client;
409+
// })
410+
// .inSingletonScope();
400411
bind(MonitorService)
401412
.toDynamicValue((context) => {
402413
const connection = context.container.get(WebSocketConnectionProvider);
403-
const client = context.container.get(MonitorServiceClientImpl);
414+
const client =
415+
context.container.get<MonitorServiceClient>(MonitorServiceClient);
404416
return connection.createProxy(MonitorServicePath, client);
405417
})
406418
.inSingletonScope();
407419
bind(MonitorConnection).toSelf().inSingletonScope();
408420
// Serial monitor service client to receive and delegate notifications from the backend.
409-
bind(MonitorServiceClientImpl).toSelf().inSingletonScope();
410-
bind(MonitorServiceClient)
411-
.toDynamicValue((context) => {
412-
const client = context.container.get(MonitorServiceClientImpl);
413-
WebSocketConnectionProvider.createProxy(
414-
context.container,
415-
MonitorServicePath,
416-
client
417-
);
418-
return client;
419-
})
420-
.inSingletonScope();
421+
bind(MonitorServiceClient).to(MonitorServiceClientImpl).inSingletonScope();
421422

422423
bind(WorkspaceService).toSelf().inSingletonScope();
423424
rebind(TheiaWorkspaceService).toService(WorkspaceService);

‎arduino-ide-extension/src/browser/monitor/monitor-connection.ts‎

Lines changed: 132 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
MonitorConfig,
99
MonitorError,
1010
Status,
11+
MonitorServiceClient,
1112
} from '../../common/protocol/monitor-service';
1213
import { BoardsServiceProvider } from '../boards/boards-service-provider';
1314
import {
@@ -16,7 +17,6 @@ import {
1617
BoardsService,
1718
AttachedBoardsChangeEvent,
1819
} from '../../common/protocol/boards-service';
19-
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
2020
import { BoardsConfig } from '../boards/boards-config';
2121
import { MonitorModel } from './monitor-model';
2222
import { NotificationCenter } from '../notification-center';
@@ -29,8 +29,8 @@ export class MonitorConnection {
2929
@inject(MonitorService)
3030
protected readonly monitorService: MonitorService;
3131

32-
@inject(MonitorServiceClientImpl)
33-
protected readonly monitorServiceClient: MonitorServiceClientImpl;
32+
@inject(MonitorServiceClient)
33+
protected readonly monitorServiceClient: MonitorServiceClient;
3434

3535
@inject(BoardsService)
3636
protected readonly boardsService: BoardsService;
@@ -59,7 +59,7 @@ export class MonitorConnection {
5959
/**
6060
* This emitter forwards all read events **iff** the connection is established.
6161
*/
62-
protected readonly onReadEmitter = new Emitter<{ message: string }>();
62+
protected readonly onReadEmitter = new Emitter<{ messages: string[] }>();
6363

6464
/**
6565
* Array for storing previous monitor errors received from the server, and based on the number of elements in this array,
@@ -71,112 +71,15 @@ export class MonitorConnection {
7171

7272
@postConstruct()
7373
protected init(): void {
74-
this.monitorServiceClient.onError(async (error) => {
75-
let shouldReconnect = false;
76-
if (this.state) {
77-
const { code, config } = error;
78-
const { board, port } = config;
79-
const options = { timeout: 3000 };
80-
switch (code) {
81-
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
82-
console.debug(
83-
`Connection was canceled by client: ${MonitorConnection.State.toString(
84-
this.state
85-
)}.`
86-
);
87-
break;
88-
}
89-
case MonitorError.ErrorCodes.DEVICE_BUSY: {
90-
this.messageService.warn(
91-
`Connection failed. Serial port is busy: ${Port.toString(port)}.`,
92-
options
93-
);
94-
shouldReconnect = this.autoConnect;
95-
this.monitorErrors.push(error);
96-
break;
97-
}
98-
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
99-
this.messageService.info(
100-
`Disconnected ${Board.toString(board, {
101-
useFqbn: false,
102-
})} from ${Port.toString(port)}.`,
103-
options
104-
);
105-
break;
106-
}
107-
case undefined: {
108-
this.messageService.error(
109-
`Unexpected error. Reconnecting ${Board.toString(
110-
board
111-
)} on port ${Port.toString(port)}.`,
112-
options
113-
);
114-
console.error(JSON.stringify(error));
115-
shouldReconnect = this.connected && this.autoConnect;
116-
break;
117-
}
118-
}
119-
const oldState = this.state;
120-
this.state = undefined;
121-
this.onConnectionChangedEmitter.fire(this.state);
122-
if (shouldReconnect) {
123-
if (this.monitorErrors.length >= 10) {
124-
this.messageService.warn(
125-
`Failed to reconnect ${Board.toString(board, {
126-
useFqbn: false,
127-
})} to the the serial-monitor after 10 consecutive attempts. The ${Port.toString(
128-
port
129-
)} serial port is busy. after 10 consecutive attempts.`
130-
);
131-
this.monitorErrors.length = 0;
132-
} else {
133-
const attempts = this.monitorErrors.length || 1;
134-
if (this.reconnectTimeout !== undefined) {
135-
// Clear the previous timer.
136-
window.clearTimeout(this.reconnectTimeout);
137-
}
138-
const timeout = attempts * 1000;
139-
this.messageService.warn(
140-
`Reconnecting ${Board.toString(board, {
141-
useFqbn: false,
142-
})} to ${Port.toString(port)} in ${attempts} seconds...`,
143-
{ timeout }
144-
);
145-
this.reconnectTimeout = window.setTimeout(
146-
() => this.connect(oldState.config),
147-
timeout
148-
);
149-
}
150-
}
151-
}
152-
});
74+
this.monitorServiceClient.onMessage(this.handleMessage.bind(this));
75+
this.monitorServiceClient.onError(this.handleError.bind(this));
15376
this.boardsServiceProvider.onBoardsConfigChanged(
15477
this.handleBoardConfigChange.bind(this)
15578
);
156-
this.notificationCenter.onAttachedBoardsChanged((event) => {
157-
if (this.autoConnect && this.connected) {
158-
const { boardsConfig } = this.boardsServiceProvider;
159-
if (
160-
this.boardsServiceProvider.canUploadTo(boardsConfig, {
161-
silent: false,
162-
})
163-
) {
164-
const { attached } = AttachedBoardsChangeEvent.diff(event);
165-
if (
166-
attached.boards.some(
167-
(board) =>
168-
!!board.port && BoardsConfig.Config.sameAs(boardsConfig, board)
169-
)
170-
) {
171-
const { selectedBoard: board, selectedPort: port } = boardsConfig;
172-
const { baudRate } = this.monitorModel;
173-
this.disconnect().then(() =>
174-
this.connect({ board, port, baudRate })
175-
);
176-
}
177-
}
178-
}
179-
});
79+
this.notificationCenter.onAttachedBoardsChanged(
80+
this.handleAttachedBoardsChanged.bind(this)
81+
);
82+
18083
// Handles the `baudRate` changes by reconnecting if required.
18184
this.monitorModel.onChange(({ property }) => {
18285
if (property === 'baudRate' && this.autoConnect && this.connected) {
@@ -186,6 +89,14 @@ export class MonitorConnection {
18689
});
18790
}
18891

92+
async handleMessage(port: string): Promise<void> {
93+
const w = new WebSocket(`ws://localhost:${port}`);
94+
w.onmessage = (res) => {
95+
const messages = JSON.parse(res.data);
96+
this.onReadEmitter.fire({ messages });
97+
};
98+
}
99+
189100
get connected(): boolean {
190101
return !!this.state;
191102
}
@@ -217,6 +128,109 @@ export class MonitorConnection {
217128
}
218129
}
219130

131+
handleError(error: MonitorError): void {
132+
let shouldReconnect = false;
133+
if (this.state) {
134+
const { code, config } = error;
135+
const { board, port } = config;
136+
const options = { timeout: 3000 };
137+
switch (code) {
138+
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
139+
console.debug(
140+
`Connection was canceled by client: ${MonitorConnection.State.toString(
141+
this.state
142+
)}.`
143+
);
144+
break;
145+
}
146+
case MonitorError.ErrorCodes.DEVICE_BUSY: {
147+
this.messageService.warn(
148+
`Connection failed. Serial port is busy: ${Port.toString(port)}.`,
149+
options
150+
);
151+
shouldReconnect = this.autoConnect;
152+
this.monitorErrors.push(error);
153+
break;
154+
}
155+
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
156+
this.messageService.info(
157+
`Disconnected ${Board.toString(board, {
158+
useFqbn: false,
159+
})} from ${Port.toString(port)}.`,
160+
options
161+
);
162+
break;
163+
}
164+
case undefined: {
165+
this.messageService.error(
166+
`Unexpected error. Reconnecting ${Board.toString(
167+
board
168+
)} on port ${Port.toString(port)}.`,
169+
options
170+
);
171+
console.error(JSON.stringify(error));
172+
shouldReconnect = this.connected && this.autoConnect;
173+
break;
174+
}
175+
}
176+
const oldState = this.state;
177+
this.state = undefined;
178+
this.onConnectionChangedEmitter.fire(this.state);
179+
if (shouldReconnect) {
180+
if (this.monitorErrors.length >= 10) {
181+
this.messageService.warn(
182+
`Failed to reconnect ${Board.toString(board, {
183+
useFqbn: false,
184+
})} to the the serial-monitor after 10 consecutive attempts. The ${Port.toString(
185+
port
186+
)} serial port is busy. after 10 consecutive attempts.`
187+
);
188+
this.monitorErrors.length = 0;
189+
} else {
190+
const attempts = this.monitorErrors.length || 1;
191+
if (this.reconnectTimeout !== undefined) {
192+
// Clear the previous timer.
193+
window.clearTimeout(this.reconnectTimeout);
194+
}
195+
const timeout = attempts * 1000;
196+
this.messageService.warn(
197+
`Reconnecting ${Board.toString(board, {
198+
useFqbn: false,
199+
})} to ${Port.toString(port)} in ${attempts} seconds...`,
200+
{ timeout }
201+
);
202+
this.reconnectTimeout = window.setTimeout(
203+
() => this.connect(oldState.config),
204+
timeout
205+
);
206+
}
207+
}
208+
}
209+
}
210+
211+
handleAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
212+
if (this.autoConnect && this.connected) {
213+
const { boardsConfig } = this.boardsServiceProvider;
214+
if (
215+
this.boardsServiceProvider.canUploadTo(boardsConfig, {
216+
silent: false,
217+
})
218+
) {
219+
const { attached } = AttachedBoardsChangeEvent.diff(event);
220+
if (
221+
attached.boards.some(
222+
(board) =>
223+
!!board.port && BoardsConfig.Config.sameAs(boardsConfig, board)
224+
)
225+
) {
226+
const { selectedBoard: board, selectedPort: port } = boardsConfig;
227+
const { baudRate } = this.monitorModel;
228+
this.disconnect().then(() => this.connect({ board, port, baudRate }));
229+
}
230+
}
231+
}
232+
}
233+
220234
async connect(config: MonitorConfig): Promise<Status> {
221235
if (this.connected) {
222236
const disconnectStatus = await this.disconnect();
@@ -231,15 +245,22 @@ export class MonitorConnection {
231245
);
232246
const connectStatus = await this.monitorService.connect(config);
233247
if (Status.isOK(connectStatus)) {
248+
let j = 0;
234249
const requestMessage = () => {
235-
this.monitorService.request().then(({ message }) => {
250+
this.monitorService.request().then(({ messages }) => {
236251
if (this.connected) {
237-
this.onReadEmitter.fire({ message });
252+
// this.onReadEmitter.fire({ messages });
253+
j += messages.length;
254+
if (j > 1000) {
255+
j = 0;
256+
// console.log(`read more than 1000 messages`);
257+
}
258+
238259
requestMessage();
239260
}
240261
});
241262
};
242-
requestMessage();
263+
// requestMessage();
243264
this.state = { config };
244265
console.info(
245266
`<<< Serial monitor connection created for ${Board.toString(
@@ -300,7 +321,7 @@ export class MonitorConnection {
300321
return this.onConnectionChangedEmitter.event;
301322
}
302323

303-
get onRead(): Event<{ message: string }> {
324+
get onRead(): Event<{ messages: string[] }> {
304325
return this.onReadEmitter.event;
305326
}
306327

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /