Discovering JoularJX#
Note
For this lab, you should work on the lab room PCs.
We use the JoularJX tool, restricted to machines equipped with an Intel processor, furthermore you need specific rights to access RAPL registers.
Objectives
This lab will allow you to discover the JoularJX tool. This tool has the particularity to measure power consumption of a Java application down to the granularity of a single method.
Introduction#
About JoularJX#
JoularJX is a Java-based agent for software power monitoring at the source code level which:
Monitors power consumption of each method at runtime;
Uses a Java agent, no source code instrumentation needed;
Uses Intel RAPL (powercap interface) for getting accurate power reading on GNU/Linux;
Provides real time power consumption of every method in the monitored program;
Provides total energy for every method on program exit.
JoularJX stores power data every second in CSV files and, at the end of the monitoring session, it displays the total energy consumption for the java process (in Joules).
JoularJX has a non negligible energy cost. Its objective is more to highlight the most energy-hungry methods than to measure a java program energy consumption.
How it works
This is done by
Monitoring CPU utilization every second for each Java thread. Power consumption is allocated accordingly to the percentage. As a consequence, the energy consumed by other processes is not included in the energy result. This is done only every second because it is a costly operation.
A second monitoring loop detects, for every thread, which method is currently being executed for every 10 milliseconds (by observing the first method in the thread stacktrace). Then power consumption is allocated statistically to each method.
Attention
In practice, this requires to run a program for at least several seconds to be able to measure its power consumption.
Methods that last less than 10ms may not be detected.
Note
For more information on JoularJX:
Organization of the lab#
This lab has two parts:
You will first measure the power consumption of a single class Java program.
You will then test an application composed of a package with several classes and experiment with measurements at the level of a package, a class or a method.
Initializations#
The whole lab will be done in the $HOME/ENV4101/DiscoverJoularJXLab directory. If it does not already exist, create the ENV4101 directory. Go to this directory.
mkdir -p $HOME/ENV4101
cd $HOME/ENV4101
Activate the python environment#
In all the terminals used for this lab, activate the env4101 environment:
source $HOME/env4101/bin/activate
as described on the python installation page: Installations Python
Get the code#
Then download the code for this lab (click on the mouse right button) and store it in your ENV4101 directory:
or copy the following command on your terminal:
wget https://www-inf.telecom-sudparis.eu/COURS/cen/Mesures/DiscoverJoularJXLab.zip
Unzip the code
unzip DiscoverJoularJXLab.zip
Go to the DiscoverJoularJXLab directory.
cd DiscoverJoularJXLab
Part 1 - Single class Java program#
Go to the RayCastingSingleClass directory.
cd RayCastingSingleClass
Overview of RayCasting class#
The RayCasting.java
file implements the RayCasting
class. This class is a simplified version of a ray casting algorithm adapted from the Rosetta Java implementation[1]. Its purpose is to check wether a given point is inside or outside a polygon.
In our RayCasting class, the algorithm is tested for the following shapes: square, squareHole, strange and hexagon
final static int[][] square = ; final static int[][] squareHole = ; final static int[][] strange = ; final static int[][] hexagon = ;
final static int[][][] shapes = {square, squareHole, strange, hexagon};
A loop with a variable number of iterations nb_iteration
is used to modify the duration
of the program and better detect the energy used.
for (int i=0; i < nb_iteration; i++){ for (int[][] shape : shapes) { for (double[] pnt : testPoints) contains(shape, pnt); } } }
Perform measurements#
The RayCasting.java
file is composed by the main()
method which parses the input argument nb_iteration
.
The argument represents the number of iterations to be performed in the main()
.
This number of iterations is used to modify the duration of the program.
Augmenting the duration of the program is necessary to obtain exploitable results with JoularJX.
Take a look at the source code RayCasting.java
.
The provided code does not print information at the execution of each loop.
In this case, we recommend to request 10.000.000 iterations.
If you remove the comments on the lines printing information, the execution will take more time and you can request a smaller number of iterations.
The more times we launch the program, and the more accurate will be the computation of the means and standard deviations. We suggest this number to be between 3 to 5 during this lab, but it depends on the speed of the device.
To launch the application with JoularJX, we have prepared a main.sh
script, see the readme.md
file. The command to run has the following form:
bash main.sh RayCasting <nb_iteration> <nb_launch>
First compile the application:
javac *.java
Then, experiment with the provided version of the program that does not print any information at each loop. Make a try with the following input values:
bash main.sh RayCasting 10000000 3
If the line “Program consumed 0,00 joules” gets displayed, this means that the program was too short to make relevant power measurements. You then have to ask for a larger number of iterations.
If the graph is difficult to read (too many methods displayed), may be it is a good idea to filter by method. We will do it in the next steps.
2 CSV files are automatically generated by JoularJX for each launch of the program.
Those file names contain the Process ID (PID) of the java virtual machine. They are kept in a subdirectory of the results
directory named with the date and time of the experiment
(e.g. results/23.09.21-14h48m29s/
).
joularJX-PID-methods-energy.csv
: total cumulated energy consumption for all methods, include the called methods time.joularJX-PID-methods-energy-filtered.csv
: total cumulated energy consumption of the filtered methods (no filtered method for this question).
You will get these files for each execution (the nb_launch
argument of the main.sh
script corresponds to the number of executions).
The collected data are concatenated to prepare the final graphs displayed at the end of the script.
The script produces one graph for each csv file :
The first graph with the total cumulated energy consumption for all methods (may be difficult to read when there are too many methods). Each method appears with its total mean time and standard deviation computed from all the executions.
Be careful the consumption, is counted only when the method is the first one in the stack trace execution:
e.g. if m1 calls m2: during m2, the consumption will be attributed to m2.
The second graph shows only filtered methods. This second graph is not produced in this part of the lab, it is the reason why you see this message
No result in filtered methods, either there is no filter or the filtered methods duration may be too short
, we will use the filtering feature of JoularJX in the next part of the lab.Be careful, in this second graph, the consumption is counted for the first FILTERED method encountered while browsing the stack trace from its top.
e.g. if m1 is filtered and m1 calls m2, the method for which the consumption will be counted during m2 depends on the fact that m2 is or not filtered.
If m2 is a filtered method, it will be counted for m2,
if m2 is not filtered, it will be counted for m1.
Attention
For each graph, the method consumption is counted for only one method.
In the case of the non filtered graph, it is counted for the active method only.
In the case of the filtered graph it is counted for the first filtered and active method encountered in the stack trace.
Experiment with filtering#
Initially, no filtering is performed, and the csv file produced for filtering is empty.
In this part of the lab, we will select the methods for which energy performance should be collected.
Filter configuration in config.properties file
Take a look at the config.properties
file. It is a configuration file for JoularJX that describes which methods should be measured. This file contains the filter-method-names
property to indicate JoularJX at which level the measurements should take place. If empty, no filtering will occur. The property may contain a list of filters, separated by commas. For a single class application like in this first step, the following filters may be used:
filter-method-names=
\(\implies\) keep results for all methods from all invoked classes (even from JDK)filter-method-names=Class1
\(\implies\) keep measures for all methods present inClass1
filter-method-names=Class1.methodA
\(\implies\) keep measures formethodA
ofClass1
filter-method-names=Class1.methodA,Class1.methodB
\(\implies\) keep measures formethodA
andmethodB
ofClass1
Be careful: no blank between two elements !
Modify the config.properties
file to monitor only:
The
RayCasting
class (i.e. filter all the methods of the class,RayCasting.main
,RayCasting.contains
andRayCasting.intersect
)
filter-method-names=RayCasting
The
RayCasting.main
method only
filter-method-names=RayCasting.main
The
RayCasting.main
and theRayCasting.intersect
methods
filter-method-names=RayCasting.main,RayCasting.intersect
This means that you have to change the config.properties
file and then launch the above bash main.sh RayCasting 10000000 3
command again after each modification of the file. NB: You only change a configuration file, you don’t need to compile the java classes.
Question
How many methods are provided by the RayCasting class ? Do you see all the methods in the filtered diagram ? Why ?
NB: Some methods may be so short that JoularJX does not detect them: JoularJX gets method name (through execution stack trace) - every 10ms
Specificities of JoularJX
For the filtered results, the data are not simply a subset of the non-filtered results.
The data of a filtered method will include the energy consumed by the methods that it calls.
For example, if package1.Class1.methodA
calls java.io.PrintStream.println
to print some text to a terminal,
JoularJX then calculates:
In the first file (joularJX-PID-methods-energy.csv), the power or energy consumed by println separately from methodA. The latter power consumption will not include the power consumed by println.
In the second file (joularJX-PID-methods-energy-filtered.csv), if methods from package1 are filtered, then the power consumption of println will be added to methodA power consumption.
Measure the cost of displaying information on screen#
The method intersect
does not consume much energy. In case it is not detected by JoularJX, it may not be shown on the graph.
In this exercice, we will add a print call in this method, and see if it changes this method energy impact.
Warning
Make sure that your config.properties
contains the line filter-method-names=RayCasting
to select all the methods of the RayCasting class.
You have changed a java file, you need a new compilation
javac *.java
Modify the source code by uncommenting the line for printing information at each call.
In the RayCasting.java
file, uncomment the print line in the intersect method
/*
Uncomment the following line
if you want to print results on the terminal.
NB: This will take more time and energy.
*/
System.out.print("");
Compile and launch a new series of experiment. Did it modify the result ?
Add the method java.io.PrintStream.print
to the method filter, and explain the differences.
Part 2 - Java application in one package#
Go to the JavaCollectionsInOnePackage
directory:
cd ../JavaCollectionsInOnePackage
Overview of the measureJavaCollections
package#
Open the MeasureJavaCollections project in your favorite java development environment
(e.g. eclipse). Then look at the 3 Java classes : Main
, TestArrayList
, TestLinkedList
.
The measureJavaCollections
package contains test classes with a name starting by Test (TestArrayList
, TestLinkedList
)to analyze the energy consumption of two basic Java collections:
ArrayList
(Java Doc), a Resizable-array implementationLinkedList
(Java Doc), a Double-linked list implementation
Take time to remember the differences between those two implementations of the List interface.
Java collection test classes#
The test classes allow to test several methods to manipulate a collection. For each collection, there are methods to:
“add
n
elements” at the end of the collection (addElementsLinkedList
,addElementsArrayList
),“access
n
elements” with their index varying from0
ton
(accessElementsLinkedList
,accessElementsArrayList
),and finally methods to “remove
n
elements” taken at the end of the collection (removeElementsLinkedList
,removeElementsArrayList
).
Reflexion time
Take time to make your opinion on a hierarchy of the most consuming methods among the 6 above methods. Would it be the same hierarchy if we had done
“add
n
elements” at the beginning of the collection“remove
n
elements” at the beginning of the collection
Main class#
The Main.java
file contains the main()
method which simply parses the input arguments to get the number of elements
to store in the collections and then create the collections, add, access and remove
elements in the two kinds of collections.
Perform measurements#
First compile the application:
javac measureJavaCollections/*.java
To launch the application with JoularJX, see the readme.md
file. The command to launch has the following form:
bash main.sh measureJavaCollections.Main <number_of_elements_in_a_collection> <number_of_times_to_launch>
The higher number_of_times_to_launch
is, the more times we launch the program, and the more accurate we are for making means and standard deviations.
Experiment with filtering#
Experiment for measuring the consumption of the different methods present in the package. Initially, no filtering is performed.
Then modify the config.properties
files (See the explanations on the config.properties file in Part 1) to monitor:
The
measureJavaCollections
package (that is all the methods of all the classes in the package)The
measureJavaCollections.TestArrayList.addElementsArrayList,measureJavaCollections.TestLinkedList.addElementsLinkedList
methodsThe
measureJavaCollections.TestArrayList.accessElementsArrayList,measureJavaCollections.TestLinkedList.accessElementsLinkedList
methodsThe
measureJavaCollections.TestArrayList.removeElementsArrayList,measureJavaCollections.TestLinkedList.removeElementsLinkedList
methods
After each modification of the config.properties
file, launch the main.sh
script.
NB: You may have to ADAPT the size of the collection according to your computer:
You may begin with a collection of 200000 elements and 1 run (to adapt the size of the collection for an acceptable duration time (below one minute) before augmenting the number of runs for a better standard deviation).
bash main.sh measureJavaCollections.Main 200000 2
REDUCE the collection size if the execution time is too high (e.g. above 1 min).
INCREASE the collection size if the energy is too low to be detectable.
Detect the most consuming method (e.g. TestLinkedList.accessElementsLinkedList
), remove the call to this method from the Main
class to reduce the execution time, and lauch the experiment again to be able to compare the other methods (NB: Do not remove the add method that is creating
the collection !).
Analyze the different results obtained and try to identify what collection is the most energy-efficient in the following cases:
To add elements (at the end of the collection),
To access elements by their index,
To remove elements (beginning at the end of the collection).
Verify your results and check whether you get the same results as in this catalog of good practices. Take this opportunity to explore the catalog as we will use it in the next lab.