RFR: 8253086: Optimization of removeAll and retainAll of ObservableListWrapper [v4]

yosbits github.com+7517141+yososs at openjdk.java.net
Sat Oct 10 15:12:08 UTC 2020


On Fri, 9 Oct 2020 22:59:37 GMT, Kevin Rushforth <kcr at openjdk.org> wrote:

>> @kevinrushforth
>> 
>> To show an improvement in time efficiency, the
>> We need to fix the other high-priority hotspots first. I have determined that the current proposed change in the
>> Run-Length approach needs a lot of time to be accepted. I will change my approach.
>> I will switch to an approach that focuses solely on fixing the BitSet initialization size issue. The previous post
>> explains.
>>     @Override
>>     public boolean removeAll(Collection<?> c) {
>>         beginChange();
>>         BitSet bs = new BitSet(c.size());
>> 
>> * new BitSet(c.size())
>> 
>> Don't you notice this mistake?
>
>> * new BitSet(c.size())
>> 
>> Don't you notice this mistake?
> 
> It certainly isn't an exact size, and probably not a very good guess in many cases (e.g., a small number of objects
> where one near the end is chosen), but it is at least a lower limit on the memory you need.
> So I take it you propose to allocate the BitSet the first time you need it, while looping in the reverse order of this
> array list? That will work, at the (fairly minor) expense of having to do a null check in the loop (or the added
> complexity of an initial loop that runs until you find one and a second loop from that point to the end).  I'm still
> not convinced that this is worth the effort, at least not without a test case showing some gain that we can measure.

Here's an improvement on BitSet:

 java
	private boolean remove(Collection<?> c, boolean isRemoveAll) {
		BitSet bs = null;
		// find last index
		final int max = size();
		int i;
		for (i = max - 1; i >= 0; i--) {
			if (c.contains(get(i)) == isRemoveAll) {
				bs = new BitSet(i);
				bs.set(i--);
				break;
			}
		}
		final boolean removed = bs != null;
		beginChange();
		if (removed) {
			for (; i >= 0; i--) {
				if (c.contains(get(i)) == isRemoveAll) {
					bs.set(i);
				}
			}
			int cur = max;
			while ((cur = bs.previousSetBit(cur - 1)) >= 0) {
				remove(cur);
			}
		}
		endChange();
		return removed;
	}
Extreme test cases that show the most improvement.

 Java
			for (; olist.size() > 0;) {
				olist.removeAll(olist.get(olist.size() - 1));
			}

Here's an improvement on Run-Lengths:
 java
	private boolean remove(Collection<?> c, boolean isRemoveAll) {
		int[] runLength = new int[4];
		int size = 0;
		final int n = size();
		{
			int run = 0;
			boolean flag = isRemoveAll;
			for (int i = n - 1; i >= 0; i--) {
				if (c.contains(get(i)) == flag) {
					run++;
				} else {
					if (runLength.length <= size) {
						runLength = Arrays.copyOf(runLength, Math.min(runLength.length << 1, n + 1));
					}
					runLength[size++] = run;
					run = 1;
					flag = !flag;
				}
			}
			if (run > 0 && flag == isRemoveAll) {
				if (runLength.length <= size) {
					runLength = Arrays.copyOf(runLength, Math.min(runLength.length << 1, n + 1));
				}
				runLength[size++] = run;
			}
		}
		boolean flag = true;
		boolean removed = false;
		beginChange();
		int cur = n - 1;
		for (int i = 0; i < size; i++) {
			final int run = runLength[i];
			if (flag) {
				removed = run > 0;
				for (int to = cur - run; cur > to; cur--) {
					remove(cur);
				}
			} else {
				cur -= run;
			}
			flag = !flag;
		}
		endChange();
		return removed;
	}

-------------

PR: https://git.openjdk.java.net/jfx/pull/305


More information about the openjfx-dev mailing list