You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Vector vertex loads: the JVM wheel spends about 60 percent of the wall in unwrapped Python when rows hold Java float[], the native wheel about 30 percent in prep #337
From the untimed ingest profile of the released 26.11.1 wheels (no speed claim; 3 repetitions, 66 cells, none void): a create_vertices load whose rows hold Java float[] vectors (the shape the e2 and l3d lanes use) spends 59.2 percent (e2) and 60.6 percent (l3d) of the JVM wheel's measured wall in Python code that no phase counter covers, and the native wheel spends 31.3 percent (e2) and 29.0 percent (l3d) in its prep phase (the vector split and the binary argument encoding).
Read in the profile: the JVM cells count only createVertices (the property-matrix call of the engine's GraphBatch) and no batcher call, so a load with Java float[] rows takes the property-matrix path, and _create_vertices_json_bulk returns None at the first Java float[] (graph_batch.py), so the scan costs one row, not every row. A Java float[] is not a vector candidate, and the 60 percent is in _to_java_property_matrix (a Python loop over each row's properties, one JArray(JObject) per row, the whole input held at once), read from the code, not timed. A numpy array or a list of floats is documented to take the binary-matrix path instead.
Proposal: recognise a Java float[] (and a numpy float32 array) as a vector candidate on both wheels and send it through the one binary-matrix path, with a test that the stored vectors are bit-identical to the old path; measure per-phase time and memory (B per row) before and after. This is not gated on a paper cell: every glue drawback found gets fixed.
Edited: the first version said the scan reads every row; PR #339 read the code and it stops at the first Java float[].
I edited the issue body: the scan in _create_vertices_json_bulk stops at the first Java float[] (one row), it does not read every row. The 60 percent is in _to_java_property_matrix. Found while reading the code for #339.
Here are the before and after figures for this issue, from the timed A/B I ran on 2026-11-10 on my laptop (Intel Core Ultra X9 388H, Linux 7.0.0, Python 3.12, two cores). A is the released 26.11.1 wheel of each family and B is the candidate wheel of each (CI builds of the release/26.11.1 line before 26.11.1.post1, sha256 starting 7cc57106 for JVM and 144091c9 for native), with PR #339 at its final head in them. B is not the published 26.11.1.post2 wheel: PR #339 is on main and in the 26.11.1.post2 tag, and I did not re-run this on the published files.
The cells are graph_batch(use_wal=True).create_vertices with rows built by to_java_float_array (a Java float[] on the JVM wheel, a float32 array on the native wheel), as the e2 shape (2 calls of 50,000 rows, 64 dimensions) and the l3d shape (10 calls of 10,000 rows, 96 dimensions), 100,000 rows per cell, with use_wal=True passed in both arms so the durability matches. The study registered these cells as controls and not as the gating figures of this issue, but their rows are exactly the shape of this issue. There are 13 or 14 clean pairs per cell, and below 1.00 means B is faster.
wheel and shape
A
B
time B/A [95% CI]
peak RSS B/A [95% CI]
RssAnon growth per row, A to B
JVM, e2
1.398 s
0.749 s
0.544 [0.527, 0.546]
0.936 [0.861, 0.954]
1439.9 to 978.5 bytes
JVM, l3d
1.152 s
0.664 s
0.570 [0.562, 0.588]
0.943 [0.923, 1.017]
985.1 to 833.3 bytes
native, e2
0.752 s
0.567 s
0.755 [0.749, 0.757]
1.009 [1.008, 1.009]
692.7 to 686.0 bytes
native, l3d
0.785 s
0.614 s
0.783 [0.781, 0.784]
0.994 [0.993, 0.995]
866.1 to 844.3 bytes
Time falls on both wheels and the upper end of every interval is below 0.90, which is a WIN by the rule I wrote before the run. The memory columns are process readings that the rule does not gate on: the JVM wheel's peak is lower, though the interval of the l3d shape reaches 1.017, and the native wheel's peak did not move. An earlier candidate wheel had made the plain scalar Person load 1.307 times slower on the JVM wheel (the validation pass of #330); the fix is in the final head of PR #339, and with it j_g1_cv is 0.888 s to 0.881 s, B/A 1.018 [0.947, 1.026] (GRAY), and n_g1_cv is 0.998 [0.995, 1.001] (NO-CHANGE).
I did not time the phases again: the 59.2 and 60.6 percent of the first profile were read from the profile and the code, and this A/B times the whole call. The code is on main with the tests that the stored vectors are bit-identical, and the time and memory before and after are above, so I am closing this issue.
Activity
tae898 commentedon Nov 9, 2026
I edited the issue body: the scan in
_create_vertices_json_bulkstops at the first Javafloat[](one row), it does not read every row. The 60 percent is in_to_java_property_matrix. Found while reading the code for #339.Native spy test: count the codec hooks around create_vertices, not ar…
create_vertices: no text scan for a table of scalars (g1 regression o…
create_vertices: Java float[] and float32 arrays cross as one matrix …
tae898 commentedon Nov 12, 2026
Here are the before and after figures for this issue, from the timed A/B I ran on 2026-11-10 on my laptop (Intel Core Ultra X9 388H, Linux 7.0.0, Python 3.12, two cores). A is the released
26.11.1wheel of each family and B is the candidate wheel of each (CI builds of therelease/26.11.1line before26.11.1.post1, sha256 starting7cc57106for JVM and144091c9for native), with PR #339 at its final head in them. B is not the published26.11.1.post2wheel: PR #339 is on main and in the26.11.1.post2tag, and I did not re-run this on the published files.The cells are
graph_batch(use_wal=True).create_verticeswith rows built byto_java_float_array(a Javafloat[]on the JVM wheel, a float32 array on the native wheel), as the e2 shape (2 calls of 50,000 rows, 64 dimensions) and the l3d shape (10 calls of 10,000 rows, 96 dimensions), 100,000 rows per cell, withuse_wal=Truepassed in both arms so the durability matches. The study registered these cells as controls and not as the gating figures of this issue, but their rows are exactly the shape of this issue. There are 13 or 14 clean pairs per cell, and below 1.00 means B is faster.Time falls on both wheels and the upper end of every interval is below 0.90, which is a WIN by the rule I wrote before the run. The memory columns are process readings that the rule does not gate on: the JVM wheel's peak is lower, though the interval of the l3d shape reaches 1.017, and the native wheel's peak did not move. An earlier candidate wheel had made the plain scalar Person load 1.307 times slower on the JVM wheel (the validation pass of #330); the fix is in the final head of PR #339, and with it
j_g1_cvis 0.888 s to 0.881 s, B/A 1.018 [0.947, 1.026] (GRAY), andn_g1_cvis 0.998 [0.995, 1.001] (NO-CHANGE).I did not time the phases again: the 59.2 and 60.6 percent of the first profile were read from the profile and the code, and this A/B times the whole call. The code is on main with the tests that the stored vectors are bit-identical, and the time and memory before and after are above, so I am closing this issue.