/* * Copyright (c) 2011, 2012, 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.tele.method; import java.io.*; import java.lang.management.*; import java.text.*; import java.util.*; import com.sun.max.lang.*; import com.sun.max.tele.*; import com.sun.max.tele.memory.*; import com.sun.max.tele.object.*; import com.sun.max.tele.reference.*; import com.sun.max.unsafe.*; import com.sun.max.vm.code.*; import com.sun.max.vm.compiler.target.*; /** * Access to an <em>area</em> of the VM's code cache, described in the VM by a (heap) instance of {@link CodeRegion}. * All of the allocated data in an area of a code cache region is <em>owned</em> * by a method compilation, represented in the VM as a (heap) instance of {@link TargetMethod}. * <p> * Allocated data is stored in the same <em>object format</em> as are objects in the VM's heap. * Interaction with objects in the area is delegated to an instance of {@link RemoteObjectReferenceManager}, which permits * specialized implementations of {@link RemoteReference} to be created that embody knowledge of how objects are managed in each region. * * @see CodeRegion * @see TargetMethod * @see VmCodeCacheAccess */ public abstract class VmCodeCacheRegion extends AbstractVmHolder implements TeleVMCache, MaxCodeCacheRegion, VmObjectHoldingRegion<MaxCodeCacheRegion>, MaxCodeHoldingRegion<MaxCodeCacheRegion> { private static final int TRACE_VALUE = 1; /** * Representation of a VM memory region used as part of the compiled code cache. * <p> * This region has no parent; it is either in the boot image or is allocated dynamically from the OS * <p> * This region has no children. * We could decompose it into sub-regions containing a method compilation each, but we don't * do that at this time. */ private static final class CodeCacheMemoryRegion extends TeleDelegatedMemoryRegion implements MaxEntityMemoryRegion<MaxCodeCacheRegion> { private static final List<MaxEntityMemoryRegion< ? extends MaxEntity>> EMPTY = Collections.emptyList(); private final MaxCodeCacheRegion owner; /** * Creates access to a VM memory object that describes part of the VM's code cache. * @param owner the object that models the code allocation area * @param teleCodeRegion the VM object that describes this region of VM memory */ public CodeCacheMemoryRegion(MaxVM vm, MaxCodeCacheRegion owner, TeleCodeRegion teleCodeRegion) { super(vm, teleCodeRegion); this.owner = owner; } public MaxEntityMemoryRegion< ? extends MaxEntity> parent() { // Compiled code regions are allocated from the OS, not part of any other region return null; } public List<MaxEntityMemoryRegion< ? extends MaxEntity>> children() { // We don't break a compiled code memory region into any smaller entities. return EMPTY; } public MaxCodeCacheRegion owner() { return owner; } } private final TeleCodeRegion teleCodeRegion; /** * Representation of the VM memory region holding this part of the code cache. */ private final CodeCacheMemoryRegion codeCacheMemoryRegion; public VmCodeCacheRegion(TeleVM vm, TeleCodeRegion teleCodeRegion) { super(vm); this.teleCodeRegion = teleCodeRegion; this.codeCacheMemoryRegion = new CodeCacheMemoryRegion(vm, this, teleCodeRegion); } public String entityName() { return codeCacheMemoryRegion.regionName(); } public MaxEntityMemoryRegion<MaxCodeCacheRegion> memoryRegion() { return codeCacheMemoryRegion; } public boolean contains(Address address) { return codeCacheMemoryRegion.contains(address); } public TeleObject representation() { return teleCodeRegion; } /** * Refresh enough state to understand the state of this region in the code cache, for example, whether * eviction is underway, without necessarily doing any other cache updates. * <p> * This must be done before heap objects are refreshed, in particular so that the * code cache region status can be used to determine refresh behavior in instances of * {@link TargetMethod}. */ public final void updateStatus(long epoch) { teleCodeRegion.updateCache(epoch); } /** * @return whether code eviction ever takes place in this code region */ public boolean isManaged() { return teleCodeRegion.isManaged(); } /** * @return whether code eviction is currently underway in this code region */ public boolean isInEviction() { return teleCodeRegion.isInEviction(); } /** * @return the number of code evictions that have been completed in this code region */ public long evictionCount() { return teleCodeRegion.evictionCount(); } /** * @see MaxVM#inspectableObjects() */ public abstract List<MaxObject> inspectableObjects(); /** * Notifies the code cache region that a target method has been discovered * in the region and that an instance of {@link TeleTargetMethod} has * been created to represent it. * * @param teleTargetMethod a newly created {@link TeleTargetMethod} */ public abstract void register(TeleTargetMethod teleTargetMethod); public abstract TeleCompilation findCompilation(Address address); /** * @return the number of method compilations that have been copied from * the VM and cached locally. This is not done automatically when a * {@link TeleTargetMethod} is created corresponding to a compilation, * but rather done lazily when detailed information about the compilation is needed. */ public abstract int loadedCompilationCount(); public abstract void writeSummary(PrintStream printStream); public void printSessionStats(PrintStream printStream, int indent, boolean verbose) { final String indentation = Strings.times(' ', indent); final NumberFormat formatter = NumberFormat.getInstance(); // Line 1 final StringBuilder sb1 = new StringBuilder(); sb1.append(indentation + entityName()); if (isManaged()) { if (isInEviction()) { sb1.append(" (managed, EVICTION UNDERWAY)"); } else { sb1.append(" (managed)"); } } printStream.println(sb1.toString()); // Line 2 final StringBuilder sb2 = new StringBuilder(); sb2.append("region: "); final MemoryUsage usage = memoryRegion().getUsage(); final long size = usage.getCommitted(); sb2.append("size=" + formatter.format(size)); if (size > 0) { final long used = usage.getUsed(); sb2.append(", usage=" + (Long.toString(100 * used / size)) + "%"); } printStream.println(indentation + " " + sb2.toString()); // Line 3 final StringBuilder sb3 = new StringBuilder(); sb3.append("compilations: registered=").append(formatter.format(compilationCount())); sb3.append(", code loaded=").append(formatter.format(loadedCompilationCount())); if (teleCodeRegion.isManaged()) { sb3.append(", completed evictions=").append(formatter.format(teleCodeRegion.evictionCount())); } printStream.println(indentation + " " + sb3.toString()); // Line 4 codePointerManager().printSessionStats(printStream, indent + 4, verbose); // Line 5 // Was objectReferenceManager().printSessionStats(printStream, indent + 4, verbose); } @Override public void printObjectSessionStats(PrintStream printStream, int indent, boolean verbose) { final String indentation = Strings.times(' ', indent); printStream.println(indentation + "Object session stats for: " + entityName()); } /** * A simple status printer to be used after updating state concerning * a VM area of code cache that is not managed, which is to say, the * registered contents can only grow monotonically, if at all. */ protected final class UnmanagedCodeCacheRegionStatsPrinter { private int previousCompilationCount = 0; @Override public String toString() { final int compilationCount = compilationCount(); final int newCompilationCount = compilationCount - previousCompilationCount; final StringBuilder msg = new StringBuilder(); msg.append("#compilations=(").append(compilationCount); msg.append(",new=").append(newCompilationCount).append(")"); previousCompilationCount = compilationCount; return msg.toString(); } } }