ContentCacheMetrics.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. const logger = require('@overleaf/logger')
  2. const Metrics = require('./Metrics')
  3. const os = require('os')
  4. let CACHED_LOAD = {
  5. expires: -1,
  6. load: [0, 0, 0],
  7. }
  8. function getSystemLoad() {
  9. if (CACHED_LOAD.expires < Date.now()) {
  10. CACHED_LOAD = {
  11. expires: Date.now() + 10 * 1000,
  12. load: os.loadavg(),
  13. }
  14. }
  15. return CACHED_LOAD.load
  16. }
  17. const ONE_MB = 1024 * 1024
  18. function emitPdfStats(stats, timings, request) {
  19. if (timings['compute-pdf-caching']) {
  20. emitPdfCachingStats(stats, timings, request)
  21. } else {
  22. // How much bandwidth will the pdf incur when downloaded in full?
  23. Metrics.summary('pdf-bandwidth', stats['pdf-size'], request.metricsOpts)
  24. }
  25. }
  26. function emitPdfCachingStats(stats, timings, request) {
  27. if (!stats['pdf-size']) return // double check
  28. if (stats['pdf-caching-timed-out']) {
  29. Metrics.inc('pdf-caching-timed-out', 1, request.metricsOpts)
  30. }
  31. if (timings['pdf-caching-overhead-delete-stale-hashes'] !== undefined) {
  32. Metrics.summary(
  33. 'pdf-caching-overhead-delete-stale-hashes',
  34. timings['pdf-caching-overhead-delete-stale-hashes'],
  35. request.metricsOpts
  36. )
  37. }
  38. // How much extra time did we spent in PDF.js?
  39. Metrics.timing(
  40. 'compute-pdf-caching',
  41. timings['compute-pdf-caching'],
  42. 1,
  43. request.metricsOpts
  44. )
  45. // How large is the overhead of hashing up-front?
  46. const fraction =
  47. timings.compileE2E - timings['compute-pdf-caching'] !== 0
  48. ? timings.compileE2E /
  49. (timings.compileE2E - timings['compute-pdf-caching'])
  50. : 1
  51. if (fraction > 1.5 && timings.compileE2E > 10 * 1000) {
  52. logger.warn(
  53. {
  54. stats,
  55. timings,
  56. load: getSystemLoad(),
  57. },
  58. 'slow pdf caching'
  59. )
  60. }
  61. Metrics.summary(
  62. 'overhead-compute-pdf-ranges',
  63. fraction * 100 - 100,
  64. request.metricsOpts
  65. )
  66. // How does the hashing scale to pdf size in MB?
  67. Metrics.timing(
  68. 'compute-pdf-caching-relative-to-pdf-size',
  69. timings['compute-pdf-caching'] / (stats['pdf-size'] / ONE_MB),
  70. 1,
  71. request.metricsOpts
  72. )
  73. if (stats['pdf-caching-total-ranges-size']) {
  74. // How does the hashing scale to total ranges size in MB?
  75. Metrics.timing(
  76. 'compute-pdf-caching-relative-to-total-ranges-size',
  77. timings['compute-pdf-caching'] /
  78. (stats['pdf-caching-total-ranges-size'] / ONE_MB),
  79. 1,
  80. request.metricsOpts
  81. )
  82. // How fast is the hashing per range on average?
  83. Metrics.timing(
  84. 'compute-pdf-caching-relative-to-ranges-count',
  85. timings['compute-pdf-caching'] / stats['pdf-caching-n-ranges'],
  86. 1,
  87. request.metricsOpts
  88. )
  89. // How many ranges are new?
  90. Metrics.summary(
  91. 'new-pdf-ranges-relative-to-total-ranges',
  92. (stats['pdf-caching-n-new-ranges'] / stats['pdf-caching-n-ranges']) * 100,
  93. request.metricsOpts
  94. )
  95. }
  96. // How much content is cacheable?
  97. Metrics.summary(
  98. 'cacheable-ranges-to-pdf-size',
  99. (stats['pdf-caching-total-ranges-size'] / stats['pdf-size']) * 100,
  100. request.metricsOpts
  101. )
  102. const sizeWhenDownloadedInFull =
  103. // All of the pdf
  104. stats['pdf-size'] -
  105. // These ranges are potentially cached.
  106. stats['pdf-caching-total-ranges-size'] +
  107. // These ranges are not cached.
  108. stats['pdf-caching-new-ranges-size']
  109. // How much bandwidth can we save when downloading the pdf in full?
  110. Metrics.summary(
  111. 'pdf-bandwidth-savings',
  112. 100 - (sizeWhenDownloadedInFull / stats['pdf-size']) * 100,
  113. request.metricsOpts
  114. )
  115. // How much bandwidth will the pdf incur when downloaded in full?
  116. Metrics.summary(
  117. 'pdf-bandwidth',
  118. sizeWhenDownloadedInFull,
  119. request.metricsOpts
  120. )
  121. // How much space do the ranges use?
  122. // This will accumulate the ranges size over time, skipping already written ranges.
  123. Metrics.summary(
  124. 'pdf-ranges-disk-size',
  125. stats['pdf-caching-new-ranges-size'] - stats['pdf-caching-reclaimed-space'],
  126. request.metricsOpts
  127. )
  128. }
  129. module.exports = {
  130. emitPdfStats,
  131. }