UNPKG

@quick-game/cli

Version:

Command line interface for rapid qg development

392 lines 15.8 kB
// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* * Copyright (C) 2008 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import * as Common from '../../core/common/common.js'; import * as Host from '../../core/host/host.js'; import * as i18n from '../../core/i18n/i18n.js'; import * as SDK from '../../core/sdk/sdk.js'; import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js'; import * as Components from '../../ui/legacy/components/utils/utils.js'; import * as UI from '../../ui/legacy/legacy.js'; import * as CPUProfile from '../../models/cpu_profile/cpu_profile.js'; import { ProfileFlameChartDataProvider } from './CPUProfileFlameChart.js'; import { ProfileEvents, ProfileType } from './ProfileHeader.js'; import { ProfileView, WritableProfileHeader } from './ProfileView.js'; const UIStrings = { /** *@description Time of a single activity, as opposed to the total time */ selfTime: 'Self Time', /** *@description Text for the total time of something */ totalTime: 'Total Time', /** *@description Text in CPUProfile View of a profiler tool */ recordJavascriptCpuProfile: 'Record JavaScript CPU Profile', /** *@description Text in CPUProfile View of a profiler tool */ stopCpuProfiling: 'Stop CPU profiling', /** *@description Text in CPUProfile View of a profiler tool */ startCpuProfiling: 'Start CPU profiling', /** *@description Text in CPUProfile View of a profiler tool */ cpuProfiles: 'CPU PROFILES', /** *@description Text in CPUProfile View of a profiler tool, that show how much time a script spend executing a function. */ cpuProfilesShow: 'CPU profiles show where the execution time is spent in your page\'s JavaScript functions.', /** *@description Text in CPUProfile View of a profiler tool */ recording: 'Recording…', /** *@description Time in miliseconds *@example {30.1} PH1 */ fms: '{PH1} ms', /** *@description Text in CPUProfile View of a profiler tool *@example {21.33} PH1 */ formatPercent: '{PH1} %', /** *@description Text for the name of something */ name: 'Name', /** *@description Text for web URLs */ url: 'URL', /** *@description Text in CPUProfile View of a profiler tool */ aggregatedSelfTime: 'Aggregated self time', /** *@description Text in CPUProfile View of a profiler tool */ aggregatedTotalTime: 'Aggregated total time', /** *@description Text that indicates a JavaScript function in a CPU profile is not optimized. */ notOptimized: 'Not optimized', }; const str_ = i18n.i18n.registerUIStrings('panels/profiler/CPUProfileView.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class CPUProfileView extends ProfileView { profileHeader; adjustedTotal; constructor(profileHeader) { super(); this.profileHeader = profileHeader; this.initialize(new NodeFormatter(this)); const profile = profileHeader.profileModel(); this.adjustedTotal = profile.profileHead.total; this.adjustedTotal -= profile.idleNode ? profile.idleNode.total : 0; this.setProfile(profile); } wasShown() { super.wasShown(); PerfUI.LineLevelProfile.Performance.instance().reset(); PerfUI.LineLevelProfile.Performance.instance().appendCPUProfile(this.profileHeader.profileModel(), this.profileHeader.target); } columnHeader(columnId) { switch (columnId) { case 'self': return i18nString(UIStrings.selfTime); case 'total': return i18nString(UIStrings.totalTime); } return Common.UIString.LocalizedEmptyString; } createFlameChartDataProvider() { return new CPUFlameChartDataProvider(this.profileHeader.profileModel(), this.profileHeader.cpuProfilerModel); } } export class CPUProfileType extends ProfileType { recording; constructor() { super(CPUProfileType.TypeId, i18nString(UIStrings.recordJavascriptCpuProfile)); this.recording = false; const targetManager = SDK.TargetManager.TargetManager.instance(); const profilerModels = targetManager.models(SDK.CPUProfilerModel.CPUProfilerModel); for (const model of profilerModels) { for (const message of model.registeredConsoleProfileMessages) { this.consoleProfileFinished(message); } } SDK.TargetManager.TargetManager.instance().addModelListener(SDK.CPUProfilerModel.CPUProfilerModel, SDK.CPUProfilerModel.Events.ConsoleProfileFinished, event => this.consoleProfileFinished(event.data), this); } profileBeingRecorded() { return super.profileBeingRecorded(); } typeName() { return 'CPU'; } fileExtension() { return '.cpuprofile'; } get buttonTooltip() { return this.recording ? i18nString(UIStrings.stopCpuProfiling) : i18nString(UIStrings.startCpuProfiling); } buttonClicked() { if (this.recording) { void this.stopRecordingProfile(); return false; } this.startRecordingProfile(); return true; } get treeItemTitle() { return i18nString(UIStrings.cpuProfiles); } get description() { return i18nString(UIStrings.cpuProfilesShow); } consoleProfileFinished(data) { const profile = new CPUProfileHeader(data.cpuProfilerModel, this, data.title); profile.setProtocolProfile(data.cpuProfile); this.addProfile(profile); } startRecordingProfile() { const cpuProfilerModel = UI.Context.Context.instance().flavor(SDK.CPUProfilerModel.CPUProfilerModel); if (this.profileBeingRecorded() || !cpuProfilerModel) { return; } const profile = new CPUProfileHeader(cpuProfilerModel, this); this.setProfileBeingRecorded(profile); void SDK.TargetManager.TargetManager.instance().suspendAllTargets(); this.addProfile(profile); profile.updateStatus(i18nString(UIStrings.recording)); this.recording = true; void cpuProfilerModel.startRecording(); Host.userMetrics.actionTaken(Host.UserMetrics.Action.ProfilesCPUProfileTaken); } async stopRecordingProfile() { this.recording = false; const profileBeingRecorded = this.profileBeingRecorded(); if (!profileBeingRecorded || !profileBeingRecorded.cpuProfilerModel) { return; } const profile = await profileBeingRecorded.cpuProfilerModel.stopRecording(); const recordedProfile = this.profileBeingRecorded(); if (recordedProfile) { if (!profile) { throw new Error('Expected profile to be non-null'); } recordedProfile.setProtocolProfile(profile); recordedProfile.updateStatus(''); this.setProfileBeingRecorded(null); } await SDK.TargetManager.TargetManager.instance().resumeAllTargets(); this.dispatchEventToListeners(ProfileEvents.ProfileComplete, recordedProfile); } createProfileLoadedFromFile(title) { return new CPUProfileHeader(null, this, title); } profileBeingRecordedRemoved() { void this.stopRecordingProfile(); } // eslint-disable-next-line @typescript-eslint/naming-convention static TypeId = 'CPU'; } export class CPUProfileHeader extends WritableProfileHeader { cpuProfilerModel; profileModelInternal; target; constructor(cpuProfilerModel, type, title) { super(cpuProfilerModel && cpuProfilerModel.debuggerModel(), type, title); this.cpuProfilerModel = cpuProfilerModel; this.target = this.cpuProfilerModel && this.cpuProfilerModel.target() || null; } createView() { return new CPUProfileView(this); } protocolProfile() { if (!this.protocolProfile()) { throw new Error('Expected _protocolProfile to be available'); } return this.protocolProfile(); } profileModel() { if (!this.profileModelInternal) { throw new Error('Expected _profileModel to be available'); } return this.profileModelInternal; } setProfile(profile) { this.profileModelInternal = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(profile); } } export class NodeFormatter { profileView; constructor(profileView) { this.profileView = profileView; } formatValue(value) { return i18nString(UIStrings.fms, { PH1: value.toFixed(1) }); } formatValueAccessibleText(value) { return this.formatValue(value); } formatPercent(value, node) { if (this.profileView) { const profile = this.profileView.profile(); if (profile && node.profileNode !== profile.idleNode) { return i18nString(UIStrings.formatPercent, { PH1: value.toFixed(2) }); } } return ''; } linkifyNode(node) { const cpuProfilerModel = this.profileView.profileHeader.cpuProfilerModel; const target = cpuProfilerModel ? cpuProfilerModel.target() : null; const options = { className: 'profile-node-file', inlineFrameIndex: 0 }; return this.profileView.linkifier().maybeLinkifyConsoleCallFrame(target, node.profileNode.callFrame, options); } } export class CPUFlameChartDataProvider extends ProfileFlameChartDataProvider { cpuProfile; cpuProfilerModel; entrySelfTimes; constructor(cpuProfile, cpuProfilerModel) { super(); this.cpuProfile = cpuProfile; this.cpuProfilerModel = cpuProfilerModel; } minimumBoundary() { return this.cpuProfile.profileStartTime; } totalTime() { return this.cpuProfile.profileHead.total; } entryHasDeoptReason(entryIndex) { const node = this.entryNodes[entryIndex]; return Boolean(node.deoptReason); } calculateTimelineData() { const entries = []; const stack = []; let maxDepth = 5; function onOpenFrame() { stack.push(entries.length); // Reserve space for the entry, as they have to be ordered by startTime. // The entry itself will be put there in onCloseFrame. entries.push(null); } function onCloseFrame(depth, node, startTime, totalTime, selfTime) { const index = stack.pop(); entries[index] = new CPUFlameChartDataProvider.ChartEntry(depth, totalTime, startTime, selfTime, node); maxDepth = Math.max(maxDepth, depth); } this.cpuProfile.forEachFrame(onOpenFrame, onCloseFrame); const entryNodes = new Array(entries.length); const entryLevels = new Uint16Array(entries.length); const entryTotalTimes = new Float32Array(entries.length); const entrySelfTimes = new Float32Array(entries.length); const entryStartTimes = new Float64Array(entries.length); for (let i = 0; i < entries.length; ++i) { const entry = entries[i]; if (!entry) { continue; } entryNodes[i] = entry.node; entryLevels[i] = entry.depth; entryTotalTimes[i] = entry.duration; entryStartTimes[i] = entry.startTime; entrySelfTimes[i] = entry.selfTime; } this.maxStackDepthInternal = maxDepth + 1; this.entryNodes = entryNodes; this.timelineData_ = PerfUI.FlameChart.FlameChartTimelineData.create({ entryLevels, entryTotalTimes, entryStartTimes, groups: null }); this.entrySelfTimes = entrySelfTimes; return this.timelineData_; } prepareHighlightedEntryInfo(entryIndex) { const timelineData = this.timelineData_; const node = this.entryNodes[entryIndex]; if (!node) { return null; } const entryInfo = []; function pushEntryInfoRow(title, value) { entryInfo.push({ title: title, value: value }); } function millisecondsToString(ms) { if (ms === 0) { return '0'; } if (ms < 1000) { return i18nString(UIStrings.fms, { PH1: ms.toFixed(1) }); } return i18n.TimeUtilities.secondsToString(ms / 1000, true); } const name = UI.UIUtils.beautifyFunctionName(node.functionName); pushEntryInfoRow(i18nString(UIStrings.name), name); const selfTime = millisecondsToString(this.entrySelfTimes[entryIndex]); const totalTime = millisecondsToString(timelineData.entryTotalTimes[entryIndex]); pushEntryInfoRow(i18nString(UIStrings.selfTime), selfTime); pushEntryInfoRow(i18nString(UIStrings.totalTime), totalTime); const linkifier = new Components.Linkifier.Linkifier(); const link = linkifier.maybeLinkifyConsoleCallFrame(this.cpuProfilerModel && this.cpuProfilerModel.target(), node.callFrame); if (link) { pushEntryInfoRow(i18nString(UIStrings.url), link.textContent || ''); } linkifier.dispose(); pushEntryInfoRow(i18nString(UIStrings.aggregatedSelfTime), i18n.TimeUtilities.secondsToString(node.self / 1000, true)); pushEntryInfoRow(i18nString(UIStrings.aggregatedTotalTime), i18n.TimeUtilities.secondsToString(node.total / 1000, true)); const deoptReason = node.deoptReason; if (deoptReason) { pushEntryInfoRow(i18nString(UIStrings.notOptimized), deoptReason); } return ProfileView.buildPopoverTable(entryInfo); } } (function (CPUFlameChartDataProvider) { class ChartEntry { depth; duration; startTime; selfTime; node; constructor(depth, duration, startTime, selfTime, node) { this.depth = depth; this.duration = duration; this.startTime = startTime; this.selfTime = selfTime; this.node = node; } } CPUFlameChartDataProvider.ChartEntry = ChartEntry; })(CPUFlameChartDataProvider || (CPUFlameChartDataProvider = {})); //# sourceMappingURL=CPUProfileView.js.map