MemoryLimit.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. /**
  3. * A tool for limiting allowed memory usage and memory leaks
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\TestFramework;
  9. class MemoryLimit
  10. {
  11. /**
  12. * @var \Magento\TestFramework\Helper\Memory
  13. */
  14. private $_helper;
  15. /**
  16. * @var int
  17. */
  18. private $_memCap = 0;
  19. /**
  20. * @var int
  21. */
  22. private $_leakCap = 0;
  23. /**
  24. * Initialize with the values
  25. *
  26. * @param string $memCap
  27. * @param string $leakCap
  28. * @param \Magento\TestFramework\Helper\Memory $helper
  29. * @throws \InvalidArgumentException
  30. */
  31. public function __construct($memCap, $leakCap, \Magento\TestFramework\Helper\Memory $helper)
  32. {
  33. $this->_memCap = $memCap ? $helper->convertToBytes($memCap) : 0;
  34. $this->_leakCap = $leakCap ? $helper->convertToBytes($leakCap) : 0;
  35. $this->_helper = $helper;
  36. }
  37. /**
  38. * Get a header printout
  39. *
  40. * @return string
  41. */
  42. public static function printHeader()
  43. {
  44. return PHP_EOL . '=== Memory Usage System Stats ===' . PHP_EOL;
  45. }
  46. /**
  47. * Get statistics printout
  48. *
  49. * @return string
  50. */
  51. public function printStats()
  52. {
  53. list($usage, $leak) = $this->_getUsage();
  54. $result = [];
  55. $msg = sprintf(
  56. "Memory usage (OS):\t%s (%.2F%% of %s reported by PHP",
  57. $this->_toMb($usage),
  58. 100 * $usage / ($usage - $leak),
  59. $this->_toMb($usage - $leak)
  60. );
  61. $percentMsg = '%.2F%% of configured %s limit';
  62. if ($this->_memCap) {
  63. $msg .= ', ' . sprintf($percentMsg, 100 * $usage / $this->_memCap, $this->_toMb($this->_memCap));
  64. }
  65. $result[] = "{$msg})";
  66. $msg = sprintf("Estimated memory leak:\t%s (%.2F%% of used memory", $this->_toMb($leak), 100 * $leak / $usage);
  67. if ($this->_leakCap) {
  68. $msg .= ', ' . sprintf($percentMsg, 100 * $leak / $this->_leakCap, $this->_toMb($this->_leakCap));
  69. }
  70. $result[] = "{$msg})";
  71. return implode(PHP_EOL, $result) . PHP_EOL;
  72. }
  73. /**
  74. * Convert bytes to mebibytes (2^20)
  75. *
  76. * @param int $bytes
  77. * @return string
  78. */
  79. private function _toMb($bytes)
  80. {
  81. return sprintf('%.2FM', $bytes / (1024 * 1024));
  82. }
  83. /**
  84. * Raise error if memory usage breaks configured thresholds
  85. *
  86. * @return null
  87. * @throws \LogicException
  88. */
  89. public function validateUsage()
  90. {
  91. if (!$this->_memCap && !$this->_leakCap) {
  92. return null;
  93. }
  94. list($usage, $leak) = $this->_getUsage();
  95. if ($this->_memCap && $usage >= $this->_memCap) {
  96. throw new \LogicException(
  97. "Memory limit of {$this->_toMb($this->_memCap)} ({$this->_memCap} bytes) has been reached."
  98. );
  99. }
  100. if ($this->_leakCap && $leak >= $this->_leakCap) {
  101. throw new \LogicException(
  102. "Estimated memory leak limit of {$this->_toMb(
  103. $this->_leakCap
  104. )}" . " ({$this->_leakCap} bytes) has been reached."
  105. );
  106. }
  107. }
  108. /**
  109. * Usage/leak getter sub-routine
  110. *
  111. * @return array
  112. */
  113. private function _getUsage()
  114. {
  115. $usage = $this->_helper->getRealMemoryUsage();
  116. return [$usage, $usage - memory_get_usage(true)];
  117. }
  118. }