PerfService.jsm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. "use strict";
  2. if (typeof ChromeUtils !== "undefined") {
  3. // Use a var here instead of let outside to avoid creating a locally scoped
  4. // variable that hides the global, which we modify for testing.
  5. // eslint-disable-next-line no-var, vars-on-top
  6. var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
  7. }
  8. let usablePerfObj;
  9. /* istanbul ignore else */
  10. // eslint-disable-next-line block-scoped-var
  11. if (typeof Services !== "undefined") {
  12. // Borrow the high-resolution timer from the hidden window....
  13. // eslint-disable-next-line block-scoped-var
  14. usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
  15. } else {
  16. // we must be running in content space
  17. // eslint-disable-next-line no-undef
  18. usablePerfObj = performance;
  19. }
  20. function _PerfService(options) {
  21. // For testing, so that we can use a fake Window.performance object with
  22. // known state.
  23. if (options && options.performanceObj) {
  24. this._perf = options.performanceObj;
  25. } else {
  26. this._perf = usablePerfObj;
  27. }
  28. }
  29. _PerfService.prototype = {
  30. /**
  31. * Calls the underlying mark() method on the appropriate Window.performance
  32. * object to add a mark with the given name to the appropriate performance
  33. * timeline.
  34. *
  35. * @param {String} name the name to give the current mark
  36. * @return {void}
  37. */
  38. mark: function mark(str) {
  39. this._perf.mark(str);
  40. },
  41. /**
  42. * Calls the underlying getEntriesByName on the appropriate Window.performance
  43. * object.
  44. *
  45. * @param {String} name
  46. * @param {String} type eg "mark"
  47. * @return {Array} Performance* objects
  48. */
  49. getEntriesByName: function getEntriesByName(name, type) {
  50. return this._perf.getEntriesByName(name, type);
  51. },
  52. /**
  53. * The timeOrigin property from the appropriate performance object.
  54. * Used to ensure that timestamps from the add-on code and the content code
  55. * are comparable.
  56. *
  57. * @note If this is called from a context without a window
  58. * (eg a JSM in chrome), it will return the timeOrigin of the XUL hidden
  59. * window, which appears to be the first created window (and thus
  60. * timeOrigin) in the browser. Note also, however, there is also a private
  61. * hidden window, presumably for private browsing, which appears to be
  62. * created dynamically later. Exactly how/when that shows up needs to be
  63. * investigated.
  64. *
  65. * @return {Number} A double of milliseconds with a precision of 0.5us.
  66. */
  67. get timeOrigin() {
  68. return this._perf.timeOrigin;
  69. },
  70. /**
  71. * Returns the "absolute" version of performance.now(), i.e. one that
  72. * should ([bug 1401406](https://bugzilla.mozilla.org/show_bug.cgi?id=1401406)
  73. * be comparable across both chrome and content.
  74. *
  75. * @return {Number}
  76. */
  77. absNow: function absNow() {
  78. return this.timeOrigin + this._perf.now();
  79. },
  80. /**
  81. * This returns the absolute startTime from the most recent performance.mark()
  82. * with the given name.
  83. *
  84. * @param {String} name the name to lookup the start time for
  85. *
  86. * @return {Number} the returned start time, as a DOMHighResTimeStamp
  87. *
  88. * @throws {Error} "No Marks with the name ..." if none are available
  89. *
  90. * @note Always surround calls to this by try/catch. Otherwise your code
  91. * may fail when the `privacy.resistFingerprinting` pref is true. When
  92. * this pref is set, all attempts to get marks will likely fail, which will
  93. * cause this method to throw.
  94. *
  95. * See [bug 1369303](https://bugzilla.mozilla.org/show_bug.cgi?id=1369303)
  96. * for more info.
  97. */
  98. getMostRecentAbsMarkStartByName(name) {
  99. let entries = this.getEntriesByName(name, "mark");
  100. if (!entries.length) {
  101. throw new Error(`No marks with the name ${name}`);
  102. }
  103. let mostRecentEntry = entries[entries.length - 1];
  104. return this._perf.timeOrigin + mostRecentEntry.startTime;
  105. },
  106. };
  107. this.perfService = new _PerfService();
  108. const EXPORTED_SYMBOLS = ["_PerfService", "perfService"];