Skip to content

Commit

Permalink
Merge pull request #69 from joular/develop
Browse files Browse the repository at this point in the history
Version 2.8.3
  • Loading branch information
adelnoureddine authored Mar 29, 2024
2 parents 3ed30c0 + 2af2221 commit f45f499
Show file tree
Hide file tree
Showing 16 changed files with 136 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ JoularJX can be configured by modifying the ```config.properties``` files:
- ```enable-call-trees-consumption```: compute methods call trees energy consumption. A CSV file will be generated at the end of the agent's execution, associating to each call tree it's total energy consumption.
- ```save-call-trees-runtime-data```: write runtime call trees power consumption in a CSV file. For each monitoring cycle (1 second), a new CSV file will be generated, containing the runtime power consumption of the call trees. The generated files will include timestamps in their names.
- ```overwrite-call-trees-runtime-data```: overwrite runtime call trees power data file, or if set to false, it will write new file for each monitoring cycle.
- ```application-server```: properly handles application servers and frameworks (Sprig Boot, Tomcat, etc.). Set ```true``` when running on application servers. If false, the monitoring loop will check if the JVM is destroyed, hence closing JoularJX when the application ends (in regular Java application). If true, JoularJX will continue to monitor correctly as the JVM isn't destroyed in a application server.

You can install the jar package (and the PowerMonitor.exe on Windows) wherever you want, and call it in the ```javaagent``` with the full path.
However, ```config.properties``` must be copied to the same folder as where you run the Java command.
Expand Down
6 changes: 6 additions & 0 deletions config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ overwrite-call-trees-runtime-data=true
# from 1 to 1000.
stack-monitoring-sample-rate=10

# If running the application on top of an application server or framework (spring, tomcat, etc.)
# This changes how JoularJX loops when monitoring, using a while-true loop instead of a checking if the JVM is destroyed
# On standard Java applications, the while-true loop don't quit when the application ends, hence why destroying the VM
# Values: true, false
application-server=false

# Path for our power monitor program on Windows
# On Windows, please escape slashes twice
powermonitor-path=C:\\joularjx\\PowerMonitor.exe
6 changes: 6 additions & 0 deletions install/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ overwrite-call-trees-runtime-data=true
# from 1 to 1000.
stack-monitoring-sample-rate=10

# If running the application on top of an application server or framework (spring, tomcat, etc.)
# This changes how JoularJX loops when monitoring, using a while-true loop instead of a checking if the JVM is destroyed
# On standard Java applications, the while-true loop don't quit when the application ends, hence why destroying the VM
# Values: true, false
application-server=false

# Path for our power monitor program on Windows
# On Windows, please escape slashes twice
powermonitor-path=C:\\joularjx\\PowerMonitor.exe
Binary file removed install/joularjx-2.8.2.jar
Binary file not shown.
Binary file added install/joularjx-2.8.3.jar
Binary file not shown.
25 changes: 25 additions & 0 deletions install/windows-install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (c) 2021-2024, Adel Noureddine, Université de Pau et des Pays de l'Adour.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the
# GNU General Public License v3.0 only (GPL-3.0-only)
# which accompanies this distribution, and is available at
# https://www.gnu.org/licenses/gpl-3.0.en.html
#
# Author : Adel Noureddine

$host.UI.RawUI.WindowTitle = "JoularJX Windows Installer"

$INSTALLATION_PATH = "C:\joularjx"

$USER_CONFIRMATION = Read-Host "Installation to $INSTALLATION_PATH. Continue ([y]/n)"
if ($USER_CONFIRMATION -ine "y") {
exit
}

New-Item -ItemType Directory -Force -Path $INSTALLATION_PATH
Copy-Item "joularjx-*.jar" -Destination $INSTALLATION_PATH
Copy-Item "config.properties" -Destination $INSTALLATION_PATH
Copy-Item "PowerMonitor.exe" -Destination $INSTALLATION_PATH
Write-Host "Installation complete. JoularJX files installed in $INSTALLATION_PATH"

Read-Host "Press Enter to continue..."
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<groupId>org.noureddine</groupId>
<artifactId>joularjx</artifactId>
<version>2.8.2</version>
<version>2.8.3</version>

<packaging>jar</packaging>
<name>${project.artifactId}</name>
Expand Down Expand Up @@ -71,7 +71,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.10.1</version>
<version>5.10.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
Expand All @@ -83,7 +83,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version>
<version>3.13.0</version>
<configuration>
<debug>true</debug>
</configuration>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/noureddine/joularjx/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static void premain(String args, Instrumentation inst) {
JoularJXLogging.updateLevel(properties.getLoggerLevel());

logger.info("+---------------------------------+");
logger.info("| JoularJX Agent Version 2.8.2 |");
logger.info("| JoularJX Agent Version 2.8.3 |");
logger.info("+---------------------------------+");

ThreadMXBean threadBean = createThreadBean();
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/noureddine/joularjx/cpu/Cpu.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public interface Cpu extends AutoCloseable {
double getInitialPower();

double getCurrentPower(double cpuLoad);

double getMaxPower(double cpuLoad);
}
7 changes: 7 additions & 0 deletions src/main/java/org/noureddine/joularjx/cpu/IntelWindows.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,11 @@ public void close() {
process.destroy();
}
}

