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

try to use flyweight pattern with FileBufferCache #12

Closed
subes opened this issue Sep 24, 2021 · 4 comments
Closed

try to use flyweight pattern with FileBufferCache #12

subes opened this issue Sep 24, 2021 · 4 comments

Comments

@subes
Copy link
Collaborator

subes commented Sep 24, 2021

instead of having to deserialize the data and storing the objects, we could just store the decompressed bytes and reference the data with the flyweight pattern. Specialized ISerde implementations should be able to do that.

Drawback: The segments byte[] array will then be referenced as long as a flyweight object still exists that is based on that data.

  • We could also create separate smaller byte[] arrays per object, but that would add a copy again, which should be more or less the same overhead as deserializing (should not be done per individual object, instead a pool of reusable segment buffers for the byte[] array should be used, the buffer is returned to the pool via a cleaner)
  • if no compression is used, we could also reference the memory mapped bytes directly in the flyweight object, though for this the file needs to be kept open a lot longer which might lead to too many open files (might not be a problem anymore due to the combined memory mapped file per database now)
@subes subes changed the title use flyweight pattern with FileBufferCache try to use flyweight pattern with FileBufferCache Sep 24, 2021
@subes
Copy link
Collaborator Author

subes commented Jul 8, 2022

From TechPaper:

QuestDB is still the fastest for \emph{Iteration} because it utilises the flyweight pattern \citep[p.~218]{gamma1994design}.
Our database could support this in the future as well for uncompressed storage where data is directly read from the file system with the flyweight pattern (using only the operating system cache).
We could even implement a derivation of it that works with compression. In that form, decompressed segments are stored in memory as primitive byte arrays (this could utilise a pool of reusable buffers to reduce allocations)
and processed with the flyweight pattern without creating additional objects (zero-allocation).
This promises us to achieve an \emph{Iteration} speed that is as fast as QuestDB with 125,410,570/s (or maybe even slightly faster).

@subes
Copy link
Collaborator Author

subes commented Aug 25, 2023

i9-13900HX

Did some tests on a strategy (PerformanceTraderInnerStrategyTest with precalculated values) with IPrimitiveArrayAllocator and classical Serde implementations (instantiating actual objects from the decompressed buffer).

None (as before): 26.78/ms
OnHeap: 23.96/ms
OnHeapCached: 25.94/ms
OffHeap: 25.15/ms
OffHeapCached: 26.58/ms


With IFlyweightSerdeProvider integrated:

None (as before): 26.59/ms
OnHeap: 24.13/ms
OnHeapCached: 24.94/ms
OffHeap: 23.97/ms
OffHeapCached: 24.42/ms


Thus using buffers or flyweight serdes in FileBufferCache alone is slower. Using heap objects is more efficient because deserialization (using ISerde) is done in parallel to strategy and objects on heap are the most efficient to access for this test case.

=> [x] Next will be to test if turning off compression and using the underlying mmap-buffer for the flyweight serdes improves the speed. That way flyweight pattern is used like it is supposed to (even though we still allocate some shallow buffer slice wrappers).

=> [x] Also try to use Bisect in ArrayAllocatorFileBufferCacheResult.

@subes
Copy link
Collaborator Author

subes commented Aug 26, 2023

i9-13900HX

With Bisect in ArrayAllocatorFileBufferCacheResult:

None (as before): 25.15/ms
OnHeap: 23.83/ms
OnHeapCached: 23.55/ms
OffHeap: 24.21/ms
OffHeapCached: 23.43/ms

=> Not much of a difference.

@subes
Copy link
Collaborator Author

subes commented Sep 5, 2023

i9-12900HX

Underlying MMapped-File Flyweight without compression:


TimeseriesDbPerformanceTest:

None (as before): 52.09/µs
OnHeap: 15.19/µs
OnHeapCached: 14.98/µs
OffHeap: 14.68/µs
OffHeapCached: 15.09/µs
FlyweightNoCompression: 15.13/µs

=> Overhead for FDate-Creation is too high, thus values to small and values might get deserialized multiple times during lookups. Likely QuestDB is faster because in the test there is a tight loop around the mmap-buffer and because the FDate objects are allocated on the stack instead of the heap there.


PerformanceTraderInnerStrategyTest:

None (as before): 28.55/ms
OnHeap: 25.9/ms
OnHeapCached: 26/ms
OffHeap: 25.95/ms
OffHeapCached: 26.32/ms
FlyweightNoCompression: 30.15/ms

=> "FlyweightNoCompression" can be slightly faster than "None (as before)", though most likely not worth the storage and additional I/O without compression (457.7 MB vs 1.4 GB on Disk with this Test). Though it could be useful for low latency applications (HFT) or when memory usage should be minimized. The difference might become more prominent in an optimization run (Workshop5StrategyTest.optimize).


Workshop5StrategyTest.optimize (NoPrecalc):

None (as before): 5675.36/ms
FlyweightNoCompression: 5594.69/ms

=> does not seem to make it faster

@subes subes closed this as completed Sep 5, 2023
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

No branches or pull requests

1 participant