From 97d8f90657204315794da82ec344d7b3785b405d Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 13 Jun 2017 17:01:42 +0200 Subject: [PATCH] debug: have a scheduler per thread fixes #28536 --- .../parts/debug/common/debugModel.ts | 38 ++++++++++++------- .../debug/electron-browser/debugService.ts | 16 -------- .../debug/electron-browser/debugViewer.ts | 4 +- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 702ada257df..23f762661b4 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -9,6 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; +import * as errors from 'vs/base/common/errors'; +import { RunOnceScheduler } from 'vs/base/common/async'; import { clone } from 'vs/base/common/objects'; import severity from 'vs/base/common/severity'; import { isObject, isString } from 'vs/base/common/types'; @@ -435,22 +437,14 @@ export class Thread implements IThread { * Only fetches the first stack frame for performance reasons. Calling this method consecutive times * gets the remainder of the call stack. */ - public fetchCallStack(smartFetch = true): TPromise { + public fetchCallStack(levels = 20): TPromise { if (!this.stopped) { return TPromise.as(null); } - if (!this.fetchPromise && smartFetch) { - this.fetchPromise = this.getCallStackImpl(0, 1).then(callStack => { - this.callStack = callStack || []; - }); - } else { - this.fetchPromise = (this.fetchPromise || TPromise.as(null)).then(() => this.getCallStackImpl(this.callStack.length, 20).then(callStackSecondPart => { - this.callStack = this.callStack.concat(callStackSecondPart); - })); - } - - return this.fetchPromise; + return this.getCallStackImpl(this.callStack.length, levels).then(callStack => { + this.callStack = this.callStack.concat(callStack || []); + }); } private getCallStackImpl(startFrame: number, levels: number): TPromise { @@ -738,6 +732,7 @@ export class Model implements IModel { private processes: Process[]; private toDispose: lifecycle.IDisposable[]; private replElements: IReplElement[]; + private schedulers = new Map(); private _onDidChangeBreakpoints: Emitter; private _onDidChangeCallStack: Emitter; private _onDidChangeWatchExpressions: Emitter; @@ -805,6 +800,9 @@ export class Model implements IModel { public clearThreads(id: string, removeThreads: boolean, reference: number = undefined): void { const process = this.processes.filter(p => p.getId() === id).pop(); + this.schedulers.forEach(scheduler => scheduler.dispose()); + this.schedulers.clear(); + if (process) { process.clearThreads(removeThreads, reference); this._onDidChangeCallStack.fire(); @@ -812,7 +810,21 @@ export class Model implements IModel { } public fetchCallStack(thread: IThread): TPromise { - return (thread).fetchCallStack().then(() => { + return (thread).fetchCallStack(1).then(() => { + if (!this.schedulers.has(thread.getId())) { + this.schedulers.set(thread.getId(), new RunOnceScheduler(() => { + const callStack = thread.getCallStack(); + // Some adapters might not respect the number levels in StackTraceRequest and might + // return more stackFrames than requested. For those do not send an additional stackTrace request. + if (callStack.length <= 1) { + (thread).fetchCallStack(19).done(() => { + this._onDidChangeCallStack.fire(); + }, errors.onUnexpectedError); + } + }, 420)); + } + + this.schedulers.get(thread.getId()).schedule(); this._onDidChangeCallStack.fire(); }); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 0f363b20908..40c3ce62b05 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -7,7 +7,6 @@ import * as nls from 'vs/nls'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import * as paths from 'vs/base/common/paths'; -import { RunOnceScheduler } from 'vs/base/common/async'; import * as strings from 'vs/base/common/strings'; import { generateUuid } from 'vs/base/common/uuid'; import uri from 'vs/base/common/uri'; @@ -80,9 +79,7 @@ export class DebugService implements debug.IDebugService { private debugType: IContextKey; private debugState: IContextKey; private breakpointsToSendOnResourceSaved: Set; - private callStackScheduler: RunOnceScheduler; private launchJsonChanged: boolean; - private threadToFetch: debug.IThread; constructor( @IStorageService private storageService: IStorageService, @@ -121,17 +118,6 @@ export class DebugService implements debug.IDebugService { this.loadExceptionBreakpoints(), this.loadWatchExpressions()); this.toDispose.push(this.model); this.viewModel = new ViewModel(this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE, null)); - this.callStackScheduler = new RunOnceScheduler(() => { - if (this.threadToFetch) { - const callStack = this.threadToFetch.getCallStack(); - // Some adapters might not respect the number levels in StackTraceRequest and might - // return more stackFrames than requested. For those do not send an additional stackTrace request. - if (callStack.length <= 1) { - this.model.fetchCallStack(this.threadToFetch).done(() => - this.tryToAutoFocusStackFrame(this.threadToFetch), errors.onUnexpectedError); - } - } - }, 420); this.registerListeners(lifecycleService); } @@ -330,8 +316,6 @@ export class DebugService implements debug.IDebugService { // Call fetch call stack twice, the first only return the top stack frame. // Second retrieves the rest of the call stack. For performance reasons #25605 this.model.fetchCallStack(thread).then(() => { - this.threadToFetch = thread; - this.callStackScheduler.schedule(); return this.tryToAutoFocusStackFrame(thread); }); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index b7bd340b853..81b08439bd2 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -366,9 +366,9 @@ export class CallStackDataSource implements IDataSource { } private getThreadChildren(thread: Thread): TPromise { - const callStack: any[] = thread.getCallStack(); + let callStack: any[] = thread.getCallStack(); if (!callStack || !callStack.length) { - return thread.fetchCallStack(false).then(() => thread.getCallStack()); + thread.fetchCallStack().then(() => callStack = thread.getCallStack()); } if (callStack.length === 1) { // To reduce flashing of the call stack view simply append the stale call stack -- GitLab