提交 97d8f906 编写于 作者: I isidor

debug: have a scheduler per thread

fixes #28536
上级 cf06cc07
...@@ -9,6 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; ...@@ -9,6 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base';
import * as lifecycle from 'vs/base/common/lifecycle'; import * as lifecycle from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import { generateUuid } from 'vs/base/common/uuid'; 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 { clone } from 'vs/base/common/objects';
import severity from 'vs/base/common/severity'; import severity from 'vs/base/common/severity';
import { isObject, isString } from 'vs/base/common/types'; import { isObject, isString } from 'vs/base/common/types';
...@@ -435,22 +437,14 @@ export class Thread implements IThread { ...@@ -435,22 +437,14 @@ export class Thread implements IThread {
* Only fetches the first stack frame for performance reasons. Calling this method consecutive times * Only fetches the first stack frame for performance reasons. Calling this method consecutive times
* gets the remainder of the call stack. * gets the remainder of the call stack.
*/ */
public fetchCallStack(smartFetch = true): TPromise<void> { public fetchCallStack(levels = 20): TPromise<void> {
if (!this.stopped) { if (!this.stopped) {
return TPromise.as(null); return TPromise.as(null);
} }
if (!this.fetchPromise && smartFetch) { return this.getCallStackImpl(this.callStack.length, levels).then(callStack => {
this.fetchPromise = this.getCallStackImpl(0, 1).then(callStack => { this.callStack = this.callStack.concat(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;
} }
private getCallStackImpl(startFrame: number, levels: number): TPromise<IStackFrame[]> { private getCallStackImpl(startFrame: number, levels: number): TPromise<IStackFrame[]> {
...@@ -738,6 +732,7 @@ export class Model implements IModel { ...@@ -738,6 +732,7 @@ export class Model implements IModel {
private processes: Process[]; private processes: Process[];
private toDispose: lifecycle.IDisposable[]; private toDispose: lifecycle.IDisposable[];
private replElements: IReplElement[]; private replElements: IReplElement[];
private schedulers = new Map<string, RunOnceScheduler>();
private _onDidChangeBreakpoints: Emitter<void>; private _onDidChangeBreakpoints: Emitter<void>;
private _onDidChangeCallStack: Emitter<void>; private _onDidChangeCallStack: Emitter<void>;
private _onDidChangeWatchExpressions: Emitter<IExpression>; private _onDidChangeWatchExpressions: Emitter<IExpression>;
...@@ -805,6 +800,9 @@ export class Model implements IModel { ...@@ -805,6 +800,9 @@ export class Model implements IModel {
public clearThreads(id: string, removeThreads: boolean, reference: number = undefined): void { public clearThreads(id: string, removeThreads: boolean, reference: number = undefined): void {
const process = this.processes.filter(p => p.getId() === id).pop(); const process = this.processes.filter(p => p.getId() === id).pop();
this.schedulers.forEach(scheduler => scheduler.dispose());
this.schedulers.clear();
if (process) { if (process) {
process.clearThreads(removeThreads, reference); process.clearThreads(removeThreads, reference);
this._onDidChangeCallStack.fire(); this._onDidChangeCallStack.fire();
...@@ -812,7 +810,21 @@ export class Model implements IModel { ...@@ -812,7 +810,21 @@ export class Model implements IModel {
} }
public fetchCallStack(thread: IThread): TPromise<void> { public fetchCallStack(thread: IThread): TPromise<void> {
return (<Thread>thread).fetchCallStack().then(() => { return (<Thread>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>thread).fetchCallStack(19).done(() => {
this._onDidChangeCallStack.fire();
}, errors.onUnexpectedError);
}
}, 420));
}
this.schedulers.get(thread.getId()).schedule();
this._onDidChangeCallStack.fire(); this._onDidChangeCallStack.fire();
}); });
} }
......
...@@ -7,7 +7,6 @@ import * as nls from 'vs/nls'; ...@@ -7,7 +7,6 @@ import * as nls from 'vs/nls';
import * as lifecycle from 'vs/base/common/lifecycle'; import * as lifecycle from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import * as paths from 'vs/base/common/paths'; import * as paths from 'vs/base/common/paths';
import { RunOnceScheduler } from 'vs/base/common/async';
import * as strings from 'vs/base/common/strings'; import * as strings from 'vs/base/common/strings';
import { generateUuid } from 'vs/base/common/uuid'; import { generateUuid } from 'vs/base/common/uuid';
import uri from 'vs/base/common/uri'; import uri from 'vs/base/common/uri';
...@@ -80,9 +79,7 @@ export class DebugService implements debug.IDebugService { ...@@ -80,9 +79,7 @@ export class DebugService implements debug.IDebugService {
private debugType: IContextKey<string>; private debugType: IContextKey<string>;
private debugState: IContextKey<string>; private debugState: IContextKey<string>;
private breakpointsToSendOnResourceSaved: Set<string>; private breakpointsToSendOnResourceSaved: Set<string>;
private callStackScheduler: RunOnceScheduler;
private launchJsonChanged: boolean; private launchJsonChanged: boolean;
private threadToFetch: debug.IThread;
constructor( constructor(
@IStorageService private storageService: IStorageService, @IStorageService private storageService: IStorageService,
...@@ -121,17 +118,6 @@ export class DebugService implements debug.IDebugService { ...@@ -121,17 +118,6 @@ export class DebugService implements debug.IDebugService {
this.loadExceptionBreakpoints(), this.loadWatchExpressions()); this.loadExceptionBreakpoints(), this.loadWatchExpressions());
this.toDispose.push(this.model); this.toDispose.push(this.model);
this.viewModel = new ViewModel(this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE, null)); 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); this.registerListeners(lifecycleService);
} }
...@@ -330,8 +316,6 @@ export class DebugService implements debug.IDebugService { ...@@ -330,8 +316,6 @@ export class DebugService implements debug.IDebugService {
// Call fetch call stack twice, the first only return the top stack frame. // 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 // Second retrieves the rest of the call stack. For performance reasons #25605
this.model.fetchCallStack(thread).then(() => { this.model.fetchCallStack(thread).then(() => {
this.threadToFetch = thread;
this.callStackScheduler.schedule();
return this.tryToAutoFocusStackFrame(thread); return this.tryToAutoFocusStackFrame(thread);
}); });
} }
......
...@@ -366,9 +366,9 @@ export class CallStackDataSource implements IDataSource { ...@@ -366,9 +366,9 @@ export class CallStackDataSource implements IDataSource {
} }
private getThreadChildren(thread: Thread): TPromise<any> { private getThreadChildren(thread: Thread): TPromise<any> {
const callStack: any[] = thread.getCallStack(); let callStack: any[] = thread.getCallStack();
if (!callStack || !callStack.length) { if (!callStack || !callStack.length) {
return thread.fetchCallStack(false).then(() => thread.getCallStack()); thread.fetchCallStack().then(() => callStack = thread.getCallStack());
} }
if (callStack.length === 1) { if (callStack.length === 1) {
// To reduce flashing of the call stack view simply append the stale call stack // To reduce flashing of the call stack view simply append the stale call stack
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册