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.scheduler; 014 015import java.util.HashMap; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.runtime.StackTrace; 019import org.jikesrvm.runtime.StackTrace.Element; 020import org.vmmagic.pragma.Uninterruptible; 021 022public class JMXSupport { 023 024 private static HashMap<Long, Thread> threadIdToThread; 025 026 private static final org.jikesrvm.mm.mmtk.Lock peakThreadCountLock = 027 new org.jikesrvm.mm.mmtk.Lock("peakThreadCount"); 028 029 private static int peakThreadCount; 030 031 private static final org.jikesrvm.mm.mmtk.Lock startedThreadCountLock = 032 new org.jikesrvm.mm.mmtk.Lock("startedThreadCount"); 033 034 private static long startedThreadCount; 035 036 /** 037 * Updates the current peak thread count. 038 * <p> 039 * Note: this must be uninterruptible because it's called from the 040 * {@link RVMThread#start()} and that method must not have yieldpoints. 041 * 042 * @param liveThreadCount the current count of live threads 043 * @param numActiveSystemThreads the current count of live system threads 044 */ 045 @Uninterruptible 046 static void updatePeakThreadCount(int liveThreadCount, int numActiveSystemThreads) { 047 int currentThreadCount = liveThreadCount - numActiveSystemThreads; 048 peakThreadCountLock.acquire(); 049 if (currentThreadCount > peakThreadCount) { 050 peakThreadCount = currentThreadCount; 051 } 052 peakThreadCountLock.release(); 053 } 054 055 public static int getPeakThreadCount() { 056 int currentCount = 0; 057 peakThreadCountLock.acquire(); 058 currentCount = peakThreadCount; 059 peakThreadCountLock.release(); 060 return currentCount; 061 } 062 063 public static void resetPeakThreadCount() { 064 peakThreadCountLock.acquire(); 065 peakThreadCount = getLiveThreadCount(); 066 peakThreadCountLock.release(); 067 } 068 069 /** 070 * Increases the number of started threads 071 * <p> 072 * Note: this must be uninterruptible because it's called from the 073 * {@link RVMThread#start()} and that method must not have yieldpoints. 074 */ 075 @Uninterruptible 076 static void increaseStartedThreadCount() { 077 startedThreadCountLock.acquire(); 078 startedThreadCount++; 079 startedThreadCountLock.release(); 080 } 081 082 public static long getStartedThreadCount() { 083 long startedThreadCountTemp = 0; 084 startedThreadCountLock.acquire(); 085 startedThreadCountTemp = startedThreadCount; 086 startedThreadCountLock.release(); 087 return startedThreadCountTemp; 088 } 089 090 091 public static int getLiveThreadCount() { 092 return RVMThread.getNumActiveThreads() - RVMThread.getNumActiveSystemThreads(); 093 } 094 095 public static int getLiveDaemonCount() { 096 return RVMThread.getNumActiveDaemons(); 097 } 098 099 /** 100 * @return thread ids (those of java.lang.Thread and not of our internal 101 * threads!) 102 */ 103 public static synchronized long[] getAllLiveThreadIds() { 104 Thread[] liveThreads = RVMThread.getLiveThreadsForJMX(); 105 int liveThreadCount = liveThreads.length; 106 107 int mapSizeEstimate = (int) (liveThreadCount * 1.5); 108 threadIdToThread = new HashMap<Long, Thread>(mapSizeEstimate); 109 110 long[] ids = new long[liveThreadCount]; 111 for (int i = 0; i < liveThreadCount; i++) { 112 Thread liveThread = liveThreads[i]; 113 if (liveThread == null) { 114 // Once a null thread was found, all following threads must also be null 115 if (VM.VerifyAssertions) { 116 for (int j = i + 1; j < liveThreadCount; j++) { 117 liveThread = liveThreads[j]; 118 VM._assert(liveThread == null); 119 } 120 } 121 break; 122 } 123 long threadId = liveThread.getId(); 124 ids[i] = threadId; 125 threadIdToThread.put(Long.valueOf(threadId), liveThread); 126 } 127 return ids; 128 } 129 130 public static synchronized Thread getThreadForId(long id) { 131 getAllLiveThreadIds(); 132 Thread thread = threadIdToThread.get(id); 133 if (thread == null) 134 throw new IllegalArgumentException("Invalid id: " + id); 135 return thread; 136 } 137 138 139 /** 140 * Checks whether the thread is in native according to JMX. 141 * @param t a thread 142 * @return whether the thread is executing JNI code 143 */ 144 public static boolean isInNative(RVMThread t) { 145 t.monitor().lockNoHandshake(); 146 boolean inNative = t.isInNativeAccordingToJMX(); 147 t.monitor().unlock(); 148 return inNative; 149 } 150 151 /** 152 * Checks whether the thread is currently suspended 153 * according to JMX. 154 * @param t a thread 155 * @return whether {@code Thread.suspend()} was called on the 156 * thread 157 */ 158 public static boolean isSuspended(RVMThread t) { 159 t.monitor().lockNoHandshake(); 160 boolean isSuspended = t.blockedFor(RVMThread.suspendBlockAdapter); 161 t.monitor().unlock(); 162 return isSuspended; 163 } 164 165 public static long getWaitingCount(RVMThread rvmThread) { 166 return rvmThread.getTotalWaitingCount(); 167 } 168 169 public static long getWaitingTime(RVMThread rvmThread) { 170 return rvmThread.getTotalWaitedTime(); 171 } 172 173 public static StackTraceElement[] getStackTraceForThread(RVMThread rvmThread) { 174 RVMThread currentThread = RVMThread.getCurrentThread(); 175 176 Element[] elements = null; 177 if (rvmThread == currentThread) { 178 StackTrace st = new StackTrace(); 179 // Skip 1 frame (the frame of this call) 180 elements = st.stackTraceNoException(1); 181 } else { 182 // Wait until other thread is blocked 183 while (true) { 184 rvmThread.safeBlock(RVMThread.stackTraceBlockAdapter); 185 rvmThread.monitor().lockNoHandshake(); 186 if (rvmThread.blockedFor(RVMThread.stackTraceBlockAdapter)) { 187 rvmThread.monitor().unlock(); 188 break; 189 } 190 rvmThread.monitor().unlock(); 191 } 192 StackTrace st = new StackTrace(rvmThread); 193 // Skip 2 frames: the frames for yieldpointFrom* and yieldpoint 194 // TODO this assumes that the thread is blocked in Java (and not in JNI) 195 elements = st.stackTraceNoException(2); 196 rvmThread.unblock(RVMThread.stackTraceBlockAdapter); 197 } 198 199 return JikesRVMStackTraceSupport.convertToJavaClassLibraryStackTrace(elements); 200 } 201 202}