Skip to content

Commit 35bc023

Browse files
authored
Skip reading CPU frequency from 'SystemCoreClock' after failure. (#658)
* Skip reading CPU frequency from 'SystemCoreClock' after failure. Retries after CPU Time Information reset. * Initial CPU frequency update if target not stopped after connect * Fix logic to keep previous frequency if getting undefined
1 parent bdc61cf commit 35bc023

3 files changed

Lines changed: 68 additions & 10 deletions

File tree

src/debug-session/gdbtarget-debug-session.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ import { PeriodicRefreshTimer } from './periodic-refresh-timer';
2525
*/
2626
export class GDBTargetDebugSession {
2727
public readonly refreshTimer: PeriodicRefreshTimer<GDBTargetDebugSession>;
28+
public readonly canAccessWhileRunning: boolean;
2829
private _cbuildRun: CbuildRunReader|undefined;
2930
private _cbuildRunParsePromise: Promise<void>|undefined;
3031

3132
constructor(public session: vscode.DebugSession) {
3233
this.refreshTimer = new PeriodicRefreshTimer(this);
33-
if (this.session.configuration.type === 'gdbtarget') {
34-
this.refreshTimer.enabled = this.session.configuration['auxiliaryGdb'] === true;
35-
}
34+
this.canAccessWhileRunning = this.session.configuration.type === 'gdbtarget' && this.session.configuration['auxiliaryGdb'] === true;
35+
this.refreshTimer.enabled = this.canAccessWhileRunning;
3636
}
3737

3838
public async getCbuildRun(): Promise<CbuildRunReader|undefined> {

src/features/cpu-states/cpu-states.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,17 @@ describe('CpuStates', () => {
188188
// eslint-disable-next-line @typescript-eslint/no-explicit-any
189189
(tracker as any)._onConnected.fire(gdbtargetDebugSession);
190190
await waitForMs(0);
191+
// Bring into stopped state
192+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
193+
(tracker as any)._onStopped.fire(createStoppedEvent(gdbtargetDebugSession, 'breakpoint', 0));
194+
await waitForMs(0);
191195
});
192196

193197
it('handles running state correctly', async () => {
198+
// Set running
199+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
200+
(tracker as any)._onContinued.fire(createContinuedEvent(gdbtargetDebugSession, 0));
201+
await waitForMs(0);
194202
// Considered running after connection
195203
expect(cpuStates.activeCpuStates?.isRunning).toEqual(true);
196204
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -329,6 +337,7 @@ describe('CpuStates', () => {
329337
(debugSession.customRequest as jest.Mock).mockRejectedValueOnce(new Error('test error'));
330338
await cpuStates.updateFrequency();
331339
expect(cpuStates.activeCpuStates).toBeDefined();
340+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(true);
332341
expect(cpuStates.activeCpuStates?.frequency).toBeUndefined();
333342
expect(cpuStates.activeCpuStates?.statesHistory.frequency).toBeUndefined();
334343
expect(await cpuStates.getActiveTimeString()).toEqual(' 0 states');
@@ -338,6 +347,8 @@ describe('CpuStates', () => {
338347
(debugSession.customRequest as jest.Mock).mockReturnValueOnce({ result: 'not a number' });
339348
await cpuStates.updateFrequency();
340349
expect(cpuStates.activeCpuStates).toBeDefined();
350+
// Not considered as severe error yet, so not skipping frequency updates
351+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(false);
341352
expect(cpuStates.activeCpuStates?.frequency).toBeUndefined();
342353
expect(cpuStates.activeCpuStates?.statesHistory.frequency).toBeUndefined();
343354
expect(await cpuStates.getActiveTimeString()).toEqual(' 0 states');
@@ -347,11 +358,40 @@ describe('CpuStates', () => {
347358
(debugSession.customRequest as jest.Mock).mockReturnValueOnce({ result: '12000000' });
348359
await cpuStates.updateFrequency();
349360
expect(cpuStates.activeCpuStates).toBeDefined();
361+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(false);
350362
expect(cpuStates.activeCpuStates?.frequency).toEqual(12000000);
351363
expect(cpuStates.activeCpuStates?.statesHistory.frequency).toEqual(12000000);
352364
expect(await cpuStates.getActiveTimeString()).toEqual(' 0ns');
353365
});
354366

367+
it('skips updating frequency after getting SystemCoreClock throws until next CPU states reset', async () => {
368+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(false);
369+
(debugSession.customRequest as jest.Mock).mockRejectedValueOnce(new Error('test error'));
370+
// First update causing CPU states to skip further updates, time string in states
371+
await cpuStates.updateFrequency();
372+
expect(cpuStates.activeCpuStates).toBeDefined();
373+
expect(cpuStates.activeCpuStates?.frequency).toBeUndefined();
374+
expect(cpuStates.activeCpuStates?.statesHistory.frequency).toBeUndefined();
375+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(true);
376+
expect(await cpuStates.getActiveTimeString()).toEqual(' 0 states');
377+
// Second update, valid frequency but still skipping frequency update, time string still in states
378+
(debugSession.customRequest as jest.Mock).mockResolvedValueOnce({ result: '12000000' });
379+
await cpuStates.updateFrequency();
380+
expect(cpuStates.activeCpuStates?.frequency).toBeUndefined();
381+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(true);
382+
expect(await cpuStates.getActiveTimeString()).toEqual(' 0 states');
383+
// Reset states, skipFrequencyUpdate reset to false
384+
cpuStates.resetStatesHistory();
385+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(false);
386+
// Now update again
387+
// Third update, valid frequency, time string now in time
388+
(debugSession.customRequest as jest.Mock).mockResolvedValueOnce({ result: '12000000' });
389+
await cpuStates.updateFrequency();
390+
expect(cpuStates.activeCpuStates?.frequency).toEqual(12000000);
391+
expect(cpuStates.activeCpuStates?.skipFrequencyUpdate).toEqual(false);
392+
expect(await cpuStates.getActiveTimeString()).toEqual(' 0ns');
393+
});
394+
355395
it('assigns frame location to captured stop point based on threadId match', async () => {
356396
const debugConsoleOutput: string[] = [];
357397
(vscode.debug.activeDebugConsole.appendLine as jest.Mock).mockImplementation(line => debugConsoleOutput.push(line));

src/features/cpu-states/cpu-states.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { GDBTargetDebugSession } from '../../debug-session/gdbtarget-debug-sessi
2626
import { CpuStatesHistory } from './cpu-states-history';
2727
import { calculateTime, extractPname } from '../../utils';
2828
import { GDBTargetConfiguration } from '../../debug-configuration';
29+
import { logger } from '../../logger';
2930

3031
// Architecturally defined registers (M-profile)
3132
const DWT_CTRL_ADDRESS = 0xE0001000;
@@ -41,6 +42,7 @@ interface SessionCpuStates {
4142
statesHistory: CpuStatesHistory;
4243
isRunning: boolean;
4344
hasStates: boolean|undefined;
45+
skipFrequencyUpdate: boolean;
4446
}
4547

4648
export class CpuStates {
@@ -75,7 +77,8 @@ export class CpuStates {
7577
frequency: undefined,
7678
statesHistory: new CpuStatesHistory(extractPname(session.session.name)),
7779
isRunning: true,
78-
hasStates: undefined
80+
hasStates: undefined,
81+
skipFrequencyUpdate: false
7982
};
8083
this.sessionCpuStates.set(session.session.id, states);
8184
session.refreshTimer.onRefresh(async (refreshSession) => this.handlePeriodicRefresh(refreshSession));
@@ -216,6 +219,10 @@ export class CpuStates {
216219
protected async getFrequency(): Promise<number|undefined> {
217220
const result = await this.activeSession?.evaluateGlobalExpression('SystemCoreClock');
218221
if (typeof result == 'string') {
222+
if (this.activeCpuStates) {
223+
// Do not retry until reset of CPU Time information
224+
this.activeCpuStates.skipFrequencyUpdate = true;
225+
}
219226
return undefined;
220227
}
221228
const frequencyString = result?.result.match(/\d+/) ? result.result : undefined;
@@ -252,11 +259,7 @@ export class CpuStates {
252259
return undefined;
253260
}
254261
const pname = await this.getActivePname();
255-
if (!this.activeCpuStates.isRunning) {
256-
// Only update frequency while stopped. User previous otherwise
257-
// to avoid switching between states and time display.
258-
await this.updateFrequency();
259-
}
262+
await this.updateFrequency();
260263
const cpuName = pname ? ` ${pname} ` : '';
261264
if (!this.activeHasStates()) {
262265
return `${cpuName} N/A`;
@@ -268,11 +271,25 @@ export class CpuStates {
268271
}
269272

270273
public async updateFrequency(): Promise<void> {
274+
// Only update frequency while stopped. Use previous otherwise
275+
// to avoid switching between states and time display.
271276
const states = this.activeCpuStates;
272-
if (!states) {
277+
if (!states || states.skipFrequencyUpdate) {
278+
// No states or frequency update disabled
273279
return;
274280
}
281+
if (this.activeCpuStates.isRunning && (this.activeCpuStates.frequency !== undefined || !this.activeSession?.canAccessWhileRunning)) {
282+
// Skip update while running if we already have a frequency (update after next stop to avoid jumpy time display),
283+
// or if session does not support access while running.
284+
return;
285+
}
286+
// Update frequency if stopped or if initial update while running and access while running supported.
275287
const frequency = await this.getFrequency();
288+
if (frequency === undefined) {
289+
// Keep previous frequency value to avoid toggling between states and time display if there was a frequency before.
290+
logger.debug(`CPU States: Unable to read frequency from target, keeping previous value '${states.frequency}' (Session: '${this.activeSession?.session.name})'`);
291+
return;
292+
}
276293
states.frequency = frequency;
277294
states.statesHistory.frequency = frequency;
278295
}
@@ -300,6 +317,7 @@ export class CpuStates {
300317
}
301318
states.statesHistory.resetHistory();
302319
states.states = BigInt(0);
320+
states.skipFrequencyUpdate = false;
303321
this._onRefresh.fire(0);
304322
}
305323
};

0 commit comments

Comments
 (0)