/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.varia.stats.report; import org.jboss.varia.stats.TxReport; import org.jboss.varia.stats.CacheListener; import java.util.Map; import java.util.Iterator; import java.util.HashMap; /** * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a> * @version <tt>$Revision: 81038 $</tt> */ public class CacheReportGenerator extends ReportGenerator { protected void content(String reportName, StringBuffer content) throws Exception { StringBuffer contentionBuf = new StringBuffer(); contentionBuf.append( "<table><tr><th>Lock Contention Per Table</th><th>Total time</th><th>Max time</th><th>count</th></tr>"); int contentionTotal = 0; int contentionTimeTotal = 0; long maxContentionTime = 0; StringBuffer evictionBuf = new StringBuffer(); evictionBuf.append("<table><tr><th>Eviction per table</th><th>count</th></tr>"); int evictionTotal = 0; StringBuffer hitsBuf = new StringBuffer(); hitsBuf.append("<table><tr><th>Hits per table</th><th>count</th></tr>"); int hitsTotal = 0; StringBuffer missesBuf = new StringBuffer(); missesBuf.append("<table><tr><th>Misses per table</th><th>count</th></tr>"); int missesTotal = 0; StringBuffer reportsTable = new StringBuffer(); reportsTable.append("<table><tr><th>Transaction started by</th><th>Total</th></tr>"); int txTotal = 0; Map contention = new HashMap(); Map eviction = new HashMap(); Map hits = new HashMap(); Map misses = new HashMap(); Iterator reports = getReportsIterator(); while(reports.hasNext()) { TxReport report = (TxReport) reports.next(); Map contentionMap = (Map) report.getStats().get(CacheListener.ContentionStats.NAME); Map evictionMap = (Map) report.getStats().get(CacheListener.EvictionStats.NAME); Map hitsMap = (Map) report.getStats().get(CacheListener.HitStats.NAME); Map missesMap = (Map) report.getStats().get(CacheListener.MissStats.NAME); txTotal += report.getCount(); if(contentionMap == null && evictionMap == null && hitsMap == null && missesMap == null) { continue; } reportsTable.append("<tr><td>"); boolean selected = report.getName().equals(reportName); if(!selected) { reportsTable.append("<a href='HtmlAdaptor?") .append("action=invokeOpByName&name=") .append(getServiceName()) .append("&methodName=generate&") .append("argType=java.lang.String&arg0=") .append(report.getName()) .append("'>"); } reportsTable.append(report.getName()); if(!selected) { reportsTable.append("</a>"); } reportsTable.append("</td><td>") .append(report.getCount()).append("</td></tr>"); if(selected || reportName == null || reportName.trim().length() == 0) { if(contentionMap != null) { for(Iterator items = contentionMap.values().iterator(); items.hasNext();) { CacheListener.ContentionStats item = (CacheListener.ContentionStats) items.next(); Contention c = (Contention) contention.get(item.getValue()); if(c == null) { c = new Contention(item.getValue()); contention.put(c.tableName, c); } c.total += item.getContentionTimeTotal(); c.count += item.getCount(); if(c.maxTime < item.getMaxContentionTime()) { c.maxTime = item.getMaxContentionTime(); } contentionTotal += item.getCount(); contentionTimeTotal += item.getContentionTimeTotal(); if(item.getMaxContentionTime() > maxContentionTime) { maxContentionTime = item.getMaxContentionTime(); } } } if(evictionMap != null) { for(Iterator items = evictionMap.values().iterator(); items.hasNext();) { CacheListener.EvictionStats item = (CacheListener.EvictionStats) items.next(); Eviction e = (Eviction) eviction.get(item.getTableName()); if(e == null) { e = new Eviction(item.getTableName()); eviction.put(e.tableName, e); } e.count += item.getCount(); evictionTotal += item.getCount(); } } if(hitsMap != null) { for(Iterator items = hitsMap.values().iterator(); items.hasNext();) { CacheListener.HitStats item = (CacheListener.HitStats) items.next(); Hit h = (Hit) hits.get(item.getTableName()); if(h == null) { h = new Hit(item.getTableName()); hits.put(h.tableName, h); } h.partitionHit(item.getPartitionIndex(), item.getCount()); hitsTotal += item.getCount(); } } if(missesMap != null) { for(Iterator items = missesMap.values().iterator(); items.hasNext();) { CacheListener.MissStats item = (CacheListener.MissStats) items.next(); Miss m = (Miss) misses.get(item.getValue()); if(m == null) { m = new Miss(item.getValue()); misses.put(m.tableName, m); } m.count += item.getCount(); missesTotal += item.getCount(); } } } } reportsTable.append("<tr><td>"); boolean select = reportName != null && reportName.trim().length() > 0; if(select) { reportsTable.append("<a href='HtmlAdaptor?") .append("action=invokeOpByName&name=") .append(getServiceName()) .append("&methodName=generate&") .append("argType=java.lang.String&arg0=") .append("'>"); } reportsTable.append("all transactions"); if(select) { reportsTable.append("</a>"); } reportsTable.append("</td><td>").append(txTotal).append("</td></tr></table>"); for(Iterator i = contention.values().iterator(); i.hasNext();) { Contention c = (Contention) i.next(); contentionBuf.append("<tr><td>").append(c.tableName).append("</td><td>") .append(c.total).append("</td><td>") .append(c.maxTime).append("</td><td>") .append(c.count).append("</td></tr>"); } for(Iterator i = eviction.values().iterator(); i.hasNext();) { Eviction e = (Eviction) i.next(); evictionBuf.append("<tr><td>").append(e.tableName).append("</td><td>") .append(e.count).append("</td></tr>"); } StringBuffer partitionBuf = new StringBuffer(); partitionBuf.append("<table>"); for(Iterator i = hits.values().iterator(); i.hasNext();) { Hit h = (Hit) i.next(); hitsBuf.append("<tr><td>").append(h.tableName).append("</td><td>") .append(h.count).append("</td></tr>"); if(h.partitions != null && h.partitions.length > 0) { partitionBuf.append("<tr><td>"); partitionBuf.append("<table><tr><th>Table: ").append(h.tableName).append("</th></tr>") .append("<tr><th>Partition index</th><th>count</th><th>%</th></tr>"); for(int pI = 0; pI < h.partitions.length; ++pI) { final int hit = h.partitions[pI]; partitionBuf.append("<tr><td>") .append(pI).append("</td><td>") .append(hit).append("</td><td>") .append((int)(100*((double)hit/h.maxHitPerPartition))).append("</td></tr>"); } partitionBuf.append("</table>"); partitionBuf.append("</td></tr>"); } } partitionBuf.append("</table>"); for(Iterator i = misses.values().iterator(); i.hasNext();) { Miss m = (Miss) i.next(); missesBuf.append("<tr><td>").append(m.tableName).append("</td><td>") .append(m.count).append("</td></tr>"); } contentionBuf.append("<tr><td><font color='red'>total</font></td><td><font color='red'>") .append(contentionTimeTotal).append("</font></td><td><font color='red'>") .append(maxContentionTime).append("</font></td><td><font color='red'>") .append(contentionTotal).append("</font></td></tr>") .append("</table>"); evictionBuf.append("<tr><td><font color='red'>total</font></td><td><font color='red'>") .append(evictionTotal).append("</font></td></tr>") .append("</table>"); hitsBuf.append("<tr><td><font color='red'>total</font></td><td><font color='red'>") .append(hitsTotal).append("</font></td></tr>") .append("</table>"); missesBuf.append("<tr><td><font color='red'>total</font></td><td><font color='red'>") .append(missesTotal).append("</font></td></tr>") .append("</table>"); content.append("<table><tr valign='top'><td>") .append(reportsTable) .append("</td><td>").append(contentionBuf) .append("</td><td>").append(evictionBuf) .append("</td><td>").append(hitsBuf) .append("</td><td>").append(missesBuf) .append("</td></tr></table>"); content.append(partitionBuf); } // Inner class Contention { public final String tableName; public int total; public long maxTime; public int count; public Contention(String tableName) { this.tableName = tableName; } } class Eviction { public final String tableName; public int count; public Eviction(String tableName) { this.tableName = tableName; } } class Hit { public final String tableName; public int count; private int[] partitions; private int maxHitPerPartition; public Hit(String tableName) { this.tableName = tableName; } public void partitionHit(int partitionIndex, int count) { if(partitions == null) { partitions = new int[partitionIndex + 1]; } else if(partitions.length < partitionIndex + 1) { int[] tmp = partitions; partitions = new int[partitionIndex + 1]; System.arraycopy(tmp, 0, partitions, 0, tmp.length); } partitions[partitionIndex] += count; this.count += count; if(maxHitPerPartition < partitions[partitionIndex]) { maxHitPerPartition = partitions[partitionIndex]; } } } class Miss { public final String tableName; public int count; public Miss(String tableName) { this.tableName = tableName; } } }