-
Notifications
You must be signed in to change notification settings - Fork 69
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
Optimising CubeWatchers unloading #365
Optimising CubeWatchers unloading #365
Conversation
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.
Looks good overall, just a few things to improve
public T next() { | ||
prev = next; | ||
next = null; | ||
return prev; |
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.
this assumes hasNext has been called. Not a problem for most use cases but could be susprising to discover that if (!thing.isEmpty()) { return thing.iterator().next(); }
doesn't work.
/** Contain all data in sorting order */ | ||
private final List<T> data = new ArrayList<T>(); | ||
/** Contain all data without certain order. Used to detect if element is already added */ | ||
private final Set<T> data2 = new HashSet<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.
rename to dataAsSet
/** Sort and remove scheduled elements */ | ||
@SuppressWarnings({"unchecked", "rawtypes"}) | ||
public void tick() { | ||
T[] a = (T[]) data.toArray(); |
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.
Consider using 2 ObjectArrayList
s from fastutils, and swapping them around. FastUtil exposes the internal array from it's array list.
import java.util.function.Predicate; | ||
|
||
/** | ||
* Helper class to delay removing of an elements to sorting tick. Wrap both ArrayList and HashSet classes inside of it. |
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.
Explain why in the comment
bcb306e
to
57f60bc
Compare
I decide to use a raw array of objects as data container. This way we can remove elements right during iterations. |
2c8eba0
to
753ef1c
Compare
Arrays.sort((T[])data, 0, size, order); | ||
} | ||
|
||
/** Check if list is empty. Even when it return true list still could contain |
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.
What is that weird javadoc formatting?
} | ||
Object old = data[index]; | ||
data[index] = element; | ||
this.add((T) old); |
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.
is that behavior actually useful in any way? It's likely nothing actually needs to insert at specific position in the array.
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.
This function used here:
cubesToGenerate.add(0, playerInstance); |
To add cube to generation query with high priority.
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.
And your code completely missed the point as when a second none is added the first one will be moved. To the end. Just make the values stored internally in reverse order so you can have insertFirst method and it would only need to append it at the end of the array.
} | ||
|
||
private void grow() { | ||
data = Arrays.copyOf(data, data.length << 1); |
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 generally don't have an issue wit bitshifts when they are actually useful but here it only obfuscates the code for people who don't know much about them
753ef1c
to
9b7ace3
Compare
Considering adding elements to the start of a list I have even better idea. |
9b7ace3
to
9b3cc10
Compare
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.
Just a few minor corrections, and when you are done, run profiler/sampler again and show the results.,
* @return if list contain any accessible data | ||
*/ | ||
public boolean isEmpty() { | ||
return size - toRemove.size() == 0; |
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.
You may want to add assert size - toRemove.size() >= 0;
(my genIntellijRuns task enables assertions by default)
|
||
private void peekNext() { | ||
while (next == null && a < start + size) { | ||
T e = (T) data[++a - 1]; |
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.
either split it into 2 lines or use increment properly and do data[i++]
T e = (T) data[++a - 1]; | ||
if (toRemove.remove(e)) { | ||
dataAsSet.remove(e); | ||
data[--a] = data[start + --size]; |
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.
There you should definitely split it into more lines. Just because it works doesn't mean it's a good idea.
@Override | ||
public void remove() { | ||
dataAsSet.remove(prev); | ||
data[--a] = data[start + --size]; |
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.
And here
if (predicate.test(a)) { | ||
toRemove.remove(a); | ||
dataAsSet.remove(a); | ||
data[i] = data[start + --size]; |
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.
And here
throw new NullPointerException("This list does not allow null elements."); | ||
if (start <= 0) | ||
grow(); | ||
data[--start] = element; |
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.
again
* to remove non-existing elements will cause nasty bugs. | ||
*/ | ||
public void remove(T entry) { | ||
toRemove.add(entry); |
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.
how does it handle removing element that doesn't exist in the list? I'm pretty sure it breaks size and isEmpty. If you don't want to handle such things, at least crash in those cases (PlayerCubeMap shouldn't be doing that). Same for other strange cases like adding the same thing twice.
9b3cc10
to
44e2106
Compare
This is running with vanilla world, not cubic chunks world. |
1b741c7
to
cecb80e
Compare
This seems to actually be either faster to sort or slower overall than the first implementation. Can you actually measure the time it takes to run the methods on average with the first and the current version? (git reflog should still show those old commits that you overwrote, unless you ran git gc) |
while (next == null && i < start + size) { | ||
T e = (T) data[i++]; | ||
if (toRemove.remove(e)) { | ||
remove(); |
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.
If it actually is slower, this is likely the part responsible for it. Just do contains() check and skip it here and do mass-removal on tick. The System.arrayCopy during removal of every single element is what this PR was supposed to avoid.
cecb80e
to
5bb6c7c
Compare
I made a one simple trick to use sorting algorithm in getting rid of dead elements.
"Old" - is a yesterday version of a list. |
This just tests the lists, not the whole PlayerCubeMap.tick() which is what actually counts. A lot of time is spent in hasNext, which calls peekNext which removed any elements in the toRemove set, one by one. With System.arrayCopy each time. And it is an issue because sort() isn't done every tick, you should probably just skip the al;ready removed elements during iteration. |
5bb6c7c
to
c53097e
Compare
Done as requested. |
And update the sampler/profiler screenshot |
As you can see, hasNext takes significantly less time than before. Merging it now. |
Working marvelously.