1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.marlin; 27 28 import java.util.Arrays; 29 import static sun.java2d.marlin.MarlinUtils.logInfo; 30 31 public final class ArrayCacheConst implements MarlinConst { 32 33 static final int BUCKETS = 8; 34 static final int MIN_ARRAY_SIZE = 4096; 35 // maximum array size 36 static final int MAX_ARRAY_SIZE; 37 // threshold below to grow arrays by 4 38 static final int THRESHOLD_SMALL_ARRAY_SIZE = 4 * 1024 * 1024; 39 // threshold to grow arrays only by (3/2) instead of 2 40 static final int THRESHOLD_ARRAY_SIZE; 41 // threshold to grow arrays only by (5/4) instead of (3/2) 42 static final long THRESHOLD_HUGE_ARRAY_SIZE; 43 static final int[] ARRAY_SIZES = new int[BUCKETS]; 44 45 static { 46 // initialize buckets for int/float arrays 47 int arraySize = MIN_ARRAY_SIZE; 48 49 int inc_lg = 2; // x4 50 51 for (int i = 0; i < BUCKETS; i++, arraySize <<= inc_lg) { 52 ARRAY_SIZES[i] = arraySize; 53 54 if (DO_TRACE) { 55 logInfo("arraySize[" + i + "]: " + arraySize); 56 } 57 58 if (arraySize >= THRESHOLD_SMALL_ARRAY_SIZE) { 59 inc_lg = 1; // x2 60 } 61 } 62 MAX_ARRAY_SIZE = arraySize >> inc_lg; 63 64 if (MAX_ARRAY_SIZE <= 0) { 65 throw new IllegalStateException("Invalid max array size !"); 66 } 67 68 THRESHOLD_ARRAY_SIZE = 16 * 1024 * 1024; // >16M 69 THRESHOLD_HUGE_ARRAY_SIZE = 48L * 1024 * 1024; // >48M 70 71 if (DO_STATS || DO_MONITORS) { 72 logInfo("ArrayCache.BUCKETS = " + BUCKETS); 73 logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE); 74 logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE); 75 logInfo("ArrayCache.ARRAY_SIZES = " 76 + Arrays.toString(ARRAY_SIZES)); 77 logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = " 78 + THRESHOLD_ARRAY_SIZE); 79 logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = " 80 + THRESHOLD_HUGE_ARRAY_SIZE); 81 } 82 } 83 84 private ArrayCacheConst() { 85 // Utility class 86 } 87 88 // small methods used a lot (to be inlined / optimized by hotspot) 89 90 static int getBucket(final int length) { 91 for (int i = 0; i < ARRAY_SIZES.length; i++) { 92 if (length <= ARRAY_SIZES[i]) { 93 return i; 94 } 95 } 96 return -1; 97 } 98 99 /** 100 * Return the new array size (~ x2) 101 * @param curSize current used size 102 * @param needSize needed size 103 * @return new array size 104 */ 105 public static int getNewSize(final int curSize, final int needSize) { 106 // check if needSize is negative or integer overflow: 107 if (needSize < 0) { 108 // hard overflow failure - we can't even accommodate 109 // new items without overflowing 110 throw new ArrayIndexOutOfBoundsException( 111 "array exceeds maximum capacity !"); 112 } 113 assert curSize >= 0; 114 final int initial = curSize; 115 int size; 116 if (initial > THRESHOLD_ARRAY_SIZE) { 117 size = initial + (initial >> 1); // x(3/2) 118 } else { 119 size = (initial << 1); // x2 120 } 121 // ensure the new size is >= needed size: 122 if (size < needSize) { 123 // align to 4096 (may overflow): 124 size = ((needSize >> 12) + 1) << 12; 125 } 126 // check integer overflow: 127 if (size < 0) { 128 // resize to maximum capacity: 129 size = Integer.MAX_VALUE; 130 } 131 return size; 132 } 133 134 /** 135 * Return the new array size (~ x2) 136 * @param curSize current used size 137 * @param needSize needed size 138 * @return new array size 139 */ 140 public static long getNewLargeSize(final long curSize, final long needSize) { 141 // check if needSize is negative or integer overflow: 142 if ((needSize >> 31L) != 0L) { 143 // hard overflow failure - we can't even accommodate 144 // new items without overflowing 145 throw new ArrayIndexOutOfBoundsException( 146 "array exceeds maximum capacity !"); 147 } 148 assert curSize >= 0L; 149 long size; 150 if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) { 151 size = curSize + (curSize >> 2L); // x(5/4) 152 } else if (curSize > THRESHOLD_ARRAY_SIZE) { 153 size = curSize + (curSize >> 1L); // x(3/2) 154 } else if (curSize > THRESHOLD_SMALL_ARRAY_SIZE) { 155 size = (curSize << 1L); // x2 156 } else { 157 size = (curSize << 2L); // x4 158 } 159 // ensure the new size is >= needed size: 160 if (size < needSize) { 161 // align to 4096: 162 size = ((needSize >> 12L) + 1L) << 12L; 163 } 164 // check integer overflow: 165 if (size > Integer.MAX_VALUE) { 166 // resize to maximum capacity: 167 size = Integer.MAX_VALUE; 168 } 169 return size; 170 } 171 172 static final class CacheStats { 173 final String name; 174 final BucketStats[] bucketStats; 175 int resize = 0; 176 int oversize = 0; 177 long totalInitial = 0L; 178 179 CacheStats(final String name) { 180 this.name = name; 181 182 bucketStats = new BucketStats[BUCKETS]; 183 for (int i = 0; i < BUCKETS; i++) { 184 bucketStats[i] = new BucketStats(); 185 } 186 } 187 188 void reset() { 189 resize = 0; 190 oversize = 0; 191 192 for (int i = 0; i < BUCKETS; i++) { 193 bucketStats[i].reset(); 194 } 195 } 196 197 long dumpStats() { 198 long totalCacheBytes = 0L; 199 200 if (DO_STATS) { 201 for (int i = 0; i < BUCKETS; i++) { 202 final BucketStats s = bucketStats[i]; 203 204 if (s.maxSize != 0) { 205 totalCacheBytes += getByteFactor() 206 * (s.maxSize * ARRAY_SIZES[i]); 207 } 208 } 209 210 if (totalInitial != 0L || totalCacheBytes != 0L 211 || resize != 0 || oversize != 0) 212 { 213 logInfo(name + ": resize: " + resize 214 + " - oversize: " + oversize 215 + " - initial: " + getTotalInitialBytes() 216 + " bytes (" + totalInitial + " elements)" 217 + " - cache: " + totalCacheBytes + " bytes" 218 ); 219 } 220 221 if (totalCacheBytes != 0L) { 222 logInfo(name + ": usage stats:"); 223 224 for (int i = 0; i < BUCKETS; i++) { 225 final BucketStats s = bucketStats[i]; 226 227 if (s.getOp != 0) { 228 logInfo(" Bucket[" + ARRAY_SIZES[i] + "]: " 229 + "get: " + s.getOp 230 + " - put: " + s.returnOp 231 + " - create: " + s.createOp 232 + " :: max size: " + s.maxSize 233 ); 234 } 235 } 236 } 237 } 238 return totalCacheBytes; 239 } 240 241 private int getByteFactor() { 242 int factor = 1; 243 if (name.contains("Int") || name.contains("Float")) { 244 factor = 4; 245 } 246 return factor; 247 } 248 249 long getTotalInitialBytes() { 250 return getByteFactor() * totalInitial; 251 } 252 } 253 254 static final class BucketStats { 255 int getOp = 0; 256 int createOp = 0; 257 int returnOp = 0; 258 int maxSize = 0; 259 260 void reset() { 261 getOp = 0; 262 createOp = 0; 263 returnOp = 0; 264 maxSize = 0; 265 } 266 267 void updateMaxSize(final int size) { 268 if (size > maxSize) { 269 maxSize = size; 270 } 271 } 272 } 273 }