Path: blob/main/src/vs/workbench/contrib/performance/browser/startupTimings.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js';6import { ILifecycleService, StartupKind, StartupKindToString } from '../../../services/lifecycle/common/lifecycle.js';7import { IUpdateService } from '../../../../platform/update/common/update.js';8import * as files from '../../files/common/files.js';9import { IEditorService } from '../../../services/editor/common/editorService.js';10import { IWorkspaceTrustManagementService } from '../../../../platform/workspace/common/workspaceTrust.js';11import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.js';12import { ViewContainerLocation } from '../../../common/views.js';13import { ILogService } from '../../../../platform/log/common/log.js';14import { IProductService } from '../../../../platform/product/common/productService.js';15import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';16import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js';17import { ITimerService } from '../../../services/timer/browser/timerService.js';18import { IWorkbenchContribution } from '../../../common/contributions.js';19import { posix } from '../../../../base/common/path.js';20import { hash } from '../../../../base/common/hash.js';2122export abstract class StartupTimings {2324constructor(25@IEditorService private readonly _editorService: IEditorService,26@IPaneCompositePartService private readonly _paneCompositeService: IPaneCompositePartService,27@ILifecycleService private readonly _lifecycleService: ILifecycleService,28@IUpdateService private readonly _updateService: IUpdateService,29@IWorkspaceTrustManagementService private readonly _workspaceTrustService: IWorkspaceTrustManagementService30) {31}3233protected async _isStandardStartup(): Promise<string | undefined> {34// check for standard startup:35// * new window (no reload)36// * workspace is trusted37// * just one window38// * explorer viewlet visible39// * one text editor (not multiple, not webview, welcome etc...)40// * cached data present (not rejected, not created)41if (this._lifecycleService.startupKind !== StartupKind.NewWindow) {42return StartupKindToString(this._lifecycleService.startupKind);43}44if (!this._workspaceTrustService.isWorkspaceTrusted()) {45return 'Workspace not trusted';46}47const activeViewlet = this._paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);48if (!activeViewlet || activeViewlet.getId() !== files.VIEWLET_ID) {49return 'Explorer viewlet not visible';50}51const visibleEditorPanes = this._editorService.visibleEditorPanes;52if (visibleEditorPanes.length !== 1) {53return `Expected text editor count : 1, Actual : ${visibleEditorPanes.length}`;54}55if (!isCodeEditor(visibleEditorPanes[0].getControl())) {56return 'Active editor is not a text editor';57}58const activePanel = this._paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);59if (activePanel) {60return `Current active panel : ${this._paneCompositeService.getPaneComposite(activePanel.getId(), ViewContainerLocation.Panel)?.name}`;61}62const isLatestVersion = await this._updateService.isLatestVersion();63if (isLatestVersion === false) {64return 'Not on latest version, updates available';65}66return undefined;67}68}6970export class BrowserStartupTimings extends StartupTimings implements IWorkbenchContribution {7172constructor(73@IEditorService editorService: IEditorService,74@IPaneCompositePartService paneCompositeService: IPaneCompositePartService,75@ILifecycleService lifecycleService: ILifecycleService,76@IUpdateService updateService: IUpdateService,77@IWorkspaceTrustManagementService workspaceTrustService: IWorkspaceTrustManagementService,78@ITimerService private readonly timerService: ITimerService,79@ILogService private readonly logService: ILogService,80@IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,81@ITelemetryService private readonly telemetryService: ITelemetryService,82@IProductService private readonly productService: IProductService83) {84super(editorService, paneCompositeService, lifecycleService, updateService, workspaceTrustService);8586this.logPerfMarks();87}8889private async logPerfMarks(): Promise<void> {90if (!this.environmentService.profDurationMarkers) {91return;92}9394await this.timerService.whenReady();9596const standardStartupError = await this._isStandardStartup();97const perfBaseline = await this.timerService.perfBaseline;98const [from, to] = this.environmentService.profDurationMarkers;99const content = `${this.timerService.getDuration(from, to)}\t${this.productService.nameShort}\t${(this.productService.commit || '').slice(0, 10) || '0000000000'}\t${this.telemetryService.sessionId}\t${standardStartupError === undefined ? 'standard_start' : 'NO_standard_start : ' + standardStartupError}\t${String(perfBaseline).padStart(4, '0')}ms\n`;100101this.logService.info(`[prof-timers] ${content}`);102}103}104105export class BrowserResourcePerformanceMarks {106107constructor(108@ITelemetryService telemetryService: ITelemetryService109) {110111type Entry = {112hosthash: string;113name: string;114duration: number;115};116type EntryClassifify = {117owner: 'jrieken';118comment: 'Resource performance numbers';119hosthash: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Hash of the hostname' };120name: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Resource basename' };121duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Resource duration' };122};123for (const item of performance.getEntriesByType('resource')) {124125try {126const url = new URL(item.name);127const name = posix.basename(url.pathname);128129telemetryService.publicLog2<Entry, EntryClassifify>('startup.resource.perf', {130hosthash: `H${hash(url.host).toString(16)}`,131name,132duration: item.duration133});134} catch {135// ignore136}137}138}139}140141142