/******************************************************************************* * 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(); } }