1 /* 2 * Copyright 2019 Google Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.bench.java.lang; 24 25 import org.openjdk.jmh.annotations.Benchmark; 26 import org.openjdk.jmh.annotations.BenchmarkMode; 27 import org.openjdk.jmh.annotations.Mode; 28 import org.openjdk.jmh.annotations.OutputTimeUnit; 29 import org.openjdk.jmh.annotations.Scope; 30 import org.openjdk.jmh.annotations.Setup; 31 import org.openjdk.jmh.annotations.State; 32 33 import java.util.Arrays; 34 import java.util.concurrent.ThreadLocalRandom; 35 import java.util.concurrent.TimeUnit; 36 37 /** 38 * Explores the cost of copying the contents of one array to another, as is 39 * commonly seen in collection classes that need to resize their backing 40 * array, like ArrayList. 41 * 42 * We have multiple variations on copying, and we explore the cost of 43 * clearing the old array, which might help for generational GCs. 44 * 45 * Benchmarks the operations in the ancient 46 * JDK-6428387: array clone() much slower than Arrays.copyOf 47 * 48 * 2019 results on x86: 49 * 50 * The "simple" benchmarks below have the same performance, except that 51 * simple_copyLoop is surprisingly 5x slower. The array copying intrinsics 52 * are very effective and a naive loop does not get optimized the same way. 53 * OTOH there is no intrinsic for Arrays.fill but the naive array zeroing loop 54 * *does* get optimized to something a little faster than than arraycopy. 55 * Because of the performance of intrinsics, the two-pass grow_copyOf_zeroLoop 56 * outperforms grow_copyZeroLoop. 57 */ 58 @BenchmarkMode(Mode.AverageTime) 59 @OutputTimeUnit(TimeUnit.NANOSECONDS) 60 @State(Scope.Benchmark) 61 public class ArrayFiddle { 62 private static final int SIZE = 1024; 63 private static final int LARGER_SIZE = SIZE + (SIZE >> 1); 64 private Object[] data = new Object[SIZE]; 65 private Object[] copy = data.clone(); 66 67 @Setup 68 public void setup() { 69 ThreadLocalRandom rnd = ThreadLocalRandom.current(); 70 for (int i = data.length; i--> 0; ) 71 data[i] = rnd.nextInt(256); 72 } 73 74 // --- "simple" benchmarks just make an array clone 75 76 @Benchmark 77 public Object[] simple_clone() { 78 return data.clone(); 79 } 80 81 @Benchmark 82 public Object[] simple_copyOf() { 83 return Arrays.copyOf(data, data.length); 84 } 85 86 @Benchmark 87 public Object[] simple_arraycopy() { 88 int length = data.length; 89 Object[] out = new Object[length]; 90 System.arraycopy(data, 0, out, 0, length); 91 return out; 92 } 93 94 @Benchmark 95 public Object[] simple_copyLoop() { 96 final Object[] data = this.data; 97 int length = data.length; 98 Object[] out = new Object[length]; 99 for (int j = 0; j < length; j++) 100 out[j] = data[j]; 101 return out; 102 } 103 104 // --- "grow" benchmarks have an output array that is larger 105 106 private Object[] input_array() { 107 System.arraycopy(data, 0, copy, 0, SIZE); 108 return copy; 109 } 110 111 @Benchmark 112 public Object[] grow_copyLoop() { 113 Object[] in = input_array(); 114 Object[] out = new Object[LARGER_SIZE]; 115 for (int j = 0; j < SIZE; j++) 116 out[j] = in[j]; 117 return out; 118 } 119 120 @Benchmark 121 public Object[] grow_copyZeroLoop() { 122 Object[] in = input_array(); 123 Object[] out = new Object[LARGER_SIZE]; 124 for (int j = 0; j < SIZE; j++) { 125 out[j] = in[j]; 126 in[j] = null; 127 } 128 return out; 129 } 130 131 @Benchmark 132 public Object[] grow_arraycopy() { 133 Object[] in = input_array(); 134 Object[] out = new Object[LARGER_SIZE]; 135 System.arraycopy(in, 0, out, 0, SIZE); 136 return out; 137 } 138 139 @Benchmark 140 public Object[] grow_arraycopy_fill() { 141 Object[] in = input_array(); 142 Object[] out = new Object[LARGER_SIZE]; 143 System.arraycopy(in, 0, out, 0, SIZE); 144 Arrays.fill(in, null); 145 return out; 146 } 147 148 @Benchmark 149 public Object[] grow_arraycopy_zeroLoop() { 150 Object[] in = input_array(); 151 Object[] out = new Object[LARGER_SIZE]; 152 System.arraycopy(in, 0, out, 0, SIZE); 153 for (int i = 0; i < SIZE; i++) 154 in[i] = null; 155 return out; 156 } 157 158 @Benchmark 159 public Object[] grow_copyOf() { 160 Object[] in = input_array(); 161 Object[] out = Arrays.copyOf(in, LARGER_SIZE); 162 return out; 163 } 164 165 @Benchmark 166 public Object[] grow_copyOf_fill() { 167 Object[] in = input_array(); 168 Object[] out = Arrays.copyOf(in, LARGER_SIZE); 169 Arrays.fill(in, null); 170 return out; 171 } 172 173 @Benchmark 174 public Object[] grow_copyOf_zeroLoop() { 175 Object[] in = input_array(); 176 Object[] out = Arrays.copyOf(in, LARGER_SIZE); 177 for (int i = 0; i < SIZE; i++) 178 in[i] = null; 179 return out; 180 } 181 182 }