/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.admin.sysinfo.manager; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.olat.admin.sysinfo.model.ThreadView; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.WorkThreadInformations; import org.olat.restapi.system.Sampler; import org.springframework.stereotype.Service; /** * * <h3>Description:</h3> * * Initial Date: 21 juin 2010 <br> * @author srosse, stephane.rosse@frentix.com, www.frentix.com */ @Service public class ThreadInfosManager implements Sampler { private static final OLog log = Tracing.createLoggerFor(ThreadInfosManager.class); private final static NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.ENGLISH); private long prevUpTime; private Map<Long,ThreadView> threadMap = new ConcurrentHashMap<Long,ThreadView>(); public List<ThreadView> getThreadViews() { if(threadMap.isEmpty()) { takeSample(); } List<ThreadView> threads = new ArrayList<ThreadView>(threadMap.values()); Collections.sort(threads); return threads; } @Override public synchronized void takeSample() { updateTimeSeries(); } private void updateTimeSeries() { ThreadMXBean threadProxy = ManagementFactory.getThreadMXBean(); RuntimeMXBean runtimeProxy = ManagementFactory.getRuntimeMXBean(); ThreadInfo tis[] = threadProxy.dumpAllThreads(false, false); List<String> currentThreadNames = new ArrayList<String>(); Set<Long> currentThreadIds = new HashSet<Long>(); for (ThreadInfo ti : tis) { Long threadId = new Long(ti.getThreadId()); if (threadMap.containsKey(threadId)) { ThreadView threadVO = threadMap.get(threadId); threadVO.setState(ti.getThreadState()); } else { ThreadView threadVO = new ThreadView(); threadVO.setId(threadId); threadVO.setName(ti.getThreadName()); threadVO.setState(ti.getThreadState()); threadMap.put(threadId, threadVO); } currentThreadIds.add(threadId); } WorkThreadInformations.currentThreadNames(currentThreadNames); for (ThreadView threadVO:threadMap.values()) { threadVO.setPrevCpuTime(Math.max(0, threadVO.getCpuTime())); threadVO.setCpuTime(Math.max(0, threadProxy.getThreadCpuTime(threadVO.getId()))); } long upTime = runtimeProxy.getUptime(); if (prevUpTime > 0L && upTime > prevUpTime) { // elapsedTime is in ms long elapsedTime = upTime - prevUpTime; for (ThreadView threadVO:threadMap.values()) { // elapsedCpu is in ns long elapsedCpu = threadVO.getCpuTime() - threadVO.getPrevCpuTime(); // cpuUsage could go higher than 100% because elapsedTime // and elapsedCpu are not fetched simultaneously. Limit to // 99% to avoid Chart showing a scale from 0% to 200%. float cpuUsage = Math.min(99f, elapsedCpu / (elapsedTime * 1000000F)); threadVO.setCpuUsage(cpuUsage); threadVO.setCpuUsagePercent(percentFormat.format(cpuUsage)); if(cpuUsage > 0.8) { threadVO.setWarningCounter(threadVO.getWarningCounter() + 1); if(threadVO.getWarningCounter() >= 2) { String currentWork = WorkThreadInformations.get(threadVO.getName()); if(currentWork == null) { currentWork = "unkown"; } log.info("High usage on thread:" + threadVO + " because thread work at: " + currentWork); } } else { threadVO.setWarningCounter(0); } } } prevUpTime = upTime; //clean-up closed threads for (Iterator<Map.Entry<Long,ThreadView>> it=threadMap.entrySet().iterator(); it.hasNext(); ) { Map.Entry<Long,ThreadView> entry = it.next(); if(!currentThreadIds.contains(entry.getKey())) { it.remove(); } } } }