Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14bbb8a7 authored by Kweku Adams's avatar Kweku Adams
Browse files

Improve forEach.

The default implementation of Collection.forEach() uses the
iterator(). Switch to straight iterating through the array since the
iterator is an inefficient way to access the array contents.

Benchmark results:

Before:

android.util.ArraySetPerfTest#testForEach_Large:
	forEach_Large_median (ns): 398480
	forEach_Large_min (ns): 395758
	forEach_Large_mean (ns): 400957
	forEach_Large_standardDeviation: 5457
android.util.ArraySetPerfTest#testForEach_Small:
	forEach_Small_min (ns): 82768
	forEach_Small_median (ns): 83884
	forEach_Small_standardDeviation: 896
	forEach_Small_mean (ns): 83724

After:

android.util.ArraySetPerfTest#testForEach_Large:
	forEach_Large_median (ns): 319481
	forEach_Large_min (ns): 316166
	forEach_Large_mean (ns): 339865
	forEach_Large_standardDeviation: 44201
android.util.ArraySetPerfTest#testForEach_Small:
	forEach_Small_min (ns): 58736
	forEach_Small_median (ns): 60648
	forEach_Small_standardDeviation: 1375
	forEach_Small_mean (ns): 60622

Bug: 194098491
Test: atest CorePerfTests:ArraySetPerfTest (see results above)
Test: atest CtsUtilTestCases:ArraySetTest
Test: atest FrameworksCoreTests:ArraySetTest
Change-Id: Ib14b96f095203e1f5811132f2a21be0452645f7e
parent 7efcc4df
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.function.Consumer;
import java.util.function.Predicate;

@RunWith(AndroidJUnit4.class)
@@ -38,6 +39,38 @@ public class ArraySetPerfTest {
    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    @Test
    public void testForEach_Small() {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        Consumer<Integer> consumer = (i) -> {
        };
        while (state.keepRunning()) {
            for (int i = 0; i < NUM_ITERATIONS; ++i) {
                ArraySet<Integer> set = new ArraySet<>();
                for (int j = 0; j < SET_SIZE_SMALL; j++) {
                    set.add(j);
                }
                set.forEach(consumer);
            }
        }
    }

    @Test
    public void testForEach_Large() {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        Consumer<Integer> consumer = (i) -> {
        };
        while (state.keepRunning()) {
            for (int i = 0; i < NUM_ITERATIONS; ++i) {
                ArraySet<Integer> set = new ArraySet<>();
                for (int j = 0; j < SET_SIZE_LARGE; j++) {
                    set.add(j);
                }
                set.forEach(consumer);
            }
        }
    }

    @Test
    public void testValueAt_InBounds() {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+1 −0
Original line number Diff line number Diff line
@@ -45993,6 +45993,7 @@ package android.util {
    method public boolean contains(Object);
    method public boolean containsAll(java.util.Collection<?>);
    method public void ensureCapacity(int);
    method public void forEach(java.util.function.Consumer<? super E>);
    method public int indexOf(Object);
    method public boolean isEmpty();
    method public java.util.Iterator<E> iterator();
+18 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
@@ -747,6 +748,23 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
        return mSize;
    }

    /**
     * Performs the given action for all elements in the stored order. This implementation overrides
     * the default implementation to avoid using the {@link #iterator()}.
     *
     * @param action The action to be performed for each element
     */
    @Override
    public void forEach(Consumer<? super E> action) {
        if (action == null) {
            throw new NullPointerException("action must not be null");
        }

        for (int i = 0; i < mSize; ++i) {
            action.accept(valueAt(i));
        }
    }

    @Override
    public Object[] toArray() {
        Object[] result = new Object[mSize];