SkillAgentSearch skills...

Cacophonia

Run Eclipse with bytecode instrumentation to learn about its execution

Install / Use

/learn @laffra/Cacophonia
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Project Cacophonia

This project visualizes Eclipse to better understand how it works internally.

<img src="http://img.youtube.com/vi/-lYNQ7SXGKY/0.jpg" width=800>

More Information

Setup

  • Install and Launch Eclipse for Committers.
  • From the Project Explorer, Import a project from git.
  • Chose the URL https://github.com/laffra/cacophonia.git
  • Switch back to the Project Explorer and open properties for the file build_agent.sh. Make it executable.
  • Run Project > Clean...

By now, you should see something looking like this:

Cacophonia UI

Launch

  • Select the file Cacophonia.launch and run it as Eclipse launch named Cacophonia

    Cacophonia UI

  • This will launch the Cacophonia UI:

    Cacophonia UI

Enabling Sound

Inside the Cacophonia UI, you can enable sounds when certain plugins interact:

  • Click the mute checkbox in the UI to toggle sound.
  • Switch sound themes by choosing a different theme in the dropdown showing Cacophonia.
  • Choose your own instruments by:
    • Click or drag one of the plugins you are interested in.

    • A red X will show it is now fixed in place.

    • Choose an instrument (e.g., xylophone) from the dropdown:

      Cacophonia UI

    • If you hear nothing, toggle the mute button.

The Cacophonia Implementation

Cacophonia exists of three separate components:

Cacophonia UI

The Agent

This is a Java agent, see Agent.java, which is passed to the JVM at startup. The agent is enabled in the launch configuration. The agent_build.sh build script creates the jar and copies it to your home directory. That jar is then passed to the JVM. See the launch configuration:

Cacophonia UI

A byte array is passed to the Agent for each class being loaded during Eclipse's execution. That byte array is given to Javassist and each method found in every class is then instrumented to call the Cacophonia runtime. The result is that when Eclipse launches, every time a method is entered and left, Cacophonia's runtime is notified. In the Eclipse console you can see what plugins and classes the agent sees coming by:

Cacophonia UI

Look for the System.out.println calls in Agent.java.

The Runtime

The runtime, see Cacophonia.java, is invoked by Eclipse at runtime.

After the code is loaded by the agent, the Cacophonia runtime will handle method enter and leave events to find out which plugin is calling which other plugin. This is done by using the classLoader for each object. Namely, each eclipse plugin has its own unique classloader, which helps us locate the owning plugin for a given method call very easily. The only complication to worry about are multiple threads, so we create a callstack per thread and handle concurrent access.

Once we determined a call is being made from one plugin to another, we send an event to the remote UI, which runs in another process. The UI is actually launched by the agent.

The UI

Finally, the UI, see UI.java, is running in a separate process.

The UI receives the event and draws a line between the two plugins in its UI. Timer threads are used to detect if a call took place between two plugins and to decay the line over time. The UI itself is a simple Java AWT implementation using double-buffered drawing into a canvas.

The UI also has support for generating sounds for each plugin using Java's midi API.

Why Do We Care?

The whole goal of Cacophonia and its UI is to show you what is happening inside Eclipse "under the hood". To paraphrase Richard Feynman, to most effectively use a tool, it is best to have a good understanding of how it works.

Cacophonia UI

