Dandandan opened a new pull request, #24330:
URL: https://github.com/apache/datafusion/pull/24330

   ## Which issue does this PR close?
   
   Fourth and last crate in the family from #24325 (`datafusion-catalog`), 
#24326
   (`datafusion-session`) and #24329 (`datafusion` core). Independent of all 
three —
   different crates, so they can merge in any order.
   
   ## Rationale for this change
   
   `datafusion-catalog-listing` is 3,013 lines of source but spends **20.5s** 
in the
   frontend during a cold `cargo build -p datafusion` (`cargo build 
--timings`), and
   it sits on the critical path between `datafusion-catalog` and `datafusion` 
core.
   
   `-Zself-profile` puts 58% of the crate's compile time in 
`evaluate_obligation`,
   and grouping those goals by the `Self` type in their `ParamEnv` shows all of 
it
   in one impl:
   
   | `Self` in `ParamEnv` | time | goals |
   |---|---|---|
   | `ListingTable` | 3.16s | 6,967 |
   | *(empty `ParamEnv`)* | 0.04s | 8,443 |
   
   Note the second row — the same kind of goals cost ~5µs each with an empty
   `ParamEnv` against ~450µs here.
   
   The cause is the one from the earlier PRs: `#[async_trait]` gives each 
`async fn`
   a `where 'life0: 'async_trait, ..` clause, which makes the method's 
`ParamEnv`
   non-empty, and rustc only serves auto-trait obligations from its **global**
   evaluation cache when the `ParamEnv` is empty. So the `Send`/`Sync` proof for
   everything the future captures is redone per method.
   
   All three async methods in this impl reach `Expr`:
   
   - `scan` takes `&[Expr]`
   - `scan_with_args` takes `ScanArgs<'a>`, which holds `&[Expr]`
   - `insert_into` keeps `self.options` (`Vec<Vec<SortExpr>>`) live across an 
await
   
   so each one pays for a walk of the whole `Expr`/`LogicalPlan` graph.
   
   ## What changes are included in this PR?
   
   Each method is now the hand-written desugaring of `async fn` and only 
forwards;
   the coroutine is built in a shim with no where-clauses, so its proofs land 
in the
   global cache. Bodies are moved verbatim into inherent fns and all three stay
   `async`, so nothing is evaluated any earlier than before —
   `Box::pin(self.m_inner(..))` polls nothing.
   
   Following the review on #24326, I measured each method's marginal 
contribution
   first, by reverting one at a time (together with its helpers) from the
   all-converted state:
   
   | state | crate build | `evaluate_obligation` |
   |---|---|---|
   | all three converted | 0.931s | 34.9ms |
   | revert `insert_into` | 1.866s | 1.01s |
   | revert `scan` | 1.943s | 1.05s |
   | revert `scan_with_args` | 2.118s | 1.17s |
   | none converted (base) | 4.201s | 3.25s |
   
   Unlike #24326 — where two of the seven bodies I first converted turned out to
   gain nothing — all three pull their weight here. Converting all of them 
leaves no
   coroutine in the impl at all, so the graph is never walked in a non-empty
   `ParamEnv`, which is why the total drops by two orders of magnitude rather 
than
   by a third.
   
   ## Are these changes tested?
   
   - `cargo test -p datafusion-catalog-listing` — 18 + 7 passed
   - `cargo test -p datafusion --lib` — 442 passed
   - `cargo check -p datafusion --all-targets` — clean (`ListingTable` is used
     heavily by core's integration tests and benches)
   - `cargo clippy -p datafusion-catalog-listing --all-targets` — clean
   - `cargo fmt --check` — clean
   
   The compiler checks each rewritten signature against the trait declaration, 
and
   every body is moved verbatim.
   
   Interleaved A/B of `cargo rustc -p datafusion-catalog-listing --lib`, 
alternating
   3 times so machine drift cancels out:
   
   ```
   base: 4.257s  4.189s  4.134s
   fix:  0.984s  0.935s  0.980s
   ```
   
   `evaluate_obligation` drops from 3.25s to 34.7ms.
   
   ## Are there any user-facing changes?
   
   No. No public signature changes — after macro expansion these methods have 
the
   same signatures as before.
   
   ### Follow-up
   
   With this, the four crates that made up the serial tail of a cold build are 
done.
   The general fix remains available and would cover downstream implementors 
too:
   drop `#[async_trait]` from these traits in favour of an explicit `BoxFuture`
   return with a single lifetime and no where-clauses, so that *every* impl is 
cheap
   without hand-desugaring. That is a breaking change to public traits, so it 
is out
   of scope here.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to