|
7 | 7 | */ |
8 | 8 | #include "test_framework.h" |
9 | 9 | #include "cbm.h" |
10 | | -#include <time.h> /* wide-flat linearity bound (extract_wide_flat_file_is_linear) */ |
| 10 | +#include "../src/foundation/compat.h" /* cbm_clock_gettime (wide-flat scaling guard) */ |
| 11 | +#include <time.h> |
11 | 12 |
|
12 | 13 | /* ── Helpers ───────────────────────────────────────────────────── */ |
13 | 14 |
|
@@ -3406,37 +3407,76 @@ TEST(extract_rust_test_attr_marks_is_test_issue855) { |
3406 | 3407 | * RED on index-based child pushes, GREEN on the cursor walk. The def-count |
3407 | 3408 | * guard keeps the test honest: extraction must actually process the whole |
3408 | 3409 | * breadth, not skip it. */ |
3409 | | -TEST(extract_wide_flat_file_is_linear) { |
3410 | | - /* Mirror the monster's exact shape: its 580k wide siblings are COMMENT |
3411 | | - * nodes, not defs, so this fixture isolates the WALK cost. A def-heavy |
3412 | | - * fixture (400k var statements) additionally hits a separate per-def |
3413 | | - * sibling-scan cost in extraction (O(defs x siblings), tracked as its own |
3414 | | - * finding) and took 647s even with the walk fixed — it guarded the wrong |
3415 | | - * thing. Sparse real defs keep the anti-vacuous breadth check. */ |
3416 | | - const int n = 400 * 1000; /* comment siblings */ |
3417 | | - const size_t cap = (size_t)n * 24 + (size_t)8192; /* "// wide filler 399999\n" = 22 chars */ |
| 3410 | +/* Extract a wide-flat comment-sibling fixture of n lines (the exact shape of |
| 3411 | + * ms-typescript's reallyLargeFile.ts: hundreds of thousands of flat comment |
| 3412 | + * children under the root, plus sparse real defs so the breadth check cannot |
| 3413 | + * pass vacuously). Returns elapsed milliseconds; stores the def count. */ |
| 3414 | +static long extract_wide_flat_ms(int n, int *out_defs) { |
| 3415 | + const size_t cap = (size_t)n * 24 + (size_t)8192; /* "// wide filler N\n" <= 24 chars */ |
3418 | 3416 | char *src = malloc(cap); |
3419 | | - ASSERT_NOT_NULL(src); |
| 3417 | + if (!src) { |
| 3418 | + return -1; |
| 3419 | + } |
3420 | 3420 | size_t off = 0; |
3421 | 3421 | for (int i = 0; i < n; i++) { |
3422 | 3422 | off += (size_t)snprintf(src + off, cap - off, "// wide filler %d\n", i); |
3423 | | - if (i % 4000 == 0) { |
| 3423 | + if (i % 2000 == 0) { |
3424 | 3424 | off += (size_t)snprintf(src + off, cap - off, "var wide_a%d = %d;\n", i, i); |
3425 | 3425 | } |
3426 | 3426 | } |
3427 | | - time_t start = time(NULL); |
| 3427 | + struct timespec a; |
| 3428 | + struct timespec b; |
| 3429 | + cbm_clock_gettime(CLOCK_MONOTONIC, &a); |
3428 | 3430 | CBMFileResult *r = |
3429 | 3431 | cbm_extract_file(src, (int)off, CBM_LANG_JAVASCRIPT, "proj", "wide.js", 0, NULL, NULL); |
3430 | | - long elapsed_s = (long)(time(NULL) - start); |
| 3432 | + cbm_clock_gettime(CLOCK_MONOTONIC, &b); |
3431 | 3433 | free(src); |
3432 | | - ASSERT_NOT_NULL(r); |
3433 | | - /* Anti-vacuous guard: the breadth was actually walked. */ |
3434 | | - ASSERT_GTE(r->defs.count, 100); |
| 3434 | + if (!r) { |
| 3435 | + return -1; |
| 3436 | + } |
| 3437 | + *out_defs = r->defs.count; |
3435 | 3438 | cbm_free_result(r); |
3436 | | - if (elapsed_s >= 30) { |
3437 | | - char msg[128]; |
| 3439 | + return (b.tv_sec - a.tv_sec) * 1000L + (b.tv_nsec - a.tv_nsec) / 1000000L; |
| 3440 | +} |
| 3441 | + |
| 3442 | +TEST(extract_wide_flat_file_is_linear) { |
| 3443 | + /* SCALING-RATIO guard: assert the COMPLEXITY CLASS, not a wall-clock |
| 3444 | + * bound. Index-based ts_node_child(i) child loops are O(i) per call — |
| 3445 | + * quadratic per wide node — and hung a 580k-sibling file for hours |
| 3446 | + * (ms-typescript reallyLargeFile.ts). An absolute time bound conflates |
| 3447 | + * machine speed with complexity: the gcc-13-ARM ASan CI leg runs this |
| 3448 | + * extraction ~200x slower than clang at the SAME (measured perfectly |
| 3449 | + * linear: 27.1s/54.2s/108.3s for 50k/100k/200k) complexity, and flunked |
| 3450 | + * a 30s bound on linear code. Growing the input 4x must grow the time |
| 3451 | + * ~4x when linear and ~16x when quadratic; the 10x bound splits those |
| 3452 | + * decisively on every toolchain. The 120ms floor keeps clock noise from |
| 3453 | + * mattering on fast machines. */ |
| 3454 | + /* Growth and bound CALIBRATED FROM MEASUREMENT, not models. The ASan |
| 3455 | + * test build carries a large LINEAR per-line baseline (~31us/line on |
| 3456 | + * clang-macOS, ~540us/line on gcc-13-ARM) that dilutes small-growth |
| 3457 | + * ratios: at 8x growth the measured quadratic ratio was 22.4 — a 24x |
| 3458 | + * bound false-passed the known-quadratic pre-merge walk. At 20x growth |
| 3459 | + * the measured ratios are ~20x for linear code (both toolchains) and |
| 3460 | + * ~128x for the quadratic walk (clang-macOS) — bound 40 sits >=2x from |
| 3461 | + * both. The 120ms floor keeps clock noise irrelevant on fast hosts. */ |
| 3462 | + enum { WF_SMALL = 20 * 1000, WF_BIG = 400 * 1000, WF_RATIO_MAX = 40, WF_FLOOR_MS = 120 }; |
| 3463 | + int defs_small = 0; |
| 3464 | + int defs_big = 0; |
| 3465 | + long t_small = extract_wide_flat_ms(WF_SMALL, &defs_small); |
| 3466 | + long t_big = extract_wide_flat_ms(WF_BIG, &defs_big); |
| 3467 | + ASSERT_GTE(t_small, 0); |
| 3468 | + ASSERT_GTE(t_big, 0); |
| 3469 | + /* Anti-vacuous guard: the breadth was actually walked at both sizes. */ |
| 3470 | + ASSERT_GTE(defs_small, 10); |
| 3471 | + ASSERT_GTE(defs_big, 40); |
| 3472 | + fprintf(stderr, " [wide-flat] t(%d)=%ldms t(%d)=%ldms\n", WF_SMALL, t_small, WF_BIG, t_big); |
| 3473 | + long base = t_small > WF_FLOOR_MS ? t_small : WF_FLOOR_MS; |
| 3474 | + if (t_big > WF_RATIO_MAX * base) { |
| 3475 | + char msg[160]; |
3438 | 3476 | snprintf(msg, sizeof(msg), |
3439 | | - "wide-flat extract took %lds (>=30s bound) — quadratic child access", elapsed_s); |
| 3477 | + "wide-flat scaling 20x input: %ldms -> %ldms (> %dx base %ldms) — " |
| 3478 | + "quadratic child access", |
| 3479 | + t_small, t_big, WF_RATIO_MAX, base); |
3440 | 3480 | FAIL(msg); |
3441 | 3481 | } |
3442 | 3482 | PASS(); |
|
0 commit comments