/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package scouter.client.stack.base;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import scouter.client.Activator;
import scouter.client.Images;
import scouter.client.stack.data.StackFileInfo;
import scouter.client.stack.data.StackParser;
import scouter.client.stack.utils.NumberUtils;
import scouter.client.stack.utils.StringUtils;
public class PerformanceWindow implements Listener{
private Shell m_parentShell = null;
private Shell m_shell = null;
private Tree m_performanceTree = null;
private StackFileInfo m_stackFileInfo = null;
private String m_filter = null;
private boolean m_isExcludeStack = true;
private boolean m_isAscending = true;
private boolean m_isRemoveLine = true;
private boolean m_isInerPercent = false;
private int m_totalCount = 0;
private ArrayList<String> m_excludeStack = null;
private ArrayList<String> m_singleStack = null;
private int m_singleStackCount = 0;
private int m_expandStartInx = 0;
public PerformanceWindow(Shell shell, StackFileInfo stackFileInfo, String filter, boolean isExcludeStack, boolean isAscending, boolean isRemoveLine, boolean isInerPercent) {
m_parentShell = shell;
m_stackFileInfo = stackFileInfo;
m_filter = filter;
m_isExcludeStack = isExcludeStack;
m_isAscending = isAscending;
m_isRemoveLine = isRemoveLine;
m_isInerPercent = isInerPercent;
ArrayList<String> list = stackFileInfo.getParserConfig().getExcludeStack();
if ( m_isExcludeStack && list != null && list.size() > 0 ) {
m_excludeStack = list;
}
list = stackFileInfo.getParserConfig().getSingleStack();
if ( list != null && list.size() > 0 ) {
m_singleStack = list;
m_singleStackCount = list.size();
}
StringBuilder buffer = new StringBuilder(200);
buffer.append('[');
if ( filter == null )
buffer.append("All");
else
buffer.append(filter);
buffer.append("] ").append(stackFileInfo.getFilename());
buffer.append(" [EXC:").append(isExcludeStack).append("] [ASC:");
buffer.append(isAscending).append(']');
init(shell, buffer.toString());
}
private void init(Shell shell, String title) {
m_shell = new Shell(shell, SWT.MIN | SWT.MAX | SWT.CLOSE | SWT.TITLE | SWT.RESIZE);
m_shell.setText(title);
m_shell.setImage(Images.tree_mode);
m_shell.setLayout(new FillLayout());
m_performanceTree = new Tree(m_shell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
m_performanceTree.setBackgroundImage(Activator.getImage("icons/grid.jpg"));
constructTree();
createTreePopupMenu();
m_shell.open();
}
private void constructTree() {
String filename = StackParser.getWorkingThreadFilename(m_stackFileInfo.getFilename());
if ( filename == null )
return;
HashMap<String, Counter> tree = new HashMap<String, Counter>();
BufferedReader reader = null;
int startStackLine = m_stackFileInfo.getUsedParser().getConfig().getStackStartLine();
try {
File file = new File(filename);
reader = new BufferedReader(new FileReader(file));
String line = null;
int lineCount = 0;
boolean isFiltered = false;
int filterIndex = 0;
ArrayList<String> list = new ArrayList<String>(300);
while ( (line = reader.readLine()) != null ) {
if ( line.length() == 0 ) {
if ( isFiltered && list.size() > 0 ) {
createPerformanceTree(tree, list, filterIndex);
}
list = new ArrayList<String>(300);
lineCount = 0;
isFiltered = false;
} else {
lineCount++;
if ( lineCount > startStackLine ) {
if ( !isFiltered ) {
if ( m_filter == null ) {
isFiltered = true;
} else if ( line.indexOf(m_filter) >= 0 ) {
isFiltered = true;
filterIndex = lineCount - (startStackLine + 1);
}
}
list.add(line);
}
}
}
if ( isFiltered && list.size() > 0 ) {
createPerformanceTree(tree, list, filterIndex);
}
} catch ( Exception ex ) {
throw new RuntimeException(ex);
} finally {
if ( reader != null ) {
try {
reader.close();
} catch ( Exception e ) {
}
}
}
if ( m_isInerPercent && tree != null ) {
Counter cntr;
Iterator<Counter> itor = tree.values().iterator();
while ( itor.hasNext() ) {
cntr = itor.next();
cntr.caculInerCount();
}
}
TreeItem treeItem = new TreeItem(m_performanceTree, SWT.NONE);
treeItem.setText("Stack File Nodes");
treeItem.setData(null);
treeItem.setExpanded(true);
makePerformanceTreeUI(treeItem, tree, 0);
}
private void makePerformanceTreeUI( TreeItem parent, HashMap<String, Counter> tree, int depth ) {
if ( tree == null || tree.size() == 0 )
return;
depth++;
String key = null;
Counter counter = null;
StringBuilder buffer = null;
int index = 0;
Iterator<String> itor = tree.keySet().iterator();
ArrayList<Counter> sortList = new ArrayList<Counter>();
while ( itor.hasNext() ) {
key = itor.next();
counter = tree.get(key);
counter.setValue(key);
sortList.add(counter);
}
Collections.sort(sortList, new ValueComp());
int itemCount = sortList.size();
if(itemCount > 1 && m_expandStartInx == 0){
m_expandStartInx = depth;
}
TreeItem treeItem;
for ( index = 0; index < itemCount; index++ ) {
counter = sortList.get(index);
buffer = new StringBuilder(100);
buffer.append(counter.getCount()).append(" (").append(NumberUtils.intToPercent((counter.getCount() * 10000) / m_totalCount)).append("%) ");
if ( m_isInerPercent ) {
buffer.append(NumberUtils.intToPercent((counter.getInerCount() * 10000) / m_totalCount)).append("% ");
}
buffer.append(counter.getValue());
treeItem = new TreeItem(parent, SWT.NONE );
treeItem.setText(buffer.toString());
treeItem.setData(counter.getValue());
treeItem.setExpanded(true);
if(m_expandStartInx == 0){
m_performanceTree.showItem(treeItem);
}else if((depth - m_expandStartInx) <= 3){
m_performanceTree.showItem(treeItem);
}
if ( counter.getMap() != null ) {
makePerformanceTreeUI(treeItem, counter.getMap(), depth);
}
}
}
private void createPerformanceTree( HashMap<String, Counter> tree, ArrayList<String> list, int filterIndex ) {
int startIndex = 0;
int size = list.size() - 1;
if ( m_filter != null ) {
startIndex = filterIndex;
} else {
startIndex = list.size() - 1;
}
m_totalCount++;
String line = null;
HashMap<String, Counter> currentMap = tree;
Counter currentCounter = null;
int index;
int baseIndex = startIndex;
while ( true ) {
line = list.get(startIndex);
if ( m_singleStackCount > 0 ) {
for ( index = 0; index < m_singleStackCount; index++ ) {
if ( line.indexOf(m_singleStack.get(index)) >= 0 ) {
line = m_singleStack.get(index);
break;
}
}
}
if ( m_excludeStack != null && currentMap != null && currentMap != tree ) {
if ( StringUtils.checkExist(line, m_excludeStack) ) {
if ( m_isAscending ) {
if ( startIndex == 0 )
break;
startIndex--;
} else {
if ( startIndex == size )
break;
startIndex++;
}
continue;
}
}
if ( m_filter != null && baseIndex == startIndex )
line = StringUtils.makeSimpleLine(line, false);
else
line = StringUtils.makeSimpleLine(line, m_isRemoveLine);
if ( currentCounter != null ) {
currentMap = currentCounter.getMap();
if ( currentMap == null )
currentMap = currentCounter.addMap();
}
currentCounter = currentMap.get(line);
if ( currentCounter == null ) {
currentCounter = new Counter();
currentMap.put(line, currentCounter);
}
currentCounter.addCount();
if ( m_isAscending ) {
if ( startIndex == 0 )
break;
startIndex--;
} else {
if ( startIndex == size )
break;
startIndex++;
}
}
}
private class Counter {
private int m_count = 0;
private int m_inerCount = 0;
private String m_value = null;
private HashMap<String, Counter> m_map = null;
public void addCount() {
m_count++;
}
public int getCount() {
return m_count;
}
public int getInerCount() {
return m_inerCount;
}
public void setValue( String value ) {
m_value = value;
}
public String getValue() {
return m_value;
}
public HashMap<String, Counter> addMap() {
if ( m_map == null ) {
m_map = new HashMap<String, Counter>();
}
return m_map;
}
public HashMap<String, Counter> getMap() {
return m_map;
}
public void caculInerCount() {
if ( m_map == null ) {
m_inerCount = m_count;
return;
}
int subCount = 0;
Iterator<Counter> itor = m_map.values().iterator();
Counter cntr;
while ( itor.hasNext() ) {
cntr = itor.next();
subCount += cntr.getCount();
cntr.caculInerCount();
}
m_inerCount = m_count - subCount;
}
}
private class ValueComp implements Comparator<Counter> {
public int compare( Counter o1, Counter o2 ) {
if ( o1.getCount() > o2.getCount() )
return -1;
else if ( o1.getCount() < o2.getCount() )
return 1;
return 0;
}
}
private void createTreePopupMenu() {
Menu popupMenu = new Menu(m_performanceTree);
MenuItem menuItem = new MenuItem(popupMenu, SWT.NONE);
menuItem.setText("Performance tree(Ascending)");
menuItem.addListener(SWT.Selection, this);
menuItem = new MenuItem(popupMenu, SWT.NONE);
menuItem.setText("Performance tree(Descending)");
menuItem.addListener(SWT.Selection, this);
menuItem = new MenuItem(popupMenu, SWT.SEPARATOR);
menuItem = new MenuItem(popupMenu, SWT.NONE);
menuItem.setText("Copy function");
menuItem.addListener(SWT.Selection, this);
m_performanceTree.setMenu(popupMenu);
}
public void handleEvent(Event event) {
try {
MenuItem item = (MenuItem)event.widget;
String menuText = item.getText();
if("Performance tree(Ascending)".endsWith(menuText)){
createAnalyzedPerformance(true);
}else if("Performance tree(Descending)".endsWith(menuText)){
createAnalyzedPerformance(false);
}else if("Copy function".endsWith(menuText)){
CopyFunctionName();
}
}catch(Exception ex){
ex.printStackTrace();
}
}
private void createAnalyzedPerformance( boolean isAscending ) {
String filter = getSelectedFunctionName();
if ( filter != null && m_stackFileInfo != null ){
new PerformanceWindow(m_parentShell, m_stackFileInfo, filter, m_isExcludeStack, isAscending, m_isRemoveLine, m_isInerPercent);
}
}
private void CopyFunctionName() {
String functionName = getSelectedFunctionName();
if ( functionName != null )
StringUtils.setClipboard(functionName.trim());
}
private String getSelectedFunctionName() {
TreeItem [] items = m_performanceTree.getSelection();
if(items == null || items.length == 0){
return null;
}
String function = (String)items[0].getData();
int endIndex = function.indexOf((int)'(');
if ( endIndex >= 0 )
function = function.substring(0, endIndex);
return function;
}
}