Skip to content
Vijay Krishna Palepu edited this page Dec 4, 2020 · 20 revisions

Blinky: Java Code Instrumenter and Execution Tracer

Welcome to the Blinky wiki!

Blinky is an instrumenter and execution tracer for software systems that compile to Java Bytecode and target the Java Virtual Machine for execution.

Blinky has the capability to log the execution of any source- or byte-code instruction being executed during a software run. In addition, it also logs auxiliary execution events for the entry, exit, and competition of method invocations, method declarations, and compile-time source- and byte-code instructions. Execution event logs that indicate method exits may take the form of return or throw instructions.

INSTALLATION & USAGE INSTRUCTIONS

Installation

The installation of Blinky is currently based on Maven. To install,

  1. Make sure that you have installed Maven (3.6.3) and Java 8 in your device.
  2. Clone blinky-util blinky-core and blinky-config.
  3. Change into the blinky-util folder and run mvn package -DskipTests -q and mvn install.
  4. Change into the blinky-config folder and run mvn package -DskipTests -q and mvn install.
  5. Change into the blinky-core folder and run mvn package -DskipTests -q. This should create three JAR files in the target directory under the blinky-core module (check ./blinky-core/target).
  6. If you find blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar in your ./target folder, that would mean you have successfully installed and compiled the blink-core and could start to write your own profiler.

Usage

(cont. from the installation instructions from above)

  1. Use blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar for just about anything, like (typically) when using Blinky as a javaagent for instrumenting and profiling software programs that are run with the java command.
  2. Run mvn install to deploy Blinky and its dependencies in your local maven repository when using Blinky as a dependency for other projects. This should run all the unit tests in Blinky Core and Util.

The following is a basic structure of using blinky as a java-agent with the java command, to instrument and profile a system-under-analysis: java -Xbootclasspath/p:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/ -javaagent:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/=<arguments-to-blinky-java-agent> /*your java program*/.

Arguments to Blinky's Java Agent

<arguments-to-blinky-java-agent> could be "0" or "A" or your desired combination of the listed characters e.g. "exl". Arguments will determine whether a corresponding trace event will be monitered.

  • 0 ... no execution tracing

OR

  • A stands for All of the Above! (use with great caution!)

OR the combination of

  • x stands for method exit events;
  • i stands for method invocation events;
  • l stands for source line execution events;
  • e stands for method enter events.
  • v stands for local variable instructions, e.g. ILOAD, ISTORE, etc.
  • z stands for zero operand instructions, e.g. ADD, MUL, GOTO, PUSH, POP, etc.
  • j stands for jump instructions, e.g. IFNULL
  • f stands for field instructions, e.g. PUTFIELD, GETFIELD, PUTSTATIC and GETSTATIC
  • c stands for load constant instructions, e.g. LDC, ICONST_1, etc
  • t stands for type instructions, e.g. CHECKCAST
  • s stands for switch instructions, e.g. TABLESWITCH and LOOKUPSWITCH

whitelist ... read a selection of classes, a.k.a. whitelist, to ensure that they are instrumented.
entry-method ... name of method that the profiler should start/end the trace collection at.
entry-class ... fully qualified name of the class for the entry-method. Providing this argument without entry-method is a bad idea.

Examples:

xle, whitelist will force the instrumenter to check against the whitelist, and trace method enter exit, and source line execution events.
l will trace only source line execution events while ignoring the whitelist.
i will trace only method invocation events while ignoring the whitelist.

More information on the Blinky Arguments can be found in here and here.

For example, if you want Blinky to calculate call depth, the command should be java -Xbootclasspath/p:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/ -javaagent:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/=exl,calldepth /*your java program*/.

You also may need to add -noverify behind the above command to run the code for these reasons.

Attention: The default profiler(the file that actually generates output) is an empty profiler. So there will only be 2 lines of meaningless output generated.

GENERATE CUSTOMIZED OUTPUT

So far, the blinky-core should be working correctly. However, to generate actual meaningful output, we need to write our own blinky profiler. This section is a simple guide on how to customize your own output.

Configure the Inclusion and Exclusion List of Package/Class

This step is rather simple. In the pom.xml, we can see that the system uses a .yaml as its configuration. Blinky will parse this file and inject the information to these variables.

Write Your Own Blinky Profiler

The pom.xml also indicate which profiler the blinky is currently using. The default profiler is an empty profiler so it will not have any output.

The new profiler should extend the IProfiler and overwrite the existing functions. When the functions will be called during the execution of a program is self-explanatory. All we have to do is to overwrite the functions and let it output something we want.

An instance of TraceEvent has many different variables. While the variable names are self-explanatory to some extend, it might be a little tricky for a beginner to understand all the meanings. Therefore I uploaded a simple profiler to give you a head start. You can run it and use it as a reference to write your own.

You should notice that you don't have to rewrite all functions in IProfiler. Whether a function will be called is determined by your calling arguments. Also, remember to change the corresponding line in pom.xml to your own profiler file location.

Attention: blinky-core needs to be recompiled whenever the source code is changed. To ignore the test cases and make the compiling process faster, use mvn package -DskipTests -q.

Use Blinky with IDEs

To use Blinky test your own program in Eclipse, you could:

  1. Right-click the program you want to run.
  2. Click 'Run as'
  3. Click 'Run configuration'
  4. Choose the 'Arguments' tab
  5. Add the correct arguments to 'VM argument' section. e.g. -Xbootclasspath/p:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/ -javaagent:/*path to your blinky-core-0.0.1-SNAPSHOT-jar-with-dependencies.jar*/=exl,calldepth -noverify
  6. Click 'Apply' and run the program

The steps should be similar to other IDE.

Troubleshooting

  1. "Failed to execute goal [TEST] on project [PROJECT]: there are test failures."
  • FIX: run the command mvn package -DskipTests -q
  1. "Failed to execute goal on project [PROJECT]: Could not resolve dependencies for project org.spideruci.analysis:blinky-core:jar:0.0.1-SNAPSHOT: Could not find artifact org.spideruci.analysis.util:blinky-util:jar:0.0.1-SNAPSHOT"
  • FIX: clone blinky-util. Run mvn compile, mvn package -DskipTests -q, and mvn install