profiler.js (4384B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 // The functions in the class use standard functions called from tracer.js but we want to keep the 8 // arguments intact. 9 /* eslint "no-unused-vars": ["error", {args: "none"} ]*/ 10 11 class ProfilerTracingListener { 12 constructor({ targetActor, traceActor }) { 13 this.targetActor = targetActor; 14 this.traceActor = traceActor; 15 } 16 17 /** 18 * Stop the record and return the gecko profiler data. 19 * 20 * @param {object} nativeTrace 21 * If we're using native tracing, this contains a table of what the 22 * native tracer has collected. 23 * @return {object} 24 * The Gecko profile object. 25 */ 26 async stop(nativeTrace) { 27 // Pause profiler before we collect the profile, so that we don't capture 28 // more samples while the parent process or android threads wait for subprocess profiles. 29 Services.profiler.Pause(); 30 31 let profile; 32 try { 33 // Attempt to pull out the data. 34 profile = await Services.profiler.getProfileDataAsync(); 35 36 if (Object.keys(profile).length === 0) { 37 console.error( 38 "An empty object was received from getProfileDataAsync.getProfileDataAsync(), " + 39 "meaning that a profile could not successfully be serialized and captured." 40 ); 41 profile = null; 42 } 43 } catch (e) { 44 // Explicitly set the profile to null if there as an error. 45 profile = null; 46 console.error(`There was an error fetching a profile`, e); 47 } 48 49 Services.profiler.StopProfiler(); 50 51 return profile; 52 } 53 54 /** 55 * Be notified by the underlying JavaScriptTracer class 56 * in case it stops by itself, instead of being stopped when the Actor's stopTracing 57 * method is called by the user. 58 * 59 * @param {boolean} enabled 60 * True if the tracer starts tracing, false it it stops. 61 * @return {boolean} 62 * Return true, if the JavaScriptTracer should log a message to stdout. 63 */ 64 onTracingToggled(enabled) { 65 if (!enabled) { 66 this.traceActor.stopTracing(); 67 } else { 68 Services.profiler.StartProfiler( 69 // Note that this is the same default as profiler ones defined in: 70 // devtools/client/performance-new/shared/background.sys.mjs 71 128 * 1024 * 1024, 72 1, 73 ["screenshots", "tracing"], 74 ["GeckoMain", "DOM Worker"], 75 this.targetActor.sessionContext.browserId, 76 0 77 ); 78 } 79 return false; 80 } 81 82 /** 83 * Called when "trace on next user interaction" is enabled, to notify the user 84 * that the tracer is initialized but waiting for the user first input. 85 */ 86 onTracingPending() { 87 return false; 88 } 89 90 /** 91 * Called by JavaScriptTracer class when a new mutation happened on any DOM Element. 92 * 93 * @param {object} options 94 * @param {number} options.depth 95 * Represents the depth of the frame in the call stack. 96 * @param {string} options.prefix 97 * A string to be displayed as a prefix of any logged frame. 98 * @param {nsIStackFrame} options.caller 99 * The JS Callsite which caused this mutation. 100 * @param {string} options.type 101 * Type of DOM Mutation: 102 * - "add": Node being added, 103 * - "attributes": Node whose attributes changed, 104 * - "remove": Node being removed, 105 * @param {DOMNode} options.element 106 * The DOM Node related to the current mutation. 107 * @return {boolean} 108 * Return true, if the JavaScriptTracer should log a message to stdout. 109 */ 110 onTracingDOMMutation({ depth, prefix, type, caller, element }) { 111 let elementDescription = element.tagName?.toLowerCase(); 112 if (element.id) { 113 elementDescription += `#${element.id}`; 114 } 115 if (element.className) { 116 elementDescription += `.${element.className.trim().replace(/ +/g, ".")}`; 117 } 118 119 const description = `${type} on ${elementDescription}`; 120 121 // Bug 1904602: we need a tweak in profiler frontend before being able to show 122 // dom mutation in the stack chart. Until then, add a custom marker. 123 ChromeUtils.addProfilerMarker("DOM-Mutation", undefined, description); 124 125 return false; 126 } 127 } 128 129 exports.ProfilerTracingListener = ProfilerTracingListener;