001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.mm.mminterface;
014
015import java.lang.management.MemoryType;
016import java.lang.management.MemoryUsage;
017import java.util.HashMap;
018
019import org.jikesrvm.mm.mminterface.Selected.Plan;
020import org.jikesrvm.mm.mmtk.FinalizableProcessor;
021import org.mmtk.policy.Space;
022import org.mmtk.utility.Conversions;
023import org.mmtk.utility.options.Options;
024import org.mmtk.utility.statistics.Stats;
025import org.vmmagic.unboxed.Extent;
026
027/**
028 * Provides methods supporting all JMX beans that relate to memory. Functionality
029 * for memory management beans generally requires interfacing with MMTk which is
030 * why this class belongs to the MMTk-VM interface.
031 * <p>
032 * In JMX terms, the Jikes RVM provides only one memory manager (the garbage collector)
033 * and several memory pools (each of which corresponds to exactly one MMTk space).
034 * <p>
035 * NOTE: Features related to memory usage are currently not implemented.
036 */
037public class JMXSupport {
038
039  /**
040   * We only provide one garbage collector because the choice of garbage collector
041   * for the VM is fixed at build time.
042   */
043  private static final String[] garbageCollectorNames = { Selected.name };
044
045  /**
046   * The names of all memory managers that are not garbage collectors.
047   * All of our memory managers are collectors so this is empty.
048   */
049  private static final String[] memoryManagerNames = {};
050
051  /**
052   * Maps a space name to its index in the space array.
053   */
054  private static HashMap<String, Integer> pools;
055
056  private static String[] poolNames;
057
058  /**
059   * The level of verbosity that was used in MMTk when verbosity was switched off.
060   * It will be restored when verbosity is switched on again. We can do this
061   * because no other part of the system ever switches the verbosity.
062   */
063  private static int lastMMTkVerbosity;
064
065  /**
066   * Initializes data structures.
067   * This needs to called before the application starts.
068   */
069  public static void fullyBootedVM() {
070    int spaceCount = Space.getSpaceCount();
071    pools = new HashMap<String, Integer>(spaceCount * 2);
072    Space[] spaces = Space.getSpaces();
073    for (int i = 0; i < spaceCount; i++) {
074      pools.put(spaces[i].getName(), i);
075    }
076    poolNames = pools.keySet().toArray(new String[spaceCount]);
077  }
078
079  public static String[] getGarbageCollectorNames() {
080    return garbageCollectorNames;
081  }
082
083  public static String[] getMemoryManagerNames() {
084    return memoryManagerNames;
085  }
086
087  /**
088   * @param poolName the name of the pool
089   * @return the name of the memory manager(s) of the pool (always
090   *  our single garbage collector, i.e. active plan)
091   */
092  public static String[] getMemoryManagerNames(String poolName) {
093    return garbageCollectorNames;
094  }
095
096  public static String[] getPoolNames() {
097    return poolNames;
098  }
099
100  /**
101   * Returns non-heap for immortal spaces and heap for non-immortal
102   * spaces because objects can be added and remove from non-immortal
103   * spaces.
104   *
105   * @param poolName the pool's name
106   * @return the type of the memory pool
107   */
108  public static MemoryType getType(String poolName) {
109    Space space = getSpace(poolName);
110    boolean immortal = space.isImmortal();
111    if (immortal) {
112      return MemoryType.NON_HEAP;
113    } else {
114      return MemoryType.HEAP;
115    }
116  }
117
118  private static Space getSpace(String poolName) {
119    Space[] spaces = Space.getSpaces();
120    int poolIndex = pools.get(poolName);
121    return spaces[poolIndex];
122  }
123
124  /**
125   * @param poolName a memory pool name
126   * @return whether a space with the given name exists
127   */
128  public static boolean isValid(String poolName) {
129    return pools.get(poolName) != null;
130  }
131
132  public static long getReservedBytes(Space space) {
133    int reservedPages = space.reservedPages();
134    return Conversions.pagesToBytes(reservedPages).toLong();
135  }
136
137  public static long getComittedBytes(Space space) {
138    int committedPages = space.committedPages();
139    return Conversions.pagesToBytes(committedPages).toLong();
140  }
141
142  public static long getPoolExtent(Space space) {
143    Extent poolExtent = space.getExtent();
144    return poolExtent.toLong();
145  }
146
147  public static MemoryUsage getUsage(boolean immortal) {
148    long committed = 0, used = 0, max = 0;
149    int spaceCount = Space.getSpaceCount();
150    Space[] spaces = Space.getSpaces();
151    for (int index = 0; index < spaceCount; index++) {
152      Space space = spaces[index];
153      if (space.isImmortal() == immortal) {
154        used += getReservedBytes(space);
155        committed += getComittedBytes(space);
156        max += getPoolExtent(space);
157      }
158    }
159    return new MemoryUsage(-1, used, committed, max);
160  }
161
162  public static MemoryUsage getUsage(String poolName) {
163    Space space = getSpace(poolName);
164    long reservedBytes = JMXSupport.getReservedBytes(space);
165    long committedBytes = JMXSupport.getComittedBytes(space);
166    long poolExtent = JMXSupport.getPoolExtent(space);
167    return new MemoryUsage(-1, reservedBytes, committedBytes, poolExtent);
168  }
169
170  public static int getObjectPendingFinalizationCount() {
171    return FinalizableProcessor.countReadyForFinalize();
172  }
173
174  public static synchronized boolean isMMTkVerbose() {
175    return Options.verbose.getValue() > 0;
176  }
177
178  /**
179   * Sets the verbosity for MMTk. Verbosity in MMTk has several levels
180   * so this method makes an effort to save the previous verbosity level
181   * if possible.
182   *
183   * @param verbose {@code true} if verbosity is to be enabled,
184   *  {@code false} otherwise
185   */
186  public static synchronized void setMMTkVerbose(boolean verbose) {
187    int currentVerbosity = Options.verbose.getValue();
188    if (verbose == false) {
189      if (currentVerbosity > 0) {
190        lastMMTkVerbosity = currentVerbosity;
191        Options.verbose.setValue(0);
192      }
193      // else: nothing to do, MMTk is already non-verbose
194    } else {
195      if (lastMMTkVerbosity > 0) {
196        // Restore old verbosity value, if we have one
197        Options.verbose.setValue(lastMMTkVerbosity);
198      } else {
199        // No old value, so we assume verbosity of 1 because that will get
200        // us printouts of collection times
201        Options.verbose.setValue(1);
202      }
203    }
204  }
205
206  public static long getCollectionCount() {
207    return Stats.gcCount();
208  }
209
210  public static long getCollectionTime() {
211    return Math.round(Plan.totalTime.getTotalMillis());
212  }
213
214}