| /** | |
| * @unrestricted | |
| */ | |
| export default class HeapProfilerModel extends SDK.SDKModel { | |
| /** | |
| * @param {!SDK.Target} target | |
| */ | |
| constructor(target) { | |
| super(target); | |
| target.registerHeapProfilerDispatcher(new HeapProfilerDispatcher(this)); | |
| this._enabled = false; | |
| this._heapProfilerAgent = target.heapProfilerAgent(); | |
| this._memoryAgent = target.memoryAgent(); | |
| this._runtimeModel = /** @type {!SDK.RuntimeModel} */ (target.model(SDK.RuntimeModel)); | |
| this._samplingProfilerDepth = 0; | |
| } | |
| /** | |
| * @return {!SDK.DebuggerModel} | |
| */ | |
| debuggerModel() { | |
| return this._runtimeModel.debuggerModel(); | |
| } | |
| /** | |
| * @return {!SDK.RuntimeModel} | |
| */ | |
| runtimeModel() { | |
| return this._runtimeModel; | |
| } | |
| enable() { | |
| if (this._enabled) { | |
| return; | |
| } | |
| this._enabled = true; | |
| this._heapProfilerAgent.enable(); | |
| } | |
| /** | |
| * @param {number=} samplingRateInBytes | |
| */ | |
| startSampling(samplingRateInBytes) { | |
| if (this._samplingProfilerDepth++) { | |
| return; | |
| } | |
| const defaultSamplingIntervalInBytes = 16384; | |
| this._heapProfilerAgent.startSampling(samplingRateInBytes || defaultSamplingIntervalInBytes); | |
| } | |
| /** | |
| * @return {!Promise<?Protocol.HeapProfiler.SamplingHeapProfile>} | |
| */ | |
| stopSampling() { | |
| if (!this._samplingProfilerDepth) { | |
| throw new Error('Sampling profiler is not running.'); | |
| } | |
| if (--this._samplingProfilerDepth) { | |
| return this.getSamplingProfile(); | |
| } | |
| return this._heapProfilerAgent.stopSampling(); | |
| } | |
| /** | |
| * @return {!Promise<?Protocol.HeapProfiler.SamplingHeapProfile>} | |
| */ | |
| getSamplingProfile() { | |
| return this._heapProfilerAgent.getSamplingProfile(); | |
| } | |
| startNativeSampling() { | |
| const defaultSamplingIntervalInBytes = 65536; | |
| this._memoryAgent.startSampling(defaultSamplingIntervalInBytes); | |
| } | |
| /** | |
| * @return {!Promise<!NativeHeapProfile>} | |
| */ | |
| async stopNativeSampling() { | |
| const rawProfile = /** @type {!Protocol.Memory.SamplingProfile} */ (await this._memoryAgent.getSamplingProfile()); | |
| this._memoryAgent.stopSampling(); | |
| return this._convertNativeProfile(rawProfile); | |
| } | |
| /** | |
| * @return {!Promise<!NativeHeapProfile>} | |
| */ | |
| async takeNativeSnapshot() { | |
| const rawProfile = | |
| /** @type {!Protocol.Memory.SamplingProfile} */ (await this._memoryAgent.getAllTimeSamplingProfile()); | |
| return this._convertNativeProfile(rawProfile); | |
| } | |
| /** | |
| * @return {!Promise<!NativeHeapProfile>} | |
| */ | |
| async takeNativeBrowserSnapshot() { | |
| const rawProfile = | |
| /** @type {!Protocol.Memory.SamplingProfile} */ (await this._memoryAgent.getBrowserSamplingProfile()); | |
| return this._convertNativeProfile(rawProfile); | |
| } | |
| /** | |
| * @param {!Protocol.Memory.SamplingProfile} rawProfile | |
| * @return {!NativeHeapProfile} | |
| */ | |
| _convertNativeProfile(rawProfile) { | |
| const head = /** @type {!Protocol.HeapProfiler.SamplingHeapProfileNode} */ | |
| ({children: new Map(), selfSize: 0, callFrame: {functionName: '(root)', url: ''}}); | |
| for (const sample of rawProfile.samples) { | |
| const node = sample.stack.reverse().reduce((node, name) => { | |
| let child = node.children.get(name); | |
| if (child) { | |
| return child; | |
| } | |
| const namespace = /^([^:]*)::/.exec(name); | |
| child = { | |
| children: new Map(), | |
| callFrame: {functionName: name, url: namespace && namespace[1] || ''}, | |
| selfSize: 0 | |
| }; | |
| node.children.set(name, child); | |
| return child; | |
| }, head); | |
| node.selfSize += sample.total; | |
| } | |
| function convertChildren(node) { | |
| node.children = Array.from(node.children.values()); | |
| node.children.forEach(convertChildren); | |
| } | |
| convertChildren(head); | |
| return new NativeHeapProfile(head, rawProfile.modules); | |
| } | |
| /** | |
| * @return {!Promise} | |
| */ | |
| collectGarbage() { | |
| return this._heapProfilerAgent.collectGarbage(); | |
| } | |
| /** | |
| * @param {string} objectId | |
| * @return {!Promise<?string>} | |
| */ | |
| snapshotObjectIdForObjectId(objectId) { | |
| return this._heapProfilerAgent.getHeapObjectId(objectId); | |
| } | |
| /** | |
| * @param {string} snapshotObjectId | |
| * @param {string} objectGroupName | |
| * @return {!Promise<?SDK.RemoteObject>} | |
| */ | |
| async objectForSnapshotObjectId(snapshotObjectId, objectGroupName) { | |
| const result = await this._heapProfilerAgent.getObjectByHeapObjectId(snapshotObjectId, objectGroupName); | |
| return result && result.type && this._runtimeModel.createRemoteObject(result) || null; | |
| } | |
| /** | |
| * @param {string} snapshotObjectId | |
| * @return {!Promise} | |
| */ | |
| addInspectedHeapObject(snapshotObjectId) { | |
| return this._heapProfilerAgent.addInspectedHeapObject(snapshotObjectId); | |
| } | |
| /** | |
| * @param {boolean} reportProgress | |
| * @return {!Promise} | |
| */ | |
| takeHeapSnapshot(reportProgress) { | |
| return this._heapProfilerAgent.takeHeapSnapshot(reportProgress); | |
| } | |
| /** | |
| * @param {boolean} recordAllocationStacks | |
| * @return {!Promise} | |
| */ | |
| startTrackingHeapObjects(recordAllocationStacks) { | |
| return this._heapProfilerAgent.startTrackingHeapObjects(recordAllocationStacks); | |
| } | |
| /** | |
| * @param {boolean} reportProgress | |
| * @return {!Promise} | |
| */ | |
| stopTrackingHeapObjects(reportProgress) { | |
| return this._heapProfilerAgent.stopTrackingHeapObjects(reportProgress); | |
| } | |
| /** | |
| * @param {!Array<number>} samples | |
| */ | |
| heapStatsUpdate(samples) { | |
| this.dispatchEventToListeners(Events.HeapStatsUpdate, samples); | |
| } | |
| /** | |
| * @param {number} lastSeenObjectId | |
| * @param {number} timestamp | |
| */ | |
| lastSeenObjectId(lastSeenObjectId, timestamp) { | |
| this.dispatchEventToListeners(Events.LastSeenObjectId, {lastSeenObjectId: lastSeenObjectId, timestamp: timestamp}); | |
| } | |
| /** | |
| * @param {string} chunk | |
| */ | |
| addHeapSnapshotChunk(chunk) { | |
| this.dispatchEventToListeners(Events.AddHeapSnapshotChunk, chunk); | |
| } | |
| /** | |
| * @param {number} done | |
| * @param {number} total | |
| * @param {boolean=} finished | |
| */ | |
| reportHeapSnapshotProgress(done, total, finished) { | |
| this.dispatchEventToListeners(Events.ReportHeapSnapshotProgress, {done: done, total: total, finished: finished}); | |
| } | |
| resetProfiles() { | |
| this.dispatchEventToListeners(Events.ResetProfiles, this); | |
| } | |
| } | |
| /** @enum {symbol} */ | |
| export const Events = { | |
| HeapStatsUpdate: Symbol('HeapStatsUpdate'), | |
| LastSeenObjectId: Symbol('LastSeenObjectId'), | |
| AddHeapSnapshotChunk: Symbol('AddHeapSnapshotChunk'), | |
| ReportHeapSnapshotProgress: Symbol('ReportHeapSnapshotProgress'), | |
| ResetProfiles: Symbol('ResetProfiles') | |
| }; | |
| /** | |
| * @implements {Protocol.Profiler.Profile} | |
| * @extends {Protocol.HeapProfiler.SamplingHeapProfile} | |
| */ | |
| class NativeHeapProfile { | |
| /** | |
| * @param {!Protocol.HeapProfiler.SamplingHeapProfileNode} head | |
| * @param {!Array<!Protocol.Memory.Module>} modules | |
| */ | |
| constructor(head, modules) { | |
| this.head = head; | |
| this.modules = modules; | |
| } | |
| } | |
| /** | |
| * @extends {Protocol.HeapProfilerDispatcher} | |
| * @unrestricted | |
| */ | |
| class HeapProfilerDispatcher { | |
| constructor(model) { | |
| this._heapProfilerModel = model; | |
| } | |
| /** | |
| * @override | |
| * @param {!Array.<number>} samples | |
| */ | |
| heapStatsUpdate(samples) { | |
| this._heapProfilerModel.heapStatsUpdate(samples); | |
| } | |
| /** | |
| * @override | |
| * @param {number} lastSeenObjectId | |
| * @param {number} timestamp | |
| */ | |
| lastSeenObjectId(lastSeenObjectId, timestamp) { | |
| this._heapProfilerModel.lastSeenObjectId(lastSeenObjectId, timestamp); | |
| } | |
| /** | |
| * @override | |
| * @param {string} chunk | |
| */ | |
| addHeapSnapshotChunk(chunk) { | |
| this._heapProfilerModel.addHeapSnapshotChunk(chunk); | |
| } | |
| /** | |
| * @override | |
| * @param {number} done | |
| * @param {number} total | |
| * @param {boolean=} finished | |
| */ | |
| reportHeapSnapshotProgress(done, total, finished) { | |
| this._heapProfilerModel.reportHeapSnapshotProgress(done, total, finished); | |
| } | |
| /** | |
| * @override | |
| */ | |
| resetProfiles() { | |
| this._heapProfilerModel.resetProfiles(); | |
| } | |
| } | |
| /* Legacy exported object */ | |
| self.SDK = self.SDK || {}; | |
| /* Legacy exported object */ | |
| SDK = SDK || {}; | |
| /** @constructor */ | |
| SDK.HeapProfilerModel = HeapProfilerModel; | |
| /** @enum {symbol} */ | |
| SDK.HeapProfilerModel.Events = Events; | |
| SDK.SDKModel.register(SDK.HeapProfilerModel, SDK.Target.Capability.JS, false); |