index.mjs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { activeAnimations } from './animation-count.mjs';
  2. import { statsBuffer } from './buffer.mjs';
  3. import { frame, cancelFrame, frameData } from '../frameloop/frame.mjs';
  4. function record() {
  5. const { value } = statsBuffer;
  6. if (value === null) {
  7. cancelFrame(record);
  8. return;
  9. }
  10. value.frameloop.rate.push(frameData.delta);
  11. value.animations.mainThread.push(activeAnimations.mainThread);
  12. value.animations.waapi.push(activeAnimations.waapi);
  13. value.animations.layout.push(activeAnimations.layout);
  14. }
  15. function mean(values) {
  16. return values.reduce((acc, value) => acc + value, 0) / values.length;
  17. }
  18. function summarise(values, calcAverage = mean) {
  19. if (values.length === 0) {
  20. return {
  21. min: 0,
  22. max: 0,
  23. avg: 0,
  24. };
  25. }
  26. return {
  27. min: Math.min(...values),
  28. max: Math.max(...values),
  29. avg: calcAverage(values),
  30. };
  31. }
  32. const msToFps = (ms) => Math.round(1000 / ms);
  33. function clearStatsBuffer() {
  34. statsBuffer.value = null;
  35. statsBuffer.addProjectionMetrics = null;
  36. }
  37. function reportStats() {
  38. const { value } = statsBuffer;
  39. if (!value) {
  40. throw new Error("Stats are not being measured");
  41. }
  42. clearStatsBuffer();
  43. cancelFrame(record);
  44. const summary = {
  45. frameloop: {
  46. rate: summarise(value.frameloop.rate),
  47. read: summarise(value.frameloop.read),
  48. resolveKeyframes: summarise(value.frameloop.resolveKeyframes),
  49. update: summarise(value.frameloop.update),
  50. preRender: summarise(value.frameloop.preRender),
  51. render: summarise(value.frameloop.render),
  52. postRender: summarise(value.frameloop.postRender),
  53. },
  54. animations: {
  55. mainThread: summarise(value.animations.mainThread),
  56. waapi: summarise(value.animations.waapi),
  57. layout: summarise(value.animations.layout),
  58. },
  59. layoutProjection: {
  60. nodes: summarise(value.layoutProjection.nodes),
  61. calculatedTargetDeltas: summarise(value.layoutProjection.calculatedTargetDeltas),
  62. calculatedProjections: summarise(value.layoutProjection.calculatedProjections),
  63. },
  64. };
  65. /**
  66. * Convert the rate to FPS
  67. */
  68. const { rate } = summary.frameloop;
  69. rate.min = msToFps(rate.min);
  70. rate.max = msToFps(rate.max);
  71. rate.avg = msToFps(rate.avg);
  72. [rate.min, rate.max] = [rate.max, rate.min];
  73. return summary;
  74. }
  75. function recordStats() {
  76. if (statsBuffer.value) {
  77. clearStatsBuffer();
  78. throw new Error("Stats are already being measured");
  79. }
  80. const newStatsBuffer = statsBuffer;
  81. newStatsBuffer.value = {
  82. frameloop: {
  83. rate: [],
  84. read: [],
  85. resolveKeyframes: [],
  86. update: [],
  87. preRender: [],
  88. render: [],
  89. postRender: [],
  90. },
  91. animations: {
  92. mainThread: [],
  93. waapi: [],
  94. layout: [],
  95. },
  96. layoutProjection: {
  97. nodes: [],
  98. calculatedTargetDeltas: [],
  99. calculatedProjections: [],
  100. },
  101. };
  102. newStatsBuffer.addProjectionMetrics = (metrics) => {
  103. const { layoutProjection } = newStatsBuffer.value;
  104. layoutProjection.nodes.push(metrics.nodes);
  105. layoutProjection.calculatedTargetDeltas.push(metrics.calculatedTargetDeltas);
  106. layoutProjection.calculatedProjections.push(metrics.calculatedProjections);
  107. };
  108. frame.postRender(record, true);
  109. return reportStats;
  110. }
  111. export { recordStats };