Monoblocks: optimize blocks that contain a single type of node - #16293
Conversation
|
It occurs to me that the MapNode [] on the client will never change. It always stays in its expanded state (we never call a method on the client that will try to shrink the array.) So maybe we focus on threading correctness changes on the server. |
659006f to
61137f8
Compare
|
Did some more tests: Without the PR server memory usage is > 16GB, with the PR around 1GB. So a 16x improvement. (When I enabled this on the client too - by calling Imagine you have 5 or 10 players at this range. |
|
Would it help if I put this behind an "experimental" setting, or perhaps a compile time option? |
I would vote for |
|
I looked again at the code. All mapgen is triggered from the EmergeThread(s).
So we really should be good. Of course I could have missed something. It's hard/impossible to prove the absence of something. @sfan5 |
|
That sounds good, except
..is a footgun waiting to happen. It doesn't look like the Client, ClientEnvironment or ClientMap has a lock, it probably should and then we could just take it for the duration of the copy. |
Do you mean this as a general foot gun, or specifically if somebody later changes how Mono-Blocks work on the client? Generally, yes... And that is a different issue. This PR will not make this better or worse. Maybe I add comments at the right spots. I can probably distinguish a MapBlock on the client by using the used Locking the client during the copy would effectively be like #16282, with the same performance profile (at least I cannot think of any scenario that would not lock out the client while we copy the block data to the VManip). We need to think about that more. Let's fix that in another PR.
I actually like that. All access to map/mapblock is cleanly from the main thread (except the ones we found). That is easy to reason about. I could revive #16282, but (a) it is currently unnecessary, and (b) causes a quite significant slowdown and client stutter. |
(the latter)
It wouldn't. Because when copying while enqueueing there's a real chance that we copy multiple times, while copying just before processing only happens once.
I don't disagree. But the unsafe access we found does pose a bit of a problem, which we shouldn't leave unsolved. |
So let me just make sure that The main thread on the client is actually in In summary, I do not want to fix locking as part of this PR, and I am not even sure we want do that for 5.13. |
|
Like so... I am happy to file a separate PR and see how we can fix the locking on the client.
Yes, you are right. Update: As I think about it... Note that in the last version of #16282 I had only the one block in question updated (not its surrounding blocks, because that is actually not needed). So there was a full copy when the event is first placed and then only replacing the one potentially changed block, and that was still quite slower (client_mesh_chunk was 6 or 8). So it's that one copy that takes time. |
|
I briefly looked through the client code. There are various places in client/clientMap/game that access the map and/or mapblocks. This is not a quick fix. We'd need to carefully look through all the call and lock what is necessary. The only safe thing would be to lock This is just to reinforce the points: (a) on the client this PR ensures that there are no new issues, (b) getting locking right needs its own PR and some thinking - I'd suggest after 5.13, and (c) let's think hard about keeping/having the invariant that only the main thread accesses map/bocks on the client. @sfan5 I do think that this is good to merge. Access to the MapNode[] is currently safe and now there are safeguards that nobody would accidentally change it. |
|
Gentlemen, what should I do with this? :) @sfan5 @Desour @appgurueu |
|
Wait until after 5.13. Then wait more until someone has time. |
I'd like to point out that this PR is now guaranteed to cause no new issues. On the client this is not used, and on the server we do proper locking. I am not planning any further changes in this one. |
|
@sfan5 Another safety check: Never compress/shrink the node array when a block is referenced. |
|
When is this going to get merged? |
|
The answer is always the same: It will be when another coredev has reviewed (and ideally tested) the PR himself/herself or someone else who they are confident in has done so. |
|
@sfan5 @appgurueu Any chance to do a review? (I addressed the risk of client race conditions.) |
|
Is there anything you want me to do (other than wait)? |
There was a problem hiding this comment.
Tested with ubsan, asan, and leaksan (all at once), found nothing.
The thread safety stuff (i.e. why monoblocks are disabled) needs code comments. One shouldn't have to read lengthy PR descriptions to understand code.
(Edit: Also tested with tsan now. Found nothing new as well. But I didn't do much more than fly around in a map to trigger emerge, so I didn't cover all code paths by far.)
|
Thanks @Desour , all good comments. I'll post an update later today or tomorrow. |
5c687fc to
62ac2e3
Compare
This reverts commit cc8f260.
62ac2e3 to
95e7d7b
Compare
Whoops I had that, but somehow undid it before I pushed... Weird. Anyway, done now. |
|
Finally merged! Yay! |
|
Regarding the client safety stuff: by chance I stumbled upon #13124, which is the PR that introduced this thread unsafety (to achieve more performance) |
…i-org#16293) Reduces memory usage on the server, especially with many user and/or large viewing distances. Currently disabled on the client due to known data races on a block's data.
(This continues #16152. Lot's discussion there, but I cannot reopen that one, because I force pushed a rebase before I opened it. There a way to fix that, but it seemed easier to open a new PR, and it's what github wants.)
(And apparently I am an idiot. I meant to update a message, and accidentally closed #16291, and then force-pushed a change. This time github was really mad at me... So here is attempt 3 with a brand-new branch, hopefully the last one.)
See discussion in #16097
For blocks that only contain a single type of node, that node is only stored once.
When copied to a VMANIP the full array is materialized. Could be optimized.
@appgurueu pointed out, rightly, that the normal compression we do in disk and on the wire naturally already takes care of mono-block, so this is just to save in process memory.
Only works on the server, currently.
Making it work on the client would need a protocol version change.Goal of the PR, How does the PR work?
See description
Does it resolve any reported issue?
Fixes Standing still increases ram consumption #16097
To do
This PR is a ready for review.
It needs mostly testing and a review of the approach.
How to test
Try any world, new or existing, everything should just work.
There should be no measurable overall slowdown, and server memory usage should be drastically (50-90% depending on scene) reduced, especially with larger viewing ranging.
Try with many mesh-generation-threads and larger values of
client_mesh_chunk.