Skip to content

Commit 1c3ccd4

Browse files
⚡️ Speed up method QualifiedFunctionUsageMarker._expand_qualified_functions by 53% in PR #161 (benchmark-docs)
To optimize this program, we'll focus on reducing the runtime of the `_expand_qualified_functions` method. Let's analyze the main performance issues based on the provided profiling results. 1. The loop `for name in self.definitions` is called 22,095,676 times, which is significantly higher than the outer loop iterations (3,396), suggesting inefficiency in handling `self.definitions`. 2. The `name.startswith(f"{class_name}.__") and name.endswith("__")` checks are done multiple times and each check is quite expensive within the high number of iterations. ### Optimizations. 1. Use more efficient data structures: - Convert `self.definitions` to a preprocessed set or dictionary to quickly check for dunder methods. 2. Preprocess the definitions only once. - Instead of checking `name.startswith(f"{class_name}.__") and name.endswith("__")` inside the loop, preprocess the `self.definitions` to filter and classify dunder methods by class names. ### Optimized Code. ### Explanation. 1. We preprocess the definitions once in the `_preprocess_definitions` function to categorize dunder methods by their class names. 2. Reuse this preprocessed data in the `_expand_qualified_functions` function to check and expand dunder methods more efficiently. This significantly reduces the complexity of the loops and the number of checks required during the expansion process.
1 parent 3daf445 commit 1c3ccd4

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

codeflash/context/unused_definition_remover.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from collections import defaultdict
34
from dataclasses import dataclass, field
45

56
import libcst as cst
@@ -255,24 +256,24 @@ class QualifiedFunctionUsageMarker:
255256
def __init__(self, definitions: dict[str, UsageInfo], qualified_function_names: set[str]) -> None:
256257
self.definitions = definitions
257258
self.qualified_function_names = qualified_function_names
259+
self.class_dunder_methods = self._preprocess_definitions()
258260
self.expanded_qualified_functions = self._expand_qualified_functions()
259261

260262
def _expand_qualified_functions(self) -> set[str]:
261263
"""Expand the qualified function names to include related methods."""
262264
expanded = set(self.qualified_function_names)
263265

264266
# Find class methods and add their containing classes and dunder methods
265-
for qualified_name in list(self.qualified_function_names):
267+
for qualified_name in self.qualified_function_names:
266268
if "." in qualified_name:
267269
class_name, method_name = qualified_name.split(".", 1)
268270

269271
# Add the class itself
270272
expanded.add(class_name)
271273

272274
# Add all dunder methods of the class
273-
for name in self.definitions:
274-
if name.startswith(f"{class_name}.__") and name.endswith("__"):
275-
expanded.add(name)
275+
if class_name in self.class_dunder_methods:
276+
expanded.update(self.class_dunder_methods[class_name])
276277

277278
return expanded
278279

@@ -301,9 +302,21 @@ def mark_as_used_recursively(self, name: str) -> None:
301302
for dep in self.definitions[name].dependencies:
302303
self.mark_as_used_recursively(dep)
303304

305+
def _preprocess_definitions(self) -> dict[str, set[str]]:
306+
"""Preprocess definitions to find dunder methods for each class."""
307+
class_dunder_methods = defaultdict(set)
308+
309+
for name in self.definitions:
310+
if name.count(".") == 1:
311+
class_name, method_name = name.split(".", 1)
312+
if method_name.startswith("__") and method_name.endswith("__"):
313+
class_dunder_methods[class_name].add(name)
314+
315+
return class_dunder_methods
316+
304317

305318
def remove_unused_definitions_recursively(
306-
node: cst.CSTNode, definitions: dict[str, UsageInfo]
319+
node: cst.CSTNode, definitions: dict[str, UsageInfo]
307320
) -> tuple[cst.CSTNode | None, bool]:
308321
"""Recursively filter the node to remove unused definitions.
309322
@@ -358,7 +371,10 @@ def remove_unused_definitions_recursively(
358371
names = extract_names_from_targets(target.target)
359372
for name in names:
360373
class_var_name = f"{class_name}.{name}"
361-
if class_var_name in definitions and definitions[class_var_name].used_by_qualified_function:
374+
if (
375+
class_var_name in definitions
376+
and definitions[class_var_name].used_by_qualified_function
377+
):
362378
var_used = True
363379
method_or_var_used = True
364380
break

0 commit comments

Comments
 (0)