Skip to content

Commit 70cecaf

Browse files
committed
rank only, change formula
1 parent 9addd95 commit 70cecaf

File tree

4 files changed

+45
-31
lines changed

4 files changed

+45
-31
lines changed
Binary file not shown.

codeflash/benchmarking/function_ranker.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,17 @@
1414

1515

1616
class FunctionRanker:
17-
"""Ranks and filters functions for optimization based on profiling trace data using the ttX scoring method.
17+
"""Ranks and filters functions based on a ttX score derived from profiling data.
1818
19-
The FunctionRanker analyzes function-level timing statistics from a trace file and assigns a ttX score to each function:
19+
The ttX score is calculated as:
20+
ttX = own_time + (time_spent_in_callees / call_count)
2021
21-
ttX = own_time + (time_spent_in_callees x call_count)
22+
This score prioritizes functions that are computationally heavy themselves (high `own_time`)
23+
or that make expensive calls to other functions (high average `time_spent_in_callees`).
2224
23-
This scoring prioritizes functions that:
24-
1. Consume significant time themselves (own_time)
25-
2. Are called frequently and have expensive subcalls (time_spent_in_callees x call_count)
26-
27-
first, filters out functions whose own_time is less than a specified percentage (importance_threshold = minimum fraction of total runtime a function must account for to be considered important) of the total runtime, considering them unimportant for optimization.
28-
29-
The remaining functions are then ranked in descending order by their ttX score, prioritizing those most likely to yield performance improvements if optimized.
25+
Functions are first filtered by an importance threshold based on their `own_time` as a
26+
fraction of the total runtime. The remaining functions are then ranked by their ttX score
27+
to identify the best candidates for optimization.
3028
"""
3129

3230
def __init__(self, trace_file_path: Path) -> None:
@@ -59,7 +57,7 @@ def load_function_stats(self) -> None:
5957
time_in_callees_ns = cumulative_time_ns - total_time_ns
6058

6159
# Calculate ttX score
62-
ttx_score = own_time_ns + (time_in_callees_ns * call_count)
60+
ttx_score = own_time_ns + (time_in_callees_ns / call_count)
6361

6462
function_key = f"{filename}:{qualified_name}"
6563
self._function_stats[function_key] = {
@@ -99,11 +97,27 @@ def get_function_ttx_score(self, function_to_optimize: FunctionToOptimize) -> fl
9997
return stats["ttx_score"] if stats else 0.0
10098

10199
def rank_functions(self, functions_to_optimize: list[FunctionToOptimize]) -> list[FunctionToOptimize]:
102-
return sorted(functions_to_optimize, key=self.get_function_ttx_score, reverse=True)
100+
ranked = sorted(functions_to_optimize, key=self.get_function_ttx_score, reverse=True)
101+
logger.info(
102+
f"Function ranking order: {[f'{func.function_name} (ttX={self.get_function_ttx_score(func):.2f})' for func in ranked]}"
103+
)
104+
return ranked
103105

104106
def get_function_stats_summary(self, function_to_optimize: FunctionToOptimize) -> dict | None:
105107
return self._get_function_stats(function_to_optimize)
106108

109+
def rerank_functions(self, functions_to_optimize: list[FunctionToOptimize]) -> list[FunctionToOptimize]:
110+
"""Ranks functions based on their ttX score.
111+
112+
This method calculates the ttX score for each function and returns
113+
the functions sorted in descending order of their ttX score.
114+
"""
115+
if not self._function_stats:
116+
logger.warning("No function stats available to rank functions.")
117+
return []
118+
119+
return self.rank_functions(functions_to_optimize)
120+
107121
def rerank_and_filter_functions(self, functions_to_optimize: list[FunctionToOptimize]) -> list[FunctionToOptimize]:
108122
"""Reranks and filters functions based on their impact on total runtime.
109123

