Skip to content

Commit 50a2538

Browse files
authored
Merge pull request #1686 from codeflash-ai/trace_ops
perf: optimize tracer hot path with string-based path ops and caching
2 parents 4efbd5f + 9475548 commit 50a2538

3 files changed

Lines changed: 21 additions & 27 deletions

File tree

codeflash/tracing/tracing_new_process.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def __init__(
125125
self.max_function_count = max_function_count
126126
self.config = config
127127
self.project_root = project_root
128+
self.project_root_str = str(project_root) + os.sep if project_root else ""
128129
console.rule(f"Project Root: {self.project_root}", style="bold blue")
129130
self.ignored_functions = {"<listcomp>", "<genexpr>", "<dictcomp>", "<setcomp>", "<lambda>", "<module>"}
130131

@@ -327,19 +328,20 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
327328
if code.co_name in self.ignored_functions:
328329
return
329330

330-
# Now resolve file path only if we need it
331+
# Resolve file path and check validity (cached)
331332
co_filename = code.co_filename
332333
if co_filename in self.path_cache:
333-
file_name = self.path_cache[co_filename]
334+
file_name, is_valid = self.path_cache[co_filename]
335+
if not is_valid:
336+
return
334337
else:
335-
file_name = Path(co_filename).resolve()
336-
self.path_cache[co_filename] = file_name
337-
# TODO : It currently doesn't log the last return call from the first function
338-
339-
if not file_name.is_relative_to(self.project_root):
340-
return
341-
if not file_name.exists():
342-
return
338+
resolved = os.path.realpath(co_filename)
339+
# startswith is cheaper than Path.is_relative_to, os.path.exists avoids Path construction
340+
is_valid = resolved.startswith(self.project_root_str) and os.path.exists(resolved) # noqa: PTH110
341+
self.path_cache[co_filename] = (resolved, is_valid)
342+
if not is_valid:
343+
return
344+
file_name = resolved
343345
if self.functions and code.co_name not in self.functions:
344346
return
345347
class_name = None
@@ -376,10 +378,11 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
376378
if function_qualified_name in self.ignored_qualified_functions:
377379
return
378380
if function_qualified_name not in self.function_count:
379-
# seeing this function for the first time
381+
# seeing this function for the first time — Path construction only happens here
380382
self.function_count[function_qualified_name] = 1
383+
file_path = Path(file_name)
381384
file_valid = filter_files_optimized(
382-
file_path=file_name,
385+
file_path=file_path,
383386
tests_root=Path(self.config["tests_root"]),
384387
ignore_paths=[Path(p) for p in self.config["ignore_paths"]],
385388
module_root=Path(self.config["module_root"]),
@@ -391,8 +394,8 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
391394
self.function_modules.append(
392395
FunctionModules(
393396
function_name=code.co_name,
394-
file_name=file_name,
395-
module_name=module_name_from_file_path(file_name, project_root_path=self.project_root),
397+
file_name=file_path,
398+
module_name=module_name_from_file_path(file_path, project_root_path=self.project_root),
396399
class_name=class_name,
397400
line_no=code.co_firstlineno,
398401
)
@@ -432,16 +435,7 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
432435

433436
cur.execute(
434437
"INSERT INTO function_calls VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
435-
(
436-
event,
437-
code.co_name,
438-
class_name,
439-
str(file_name),
440-
frame.f_lineno,
441-
frame.f_back.__hash__(),
442-
t_ns,
443-
local_vars,
444-
),
438+
(event, code.co_name, class_name, file_name, frame.f_lineno, frame.f_back.__hash__(), t_ns, local_vars),
445439
)
446440
self.trace_count += 1
447441
self.next_insert -= 1

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ __version__ = "{version}"
344344
[tool.codeflash]
345345
# All paths are relative to this pyproject.toml's directory.
346346
module-root = "codeflash"
347-
tests-root = "codeflash"
347+
tests-root = "tests"
348348
benchmarks-root = "tests/benchmarks"
349349
ignore-paths = []
350350
formatter-cmds = ["disabled"]

tests/test_worktree.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ def test_mirror_paths_for_worktree_mode(monkeypatch: pytest.MonkeyPatch):
6161
assert optimizer.args.test_project_root == worktree_dir
6262
assert optimizer.args.module_root == worktree_dir / "codeflash"
6363
# tests_root is configured as "codeflash" in pyproject.toml
64-
assert optimizer.args.tests_root == worktree_dir / "codeflash"
64+
assert optimizer.args.tests_root == worktree_dir / "tests"
6565
assert optimizer.args.file == worktree_dir / "codeflash/optimization/optimizer.py"
6666

67-
assert optimizer.test_cfg.tests_root == worktree_dir / "codeflash"
67+
assert optimizer.test_cfg.tests_root == worktree_dir / "tests"
6868
assert optimizer.test_cfg.project_root_path == worktree_dir # same as project_root
6969
assert optimizer.test_cfg.tests_project_rootdir == worktree_dir # same as test_project_root

0 commit comments

Comments
 (0)