65 lines
1.6 KiB
Python
65 lines
1.6 KiB
Python
# graph/critical_path.py
|
|
|
|
def compute_critical_path(actions):
|
|
"""
|
|
Computes the longest dependency-weighted path in a build DAG.
|
|
|
|
This represents the true bottleneck chain ("critical path")
|
|
that determines total build time.
|
|
"""
|
|
|
|
# -----------------------------
|
|
# Build adjacency + cost map
|
|
# -----------------------------
|
|
graph = {}
|
|
duration = {}
|
|
|
|
for action in actions:
|
|
name = action["name"]
|
|
deps = action.get("deps", [])
|
|
|
|
graph[name] = deps
|
|
|
|
# fallback cost model (later replace with real timing data)
|
|
duration[name] = action.get("cost", 1)
|
|
|
|
# -----------------------------
|
|
# memoized DFS for longest path
|
|
# -----------------------------
|
|
memo = {}
|
|
|
|
def dfs(node):
|
|
if node in memo:
|
|
return memo[node]
|
|
|
|
# leaf node
|
|
if node not in graph or not graph[node]:
|
|
memo[node] = duration.get(node, 1)
|
|
return memo[node]
|
|
|
|
best_dep = 0
|
|
|
|
for dep in graph[node]:
|
|
best_dep = max(best_dep, dfs(dep))
|
|
|
|
memo[node] = best_dep + duration.get(node, 1)
|
|
return memo[node]
|
|
|
|
# -----------------------------
|
|
# find worst (critical) endpoint
|
|
# -----------------------------
|
|
critical_node = None
|
|
critical_score = -1
|
|
|
|
for node in graph.keys():
|
|
score = dfs(node)
|
|
if score > critical_score:
|
|
critical_score = score
|
|
critical_node = node
|
|
|
|
return {
|
|
"critical_node": critical_node,
|
|
"critical_score": critical_score,
|
|
"score_map": memo
|
|
}
|