Skip to content

Commit 551fa6f

Browse files
committed
adding tooltip
1 parent 0a4f014 commit 551fa6f

File tree

5 files changed

+228
-57
lines changed

5 files changed

+228
-57
lines changed

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function activate(context: vscode.ExtensionContext)
6868
context.subscriptions.push(new CodeAnalyticsView(analyticsProvider, documentInfoProvider,
6969
context.extensionUri, editorHelper, workspaceState, codeLensProvider, envStatusbar, environmentManager,spanLinkResolver, documentInfoCache));
7070
context.subscriptions.push(new ErrorsLineDecorator(documentInfoProvider));
71-
context.subscriptions.push(new PerformanceDecorator(documentInfoProvider,workspaceState ));
71+
context.subscriptions.push(new PerformanceDecorator(documentInfoProvider,workspaceState, codeInspector ));
7272
context.subscriptions.push(new HotspotMarkerDecorator(documentInfoProvider));
7373
context.subscriptions.push(new VsCodeDebugInstrumentation(analyticsProvider));
7474

src/services/codeInspector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type DefinitionWithTokens = Definition & {
1515

1616
export class CodeInspector {
1717

18-
public async getExecuteDefinitionMethodInfo(
18+
public async getExecuteDefinitionMethodInfo(
1919
usageDocument: vscode.TextDocument,
2020
usagePosition: vscode.Position,
2121
documentInfoProvider: DocumentInfoProvider,

src/services/methodCallErrorTooltip.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class MethodCallErrorHoverProvider implements vscode.HoverProvider
4444
) {
4545
}
4646

47-
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined>
47+
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined>
4848
{
4949
const sourceDocInfo = await this._documentInfoProvider.getDocumentInfo(document);
5050
if(!sourceDocInfo) {
@@ -119,7 +119,7 @@ class MethodCallErrorHoverProvider implements vscode.HoverProvider
119119
const spanName = durationInsight.span.displayName;
120120

121121
if (p50 || p95){
122-
markdown.appendText(`${spanName} Duration: `)
122+
markdown.appendText(`${spanName} Duration: `);
123123
if (p50!=null){
124124
markdown.appendText(`${p50.currentDuration.value} ${p50.currentDuration.unit} (Median) `);
125125
}

src/views/codeAnalytics/codeAnalyticsView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ class CodeAnalyticsViewProvider implements vscode.WebviewViewProvider,vscode.Dis
445445
this._overlay.hide();
446446
}
447447
this._currentCodeObject = codeObject;
448-
// await vscode.commands.executeCommand(PerformanceDecorator.Commands.Show);
448+
await vscode.commands.executeCommand(PerformanceDecorator.Commands.Show);
449449

450450

451451
}

src/views/codeAnalytics/decorators/performanceDecorator.ts

Lines changed: 223 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { nextTick } from 'process';
12
import * as vscode from 'vscode';
2-
import { DocumentInfoProvider, LineInfo } from '../../../services/documentInfoProvider';
3+
import { CodeInspector } from '../../../services/codeInspector';
4+
import { DocumentInfo, DocumentInfoProvider, LineInfo, MethodInfo } from '../../../services/documentInfoProvider';
5+
import { Token } from '../../../services/languages/tokens';
36
import { WorkspaceState } from '../../../state';
47
import { SpanDurationsInsight } from '../InsightListView/SpanInsight';
58

@@ -13,9 +16,11 @@ export class PerformanceDecorator implements vscode.Disposable
1316
private _iconDecorationType: vscode.TextEditorDecorationType;
1417
private _textDecorationType: vscode.TextEditorDecorationType;
1518
private _disposables: vscode.Disposable[] = [];
19+
readonly recursionLimit = 2;
1620

1721
constructor(private _documentInfoProvider: DocumentInfoProvider,
18-
private _workspaceState: WorkspaceState
22+
private _workspaceState: WorkspaceState,
23+
private _codeInspector: CodeInspector
1924
)
2025
{
2126
this._iconDecorationType = vscode.window.createTextEditorDecorationType({
@@ -37,80 +42,246 @@ export class PerformanceDecorator implements vscode.Disposable
3742
this._disposables.push(vscode.commands.registerCommand(PerformanceDecorator.Commands.Hide, this.onHide.bind(this)));
3843
}
3944

40-
private async onShow()
41-
{
45+
private getDisplayDuration(totalDuration : number):string{
4246

43-
const editor = vscode.window.activeTextEditor;
44-
if(!editor)
47+
let rawValue = (totalDuration / 1000000);
48+
let unit = "ms";
49+
if (rawValue>1000){
50+
rawValue = rawValue/1000;
51+
unit = "sec";
52+
53+
if (rawValue>60){
54+
unit = "min";
55+
rawValue = rawValue/60;
56+
57+
}
58+
}
59+
return `~${rawValue.toFixed(2)} ${unit}`;
60+
}
61+
62+
private getTotalDurationFromInsights(docInfo:DocumentInfo, method:MethodInfo) : number|undefined{
63+
64+
const insights = docInfo.insights.forMethod(method,this._workspaceState.environment)
65+
.filter(x=>x.name==="Performance Stats");
66+
67+
const percentileInfo = insights.map(x=>x as SpanDurationsInsight)
68+
.flatMap(x=>x.percentiles).filter(x=>x.currentDuration);
69+
70+
if (percentileInfo.length===0){
4571
return;
72+
}
4673

47-
const docInfo = await this._documentInfoProvider.getDocumentInfo(editor.document);
48-
if(!docInfo)
74+
const totalDuration = percentileInfo.filter(x=>x.percentile==0.5).map(x=>x.currentDuration.raw)
75+
.reduce((acc, val)=>acc + val,0);
76+
77+
if (totalDuration===0){
4978
return;
79+
}
80+
81+
return totalDuration;
82+
}
83+
84+
private async discoverIndirectDurationRecursive( document: vscode.TextDocument,
85+
docInfo:DocumentInfo,
86+
methodInfo: MethodInfo,
87+
functions:Token[], recursionDepth: number) : Promise<number | undefined> {
88+
if (recursionDepth>this.recursionLimit){
89+
return undefined;
90+
}
91+
92+
let totalDurationSum: number|undefined = undefined;
93+
94+
for (const func of functions.filter(x=>x.range.intersection(methodInfo.range))){
95+
96+
if (func.text === methodInfo.name && func.range === methodInfo.nameRange){
97+
const completeDuration = this.getTotalDurationFromInsights(docInfo,methodInfo);
98+
if (completeDuration){
99+
return completeDuration;
100+
}
101+
continue;
102+
}
103+
104+
const remoteMethodInfo =
105+
await this._codeInspector.getExecuteDefinitionMethodInfo(document, func.range.start, this._documentInfoProvider);
50106

51-
let decorators : vscode.DecorationOptions[] = [];
107+
if(!remoteMethodInfo) {
108+
continue;
109+
}
110+
const remoteDoc = await this._codeInspector.getDocumentInfo(document, func.range.start, this._documentInfoProvider);
111+
if(!remoteDoc) {
112+
continue;
113+
}
114+
115+
let totalDuration = this.getTotalDurationFromInsights(remoteDoc, remoteMethodInfo);
116+
if (!totalDuration){
117+
118+
const nextDoc = await vscode.workspace.openTextDocument(remoteDoc.uri);
119+
if (nextDoc){
120+
totalDuration = await this.discoverIndirectDurationRecursive(nextDoc,
121+
remoteDoc,
122+
remoteMethodInfo,remoteDoc.tokens.filter(x=>x.type==='function'),
123+
recursionDepth++);
124+
}
52125

53-
for (const method of docInfo.methods){
126+
}
127+
128+
if (totalDuration && !totalDurationSum){
129+
totalDurationSum= totalDuration;
130+
}
131+
else if (totalDuration && totalDurationSum){
132+
totalDurationSum+=totalDuration;
133+
}
134+
}
135+
136+
137+
return totalDurationSum;
138+
139+
140+
}
141+
142+
143+
private async discoverPerfDecorators(decorators : vscode.DecorationOptions[],
144+
document: vscode.TextDocument,
145+
documentInfo: DocumentInfo,
146+
methodInfo: MethodInfo,
147+
functions:Token[],
148+
memoised: {[token:string]: number|undefined}){
149+
150+
151+
for (const func of functions.filter(x=>x.range.intersection(methodInfo.range))){
54152

55-
const insights = docInfo.insights.forMethod(method,this._workspaceState.environment)
56-
.filter(x=>x.name=="Performance Stats");
153+
let totalDuration : undefined | number = undefined;
57154

58-
const percentileInfo = insights.map(x=>x as SpanDurationsInsight)
59-
.flatMap(x=>x.percentiles).filter(x=>x.currentDuration);
60-
61-
const totalDuration = percentileInfo.filter(x=>x.percentile==0.5).map(x=>x.currentDuration.raw)
62-
.reduce((acc, val)=>acc + val,0);
63-
64-
const lines = docInfo.lines.getAllByCurrentEnv().filter(l => method.range.contains(l.range.start));
65-
for (const lineInfo of lines ){
66-
decorators.push({
67-
hoverMessage: "",
68-
range: new vscode.Range(lineInfo.range.end, lineInfo.range.end),
69-
renderOptions: {
70-
after:{
71-
contentText: `Duration: ${totalDuration}`
155+
if (func.text === methodInfo.name && func.range === methodInfo.nameRange){
156+
totalDuration= this.getTotalDurationFromInsights(documentInfo,methodInfo);
157+
}
158+
159+
else{
160+
161+
const mem = memoised[document.uri + "$$" + func.text];
162+
if (mem){
163+
if (mem===-1){
164+
totalDuration=undefined;
165+
}
166+
else{
167+
totalDuration=mem;
168+
}
169+
}
170+
171+
else{
172+
173+
174+
const remoteMethodInfo =
175+
await this._codeInspector.getExecuteDefinitionMethodInfo(document, func.range.start, this._documentInfoProvider);
176+
177+
if(!remoteMethodInfo) {
178+
continue;
179+
}
180+
const remoteDoc = await this._codeInspector.getDocumentInfo(document, func.range.start, this._documentInfoProvider);
181+
if(!remoteDoc) {
182+
continue;
183+
}
184+
totalDuration = this.getTotalDurationFromInsights(remoteDoc, remoteMethodInfo);
185+
186+
if (!totalDuration){
187+
188+
const remoteTextDoc = await vscode.workspace.openTextDocument(remoteDoc.uri);
189+
if (remoteTextDoc){
190+
totalDuration=await this.discoverIndirectDurationRecursive(remoteTextDoc,
191+
remoteDoc,
192+
remoteMethodInfo,
193+
remoteDoc.tokens.filter(x=>x.type==='function'),
194+
0);
195+
if (totalDuration){
196+
memoised[document.uri + "$$" + func.text]=totalDuration;
197+
198+
}
72199
}
200+
201+
}
202+
if (!totalDuration){
203+
memoised[func.text]=-1;
204+
}
205+
else{
206+
memoised[document.uri + "$$" + func.text]=totalDuration;
73207
}
208+
}
209+
210+
}
211+
212+
213+
if (totalDuration){
214+
215+
const textLine = document.lineAt(func.range.start.line);
216+
217+
this.addPerformanceDecorator(totalDuration, decorators, new vscode.Range(textLine.range.end, textLine.range.end));
74218

75-
})
76219
}
77-
78-
79-
80-
// hoverMessage: this.getTooltip(lineInfo),
81-
// range: new vscode.Range(lineInfo.range.end, lineInfo.range.end),
82-
// renderOptions: {
83-
// after:{
84-
// contentText: [...new Set( lineInfo.exceptions.map(e => e.type))].join('\xB7')
85-
// }
86-
// }
87-
// }
88220

89221
}
222+
223+
}
224+
private async onShow()
225+
{
226+
227+
const editor = vscode.window.activeTextEditor;
228+
if(!editor){ return; };
229+
230+
const docInfo = await this._documentInfoProvider.getDocumentInfo(editor.document);
231+
232+
if(!docInfo){ return; };
233+
234+
let decorators : vscode.DecorationOptions[] = [];
235+
const mem : {[token:string]: number|undefined}= {};
236+
const functions = docInfo.tokens.filter(x=>x.type==='function');
237+
for (const method of docInfo.methods){
238+
239+
await this.discoverPerfDecorators(decorators,editor.document,docInfo,method,functions,mem);
240+
}
90241

91-
// const textDecorationOptions: vscode.DecorationOptions[] = lines
92-
// .map(lineInfo => {
93-
// return <vscode.DecorationOptions>{
94-
// hoverMessage: this.getTooltip(lineInfo),
95-
// range: new vscode.Range(lineInfo.range.end, lineInfo.range.end),
242+
243+
// for (const method of docInfo.methods){
244+
245+
// const totalDuration = this.getTotalDurationFromInsights(docInfo, method);
246+
247+
// const textLine = editor.document.lineAt(method.range.start.line);
248+
249+
// if (totalDuration){
250+
// decorators.push({
251+
// hoverMessage: "",
252+
// range: new vscode.Range(textLine.rangeIncludingLineBreak.end,
253+
// textLine.rangeIncludingLineBreak.end),
96254
// renderOptions: {
97255
// after:{
98-
// contentText: [...new Set( lineInfo.exceptions.map(e => e.type))].join('\xB7')
256+
// contentText: this.getDisplayDuration(totalDuration)
99257
// }
100258
// }
101-
// }
102-
// });
103-
// const iconDecorationOptions = lines
104-
// .map(lineInfo => {
105-
// return <vscode.DecorationOptions>{
106-
// range: new vscode.Range(lineInfo.range.end, lineInfo.range.end),
107-
// }
108-
// });
259+
260+
// });
261+
// }
262+
263+
109264

265+
// }
266+
110267
editor.setDecorations(this._iconDecorationType, decorators);
111268
//editor.setDecorations(this._textDecorationType, textDecorationOptions);
112269
}
113270

271+
private addPerformanceDecorator(totalDuration: number | undefined, decorators: vscode.DecorationOptions[], range: vscode.Range) {
272+
if (totalDuration) {
273+
decorators.push({
274+
hoverMessage: "",
275+
range: range,
276+
renderOptions: {
277+
after: {
278+
contentText: this.getDisplayDuration(totalDuration)
279+
}
280+
}
281+
});
282+
}
283+
}
284+
114285
private async onHide()
115286
{
116287
const editor = vscode.window.activeTextEditor;

0 commit comments

Comments
 (0)