Skip to content
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

[rfc][Run Job Perf] Receive logs in webworker and send to main thread using Transferable #8734

Closed
wants to merge 4 commits into from

Conversation

salazarm
Copy link
Contributor

@salazarm salazarm commented Jul 4, 2022

Summary & Motivation

On heavy jobs, receiving logs for the PipelineRunLogsSubscription ends up taking a lot of CPU cycles on the main thread leading to poor user experience due to lack of idle time. To combat this we move the websocket to a webworker so that the data is received in a separate thread. We then transfer the data to the main-thread using an ArrayBuffer and parse the JSON on the main-thread. I don't expect any performance benefits from this alone but we can get some down the line by throttling the sending of messages to the main thread and by never sending some messages to the main thread if they would never be seen.

Implementation:
The webworker passes websocket messages straight to the main thread as soon as it receives them.

I opted to copy the graphql subscription / fragments into a new file so that the worker doesn't have a dependency on modules with side effects that break the WebWorker (eg. modules assuming access to window/document (SharedToaster, CodeMirror, domUtils, etc.).

Right now the worker will only be enabled if a query parameter worker=1 is in the URL.

How I Tested These Changes

  1. Loaded the 500mb debug file here
  2. Modified many_events_job to materialize 10,000 files and validate 10,000 tables and profiled with and without the worker 10 times each I did see a decrease in the main thread being busy with the worker but its hard to get an accurate apples to apples comparison so its unclear if this is was just by chance.

worker:
Screen Shot 2022-07-04 at 10 42 46 PM

No worker:
Screen Shot 2022-07-04 at 3 31 28 PM

@vercel
Copy link

vercel bot commented Jul 4, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

3 Ignored Deployments
Name Status Preview Updated
dagit-storybook ⬜️ Ignored (Inspect) Jul 5, 2022 at 2:15AM (UTC)
dagster ⬜️ Ignored (Inspect) Jul 5, 2022 at 2:15AM (UTC)
dagster-oss-cloud-consolidated ⬜️ Ignored (Inspect) Jul 5, 2022 at 2:15AM (UTC)

@salazarm salazarm changed the title [Run Job Perf] Receive logs in webworker and send to main thread using Transferable [rfc][Run Job Perf] Receive logs in webworker and send to main thread using Transferable Jul 5, 2022
Copy link
Collaborator

@bengotow bengotow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great so far! I added one inline comment, overall it's super cool this is working! I'm not 100% up-to-date on our Apollo Client configuration, but it's possible that to deploy this we'd also need to copy some base path / auth token type of stuff that is applied in cloud? @hellendag might know more about that.

Maybe we should try to layer on one more phase of this with a perf win before merging it?

Comment on lines +8 to +12
const char = String.fromCharCode(bytes[i]);
if (char !== '\x00') {
binary += char;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this seems like it could be a pretty big bottleneck, is there a particular field in our JSON that contains null characters? It seems like removing them during both serialization and deserialization is unnecessary. (Nice for completeness, but if they're always used together it'd be safe to clean only the serializer?)

If we could reduce this entire function to this line, I think it'd be a big win because we can avoid having to concatenate onto a string over and over:

String.fromCharCode.apply(null, new Uint16Array(buf))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had that originally but hit Maximum call stack exceeded because there is a limit on the number of arguments =. I can try chunking into smaller segments. The issue I saw was that the end of the JSON had tons of null characters for some reason. I need to investigate where its coming from, this is more of a bandaid for that issue

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.

None yet

2 participants