/* * Copyright (c) 2009, 2011, 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. * * 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 com.sun.max.vm.heap; import com.sun.max.unsafe.*; /** * A policy object that helps with taking decisions with respect to when to refill a tlab on allocation failure, what size the tlab should have on next refill etc.... * TLABRefillPolicy are stored in a thread local variable TLAB_REFILL_POLICY if tlabs are being used. Threads may refer to the same TLAB policy or * to one individual policy if the policy allows each thread to have their TLAB evolves differently. */ public class SimpleTLABRefillPolicy extends TLABRefillPolicy { /** * Number of allocation failure tolerated per allocation mark. * Arbitrarily chosen at the moment. Statistics needed to see if it helps. * with limiting fragmentation of TLABs. */ static final int TLAB_NUM_ALLOCATION_FAILURES_PER_MARK = 3; /** * refillThreshold is computed as TLAB size / refill ratio. * A refill ratio of 10 correspond to a refill threshold at 10% of the TLAB size. */ static final int TLAB_REFILL_RATIO = 10; /** * Size the TLAB should have on next refill. */ private Size nextSize; /** * Threshold for refilling the TLAB on allocation failure. * When space left in the TLAB is below this threshold, the TLAB is refilled. */ private Size refillThreshold; /** * Number of allocation failures on the same allocation mark. * A number of failures are tolerated on the same allocation mark * when the TLAB's used space is below the refill threshold. */ private int allocationFailures; /** * Last allocation mark where an allocation failure occurred. */ private Pointer lastMark; public SimpleTLABRefillPolicy(Size initialTLABSize) { lastMark = Pointer.zero(); allocationFailures = 0; nextSize = initialTLABSize; refillThreshold = initialTLABSize.dividedBy(TLAB_REFILL_RATIO); } @Override public boolean shouldRefill(Size size, Pointer allocationMark) { if (allocationMark.isZero()) { // No TLAB. Refill whatsoever return true; } if (size.lessThan(refillThreshold)) { // space the TLAB failed to allocate is smaller than the refill threshold. // We should definitively refill return true; } // Space left in TLAB is larger than refill ratio. Don't want to refill, unless // we had a number of allocation failures for the same allocation mark. // In that case, let bite the bullet and get a new TLAB. // TODO (ld) a tlab global allocation failure counter is probably better... if (!lastMark.equals(allocationMark)) { lastMark = allocationMark; allocationFailures = 1; return false; } allocationFailures++; return allocationFailures > TLAB_NUM_ALLOCATION_FAILURES_PER_MARK; } @Override public Size nextTlabSize() { // Currently, nothing fancy. Just always returns the initial TLAB size value. return nextSize; } }