|
22 | 22 | if TYPE_CHECKING: |
23 | 23 | from collections.abc import Callable, Sequence |
24 | 24 | from pathlib import Path |
| 25 | + from types import ModuleType |
25 | 26 | from typing import Any |
26 | 27 |
|
| 28 | +psutil: ModuleType | None |
| 29 | +try: |
| 30 | + import psutil |
| 31 | +except ImportError: |
| 32 | + psutil = None |
| 33 | + |
27 | 34 | logger = logging.getLogger(__name__) |
28 | 35 |
|
29 | 36 | uploader = None |
@@ -211,33 +218,33 @@ def is_pypy() -> bool: |
211 | 218 | return sys.implementation.name == "pypy" |
212 | 219 |
|
213 | 220 |
|
214 | | -@pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS") |
| 221 | +@pytest.mark.skipif(psutil is None, reason="psutil not installed") |
| 222 | +@pytest.mark.skipif( |
| 223 | + sys.platform.startswith("win32"), |
| 224 | + reason="Leak limits are not calibrated for Windows", |
| 225 | +) |
215 | 226 | # Per https://stackoverflow.com/a/29007723/51685, due to JIT compilation, |
216 | 227 | # RSS utilization is known to grow in PyPy. |
217 | 228 | @pytest.mark.skipif(is_pypy(), reason="max RSS utilization is not stable on PyPy") |
218 | 229 | class PillowLeakTestCase: |
219 | | - # requires unix/macOS |
220 | 230 | iterations = 100 # count |
221 | 231 | mem_limit = 512 # k |
222 | 232 |
|
223 | 233 | def _get_mem_usage(self) -> float: |
224 | 234 | """ |
225 | | - Gets the RUSAGE memory usage, returns in K. Encapsulates the difference |
226 | | - between macOS and Linux rss reporting |
| 235 | + Gets the resident set size currently used by this process. |
227 | 236 |
|
228 | 237 | :returns: memory usage in kilobytes |
229 | 238 | """ |
230 | 239 |
|
231 | | - from resource import RUSAGE_SELF, getrusage |
232 | | - |
233 | | - mem = getrusage(RUSAGE_SELF).ru_maxrss |
234 | | - # man 2 getrusage: |
235 | | - # ru_maxrss |
236 | | - # This is the maximum resident set size utilized |
237 | | - # in bytes on macOS, in kilobytes on Linux |
238 | | - return mem / 1024 if sys.platform == "darwin" else mem |
| 240 | + assert psutil is not None |
| 241 | + return psutil.Process().memory_info().rss / 1024 |
239 | 242 |
|
240 | 243 | def _test_leak(self, core: Callable[[], None]) -> None: |
| 244 | + # Warm up so allocator arenas, caches, etc. are allocated, |
| 245 | + # before taking the baseline measurement. |
| 246 | + core() |
| 247 | + |
241 | 248 | start_mem = self._get_mem_usage() |
242 | 249 | for cycle in range(self.iterations): |
243 | 250 | core() |
|
0 commit comments