New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf: Port the optimizer to WebAssembly #1092
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1092 +/- ##
==========================================
+ Coverage 62.07% 62.91% +0.83%
==========================================
Files 59 59
Lines 7111 7164 +53
Branches 1708 1673 -35
==========================================
+ Hits 4414 4507 +93
+ Misses 2614 2572 -42
- Partials 83 85 +2
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
± Registry diff
📊 PerformanceKeyNote that each bar component rounds up to the nearest 100ms, so each full bar is an overestimate by up to 400ms.
Data
|
Deploying with Cloudflare Pages
|
Almost there! |
@samestep can you write an issue about this? Perhaps @liangyiliang can implement a workaround for Windows since he is our main Windows user. |
Done: #1176
Done: #1070 (comment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks for going through the PR with me @samestep :p.
Description
This PR improves optimizer performance by an order of magnitude, building on my optimizer performance experiment from earlier this year.
Implementation strategy and design decisions
This PR adds the following build tools to our setup:
wasm-bindgen
to generate JavaScript/TypeScript scaffolding around Wasm compiled from RustQuoting from Stack Overflow:
One implication of this is that compiling an autodiff graph becomes an
async
operation, so in particular,compileStyle
(and thus alsocompileTrio
) becomesasync
.Another implication is that loading/initializing the optimizer itself is an
async
operation. We considered three possible architectures to accommodate this:await
and we don't need to make all those functionsasync
, but the drawback that we now need to remember to properly initialize the module before every possible usage or we'll have race conditions.async
function that initializes the Wasm module and returns an object with methods to access all the underlying Wasm functions; this has the advantage of not requiring top-levelawait
and not giving things implicit preconditions, but the viral disadvantage that now every consumer of the Wasm module needs to either beasync
or take in this object as a parameter.await
, and update our downstream packages to use ESM instead of CJS; this has the advantage of no race conditions, no implicit preconditions, and no viral changes to downstream function signatures, but the disadvantage thatdocs-site
needs to support top-levelawait
.This PR takes approach (1), but we would like to switch to (3) in the future if possible; see the further discussion below.
Checklist
diagrams/
folderOpen questions
WebAssembly.Module
"can be efficiently shared with Workers, and instantiated multiple times", a followup should allow the optimizer to be run in a web worker; see this issue: Providing a positive user experience for slow Penrose trios #1095${FORCE_COLOR+--color=true}
to@penrose/optimizer
'sesbuild
script, and${FORCE_COLOR+--color=always}
to itscargo
scripts, to get color output in Nx. I've removed those because they're not portable to Windows, but it would be nice to come up with a portable way to get this back in the future; see this issue: Some scripts aren't colored when run by Nx #1176hundred-points-around-star
example (which would previously yield a stack overflow), but instead, after this PR it simply crashes the whole page. See Stack overflow with too many substance objects #1070await ready;
by using a top-levelawait
in@penrose/optimizer
. As far as I can tell, this would require us to get rid of Webpack first; see docs: Migrate site from Docusaurus to VitePress #1172debug
node, because I don't think we ever use it, and it would have taken nontrivial effort to port to WebAssembly. I can add it back if we want, but didn't want to waste time if we don't care.wasm-bindgen
that includes the--keep-lld-exports
flag and does not emitBigInt
literals. Once version 0.2.84 is released, we should just switch to that, but for now, theCONTRIBUTING.md
instructions just say to install from GitHub at a specific commit, and our CI/CD scripts pull a Linux binary which I compiled and put in a GitHub Gist.strings packages/optimizer/target/wasm32-unknown-unknown/release/penrose_optimizer.wasm
, the built WebAssembly binary contains absolute paths (starting with/Users/samueles/.cargo/registry/src/github.com-1ecc6299db9ec823/
in my case) to local files on whatever machine built the binary. See this Rust issue: Enable --remap-path-prefix for absolute paths by default rust-lang/rust#40552