Commit bd820f8
authored
Reduce key path COW copies in Graph forEach and compactMapValues (#1725)
This avoids an accidentally-superlinear COW copy of the key path during
`Graph.forEach` and `Graph.compactMapValues` traversal.
### Motivation:
While reading [@harlanhaskins](https://github.com/harlanhaskins)'
[#1626](#1626) (which
fixes a quadratic COW issue on `Graph.insertValue`), I noticed that
`_forEach` and
`_compactMapValues` carry a related — though less dramatic — version of
the same pattern. Each recursive call builds the descendant's key path
with `var childKeyPath = keyPath; childKeyPath.append(key)`, and because
`childKeyPath` is COW-shared with `keyPath`, the `append` always
triggers a copy of the whole key-path array. For a graph with `N` nodes
at average depth `d`, this turns traversal into _O(N · d)_ instead of
the _O(N)_ it should
be.
In isolated benchmarks of the key-path copy pattern at depths 3–6 with
branching factor 3–5, the new inout-based version is consistently **3–5×
faster**, with the speedup growing with depth — exactly as expected from
the _O(N ·
d) → O(N)_ change:
| Config | Nodes | Old | New | Speedup |
| --- | --- | --- | --- | --- |
| depth 3, branch 3 | 40 | 0.006 ms | 0.002 ms | 3.51× |
| depth 4, branch 4 | 341 | 0.059 ms | 0.012 ms | 4.84× |
| depth 4, branch 5 | 781 | 0.138 ms | 0.029 ms | 4.84× |
| depth 5, branch 4 | 1,365 | 0.242 ms | 0.046 ms | 5.21× |
| depth 6, branch 4 | 5,461 | 0.830 ms | 0.159 ms | 5.23× |
### Modifications:
The four `_forEach` / `_compactMapValues` overloads (sync + async for
each) now thread a single `inout [K]` through the recursion. After
invoking the body, the child's key is appended once, recursion descends,
and the key is
popped on the way back up — mutating the key path in place rather than
copying it on every descent. The public `forEach(_:)` and
`compactMapValues(_:)` wrappers create the initial `var keyPath: [K] =
[]` and pass it through; the
public API surface is unchanged.
All six current `forEach` callsites (two in `Runner.Plan`, four in
`AdvancedConsoleOutputRecorder`) consume the key path inline — none of
them escape it — so the existing semantics are preserved. The existing
`GraphTests` for
`forEach`, `forEach (async)`, and `compactMapValues` pass unchanged.
### Checklist:
- [x] Code and documentation should follow the style of the [Style
Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md).
- [x] If public symbols are renamed or modified, DocC references should
be updated.1 parent ae4bccb commit bd820f8
1 file changed
Lines changed: 30 additions & 30 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
389 | 389 | | |
390 | 390 | | |
391 | 391 | | |
392 | | - | |
393 | | - | |
| 392 | + | |
394 | 393 | | |
395 | 394 | | |
396 | 395 | | |
397 | 396 | | |
398 | | - | |
| 397 | + | |
399 | 398 | | |
400 | 399 | | |
401 | | - | |
402 | | - | |
403 | | - | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
404 | 403 | | |
405 | 404 | | |
406 | 405 | | |
407 | 406 | | |
408 | 407 | | |
409 | 408 | | |
410 | | - | |
411 | | - | |
| 409 | + | |
412 | 410 | | |
413 | 411 | | |
414 | 412 | | |
415 | 413 | | |
416 | | - | |
| 414 | + | |
417 | 415 | | |
418 | 416 | | |
419 | | - | |
420 | | - | |
421 | | - | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
422 | 420 | | |
423 | 421 | | |
424 | 422 | | |
| |||
432 | 430 | | |
433 | 431 | | |
434 | 432 | | |
435 | | - | |
| 433 | + | |
| 434 | + | |
436 | 435 | | |
437 | 436 | | |
438 | 437 | | |
| |||
447 | 446 | | |
448 | 447 | | |
449 | 448 | | |
450 | | - | |
| 449 | + | |
| 450 | + | |
451 | 451 | | |
452 | 452 | | |
453 | 453 | | |
| |||
546 | 546 | | |
547 | 547 | | |
548 | 548 | | |
549 | | - | |
| 549 | + | |
| 550 | + | |
550 | 551 | | |
551 | 552 | | |
552 | 553 | | |
553 | 554 | | |
554 | 555 | | |
555 | 556 | | |
556 | 557 | | |
557 | | - | |
558 | | - | |
| 558 | + | |
559 | 559 | | |
560 | 560 | | |
561 | 561 | | |
| |||
565 | 565 | | |
566 | 566 | | |
567 | 567 | | |
568 | | - | |
| 568 | + | |
569 | 569 | | |
570 | 570 | | |
571 | 571 | | |
572 | 572 | | |
573 | 573 | | |
574 | 574 | | |
575 | 575 | | |
576 | | - | |
577 | | - | |
| 576 | + | |
| 577 | + | |
578 | 578 | | |
579 | 579 | | |
580 | | - | |
| 580 | + | |
581 | 581 | | |
582 | | - | |
| 582 | + | |
583 | 583 | | |
584 | 584 | | |
585 | 585 | | |
| |||
606 | 606 | | |
607 | 607 | | |
608 | 608 | | |
609 | | - | |
| 609 | + | |
| 610 | + | |
610 | 611 | | |
611 | 612 | | |
612 | 613 | | |
613 | 614 | | |
614 | 615 | | |
615 | 616 | | |
616 | 617 | | |
617 | | - | |
618 | | - | |
| 618 | + | |
619 | 619 | | |
620 | 620 | | |
621 | 621 | | |
| |||
625 | 625 | | |
626 | 626 | | |
627 | 627 | | |
628 | | - | |
| 628 | + | |
629 | 629 | | |
630 | 630 | | |
631 | 631 | | |
632 | 632 | | |
633 | 633 | | |
634 | 634 | | |
635 | 635 | | |
636 | | - | |
637 | | - | |
| 636 | + | |
| 637 | + | |
638 | 638 | | |
639 | 639 | | |
640 | | - | |
| 640 | + | |
641 | 641 | | |
642 | | - | |
| 642 | + | |
643 | 643 | | |
644 | 644 | | |
645 | 645 | | |
| |||
0 commit comments