codeflash/discovery/functions_to_optimize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def get_functions_to_optimize(
218218
all_functions.extend(file_functions)
219219

220220
if all_functions:
221-
ranked_functions = ranker.rerank_and_filter_functions(all_functions)
221+
ranked_functions = ranker.rank_functions(all_functions)
222222
functions_count = len(ranked_functions)
223223

224224
ranked_dict = {}

tests/test_function_ranker.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ def test_load_function_stats(function_ranker):
5858
# Verify funcA specific values
5959
assert func_a_stats["function_name"] == "funcA"
6060
assert func_a_stats["call_count"] == 1
61-
assert func_a_stats["own_time_ns"] == 153000
62-
assert func_a_stats["cumulative_time_ns"] == 5960000
61+
assert func_a_stats["own_time_ns"] == 63000
62+
assert func_a_stats["cumulative_time_ns"] == 5443000
6363

6464

6565
def test_get_function_ttx_score(function_ranker, workload_functions):
@@ -72,9 +72,9 @@ def test_get_function_ttx_score(function_ranker, workload_functions):
7272
assert func_a is not None
7373
ttx_score = function_ranker.get_function_ttx_score(func_a)
7474

75-
# Expected ttX score: own_time + (time_in_callees * call_count)
76-
# = 153000 + ((5960000 - 153000) * 1) = 5960000
77-
assert ttx_score == 5960000
75+
# Expected ttX score: own_time + (time_in_callees / call_count)
76+
# = 63000 + ((5443000 - 63000) / 1) = 5443000
77+
assert ttx_score == 5443000
7878

7979

8080
def test_rank_functions(function_ranker, workload_functions):
@@ -112,9 +112,9 @@ def test_get_function_stats_summary(function_ranker, workload_functions):
112112

113113
assert stats is not None
114114
assert stats["function_name"] == "funcA"
115-
assert stats["own_time_ns"] == 153000
116-
assert stats["cumulative_time_ns"] == 5960000
117-
assert stats["ttx_score"] == 5960000
115+
assert stats["own_time_ns"] == 63000
116+
assert stats["cumulative_time_ns"] == 5443000
117+
assert stats["ttx_score"] == 5443000
118118

119119

120120

@@ -134,8 +134,8 @@ def test_importance_calculation(function_ranker):
134134
assert func_a_stats is not None
135135
importance = func_a_stats["own_time_ns"] / total_program_time
136136

137-
# funcA importance should be approximately 1.0% (153000/15281000)
138-
assert abs(importance - 0.01001) < 0.001
137+
# funcA importance should be approximately 0.57% (63000/10968000)
138+
assert abs(importance - 0.0057) < 0.001
139139

140140

141141
def test_simple_model_predict_stats(function_ranker, workload_functions):
@@ -152,21 +152,21 @@ def test_simple_model_predict_stats(function_ranker, workload_functions):
152152
assert stats is not None
153153
assert stats["function_name"] == "predict"
154154
assert stats["call_count"] == 1
155-
assert stats["own_time_ns"] == 2368000
156-
assert stats["cumulative_time_ns"] == 4103000
157-
assert stats["ttx_score"] == 4103000
155+
assert stats["own_time_ns"] == 2289000
156+
assert stats["cumulative_time_ns"] == 4017000
157+
assert stats["ttx_score"] == 4017000
158158

159159
# Test ttX score calculation
160160
ttx_score = function_ranker.get_function_ttx_score(predict_func)
161-
# Expected ttX score: own_time + (time_in_callees * call_count)
162-
# = 2368000 + ((4103000 - 2368000) * 1) = 4103000
163-
assert ttx_score == 4103000
161+
# Expected ttX score: own_time + (time_in_callees / call_count)
162+
# = 2289000 + ((4017000 - 2289000) / 1) = 4017000
163+
assert ttx_score == 4017000
164164

165165
# Test importance calculation for predict function
166166
total_program_time = sum(
167167
s["own_time_ns"] for s in function_ranker._function_stats.values()
168168
if s.get("own_time_ns", 0) > 0
169169
)
170170
importance = stats["own_time_ns"] / total_program_time
171-
# predict importance should be approximately 15.5% (2368000/15281000)
172-
assert abs(importance - 0.155) < 0.01
171+
# predict importance should be approximately 20.9% (2289000/10968000)
172+
assert abs(importance - 0.209) < 0.01

0 commit comments

Comments
 (0)