performance-recording.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. "use strict";
  5. const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
  6. const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
  7. loader.lazyRequireGetter(this, "PerformanceIO",
  8. "devtools/client/performance/modules/io");
  9. loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
  10. "devtools/shared/performance/recording-common", true);
  11. loader.lazyRequireGetter(this, "RecordingUtils",
  12. "devtools/shared/performance/recording-utils");
  13. loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
  14. /**
  15. * This can be used on older Profiler implementations, but the methods cannot
  16. * be changed -- you must introduce a new method, and detect the server.
  17. */
  18. const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec, merge({
  19. form: function (form, detail) {
  20. if (detail === "actorid") {
  21. this.actorID = form;
  22. return;
  23. }
  24. this.actorID = form.actor;
  25. this._form = form;
  26. this._configuration = form.configuration;
  27. this._startingBufferStatus = form.startingBufferStatus;
  28. this._console = form.console;
  29. this._label = form.label;
  30. this._startTime = form.startTime;
  31. this._localStartTime = form.localStartTime;
  32. this._recording = form.recording;
  33. this._completed = form.completed;
  34. this._duration = form.duration;
  35. if (form.finalizedData) {
  36. this._profile = form.profile;
  37. this._systemHost = form.systemHost;
  38. this._systemClient = form.systemClient;
  39. }
  40. // Sort again on the client side if we're using realtime markers and the recording
  41. // just finished. This is because GC/Compositing markers can come into the array out
  42. // of order with the other markers, leading to strange collapsing in waterfall view.
  43. if (this._completed && !this._markersSorted) {
  44. this._markers = this._markers.sort((a, b) => (a.start > b.start));
  45. this._markersSorted = true;
  46. }
  47. },
  48. initialize: function (client, form, config) {
  49. Front.prototype.initialize.call(this, client, form);
  50. this._markers = [];
  51. this._frames = [];
  52. this._memory = [];
  53. this._ticks = [];
  54. this._allocations = { sites: [], timestamps: [], frames: [], sizes: [] };
  55. },
  56. destroy: function () {
  57. Front.prototype.destroy.call(this);
  58. },
  59. /**
  60. * Saves the current recording to a file.
  61. *
  62. * @param nsILocalFile file
  63. * The file to stream the data into.
  64. */
  65. exportRecording: function (file) {
  66. let recordingData = this.getAllData();
  67. return PerformanceIO.saveRecordingToFile(recordingData, file);
  68. },
  69. /**
  70. * Fired whenever the PerformanceFront emits markers, memory or ticks.
  71. */
  72. _addTimelineData: function (eventName, data) {
  73. let config = this.getConfiguration();
  74. switch (eventName) {
  75. // Accumulate timeline markers into an array. Furthermore, the timestamps
  76. // do not have a zero epoch, so offset all of them by the start time.
  77. case "markers": {
  78. if (!config.withMarkers) {
  79. break;
  80. }
  81. let { markers } = data;
  82. RecordingUtils.offsetMarkerTimes(markers, this._startTime);
  83. RecordingUtils.pushAll(this._markers, markers);
  84. break;
  85. }
  86. // Accumulate stack frames into an array.
  87. case "frames": {
  88. if (!config.withMarkers) {
  89. break;
  90. }
  91. let { frames } = data;
  92. RecordingUtils.pushAll(this._frames, frames);
  93. break;
  94. }
  95. // Accumulate memory measurements into an array. Furthermore, the timestamp
  96. // does not have a zero epoch, so offset it by the actor's start time.
  97. case "memory": {
  98. if (!config.withMemory) {
  99. break;
  100. }
  101. let { delta, measurement } = data;
  102. this._memory.push({
  103. delta: delta - this._startTime,
  104. value: measurement.total / 1024 / 1024
  105. });
  106. break;
  107. }
  108. // Save the accumulated refresh driver ticks.
  109. case "ticks": {
  110. if (!config.withTicks) {
  111. break;
  112. }
  113. let { timestamps } = data;
  114. this._ticks = timestamps;
  115. break;
  116. }
  117. // Accumulate allocation sites into an array.
  118. case "allocations": {
  119. if (!config.withAllocations) {
  120. break;
  121. }
  122. let {
  123. allocations: sites,
  124. allocationsTimestamps: timestamps,
  125. allocationSizes: sizes,
  126. frames,
  127. } = data;
  128. RecordingUtils.offsetAndScaleTimestamps(timestamps, this._startTime);
  129. RecordingUtils.pushAll(this._allocations.sites, sites);
  130. RecordingUtils.pushAll(this._allocations.timestamps, timestamps);
  131. RecordingUtils.pushAll(this._allocations.frames, frames);
  132. RecordingUtils.pushAll(this._allocations.sizes, sizes);
  133. break;
  134. }
  135. }
  136. },
  137. toString: () => "[object PerformanceRecordingFront]"
  138. }, PerformanceRecordingCommon));
  139. exports.PerformanceRecordingFront = PerformanceRecordingFront;