techfort / LokiJS

javascript embeddable / in-memory database
http:/techfort.github.io/LokiJS
MIT License
6.71k stars 478 forks source link

Incremental IDB performance improvements #899

Closed radex closed 2 years ago

radex commented 2 years ago

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 https://github.com/techfort/LokiJS/pull/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 commented 2 years ago

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[bot] commented 2 years ago

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.

radex commented 2 years ago

bad bot

radex commented 2 years ago

@techfort gentle nudge :)