Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timing how long each file takes to compile with ant

Tags:

java

javac

ant

Occasionally a slight modification to a Java source file like some additional explicit casts to help the compiler can improve compile time from 4 minutes to 3 seconds for a single java file (Especially in Java 8).

The problem is: In a large java project, how do you find which particular .java files are compiling slowly?

Is there a way to get Ant to time how long it takes to compile each individual .java file?

like image 348
clinux Avatar asked Apr 11 '16 02:04

clinux


People also ask

What is Ant build files?

Ant uses an xml file for its configuration. The default file name is build. xml .

What is target in build xml?

An Ant target is a sequence of tasks to be executed to perform a part (or whole) of the build process. Ant targets are defined by the user of Ant. Thus, what tasks an Ant target contains depends on what the user of Ant is trying to do in the build script.

How do you build an Ant project?

In the Project tool window, right-click the generated build file and select Add as Ant Build File to open it in the Ant tool window. In the Select Path dialog, navigate to the desired build. xml file, and click OK. A build file should have at least a root element to be added to the Ant Build tool window.

What does my Ant compile target actually do?

Here's the source code for my Ant compile target: Here's a brief description of what this Ant target does: The first part of the script runs the Ant javac task. This task compiles all the files found in the src directory, excluding all files matching the naming patter Test*.java.

How to compile a single java source file in ant?

Open the command prompt and navigate to the folder where the build.xml resides, and type ant.If the build file has been typed correctly, then you should see the following output on cmd: In the above screen Ant has compiled the single Java source file in the current directory and printed a success message after that.

Can I use ant to build a command-line based Java application?

This particular script happened to be used for building a Swing application, but it can really be used to build any Java application, command-line based or other. Here's the source code for my Ant compile target: Here's a brief description of what this Ant target does: The first part of the script runs the Ant javac task.

How does the ant javac task work?

The first part of the script runs the Ant javac task. This task compiles all the files found in the src directory, excluding all files matching the naming patter Test*.java.


Video Answer


1 Answers

I think that this might be possible. Here's what I've found:

If you're using Java 8, you can register a Plugin with the compiler to add some additional functionality during compilation. The documentation has this to say about plugins:

It is expected that a typical plug-in will simply register a TaskListener to be informed of events during the execution of the compilation, and that the rest of the work will be done by the task listener.

So you can setup a plugin to use a TaskListener, and have the task listener log timestamps when class are being generated.

package xyz;
import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;

public class TimestampPlugin implements Plugin {


    @Override
    public String getName() {
        return "Timestamp_Plugin";
    }

    @Override
    public void init(JavacTask task, String... strings) {
        task.setTaskListener(new FileTimestampListener());
    }
}

Documentation for TaskListener. A task listener is passed a TaskEvent, which has a Kind. In your case it sounds like you're interested in generation.

package xyz;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;

import java.util.HashMap;

public class FileTimestampListener implements TaskListener {
    HashMap<String, Long> timeStampMap = new HashMap<>();

    @Override
    public void started(TaskEvent taskEvent) {
        if(TaskEvent.Kind.GENERATE.equals(taskEvent.getKind())) {
            String name = taskEvent.getSourceFile().getName();
            timeStampMap.put(name, System.currentTimeMillis());
        }
    }

    @Override
    public void finished(TaskEvent taskEvent) {
        if(TaskEvent.Kind.GENERATE.equals(taskEvent.getKind())) {
            String name = taskEvent.getSourceFile().getName();
            System.out.println("Generated " + name + " over " + (System.currentTimeMillis() - timeStampMap.get(name)) + " milliseconds");
        }
    }
}

This is a simple example but it should be straightforward from here to set up something like a log file to store the information gathered. As you can see in the plugin's init function, arguments can be passed to the Plugin from the command line.

The plugin is configured by specifying it with the -Xplugin compiler argument. I'm not sure why but there doesn't appear to be any documentation on this page about it, but it can used by setting up a file called com.sun.source.util.Plugin (the FQ class name of the interface to implement) in your META-INF/services directory. So:

META-INF
|-- services
    |-- com.sun.source.util.Plugin

And in that file list the FQ class name of your implementation of this class. So the file contents would be:

xyz.TimestampPlugin

In your Ant task you'll just need to specify a compiler flag -Xplugin:Timestamp_Plugin (note this is the name provided by the Plugin's getName() function). You'll also need to provide the compiled Plugin and runtime dependencies on the classpath, or the annotation processor path, if one is specified.

like image 145
heisbrandon Avatar answered Oct 16 '22 17:10

heisbrandon