/**
* Nothing to do here. Method only useful for RAPL
*/
public double getMaxPower(final double cpuLoad) {
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,11 @@ public void close() {
process.destroy();
}
}

/**
* Nothing to do here. Method only useful for RAPL
*/
public double getMaxPower(final double cpuLoad) {
return 0;
}
}
40 changes: 40 additions & 0 deletions src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,23 @@ public class RaplLinux implements Cpu {

static final String RAPL_DRAM = "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2/energy_uj";

static final String RAPL_PSYS_MAX = "/sys/class/powercap/intel-rapl/intel-rapl:1/max_energy_range_uj";

static final String RAPL_PKG_MAX = "/sys/class/powercap/intel-rapl/intel-rapl:0/max_energy_range_uj";

static final String RAPL_DRAM_MAX = "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2/max_energy_range_uj";

/**
* RAPL files existing on the current system. All files in this list will be used for reading the
* energy values.
*/
private final List<Path> raplFilesToRead = new ArrayList<>(3);

/**
* RAPL max values files existing on the current system. All files in this list will be used for reading the energy values.
*/
private final List<Path> maxRaplFilesToRead = new ArrayList<>(3);

/**
* Filesystem where the RAPL files are located.
*/
Expand Down Expand Up @@ -66,23 +77,32 @@ public RaplLinux() {
@Override
public void initialize() {
final Path psysFile = fileSystem.getPath(RAPL_PSYS);
final Path psysMaxFile = fileSystem.getPath(RAPL_PSYS_MAX);
if (Files.exists(psysFile)) {
checkFileReadable(psysFile);
checkFileReadable(psysMaxFile);
// psys exists, so use this for energy readings
raplFilesToRead.add(psysFile);
maxRaplFilesToRead.add(psysMaxFile);
} else {
// No psys supported, then check for pkg and dram
final Path pkgFile = fileSystem.getPath(RAPL_PKG);
final Path pkgMaxFile = fileSystem.getPath(RAPL_PKG_MAX);
if (Files.exists(pkgFile)) {
checkFileReadable(pkgFile);
checkFileReadable(pkgMaxFile);
// pkg exists, check also for dram
raplFilesToRead.add(pkgFile);
maxRaplFilesToRead.add(pkgMaxFile);

final Path dramFile = fileSystem.getPath(RAPL_DRAM);
final Path dramMaxFile = fileSystem.getPath(RAPL_DRAM_MAX);
if (Files.exists(dramFile)) {
checkFileReadable(dramFile);
checkFileReadable(dramMaxFile);
// dram and pkg exists, then get sum of both
raplFilesToRead.add(dramFile);
maxRaplFilesToRead.add(dramMaxFile);
}
}
}
Expand Down Expand Up @@ -126,6 +146,26 @@ public double getCurrentPower(final double cpuLoad) {
return energyData / 1000000;
}

/**
* Get max energy value of RAPL interface through powercap
* @return Maximum energy value of RAPL interface
*/
@Override
public double getMaxPower(final double cpuLoad) {
double energyData = 0.0;

for (final Path raplFile : maxRaplFilesToRead) {
try {
energyData += Double.parseDouble(Files.readString(raplFile));
} catch (IOException exception) {
logger.throwing(getClass().getName(), "getMaxPower", exception);
}
}

// Divide by 1 million to convert microJoules to Joules
return energyData / 1000000;
}

/**
* Returns the
*
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/noureddine/joularjx/cpu/RaspberryPi.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,11 @@ public double getInitialPower() {
public void close() {
// Nothing to do for Raspberry Pi
}

/**
* Nothing to do here. Method only useful for RAPL
*/
public double getMaxPower(final double cpuLoad) {
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ public void run() {
double energyAfter = cpu.getCurrentPower(cpuLoad);
double cpuEnergy = energyAfter - energyBefore;

// Check if energy after is smaller than before
// Meaning: RAPL energy has wrapped
if (energyBefore > energyAfter) {
cpuEnergy += cpu.getMaxPower(cpuLoad);
}

// if cpuEnergy is negative, skip this cycle.
// this happens when energy counter is reset during program execution
if (cpuEnergy < 0) {
Expand Down Expand Up @@ -395,7 +401,11 @@ public <K> void saveResults(Map<Thread, Map<K,Integer>> stats, Map<Long, Double
* @return true if the JVM destroying thread is present, false otherwise
*/
private boolean destroyingVM() {
return Thread.getAllStackTraces().keySet().stream()
if (!this.properties.isApplicationServer()) {
return Thread.getAllStackTraces().keySet().stream()
.anyMatch(thread -> thread.getName().equals(DESTROY_THREAD_NAME));
} else {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class AgentProperties {
private static final String SAVE_CT_RUNTIME_DATA_PROPERTY = "save-call-trees-runtime-data";
private static final String OVERWRITE_CT_RUNTIME_DATA_PROPERTY = "overwrite-call-trees-runtime-data";
private static final String STACK_MONITORING_SAMPLE_RATE_PROPERTY = "stack-monitoring-sample-rate";
private static final String APPLICATION_SERVER_PROPERTY = "application-server";

/**
* Loaded configuration properties
Expand All @@ -58,6 +59,7 @@ public class AgentProperties {
private final boolean saveCtRuntimeData;
private final boolean overwriteCtRuntimeData;
private final int stackMonitoringSampleRate;
private final boolean applicationServer;

/**
* Instantiate a new instance which will load the properties
Expand All @@ -76,6 +78,7 @@ public AgentProperties(FileSystem fileSystem) {
this.saveCtRuntimeData = loadSaveCallTreesRuntimeData();
this.overwriteCtRuntimeData = loadOverwriteCallTreeRuntimeData();
this.stackMonitoringSampleRate = loadStackMonitoringSampleRate();
this.applicationServer = loadApplicationServer();
}

public AgentProperties() {
Expand Down Expand Up @@ -127,6 +130,8 @@ public boolean saveCallTreesRuntimeData() {

public int stackMonitoringSampleRate() { return this.stackMonitoringSampleRate; }

public boolean isApplicationServer() { return this.applicationServer; }

private Properties loadProperties(FileSystem fileSystem) {
Properties result = new Properties();

Expand Down Expand Up @@ -195,6 +200,10 @@ public boolean loadOverwriteCallTreeRuntimeData() {
return Boolean.parseBoolean(properties.getProperty(OVERWRITE_CT_RUNTIME_DATA_PROPERTY));
}

public boolean loadApplicationServer() {
return Boolean.parseBoolean(properties.getProperty(APPLICATION_SERVER_PROPERTY));
}

public int loadStackMonitoringSampleRate() {
String property = properties.getProperty(STACK_MONITORING_SAMPLE_RATE_PROPERTY);
int value = 10; // default of 10 milliseconds
Expand Down
11 changes: 11 additions & 0 deletions src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ void noRaplFilesFound() {
@Test
void psysFileSupported() throws IOException {
Path psys = fileSystem.getPath(RaplLinux.RAPL_PSYS);
Path psysMax = fileSystem.getPath(RaplLinux.RAPL_PSYS_MAX);
Files.createDirectories(psys.getParent());
Files.writeString(psys, "1000000");
Files.writeString(psysMax, "1000000");

cpu.initialize();

Expand All @@ -70,8 +72,10 @@ void psysFileSupported() throws IOException {
@Test
void pkgFileSupported() throws IOException {
Path pkg = fileSystem.getPath(RaplLinux.RAPL_PKG);
Path pkgMax = fileSystem.getPath(RaplLinux.RAPL_PKG_MAX);
Files.createDirectories(pkg.getParent());
Files.writeString(pkg, "1000000");
Files.writeString(pkgMax, "1000000");

cpu.initialize();

Expand All @@ -83,11 +87,16 @@ void pkgAndDramFileSupported() throws IOException {
Path pkg = fileSystem.getPath(RaplLinux.RAPL_PKG);
Path dram = fileSystem.getPath(RaplLinux.RAPL_DRAM);

Path pkgMax = fileSystem.getPath(RaplLinux.RAPL_PKG_MAX);
Path dramMax = fileSystem.getPath(RaplLinux.RAPL_DRAM_MAX);

Files.createDirectories(pkg.getParent());
Files.createDirectories(dram.getParent());

Files.writeString(pkg, "1000000");
Files.writeString(dram, "1000000");
Files.writeString(pkgMax, "1000000");
Files.writeString(dramMax, "1000000");

cpu.initialize();

Expand All @@ -98,8 +107,10 @@ void pkgAndDramFileSupported() throws IOException {
@ExpectSystemExitWithStatus(1)
void raplFileNotReadable() throws IOException {
Path psys = fileSystem.getPath(RaplLinux.RAPL_PSYS);
Path psysMax = fileSystem.getPath(RaplLinux.RAPL_PSYS_MAX);
Files.createDirectories(psys.getParent());
Files.writeString(psys, "1000000");
Files.writeString(psysMax, "1000000");

assertTrue(Files.isReadable(psys));
assertTrue(Files.isWritable(psys));
Expand Down

0 comments on commit f45f499

Please sign in to comment.