Skip to content

Commit 4630d2a

Browse files
authored
Merge pull request #934 from DeusData/fix/wide-flat-ratio
fix(test): scaling-ratio form for the wide-flat linearity guard
2 parents 3d8d2c1 + f380a45 commit 4630d2a

1 file changed

Lines changed: 60 additions & 20 deletions

File tree

tests/test_extraction.c

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
*/
88
#include "test_framework.h"
99
#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>
1112

1213
/* ── Helpers ───────────────────────────────────────────────────── */
1314

@@ -3406,37 +3407,76 @@ TEST(extract_rust_test_attr_marks_is_test_issue855) {
34063407
* RED on index-based child pushes, GREEN on the cursor walk. The def-count
34073408
* guard keeps the test honest: extraction must actually process the whole
34083409
* 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 */
34183416
char *src = malloc(cap);
3419-
ASSERT_NOT_NULL(src);
3417+
if (!src) {
3418+
return -1;
3419+
}
34203420
size_t off = 0;
34213421
for (int i = 0; i < n; i++) {
34223422
off += (size_t)snprintf(src + off, cap - off, "// wide filler %d\n", i);
3423-
if (i % 4000 == 0) {
3423+
if (i % 2000 == 0) {
34243424
off += (size_t)snprintf(src + off, cap - off, "var wide_a%d = %d;\n", i, i);
34253425
}
34263426
}
3427-
time_t start = time(NULL);
3427+
struct timespec a;
3428+
struct timespec b;
3429+
cbm_clock_gettime(CLOCK_MONOTONIC, &a);
34283430
CBMFileResult *r =
34293431
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);
34313433
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;
34353438
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];
34383476
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);
34403480
FAIL(msg);
34413481
}
34423482
PASS();

0 commit comments

Comments
 (0)