/*******************************************************************************
* Copyright (c) 2009-2015 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
* * Paul Klint - Paul.Klint@cwi.nl - CWI
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.interpreter.utils;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;
import org.rascalmpl.ast.AbstractAST;
import org.rascalmpl.interpreter.Evaluator;
import org.rascalmpl.interpreter.env.Environment;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IListWriter;
import org.rascalmpl.value.ISourceLocation;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.values.ValueFactoryFactory;
class Count {
int ticks;
Count(){
ticks = 1;
}
public void increment(){
ticks += 1;
}
public int getTicks(){
return ticks;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ticks;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Count other = (Count) obj;
if (ticks != other.ticks) {
return false;
}
return true;
}
}
public class Profiler extends Thread {
private Evaluator eval;
private volatile boolean running;
private long resolution = 1;
private final Map<ISourceLocation,Count> ast;
private final Map<ISourceLocation, Count> frame;
private final Map<ISourceLocation, String> names;
public Profiler(Evaluator ev){
super("Rascal-Sampling-Profiler");
this.eval = ev;
this.ast = new HashMap<>();
this.frame = new HashMap<>();
this.names = new HashMap<>();
running = true;
}
@Override
public void run(){
while(running) {
AbstractAST current = eval.getCurrentAST();
Environment env = eval.getCurrentEnvt();
String name = env.getName();
if (current != null) {
ISourceLocation stat = current.getLocation();
if(stat != null){
Count currentCount = ast.get(stat);
if (currentCount == null) {
ast.put(stat, new Count());
names.put(stat, name);
} else {
currentCount.increment();
}
}
while (env.getParent() != null && !env.getParent().isRootScope()) {
env = env.getParent();
}
if (env != null) {
Count currentCount = frame.get(env.getLocation());
if (currentCount == null) {
frame.put(env.getLocation(), new Count());
names.put(env.getLocation(), env.getName());
}
else {
currentCount.increment();
}
}
}
try {
sleep(resolution);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void pleaseStop(){
running = false;
}
/* Extract a list of entries from the collected data and
* sort it with descending tick values.
*/
private List<Map.Entry<ISourceLocation, Count>> sortData(Map<ISourceLocation,Count> data) {
List<Map.Entry<ISourceLocation, Count>> sortedData = new Vector<Entry<ISourceLocation, Count>>(data.entrySet());
java.util.Collections.sort(sortedData, new Comparator<Map.Entry<ISourceLocation, Count>>(){
public int compare(Entry<ISourceLocation, Count> entry1, Entry<ISourceLocation, Count> entry2) {
return ((entry1.getValue().getTicks() == entry2.getValue().getTicks()) ? 0 :
(entry1.getValue().getTicks() < entry2.getValue().getTicks() ? 1 : -1));
}
});
return sortedData;
}
public IList getProfileData(){
IValueFactory VF = ValueFactoryFactory.getValueFactory();
IListWriter w = VF.listWriter();
for(Map.Entry<ISourceLocation, Count> e : sortData(ast)){
w.insert(VF.tuple(e.getKey(), VF.integer(e.getValue().getTicks())));
}
return w.done();
}
public void report() {
report("FRAMES", frame);
eval.getStdOut().println();
report("ASTS", ast);
}
private void report(String title, Map<ISourceLocation, Count> data) {
List<Map.Entry<ISourceLocation, Count>> sortedData = sortData(data);
int maxName = 1;
long nTicks = 0;
for(Map.Entry<ISourceLocation, Count> e : sortedData){
int sz = names.get(e.getKey()).length();
if(sz > maxName) {
maxName = sz;
}
nTicks += e.getValue().getTicks();
}
PrintWriter out = eval.getStdOut();
String nameFormat = "%" + maxName + "s";
out.printf(title + " PROFILE: %d data points, %d ticks, tick = %d milliSecs\n", ast.size(), nTicks, resolution);
out.printf(nameFormat + "%8s%9s %s\n", " Scope", "Ticks", "%", "Source");
for (Map.Entry<ISourceLocation, Count> e : sortedData) {
String L = e.getKey().toString();
String name = names.get(e.getKey());
int ticks = e.getValue().getTicks();
double perc = (ticks * 100.0)/nTicks;
if (perc < 1.0) {
break;
}
String source = String.format("%s", L);
out.printf(nameFormat + "%8d%8.1f%% %s\n", name, ticks, perc, source);
}
// Make sure that our output is seen:
out.flush();
}
}