template.trace.Tracer.tt Maven / Gradle / Ivy
Show all versions of jastadd Show documentation
# Copyright (c) 2013-2015, The JastAdd Team
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Lund University nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Code for the class ASTNodeState.Trace.
TraceClass [[
$if(TracingEnabled)
public static class Trace {
/**
* Trace filter interface used to filter the list of collected trace class.
*/
public interface Filter {
public boolean include($StateClass.Trace.Entry e);
public String desc();
}
/**
* Interface used to process collected trace objects.
*
* Use it together with the method $StateClass.Trace.process($StateClass.Trace.Processor).
*/
public interface Processor {
public void process($StateClass.Trace.Entry e);
}
/** Prints trace events to an output stream. */
public static class PrintProcessor implements Processor {
private final java.io.PrintStream out;
public PrintProcessor(java.io.PrintStream outStream) {
this.out = outStream;
}
@Override
public void process($StateClass.Trace.Entry e) {
out.println(e);
}
};
/**
* Trace entries collected during attribute evaluation.
*/
public static class Entry {
public final $StateClass.Trace.Event event;
public final String node;
public final String nodeType;
public final String attr;
public final String params;
public final String value;
public final long timeStamp;
public Entry($StateClass.Trace.Event e, String n, String t, String a, String p, String v) {
event = e; node = n; nodeType = t; attr = a; params = p; value = v;
timeStamp = System.nanoTime();
}
public String toString() {
return "[trace: " + event + ", " + attr + "[" + params + "]=" + value + " - " + node + "]";
}
}
/**
* Trace events corresponding to where trace entries where collected.
*
* These events can be filtered statically using the flag --tracing to
* JastAdd2. For example, the flag --tracing=compute,cache will only trace
* compute events and cache events. The flag --tracing will enable all events.
*
* These events can also be filtered dynamically by extending the InputFilter
* class and then register this subclass using the method
* registerInputFilter($StateClass.Trace.InputFilter).
*/
public enum Event {
// Flag --tracing=compute
COMPUTE_BEGIN,
COMPUTE_END,
// Flag --tracing=cache
CACHED,
CACHE_ABORT,
CACHE_READ,
// Flag --tracing=rewrite
REWRITE_CASE1_START,
REWRITE_CASE1_CHANGE,
REWRITE_CASE1_RETURN,
REWRITE_CASE2_RETURN,
REWRITE_CASE3_RETURN,
// Flag --tracing=circular
CIRCULAR_NTA_CASE1_START,
CIRCULAR_NTA_CASE1_CHANGE,
CIRCULAR_NTA_CASE1_RETURN,
CIRCULAR_NTA_CASE2_START,
CIRCULAR_NTA_CASE2_CHANGE,
CIRCULAR_NTA_CASE2_RETURN,
CIRCULAR_NTA_CASE3_RETURN,
CIRCULAR_CASE1_START,
CIRCULAR_CASE1_CHANGE,
CIRCULAR_CASE1_RETURN,
CIRCULAR_CASE2_START,
CIRCULAR_CASE2_CHANGE,
CIRCULAR_CASE2_RETURN,
CIRCULAR_CASE3_RETURN,
// Flag --tracing=copy
COPY_NODE,
// Flag --tracing=flush
FLUSH_ATTR,
FLUSH_REWRITE,
FLUSH_REWRITE_INIT
}
/**
* Class used to filter input
*/
public static abstract class InputFilter implements Filter {
public Entry createEntry($StateClass.Trace.Event evt, $ASTNode node, String attr, Object params, Object value) {
String paramsString;
if (params instanceof $ASTNode) {
paramsString = String.format("%08X", params.hashCode());
} else {
paramsString = String.valueOf(params);
}
String valueString;
if (value instanceof $ASTNode) {
valueString = String.format("%08X", value.hashCode());
} else {
valueString = String.valueOf(value);
}
return new Entry(evt,
String.format("%08X", node.hashCode()),
node.getClass().getName(),
attr, paramsString, valueString);
}
public String desc() {
return "Custom input filter";
}
}
// Default input filter accepting all events
private final InputFilter defaultInputFilter = new InputFilter() {
public boolean include(Entry e) {
return true;
}
public String desc() {
return "Default input filter accepting all events";
}
};
$if(CacheAnalyzeEnabled)
private final CacheAnalyzer cacheAnalyzer = new CacheAnalyzer();
public CacheAnalyzer cacheAnalyzer() {
return cacheAnalyzer;
}
private Trace.InputFilter inputFilter = cacheAnalyzer;
$else
private Trace.InputFilter inputFilter = defaultInputFilter;
$endif
/**
* Registers an input filter to use during tracing.
* @param filter The input filter to register.
*/
public void registerInputFilter($StateClass.Trace.InputFilter filter) {
if (filter != null) {
inputFilter = filter;
}
}
/**
* Resets the input filter to the default input filter accepting all events.
*/
public void unregisterInputFilter() {
inputFilter = defaultInputFilter;
}
private java.util.List<$StateClass.Trace.Entry> list = new java.util.ArrayList<$StateClass.Trace.Entry>();
/**
* Add a trace event for an attribute instance.
* @param node The host node.
* @param attr The attribute name.
* @param params The parameter list.
* @param value The current value of the attribute instance.
*/
private void add($StateClass.Trace.Event evt, $ASTNode node, String attr, Object params, Object value) {
$StateClass.Trace.Entry e = inputFilter.createEntry(evt, node, attr, params, value);
if (inputFilter.include(e)) {
list.add(e);
}
}
public void clear() {
list.clear();
}
/**
* Trace that an attribute instance started its computation.
* @param value The value of the attribute instance.
*/
public void computeBegin($ASTNode node, String attr, Object params, Object value) {
add(Event.COMPUTE_BEGIN, node, attr, params, value);
}
/**
* Trace that an attribute instance ended its computation.
* @param value The value of the attribute instance.
*/
public void computeEnd($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.COMPUTE_END, node, attr, params, value);
}
/**
* Trace that the cache of an attribute instances was read.
* @param value The value of the attribute instance.
*/
public void cacheRead($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CACHE_READ, node, attr, params, value);
}
/**
* Trace that an attribute instance was cached.
* @param value The value of the attribute instance.
*/
public void cacheWrite($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CACHED, node, attr, params, value);
}
/**
* Trace that the caching of an attribute instance was aborted.
* @param value The value of the attribute instance.
*/
public void cacheAbort($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CACHE_ABORT, node, attr, params, value);
}
/**
* Trace that a rewrite evaluation entered case 1.
* @param value The value of the rewrite.
*/
public void enterRewriteCase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.REWRITE_CASE1_START, node, attr, params, value);
}
/**
* Trace that a rewrite in evaluation case 1 changed value.
* @param value The value of the rewrite before and after.
*/
public void rewriteChange($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.REWRITE_CASE1_CHANGE, node, attr, params, value);
}
/**
* Trace that a rewrite returned from evaluation case 1.
* @param value The value of the rewrite.
*/
public void exitRewriteCase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.REWRITE_CASE1_RETURN, node, attr, params, value);
}
/**
* Trace that a rewrite returned from evaluation case 2.
* @param value The value of the rewrite.
*/
public void exitRewriteCase2($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.REWRITE_CASE2_RETURN, node, attr, params, value);
}
/**
* Trace that a rewrite returned from evaluation case 3.
* @param value The value of the rewrite.
*/
public void exitRewriteCase3($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.REWRITE_CASE3_RETURN, node, attr, params, value);
}
/**
* Trace that a circular attribute instance entered evaluation case 1.
* @param value The value of the circular attribute instance.
*/
public void enterCircularCase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE1_START, node, attr, params, value);
}
/**
* Trace that a circular attribute instance in evaluation case 1 changed value.
* @param value The value of the circular attribute instance, before and after.
*/
public void circularCase1Change($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE1_CHANGE, node, attr, params, value);
}
/**
* Trace that a circular attribute instance returned from evaluation case 1.
* @param value The value of the circular attribute instance.
*/
public void exitCircularCase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE1_RETURN, node, attr, params, value);
}
/**
* Trace that a circular attribute instance entered evaluation case 2.
* @param value The value of the circular attribute instance.
*/
public void enterCircularCase2($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE2_START, node, attr, params, value);
}
/**
* Trace that a circular attribute instance in evaluation case 2 changed value.
* @param value The value of the circular attribute instance, before and after.
*/
public void circularCase2Change($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE2_CHANGE, node, attr, params, value);
}
/**
* Trace that a circular attribute instance returned from evaluation case 2.
* @param value The value of the circular attribute instance.
*/
public void exitCircularCase2($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE2_RETURN, node, attr, params, value);
}
/**
* Trace that a circular attribute instance returned from evaluation case 2.
* @param value The value of the circular attribute instance.
*/
public void exitCircularCase3($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_CASE3_RETURN, node, attr, params, value);
}
/**
* Trace that a circular NTA entered evaluation case 1.
* @param value The value of the circular NTA.
*/
public void enterCircularNTACase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE1_START, node, attr, params, value);
}
/**
* Trace that a circular NTA in evaluation case 1 changed value.
* @param value The value of the circular NTA, before and after.
*/
public void circularNTACase1Change($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE1_CHANGE, node, attr, params, value);
}
/**
* Trace that a circular NTA returned from evaluation case 1.
* @param value The value of the circular NTA.
*/
public void exitCircularNTACase1($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE1_RETURN, node, attr, params, value);
}
/**
* Trace that a circular NTA entered evaluation case 2.
* @param value The value of the circular NTA.
*/
public void enterCircularNTACase2($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE2_START, node, attr, params, value);
}
/**
* Trace that a circular NTA in evaluation case 2 changed value.
* @param value The value of the circular NTA, before and after.
*/
public void circularNTACase2Change($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE2_CHANGE, node, attr, params, value);
}
/**
* Trace that a circular NTA returned from evaluation case 2.
* @param value The value of the circular NTA.
*/
public void exitCircularNTACase2($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE2_RETURN, node, attr, params, value);
}
/**
* Trace that a circular NTA returned from evaluation case 2.
* @param value The value of the circular NTA.
*/
public void exitCircularNTACase3($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.CIRCULAR_NTA_CASE3_RETURN, node, attr, params, value);
}
/**
* Trace that an AST node was copied.
* @param node The copied node.
* @param value The value of the node.
*/
public void copyNode($ASTNode node, Object value) {
add($StateClass.Trace.Event.COPY_NODE, node, "ASTNode.copy", "", value);
}
/**
* Trace that an attribute was flushed.
* @param value The value of the attribute.
*/
public void flushAttr($ASTNode node, String attr, Object params, Object value) {
add($StateClass.Trace.Event.FLUSH_ATTR, node, attr, params, value);
}
/**
* Process all trace entries given a trace processor
*/
public void process($StateClass.Trace.Processor processor) {
for ($StateClass.Trace.Entry e: list) {
processor.process(e);
}
}
/**
* Print report from collected trace using the given filter.
* @param out Print writer to use.
* @param filter The filter to use.
*/
public void printReport(java.io.PrintWriter out, $StateClass.Trace.Filter filter) {
// Construct report model: attr->param->node:count
java.util.Map>> attrMap =
new java.util.HashMap>>();
for ($StateClass.Trace.Entry e : list) {
if (filter.include(e)) {
if (!attrMap.containsKey(e.attr)) {
attrMap.put(e.attr, new java.util.HashMap>());
}
java.util.Map> paramMap = attrMap.get(e.attr);
if (!paramMap.containsKey(e.params)) {
paramMap.put(e.params, new java.util.HashMap());
}
java.util.Map nodeMap = paramMap.get(e.params);
if (!nodeMap.containsKey(e.node)) {
nodeMap.put(e.node, Integer.valueOf(0));
}
Integer nodeCount = nodeMap.get(e.node);
nodeMap.put(e.node, Integer.valueOf(nodeCount + 1));
}
}
// Create result string
int totalCount = 0;
StringBuffer res = new StringBuffer();
for (String attr : attrMap.keySet()) {
int attrCount = 0;
StringBuffer paramBuf = new StringBuffer();
java.util.Map> paramMap = attrMap.get(attr);
for (String param : paramMap.keySet()) {
int paramCount = 0;
StringBuffer nodeBuf = new StringBuffer();
java.util.Map nodeMap = paramMap.get(param);
for (java.util.Map.Entry e : nodeMap.entrySet()) {
nodeBuf.append(indentToStr(3) + e.getKey() + " - " + e.getValue() + "\n");
paramCount += e.getValue();
}
paramBuf.append((!param.equals("") ? indentToStr(2) + "[" + param + "] - " + paramCount + "\n" : "") + nodeBuf.toString());
attrCount += paramCount;
}
res.append(indentToStr(1) + attr + " - " + attrCount + "\n" + paramBuf.toString());
totalCount += attrCount;
}
out.println("[report:" + filter.desc() + "] - " + totalCount + "\n" + res.toString());
out.flush();
}
protected boolean incIndent($StateClass.Trace.Event evt) {
switch (evt) {
case COMPUTE_BEGIN:
case REWRITE_CASE1_START:
case CIRCULAR_NTA_CASE1_START:
case CIRCULAR_NTA_CASE2_START:
return true;
default:
return false;
}
}
protected boolean decIndent($StateClass.Trace.Event evt) {
switch (evt) {
case COMPUTE_END:
case REWRITE_CASE1_RETURN:
case CIRCULAR_NTA_CASE1_RETURN:
case CIRCULAR_NTA_CASE2_RETURN:
return true;
default:
return false;
}
}
protected String INDENT_STEP = " ";
protected String indentToStr(int indent) {
StringBuffer buf = new StringBuffer();
for(int i = 0; i < indent; i++) {
buf.append(INDENT_STEP);
}
return buf.toString();
}
/**
* Prints all objects in the collected trace list.
*/
public void printTrace(java.io.PrintWriter out) {
boolean firstTimeStamp = true;
long prevTime = 0; long startTime = 0;
int indent = 0;
for ($StateClass.Trace.Entry e : list) {
if (firstTimeStamp) {
firstTimeStamp = false;
prevTime = startTime = e.timeStamp;
}
out.print(indentToStr(indent) + e + " - ");
out.print(((e.timeStamp-prevTime)/1000000) + " ms - ");
out.println(((e.timeStamp-startTime)/1000000) + " ms");
if (incIndent(e.event)) indent++;
else if (decIndent(e.event)) indent--;
prevTime = e.timeStamp;
}
out.flush();
}
/**
* Prints all of attribute instance computations (cached or aborted).
*/
public void printComputeReport(java.io.PrintWriter out) {
printReport(out, new $StateClass.Trace.Filter() {
public boolean include($StateClass.Trace.Entry e) {
return e.event == $StateClass.Trace.Event.CACHE_ABORT || e.event == $StateClass.Trace.Event.CACHED;
}
public String desc() {
return "computed(i.e.,CACHE_ABORT||CACHED)";
}
});
}
/**
* Prints all cache aborts.
*/
public void printCacheAbortReport(java.io.PrintWriter out) {
printReport(out, new $StateClass.Trace.Filter() {
public boolean include($StateClass.Trace.Entry e) {
return e.event == $StateClass.Trace.Event.CACHE_ABORT;
}
public String desc() {
return "CACHE_ABORT";
}
});
}
/**
* Prints all cached.
*/
public void printCacheReport(java.io.PrintWriter out) {
printReport(out, new $StateClass.Trace.Filter() {
public boolean include($StateClass.Trace.Entry e) {
return e.event == $StateClass.Trace.Event.CACHED;
}
public String desc() {
return "CACHED";
}
});
}
/**
* Prints all copied nodes.
*/
public void printCopyReport(java.io.PrintWriter out) {
printReport(out, new $StateClass.Trace.Filter() {
public boolean include($StateClass.Trace.Entry e) {
return e.event == $StateClass.Trace.Event.COPY_NODE;
}
public String desc() {
return "COPY_NODE";
}
});
}
/**
* Prints report of maxiumum nesting of circular NTA evaluations.
*/
public void printCircularNtaNestingReport(java.io.PrintWriter out) {
class NestingCounter {
int nesting = 0;
int maxNesting = 0;
public void push() {
nesting++;
if (nesting > maxNesting) {
maxNesting = nesting;
}
}
public void pop() {
nesting--;
}
public int max() { return maxNesting; }
}
final NestingCounter counter = new NestingCounter();
printReport(out, new $StateClass.Trace.Filter() {
public boolean include($StateClass.Trace.Entry e) {
boolean res = false;
if (e.event == $StateClass.Trace.Event.CIRCULAR_NTA_CASE1_START ||
e.event == $StateClass.Trace.Event.CIRCULAR_NTA_CASE2_START) {
res = true;
counter.push();
}
if (e.event == $StateClass.Trace.Event.CIRCULAR_NTA_CASE1_RETURN ||
e.event == $StateClass.Trace.Event.CIRCULAR_NTA_CASE2_RETURN) {
counter.pop();
}
return res;
}
public String desc() {
return "CIRCULAR_NTA_CASE*_START";
}
});
System.out.println("Max nesting: " + counter.max() + "\n");
}
}
$endif
]]