Skip to content
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

Create constant empty arrays Field[0] and String[0] for faster toArray() calls #5322

Closed
lukaseder opened this issue May 31, 2016 · 1 comment

Comments

@lukaseder
Copy link
Member

lukaseder commented May 31, 2016

Some further improvement after this: #5057

(benchmark this first!)

@lukaseder
Copy link
Member Author

Benchmark:

import java.util.ArrayList;
import java.util.List;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;

@Fork(value = 3, jvmArgsAppend = "-Djmh.stack.lines=3")
@Warmup(iterations = 5)
@Measurement(iterations = 7)
public class ToArrayBenchmark {

    @State(Scope.Benchmark)
    public static class BenchmarkState {

        List<String>          list;
        static final String[] EMPTY = {};

        @Setup(Level.Trial)
        public void setup() throws Exception {
            list = new ArrayList<String>();
            list.add("a");
            list.add("b");
            list.add("c");
        }

        @TearDown(Level.Trial)
        public void teardown() throws Exception {
            list = null;
        }
    }

    @Benchmark
    public void testToArray(Blackhole blackhole, BenchmarkState state) {
        blackhole.consume(
            state.list.toArray()
        );
    }

    @Benchmark
    public void testToArrayEmptyConstant(Blackhole blackhole, BenchmarkState state) {
        blackhole.consume(
            state.list.toArray(BenchmarkState.EMPTY)
        );
    }

    @Benchmark
    public void testToArrayEmptyNew(Blackhole blackhole, BenchmarkState state) {
        blackhole.consume(
            state.list.toArray(new String[0])
        );
    }

    @Benchmark
    public void testToArraySizedNew(Blackhole blackhole, BenchmarkState state) {
        blackhole.consume(
            state.list.toArray(new String[state.list.size()])
        );
    }

    @Benchmark
    public void testToArraySizedFromStream(Blackhole blackhole, BenchmarkState state) {
        blackhole.consume(
            state.list.stream().toArray(String[]::new)
        );
    }
}

Results:

Benchmark                                     Mode  Cnt         Score         Error  Units
ToArrayBenchmark.testToArray                 thrpt   21  80615750.621 ▒ 5686268.337  ops/s
ToArrayBenchmark.testToArrayEmptyConstant    thrpt   21  67133158.712 ▒ 1811051.674  ops/s
ToArrayBenchmark.testToArrayEmptyNew         thrpt   21  60806516.153 ▒  437034.988  ops/s
ToArrayBenchmark.testToArraySizedFromStream  thrpt   21  17771647.599 ▒  702893.100  ops/s
ToArrayBenchmark.testToArraySizedNew         thrpt   21  32900924.072 ▒  743051.700  ops/s

The winner is, obviously, Collection.toArray() which returns an Object[]. If the array type is relevant, then passing a constant empty array beats passing a fresh empty array by roughly 10% due to decreased GC pressure. The refactoring is probably safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant