提交 f4c2b4d1 编写于 作者: I isidor

debug: fetch first call stack to improve perf

#25605
上级 e1386fea
......@@ -371,15 +371,15 @@ export class StackFrame implements IStackFrame {
}
export class Thread implements IThread {
private promisedCallStack: TPromise<IStackFrame[]>;
private cachedCallStack: IStackFrame[];
private fetchPromise: TPromise<void>;
private callStack: IStackFrame[];
public stoppedDetails: IRawStoppedDetails;
public stopped: boolean;
constructor(public process: IProcess, public name: string, public threadId: number) {
this.promisedCallStack = null;
this.fetchPromise = null;
this.stoppedDetails = null;
this.cachedCallStack = null;
this.callStack = null;
this.stopped = false;
}
......@@ -388,43 +388,41 @@ export class Thread implements IThread {
}
public clearCallStack(): void {
this.promisedCallStack = null;
this.cachedCallStack = null;
this.fetchPromise = null;
this.callStack = null;
}
public getCallStack(): IStackFrame[] {
return this.cachedCallStack;
return this.callStack;
}
/**
* Queries the debug adapter for the callstack and returns a promise with
* the stack frames of the callstack.
* Queries the debug adapter for the callstack and returns a promise
* which completes once the call stack has been retrieved.
* If the thread is not stopped, it returns a promise to an empty array.
* Only gets the first 20 stack frames. Calling this method consecutive times
* with getAdditionalStackFrames = true gets the remainder of the call stack.
* Only fetches the first stack frame for performance reasons. Calling this method consecutive times
* gets the remainder of the call stack.
*/
public fetchCallStack(getAdditionalStackFrames = false): TPromise<IStackFrame[]> {
public fetchCallStack(): TPromise<void> {
if (!this.stopped) {
return TPromise.as([]);
return TPromise.as(null);
}
if (!this.promisedCallStack) {
this.promisedCallStack = this.getCallStackImpl(0).then(callStack => {
this.cachedCallStack = callStack;
return callStack;
if (!this.fetchPromise) {
this.fetchPromise = this.getCallStackImpl(0, 1).then(callStack => {
this.callStack = callStack || [];
});
} else if (getAdditionalStackFrames) {
this.promisedCallStack = this.promisedCallStack.then(callStackFirstPart => this.getCallStackImpl(callStackFirstPart.length).then(callStackSecondPart => {
this.cachedCallStack = callStackFirstPart.concat(callStackSecondPart);
return this.cachedCallStack;
} else {
this.fetchPromise = this.fetchPromise.then(() => this.getCallStackImpl(this.callStack.length, 20).then(callStackSecondPart => {
this.callStack = this.callStack.concat(callStackSecondPart);
}));
}
return this.promisedCallStack;
return this.fetchPromise;
}
private getCallStackImpl(startFrame: number): TPromise<IStackFrame[]> {
return this.process.session.stackTrace({ threadId: this.threadId, startFrame, levels: 20 }).then(response => {
private getCallStackImpl(startFrame: number, levels: number): TPromise<IStackFrame[]> {
return this.process.session.stackTrace({ threadId: this.threadId, startFrame, levels }).then(response => {
if (!response || !response.body) {
return [];
}
......@@ -781,6 +779,12 @@ export class Model implements IModel {
}
}
public fetchCallStack(thread: Thread): TPromise<void> {
return thread.fetchCallStack().then(() => {
this._onDidChangeCallStack.fire();
});
}
public getBreakpoints(): Breakpoint[] {
return this.breakpoints;
}
......
......@@ -291,7 +291,15 @@ export class DebugService implements debug.IDebugService {
const thread = process && process.getThread(threadId);
if (thread) {
thread.fetchCallStack().then(callStack => {
// 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(() => {
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) {
this.model.fetchCallStack(thread).done(undefined, errors.onUnexpectedError);
}
if (callStack.length > 0 && !this.viewModel.focusedStackFrame) {
// focus first stack frame from top that has source location if no other stack frame is focussed
const stackFrameToFocus = first(callStack, sf => sf.source && sf.source.available, callStack[0]);
......
......@@ -271,7 +271,7 @@ export class CallStackController extends BaseDebugController {
const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === threadAndProcessIds.processId).pop();
const thread = process && process.getThread(threadAndProcessIds.threadId);
if (thread) {
(<Thread>thread).fetchCallStack(true)
(<Thread>thread).fetchCallStack()
.done(() => tree.refresh(), errors.onUnexpectedError);
}
......@@ -363,6 +363,10 @@ export class CallStackDataSource implements IDataSource {
private getThreadChildren(thread: Thread): any[] {
const callStack: any[] = thread.getCallStack();
if (!callStack) {
return [];
}
if (thread.stoppedDetails && thread.stoppedDetails.framesErrorMessage) {
return callStack.concat([thread.stoppedDetails.framesErrorMessage]);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册