Skip to content

Settle the native read timing test on paired rounds, and count the case work - #96

Merged
jwrosewell merged 1 commit into
rcfrom
fix/native-read-timing
Nov 13, 2026
Merged

jwrosewell merged 1 commit into
rcfrom
fix/native-read-timing

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

The problem

The full build of #94,
run 43436807511,
failed on macOS_Node_24 in a test #94 does not touch,
the time of a read with the native engine › a read by name is no slower than it was, at
device-detection/fiftyone.devicedetection.onpremise/tests/propertyNameCaseNative.test.js line 164 at 24592acb.

Read of ismobile, fastest of 10 rounds of 20000, before 1260 ns, after 1461 ns.
Expected: <= 1385.9633150000002
Received:    1460.9396

The test came with #68.
"Before" is the Element Data with a getInternalIgnoringCase that finds
nothing, and "after" is the Element Data as it is. The key read, ismobile,
is found as given, and AspectData.get calls getInternalIgnoringCase only
when getInternal finds nothing
(aspectData.js lines 75 to 90),
so before and after run the same code. The test took the fastest before
over ten rounds and the fastest after over ten rounds, each from one object
built once, and failed when after was more than a tenth over before. The
difference it measures is the runner's noise, not the code.

Each runner's measurements

All of these are after over before, from the test as it is on rc.

From the logs of the 58 full build and nightly runs since #68 merged, 293
measurements in all.

Runner Measurements Lowest Middle Highest Over 1.1
Ubuntu_Node_22 45 0.989 1.001 1.026 0
Ubuntu_Node_24 45 0.987 1.000 1.024 0
Ubuntu_ARM_Node_22 49 0.975 1.000 1.019 0
Ubuntu_ARM_Node_24 52 0.984 0.999 1.026 0
Windows_Node_22 40 0.968 1.000 1.025 0
Windows_Node_24 43 0.977 1.000 1.018 0
macOS_Node_22 9 0.769 0.961 1.084 0
macOS_Node_24 10 0.874 1.010 1.160 1

Run 43443859591
ran the test 20 times on each of the 8 runners, with the flags of the
repository's unit-test script and the data file CI uses. This is the red.
It failed 2 of 20 times on macOS with Node.js 24, where the ratio reached
1.373, and passed every run elsewhere.

Runner Lowest Middle Highest Failed
ubuntu-22.04, Node.js 22 0.990 1.000 1.010 0 of 20
ubuntu-22.04, Node.js 24 0.996 1.001 1.003 0 of 20
ubuntu-22.04-arm, Node.js 22 0.971 0.999 1.009 0 of 20
ubuntu-22.04-arm, Node.js 24 0.993 0.999 1.010 0 of 20
windows-latest, Node.js 22 0.986 0.994 1.019 0 of 20
windows-latest, Node.js 24 0.949 0.996 1.026 0 of 20
macos-latest, Node.js 22 0.939 1.002 1.060 0 of 20
macos-latest, Node.js 24 0.877 0.973 1.373 2 of 20

The same run measured the read the way the dictionary timing test in
pipeline/fiftyone.pipeline.engines/tests/engines.test.js has done since
#84, 15 times on each
runner. Each round times a before and an after side by side and keeps its own
ratio, each of 10 pairs is built fresh, and the middle of the 200 rounds of
2,000 reads decides. It also measured a read that folds letter case inside
getInternal, which is the slowdown the timing is there to catch.

Runner Same code, lowest middle highest Folding case, lowest highest
ubuntu-22.04, Node.js 22 0.999 1.000 1.001 1.072 1.075
ubuntu-22.04, Node.js 24 0.998 1.000 1.002 1.058 1.062
ubuntu-22.04-arm, Node.js 22 1.001 1.006 1.008 1.090 1.099
ubuntu-22.04-arm, Node.js 24 0.999 1.000 1.003 1.082 1.103
windows-latest, Node.js 22 0.995 1.001 1.002 1.062 1.071
windows-latest, Node.js 24 0.998 1.001 1.007 1.067 1.087
macos-latest, Node.js 22 0.982 1.003 1.022 1.055 1.085
macos-latest, Node.js 24 0.963 0.990 1.040 1.032 1.130

What changed

In propertyNameCaseNative.test.js only, following #84.

  1. a read that finds its key as given never looks at letter case is new.
    It counts calls to getInternalIgnoringCase on the native Element Data. A
    read of ismobile must make none and a read of IsMobile exactly one.
    This is the guarantee Compare property names ignoring case, in the restricted list and in every read #68 gave, checked with no clock.
  2. a read by name is no slower than it was stays as a backstop for a
    slowdown the count cannot see, such as letter case folded inside
    getInternal. It now times each pair side by side in each round, builds
    10 pairs fresh, takes the middle of 200 rounds of 2,000 reads, measures
    again once when over the bound and takes the better of the two, and
    allows 1.05. Same code measured at most 1.040 on any runner, and folding
    case measured over 1.05 on every runner but macOS, where it measured from
    1.032 and the count is the exact check. The test has a timeout of 120
    seconds, as a second measurement doubles its time.
  3. The log line now gives the before, the after, the middle ratio and the
    range of the rounds.

How it was verified

The red is the table above from
run 43443859591,
where the test as it is on rc failed 2 of 20 times on macOS with Node.js 24.

Run 43473620570
ran the test file at the head, 1ef641c, 20 times on each of the 8 runners
with the same flags and data file, and eslint on it. All 160 runs passed,
each with the 5 tests of the file, none needed the second measurement, and
eslint is clean.

Runner Middle ratio, lowest middle highest
ubuntu-22.04, Node.js 22 0.999 1.000 1.003
ubuntu-22.04, Node.js 24 0.996 1.000 1.002
ubuntu-22.04-arm, Node.js 22 0.998 1.000 1.015
ubuntu-22.04-arm, Node.js 24 0.996 1.000 1.003
windows-latest, Node.js 22 0.993 1.000 1.005
windows-latest, Node.js 24 0.998 1.001 1.003
macos-latest, Node.js 22 0.981 0.997 1.017
macos-latest, Node.js 24 0.975 1.003 1.031

The full build of this draft,
run 43473656997,
passed. All 8 Ubuntu, Ubuntu ARM, Windows and macOS jobs on Node.js 22 and
24 succeeded, the six Ubuntu, Ubuntu ARM and Windows jobs each with 1,356
unit tests passed and the two macOS jobs each with 1,357, all with 132
integration tests passed, and all 9 Setting 'PullRequestSha' lines are
1ef641c0. Compare Performance and Complete passed.

What remains

…se work

The test "a read by name is no slower than it was" took the fastest before
and the fastest after over ten rounds, each from one object built once,
and failed when the after was more than a tenth slower. Both read a key
found as given, so both run the same code, and the gap between them is the
runner's noise. On macOS with Node.js 24 that gap reached 1.373 against the
bound of 1.1, and the test failed 2 of 20 runs there.

The test now times a before and an after side by side in each round, builds
each pair fresh, takes the middle of 200 rounds, measures again once when
over the bound, and allows 1.05, as the dictionary timing test in the
engines package does. A new test counts the reads that look at letter case,
which checks exactly that a read finding its key as given never does.
@jwrosewell
jwrosewell marked this pull request as ready for review November 13, 2026 22:38
@jwrosewell
jwrosewell merged commit b2c757e into rc Nov 13, 2026
2 checks passed
@jwrosewell
jwrosewell deleted the fix/native-read-timing branch November 13, 2026 22:39
@jwrosewell jwrosewell mentioned this pull request Nov 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant