profiling.ts 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /* oxlint-disable no-console */
  2. /* oxlint-disable no-restricted-syntax */
  3. /* oxlint-disable no-restricted-globals */
  4. import { nextTick } from 'vue'
  5. declare global {
  6. var doProfile: boolean
  7. var reactivity: boolean
  8. var recordTime: boolean
  9. var times: Record<string, number[]>
  10. }
  11. globalThis.recordTime = true
  12. globalThis.doProfile = false
  13. globalThis.reactivity = false
  14. export const defer = () => new Promise(r => requestIdleCallback(r))
  15. const times: Record<string, number[]> = (globalThis.times = {})
  16. export function wrap(
  17. id: string,
  18. fn: (...args: any[]) => any,
  19. ): (...args: any[]) => Promise<void> {
  20. return async (...args) => {
  21. if (!globalThis.recordTime) {
  22. return fn(...args)
  23. }
  24. document.body.classList.remove('done')
  25. const { doProfile } = globalThis
  26. await nextTick()
  27. doProfile && console.profile(id)
  28. const start = performance.now()
  29. fn(...args)
  30. await nextTick()
  31. let time: number
  32. if (globalThis.reactivity) {
  33. time = performance.measure(
  34. 'flushJobs-measure',
  35. 'flushJobs-start',
  36. 'flushJobs-end',
  37. ).duration
  38. performance.clearMarks()
  39. performance.clearMeasures()
  40. } else {
  41. time = performance.now() - start
  42. }
  43. const prevTimes = times[id] || (times[id] = [])
  44. prevTimes.push(time)
  45. const { min, max, median, mean, std } = compute(prevTimes)
  46. const msg =
  47. `${id}: min: ${min} / ` +
  48. `max: ${max} / ` +
  49. `median: ${median}ms / ` +
  50. `mean: ${mean}ms / ` +
  51. `time: ${time.toFixed(2)}ms / ` +
  52. `std: ${std} ` +
  53. `over ${prevTimes.length} runs`
  54. doProfile && console.profileEnd(id)
  55. console.log(msg)
  56. const timeEl = document.getElementById('time')!
  57. timeEl.textContent = msg
  58. document.body.classList.add('done')
  59. }
  60. }
  61. function compute(array: number[]) {
  62. const n = array.length
  63. const max = Math.max(...array)
  64. const min = Math.min(...array)
  65. const mean = array.reduce((a, b) => a + b) / n
  66. const std = Math.sqrt(
  67. array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n,
  68. )
  69. const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)]
  70. return {
  71. max: round(max),
  72. min: round(min),
  73. mean: round(mean),
  74. std: round(std),
  75. median: round(median),
  76. }
  77. }
  78. function round(n: number) {
  79. return +n.toFixed(2)
  80. }