Skip to content

Commit

Permalink
Stop using pint to parse --pantsd-max-memory-usage due to perform…
Browse files Browse the repository at this point in the history
…ance regression (pantsbuild#12176)
  • Loading branch information
Eric-Arellano authored Jun 4, 2021
1 parent 66045c2 commit 657caa8
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 44 deletions.
7 changes: 3 additions & 4 deletions 3rdparty/python/constraints.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Generated by build-support/bin/generate_lockfile.sh on Tue May 25 10:22:48 MST 2021
# Generated by build-support/bin/generate_lockfile.sh on Thu Jun 3 22:05:26 PDT 2021
ansicolors==1.1.8
attrs==21.2.0
bugout==0.1.12
certifi==2020.12.5
certifi==2021.5.30
cffi==1.14.5
chardet==4.0.0
cryptography==3.4.7
Expand All @@ -15,7 +15,6 @@ mypy==0.812
mypy-extensions==0.4.3
packaging==20.9
pex==2.1.42
Pint==0.17
pip==20.2.3
pluggy==0.13.1
psutil==5.8.0
Expand All @@ -35,4 +34,4 @@ six==1.16.0
toml==0.10.2
typed-ast==1.4.3
typing-extensions==3.7.4.3
urllib3==1.26.4
urllib3==1.26.5
1 change: 0 additions & 1 deletion 3rdparty/python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ mypy==0.812
packaging==20.9
pathspec==0.8.1
pex==2.1.42
pint==0.17
psutil==5.8.0
pystache==0.5.4
# This should be kept in sync with `pytest.py`.
Expand Down
3 changes: 0 additions & 3 deletions build-support/mypy/mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ ignore_missing_imports = True
[mypy-pex.*]
ignore_missing_imports = True

[mypy-pint]
ignore_missing_imports = True

[mypy-psutil]
ignore_missing_imports = True

Expand Down
48 changes: 30 additions & 18 deletions src/python/pants/option/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from enum import Enum
from typing import Dict, Iterable, List, Pattern, Sequence

import pint

from pants.option.errors import ParseError
from pants.util.eval import parse_expression
from pants.util.memo import memoized_method
Expand Down Expand Up @@ -103,7 +101,7 @@ def shell_str(s: str) -> str:


def memory_size(s: str | int | float) -> int:
"""A string or number that normalizes into the number of bytes.
"""A string that normalizes the suffixes {GiB, MiB, KiB, B} into the number of bytes.
:API: public
"""
Expand All @@ -112,23 +110,37 @@ def memory_size(s: str | int | float) -> int:
if not s:
raise ParseError("Missing value.")

ureg = pint.UnitRegistry()
invalid_suffix = ParseError(
f"Invalid suffix for `{s}`. Expected either a bare number or one of `GB`, `GiB`, `MB`, "
f"`MiB`, `kB`, `KiB`, or `B`."
)
try:
parsed = ureg(s)
except pint.UndefinedUnitError:
raise invalid_suffix
original = s
s = s.lower().strip()

if isinstance(parsed, (int, float)):
return int(parsed)
try:
parsed.ito("byte")
except pint.DimensionalityError:
raise invalid_suffix
return int(parsed.magnitude)
return int(float(s))
except ValueError:
pass

invalid = ParseError(
f"Invalid value: `{original}`. Expected either a bare number or a number with one of "
f"`GiB`, `MiB`, `KiB`, or `B`."
)

def convert_to_bytes(power_of_2) -> int:
try:
return int(float(s[:-3]) * (2 ** power_of_2)) # type: ignore[index]
except TypeError:
raise invalid

if s.endswith("gib"):
return convert_to_bytes(30)
elif s.endswith("mib"):
return convert_to_bytes(20)
elif s.endswith("kib"):
return convert_to_bytes(10)
elif s.endswith("b"):
try:
return int(float(s[:-1]))
except TypeError:
raise invalid
raise invalid


def _convert(val, acceptable_types):
Expand Down
11 changes: 1 addition & 10 deletions src/python/pants/option/custom_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,14 @@ def test_memory_size() -> None:
assert memory_size("1GiB") == 1_073_741_824
assert memory_size(" 1 GiB ") == 1_073_741_824
assert memory_size("1.22GiB") == 1_309_965_025
assert memory_size("1GB") == 1_000_000_000

assert memory_size("1MiB") == 1_048_576
assert memory_size(" 1 MiB ") == 1_048_576
assert memory_size("1.4MiB") == 1_468_006
assert memory_size("1MB") == 1_000_000

assert memory_size("1KiB") == 1024
assert memory_size(" 1 KiB ") == 1024
assert memory_size("1.4KiB") == 1433
assert memory_size("1kB") == 1000

assert memory_size("10B") == 10
assert memory_size(" 10 B ") == 10
Expand All @@ -39,17 +36,11 @@ def test_memory_size() -> None:
assert memory_size(" 10 ") == 10
assert memory_size("10.4") == 10

# Capitalization matters:
with pytest.raises(ParseError):
memory_size("1gib")
with pytest.raises(ParseError):
memory_size("1gb")

# Must be a Bytes unit.
with pytest.raises(ParseError):
memory_size("1ft")
with pytest.raises(ParseError):
memory_size("1Gib")
memory_size("1m")

# Invalid input.
with pytest.raises(ParseError):
Expand Down
4 changes: 2 additions & 2 deletions src/python/pants/option/global_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,8 @@ def register_bootstrap_options(cls, register):
"you may miss out on some caching, whereas setting too high may over-consume "
"resources and may result in the operating system killing Pantsd due to memory "
"overconsumption (e.g. via the OOM killer).\n\n"
"You can suffix with `GiB`, `GB`, `MiB`, `MB`, `KiB`, `kB`, or `B` to indicate "
"the unit, e.g. `2GiB` or `2.12GiB`. A bare number will be in bytes.\n\n"
"You can suffix with `GiB`, `MiB`, `KiB`, or `B` to indicate the unit, e.g. "
"`2GiB` or `2.12GiB`. A bare number will be in bytes.\n\n"
"There is at most one pantsd process per workspace."
),
)
Expand Down
10 changes: 4 additions & 6 deletions src/python/pants/pantsd/service/scheduler_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import time
from typing import Optional, Tuple, cast

import pint
import psutil

from pants.engine.fs import PathGlobs, Snapshot
Expand Down Expand Up @@ -125,12 +124,11 @@ def _check_pidfile(self):
def _check_memory_usage(self):
memory_usage_in_bytes = psutil.Process(self._pid).memory_info()[0]
if memory_usage_in_bytes > self._max_memory_usage_in_bytes:
ureg = pint.UnitRegistry()
memory_usage = (memory_usage_in_bytes * ureg.byte).to_compact()
max_memory_usage = (self._max_memory_usage_in_bytes * ureg.byte).to_compact()
bytes_per_mib = 1_048_576
raise Exception(
f"pantsd process {self._pid} was using {memory_usage:~} of memory (above the "
f"`--pantsd-max-memory-usage` limit of {max_memory_usage:~})."
f"pantsd process {self._pid} was using {memory_usage_in_bytes / bytes_per_mib:.2f} "
f"MiB of memory (above the `--pantsd-max-memory-usage` limit of "
f"{self._max_memory_usage_in_bytes / bytes_per_mib:.2f} MiB)."
)

def _check_invalidation_watcher_liveness(self):
Expand Down

0 comments on commit 657caa8

Please sign in to comment.