ArrayCache.java 7.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.java2d.marlin;

import java.util.Arrays;
import static sun.java2d.marlin.MarlinUtils.logInfo;

public final class ArrayCache implements MarlinConst {

    static final int BUCKETS = 4;
    static final int MIN_ARRAY_SIZE = 4096;
    static final int MAX_ARRAY_SIZE;
    static final int MASK_CLR_1 = ~1;
    // threshold to grow arrays only by (3/2) instead of 2
    static final int THRESHOLD_ARRAY_SIZE;
    static final int[] ARRAY_SIZES = new int[BUCKETS];
    // dirty byte array sizes
    static final int MIN_DIRTY_BYTE_ARRAY_SIZE = 32 * 2048; // 32px x 2048px
    static final int MAX_DIRTY_BYTE_ARRAY_SIZE;
    static final int[] DIRTY_BYTE_ARRAY_SIZES = new int[BUCKETS];
    // large array thresholds:
    static final long THRESHOLD_LARGE_ARRAY_SIZE;
    static final long THRESHOLD_HUGE_ARRAY_SIZE;
    // stats
    private static int resizeInt = 0;
    private static int resizeDirtyInt = 0;
    private static int resizeDirtyFloat = 0;
    private static int resizeDirtyByte = 0;
    private static int oversize = 0;

    static {
        // initialize buckets for int/float arrays
        int arraySize = MIN_ARRAY_SIZE;

        for (int i = 0; i < BUCKETS; i++, arraySize <<= 2) {
            ARRAY_SIZES[i] = arraySize;

            if (doTrace) {
                logInfo("arraySize[" + i + "]: " + arraySize);
            }
        }
        MAX_ARRAY_SIZE = arraySize >> 2;

        /* initialize buckets for dirty byte arrays
         (large AA chunk = 32 x 2048 pixels) */
        arraySize = MIN_DIRTY_BYTE_ARRAY_SIZE;

        for (int i = 0; i < BUCKETS; i++, arraySize <<= 1) {
            DIRTY_BYTE_ARRAY_SIZES[i] = arraySize;

            if (doTrace) {
                logInfo("dirty arraySize[" + i + "]: " + arraySize);
            }
        }
        MAX_DIRTY_BYTE_ARRAY_SIZE = arraySize >> 1;

        // threshold to grow arrays only by (3/2) instead of 2
        THRESHOLD_ARRAY_SIZE = Math.max(2 * 1024 * 1024, MAX_ARRAY_SIZE); // 2M

        THRESHOLD_LARGE_ARRAY_SIZE = 8L * THRESHOLD_ARRAY_SIZE; // 16M
        THRESHOLD_HUGE_ARRAY_SIZE  = 8L * THRESHOLD_LARGE_ARRAY_SIZE; // 128M

        if (doStats || doMonitors) {
            logInfo("ArrayCache.BUCKETS        = " + BUCKETS);
            logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE);
            logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE);
            logInfo("ArrayCache.ARRAY_SIZES = "
                    + Arrays.toString(ARRAY_SIZES));
            logInfo("ArrayCache.MIN_DIRTY_BYTE_ARRAY_SIZE = "
                    + MIN_DIRTY_BYTE_ARRAY_SIZE);
            logInfo("ArrayCache.MAX_DIRTY_BYTE_ARRAY_SIZE = "
                    + MAX_DIRTY_BYTE_ARRAY_SIZE);
            logInfo("ArrayCache.ARRAY_SIZES = "
                    + Arrays.toString(DIRTY_BYTE_ARRAY_SIZES));
            logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = "
                    + THRESHOLD_ARRAY_SIZE);
            logInfo("ArrayCache.THRESHOLD_LARGE_ARRAY_SIZE = "
                    + THRESHOLD_LARGE_ARRAY_SIZE);
            logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = "
                    + THRESHOLD_HUGE_ARRAY_SIZE);
        }
    }

    private ArrayCache() {
        // Utility class
    }

    static synchronized void incResizeInt() {
        resizeInt++;
    }

    static synchronized void incResizeDirtyInt() {
        resizeDirtyInt++;
    }

    static synchronized void incResizeDirtyFloat() {
        resizeDirtyFloat++;
    }

    static synchronized void incResizeDirtyByte() {
        resizeDirtyByte++;
    }

    static synchronized void incOversize() {
        oversize++;
    }

    static void dumpStats() {
        if (resizeInt != 0 || resizeDirtyInt != 0 || resizeDirtyFloat != 0
                || resizeDirtyByte != 0 || oversize != 0) {
            logInfo("ArrayCache: int resize: " + resizeInt
                    + " - dirty int resize: " + resizeDirtyInt
                    + " - dirty float resize: " + resizeDirtyFloat
                    + " - dirty byte resize: " + resizeDirtyByte
                    + " - oversize: " + oversize);
        }
    }

    // small methods used a lot (to be inlined / optimized by hotspot)

    static int getBucket(final int length) {
        for (int i = 0; i < ARRAY_SIZES.length; i++) {
            if (length <= ARRAY_SIZES[i]) {
                return i;
            }
        }
        return -1;
    }

    static int getBucketDirtyBytes(final int length) {
        for (int i = 0; i < DIRTY_BYTE_ARRAY_SIZES.length; i++) {
            if (length <= DIRTY_BYTE_ARRAY_SIZES[i]) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Return the new array size (~ x2)
     * @param curSize current used size
     * @param needSize needed size
     * @return new array size
     */
    public static int getNewSize(final int curSize, final int needSize) {
        final int initial = (curSize & MASK_CLR_1);
        int size;
        if (initial > THRESHOLD_ARRAY_SIZE) {
            size = initial + (initial >> 1); // x(3/2)
        } else {
            size = (initial) << 1; // x2
        }
        // ensure the new size is >= needed size:
        if (size < needSize) {
            // align to 4096:
            size = ((needSize >> 12) + 1) << 12;
        }
        return size;
    }

    /**
     * Return the new array size (~ x2)
     * @param curSize current used size
     * @param needSize needed size
     * @return new array size
     */
    public static long getNewLargeSize(final long curSize, final long needSize) {
        long size;
        if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
            size = curSize + (curSize >> 2L); // x(5/4)
        } else  if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) {
            size = curSize + (curSize >> 1L); // x(3/2)
        } else {
            size = curSize << 1L; // x2
        }
        // ensure the new size is >= needed size:
        if (size < needSize) {
            // align to 4096:
            size = ((needSize >> 12) + 1) << 12;
        }
        if (size >= Integer.MAX_VALUE) {
            if (curSize >= Integer.MAX_VALUE) {
                // hard overflow failure - we can't even accommodate
                // new items without overflowing
                throw new ArrayIndexOutOfBoundsException(
                              "array exceeds maximum capacity !");
            }
            // resize to maximum capacity:
            size = Integer.MAX_VALUE;
        }
        return size;
    }
}