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

Incremental IDB performance improvements #899

Merged
merged 14 commits into from
Feb 11, 2022
Merged

Conversation

radex
Copy link
Contributor

@radex radex commented Oct 13, 2021

I've had a few more ideas for squeezing more performance out of IncrementalIDB :)

  1. Preloading an IndexedDB and a list of keys:

Screen Shot 2021-09-30 at 09 49 58

There's usually a pretty big gap between the beginning of index.html parsing and getting to the point with loading the JS bundle that Loki code can begin running. This CPU and network wait could be interleaved with beginning of disk/IDB operations. Now, an advanced user can add a tiny bit of JS into their index.html to preload the idb and list of keys and pass it to IncrementalIDBAdapter to do the complicated work. I've measured a 6-15% improvement (on a very fast computer and testing on a 38MB database - I suspect real-world improvement may be better since triggering the disk operation should warm up IO caches and reduce latency for later reads, while the caches are warm in my tests… I'm not quite sure how to verify this).

  1. Lazy deserialization of chunks on demand. About half the total IDB loading time (in my test setup) is deserialization of chunks (JSON.parse + optional deserializeChunk). It doesn't make sense to do this step lazily by default all the time, because if we're gonna need a collection at startup, we'll have to do it anyway, and during IDB load, we have a concurrency opportunity, since we're both waiting on IO and doing CPU computation. Also, processing incoming IDB objects into its final, deserialized form, and synchronously discarding the initial object is probably better for GC performance and memory pressure (because that object won't graduate to old generation, so a minor GC cycle can clean it up more efficiently), though I don't have the tools to test that. However, an advanced user who knows that certain big, heavy collections are almost never needed for initial launch of the app can opt into deserializing its chunks lazily.

In my tests (a real app, with a big, real world account), this yielded a 8% improvement, with a possibility of ~doubling that if I move things around on the app side. This also creates some gaps while app waits for IO, so if I can also take advantage of the concurrency opportunity, the improvement could be as big as 20-25%.

  1. I've tried to improve this:

Screen Shot 2021-09-30 at 13 00 01

Those are cross-process communication tasks that have to do with sending data between the IDB and main process. However, they're not densely packed, and so CPU utilization is at 60-70% during this period. I'm almost sure this can be improved and this is a quirk of scheduling. I've already improved it a lot with #874, however an opportunity for improvement remains.

I've tried adding more "waves" of requests, changing their timing, changing which key ranges are scheduled to even/odd, reverse, random order… none of that worked :( So no improvement here, for now, but I've committed some tweaks to the key request scheduling code to be more easy to hack and play around in the future

  1. A small improvement to stop parsing chunk key N*log N times

@radex radex changed the title Performance3 [WIP] Incremental IDB performance improvements Oct 13, 2021
}
copyColl.getData = coll.getData;
Object.defineProperty(copyColl, 'data', {
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 didn't want lazy deserialization of chunks (a concern of the storage layer) to impact Loki the in-memory database itself more than absolutely necessary, so instead of modifying places that use Collection.data, I modified the Loki object inflation machinery to make Collection.data a lazily-computed property

@radex radex changed the title [WIP] Incremental IDB performance improvements Incremental IDB performance improvements Oct 15, 2021
@radex radex marked this pull request as ready for review October 15, 2021 12:02
@radex
Copy link
Contributor Author

radex commented Oct 29, 2021

Update: I've been running this on production for a while now and haven't seen any issues.

I have, however, removed the IDB&keys preloading feature. After more extensive performance testing this idea turned out to be a dud. Due to IDB's asynchronous nature, I can't actually hit this optimization reliably enough on production to be worth it (Chrome on production will pull execution of the main scripts synchronously into index.html parsing when it already has it cached, so the main bundle's code won't have a chance to yield to the tiny preload script's IDB callbacks so it can do its job)

@stale
Copy link

stale bot commented Jan 9, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jan 9, 2022
@radex
Copy link
Contributor Author

radex commented Jan 10, 2022

bad bot

@stale stale bot removed the wontfix label Jan 10, 2022
@radex
Copy link
Contributor Author

radex commented Feb 11, 2022

@techfort gentle nudge :)

@techfort techfort merged commit 1f414a5 into techfort:master Feb 11, 2022
@radex radex deleted the performance3 branch February 11, 2022 13:15
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.

2 participants