By observing the visualization, you may learn quite a few things about Eclipse. Examples:

  • The Eclipse splash screen could have a better progress bar. It does nothing for a while, then quickly jumps to 80%, and then just hangs there. A lot of plugins are still being loaded while no progress is shown in the splash screen. I care about this part quite a bit, as I used to spend a lot of time on the splash screen when I worked on Eclipse performance, a long time ago.
  • It takes 147 plugins to launch Eclipse and see the IDE come alive. For reference, in 2004, it took 26 plugins.
  • It takes about 20s to launch with all the instrumentation happening, versus 10s normal launch time. So, startup is roughly 2X slower with Cacophonia. Interestingly enough, during normal usage of Eclipse, you cannot really tell the visualization is happening. Just when new features are loaded, you can tell a lot of extra work is being done.
  • After Eclipse opens, 28 more plugins get loaded to a total of 175 plugins. By then, we loaded more than 7,000 Eclipse classes (JRE classes are not counted)
  • Switching to another perspective (say from Default to Plugin-in Development) adds only a handful of extra plugins.
  • With each "new" activity or task you will notice more plugins will need to be added. This shows the well-designed internal architecture of the Eclipse platform. The IDE is really one big monolith, but feature are only loaded and activated when needed. Plugins are decoupled from each other using the OSGI bundle framework. In that sense, Eclipse really acts like a micro-services architecture.
  • When you create a project and edit a Java file, you will notice Eclipse has a "heartbeat" to draw the insertion cursor. If you play around, you will see different heart beats. Different input fields involve different plugins and generate different patterns.
  • When you open the Search dialog, you will notice that Eclipse is polling more aggressively now. A similar thing happens during debug. If you bring up the Activity Monitor, you will notice that Eclipse is actually spinning the CPU at around 10% of a core.
  • Mylyn is involved in many things. It almost looks like a spying tool, but I am sure it is not.
  • If you used the Eclipse Installer, like I did, you will notice a lot of "oomph" plugins. Not sure what they all do...
  • Set a breakpoint in your Java code and step into the code. Notice the UI and see how Eclipse supports debugging.
  • When you have a dialog open, such as the search dialog, click on the ? icon and see what plugins are loaded. You will see Eclipse will run a webserver.

Investigating Plugins In More Detail

Aside from the explorations shown above, after running Eclipse for a while, you may notice a certain Eclipse job running every 5 seconds. You can more easily notice the occurence of this event as follows:

  • In the Cacophonia UI, click on manual.
  • Select the "core jobs" plugin. It will turn bright red.
  • Look in the top of the UI and assign an instrument to the plugin, for instance "Marimba".

This will look like the following:

Cacophonia UI

The plugin we selected, core jobs, is shown bright red. All the plugins that were invoked during the job's execution are light red. The lines between the plugins indicate Java calls made from one plugin to another. One of them that stands out quite a bit is the "mylyn monitor ui" plugin.

Let us investigate what the job is doing. For that, we will revisit the Cacophonia runtime in Cacophonia.java. In that file, locate the Method.enter method:

public void enter() {
    callCount++;
    if (Cacophonia.debug) System.out.println(String.format("> %d %s %s", callCount, plugin, name));
    if (!lastPlugin.equals(plugin)) {
        Stack<String> stack = pluginStack.get();
        stack.push(plugin);
        remoteUI.sendEvent(String.format("%s %s", lastPlugin, plugin));
    }
    lastPlugin = plugin;
}

At the end of this method, we add an extra print statement:

    if (plugin.startsWith("org.eclipse.core.jobs")) {
        System.out.println(String.format("# %d %s", callCount, name));
    }

When you save the file, you should see the agent build script run and update the agent jar with the new runtime. Relaunch the Eclipse launch configuration now, and you should see something like this:

Cacophonia UI

This does show us all the methods invoked inside the org.eclipse.core.jobs plugin, but it does not tell us much yet what jobs are actually being run. We can update our runtime to pass the object itself and then print out more details about the method being called. However, we don't know what to print yet. So, let us look at the plugin itself first. For that, we will import the plugin into our Eclipse workspace.

Cacophonia UI

Eclipse jobs are essentially implemented as Java threads. This is explained in this FAQ. So, to find out interesting things about running jobs, we will search for anything implementing a Java thread. Such implementation will always override void run(), so we search for that.

Cacophonia UI

The occurrence in Worker.java looks very promising as it appears to activate a job and then run it:

    setName(getJobName());
    result = currentJob.run(monitor);

We change this code into:

    setName(getJobName());
    System.out.println("Run job: " + currentJob.getClass().getName() + 

Related Skills

View on GitHub
GitHub Stars18
CategoryDevelopment
Updated4y ago
Forks2

Languages

Java

Security Score

75/100

Audited on Nov 23, 2021

No findings