-
Notifications
You must be signed in to change notification settings - Fork 154
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
irmin-pack: no mmap syscall #2232
Conversation
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## main #2232 +/- ##
==========================================
+ Coverage 67.97% 68.02% +0.04%
==========================================
Files 136 136
Lines 16564 16587 +23
==========================================
+ Hits 11260 11283 +23
Misses 5304 5304
... and 1 file with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
I still need to take a close look at the code, but as discussed earlier, I ran some preliminary benchmarks locally based on the benchmark I did last week. Early results are very promising! 😻 Below is a graph of average medians for two runs with LRU size of 0 (to focus on the mapping file perf) of no mmap (this PR) vs mmap (main, essentially). The title says "commit load times" but this is really "sample commits and load their entire trees"; it doesn't take this long to just "load a commit" 😄. Based on these results, I definitely think it is worth doing a full replay trace benchmark (and potentially looking at the other optimization ideas you have!). |
Results of a benchmark run using a Tezos Context replay: https://github.com/tarides/irmin-tezos-benchmarking/blob/main/benchmarks/2023-04-no-mmap/stats.txt |
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.
Left some opening comments. I'm really excited about these changes -- thanks for working on it!
src/irmin-pack/unix/gc.mli
Outdated
@@ -54,7 +54,7 @@ module Make (Args : Gc_args.S) : sig | |||
|
|||
val cancel : t -> bool | |||
|
|||
val finalise_without_swap : t -> (int63 * int63) Lwt.t | |||
val finalise_without_swap : t -> (int63 * int63 * int63) Lwt.t |
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.
Two thoughts:
- For a future improvement, it would be nice to model this return type explicitly instead of a triple of
int63
s. - As is, the docs need updating to say what the third element is.
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.
I went with producing a gced
control file status here directly since it has all the required values for the store to then create the snapshot... but let me know if you think it's worse!
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.
I kinda like it!
My only point of consideration is thinking about where the "knowledge" of constructing the Gced status ought to live.
If we wanted to embrace the Gc module having the knowledge of how to construct a control file Gced status after Gc finishes, we could also change the file manager's swap
function to accept the status instead of creating it itself. But that is definitely for a separate PR!
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.
Since we don't really use any of the "features" of Bigarray
after this PR, I got curious if there is any performance benefit to using them. I did some simple benches and it would appear that we may get some benefit to switching to just Array
. Perhaps already in your list of optimization ideas, but putting out there for some food for thought.
# dune exec arrays/main.exe
Sum 1000 integers
[Array#fold] 6.452000s
[Array#safe] 0.761000s
[Array#unsafe] 0.531000s
[BigArray#safe] 15.919000s
[BigArray#unsafe] 14.647000s
Sample 100 out of 1000
[Array#safe_sample] 0.421000s
[Array#unsafe_sample] 0.371000s
[BigArray#safe] 1.222000s
[BigArray#unsafe] 0.992000s
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.
I'm guessing your benchmark is stressing the OCaml GC with all the Int64
custom objects... I added a patch to the "userland mmap" to not use bigarrays/Int64 in case you want to compare performances :)
(In this latest patch, I'm not sure if the array array
is optimal, we could switch back to a flat array
, but I wanted to see if it would help memory usage)
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.
I tried it originally with floats and had similar results. I changed it to Int64
to mirror our setup and see if there was any observable difference.
I'll run another bench with your latest to see if there is any difference!
Thanks a lot for your benchmarks and feedbacks! <3 @adatario > If you have some time, I think there's a small glitch with the memory usage graph as it's a bit flat during GC.. I'm guessing it's because the GC is running in a child process and doesn't get measured by |
Here's a fixed graph: |
@art-w here is an updated bench with the "no bigarray" version. For now, lets stick with bigarray (unless you want to try a 1-D array as well). 😎 |
Thanks a lot @adatario !!
Yeah sorry I should have mentioned that I expected the memory usage to grow slightly during GC following PR #2215 (the current PR is unrelated). Previously an array was used to represent the |
1616977
to
3728b13
Compare
Nice! I've started another benchmark run with the memory optimizing commit you pushed. |
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!
…min-pack, irmin-pack-tools, irmin-mirage, irmin-mirage-graphql, irmin-mirage-git, irmin-http, irmin-graphql, irmin-git, irmin-fs, irmin-containers, irmin-cli, irmin-chunk and irmin-bench (3.7.0) CHANGES: ### Added - **irmin** - Add `Conf.pp` and `Conf.equal` to print and compare configuration values (mirage/irmin#2227, @samoht) - Add a `clear` optional arguments to all function that adds a new commit: `Commit.v`, `set`, `set_tree`, `remove`, `test_and_set`, `test_and_set_tree`, `test_set_and_get`, `test_set_and_get_tree`, `merge`, `merge_tree` and `with_tree`. This new argument allows to control whether the tree caches are cleared up after objects are exported to disk during the commit. (mirage/irmin#2225, @samoht) - **irmin-pack** - Add configuration option, `lower_root`, to specify a path for archiving data during a GC. (mirage/irmin#2177, @metanivek) - Add `is_split_allowed` to check if a store allows split. (mirage/irmin#2175, @metanivek) - Add `add_volume` to allow creating new empty volume in lower layer. (mirage/irmin#2188, @metanivek) - Add a `behaviour` function to the GC to check wether the GC will archive or delete data. (mirage/irmin#2190, @Firobe) - Add a migration on `open_rw` to move the data to the `lower_root` if the configuration was enabled (mirage/irmin#2205, @art-w) ### Changed - **irmin** - Expose type equality for `Schema.Info` to avoid defining the `info` function multiple times when using similar stores (mirage/irmin#2189, mirage/irmin#2193, @samoht) - **irmin-pack** - GC now changes its behaviour depending on the presence of a lower layer. (mirage/irmin#2190, @Firobe) - Split now raises an exception if it is not allowed. It is not allowed on stores that do not allow GC. (mirage/irmin#2175, @metanivek) - GC now supports stores imported V1/V2 stores, in presence of a lower layer only. (mirage/irmin#2190, @art-w, @Firobe) - Upgrade on-disk format to version 5. (mirage/irmin#2184, @metanivek) - Archive to lower volume does not copy orphaned commits. (mirage/irmin#2215, @art-w) ### Fixed - **irmin-pack** - Unhandled exceptions in GC worker process are now reported as a failure (mirage/irmin#2163, @metanivek) - Fix the silent mode for the integrity checks. (mirage/irmin#2179, @icristescu) - Fix file descriptor leak caused by `mmap`. (mirage/irmin#2232, @art-w)
Since the mapping file is read-only, we can simulate the mmap in userland by lazily reading chunks on demand (and avoid the file descriptor leak from mmaped bigarrays..) There are a bunch of optimizations that we could try here, but I'm curious how the benchmarks are impacted by this change before going too deep into this rabbit hole :)
(also added the expected
mapping_size
in the control file as a consistency check to detect a partially written mapping, after a gc or a snapshot)