Skip to content

Commit 608134f

Browse files
authored
Speed up suppressed deps options processing (#20806)
`suppressed_deps_opts` was consuming 5% of total CPU in a small incremental run targeting a very large codebase. Make it faster by avoiding json dump, and overall using a more efficient encoding. We could still make this faster by encoding the options as a single integer, but maybe this is already good enough.
1 parent b23d9e8 commit 608134f

2 files changed

Lines changed: 24 additions & 16 deletions

File tree

mypy/build.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,9 @@ def __init__(
905905
# location of a symbol used as a location for an error message.
906906
self.extra_trees: dict[str, MypyFile] = {}
907907
# Snapshot of import-related options per module. We record these even for
908-
# suppressed imports, since they can affect errors in the callers.
909-
self.import_options: dict[str, dict[str, object]] = {}
908+
# suppressed imports, since they can affect errors in the callers. Bytes
909+
# value is opaque but can be compared to detect changes in options.
910+
self.import_options: dict[str, bytes] = {}
910911
# Cache for transitive dependency check (expensive).
911912
self.transitive_deps_cache: dict[tuple[int, int], bool] = {}
912913

@@ -3065,13 +3066,15 @@ def update_fine_grained_deps(self, deps: dict[str, set[str]]) -> None:
30653066
type_state.update_protocol_deps(deps)
30663067

30673068
def suppressed_deps_opts(self) -> bytes:
3068-
return json_dumps(
3069-
{
3070-
dep: self.manager.import_options[dep]
3071-
for dep in self.suppressed
3072-
if self.priorities.get(dep) != PRI_INDIRECT
3073-
}
3074-
)
3069+
if not self.suppressed:
3070+
return b""
3071+
buf = WriteBuffer()
3072+
import_options = self.manager.import_options
3073+
for dep in sorted(self.suppressed):
3074+
if self.priorities.get(dep) != PRI_INDIRECT:
3075+
write_str_bare(buf, dep)
3076+
write_bytes_bare(buf, import_options[dep])
3077+
return buf.getvalue()
30753078

30763079
def write_cache(self) -> tuple[CacheMeta, str] | None:
30773080
assert self.tree is not None, "Internal error: method must be called on parsed file only"

mypy/options.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from re import Pattern
99
from typing import Any, Final
1010

11+
from librt.internal import WriteBuffer, write_bool, write_str
12+
1113
from mypy import defaults
1214
from mypy.errorcodes import ErrorCode, error_codes
1315
from mypy.util import get_class_descriptors, replace_object_state
@@ -628,10 +630,13 @@ def select_options_affecting_cache(self) -> tuple[str, list[object]]:
628630
result.append(val)
629631
return self.platform, result
630632

631-
def dep_import_options(self) -> dict[str, object]:
632-
# These are options that can affect dependent modules as well.
633-
return {
634-
"ignore_missing_imports": self.ignore_missing_imports,
635-
"follow_imports": self.follow_imports,
636-
"follow_imports_for_stubs": self.follow_imports_for_stubs,
637-
}
633+
def dep_import_options(self) -> bytes:
634+
"""Return opaque bytes with options that can affect dependent modules as well.
635+
636+
The value can be compared for equality to detect changed options.
637+
"""
638+
buf = WriteBuffer()
639+
write_bool(buf, self.ignore_missing_imports)
640+
write_str(buf, self.follow_imports)
641+
write_bool(buf, self.follow_imports_for_stubs)
642+
return buf.getvalue()

0 commit comments

Comments
 (0)