Repository navigation
feat: lay large graphs out on the Java ELK server - #99
Merged
Merged
Conversation
elkjs runs ELK compiled to JavaScript on the extension host's thread. The
same ELK on a JVM, in its own process, is three times faster on the
platform's own layouts and seven to ten times faster with the default
preset kept on large graphs (NDF documents, warm JVM: Free Ports on 2000
clauses 8.2 s against 2.6 s; the default preset on 1000 clauses 61 s
against 6.4 s), and the host keeps running while it works.
From mlir-viewer's elk-server engine, adapted:
- `server/elk-server/`: the process (started by the first layout that
needs it, one per extension host, restarted after it dies or runs out of
heap, stopped with the extension), the client and the answer's writer.
- The client speaks only the server's framed mode (`GZ10`, length, gzip,
both ways) over one connection per layout. The plain JSON mode mlir-viewer
uses finds the end of a message by counting braces, string contents
included, so an id with a `}` hangs it; the platform's ids carry labels.
A framed request must be gzip however small, or the server never answers.
- `SwitchingElk` stands where elkjs stood (`ElkFactory`): `auto` sends a
graph past 150 nodes or 400 edges (where the cheaper presets begin) to
the server and keeps the rest on elkjs, so small diagrams lay out exactly
as before; anything the server cannot do falls back to elkjs.
- `DiagramProfile.elkServer: { jar }` (and `SidecarProfileInput.elkServer`)
names the jar a product ships; `<settingsNamespace>.layout.engine`,
`.javaPath`, `.javaOpts` and `.serverTimeoutMs` are the person's.
- `packages/diagram-server/resources/elk-server/`: the jar (byte-identical
to mlir-viewer's) and where it comes from. It carries ELK 0.8.1; elkjs is
0.9.3, so the engines can differ on the same graph until it is rebuilt.
Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
Plain elkjs without a server or with elkjs chosen, the switch otherwise, and one shared process per jar and JVM options. Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
5 of 6 tasks
Review of #99: the threshold's measurements were described as an NDF product's documents; they are a producer's document graphs. Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
elkjs runs ELK, compiled to JavaScript, on the extension host's thread: while a large diagram lays out, the whole host waits. This lets a product lay large graphs out on the Java ELK server mlir-viewer already uses, in its own process.
Measured with the platform's own layout engine on NDF documents generated at size (warm JVM, identical ELK input to both engines):
On real HDL netlists (endrix/vhdl-ide#1, endrix/sv-ide#1, which turn this on there), Layout Diagram:
The picorv32 synthesis netlists are about 10 % slower on the server, inside ELK itself rather than on the socket, which points to the ELK 0.8.1 / 0.9 gap below.
What is in it
server/elk-server/, adapted from mlir-viewer's engine:ELK_SERVER_PORT, and it's ready once it prints "listening". It restarts with the next layout after dying or running out of heap, and stops when the extension deactivates.GZ10, length, gzip body, both ways), over one connection per layout. I reproduced two problems in mlir-viewer's approach against the jar:}hangs the layout until timeout, and Dialogram's ids carry labels.SwitchingElk. It stands where the elkjs instance stood (ElkFactory), so the engine, the Free Ports probe and every layout command use it unchanged.auto(the default) sends a graph past 150 nodes or 400 edges to the server; that's where the cheaper presets start. Smaller graphs stay on elkjs and lay out exactly as before.elk-serversends everything.elkjsnever starts Java.DiagramProfile.elkServer: { jar }(andSidecarProfileInput.elkServer).<settingsNamespace>.layout.engine,.javaPath,.javaOpts(default-Xmx2g) and.serverTimeoutMs. These are read when the server starts.packages/diagram-server/resources/elk-server/, with a README covering where it comes from, its SHA-256, licences and protocol notes. It's byte-identical to mlir-viewer's and ascpp-graph-sprotty's (af9cc65). It's a 7.6 MB binary in git, as in mlir-viewer.Known gap
The jar bundles ELK 0.8.1 and elkjs is 0.9.3, so the two engines can lay the same graph out differently (seen on a small NDF document; the picorv32 pipeline was nearly identical). Under
autoonly large graphs reach the server, so small diagrams are unaffected. The fix is to rebuild the server on the ELK that elkjs carries, once its sources are located.Not in this PR: an
--engineoption forscripts/render-svg. The renderer is in #91, so that option follows once both land.Test plan
npm run typecheck,npm run check:neutralityelk-server.test.ts(15 tests):{}.elkjschosen, the switch otherwise, one shared process per jar and JVM options.WorkflowElkLayoutEngine: a chain whose ids all contain braces, laid out with elkjs never called. Skipped without Java.profile-elk-server-options.test.ts, plus a sidecar profile pass-through test.elkServer).https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8