Trevil is a language for composing visualizations of unordered trees, such as the calling context trees produced by standard profilers.
Trevil is based on Trevis. It provides a language with which users can configure Trevis visualizations. Trevil is modeled after the ideas behind Conditional XPath, and it uses syntactic aspects of LPath. However, given that Trevis trees are unordered, Trevil does not support concepts in XPath related to document-order.
Trevil supports four primitive types: long, double, boolean, and String. The four types correspond to the Java types of the same names, however, in Trevil String is a value type (Trevil does not support references). Trevil is strongly typed, that is, the type of an expression is known statically.
Trevil supports a simple expression language, inspired by Java. In addition to the standard Java equality operators (== and !=), Trevil also provides special String comparison operators:
An aggregation expression computes an aggregate value over a set of nodes selected by a path expression.
Trevil supports the following aggregation (aka reduction) constructs (which were inspired to some degree by DTrace and XPath 2.0):
A PathExpression consists of a sequence of steps. A step is built from an axis, a step condition, and an optional closure operator:
A condition can be an arbitrary Trevil expression (which may itself contain aggregation expressions), surrounded by square brackets. An underscore is syntactic sugar for [true].
Trevil supports transitive closure on steps as follows:
Trevil path expressions support the following immediate axes:
Given the fact that Trevil supports transitive closure on steps (as introduced by Conditional XPath), the transitive XPath axes (e.g., ancestor) can be expressed by combining the above immediate (e.g., parent) axes with closures.
The following table shows those XPath axes that are meaningful for unordered trees together with the corresponding Trevil notation.
XPath axis | Trevil (axis and condition) | Trevil (using immediate axis and closure) |
---|---|---|
self | .[cond] | |
child | /[cond] | |
descendant | //[cond] | /_*/[cond] |
descendant_or_self | //.[cond] | /_*.[cond] |
parent | \[cond] | |
ancestor | \\[cond] | \_*\[cond] |
ancestor_or_self | \\.[cond] | \_*.[cond] |
root (not part of XPath) | ^[cond] | \\.[@no(\_) && cond] |
Returns true if there is some (transitive) caller (an ancestor in the CCT) where the class name matches "[Ll]istener"?
@some(\\[Class=~"[Ll]istener"])
@or(\\[Class=~"[Ll]istener"], true)
@or(\\[true], Class=~"[Ll]istener")
@or(\\_, Class=~"[Ll]istener")
@count(\\[Class=~"[Ll]istener"])>0
@sum(\\[Class=~"[Ll]istener"], 1)>0
Returns true if there is some immediate caller (the parent in the CCT) where the class name matches "[Ll]istener"?
@some(\[Class=~"[Ll]istener"])
@or(\[Class=~"[Ll]istener"], true)
Are all transitive callers (the parent in the CCT) in a package starting with "org.eclipse."?
@each(\\[true], Package=^"org.eclipse.")
@each(\\_, Package=^"org.eclipse.")
Does this method call some method in class "java.util.HashMap"?
@some(/[Class=="java.util.HashMap"])
Does this method call some method that calls a method called "exit"?
@some(/[true]/[Method=="exit"])
@some(/_/[Method=="exit"])
Is there some descendant in a package starting with "org.eclipse." that calls a callee in a package starting with "java.awt."
@some(//[Package=^"org.eclipse"]/[Package=^"java.awt"])
Is this method in class "Main"?
@some(.[Class=="Main"])
Class=="Main"
Does this method call somebody?
@some(/_)
Does this method call nobody? (is it a leaf)
@no(/_)
! @some(/_)
Is this method called by somebody?
@some(\_)
Is this method called by nobody? (is it the root)
@no(\_)
! @some(\_)
Height of the node (number of ancestors, excluding self)?
@count(\\_)
@count(\_+)
Height of the node, plus one (number of ancestors, including self)?
@count(\\._)
@count(\_*)
@count(\\_) + 1
Inclusive sample count (this node's plus all its descendants)?
@sum(//._, ExclusiveSamples)
@sum(//_, ExclusiveSamples) + @sum(._, ExclusiveSamples)
@sum(//_, ExclusiveSamples) + ExclusiveSamples
Sample count of descendants and self in package java.util.**?
@sum(//.[Package=^"java.util."], ExclusiveSamples)
Sample count of callees (and their descendants) in package "org.eclipse.swt" invoked by a caller in package "org.eclipse.jdt"?
@sum(//[package=="org.eclipse.jdt"], @sum(//.[package=="org.eclipse.swt"], samples))
-- buggy: double-counts in cases of nesting!!!
Is there a descendant or self called "foo"?
@some(//.[Method=="packPopup"])
@some(/_*.[Method=="packPopup"])
@some(/_*/[Method=="packPopup"]) || @some(.[Method=="packPopup"])
@some(/_+/[Method=="packPopup"]) || @some(/[Method=="packPopup"]) || @some(.[Method=="packPopup"])
Is there a descendant called "foo"?
@some(//[Method=="packPopup"])
@some(/_*/[Method=="packPopup"])
@some(/_+/[Method=="packPopup"]) || @some(/[Method=="packPopup"])
What is the sample count of this node (which may be a loop node), excluding nested loop trees?
ExclusiveSamples + @sum(/[Kind!="loop"]+, ExclusiveSamples)
How many immediately nested loops exist?
@count(/[Kind=="loop"]/[Kind=="loop])
What is sum of the exclusive number of samples in method "objc_msgSendSuper" across all contexts where it invokes "windowProc"?
@sum(//[Method=="objc_msgSendSuper" && @some(/[Method=="windowProc"])], ExclusiveSamples)
What is the inclusive number of samples in method "play" in contexts where it invokes "control"?
@sum(//[Method=="objc_msgSendSuper" && @some(/[Method=="windowProc"])], @sum(//._, ExclusiveSamples))
-- buggy, double-counts in cases of nesting!!
What is my inclusive sample count divided by the root node's inclusive sample count?
@sum(//._, ExclusiveSamples) / (double)@sum(^_, @sum(//._, ExclusiveSamples) )
@sum(//._, ExclusiveSamples) / (double)@sum(\\.[@no(\_)], @sum(//._, ExclusiveSamples) )
Given that Trevis trees are unordered, (unlike XML or linguistic trees), Trevil does not (need to) support the following axes supported e.g. by LPath: