Skip to content

L4 serial tail solves every function 3x: singleton SCCs iterate twice and assemble_sdg re-solves #155

Description

@rahlk

Problem

Roughly 48% of the L3/L4 dataflow layer is serial whole-program workcompute_summaries (33.8s) plus assemble_sdg (28.8s) on erpnext L4, out of a 228.6s run. #154 established that parallelising the other half is a dead end (measured 3.1× slower), so this is where the remaining time is.

Measurement says the serial tail is not fundamentally expensive — it is doing the same work three times.

The redundancy, measured

Instrumenting solve_function (the DDG re-derivation + reaching-defs + flow derivation that both phases call) on the flask fixture, 386 functions:

phase solve_function calls
compute_summaries 772 (exactly 2× per function)
assemble_sdg 386 (1× per function)
total 1,158 = 3.0× the 386 actually needed

solve_function accounts for 95% of the serial tail's wall time, so the call count is very nearly the cost.

Two independent causes:

  1. Singleton SCCs are solved twice. compute_summaries runs while changed: for sig in members: .... For a non-recursive function the first pass computes the summary and sets changed=True; the second pass recomputes an identical summary purely to observe convergence. Singleton SCCs are the overwhelming majority of functions.

  2. assemble_sdg re-solves from scratch. compute_summaries discards its own intermediate results (new, _, _ = solve_function(...)), then assemble_sdg calls solve_function(info, summaries) again for every signature to recover the facts and DDG it needs.

Proposed fix

  • Solve singleton SCCs once. An SCC of one member with no self-edge cannot change on a second pass — nothing it depends on is still moving, because the condensation DAG is processed bottom-up. Guard the re-iteration on len(members) > 1 or has_self_edge.
  • Reuse the converged solve. Have compute_summaries retain the (facts, ddg) from each function's final solve and hand it to assemble_sdg, which currently recomputes it. This is sound because at convergence every member was solved against the final summaries: the last pass is the one in which nothing changed, and lower SCCs were already final.

Expected: 3 solves per function → 1, i.e. up to a 3× reduction of the serial tail, ~18% off L4 wall on erpnext and proportionally more at odoo-full scale, where the tail is larger.

CAVEATS

DEFINITION OF DONE

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions