Skip to content

Commit

Permalink
Add instrumentSkipRegex and set*InstrumentationEnable controls
Browse files Browse the repository at this point in the history
  • Loading branch information
jpmonettas committed Nov 17, 2023
1 parent 1848732 commit d9ad2e8
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 39 deletions.
19 changes: 18 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ Coordinates also work with unordered literals like sets, and maps with more than
If you want utility funcitons to work with forms and coordinates take a look at
[get-form-at-coord](https://github.com/flow-storm/hansel/blob/master/src/hansel/utils.cljc#L74-L78) for example.

## Controlling instrumentation without restarting the repl
## Controlling instrumentation

Instrumentation can be controlled by 3 JVM properties :

* `clojure.storm.instrumentOnlyPrefixes` a comma separated list of namespaces prefixes to instrument
* `clojure.storm.instrumentSkipPrefixes` a comma separated list of namespaces prefixes to skip
* `clojure.storm.instrumentSkipRegex` a regex to match namespaces to skip

which apply in that order.

You can add/remove instrumentation prefixes without restarting the repl by calling :

Expand All @@ -92,9 +100,18 @@ You can add/remove instrumentation prefixes without restarting the repl by calli
```
and check them by evaluating the `:help` key.

You can also disable/enable specific types of instrumentation by using :

```clojure
(clojure.storm.Emitter/setFnCallInstrumentationEnable true)
(clojure.storm.Emitter/setFnReturnInstrumentationEnable true)
(clojure.storm.Emitter/setExprInstrumentationEnable true)
(clojure.storm.Emitter/setBindInstrumentationEnable true)
```
## Applications using ClojureStorm

* [FlowStorm debugger](http://www.flow-storm.org)
* [Clofidence](https://github.com/flow-storm/clofidence)

## Clojure

Expand Down
2 changes: 1 addition & 1 deletion src/jvm/clojure/lang/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -7451,7 +7451,7 @@ else if((form instanceof IType) ||
}
} catch (Exception e)
{
System.out.println("Error processing form. Ns: " + currentNS().toString() + " file: " + (String)file + " form: " + origForm);
// System.out.println("Error processing form. Ns: " + currentNS().toString() + " file: " + (String)file + " form: " + origForm);
throw e;
}
finally
Expand Down
115 changes: 78 additions & 37 deletions src/jvm/clojure/storm/Emitter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import clojure.asm.Opcodes;
import clojure.asm.Type;
Expand Down Expand Up @@ -41,14 +43,33 @@ public class Emitter {

public static Var INSTRUMENTATION_ENABLE = Var.create(false).setDynamic();

private static ArrayList<String> instrumentationSkipPrefixes = new ArrayList();
private static ArrayList<String> instrumentationOnlyPrefixes = new ArrayList();
private static ArrayList<String> instrumentationOnlyPrefixes = new ArrayList();
private static ArrayList<String> instrumentationSkipPrefixes = new ArrayList();
private static Pattern instrumentationSkipRegex = null;

private static boolean fnCallInstrumentationEnable=true;
private static boolean fnReturnInstrumentationEnable=true;
private static boolean exprInstrumentationEnable=true;
private static boolean bindInstrumentationEnable=true;

////////////////////
// Initialization //
////////////////////

static {
static {
String instrumentationEnableProp = System.getProperty("clojure.storm.instrumentEnable");
if(instrumentationEnableProp != null)
setInstrumentationEnable(Boolean.parseBoolean(instrumentationEnableProp));


String onlyPrefixesProp = System.getProperty("clojure.storm.instrumentOnlyPrefixes");
if(onlyPrefixesProp != null)
{
String[] prefixes = onlyPrefixesProp.split(",");
for(String p : prefixes)
addInstrumentationOnlyPrefix(p);

}

String skipPrefixesProp = System.getProperty("clojure.storm.instrumentSkipPrefixes");
if(skipPrefixesProp != null)
{
Expand All @@ -58,16 +79,15 @@ public class Emitter {

}

String onlyPrefixesProp = System.getProperty("clojure.storm.instrumentOnlyPrefixes");
if(onlyPrefixesProp != null)
{
String[] prefixes = onlyPrefixesProp.split(",");
for(String p : prefixes)
addInstrumentationOnlyPrefix(p);

}
String skipRegexProp = System.getProperty("clojure.storm.instrumentSkipRegex");
if(skipRegexProp != null)
instrumentationSkipRegex = Pattern.compile(skipRegexProp, Pattern.CASE_INSENSITIVE);
}


/////////////////////////////////////////////////
// Instrumentation enabling/disabling controls //
/////////////////////////////////////////////////

public static void setInstrumentationEnable(Boolean x) {
IFn f = new AFn() {
public Object invoke(Object prev) {
Expand All @@ -81,8 +101,17 @@ public Object invoke(Object prev) {
public static Boolean getInstrumentationEnable() {
return (Boolean) INSTRUMENTATION_ENABLE.deref();
}

public static String makePrefixesString(ArrayList<String> prefixes) {

public static void setFnCallInstrumentationEnable(boolean enable){fnCallInstrumentationEnable=enable;}
public static void setFnReturnInstrumentationEnable(boolean enable){fnReturnInstrumentationEnable=enable;}
public static void setExprInstrumentationEnable(boolean enable){exprInstrumentationEnable=enable;}
public static void setBindInstrumentationEnable(boolean enable){bindInstrumentationEnable=enable;}

////////////////////////////////////////
// Namespace instrumentation controls //
////////////////////////////////////////

public static String makePrefixesString(ArrayList<String> prefixes) {
if(prefixes.size()>0)
{
List prefs = prefixes.stream().map(p -> Compiler.demunge(p)).collect(Collectors.toList());
Expand Down Expand Up @@ -133,11 +162,21 @@ public static boolean skipInstrumentation(String fqFnName) {
instrument &= !fqFnName.startsWith(prefix);
}

if (instrumentationSkipRegex != null)
{
Matcher m = instrumentationSkipRegex.matcher(fqFnName);
instrument &= !m.find();
}

boolean skip = !getInstrumentationEnable() || !instrument;
return skip;
}

private static void dupAndBox(GeneratorAdapter gen, Type t) {

//////////////////////////////
// Instrumentation emission //
//////////////////////////////

private static void dupAndBox(GeneratorAdapter gen, Type t) {
if(t != null && (Type.LONG_TYPE.equals(t) || Type.DOUBLE_TYPE.equals(t))) {
gen.dup2();
gen.valueOf(t);
Expand All @@ -159,7 +198,7 @@ public static void emitFnCallTrace(GeneratorAdapter gen, ObjExpr objx, String mu

boolean skipFn = skipInstrumentation(mungedFnName);

if (!skipFn) {
if (fnCallInstrumentationEnable && !skipFn) {
Integer formId = (Integer) Compiler.FORM_ID.deref();
if (formId == null) formId = 0;
Symbol name = Symbol.create(Compiler.demunge(mungedFnName));
Expand All @@ -180,7 +219,7 @@ public static void emitFnCallTrace(GeneratorAdapter gen, ObjExpr objx, String mu

public static void emitFnReturnTrace(GeneratorAdapter gen, String mungedFnName, IPersistentVector coord, Type retType) {
boolean skipFn = skipInstrumentation(mungedFnName);
if (!skipFn) {
if (fnReturnInstrumentationEnable && !skipFn) {
Integer formId = (Integer) Compiler.FORM_ID.deref();
if (formId == null) formId = 0;
if(Type.VOID_TYPE.equals(retType))
Expand Down Expand Up @@ -219,7 +258,7 @@ private static void emitCoord(GeneratorAdapter gen, IPersistentVector coord) {
}

public static void emitExprTrace(GeneratorAdapter gen, ObjExpr objx, IPersistentVector coord, Type retType) {
if (coord != null) {
if (exprInstrumentationEnable && coord != null) {

Integer formId = (Integer) Compiler.FORM_ID.deref();
if (formId == null) formId = 0;
Expand All @@ -242,33 +281,35 @@ public static void emitExprTrace(GeneratorAdapter gen, ObjExpr objx, IPersistent
}

public static void emitBindTrace(GeneratorAdapter gen, ObjExpr objx, BindingInit bi, IPersistentVector coord) {
String symName = Compiler.demunge(bi.binding().name);
Integer bIdx = bi.binding().idx;
if (bindInstrumentationEnable) {
String symName = Compiler.demunge(bi.binding().name);
Integer bIdx = bi.binding().idx;

if (objx instanceof FnExpr &&
!skipInstrumentation(((FnExpr)objx).name()) &&
coord != null &&
!(symName.equals("-") || symName.contains("--"))) {
if (objx instanceof FnExpr &&
!skipInstrumentation(((FnExpr)objx).name()) &&
coord != null &&
!(symName.equals("-") || symName.contains("--"))) {

Type valType = null;
Class primc = Compiler.maybePrimitiveType(bi.init());
if (primc != null) valType = Type.getType(primc);
Type valType = null;
Class primc = Compiler.maybePrimitiveType(bi.init());
if (primc != null) valType = Type.getType(primc);

// assume binding val on the stack
dupAndBox(gen, valType);
emitCoord(gen, coord);
gen.push(symName);
// assume binding val on the stack
dupAndBox(gen, valType);
emitCoord(gen, coord);
gen.push(symName);

gen.invokeStatic(TRACER_CLASS_TYPE,
Method.getMethod("void traceBind(Object, String, String)"));
gen.invokeStatic(TRACER_CLASS_TYPE,
Method.getMethod("void traceBind(Object, String, String)"));

}
}
}
}

public static void emitBindTraces(GeneratorAdapter gen, ObjExpr objx, IPersistentVector localBindings,
IPersistentVector coord) {

if (objx instanceof FnExpr && !skipInstrumentation(((FnExpr) objx).name())) {
if (bindInstrumentationEnable && objx instanceof FnExpr && !skipInstrumentation(((FnExpr) objx).name())) {

for (int i = 0; i < localBindings.count(); i++) {

Expand Down

0 comments on commit d9ad2e8

Please sign in to comment.