From ffa9e5444af5127511734b3a04de30b286d3b354 Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Wed, 1 Nov 2023 15:23:19 +0100 Subject: [PATCH 01/14] potential fix for issue: https://github.com/joular/joularjx/issues/7 --- .../org/noureddine/joularjx/monitor/MonitoringHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java index 5b48f9a..0a8bc38 100644 --- a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java +++ b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java @@ -261,8 +261,10 @@ private long updateThreadsCpuTime(Map> methodsStats threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; // If thread already monitored, then calculate CPU time since last time + // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) + // If the last thread cpu time is 0, don't subtract, simply take the previous value threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, - (present, newValue) -> newValue - present); + (present, newValue) -> (newValue > 0 ? newValue - present : present)); totalThreadsCpuTime += threadCpuTime; } From b9b98e53b96b3c5b1d7e2c8d45521c1b99c620e5 Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Fri, 3 Nov 2023 14:09:55 +0100 Subject: [PATCH 02/14] fix for issue #7, changed version in pom --- pom.xml | 4 +-- .../joularjx/cpu/PowermetricsMacOS.java | 11 +++++--- .../joularjx/monitor/MonitoringHandler.java | 27 ++++++++++--------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 78d794b..7b8e079 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.noureddine joularjx - 2.8.0 + 2.8.0a jar ${project.artifactId} @@ -115,4 +115,4 @@ - \ No newline at end of file + diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index dfb9be8..d0082f3 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -44,14 +44,17 @@ public double getCurrentPower(double cpuLoad) { BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = input.readLine()) != null) { - // look for line that contains combined power measurement + // look for line that contains combined power measurement // which should look similar to: `Combined Power (CPU + GPU + ANE): 377 mW` - if (!line.startsWith("Combined")) { + // it seems this output is for older versions (?), current version (Sonoma 14.0) gives the following line: + // `Intel energy model derived package power (CPUs+GT+SA): 48.61W` + if (!line.startsWith("Intel energy model derived package power")) { continue; } final var powerValue = line.split(":")[1]; - final var powerInMilliwatts = powerValue.split("m")[0]; - return Double.parseDouble(powerInMilliwatts) / 1000; + final var powerInMilliwatts = powerValue.split("W")[0]; + //logger.info("Current power (w): " + powerInMilliwatts); + return Double.parseDouble(powerInMilliwatts); // / 1000; // NOTE not needed to divide by 1000 since the values is not in mW! } } catch (Exception exception) { logger.throwing(getClass().getName(), "getCurrentPower", exception); diff --git a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java index 0a8bc38..9d1728a 100644 --- a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java +++ b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java @@ -14,8 +14,10 @@ import java.lang.management.ThreadMXBean; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.function.ObjDoubleConsumer; import java.util.function.Predicate; import java.util.logging.Level; @@ -256,21 +258,22 @@ private Map> extractCallTreesStats(Map> methodsStats, Map threadsCpuTime) { long totalThreadsCpuTime = 0; for (var entry : methodsStats.entrySet()) { - long threadCpuTime = threadBean.getThreadCpuTime(entry.getKey().getId()); - - threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; - - // If thread already monitored, then calculate CPU time since last time - // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) - // If the last thread cpu time is 0, don't subtract, simply take the previous value - threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, - (present, newValue) -> (newValue > 0 ? newValue - present : present)); - - totalThreadsCpuTime += threadCpuTime; + // the call could return a value of -1, which means thread not found or otherwise some other problem in reading cpu time for the PID + long threadCpuTime = Math.abs(threadBean.getThreadCpuTime(entry.getKey().getId())); + + threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; + + // If thread already monitored, then calculate CPU time since last time + // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) + // If the last thread cpu time is <= 0, don't subtract, simply take the previous value + threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, + (present, newValue) -> (newValue > present?newValue - present:present)); + + totalThreadsCpuTime += threadCpuTime; } return totalThreadsCpuTime; } - + /** * Returns for each thread (PID) it's percentage of CPU time used * @param threadsCpuTime a map of CPU time per PID From 0615d740e62d4b3eebe73cb672723c6f75649c51 Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Mon, 20 Nov 2023 15:16:53 +0100 Subject: [PATCH 03/14] fixing the problem of negative values --- .../noureddine/joularjx/cpu/RaplLinux.java | 4 +- .../joularjx/monitor/MonitoringHandler.java | 139 ++++++++++++------ 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java b/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java index 9a2fbe0..ede5dd7 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java +++ b/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java @@ -19,7 +19,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,7 +39,7 @@ public class RaplLinux implements Cpu { * RAPL files existing on the current system. All files in this list will be used for reading the * energy values. */ - private final List raplFilesToRead = new ArrayList<>(3); + private final Set raplFilesToRead = new HashSet<>(3); /** * Filesystem where the RAPL files are located. diff --git a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java index 9d1728a..af47f58 100644 --- a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java +++ b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java @@ -108,7 +108,14 @@ public void run() { double energyAfter = cpu.getCurrentPower(cpuLoad); double cpuEnergy = energyAfter - energyBefore; - + + // if cpuEnergy is negative, skip this cycle. + // this happens when energy counter is reset during program execution + if (cpuEnergy < 0) { + logger.info("Negative energy delta detected, skipping this cycle: " + cpuEnergy); + continue; + } + // Calculate CPU energy consumption of the process of the JVM all its apps double processEnergy = calculateProcessCpuEnergy(cpuLoad, processCpuLoad, cpuEnergy); @@ -119,9 +126,11 @@ public void run() { // CPU energy for JVM process // CPU energy for all processes // We need to calculate energy for each thread - long totalThreadsCpuTime = updateThreadsCpuTime(methodsStats, threadsCpuTime); - var threadCpuTimePercentages = getThreadsCpuTimePercentage(threadsCpuTime, totalThreadsCpuTime, processEnergy); +// long totalThreadsCpuTime = updateThreadsCpuTime(methodsStats, threadsCpuTime); +// var threadCpuTimePercentages = getThreadsCpuTimePercentage(threadsCpuTime, totalThreadsCpuTime, processEnergy); + var threadCpuTimePercentages = getThreadsCpuTimePercentage(methodsStats, threadsCpuTime, processEnergy); + updateMethodsConsumedEnergy(methodsStats, threadCpuTimePercentages, status::addMethodConsumedEnergy, Scope.ALL); updateMethodsConsumedEnergy(methodsStatsFiltered, threadCpuTimePercentages, status::addFilteredMethodConsumedEnergy, Scope.FILTERED); @@ -164,7 +173,7 @@ public void run() { } } - /** + /** * Performs the sampling step. Collects a set of stack traces for each thread. * The sampling step is performed multiple time at the frequecy of SAMPLE_RATE_MILLSECONDS, for the duration of SAMPLE_TIME_MILLISECONDS * @return for each Thread, a List of it's the stack traces @@ -249,50 +258,92 @@ private Map> extractCallTreesStats(Map> methodsStats, Map threadsCpuTime) { +// long totalThreadsCpuTime = 0; +// for (var entry : methodsStats.entrySet()) { +// // the call could return a value of -1, which means thread not found or otherwise some other problem in reading cpu time for the PID +// long threadCpuTime = threadBean.getThreadCpuTime(entry.getKey().getId()); +// +// threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; +// +// // If thread already monitored, then calculate CPU time since last time +// // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) +// // If the last thread cpu time is <= 0, don't subtract, simply take the previous value +// threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, +// (present, newValue) -> newValue - present); +// +// totalThreadsCpuTime += threadCpuTime; +// } +// return totalThreadsCpuTime; +// } +// +// /** +// * Returns for each thread (PID) it's percentage of CPU time used +// * @param threadsCpuTime a map of CPU time per PID +// * @param totalThreadsCpuTime the CPU time used by all the monitored threads +// * @param processEnergy the energy consumed by the process +// * @return for each PID, the percentage of CPU time used by the associated thread +// */ +// private Map getThreadsCpuTimePercentage(Map threadsCpuTime, +// long totalThreadsCpuTime, +// double processEnergy) { +// Map threadsPower = new HashMap<>(); +// for (var entry : threadsCpuTime.entrySet()) { +// double percentageCpuTime = (entry.getValue() * 100.0) / totalThreadsCpuTime; +// double threadPower = processEnergy * (percentageCpuTime / 100.0); +// threadsPower.put(entry.getKey(), threadPower); +// } +// return threadsPower; +// } + + /** - * Updates the CPU times for each Thread. - * @param methodsStats a map of method occurences for each thread - * @param threadsCpuTime a map of CPU time per PID - * @return the total CPU time used by all the monitored threads + * + * @param methodsStats a map of method occurrences for each thread + * @param threadsCpuTime a map of CPU time per PID, contains the cpu time for each tread, resulting from the last call to getThreadCpuTime(threadId) + * @param processEnergy the energy consumed by the process in the last monitoring period + * @return for each PID, the percentage of energy used by the associated thread */ - private long updateThreadsCpuTime(Map> methodsStats, Map threadsCpuTime) { - long totalThreadsCpuTime = 0; - for (var entry : methodsStats.entrySet()) { - // the call could return a value of -1, which means thread not found or otherwise some other problem in reading cpu time for the PID - long threadCpuTime = Math.abs(threadBean.getThreadCpuTime(entry.getKey().getId())); - - threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; - - // If thread already monitored, then calculate CPU time since last time - // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) - // If the last thread cpu time is <= 0, don't subtract, simply take the previous value - threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, - (present, newValue) -> (newValue > present?newValue - present:present)); + private Map getThreadsCpuTimePercentage(Map> methodsStats, + Map threadsCpuTime, double processEnergy) { + Map threadsCpuTimePercentage = new HashMap(); + + Map actualThreadsCpuTime = new HashMap(); + double totalThreadsCpuTime = 0; + // first compute the proportion of cpu time for each thread in the last sampling period + for (Entry> threadEntry : methodsStats.entrySet()) { + long threadId = threadEntry.getKey().getId(); + long currentThreadCpuTime = threadBean.getThreadCpuTime(threadId); + long previousThreadCpuTime = threadsCpuTime.getOrDefault(threadId, 0l); + if (currentThreadCpuTime < 0) { // thread has quit + // TODO ignore last sampling period?? + currentThreadCpuTime = previousThreadCpuTime + 1; // FIXME assume interval of 1 nanosecond, ok?? + logger.info("Thread CPU time negative, taking previous time + 1: " + currentThreadCpuTime + " for thread: " + threadId); + } - totalThreadsCpuTime += threadCpuTime; - } - return totalThreadsCpuTime; - } + threadsCpuTime.put(threadId, currentThreadCpuTime); + long delta = currentThreadCpuTime - previousThreadCpuTime; + double adjustedThreadCpuTime = delta * threadEntry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; + totalThreadsCpuTime += adjustedThreadCpuTime; + actualThreadsCpuTime.put(threadId, adjustedThreadCpuTime); + } + + logger.info("Going to divide total process energy: " + processEnergy + ", over total threads cpu time: " + totalThreadsCpuTime); + // compute the proportion of total energy consumed by the thread using its proportion of cpu time in the last sampling period + for (Entry threadEntry : actualThreadsCpuTime.entrySet()) { + double threadEnergy = totalThreadsCpuTime > 0d?threadEntry.getValue() * processEnergy / totalThreadsCpuTime : 0d; + threadsCpuTimePercentage.put(threadEntry.getKey(), threadEnergy); + } + + return threadsCpuTimePercentage; + } - /** - * Returns for each thread (PID) it's percentage of CPU time used - * @param threadsCpuTime a map of CPU time per PID - * @param totalThreadsCpuTime the CPU time used by all the monitored threads - * @param processEnergy the energy consumed by the process - * @return for each PID, the percentage of CPU time used by the associated thread - */ - private Map getThreadsCpuTimePercentage(Map threadsCpuTime, - long totalThreadsCpuTime, - double processEnergy) { - Map threadsPower = new HashMap<>(); - for (var entry : threadsCpuTime.entrySet()) { - double percentageCpuTime = (entry.getValue() * 100.0) / totalThreadsCpuTime; - double threadPower = processEnergy * (percentageCpuTime / 100.0); - threadsPower.put(entry.getKey(), threadPower); - } - return threadsPower; - } - /** * Update method's consumed energy. * @param methodsStats method's encounters statistics per Thread From f03b85b8534b87f71ec6a48d762ae3a76b10abf8 Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Fri, 24 Nov 2023 12:57:10 +0100 Subject: [PATCH 04/14] removing log statement --- .../java/org/noureddine/joularjx/monitor/MonitoringHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java index af47f58..c2a29d4 100644 --- a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java +++ b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java @@ -334,7 +334,6 @@ private Map getThreadsCpuTimePercentage(Map threadEntry : actualThreadsCpuTime.entrySet()) { double threadEnergy = totalThreadsCpuTime > 0d?threadEntry.getValue() * processEnergy / totalThreadsCpuTime : 0d; From 3270dad18a7f6bbce070fa20a970bd8c0430e181 Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Mon, 8 Jan 2024 18:01:34 +0100 Subject: [PATCH 05/14] Add support for Raspberry Pi 5B --- README.md | 3 +- .../noureddine/joularjx/cpu/CpuFactory.java | 12 +- .../noureddine/joularjx/cpu/RaspberryPi.java | 399 +++++++++--------- .../joularjx/cpu/RaspberryPiModels.java | 53 +-- 4 files changed, 244 insertions(+), 223 deletions(-) diff --git a/README.md b/README.md index e31d536..0488eca 100755 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ JoularJX depend on the following software or packages in order to get power read - On Windows, JoularJX uses a custom power monitor program that uses Intel Power Gadget API on Windows, and therefore require installing the [Intel Power Gadget tool](https://www.intel.com/content/www/us/en/developer/articles/tool/power-gadget.html) and using a supported Intel CPU. - On PC/server GNU/Linux, JoularJX uses Intel RAPL interface through powercap, and therefore requires running on an Intel CPU or an AMD Ryzen CPU. - On macOS, JoularJX uses `powermetrics`, a tool bundled with macOS which requires running with `sudo` access. It is recommended to authorize the current users to run `/usr/bin/powermetrics` without requiring a password by making the proper modification to the `sudoers` file. -- On Raspberry Pi devices on GNU/Linux, JoularJX uses our own research-based regression models to estimate CPU power consumption with support for the following device models: +- On Raspberry Pi devices on GNU/Linux, JoularJX uses our own research-based regression models to estimate CPU power consumption with support for the following device models (we support all revisions of each model lineup. However, the model is generated and trained on a specific revision, listed between brackets, and the accuracy is best on this particular revision): - Model Zero W (rev 1.1), for 32-bit OS - Model 1 B (rev 2), for 32-bit OS - Model 1 B+ (rev 1.2), for 32-bit OS @@ -40,6 +40,7 @@ JoularJX depend on the following software or packages in order to get power read - Model 3 B+ (rev 1.3), for 32-bit OS - Model 4 B (rev 1.1, and rev 1.2), for both 32 bits and 64-bit OS - Model 400 (rev 1.0), for 64-bit OS + - Model 5 B (rev 1.0), for 64 bits OS We also support Asus Tinker Board (S). diff --git a/src/main/java/org/noureddine/joularjx/cpu/CpuFactory.java b/src/main/java/org/noureddine/joularjx/cpu/CpuFactory.java index bc90788..6325345 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/CpuFactory.java +++ b/src/main/java/org/noureddine/joularjx/cpu/CpuFactory.java @@ -101,7 +101,11 @@ private static Optional getRPiModelName(String osArch) { List allLines = Files.readAllLines(deviceTreeModelPath); for (String currentLine : allLines) { // SBC models and revisions - if (currentLine.contains("Raspberry Pi 400 Rev 1.0")) { + if (currentLine.contains("Raspberry Pi 5 Model B Rev 1.0")) { + if (osArch.contains("aarch64")) { + return Optional.of(RaspberryPiModels.RPI_5B_10_64); + } + } else if (currentLine.contains("Raspberry Pi 400 Rev 1.0")) { if (osArch.contains("aarch64")) { return Optional.of(RaspberryPiModels.RPI_400_10_64); } @@ -135,7 +139,11 @@ private static Optional getRPiModelName(String osArch) { // Support other revisions of supported SBC models // By using existing power models of related revision - if (currentLine.contains("Raspberry Pi 400")) { + if (currentLine.contains("Raspberry Pi 5 Model B")) { + if (osArch.contains("aarch64")) { + return Optional.of(RaspberryPiModels.RPI_5B_10_64); + } + } else if (currentLine.contains("Raspberry Pi 400")) { if (osArch.contains("aarch64")) { return Optional.of(RaspberryPiModels.RPI_400_10_64); } diff --git a/src/main/java/org/noureddine/joularjx/cpu/RaspberryPi.java b/src/main/java/org/noureddine/joularjx/cpu/RaspberryPi.java index 880dbaa..6002b6d 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/RaspberryPi.java +++ b/src/main/java/org/noureddine/joularjx/cpu/RaspberryPi.java @@ -1,195 +1,206 @@ -/* - * Copyright (c) 2021-2023, 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 - */ - -package org.noureddine.joularjx.cpu; - -public class RaspberryPi implements Cpu { - - /** - * Raspberry Pi model name - */ - private final RaspberryPiModels rpiModel; - - public RaspberryPi(final RaspberryPiModels rpiModel) { - this.rpiModel = rpiModel; - } - - /** - * Calculate CPU energy consumption for last second (power) on supported Raspberry Pi devices - * @param rpiModel Raspberry Pi model - * @param cpuUsage CPU usage - * @return CPU energy consumption for last second (power) - */ - private double calculateCpuEnergyForRaspberryPi(final RaspberryPiModels rpiModel, final double cpuUsage) { - double result = 0.0; - - switch (rpiModel) { - case RPI_400_10_64: - result = 2.6630056198236938 + (0.82814554 * cpuUsage) + - (-112.17687631 * Math.pow(cpuUsage, 2)) + - (1753.99173239 * Math.pow(cpuUsage, 3)) + - (-10992.65341181 * Math.pow(cpuUsage, 4)) + - (35988.45610911 * Math.pow(cpuUsage, 5)) + - (-66254.20051068 * Math.pow(cpuUsage, 6)) + - (69071.21138567 * Math.pow(cpuUsage, 7)) + - (-38089.87171735 * Math.pow(cpuUsage, 8)) + - (8638.45610698 * Math.pow(cpuUsage, 9)); - break; - case RPI_4B_12_64: - result = 3.039940056604439 + (-3.074225 * cpuUsage) + - (47.753114 * Math.pow(cpuUsage, 2)) + - (-271.974551 * Math.pow(cpuUsage, 3)) + - (879.966571 * Math.pow(cpuUsage, 4)) + - (-1437.466442 * Math.pow(cpuUsage, 5)) + - (1133.325791 * Math.pow(cpuUsage, 6)) + - (-345.134888 * Math.pow(cpuUsage, 7)); - break; - case RPI_4B_12: - result = 2.58542069543335 + (12.335449 * cpuUsage) + - (-248.010554 * Math.pow(cpuUsage, 2)) + - (2379.832320 * Math.pow(cpuUsage, 3)) + - (-11962.419149 * Math.pow(cpuUsage, 4)) + - (34444.268647 * Math.pow(cpuUsage, 5)) + - (-58455.266502 * Math.pow(cpuUsage, 6)) + - (57698.685016 * Math.pow(cpuUsage, 7)) + - (-30618.557703 * Math.pow(cpuUsage, 8)) + - (6752.265368 * Math.pow(cpuUsage, 9)); - break; - case RPI_4B_11_64: - result = 3.405685008777926 + (-11.834416 * cpuUsage) + - (137.312822 * Math.pow(cpuUsage, 2)) + - (-775.891511 * Math.pow(cpuUsage, 3)) + - (2563.399671 * Math.pow(cpuUsage, 4)) + - (-4783.024354 * Math.pow(cpuUsage, 5)) + - (4974.960753 * Math.pow(cpuUsage, 6)) + - (-2691.923074 * Math.pow(cpuUsage, 7)) + - (590.355251 * Math.pow(cpuUsage, 8)); - break; - case RPI_4B_11: - result = 2.5718068562852086 + (2.794871 * cpuUsage) + - (-58.954883 * Math.pow(cpuUsage, 2)) + - (838.875781 * Math.pow(cpuUsage, 3)) + - (-5371.428686 * Math.pow(cpuUsage, 4)) + - (18168.842874 * Math.pow(cpuUsage, 5)) + - (-34369.583554 * Math.pow(cpuUsage, 6)) + - (36585.681749 * Math.pow(cpuUsage, 7)) + - (-20501.307640 * Math.pow(cpuUsage, 8)) + - (4708.331490 * Math.pow(cpuUsage, 9)); - break; - case RPI_3BP_13: - result = 2.484396997449118 + (2.933542 * cpuUsage) + - (-150.400134 * Math.pow(cpuUsage, 2)) + - (2278.690310 * Math.pow(cpuUsage, 3)) + - (-15008.559279 * Math.pow(cpuUsage, 4)) + - (51537.315529 * Math.pow(cpuUsage, 5)) + - (-98756.887779 * Math.pow(cpuUsage, 6)) + - (106478.929766 * Math.pow(cpuUsage, 7)) + - (-60432.910139 * Math.pow(cpuUsage, 8)) + - (14053.677709 * Math.pow(cpuUsage, 9)); - break; - case RPI_3B_12: - result = 1.524116907651687 + (10.053851 * cpuUsage) + - (-234.186930 * Math.pow(cpuUsage, 2)) + - (2516.322119 * Math.pow(cpuUsage, 3)) + - (-13733.555536 * Math.pow(cpuUsage, 4)) + - (41739.918887 * Math.pow(cpuUsage, 5)) + - (-73342.794259 * Math.pow(cpuUsage, 6)) + - (74062.644914 * Math.pow(cpuUsage, 7)) + - (-39909.425362 * Math.pow(cpuUsage, 8)) + - (8894.110508 * Math.pow(cpuUsage, 9)); - break; - case RPI_2B_11: - result = 1.3596870187778196 + (5.135090 * cpuUsage) + - (-103.296366 * Math.pow(cpuUsage, 2)) + - (1027.169748 * Math.pow(cpuUsage, 3)) + - (-5323.639404 * Math.pow(cpuUsage, 4)) + - (15592.036875 * Math.pow(cpuUsage, 5)) + - (-26675.601585 * Math.pow(cpuUsage, 6)) + - (26412.963366 * Math.pow(cpuUsage, 7)) + - (-14023.471809 * Math.pow(cpuUsage, 8)) + - (3089.786200 * Math.pow(cpuUsage, 9)); - break; - case RPI_1BP_12: - result = 1.2513999338064061 + (1.857815 * cpuUsage) + - (-18.109537 * Math.pow(cpuUsage, 2)) + - (101.531231 * Math.pow(cpuUsage, 3)) + - (-346.386617 * Math.pow(cpuUsage, 4)) + - (749.560352 * Math.pow(cpuUsage, 5)) + - (-1028.802514 * Math.pow(cpuUsage, 6)) + - (863.877618 * Math.pow(cpuUsage, 7)) + - (-403.270951 * Math.pow(cpuUsage, 8)) + - (79.925932 * Math.pow(cpuUsage, 9)); - break; - case RPI_1B_2: - result = 2.826093843916506 + (3.539891 * cpuUsage) + - (-43.586963 * Math.pow(cpuUsage, 2)) + - (282.488560 * Math.pow(cpuUsage, 3)) + - (-1074.116844 * Math.pow(cpuUsage, 4)) + - (2537.679443 * Math.pow(cpuUsage, 5)) + - (-3761.784242 * Math.pow(cpuUsage, 6)) + - (3391.045904 * Math.pow(cpuUsage, 7)) + - (-1692.840870 * Math.pow(cpuUsage, 8)) + - (357.800968 * Math.pow(cpuUsage, 9)); - break; - case RPI_ZW_11: - result = 0.8551610676717238 + (7.207151 * cpuUsage) + - (-135.517893 * Math.pow(cpuUsage, 2)) + - (1254.808001 * Math.pow(cpuUsage, 3)) + - (-6329.450524 * Math.pow(cpuUsage, 4)) + - (18502.371291 * Math.pow(cpuUsage, 5)) + - (-32098.028941 * Math.pow(cpuUsage, 6)) + - (32554.679890 * Math.pow(cpuUsage, 7)) + - (-17824.350159 * Math.pow(cpuUsage, 8)) + - (4069.178175 * Math.pow(cpuUsage, 9)); - break; - case ASUSTBS: - result = 3.9146162374630173 + (-19.85430796 * cpuUsage) + - (141.7306532 * Math.pow(cpuUsage, 2)) + - (-298.12713091 * Math.pow(cpuUsage, 3)) + - (-1115.76983141 * Math.pow(cpuUsage, 4)) + - (8238.275731321 * Math.pow(cpuUsage, 5)) + - (-20976.13898406 * Math.pow(cpuUsage, 6)) + - (27132.90930519 * Math.pow(cpuUsage, 7)) + - (-17741.01303757 * Math.pow(cpuUsage, 8)) + - (4640.69530931 * Math.pow(cpuUsage, 9)); - break; - default: - break; - } - - return result; - } - - @Override - public void initialize() { - // Nothing to do for Raspberry Pi - } - - @Override - public double getCurrentPower(final double cpuLoad) { - return calculateCpuEnergyForRaspberryPi(rpiModel, cpuLoad); - } - - /** - * The power is approximated based on the CPU load, so it does not need an offset. - * - * @return 0 - */ - @Override - public double getInitialPower() { - return 0; - } - - @Override - public void close() { - // Nothing to do for Raspberry Pi - } +/* + * Copyright (c) 2021-2023, 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 + */ + +package org.noureddine.joularjx.cpu; + +public class RaspberryPi implements Cpu { + + /** + * Raspberry Pi model name + */ + private final RaspberryPiModels rpiModel; + + public RaspberryPi(final RaspberryPiModels rpiModel) { + this.rpiModel = rpiModel; + } + + /** + * Calculate CPU energy consumption for last second (power) on supported Raspberry Pi devices + * @param rpiModel Raspberry Pi model + * @param cpuUsage CPU usage + * @return CPU energy consumption for last second (power) + */ + private double calculateCpuEnergyForRaspberryPi(final RaspberryPiModels rpiModel, final double cpuUsage) { + double result = 0.0; + + switch (rpiModel) { + case RPI_5B_10_64: + result = 8.71648242592654 + (-186.5634686 * cpuUsage) + + (2676.08397456 * Math.pow(cpuUsage, 2)) + + (-18839.18873015 * Math.pow(cpuUsage, 3)) + + (75110.3949109 * Math.pow(cpuUsage, 4)) + + (-180373.73562042 * Math.pow(cpuUsage, 5)) + + (267380.23597063 * Math.pow(cpuUsage, 6)) + + (-240403.81341249 * Math.pow(cpuUsage, 7)) + + (120509.01405772 * Math.pow(cpuUsage, 8)) + + (-25877.41360901 * Math.pow(cpuUsage, 9)); + break; + case RPI_400_10_64: + result = 2.6630056198236938 + (0.82814554 * cpuUsage) + + (-112.17687631 * Math.pow(cpuUsage, 2)) + + (1753.99173239 * Math.pow(cpuUsage, 3)) + + (-10992.65341181 * Math.pow(cpuUsage, 4)) + + (35988.45610911 * Math.pow(cpuUsage, 5)) + + (-66254.20051068 * Math.pow(cpuUsage, 6)) + + (69071.21138567 * Math.pow(cpuUsage, 7)) + + (-38089.87171735 * Math.pow(cpuUsage, 8)) + + (8638.45610698 * Math.pow(cpuUsage, 9)); + break; + case RPI_4B_12_64: + result = 3.039940056604439 + (-3.074225 * cpuUsage) + + (47.753114 * Math.pow(cpuUsage, 2)) + + (-271.974551 * Math.pow(cpuUsage, 3)) + + (879.966571 * Math.pow(cpuUsage, 4)) + + (-1437.466442 * Math.pow(cpuUsage, 5)) + + (1133.325791 * Math.pow(cpuUsage, 6)) + + (-345.134888 * Math.pow(cpuUsage, 7)); + break; + case RPI_4B_12: + result = 2.58542069543335 + (12.335449 * cpuUsage) + + (-248.010554 * Math.pow(cpuUsage, 2)) + + (2379.832320 * Math.pow(cpuUsage, 3)) + + (-11962.419149 * Math.pow(cpuUsage, 4)) + + (34444.268647 * Math.pow(cpuUsage, 5)) + + (-58455.266502 * Math.pow(cpuUsage, 6)) + + (57698.685016 * Math.pow(cpuUsage, 7)) + + (-30618.557703 * Math.pow(cpuUsage, 8)) + + (6752.265368 * Math.pow(cpuUsage, 9)); + break; + case RPI_4B_11_64: + result = 3.405685008777926 + (-11.834416 * cpuUsage) + + (137.312822 * Math.pow(cpuUsage, 2)) + + (-775.891511 * Math.pow(cpuUsage, 3)) + + (2563.399671 * Math.pow(cpuUsage, 4)) + + (-4783.024354 * Math.pow(cpuUsage, 5)) + + (4974.960753 * Math.pow(cpuUsage, 6)) + + (-2691.923074 * Math.pow(cpuUsage, 7)) + + (590.355251 * Math.pow(cpuUsage, 8)); + break; + case RPI_4B_11: + result = 2.5718068562852086 + (2.794871 * cpuUsage) + + (-58.954883 * Math.pow(cpuUsage, 2)) + + (838.875781 * Math.pow(cpuUsage, 3)) + + (-5371.428686 * Math.pow(cpuUsage, 4)) + + (18168.842874 * Math.pow(cpuUsage, 5)) + + (-34369.583554 * Math.pow(cpuUsage, 6)) + + (36585.681749 * Math.pow(cpuUsage, 7)) + + (-20501.307640 * Math.pow(cpuUsage, 8)) + + (4708.331490 * Math.pow(cpuUsage, 9)); + break; + case RPI_3BP_13: + result = 2.484396997449118 + (2.933542 * cpuUsage) + + (-150.400134 * Math.pow(cpuUsage, 2)) + + (2278.690310 * Math.pow(cpuUsage, 3)) + + (-15008.559279 * Math.pow(cpuUsage, 4)) + + (51537.315529 * Math.pow(cpuUsage, 5)) + + (-98756.887779 * Math.pow(cpuUsage, 6)) + + (106478.929766 * Math.pow(cpuUsage, 7)) + + (-60432.910139 * Math.pow(cpuUsage, 8)) + + (14053.677709 * Math.pow(cpuUsage, 9)); + break; + case RPI_3B_12: + result = 1.524116907651687 + (10.053851 * cpuUsage) + + (-234.186930 * Math.pow(cpuUsage, 2)) + + (2516.322119 * Math.pow(cpuUsage, 3)) + + (-13733.555536 * Math.pow(cpuUsage, 4)) + + (41739.918887 * Math.pow(cpuUsage, 5)) + + (-73342.794259 * Math.pow(cpuUsage, 6)) + + (74062.644914 * Math.pow(cpuUsage, 7)) + + (-39909.425362 * Math.pow(cpuUsage, 8)) + + (8894.110508 * Math.pow(cpuUsage, 9)); + break; + case RPI_2B_11: + result = 1.3596870187778196 + (5.135090 * cpuUsage) + + (-103.296366 * Math.pow(cpuUsage, 2)) + + (1027.169748 * Math.pow(cpuUsage, 3)) + + (-5323.639404 * Math.pow(cpuUsage, 4)) + + (15592.036875 * Math.pow(cpuUsage, 5)) + + (-26675.601585 * Math.pow(cpuUsage, 6)) + + (26412.963366 * Math.pow(cpuUsage, 7)) + + (-14023.471809 * Math.pow(cpuUsage, 8)) + + (3089.786200 * Math.pow(cpuUsage, 9)); + break; + case RPI_1BP_12: + result = 1.2513999338064061 + (1.857815 * cpuUsage) + + (-18.109537 * Math.pow(cpuUsage, 2)) + + (101.531231 * Math.pow(cpuUsage, 3)) + + (-346.386617 * Math.pow(cpuUsage, 4)) + + (749.560352 * Math.pow(cpuUsage, 5)) + + (-1028.802514 * Math.pow(cpuUsage, 6)) + + (863.877618 * Math.pow(cpuUsage, 7)) + + (-403.270951 * Math.pow(cpuUsage, 8)) + + (79.925932 * Math.pow(cpuUsage, 9)); + break; + case RPI_1B_2: + result = 2.826093843916506 + (3.539891 * cpuUsage) + + (-43.586963 * Math.pow(cpuUsage, 2)) + + (282.488560 * Math.pow(cpuUsage, 3)) + + (-1074.116844 * Math.pow(cpuUsage, 4)) + + (2537.679443 * Math.pow(cpuUsage, 5)) + + (-3761.784242 * Math.pow(cpuUsage, 6)) + + (3391.045904 * Math.pow(cpuUsage, 7)) + + (-1692.840870 * Math.pow(cpuUsage, 8)) + + (357.800968 * Math.pow(cpuUsage, 9)); + break; + case RPI_ZW_11: + result = 0.8551610676717238 + (7.207151 * cpuUsage) + + (-135.517893 * Math.pow(cpuUsage, 2)) + + (1254.808001 * Math.pow(cpuUsage, 3)) + + (-6329.450524 * Math.pow(cpuUsage, 4)) + + (18502.371291 * Math.pow(cpuUsage, 5)) + + (-32098.028941 * Math.pow(cpuUsage, 6)) + + (32554.679890 * Math.pow(cpuUsage, 7)) + + (-17824.350159 * Math.pow(cpuUsage, 8)) + + (4069.178175 * Math.pow(cpuUsage, 9)); + break; + case ASUSTBS: + result = 3.9146162374630173 + (-19.85430796 * cpuUsage) + + (141.7306532 * Math.pow(cpuUsage, 2)) + + (-298.12713091 * Math.pow(cpuUsage, 3)) + + (-1115.76983141 * Math.pow(cpuUsage, 4)) + + (8238.275731321 * Math.pow(cpuUsage, 5)) + + (-20976.13898406 * Math.pow(cpuUsage, 6)) + + (27132.90930519 * Math.pow(cpuUsage, 7)) + + (-17741.01303757 * Math.pow(cpuUsage, 8)) + + (4640.69530931 * Math.pow(cpuUsage, 9)); + break; + default: + break; + } + + return result; + } + + @Override + public void initialize() { + // Nothing to do for Raspberry Pi + } + + @Override + public double getCurrentPower(final double cpuLoad) { + return calculateCpuEnergyForRaspberryPi(rpiModel, cpuLoad); + } + + /** + * The power is approximated based on the CPU load, so it does not need an offset. + * + * @return 0 + */ + @Override + public double getInitialPower() { + return 0; + } + + @Override + public void close() { + // Nothing to do for Raspberry Pi + } } \ No newline at end of file diff --git a/src/main/java/org/noureddine/joularjx/cpu/RaspberryPiModels.java b/src/main/java/org/noureddine/joularjx/cpu/RaspberryPiModels.java index 286bef2..24317e0 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/RaspberryPiModels.java +++ b/src/main/java/org/noureddine/joularjx/cpu/RaspberryPiModels.java @@ -1,27 +1,28 @@ -/* - * Copyright (c) 2021-2023, 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 - */ - -package org.noureddine.joularjx.cpu; - -public enum RaspberryPiModels { - RPI_400_10_64, - RPI_4B_12_64, - RPI_4B_12, - RPI_4B_11_64, - RPI_4B_11, - RPI_3BP_13, - RPI_3B_12, - RPI_2B_11, - RPI_1BP_12, - RPI_1B_2, - RPI_ZW_11, - ASUSTBS +/* + * Copyright (c) 2021-2023, 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 + */ + +package org.noureddine.joularjx.cpu; + +public enum RaspberryPiModels { + RPI_5B_10_64, + RPI_400_10_64, + RPI_4B_12_64, + RPI_4B_12, + RPI_4B_11_64, + RPI_4B_11, + RPI_3BP_13, + RPI_3B_12, + RPI_2B_11, + RPI_1BP_12, + RPI_1B_2, + RPI_ZW_11, + ASUSTBS } \ No newline at end of file From 9d9f1ca4c465b5eab413eb2c1b245baf0c6883a8 Mon Sep 17 00:00:00 2001 From: Arjan Lamers Date: Mon, 15 Jan 2024 21:42:24 +0100 Subject: [PATCH 06/14] added support for intel mac power measurements fixed potential missed messages when buffer wasn't fully read added test cases --- .../joularjx/cpu/PowermetricsMacOS.java | 47 ++- .../joularjx/cpu/PowermetricsMacOSTest.java | 97 +++++ src/test/resources/powermetrics-intel.txt | 341 ++++++++++++++++++ src/test/resources/powermetrics-m1-m2.txt | 26 ++ 4 files changed, 494 insertions(+), 17 deletions(-) create mode 100644 src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java create mode 100644 src/test/resources/powermetrics-intel.txt create mode 100644 src/test/resources/powermetrics-m1-m2.txt diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index 492b675..4e034b1 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.util.logging.Level; import java.util.logging.Logger; @@ -13,9 +14,11 @@ */ public class PowermetricsMacOS implements Cpu { private static final Logger logger = JoularJXLogging.getLogger(); - private static final String POWER_INDICATOR = " Power: "; - private static final int POWER_INDICATOR_LENGTH = POWER_INDICATOR.length(); + private static final String POWER_INDICATOR_M_CHIP = " Power: "; + private static final String POWER_INDICATOR_INTEL_CHIP = "Intel energy model derived package power (CPUs+GT+SA): "; private Process process; + private BufferedReader reader; + private boolean initialized; @Override @@ -27,6 +30,7 @@ public void initialize() { try { // todo: detect when sudo fails as this currently won't throw an exception process = Runtime.getRuntime().exec("sudo powermetrics --samplers cpu_power -i 1000"); + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); initialized = true; } catch (Exception exception) { logger.log(Level.SEVERE, "Can't start powermetrics. Exiting..."); @@ -45,11 +49,9 @@ public double getCurrentPower(double cpuLoad) { int headerLinesToSkip = 10; int powerInMilliwatts = 0; try { - // Should not be closed since it closes the process, so no try-with-resource - BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; - boolean processingPower = false; - while ((line = input.readLine()) != null) { + BufferedReader reader = getReader(); + while (reader.ready() && (line = reader.readLine()) != null) { if (headerLinesToSkip != 0) { headerLinesToSkip--; continue; @@ -61,19 +63,17 @@ public double getCurrentPower(double cpuLoad) { } // looking for line fitting the: " Power: xxx mW" pattern and add all of the associated values together - final var powerIndicatorIndex = line.indexOf(POWER_INDICATOR); - - // we need an exit condition to avoid looping forever (since there are always new lines, the process being periodical) - // if we started processing power lines and we don't find any anymore, we've reached the end of this "page" so exit the loop - if(processingPower && powerIndicatorIndex < 0) { - break; - } + // or, for Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern + final var powerIndicatorIndexM = line.indexOf(POWER_INDICATOR_M_CHIP); + final var powerIndicatorIndexIntel = line.indexOf(POWER_INDICATOR_INTEL_CHIP); // lines with `-` as the second char are disregarded as of the form: "E-Cluster Power: 6 mW" which fits the pattern but shouldn't be considered // also ignore Combined Power if available since it is the sum of the other components - if (powerIndicatorIndex >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { - powerInMilliwatts += extractPowerInMilliwatts(line, powerIndicatorIndex); - processingPower = true; // record we're in the power lines section of the powermetrics output + if (powerIndicatorIndexM >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { + powerInMilliwatts += extractPowerInMilliwatts(line, powerIndicatorIndexM + POWER_INDICATOR_M_CHIP.length()); + } + if (powerIndicatorIndexIntel >= 0) { + powerInMilliwatts += extractPowerInMilliwatts(line, powerIndicatorIndexIntel + POWER_INDICATOR_INTEL_CHIP.length()); } } return (double) powerInMilliwatts / 1000; @@ -84,9 +84,22 @@ public double getCurrentPower(double cpuLoad) { return 0.0; } + /** + * Override point for testing. + */ + protected BufferedReader getReader() { + return reader; + } + private static int extractPowerInMilliwatts(String line, int powerIndex) { try { - return Integer.parseInt(line.substring(powerIndex + POWER_INDICATOR_LENGTH, line.indexOf('m') - 1)); + if (line.trim().endsWith("mW")) { + return Integer.parseInt(line.substring(powerIndex, line.indexOf('m') - 1)); + } else if (line.trim().endsWith("W")) { + return (int) (1000.0 * Double.parseDouble(line.substring(powerIndex, line.indexOf('W')))); + } else { + logger.log(Level.SEVERE, "Power line does not end with mW or W, ignoring line: " + line); + } } catch (Exception e) { logger.log(Level.SEVERE, "Cannot parse power value from line '" + line + "'", e); } diff --git a/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java new file mode 100644 index 0000000..4b27332 --- /dev/null +++ b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java @@ -0,0 +1,97 @@ +package org.noureddine.joularjx.cpu; + +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PowermetricsMacOSTest { + + @Test + void parseM1M2PowerLines() { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-m1-m2.txt"))); + } + }; + + // the ??-Cluster lines are to be ignored, hence do not count the 100mW + assertEquals(/*0.100d +*/ 0d + 0.688d+0.742d + 0.026d + 2.151d, cpu.getCurrentPower(0), 0.0001d); + } + + /** + * Test if the reader returns whenever there are results. + * @throws IOException + */ + @Test + void testIntermittentResults() throws IOException, URISyntaxException, InterruptedException { + // hookup a writer to a reader + PipedInputStream intermittentInputStream = new PipedInputStream(); + PipedOutputStream outputStream = new PipedOutputStream(intermittentInputStream); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream)); + BufferedReader reader = new BufferedReader(new InputStreamReader(intermittentInputStream)); + + // create the content blocks including headers + final String contents1 = "\n".repeat(10) + "CPU Power: 742 mW\n".repeat(2); + final String contents2 = "\n".repeat(10) + "CPU Power: 1.2W\n".repeat(2); + + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return reader; + } + }; + + // nothing written yet, so expect 0 + assertEquals(0d, cpu.getCurrentPower(0), 0.0001d); + + Thread writerBlock1 = createWriter(writer, contents1); + writerBlock1.start(); + writerBlock1.join(); + assertEquals(2*0.742d, cpu.getCurrentPower(0), 0.0001d); + + Thread writerBlock2 = createWriter(writer, contents2); + writerBlock2.start(); + writerBlock2.join(); + assertEquals(2*1.2d, cpu.getCurrentPower(0), 0.0001d); + } + + /** + * Create a thread that writes the contents to the writer, simulating the actual process. + * @param writer the writer to write to + * @param contents the contents to write + * @return a thread + */ + private static Thread createWriter(BufferedWriter writer, String contents) { + Thread writerBlock1 = new Thread() { + @Override + public void run() { + try { + writer.write(contents); + writer.flush(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + }; + return writerBlock1; + } + + @Test + void parseIntelPowerLines() { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-intel.txt"))); + } + }; + + assertEquals(4.87d + 3.43d + 3.38d + 4.21d + 3.21d , cpu.getCurrentPower(0), 0.0001d); + } + +} diff --git a/src/test/resources/powermetrics-intel.txt b/src/test/resources/powermetrics-intel.txt new file mode 100644 index 0000000..1f6da6c --- /dev/null +++ b/src/test/resources/powermetrics-intel.txt @@ -0,0 +1,341 @@ +Machine model: MacBookPro15,1 +SMC version: Unknown +EFI version: 2020.1.0 +OS version: 23C71 +Boot arguments: +Boot time: Thu Dec 21 08:07:54 2023 + + + +*** Sampled system activity (Mon Jan 15 20:18:34 2024 +0100) (1002.80ms elapsed) *** + + +**** Processor usage **** + +Intel energy model derived package power (CPUs+GT+SA): 4.87W + +LLC flushed residency: 45.7% + +System Average frequency as fraction of nominal: 81.81% (2127.00 Mhz) +Package 0 C-state residency: 49.49% (C2: 32.66% C3: 16.83% C6: 0.00% C7: 0.00% C8: 0.00% C9: 0.00% C10: 0.00% ) + +Performance Limited Due to: +CPU LIMIT TURBO_ATTENUATION +CPU/GPU Overlap: 2.97% +Cores Active: 42.61% +GPU Active: 4.41% +Avg Num of Cores Active: 0.76 + +Core 0 C-state residency: 71.73% (C3: 0.65% C6: 0.00% C7: 71.08% ) + +CPU 0 duty cycles/s: active/idle [< 16 us: 303.15/112.68] [< 32 us: 148.58/18.95] [< 64 us: 195.45/203.43] [< 128 us: 397.89/221.38] [< 256 us: 208.42/126.65] [< 512 us: 106.70/199.44] [< 1024 us: 38.89/225.37] [< 2048 us: 11.97/256.28] [< 4096 us: 1.99/48.86] [< 8192 us: 2.99/4.99] [< 16384 us: 0.00/0.00] [< 32768 us: 1.00/0.00] +CPU Average frequency as fraction of nominal: 76.58% (1991.00 Mhz) + +CPU 1 duty cycles/s: active/idle [< 16 us: 1362.18/58.84] [< 32 us: 7.98/45.87] [< 64 us: 5.98/141.60] [< 128 us: 2.99/211.41] [< 256 us: 1.00/198.44] [< 512 us: 0.00/162.54] [< 1024 us: 0.00/172.52] [< 2048 us: 0.00/282.21] [< 4096 us: 0.00/85.76] [< 8192 us: 0.00/19.94] [< 16384 us: 0.00/1.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 72.27% (1878.91 Mhz) + +Core 1 C-state residency: 76.85% (C3: 0.93% C6: 0.00% C7: 75.91% ) + +CPU 2 duty cycles/s: active/idle [< 16 us: 459.71/174.51] [< 32 us: 184.48/27.92] [< 64 us: 178.50/185.48] [< 128 us: 243.32/197.45] [< 256 us: 115.68/146.59] [< 512 us: 81.77/105.70] [< 1024 us: 18.95/153.57] [< 2048 us: 5.98/198.44] [< 4096 us: 2.99/79.78] [< 8192 us: 1.00/22.94] [< 16384 us: 0.00/1.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 85.92% (2233.86 Mhz) + +CPU 3 duty cycles/s: active/idle [< 16 us: 1121.86/137.61] [< 32 us: 5.98/132.63] [< 64 us: 9.97/158.56] [< 128 us: 1.99/139.61] [< 256 us: 1.00/137.61] [< 512 us: 0.00/85.76] [< 1024 us: 0.00/78.78] [< 2048 us: 0.00/106.70] [< 4096 us: 0.00/93.74] [< 8192 us: 0.00/59.83] [< 16384 us: 0.00/8.97] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 73.11% (1900.84 Mhz) + +Core 2 C-state residency: 82.58% (C3: 0.91% C6: 0.00% C7: 81.66% ) + +CPU 4 duty cycles/s: active/idle [< 16 us: 465.70/237.33] [< 32 us: 247.31/8.97] [< 64 us: 166.53/161.55] [< 128 us: 166.53/188.47] [< 256 us: 97.73/130.63] [< 512 us: 68.81/103.71] [< 1024 us: 17.95/114.68] [< 2048 us: 5.98/162.54] [< 4096 us: 1.99/93.74] [< 8192 us: 1.00/37.89] [< 16384 us: 1.00/1.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 79.10% (2056.54 Mhz) + +CPU 5 duty cycles/s: active/idle [< 16 us: 1365.17/298.16] [< 32 us: 6.98/162.54] [< 64 us: 9.97/150.58] [< 128 us: 1.99/139.61] [< 256 us: 0.00/141.60] [< 512 us: 0.00/101.71] [< 1024 us: 0.00/93.74] [< 2048 us: 0.00/147.59] [< 4096 us: 0.00/83.77] [< 8192 us: 0.00/57.84] [< 16384 us: 0.00/6.98] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 73.36% (1907.48 Mhz) + +Core 3 C-state residency: 85.18% (C3: 1.06% C6: 0.00% C7: 84.12% ) + +CPU 6 duty cycles/s: active/idle [< 16 us: 544.47/193.46] [< 32 us: 163.54/32.91] [< 64 us: 106.70/125.65] [< 128 us: 115.68/160.55] [< 256 us: 69.80/106.70] [< 512 us: 51.85/94.73] [< 1024 us: 17.95/109.69] [< 2048 us: 4.99/111.69] [< 4096 us: 0.00/77.78] [< 8192 us: 0.00/60.83] [< 16384 us: 0.00/1.00] [< 32768 us: 1.00/0.00] +CPU Average frequency as fraction of nominal: 91.17% (2370.52 Mhz) + +CPU 7 duty cycles/s: active/idle [< 16 us: 186.48/15.96] [< 32 us: 6.98/5.98] [< 64 us: 7.98/16.95] [< 128 us: 1.99/17.95] [< 256 us: 0.00/16.95] [< 512 us: 0.00/12.96] [< 1024 us: 0.00/13.96] [< 2048 us: 0.00/14.96] [< 4096 us: 0.00/16.95] [< 8192 us: 0.00/22.94] [< 16384 us: 0.00/28.92] [< 32768 us: 0.00/17.95] +CPU Average frequency as fraction of nominal: 81.61% (2121.81 Mhz) + +Core 4 C-state residency: 92.64% (C3: 0.85% C6: 0.00% C7: 91.79% ) + +CPU 8 duty cycles/s: active/idle [< 16 us: 326.09/36.90] [< 32 us: 42.88/2.99] [< 64 us: 56.84/65.82] [< 128 us: 48.86/82.77] [< 256 us: 35.90/56.84] [< 512 us: 19.94/39.89] [< 1024 us: 7.98/42.88] [< 2048 us: 1.00/69.80] [< 4096 us: 0.00/57.84] [< 8192 us: 0.00/64.82] [< 16384 us: 1.99/18.95] [< 32768 us: 0.00/1.99] +CPU Average frequency as fraction of nominal: 82.25% (2138.61 Mhz) + +CPU 9 duty cycles/s: active/idle [< 16 us: 337.06/18.95] [< 32 us: 6.98/24.93] [< 64 us: 4.99/45.87] [< 128 us: 1.00/50.86] [< 256 us: 2.99/41.88] [< 512 us: 0.00/22.94] [< 1024 us: 0.00/11.97] [< 2048 us: 0.00/30.91] [< 4096 us: 0.00/24.93] [< 8192 us: 0.00/32.91] [< 16384 us: 0.00/34.90] [< 32768 us: 0.00/10.97] +CPU Average frequency as fraction of nominal: 75.20% (1955.32 Mhz) + +Core 5 C-state residency: 96.24% (C3: 0.00% C6: 0.00% C7: 96.24% ) + +CPU 10 duty cycles/s: active/idle [< 16 us: 280.21/26.92] [< 32 us: 24.93/1.99] [< 64 us: 46.87/54.85] [< 128 us: 39.89/56.84] [< 256 us: 21.94/46.87] [< 512 us: 12.96/31.91] [< 1024 us: 2.99/26.92] [< 2048 us: 0.00/57.84] [< 4096 us: 1.00/38.89] [< 8192 us: 0.00/53.85] [< 16384 us: 0.00/27.92] [< 32768 us: 0.00/5.98] +CPU Average frequency as fraction of nominal: 75.53% (1963.85 Mhz) + +CPU 11 duty cycles/s: active/idle [< 16 us: 41.88/2.99] [< 32 us: 1.00/1.00] [< 64 us: 1.00/2.99] [< 128 us: 3.99/1.00] [< 256 us: 1.00/3.99] [< 512 us: 0.00/1.99] [< 1024 us: 0.00/2.99] [< 2048 us: 0.00/1.00] [< 4096 us: 0.00/3.99] [< 8192 us: 0.00/3.99] [< 16384 us: 0.00/4.99] [< 32768 us: 0.00/5.98] +CPU Average frequency as fraction of nominal: 70.88% (1843.00 Mhz) + + +*** Sampled system activity (Mon Jan 15 20:18:35 2024 +0100) (1004.07ms elapsed) *** + + +**** Processor usage **** + +Intel energy model derived package power (CPUs+GT+SA): 3.43W + +LLC flushed residency: 56.2% + +System Average frequency as fraction of nominal: 64.01% (1664.23 Mhz) +Package 0 C-state residency: 59.61% (C2: 39.10% C3: 20.50% C6: 0.00% C7: 0.00% C8: 0.00% C9: 0.00% C10: 0.00% ) +CPU/GPU Overlap: 2.24% +Cores Active: 32.61% +GPU Active: 2.97% +Avg Num of Cores Active: 0.60 + +Core 0 C-state residency: 74.06% (C3: 0.04% C6: 0.00% C7: 74.02% ) + +CPU 0 duty cycles/s: active/idle [< 16 us: 212.14/225.08] [< 32 us: 237.04/32.87] [< 64 us: 160.35/141.42] [< 128 us: 437.22/156.36] [< 256 us: 171.30/112.54] [< 512 us: 97.60/177.28] [< 1024 us: 51.79/185.25] [< 2048 us: 5.98/285.84] [< 4096 us: 3.98/48.80] [< 8192 us: 1.00/12.95] [< 16384 us: 0.00/0.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 63.49% (1650.68 Mhz) + +CPU 1 duty cycles/s: active/idle [< 16 us: 1408.27/169.31] [< 32 us: 3.98/121.51] [< 64 us: 1.99/140.43] [< 128 us: 1.00/161.34] [< 256 us: 0.00/147.40] [< 512 us: 0.00/135.45] [< 1024 us: 0.00/145.41] [< 2048 us: 0.00/273.89] [< 4096 us: 0.00/92.62] [< 8192 us: 0.00/26.89] [< 16384 us: 0.00/1.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 62.62% (1628.21 Mhz) + +Core 1 C-state residency: 82.57% (C3: 0.19% C6: 0.00% C7: 82.37% ) + +CPU 2 duty cycles/s: active/idle [< 16 us: 377.46/143.42] [< 32 us: 125.49/28.88] [< 64 us: 183.25/141.42] [< 128 us: 289.82/187.24] [< 256 us: 111.55/113.54] [< 512 us: 59.76/94.61] [< 1024 us: 25.89/127.48] [< 2048 us: 3.98/236.04] [< 4096 us: 1.99/75.69] [< 8192 us: 1.00/27.89] [< 16384 us: 0.00/3.98] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 65.61% (1705.78 Mhz) + +CPU 3 duty cycles/s: active/idle [< 16 us: 903.32/72.70] [< 32 us: 2.99/93.62] [< 64 us: 7.97/122.50] [< 128 us: 2.99/104.57] [< 256 us: 0.00/115.53] [< 512 us: 0.00/76.69] [< 1024 us: 0.00/53.78] [< 2048 us: 0.00/99.59] [< 4096 us: 0.00/110.55] [< 8192 us: 0.00/57.76] [< 16384 us: 0.00/9.96] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 65.17% (1694.39 Mhz) + +Core 2 C-state residency: 86.64% (C3: 1.43% C6: 0.00% C7: 85.21% ) + +CPU 4 duty cycles/s: active/idle [< 16 us: 420.29/128.48] [< 32 us: 120.51/40.83] [< 64 us: 155.37/126.49] [< 128 us: 160.35/182.26] [< 256 us: 79.68/93.62] [< 512 us: 54.78/74.70] [< 1024 us: 14.94/93.62] [< 2048 us: 1.99/107.56] [< 4096 us: 1.00/112.54] [< 8192 us: 1.00/40.83] [< 16384 us: 0.00/7.97] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 65.33% (1698.65 Mhz) + +CPU 5 duty cycles/s: active/idle [< 16 us: 965.07/112.54] [< 32 us: 1.00/112.54] [< 64 us: 4.98/121.51] [< 128 us: 1.99/118.52] [< 256 us: 0.00/115.53] [< 512 us: 0.00/61.75] [< 1024 us: 0.00/71.71] [< 2048 us: 0.00/96.61] [< 4096 us: 0.00/92.62] [< 8192 us: 0.00/51.79] [< 16384 us: 0.00/17.93] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 64.51% (1677.15 Mhz) + +Core 3 C-state residency: 89.38% (C3: 0.35% C6: 0.00% C7: 89.03% ) + +CPU 6 duty cycles/s: active/idle [< 16 us: 395.39/104.57] [< 32 us: 78.68/39.84] [< 64 us: 86.65/90.63] [< 128 us: 130.47/112.54] [< 256 us: 60.75/82.66] [< 512 us: 49.80/53.78] [< 1024 us: 15.94/67.72] [< 2048 us: 2.99/107.56] [< 4096 us: 0.00/106.57] [< 8192 us: 0.00/44.82] [< 16384 us: 0.00/9.96] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 62.37% (1621.70 Mhz) + +CPU 7 duty cycles/s: active/idle [< 16 us: 157.36/1.99] [< 32 us: 3.98/2.99] [< 64 us: 2.99/7.97] [< 128 us: 1.00/10.96] [< 256 us: 1.99/17.93] [< 512 us: 0.00/6.97] [< 1024 us: 0.00/9.96] [< 2048 us: 0.00/9.96] [< 4096 us: 0.00/24.90] [< 8192 us: 0.00/30.87] [< 16384 us: 0.00/23.90] [< 32768 us: 0.00/17.93] +CPU Average frequency as fraction of nominal: 71.57% (1860.85 Mhz) + +Core 4 C-state residency: 95.40% (C3: 0.42% C6: 0.00% C7: 94.97% ) + +CPU 8 duty cycles/s: active/idle [< 16 us: 241.02/25.89] [< 32 us: 20.91/1.99] [< 64 us: 69.72/39.84] [< 128 us: 43.82/53.78] [< 256 us: 28.88/57.76] [< 512 us: 17.93/34.86] [< 1024 us: 5.98/29.88] [< 2048 us: 1.00/46.81] [< 4096 us: 0.00/54.78] [< 8192 us: 0.00/49.80] [< 16384 us: 0.00/28.88] [< 32768 us: 0.00/4.98] +CPU Average frequency as fraction of nominal: 63.09% (1640.22 Mhz) + +CPU 9 duty cycles/s: active/idle [< 16 us: 272.89/14.94] [< 32 us: 3.98/18.92] [< 64 us: 5.98/38.84] [< 128 us: 1.00/28.88] [< 256 us: 1.99/25.89] [< 512 us: 0.00/9.96] [< 1024 us: 0.00/18.92] [< 2048 us: 0.00/24.90] [< 4096 us: 0.00/29.88] [< 8192 us: 0.00/35.85] [< 16384 us: 0.00/22.91] [< 32768 us: 0.00/13.94] +CPU Average frequency as fraction of nominal: 66.46% (1727.95 Mhz) + +Core 5 C-state residency: 95.05% (C3: 0.00% C6: 0.00% C7: 95.05% ) + +CPU 10 duty cycles/s: active/idle [< 16 us: 171.30/27.89] [< 32 us: 21.91/3.98] [< 64 us: 40.83/39.84] [< 128 us: 34.86/31.87] [< 256 us: 49.80/33.86] [< 512 us: 28.88/27.89] [< 1024 us: 6.97/25.89] [< 2048 us: 2.99/33.86] [< 4096 us: 0.00/47.81] [< 8192 us: 0.00/47.81] [< 16384 us: 0.00/31.87] [< 32768 us: 0.00/3.98] +CPU Average frequency as fraction of nominal: 61.69% (1604.04 Mhz) + +CPU 11 duty cycles/s: active/idle [< 16 us: 22.91/0.00] [< 32 us: 0.00/1.00] [< 64 us: 3.98/1.00] [< 128 us: 1.00/0.00] [< 256 us: 0.00/1.99] [< 512 us: 0.00/1.00] [< 1024 us: 0.00/1.99] [< 2048 us: 0.00/0.00] [< 4096 us: 0.00/0.00] [< 8192 us: 0.00/3.98] [< 16384 us: 0.00/3.98] [< 32768 us: 0.00/2.99] +CPU Average frequency as fraction of nominal: 63.59% (1653.39 Mhz) + + +*** Sampled system activity (Mon Jan 15 20:18:36 2024 +0100) (1003.46ms elapsed) *** + + +**** Processor usage **** + +Intel energy model derived package power (CPUs+GT+SA): 3.38W + +LLC flushed residency: 58% + +System Average frequency as fraction of nominal: 64.68% (1681.60 Mhz) +Package 0 C-state residency: 60.69% (C2: 39.26% C3: 21.43% C6: 0.00% C7: 0.00% C8: 0.00% C9: 0.00% C10: 0.00% ) +CPU/GPU Overlap: 0.00% +Cores Active: 32.43% +GPU Active: 0.00% +Avg Num of Cores Active: 0.57 + +Core 0 C-state residency: 75.05% (C3: 0.00% C6: 0.00% C7: 75.05% ) + +CPU 0 duty cycles/s: active/idle [< 16 us: 211.27/130.55] [< 32 us: 154.47/14.95] [< 64 us: 117.59/122.58] [< 128 us: 393.64/166.42] [< 256 us: 171.41/84.71] [< 512 us: 89.69/153.47] [< 1024 us: 45.84/182.37] [< 2048 us: 8.97/275.05] [< 4096 us: 1.99/46.84] [< 8192 us: 0.00/18.93] [< 16384 us: 0.00/0.00] [< 32768 us: 1.00/0.00] +CPU Average frequency as fraction of nominal: 66.25% (1722.55 Mhz) + +CPU 1 duty cycles/s: active/idle [< 16 us: 1246.69/77.73] [< 32 us: 1.99/80.72] [< 64 us: 5.98/135.53] [< 128 us: 4.98/193.33] [< 256 us: 1.00/134.53] [< 512 us: 1.00/133.54] [< 1024 us: 0.00/113.61] [< 2048 us: 0.00/273.06] [< 4096 us: 0.00/88.69] [< 8192 us: 0.00/30.89] [< 16384 us: 0.00/0.00] [< 32768 us: 0.00/1.00] +CPU Average frequency as fraction of nominal: 60.98% (1585.42 Mhz) + +Core 1 C-state residency: 83.77% (C3: 0.18% C6: 0.00% C7: 83.59% ) + +CPU 2 duty cycles/s: active/idle [< 16 us: 335.84/138.52] [< 32 us: 126.56/16.94] [< 64 us: 165.43/122.58] [< 128 us: 280.03/171.41] [< 256 us: 98.66/82.71] [< 512 us: 67.77/93.68] [< 1024 us: 26.91/129.55] [< 2048 us: 4.98/233.19] [< 4096 us: 0.00/89.69] [< 8192 us: 0.00/25.91] [< 16384 us: 0.00/1.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 60.46% (1571.88 Mhz) + +CPU 3 duty cycles/s: active/idle [< 16 us: 861.02/92.68] [< 32 us: 1.99/73.75] [< 64 us: 1.00/96.67] [< 128 us: 1.99/119.59] [< 256 us: 1.00/106.63] [< 512 us: 0.00/68.76] [< 1024 us: 0.00/48.83] [< 2048 us: 0.00/84.71] [< 4096 us: 0.00/94.67] [< 8192 us: 0.00/73.75] [< 16384 us: 0.00/5.98] [< 32768 us: 0.00/1.00] +CPU Average frequency as fraction of nominal: 63.34% (1646.86 Mhz) + +Core 2 C-state residency: 87.54% (C3: 0.01% C6: 0.00% C7: 87.53% ) + +CPU 4 duty cycles/s: active/idle [< 16 us: 317.90/180.38] [< 32 us: 183.37/22.92] [< 64 us: 142.51/79.72] [< 128 us: 150.48/119.59] [< 256 us: 72.75/83.71] [< 512 us: 44.84/56.80] [< 1024 us: 20.93/83.71] [< 2048 us: 4.98/153.47] [< 4096 us: 0.00/104.64] [< 8192 us: 0.00/49.83] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 62.81% (1633.07 Mhz) + +CPU 5 duty cycles/s: active/idle [< 16 us: 1079.27/276.05] [< 32 us: 1.00/172.40] [< 64 us: 4.98/83.71] [< 128 us: 1.99/85.70] [< 256 us: 0.00/81.72] [< 512 us: 0.00/68.76] [< 1024 us: 1.00/60.79] [< 2048 us: 0.00/106.63] [< 4096 us: 0.00/70.76] [< 8192 us: 0.00/63.78] [< 16384 us: 0.00/17.94] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 63.19% (1642.94 Mhz) + +Core 3 C-state residency: 90.69% (C3: 0.00% C6: 0.00% C7: 90.68% ) + +CPU 6 duty cycles/s: active/idle [< 16 us: 396.63/151.48] [< 32 us: 100.65/46.84] [< 64 us: 100.65/94.67] [< 128 us: 82.71/98.66] [< 256 us: 63.78/57.80] [< 512 us: 39.86/50.82] [< 1024 us: 12.96/53.81] [< 2048 us: 3.99/74.74] [< 4096 us: 0.00/93.68] [< 8192 us: 0.00/66.77] [< 16384 us: 0.00/11.96] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 62.81% (1633.18 Mhz) + +CPU 7 duty cycles/s: active/idle [< 16 us: 125.57/5.98] [< 32 us: 4.98/3.99] [< 64 us: 0.00/3.99] [< 128 us: 1.00/4.98] [< 256 us: 1.00/12.96] [< 512 us: 0.00/8.97] [< 1024 us: 0.00/7.97] [< 2048 us: 0.00/9.97] [< 4096 us: 0.00/10.96] [< 8192 us: 0.00/16.94] [< 16384 us: 0.00/30.89] [< 32768 us: 0.00/9.97] +CPU Average frequency as fraction of nominal: 58.66% (1525.22 Mhz) + +Core 4 C-state residency: 94.19% (C3: 0.00% C6: 0.00% C7: 94.19% ) + +CPU 8 duty cycles/s: active/idle [< 16 us: 156.46/19.93] [< 32 us: 13.95/1.99] [< 64 us: 43.85/36.87] [< 128 us: 45.84/47.83] [< 256 us: 27.90/15.94] [< 512 us: 18.93/17.94] [< 1024 us: 5.98/16.94] [< 2048 us: 3.99/39.86] [< 4096 us: 0.00/37.87] [< 8192 us: 0.00/38.87] [< 16384 us: 1.00/39.86] [< 32768 us: 0.00/4.98] +CPU Average frequency as fraction of nominal: 77.32% (2010.36 Mhz) + +CPU 9 duty cycles/s: active/idle [< 16 us: 223.23/11.96] [< 32 us: 1.00/8.97] [< 64 us: 5.98/27.90] [< 128 us: 0.00/32.89] [< 256 us: 1.00/11.96] [< 512 us: 0.00/21.92] [< 1024 us: 0.00/7.97] [< 2048 us: 0.00/13.95] [< 4096 us: 0.00/15.94] [< 8192 us: 0.00/30.89] [< 16384 us: 0.00/31.89] [< 32768 us: 0.00/12.96] +CPU Average frequency as fraction of nominal: 59.17% (1538.50 Mhz) + +Core 5 C-state residency: 96.84% (C3: 0.00% C6: 0.00% C7: 96.84% ) + +CPU 10 duty cycles/s: active/idle [< 16 us: 109.62/8.97] [< 32 us: 6.98/1.99] [< 64 us: 21.92/22.92] [< 128 us: 34.88/21.92] [< 256 us: 27.90/12.96] [< 512 us: 11.96/14.95] [< 1024 us: 10.96/12.96] [< 2048 us: 1.00/23.92] [< 4096 us: 0.00/31.89] [< 8192 us: 0.00/34.88] [< 16384 us: 0.00/24.91] [< 32768 us: 0.00/11.96] +CPU Average frequency as fraction of nominal: 60.28% (1567.23 Mhz) + +CPU 11 duty cycles/s: active/idle [< 16 us: 13.95/1.00] [< 32 us: 3.99/0.00] [< 64 us: 1.99/1.00] [< 128 us: 1.99/1.00] [< 256 us: 1.00/0.00] [< 512 us: 1.00/0.00] [< 1024 us: 0.00/1.99] [< 2048 us: 0.00/1.00] [< 4096 us: 0.00/0.00] [< 8192 us: 0.00/1.00] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/2.99] +CPU Average frequency as fraction of nominal: 60.71% (1578.43 Mhz) + + +*** Sampled system activity (Mon Jan 15 20:18:37 2024 +0100) (1003.06ms elapsed) *** + + +**** Processor usage **** + +Intel energy model derived package power (CPUs+GT+SA): 4.21W + +LLC flushed residency: 54.2% + +System Average frequency as fraction of nominal: 74.44% (1935.33 Mhz) +Package 0 C-state residency: 57.44% (C2: 38.09% C3: 19.36% C6: 0.00% C7: 0.00% C8: 0.00% C9: 0.00% C10: 0.00% ) + +Performance Limited Due to: +CPU LIMIT ICCMAX/PL4/OTHER +CPU LIMIT MAX_TURBO_LIMIT +CPU LIMIT TURBO_ATTENUATION +GPU LIMIT ICCMAX/PL4/OTHER +CPU/GPU Overlap: 0.00% +Cores Active: 35.48% +GPU Active: 0.00% +Avg Num of Cores Active: 0.61 + +Core 0 C-state residency: 76.26% (C3: 1.25% C6: 0.00% C7: 75.01% ) + +CPU 0 duty cycles/s: active/idle [< 16 us: 288.12/114.65] [< 32 us: 150.54/26.92] [< 64 us: 143.56/188.42] [< 128 us: 399.78/184.44] [< 256 us: 202.38/91.72] [< 512 us: 98.70/176.46] [< 1024 us: 44.86/222.32] [< 2048 us: 8.97/262.20] [< 4096 us: 1.00/58.82] [< 8192 us: 0.00/11.96] [< 16384 us: 0.00/0.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 65.32% (1698.38 Mhz) + +CPU 1 duty cycles/s: active/idle [< 16 us: 1225.25/32.90] [< 32 us: 12.96/53.84] [< 64 us: 7.98/143.56] [< 128 us: 3.99/197.40] [< 256 us: 2.99/155.52] [< 512 us: 0.00/143.56] [< 1024 us: 0.00/153.53] [< 2048 us: 0.00/240.26] [< 4096 us: 0.00/107.67] [< 8192 us: 0.00/21.93] [< 16384 us: 0.00/1.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 69.34% (1802.88 Mhz) + +Core 1 C-state residency: 83.71% (C3: 0.68% C6: 0.00% C7: 83.03% ) + +CPU 2 duty cycles/s: active/idle [< 16 us: 383.82/144.56] [< 32 us: 101.69/11.96] [< 64 us: 197.40/150.54] [< 128 us: 290.11/194.40] [< 256 us: 101.69/108.67] [< 512 us: 72.78/68.79] [< 1024 us: 19.94/147.55] [< 2048 us: 1.99/226.31] [< 4096 us: 1.99/93.71] [< 8192 us: 0.00/21.93] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 67.89% (1765.21 Mhz) + +CPU 3 duty cycles/s: active/idle [< 16 us: 825.47/89.73] [< 32 us: 6.98/75.77] [< 64 us: 10.97/98.70] [< 128 us: 1.99/108.67] [< 256 us: 1.99/82.75] [< 512 us: 0.00/59.82] [< 1024 us: 0.00/61.81] [< 2048 us: 0.00/94.71] [< 4096 us: 0.00/111.66] [< 8192 us: 0.00/47.85] [< 16384 us: 0.00/15.95] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 70.95% (1844.76 Mhz) + +Core 2 C-state residency: 81.87% (C3: 0.42% C6: 0.00% C7: 81.44% ) + +CPU 4 duty cycles/s: active/idle [< 16 us: 324.01/152.53] [< 32 us: 159.51/23.93] [< 64 us: 136.58/117.64] [< 128 us: 145.55/125.62] [< 256 us: 65.80/86.73] [< 512 us: 57.82/57.82] [< 1024 us: 23.93/75.77] [< 2048 us: 4.98/135.58] [< 4096 us: 1.99/100.69] [< 8192 us: 0.00/42.87] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 92.94% (2416.47 Mhz) + +CPU 5 duty cycles/s: active/idle [< 16 us: 950.09/134.59] [< 32 us: 4.98/144.56] [< 64 us: 7.98/140.57] [< 128 us: 7.98/104.68] [< 256 us: 1.00/66.80] [< 512 us: 0.00/63.80] [< 1024 us: 0.00/55.83] [< 2048 us: 0.00/106.67] [< 4096 us: 0.00/76.76] [< 8192 us: 0.00/61.81] [< 16384 us: 0.00/13.96] [< 32768 us: 0.00/1.99] +CPU Average frequency as fraction of nominal: 70.47% (1832.32 Mhz) + +Core 3 C-state residency: 90.00% (C3: 0.02% C6: 0.00% C7: 89.98% ) + +CPU 6 duty cycles/s: active/idle [< 16 us: 410.74/125.62] [< 32 us: 88.73/49.85] [< 64 us: 85.74/86.73] [< 128 us: 83.74/108.67] [< 256 us: 57.82/65.80] [< 512 us: 31.90/34.89] [< 1024 us: 10.97/52.84] [< 2048 us: 3.99/83.74] [< 4096 us: 0.00/91.72] [< 8192 us: 0.00/61.81] [< 16384 us: 1.00/12.96] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 79.26% (2060.74 Mhz) + +CPU 7 duty cycles/s: active/idle [< 16 us: 142.56/14.95] [< 32 us: 4.98/7.98] [< 64 us: 8.97/5.98] [< 128 us: 3.99/10.97] [< 256 us: 1.00/15.95] [< 512 us: 0.00/10.97] [< 1024 us: 0.00/6.98] [< 2048 us: 0.00/9.97] [< 4096 us: 0.00/9.97] [< 8192 us: 0.00/18.94] [< 16384 us: 0.00/32.90] [< 32768 us: 0.00/10.97] +CPU Average frequency as fraction of nominal: 68.37% (1777.64 Mhz) + +Core 4 C-state residency: 95.33% (C3: 0.00% C6: 0.00% C7: 95.33% ) + +CPU 8 duty cycles/s: active/idle [< 16 us: 213.35/30.91] [< 32 us: 18.94/4.98] [< 64 us: 42.87/39.88] [< 128 us: 49.85/48.85] [< 256 us: 23.93/22.93] [< 512 us: 26.92/25.92] [< 1024 us: 7.98/13.96] [< 2048 us: 1.99/49.85] [< 4096 us: 0.00/58.82] [< 8192 us: 0.00/59.82] [< 16384 us: 0.00/26.92] [< 32768 us: 0.00/1.99] +CPU Average frequency as fraction of nominal: 64.77% (1683.97 Mhz) + +CPU 9 duty cycles/s: active/idle [< 16 us: 262.20/26.92] [< 32 us: 2.99/27.91] [< 64 us: 5.98/26.92] [< 128 us: 2.99/33.90] [< 256 us: 1.00/23.93] [< 512 us: 0.00/12.96] [< 1024 us: 0.00/6.98] [< 2048 us: 0.00/11.96] [< 4096 us: 0.00/26.92] [< 8192 us: 0.00/29.91] [< 16384 us: 0.00/31.90] [< 32768 us: 0.00/11.96] +CPU Average frequency as fraction of nominal: 70.50% (1833.04 Mhz) + +Core 5 C-state residency: 96.41% (C3: 0.23% C6: 0.00% C7: 96.18% ) + +CPU 10 duty cycles/s: active/idle [< 16 us: 151.54/32.90] [< 32 us: 12.96/2.99] [< 64 us: 48.85/46.86] [< 128 us: 46.86/29.91] [< 256 us: 18.94/14.95] [< 512 us: 16.95/10.97] [< 1024 us: 10.97/15.95] [< 2048 us: 1.00/29.91] [< 4096 us: 0.00/35.89] [< 8192 us: 0.00/45.86] [< 16384 us: 0.00/28.91] [< 32768 us: 0.00/11.96] +CPU Average frequency as fraction of nominal: 63.56% (1652.48 Mhz) + +CPU 11 duty cycles/s: active/idle [< 16 us: 30.91/1.99] [< 32 us: 2.99/0.00] [< 64 us: 7.98/7.98] [< 128 us: 2.99/4.98] [< 256 us: 2.99/1.99] [< 512 us: 0.00/1.99] [< 1024 us: 0.00/1.99] [< 2048 us: 0.00/3.99] [< 4096 us: 0.00/1.99] [< 8192 us: 0.00/1.00] [< 16384 us: 0.00/3.99] [< 32768 us: 0.00/5.98] +CPU Average frequency as fraction of nominal: 75.71% (1968.52 Mhz) + + +*** Sampled system activity (Mon Jan 15 20:18:38 2024 +0100) (1003.03ms elapsed) *** + + +**** Processor usage **** + +Intel energy model derived package power (CPUs+GT+SA): 3.21W + +LLC flushed residency: 57.5% + +System Average frequency as fraction of nominal: 59.77% (1553.99 Mhz) +Package 0 C-state residency: 60.79% (C2: 39.87% C3: 20.91% C6: 0.00% C7: 0.00% C8: 0.00% C9: 0.00% C10: 0.00% ) +CPU/GPU Overlap: 0.00% +Cores Active: 32.26% +GPU Active: 0.00% +Avg Num of Cores Active: 0.58 + +Core 0 C-state residency: 75.63% (C3: 0.00% C6: 0.00% C7: 75.63% ) + +CPU 0 duty cycles/s: active/idle [< 16 us: 207.37/182.45] [< 32 us: 249.25/53.84] [< 64 us: 126.62/143.57] [< 128 us: 368.88/160.51] [< 256 us: 181.45/87.73] [< 512 us: 115.65/188.43] [< 1024 us: 56.83/162.51] [< 2048 us: 6.98/260.21] [< 4096 us: 1.00/53.84] [< 8192 us: 0.00/20.94] [< 16384 us: 0.00/0.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 58.69% (1525.84 Mhz) + +CPU 1 duty cycles/s: active/idle [< 16 us: 1390.79/163.50] [< 32 us: 6.98/152.54] [< 64 us: 4.98/137.58] [< 128 us: 6.98/172.48] [< 256 us: 0.00/138.58] [< 512 us: 0.00/136.59] [< 1024 us: 0.00/126.62] [< 2048 us: 0.00/256.22] [< 4096 us: 0.00/92.72] [< 8192 us: 0.00/31.90] [< 16384 us: 0.00/1.00] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 60.58% (1575.02 Mhz) + +Core 1 C-state residency: 83.62% (C3: 0.20% C6: 0.00% C7: 83.42% ) + +CPU 2 duty cycles/s: active/idle [< 16 us: 310.06/179.46] [< 32 us: 181.45/7.98] [< 64 us: 162.51/109.67] [< 128 us: 285.14/150.54] [< 256 us: 96.71/107.67] [< 512 us: 76.77/102.69] [< 1024 us: 26.92/133.60] [< 2048 us: 2.99/242.27] [< 4096 us: 0.00/80.76] [< 8192 us: 0.00/25.92] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 58.51% (1521.35 Mhz) + +CPU 3 duty cycles/s: active/idle [< 16 us: 913.23/127.61] [< 32 us: 3.99/122.63] [< 64 us: 6.98/105.68] [< 128 us: 3.99/94.71] [< 256 us: 0.00/94.71] [< 512 us: 0.00/59.82] [< 1024 us: 0.00/54.83] [< 2048 us: 0.00/96.71] [< 4096 us: 0.00/95.71] [< 8192 us: 0.00/63.81] [< 16384 us: 0.00/11.96] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 63.11% (1640.76 Mhz) + +Core 2 C-state residency: 86.05% (C3: 0.56% C6: 0.00% C7: 85.48% ) + +CPU 4 duty cycles/s: active/idle [< 16 us: 372.87/131.60] [< 32 us: 92.72/47.86] [< 64 us: 166.50/115.65] [< 128 us: 115.65/126.62] [< 256 us: 77.76/82.75] [< 512 us: 56.83/60.82] [< 1024 us: 21.93/65.80] [< 2048 us: 2.99/126.62] [< 4096 us: 1.00/98.70] [< 8192 us: 0.00/46.86] [< 16384 us: 1.00/4.98] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 64.48% (1676.61 Mhz) + +CPU 5 duty cycles/s: active/idle [< 16 us: 860.39/108.67] [< 32 us: 4.98/99.70] [< 64 us: 4.98/104.68] [< 128 us: 4.98/91.72] [< 256 us: 1.99/93.72] [< 512 us: 0.00/61.81] [< 1024 us: 0.00/52.84] [< 2048 us: 0.00/103.69] [< 4096 us: 0.00/83.75] [< 8192 us: 0.00/57.82] [< 16384 us: 0.00/17.95] [< 32768 us: 0.00/1.00] +CPU Average frequency as fraction of nominal: 59.42% (1544.96 Mhz) + +Core 3 C-state residency: 90.93% (C3: 0.27% C6: 0.00% C7: 90.67% ) + +CPU 6 duty cycles/s: active/idle [< 16 us: 308.07/74.77] [< 32 us: 47.86/21.93] [< 64 us: 94.71/71.78] [< 128 us: 105.68/89.73] [< 256 us: 53.84/44.86] [< 512 us: 49.85/50.85] [< 1024 us: 11.96/50.85] [< 2048 us: 1.99/110.66] [< 4096 us: 0.00/88.73] [< 8192 us: 0.00/60.82] [< 16384 us: 0.00/9.97] [< 32768 us: 0.00/0.00] +CPU Average frequency as fraction of nominal: 57.97% (1507.26 Mhz) + +CPU 7 duty cycles/s: active/idle [< 16 us: 153.54/13.96] [< 32 us: 1.00/7.98] [< 64 us: 7.98/9.97] [< 128 us: 1.00/12.96] [< 256 us: 1.99/12.96] [< 512 us: 0.00/12.96] [< 1024 us: 0.00/3.99] [< 2048 us: 0.00/11.96] [< 4096 us: 0.00/16.95] [< 8192 us: 0.00/13.96] [< 16384 us: 0.00/24.92] [< 32768 us: 0.00/18.94] +CPU Average frequency as fraction of nominal: 60.39% (1570.13 Mhz) + +Core 4 C-state residency: 94.78% (C3: 0.00% C6: 0.00% C7: 94.78% ) + +CPU 8 duty cycles/s: active/idle [< 16 us: 159.52/18.94] [< 32 us: 20.94/3.99] [< 64 us: 29.91/40.88] [< 128 us: 50.85/28.91] [< 256 us: 37.89/19.94] [< 512 us: 23.93/18.94] [< 1024 us: 6.98/20.94] [< 2048 us: 1.00/47.86] [< 4096 us: 1.00/38.88] [< 8192 us: 1.00/57.82] [< 16384 us: 0.00/32.90] [< 32768 us: 0.00/2.99] +CPU Average frequency as fraction of nominal: 59.35% (1542.99 Mhz) + +CPU 9 duty cycles/s: active/idle [< 16 us: 237.28/12.96] [< 32 us: 3.99/11.96] [< 64 us: 4.98/33.90] [< 128 us: 1.99/23.93] [< 256 us: 2.99/24.92] [< 512 us: 0.00/11.96] [< 1024 us: 1.00/10.97] [< 2048 us: 0.00/23.93] [< 4096 us: 0.00/23.93] [< 8192 us: 0.00/26.92] [< 16384 us: 0.00/31.90] [< 32768 us: 0.00/13.96] +CPU Average frequency as fraction of nominal: 61.44% (1597.36 Mhz) + +Core 5 C-state residency: 96.54% (C3: 0.00% C6: 0.00% C7: 96.54% ) + +CPU 10 duty cycles/s: active/idle [< 16 us: 118.64/21.93] [< 32 us: 14.95/3.99] [< 64 us: 31.90/28.91] [< 128 us: 42.87/26.92] [< 256 us: 15.95/7.98] [< 512 us: 15.95/10.97] [< 1024 us: 4.98/13.96] [< 2048 us: 1.99/34.89] [< 4096 us: 0.00/22.93] [< 8192 us: 1.00/31.90] [< 16384 us: 0.00/27.92] [< 32768 us: 0.00/15.95] +CPU Average frequency as fraction of nominal: 58.78% (1528.32 Mhz) + +CPU 11 duty cycles/s: active/idle [< 16 us: 21.93/1.00] [< 32 us: 1.00/0.00] [< 64 us: 1.99/0.00] [< 128 us: 1.99/1.99] [< 256 us: 1.00/1.00] [< 512 us: 0.00/0.00] [< 1024 us: 0.00/1.00] [< 2048 us: 0.00/2.99] [< 4096 us: 0.00/0.00] [< 8192 us: 0.00/1.00] [< 16384 us: 0.00/2.99] [< 32768 us: 0.00/2.99] +CPU Average frequency as fraction of nominal: 68.15% (1771.79 Mhz) diff --git a/src/test/resources/powermetrics-m1-m2.txt b/src/test/resources/powermetrics-m1-m2.txt new file mode 100644 index 0000000..562036d --- /dev/null +++ b/src/test/resources/powermetrics-m1-m2.txt @@ -0,0 +1,26 @@ +P1-Cluster Power: 100 mW +P1-Cluster HW active frequency: 679 MHz +P1-Cluster HW active residency: 2.27% (600 MHz: 95% 828 MHz: 0% 1056 MHz: .52% 1296 MHz: .55% 1524 MHz: .82% 1752 MHz: .19% 1980 MHz: .68% 2208 MHz: .34% 2448 MHz: .20% 2676 MHz: .22% 2904 MHz: 0% 3036 MHz: .45% 3132 MHz: .03% 3168 MHz: 0% 3228 MHz: 1.1%) +P1-Cluster idle residency: 97.73% +P1-Cluster instructions retired: 5.13456e+08 +P1-Cluster instructions per clock: 1.78784 +CPU 6 frequency: 2367 MHz +CPU 6 idle residency: 97.76% +CPU 6 active residency: 2.24% (600 MHz: .03% 828 MHz: 0% 1056 MHz: .09% 1296 MHz: .19% 1524 MHz: .39% 1752 MHz: .13% 1980 MHz: .20% 2208 MHz: .03% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .98%) +CPU 7 frequency: 2233 MHz +CPU 7 idle residency: 98.51% +CPU 7 active residency: 1.49% (600 MHz: .00% 828 MHz: 0% 1056 MHz: .02% 1296 MHz: .18% 1524 MHz: .39% 1752 MHz: .02% 1980 MHz: .18% 2208 MHz: 0% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .49%) +CPU 8 frequency: 2247 MHz +CPU 8 idle residency: 98.58% +CPU 8 active residency: 1.42% (600 MHz: .00% 828 MHz: 0% 1056 MHz: .00% 1296 MHz: .16% 1524 MHz: .39% 1752 MHz: .00% 1980 MHz: .20% 2208 MHz: 0% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .47%) +CPU 9 frequency: 2247 MHz +CPU 9 idle residency: 98.59% +CPU 9 active residency: 1.41% (600 MHz: .00% 828 MHz: 0% 1056 MHz: 0% 1296 MHz: .17% 1524 MHz: .39% 1752 MHz: 0% 1980 MHz: .20% 2208 MHz: 0% 2448 MHz: .19% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .47%) + +System instructions retired: 1.25248e+10 +System instructions per clock: 1.35631 +ANE Power: 0 mW +DRAM Power: 688 mW +CPU Power: 742 mW +GPU Power: 26 mW +Package Power: 2151 mW From 7cc085027db63e7c091f782d9b933327a3dd6c47 Mon Sep 17 00:00:00 2001 From: Arjan Lamers Date: Mon, 15 Jan 2024 21:51:59 +0100 Subject: [PATCH 07/14] some cleanup and mentioning origin of data --- .../java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java | 1 - .../org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index 4e034b1..ba8aa1e 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -4,7 +4,6 @@ import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.util.logging.Level; import java.util.logging.Logger; diff --git a/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java index 4b27332..b303e02 100644 --- a/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java +++ b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java @@ -4,8 +4,6 @@ import java.io.*; import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Paths; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -16,6 +14,7 @@ void parseM1M2PowerLines() { PowermetricsMacOS cpu = new PowermetricsMacOS() { @Override protected BufferedReader getReader() { + // using data from https://abhimanbhau.github.io/mac/m1-mac-power-usage-monitor/ return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-m1-m2.txt"))); } }; From 2cdaa0c3f7539ea8a5ee025252925209dce369ae Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Wed, 17 Jan 2024 13:04:04 +0100 Subject: [PATCH 08/14] undoing unlrelated changes --- pom.xml | 4 ++-- .../noureddine/joularjx/cpu/PowermetricsMacOS.java | 11 ++++------- .../java/org/noureddine/joularjx/cpu/RaplLinux.java | 4 +--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 7b8e079..78d794b 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.noureddine joularjx - 2.8.0a + 2.8.0 jar ${project.artifactId} @@ -115,4 +115,4 @@ - + \ No newline at end of file diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index d0082f3..dfb9be8 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -44,17 +44,14 @@ public double getCurrentPower(double cpuLoad) { BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = input.readLine()) != null) { - // look for line that contains combined power measurement + // look for line that contains combined power measurement // which should look similar to: `Combined Power (CPU + GPU + ANE): 377 mW` - // it seems this output is for older versions (?), current version (Sonoma 14.0) gives the following line: - // `Intel energy model derived package power (CPUs+GT+SA): 48.61W` - if (!line.startsWith("Intel energy model derived package power")) { + if (!line.startsWith("Combined")) { continue; } final var powerValue = line.split(":")[1]; - final var powerInMilliwatts = powerValue.split("W")[0]; - //logger.info("Current power (w): " + powerInMilliwatts); - return Double.parseDouble(powerInMilliwatts); // / 1000; // NOTE not needed to divide by 1000 since the values is not in mW! + final var powerInMilliwatts = powerValue.split("m")[0]; + return Double.parseDouble(powerInMilliwatts) / 1000; } } catch (Exception exception) { logger.throwing(getClass().getName(), "getCurrentPower", exception); diff --git a/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java b/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java index ede5dd7..9a2fbe0 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java +++ b/src/main/java/org/noureddine/joularjx/cpu/RaplLinux.java @@ -19,9 +19,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -39,7 +37,7 @@ public class RaplLinux implements Cpu { * RAPL files existing on the current system. All files in this list will be used for reading the * energy values. */ - private final Set raplFilesToRead = new HashSet<>(3); + private final List raplFilesToRead = new ArrayList<>(3); /** * Filesystem where the RAPL files are located. From d8976edbfbdff92623045d1ab7c074759bcab02c Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 18 Jan 2024 10:17:46 +0100 Subject: [PATCH 09/14] chore: only activate RAPL Linux tests on Linux --- src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java b/src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java index e3dc844..49b5e90 100644 --- a/src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java +++ b/src/test/java/org/noureddine/joularjx/cpu/RaplLinuxTest.java @@ -16,6 +16,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.noureddine.joularjx.utils.JoularJXLogging; import java.io.IOException; @@ -28,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.*; +@EnabledOnOs(OS.LINUX) class RaplLinuxTest { private FileSystem fileSystem; From 2eaa890316c0d43c38ea27dfa36cc8f8335b54de Mon Sep 17 00:00:00 2001 From: Fitsum Kifetew Date: Mon, 22 Jan 2024 11:38:57 +0100 Subject: [PATCH 10/14] clean up --- .../joularjx/monitor/MonitoringHandler.java | 52 ++----------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java index c2a29d4..6dcce8f 100644 --- a/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java +++ b/src/main/java/org/noureddine/joularjx/monitor/MonitoringHandler.java @@ -258,53 +258,10 @@ private Map> extractCallTreesStats(Map> methodsStats, Map threadsCpuTime) { -// long totalThreadsCpuTime = 0; -// for (var entry : methodsStats.entrySet()) { -// // the call could return a value of -1, which means thread not found or otherwise some other problem in reading cpu time for the PID -// long threadCpuTime = threadBean.getThreadCpuTime(entry.getKey().getId()); -// -// threadCpuTime *= entry.getValue().values().stream().mapToDouble(i -> i).sum() / sampleIterations; -// -// // If thread already monitored, then calculate CPU time since last time -// // Fix for issue #7 (https://github.com/joular/joularjx/issues/7) -// // If the last thread cpu time is <= 0, don't subtract, simply take the previous value -// threadCpuTime = threadsCpuTime.merge(entry.getKey().getId(), threadCpuTime, -// (present, newValue) -> newValue - present); -// -// totalThreadsCpuTime += threadCpuTime; -// } -// return totalThreadsCpuTime; -// } -// -// /** -// * Returns for each thread (PID) it's percentage of CPU time used -// * @param threadsCpuTime a map of CPU time per PID -// * @param totalThreadsCpuTime the CPU time used by all the monitored threads -// * @param processEnergy the energy consumed by the process -// * @return for each PID, the percentage of CPU time used by the associated thread -// */ -// private Map getThreadsCpuTimePercentage(Map threadsCpuTime, -// long totalThreadsCpuTime, -// double processEnergy) { -// Map threadsPower = new HashMap<>(); -// for (var entry : threadsCpuTime.entrySet()) { -// double percentageCpuTime = (entry.getValue() * 100.0) / totalThreadsCpuTime; -// double threadPower = processEnergy * (percentageCpuTime / 100.0); -// threadsPower.put(entry.getKey(), threadPower); -// } -// return threadsPower; -// } - /** - * + * Updates the CPU times for each Thread. + * Returns for each thread (PID) it's percentage of CPU time used * @param methodsStats a map of method occurrences for each thread * @param threadsCpuTime a map of CPU time per PID, contains the cpu time for each tread, resulting from the last call to getThreadCpuTime(threadId) * @param processEnergy the energy consumed by the process in the last monitoring period @@ -323,8 +280,9 @@ private Map getThreadsCpuTimePercentage(Map Date: Mon, 22 Jan 2024 22:11:49 +0100 Subject: [PATCH 11/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0488eca..9621aec 100755 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ To cite our work in a research paper, please cite our paper in the 18th Internat JoularJX is licensed under the GNU GPL 3 license only (GPL-3.0-only). -Copyright (c) 2021-2023, Adel Noureddine, Université de Pau et des Pays de l'Adour. +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 From fc403622c741f5a36e6bb79c4f8de0328e46f03a Mon Sep 17 00:00:00 2001 From: Arjan Lamers Date: Tue, 23 Jan 2024 11:35:54 +0100 Subject: [PATCH 12/14] replaced m1/m2 test resources from https://github.com/metacosm/power-server/tree/main moved intel vs m chip parsing to separate functions for performance added readHeader to detect intel vs m chip --- .../joularjx/cpu/PowermetricsMacOS.java | 64 +++++-- .../joularjx/cpu/PowermetricsMacOSTest.java | 81 ++++++-- src/test/resources/powermetrics-m1-m2.txt | 26 --- .../resources/powermetrics-monterey-m2.txt | 68 +++++++ ...ntel.txt => powermetrics-sonoma-intel.txt} | 0 .../resources/powermetrics-sonoma-m1max.txt | 178 ++++++++++++++++++ 6 files changed, 358 insertions(+), 59 deletions(-) delete mode 100644 src/test/resources/powermetrics-m1-m2.txt create mode 100644 src/test/resources/powermetrics-monterey-m2.txt rename src/test/resources/{powermetrics-intel.txt => powermetrics-sonoma-intel.txt} (100%) create mode 100644 src/test/resources/powermetrics-sonoma-m1max.txt diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index ba8aa1e..3c75d2c 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -19,6 +19,7 @@ public class PowermetricsMacOS implements Cpu { private BufferedReader reader; private boolean initialized; + boolean intelCpu = false; @Override public void initialize() { @@ -31,6 +32,7 @@ public void initialize() { process = Runtime.getRuntime().exec("sudo powermetrics --samplers cpu_power -i 1000"); reader = new BufferedReader(new InputStreamReader(process.getInputStream())); initialized = true; + readHeader(); } catch (Exception exception) { logger.log(Level.SEVERE, "Can't start powermetrics. Exiting..."); logger.throwing(getClass().getName(), "initialize", exception); @@ -38,6 +40,16 @@ public void initialize() { } } + void readHeader() throws IOException { + BufferedReader reader = getReader(); + for (int i=0; i<6; i++) { + String line = reader.readLine(); + if (line.startsWith("EFI version")) { + intelCpu = true; + } + } + } + @Override public double getInitialPower() { return 0; @@ -45,17 +57,46 @@ public double getInitialPower() { @Override public double getCurrentPower(double cpuLoad) { - int headerLinesToSkip = 10; - int powerInMilliwatts = 0; + if (intelCpu) { + return getCurrentPowerIntel(); + } else { + return getCurrentPowerM(); + } + } + + private double getCurrentPowerIntel() { + double powerInWatts = 0; try { String line; BufferedReader reader = getReader(); while (reader.ready() && (line = reader.readLine()) != null) { - if (headerLinesToSkip != 0) { - headerLinesToSkip--; + + // skip empty / header lines + if (line.isEmpty() || line.startsWith("*")) { continue; } + // ofor Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern + final var i = line.indexOf(POWER_INDICATOR_INTEL_CHIP); + if (i >= 0) { + powerInWatts += Double.parseDouble(line.substring(i + POWER_INDICATOR_INTEL_CHIP.length(), line.indexOf('W'))); + } + } + return powerInWatts; + } catch (IOException e) { + logger.throwing(getClass().getName(), "getCurrentPower", e); + } + + return 0.0; + } + + public double getCurrentPowerM() { + int powerInMilliwatts = 0; + try { + String line; + BufferedReader reader = getReader(); + while (reader.ready() && (line = reader.readLine()) != null) { + // skip empty / header lines if (line.isEmpty() || line.startsWith("*")) { continue; @@ -63,17 +104,10 @@ public double getCurrentPower(double cpuLoad) { // looking for line fitting the: " Power: xxx mW" pattern and add all of the associated values together // or, for Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern - final var powerIndicatorIndexM = line.indexOf(POWER_INDICATOR_M_CHIP); - final var powerIndicatorIndexIntel = line.indexOf(POWER_INDICATOR_INTEL_CHIP); - - // lines with `-` as the second char are disregarded as of the form: "E-Cluster Power: 6 mW" which fits the pattern but shouldn't be considered - // also ignore Combined Power if available since it is the sum of the other components - if (powerIndicatorIndexM >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { - powerInMilliwatts += extractPowerInMilliwatts(line, powerIndicatorIndexM + POWER_INDICATOR_M_CHIP.length()); - } - if (powerIndicatorIndexIntel >= 0) { - powerInMilliwatts += extractPowerInMilliwatts(line, powerIndicatorIndexIntel + POWER_INDICATOR_INTEL_CHIP.length()); - } + final var i = line.indexOf(POWER_INDICATOR_M_CHIP); + if (i >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { + powerInMilliwatts += Integer.parseInt(line.substring(i + POWER_INDICATOR_M_CHIP.length(), line.indexOf('m') - 1)); + } } return (double) powerInMilliwatts / 1000; } catch (IOException e) { diff --git a/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java index b303e02..6e9edca 100644 --- a/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java +++ b/src/test/java/org/noureddine/joularjx/cpu/PowermetricsMacOSTest.java @@ -5,22 +5,78 @@ import java.io.*; import java.net.URISyntaxException; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; public class PowermetricsMacOSTest { @Test - void parseM1M2PowerLines() { + void parseSonomaM1MaxPowerLines() { PowermetricsMacOS cpu = new PowermetricsMacOS() { @Override protected BufferedReader getReader() { - // using data from https://abhimanbhau.github.io/mac/m1-mac-power-usage-monitor/ - return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-m1-m2.txt"))); + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-sonoma-m1max.txt"))); } }; + cpu.intelCpu = false; - // the ??-Cluster lines are to be ignored, hence do not count the 100mW - assertEquals(/*0.100d +*/ 0d + 0.688d+0.742d + 0.026d + 2.151d, cpu.getCurrentPower(0), 0.0001d); + + // the ??-Cluster and Combined lines are to be ignored, hence do not count the 359mW + assertEquals(0.211d + 0.147d + 0d /* +0.359d */, cpu.getCurrentPower(0), 0.0001d); + } + + @Test + void parseMontereyM2PowerLines() { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-monterey-m2.txt"))); + } + }; + cpu.intelCpu = false; + + // the ??-Cluster and Combined lines are to be ignored, hence do not count the 6mW + assertEquals(/*0.006d*/ + 0d + 0.019d + 0.036d + 0.010d + 0d + 0.025d , cpu.getCurrentPower(0), 0.0001d); + } + + @Test + void parseSonomaIntelPowerLines() { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-sonoma-intel.txt"))); + } + }; + + cpu.intelCpu = true; + + assertEquals(4.87d + 3.43d + 3.38d + 4.21d + 3.21d , cpu.getCurrentPower(0), 0.0001d); + } + + + @Test + void parseHeaderIntel() throws IOException { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-sonoma-intel.txt"))); + } + }; + + cpu.readHeader(); + assertTrue(cpu.intelCpu); + } + + @Test + void parseHeaderM1() throws IOException { + PowermetricsMacOS cpu = new PowermetricsMacOS() { + @Override + protected BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-monterey-m2.txt"))); + } + }; + + cpu.readHeader(); + assertFalse(cpu.intelCpu); } /** @@ -37,7 +93,7 @@ void testIntermittentResults() throws IOException, URISyntaxException, Interrupt // create the content blocks including headers final String contents1 = "\n".repeat(10) + "CPU Power: 742 mW\n".repeat(2); - final String contents2 = "\n".repeat(10) + "CPU Power: 1.2W\n".repeat(2); + final String contents2 = "\n".repeat(10) + "CPU Power: 1200 mW\n".repeat(2); PowermetricsMacOS cpu = new PowermetricsMacOS() { @Override @@ -81,16 +137,5 @@ public void run() { return writerBlock1; } - @Test - void parseIntelPowerLines() { - PowermetricsMacOS cpu = new PowermetricsMacOS() { - @Override - protected BufferedReader getReader() { - return new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/powermetrics-intel.txt"))); - } - }; - - assertEquals(4.87d + 3.43d + 3.38d + 4.21d + 3.21d , cpu.getCurrentPower(0), 0.0001d); - } } diff --git a/src/test/resources/powermetrics-m1-m2.txt b/src/test/resources/powermetrics-m1-m2.txt deleted file mode 100644 index 562036d..0000000 --- a/src/test/resources/powermetrics-m1-m2.txt +++ /dev/null @@ -1,26 +0,0 @@ -P1-Cluster Power: 100 mW -P1-Cluster HW active frequency: 679 MHz -P1-Cluster HW active residency: 2.27% (600 MHz: 95% 828 MHz: 0% 1056 MHz: .52% 1296 MHz: .55% 1524 MHz: .82% 1752 MHz: .19% 1980 MHz: .68% 2208 MHz: .34% 2448 MHz: .20% 2676 MHz: .22% 2904 MHz: 0% 3036 MHz: .45% 3132 MHz: .03% 3168 MHz: 0% 3228 MHz: 1.1%) -P1-Cluster idle residency: 97.73% -P1-Cluster instructions retired: 5.13456e+08 -P1-Cluster instructions per clock: 1.78784 -CPU 6 frequency: 2367 MHz -CPU 6 idle residency: 97.76% -CPU 6 active residency: 2.24% (600 MHz: .03% 828 MHz: 0% 1056 MHz: .09% 1296 MHz: .19% 1524 MHz: .39% 1752 MHz: .13% 1980 MHz: .20% 2208 MHz: .03% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .98%) -CPU 7 frequency: 2233 MHz -CPU 7 idle residency: 98.51% -CPU 7 active residency: 1.49% (600 MHz: .00% 828 MHz: 0% 1056 MHz: .02% 1296 MHz: .18% 1524 MHz: .39% 1752 MHz: .02% 1980 MHz: .18% 2208 MHz: 0% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .49%) -CPU 8 frequency: 2247 MHz -CPU 8 idle residency: 98.58% -CPU 8 active residency: 1.42% (600 MHz: .00% 828 MHz: 0% 1056 MHz: .00% 1296 MHz: .16% 1524 MHz: .39% 1752 MHz: .00% 1980 MHz: .20% 2208 MHz: 0% 2448 MHz: .20% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .47%) -CPU 9 frequency: 2247 MHz -CPU 9 idle residency: 98.59% -CPU 9 active residency: 1.41% (600 MHz: .00% 828 MHz: 0% 1056 MHz: 0% 1296 MHz: .17% 1524 MHz: .39% 1752 MHz: 0% 1980 MHz: .20% 2208 MHz: 0% 2448 MHz: .19% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .47%) - -System instructions retired: 1.25248e+10 -System instructions per clock: 1.35631 -ANE Power: 0 mW -DRAM Power: 688 mW -CPU Power: 742 mW -GPU Power: 26 mW -Package Power: 2151 mW diff --git a/src/test/resources/powermetrics-monterey-m2.txt b/src/test/resources/powermetrics-monterey-m2.txt new file mode 100644 index 0000000..1e08b2d --- /dev/null +++ b/src/test/resources/powermetrics-monterey-m2.txt @@ -0,0 +1,68 @@ +Machine model: Mac14,2 +OS version: 21G72 +Boot arguments: +Boot time: Mon Oct 2 10:37:21 2023 + + + +*** Sampled system activity (Mon Oct 23 16:51:12 2023 +0200) (1012.07ms elapsed) *** + +*** Running tasks *** + +Name ID CPU ms/s samp ms/s User% Deadlines (<2 ms, 2-5 ms) Wakeups (Intr, Pkg idle) GPU ms/s +WindowServer 391 281.98 283.25 82.97 1.97 0.00 428.87 8.85 0.00 +mdworker_shared 29420 183.26 112.83 65.49 0.00 0.00 0.00 0.00 0.00 +powermetrics 29419 23.78 23.88 6.05 0.00 0.00 0.98 0.00 0.00 +ALL_TASKS -2 1222.65 1222.65 65.70 1161.97 15.81 2875.29 132.40 0.00 + +*** Sampled system activity (Tue Nov 28 11:28:55 2023 +0100) (1002.80ms elapsed) *** + + +**** Processor usage **** + +E-Cluster Power: 6 mW +E-Cluster HW active frequency: 919 MHz +E-Cluster HW active residency: 5.37% (600 MHz: 0% 912 MHz: 100% 1284 MHz: 0% 1752 MHz: 0% 2004 MHz: 0% 2256 MHz: 0% 2424 MHz: .44%) +E-Cluster idle residency: 94.63% +E-Cluster instructions retired: 5.66564e+07 +E-Cluster instructions per clock: 0.996462 +CPU 0 frequency: 920 MHz +CPU 0 idle residency: 97.09% +CPU 0 active residency: 2.91% (600 MHz: 0% 912 MHz: 2.9% 1284 MHz: 0% 1752 MHz: 0% 2004 MHz: 0% 2256 MHz: 0% 2424 MHz: .02%) +CPU 1 frequency: 922 MHz +CPU 1 idle residency: 98.03% +CPU 1 active residency: 1.97% (600 MHz: 0% 912 MHz: 2.0% 1284 MHz: 0% 1752 MHz: 0% 2004 MHz: 0% 2256 MHz: 0% 2424 MHz: .01%) +CPU 2 frequency: 943 MHz +CPU 2 idle residency: 98.82% +CPU 2 active residency: 1.18% (600 MHz: 0% 912 MHz: 1.2% 1284 MHz: 0% 1752 MHz: 0% 2004 MHz: 0% 2256 MHz: 0% 2424 MHz: .02%) +CPU 3 frequency: 913 MHz +CPU 3 idle residency: 99.04% +CPU 3 active residency: 0.96% (600 MHz: 0% 912 MHz: .96% 1284 MHz: 0% 1752 MHz: 0% 2004 MHz: 0% 2256 MHz: 0% 2424 MHz: .00%) + +P-Cluster Power: 4 mW +P-Cluster HW active frequency: 667 MHz +P-Cluster HW active residency: 0.00% (660 MHz: 100% 924 MHz: 0% 1188 MHz: 0% 1452 MHz: 0% 1704 MHz: 0% 1968 MHz: 0% 2208 MHz: 0% 2400 MHz: 0% 2568 MHz: 0% 2724 MHz: 0% 2868 MHz: 0% 2988 MHz: 0% 3096 MHz: 0% 3204 MHz: .03% 3324 MHz: .25% 3408 MHz: 0% 3504 MHz: 0%) +P-Cluster idle residency: 100.00% +P-Cluster instructions retired: 6.11748e+07 +P-Cluster instructions per clock: 2.88735 +CPU 4 frequency: 3079 MHz +CPU 4 idle residency: 99.81% +CPU 4 active residency: 0.19% (660 MHz: .03% 924 MHz: 0% 1188 MHz: 0% 1452 MHz: 0% 1704 MHz: 0% 1968 MHz: 0% 2208 MHz: 0% 2400 MHz: 0% 2568 MHz: 0% 2724 MHz: 0% 2868 MHz: 0% 2988 MHz: 0% 3096 MHz: 0% 3204 MHz: 0% 3324 MHz: .04% 3408 MHz: 0% 3504 MHz: .12%) +CPU 5 frequency: 1814 MHz +CPU 5 idle residency: 99.99% +CPU 5 active residency: 0.01% (660 MHz: .00% 924 MHz: 0% 1188 MHz: 0% 1452 MHz: 0% 1704 MHz: 0% 1968 MHz: 0% 2208 MHz: 0% 2400 MHz: 0% 2568 MHz: 0% 2724 MHz: 0% 2868 MHz: 0% 2988 MHz: 0% 3096 MHz: 0% 3204 MHz: 0% 3324 MHz: .00% 3408 MHz: 0% 3504 MHz: 0%) +CPU 6 frequency: 660 MHz +CPU 6 idle residency: 100.00% +CPU 6 active residency: 0.00% (660 MHz: .00% 924 MHz: 0% 1188 MHz: 0% 1452 MHz: 0% 1704 MHz: 0% 1968 MHz: 0% 2208 MHz: 0% 2400 MHz: 0% 2568 MHz: 0% 2724 MHz: 0% 2868 MHz: 0% 2988 MHz: 0% 3096 MHz: 0% 3204 MHz: 0% 3324 MHz: 0% 3408 MHz: 0% 3504 MHz: 0%) +CPU 7 frequency: 660 MHz +CPU 7 idle residency: 100.00% +CPU 7 active residency: 0.00% (660 MHz: .00% 924 MHz: 0% 1188 MHz: 0% 1452 MHz: 0% 1704 MHz: 0% 1968 MHz: 0% 2208 MHz: 0% 2400 MHz: 0% 2568 MHz: 0% 2724 MHz: 0% 2868 MHz: 0% 2988 MHz: 0% 3096 MHz: 0% 3204 MHz: 0% 3324 MHz: 0% 3408 MHz: 0% 3504 MHz: 0%) + +System instructions retired: 1.17831e+08 +System instructions per clock: 1.50979 +ANE Power: 0 mW +DRAM Power: 19 mW +DCS Power: 36 mW +CPU Power: 10 mW +GPU Power: 0 mW +Package Power: 25 mW diff --git a/src/test/resources/powermetrics-intel.txt b/src/test/resources/powermetrics-sonoma-intel.txt similarity index 100% rename from src/test/resources/powermetrics-intel.txt rename to src/test/resources/powermetrics-sonoma-intel.txt diff --git a/src/test/resources/powermetrics-sonoma-m1max.txt b/src/test/resources/powermetrics-sonoma-m1max.txt new file mode 100644 index 0000000..e2e6133 --- /dev/null +++ b/src/test/resources/powermetrics-sonoma-m1max.txt @@ -0,0 +1,178 @@ +Machine model: MacBookPro18,4 +OS version: 22G120 +Boot arguments: +Boot time: Sat Oct 21 19:09:01 2023 + + + +*** Sampled system activity (Mon Oct 23 16:51:12 2023 +0200) (1012.07ms elapsed) *** + +*** Running tasks *** + +Name ID CPU ms/s samp ms/s User% Deadlines (<2 ms, 2-5 ms) Wakeups (Intr, Pkg idle) GPU ms/s +WindowServer 391 281.98 283.25 82.97 1.97 0.00 428.87 8.85 0.00 +mdworker_shared 29420 183.26 112.83 65.49 0.00 0.00 0.00 0.00 0.00 +powermetrics 29419 23.78 23.88 6.05 0.00 0.00 0.98 0.00 0.00 +firefox 678 151.38 152.06 75.55 0.00 0.98 34.43 0.98 0.00 +kernel_task 0 116.12 116.64 0.00 422.96 0.00 805.60 74.76 0.00 +idea 21834 126.37 126.94 64.94 708.22 4.92 898.06 26.56 0.00 +iTerm2 1008 32.62 32.77 76.15 0.00 0.00 22.62 0.00 0.00 +plugin-container 1096 28.85 28.98 84.36 0.00 0.00 6.89 0.00 0.00 +Music 669 41.97 42.16 72.99 0.00 0.00 86.56 0.98 0.00 +coreaudiod 412 35.09 35.25 87.47 0.00 0.00 86.56 1.97 0.00 +plugin-container 1088 41.86 42.05 93.85 9.84 4.92 44.26 0.00 0.00 +plugin-container 1037 24.55 24.67 84.93 4.92 3.93 17.71 0.00 0.00 +plugin-container 1089 13.66 13.72 85.91 0.00 0.00 3.93 0.00 0.00 +cfprefsd 604 6.33 6.36 45.20 0.00 0.00 0.00 0.00 0.00 +DEAD_TASKS -1 12.64 12.64 29.96 0.00 0.00 0.00 0.00 0.00 +launchd 1 7.86 7.90 38.55 0.00 0.00 0.00 0.00 0.00 +jetbrains-toolbox 1015 10.18 10.23 63.26 0.98 0.00 46.23 1.97 0.00 +sentineld 824 10.29 10.34 75.10 0.00 0.00 0.98 0.00 0.00 +cfprefsd 392 4.59 4.61 45.98 0.00 0.00 0.00 0.00 0.00 +splunkd 1501 9.18 9.22 37.18 4.92 0.00 40.33 1.97 0.00 +WindowManager 619 4.12 4.13 88.28 0.00 0.00 0.00 0.00 0.00 +mds_stores 610 5.72 5.75 46.17 0.00 0.00 0.00 0.00 0.00 +mds 350 5.55 5.58 53.73 0.00 0.00 1.97 0.00 0.00 +plugin-container 1085 7.85 7.89 88.19 1.97 0.98 11.80 2.95 0.00 +opendirectoryd 362 3.59 3.61 50.33 0.00 0.00 0.00 0.00 0.00 +Signal Helper (GPU) 26193 2.58 2.59 26.50 0.00 0.00 0.00 0.00 0.00 +notifyd 385 3.49 3.50 59.15 0.00 0.00 0.00 0.00 0.00 +1Password Helper (GPU) 1027 2.08 2.09 28.14 0.00 0.00 0.00 0.00 0.00 +plugin-container 1187 3.58 3.59 88.38 0.00 0.00 13.77 0.98 0.00 +LaunchBar 952 4.79 4.81 69.92 0.00 0.00 52.13 2.95 0.00 +logd 322 3.60 3.62 47.91 0.00 0.00 0.00 0.00 0.00 +OnlySwitch 1017 3.85 3.86 72.79 0.00 0.00 42.30 1.97 0.00 +Ferdi 12523 3.97 3.99 80.01 0.98 0.00 1.97 0.00 0.00 +plugin-container 1186 2.74 2.75 83.76 0.00 0.00 10.82 0.00 0.00 +plugin-container 1119 2.77 2.78 81.36 0.00 0.00 11.80 0.00 0.00 +java 22015 2.95 2.96 59.12 0.00 0.00 24.59 0.00 0.00 +java 21951 3.22 3.24 52.44 0.00 0.00 24.59 0.98 0.00 +plugin-container 23298 2.72 2.73 81.68 0.00 0.00 10.82 0.98 0.00 +java 21923 2.87 2.88 56.29 0.00 0.00 25.57 1.97 0.00 +java 22095 2.85 2.86 57.81 0.00 0.00 24.59 0.98 0.00 +Ferdi Helper (GPU) 12531 1.70 1.71 49.64 0.00 0.00 1.97 0.00 0.00 +jcef Helper (GPU) 21932 1.11 1.12 32.20 0.00 0.00 0.00 0.00 0.00 +diskarbitrationd 353 0.38 0.38 59.74 0.00 0.00 0.00 0.00 0.00 +plugin-container 1114 1.48 1.48 72.19 0.00 0.00 0.98 0.00 0.00 +SentinelAgent 936 1.06 1.07 32.01 0.00 0.00 0.00 0.00 0.00 +fseventsd 327 1.82 1.83 19.75 0.00 0.00 2.95 0.00 0.00 +corebrightnessd 387 2.47 2.48 53.16 0.00 0.00 0.98 0.00 0.00 +com.apple.AmbientDisplayAgent 822 1.73 1.73 56.59 0.00 0.00 0.00 0.00 0.00 +searchpartyd 534 3.02 3.04 85.12 0.00 0.00 0.00 0.00 0.00 +Python 931 2.57 2.59 71.71 0.00 0.00 5.90 0.00 0.00 +Ferdi Helper (Renderer) 12533 1.44 1.44 92.33 0.00 0.00 0.98 0.00 0.00 +sentineld_helper 585 1.60 1.60 43.98 0.00 0.00 0.00 0.00 0.00 +locationd 370 2.31 2.32 71.00 0.00 0.00 0.00 0.00 0.00 +bluetoothd 384 2.60 2.61 61.28 0.00 0.00 0.00 0.00 0.00 +pboard 666 1.44 1.44 47.17 0.00 0.00 0.00 0.00 0.00 +lsd 621 0.84 0.84 53.44 0.00 0.00 0.00 0.00 0.00 +plugin-container 9519 3.07 3.09 91.80 0.00 0.00 2.95 0.00 0.00 +Ferdi Helper 12532 1.37 1.38 77.37 0.00 0.00 3.93 0.00 0.00 +coreservicesd 397 0.76 0.76 54.01 0.00 0.00 0.00 0.00 0.00 +plugin-container 9000 1.11 1.12 75.19 0.00 0.00 3.93 0.00 0.00 +plugin-container 1118 0.84 0.84 80.90 0.00 0.00 3.93 0.00 0.00 +Ferdi Helper (Renderer) 12541 1.09 1.09 93.65 0.00 0.00 0.00 0.00 0.00 +Ferdi Helper (Renderer) 29240 1.49 1.50 90.96 0.00 0.00 1.97 0.00 0.00 +plugin-container 9198 1.00 1.01 77.50 0.00 0.00 3.93 0.00 0.00 +Ferdi Helper (Renderer) 12543 0.78 0.79 91.89 0.00 0.00 0.00 0.00 0.00 +plugin-container 23543 1.34 1.35 92.66 0.00 0.00 1.97 0.00 0.00 +distnoted 603 0.51 0.52 37.12 0.00 0.00 0.00 0.00 0.00 +Finder 700 0.49 0.50 51.78 0.00 0.00 0.00 0.00 0.00 +audioclocksyncd 543 0.84 0.84 57.84 0.00 0.00 0.00 0.00 0.00 +PerfPowerServices 17302 0.96 0.97 83.19 0.00 0.00 0.00 0.00 0.00 +plugin-container 9055 0.63 0.64 87.29 0.00 0.00 1.97 0.00 0.00 +storagekitd 7040 0.34 0.34 53.18 0.00 0.00 0.98 0.00 0.00 +heard 922 0.35 0.35 67.45 0.00 0.00 0.98 0.00 0.00 +lockoutagent 641 0.28 0.29 41.08 0.00 0.00 0.98 0.00 0.00 +nearbyd 1024 0.20 0.20 37.90 0.00 0.00 0.98 0.00 0.00 +plugin-container 1091 0.36 0.36 84.72 0.00 0.00 1.97 0.00 0.00 +plugin-container 1190 0.35 0.35 86.92 0.00 0.00 2.95 0.00 0.00 +fsnotifier 21921 0.21 0.21 32.94 0.00 0.00 0.00 0.00 0.00 +plugin-container 9001 0.52 0.52 76.73 0.00 0.00 1.97 0.00 0.00 +plugin-container 9190 0.49 0.49 87.71 0.00 0.00 1.97 0.00 0.00 +plugin-container 28295 0.38 0.38 85.60 0.00 0.00 1.97 0.00 0.00 +gamecontrollerd 613 0.25 0.25 50.77 0.00 0.00 0.98 0.00 0.00 +plugin-container 9191 0.37 0.37 84.36 0.00 0.00 1.97 0.00 0.00 +launchservicesd 364 0.22 0.22 52.01 0.00 0.00 0.98 0.00 0.00 +1Password 1021 0.31 0.31 41.60 0.00 0.00 3.93 0.00 0.00 +thermalmonitord 361 0.31 0.32 43.75 0.00 0.00 0.98 0.00 0.00 +askpermissiond 938 0.09 0.09 20.67 0.00 0.00 0.98 0.00 0.00 +ContinuityCaptureAgent 728 0.15 0.15 28.65 0.00 0.00 1.97 0.00 0.00 +appleh13camerad 545 0.12 0.12 29.55 0.00 0.00 0.98 0.00 0.00 +com.apple.WebKit.WebContent 1874 0.18 0.18 58.02 0.00 0.00 0.98 0.00 0.00 +CAReportingService 562 0.07 0.07 37.92 0.00 0.00 0.98 0.00 0.00 +appstoreagent 1107 0.16 0.16 26.86 0.00 0.00 0.98 0.00 0.00 +contextstored 400 0.18 0.18 20.74 0.00 0.00 0.98 0.00 0.00 +akd 731 0.08 0.08 45.70 0.00 0.00 0.98 0.00 0.00 +mDNSResponderHelper 508 0.08 0.08 35.75 0.00 0.00 0.98 0.00 0.00 +AMPArtworkAgent 799 0.11 0.11 71.12 0.00 0.00 0.98 0.00 0.00 +weatherd 1912 0.09 0.09 47.37 0.00 0.00 0.98 0.00 0.00 +photoanalysisd 16189 0.09 0.09 32.44 0.00 0.00 0.98 0.00 0.00 +bookdatastored 9301 0.07 0.07 42.43 0.00 0.00 0.98 0.00 0.00 +nbagent 6922 0.08 0.08 56.92 0.00 0.00 0.98 0.00 0.00 +osqueryd 24140 0.13 0.13 86.31 0.00 0.00 0.98 0.00 0.00 +cloudphotod 1575 0.06 0.06 43.66 0.00 0.00 0.98 0.00 0.00 +storekitagent 800 0.06 0.06 44.65 0.00 0.00 0.98 0.00 0.00 +mlruntimed 1542 0.06 0.06 44.98 0.00 0.00 0.98 0.00 0.00 +newsd 6844 0.06 0.06 45.11 0.00 0.00 0.98 0.00 0.00 +ALL_TASKS -2 1222.65 1222.65 65.70 1161.97 15.81 2875.29 132.40 0.00 + +**** Processor usage **** + +E-Cluster Online: 100% +E-Cluster HW active frequency: 1499 MHz +E-Cluster HW active residency: 67.87% (600 MHz: 0% 972 MHz: 27% 1332 MHz: 24% 1704 MHz: 26% 2064 MHz: 23%) +E-Cluster idle residency: 32.13% +E-Cluster instructions retired: 1.20745e+09 +E-Cluster instructions per clock: 0.703911 +CPU 0 frequency: 1527 MHz +CPU 0 active residency: 54.12% (600 MHz: 0% 972 MHz: 12% 1332 MHz: 15% 1704 MHz: 13% 2064 MHz: 14%) +CPU 0 idle residency: 45.88% +CPU 1 frequency: 1530 MHz +CPU 1 active residency: 55.47% (600 MHz: 0% 972 MHz: 13% 1332 MHz: 15% 1704 MHz: 13% 2064 MHz: 15%) +CPU 1 idle residency: 44.53% + +P0-Cluster Online: 100% +P0-Cluster HW active frequency: 876 MHz +P0-Cluster HW active residency: 16.05% (600 MHz: 62% 828 MHz: 5.7% 1056 MHz: 18% 1296 MHz: 4.9% 1524 MHz: 3.3% 1752 MHz: 1.3% 1980 MHz: 1.5% 2208 MHz: 1.4% 2448 MHz: .39% 2676 MHz: .37% 2904 MHz: 0% 3036 MHz: .07% 3132 MHz: .28% 3168 MHz: .19% 3228 MHz: 1.2%) +P0-Cluster idle residency: 83.95% +P0-Cluster instructions retired: 4.30488e+08 +P0-Cluster instructions per clock: 1.87471 +CPU 2 frequency: 1237 MHz +CPU 2 active residency: 12.66% (600 MHz: 1.6% 828 MHz: .53% 1056 MHz: 5.9% 1296 MHz: 1.9% 1524 MHz: 1.3% 1752 MHz: .40% 1980 MHz: .10% 2208 MHz: .17% 2448 MHz: .01% 2676 MHz: .08% 2904 MHz: 0% 3036 MHz: .01% 3132 MHz: .00% 3168 MHz: .00% 3228 MHz: .62%) +CPU 2 idle residency: 87.34% +CPU 3 frequency: 1066 MHz +CPU 3 active residency: 4.02% (600 MHz: .96% 828 MHz: .46% 1056 MHz: 1.3% 1296 MHz: .68% 1524 MHz: .44% 1752 MHz: .07% 1980 MHz: .02% 2208 MHz: .00% 2448 MHz: .00% 2676 MHz: .03% 2904 MHz: 0% 3036 MHz: .00% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .05%) +CPU 3 idle residency: 95.98% +CPU 4 frequency: 1212 MHz +CPU 4 active residency: 2.01% (600 MHz: .12% 828 MHz: .34% 1056 MHz: .92% 1296 MHz: .26% 1524 MHz: .17% 1752 MHz: .04% 1980 MHz: .05% 2208 MHz: .03% 2448 MHz: .01% 2676 MHz: .01% 2904 MHz: 0% 3036 MHz: .01% 3132 MHz: .01% 3168 MHz: .00% 3228 MHz: .06%) +CPU 4 idle residency: 97.99% +CPU 5 frequency: 1104 MHz +CPU 5 active residency: 0.82% (600 MHz: .02% 828 MHz: .16% 1056 MHz: .46% 1296 MHz: .10% 1524 MHz: .06% 1752 MHz: .00% 1980 MHz: 0% 2208 MHz: .00% 2448 MHz: 0% 2676 MHz: .00% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: .01%) +CPU 5 idle residency: 99.18% + +P1-Cluster Online: 100% +P1-Cluster HW active frequency: 629 MHz +P1-Cluster HW active residency: 0.61% (600 MHz: 94% 828 MHz: 2.1% 1056 MHz: 2.7% 1296 MHz: 1.5% 1524 MHz: .13% 1752 MHz: 0% 1980 MHz: 0% 2208 MHz: 0% 2448 MHz: 0% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: 0%) +P1-Cluster idle residency: 99.39% +P1-Cluster instructions retired: 4.84998e+06 +P1-Cluster instructions per clock: 0.692523 +CPU 6 frequency: 962 MHz +CPU 6 active residency: 0.56% (600 MHz: .07% 828 MHz: .21% 1056 MHz: .17% 1296 MHz: .11% 1524 MHz: .00% 1752 MHz: 0% 1980 MHz: 0% 2208 MHz: 0% 2448 MHz: 0% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: 0%) +CPU 6 idle residency: 99.44% +CPU 7 frequency: 1074 MHz +CPU 7 active residency: 0.10% (600 MHz: .01% 828 MHz: .01% 1056 MHz: .06% 1296 MHz: .02% 1524 MHz: .00% 1752 MHz: 0% 1980 MHz: 0% 2208 MHz: 0% 2448 MHz: 0% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: 0%) +CPU 7 idle residency: 99.90% +CPU 8 frequency: 1245 MHz +CPU 8 active residency: 0.02% (600 MHz: 0% 828 MHz: .00% 1056 MHz: .00% 1296 MHz: .02% 1524 MHz: .00% 1752 MHz: 0% 1980 MHz: 0% 2208 MHz: 0% 2448 MHz: 0% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: 0%) +CPU 8 idle residency: 99.98% +CPU 9 frequency: 1289 MHz +CPU 9 active residency: 0.02% (600 MHz: 0% 828 MHz: 0% 1056 MHz: .00% 1296 MHz: .02% 1524 MHz: .00% 1752 MHz: 0% 1980 MHz: 0% 2208 MHz: 0% 2448 MHz: 0% 2676 MHz: 0% 2904 MHz: 0% 3036 MHz: 0% 3132 MHz: 0% 3168 MHz: 0% 3228 MHz: 0%) +CPU 9 idle residency: 99.98% + +System instructions retired: 1.64279e+09 +System instructions per clock: 0.841601 +CPU Power: 211 mW +GPU Power: 147 mW +ANE Power: 0 mW +Combined Power (CPU + GPU + ANE): 359 mW \ No newline at end of file From e7f41802b1b1c763b72b8f3d8f7d5d462ee613b1 Mon Sep 17 00:00:00 2001 From: Arjan Lamers Date: Tue, 23 Jan 2024 16:08:05 +0100 Subject: [PATCH 13/14] minor formatting and comment fixes --- .../joularjx/cpu/PowermetricsMacOS.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java index 3c75d2c..1164885 100644 --- a/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java +++ b/src/main/java/org/noureddine/joularjx/cpu/PowermetricsMacOS.java @@ -23,10 +23,10 @@ public class PowermetricsMacOS implements Cpu { @Override public void initialize() { - if(initialized) { + if (initialized) { return; } - + try { // todo: detect when sudo fails as this currently won't throw an exception process = Runtime.getRuntime().exec("sudo powermetrics --samplers cpu_power -i 1000"); @@ -42,7 +42,7 @@ public void initialize() { void readHeader() throws IOException { BufferedReader reader = getReader(); - for (int i=0; i<6; i++) { + for (int i = 0; i < 6; i++) { String line = reader.readLine(); if (line.startsWith("EFI version")) { intelCpu = true; @@ -76,7 +76,7 @@ private double getCurrentPowerIntel() { continue; } - // ofor Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern + // for Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern final var i = line.indexOf(POWER_INDICATOR_INTEL_CHIP); if (i >= 0) { powerInWatts += Double.parseDouble(line.substring(i + POWER_INDICATOR_INTEL_CHIP.length(), line.indexOf('W'))); @@ -103,11 +103,10 @@ public double getCurrentPowerM() { } // looking for line fitting the: " Power: xxx mW" pattern and add all of the associated values together - // or, for Intel chips, the: "Intel energy model derived package power (CPUs+GT+SA): xxx W" pattern - final var i = line.indexOf(POWER_INDICATOR_M_CHIP); - if (i >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { - powerInMilliwatts += Integer.parseInt(line.substring(i + POWER_INDICATOR_M_CHIP.length(), line.indexOf('m') - 1)); - } + final var i = line.indexOf(POWER_INDICATOR_M_CHIP); + if (i >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { + powerInMilliwatts += Integer.parseInt(line.substring(i + POWER_INDICATOR_M_CHIP.length(), line.indexOf('m') - 1)); + } } return (double) powerInMilliwatts / 1000; } catch (IOException e) { From 5dcadbc0bd4c71ea3727aeac83ae52b935371653 Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Mon, 29 Jan 2024 15:51:51 +0100 Subject: [PATCH 14/14] Preparing 2.8.2 release --- .mvn/wrapper/maven-wrapper.jar | Bin 62547 -> 59925 bytes .mvn/wrapper/maven-wrapper.properties | 36 +- PowerMonitor/Main.cpp | 138 +++--- config-installer.bat | 50 +- config.properties | 2 +- install/config.properties | 2 +- install/joularjx-2.8.1.jar | Bin 46515 -> 0 bytes install/joularjx-2.8.2.jar | Bin 0 -> 47583 bytes install/linux-install.sh | 44 +- install/windows-install.bat | 48 +- pom.xml | 12 +- .../java/org/noureddine/joularjx/Agent.java | 4 +- .../java/org/noureddine/joularjx/cpu/Cpu.java | 42 +- .../noureddine/joularjx/cpu/CpuFactory.java | 2 +- .../noureddine/joularjx/cpu/IntelWindows.java | 2 +- .../joularjx/cpu/PowermetricsMacOS.java | 10 + .../noureddine/joularjx/cpu/RaplLinux.java | 284 +++++------ .../noureddine/joularjx/cpu/RaspberryPi.java | 2 +- .../joularjx/cpu/RaspberryPiModels.java | 2 +- .../joularjx/monitor/MonitoringHandler.java | 2 +- .../joularjx/monitor/MonitoringStatus.java | 2 +- .../joularjx/monitor/ShutdownHandler.java | 2 +- .../joularjx/result/CsvResultWriter.java | 2 +- .../joularjx/result/ResultTreeManager.java | 456 +++++++++--------- .../joularjx/result/ResultWriter.java | 44 +- .../joularjx/utils/AgentProperties.java | 2 +- .../noureddine/joularjx/utils/CallTree.java | 2 +- .../joularjx/utils/JoularJXFormatter.java | 2 +- .../joularjx/utils/JoularJXLogging.java | 2 +- .../org/noureddine/joularjx/utils/Scope.java | 2 +- .../joularjx/utils/StackTraceFilter.java | 78 +-- .../joularjx/cpu/PowermetricsMacOSTest.java | 10 + .../joularjx/cpu/RaplLinuxTest.java | 2 +- .../result/ResultTreeManagerTest.java | 274 +++++------ .../joularjx/utils/AgentPropertiesTest.java | 2 +- .../joularjx/utils/CallTreeTest.java | 226 ++++----- 36 files changed, 905 insertions(+), 885 deletions(-) delete mode 100644 install/joularjx-2.8.1.jar create mode 100644 install/joularjx-2.8.2.jar diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index cb28b0e37c7d206feb564310fdeec0927af4123a..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 100644 GIT binary patch delta 50109 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%0DIoqqGCqH%97HM??=#psgoIz5zcKJ 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 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index ac18401..34f5308 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,18 +1,18 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/PowerMonitor/Main.cpp b/PowerMonitor/Main.cpp index 0188d44..b141f89 100644 --- a/PowerMonitor/Main.cpp +++ b/PowerMonitor/Main.cpp @@ -1,70 +1,70 @@ -/* - * Copyright (c) 2021-2023, 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 - */ - -#include - -#include - -#include -#include -#include "IntelPowerGadgetLib.h" - -using namespace std; - -int main() { - CIntelPowerGadgetLib energyLib; - - if (energyLib.IntelEnergyLibInitialize() == false) { - return 0; - } - - int nNodes = 0; - int nMsrs = 0; - - energyLib.GetNumNodes(&nNodes); - energyLib.GetNumMsrs(&nMsrs); - - while (true) { - if (!energyLib.ReadSample()) { - return 0; - } - - double data[3]; - int nData, funcId; - double power = 0; - wchar_t szName[MAX_PATH]; - - // Processor (i=0, j=1) - energyLib.GetMsrFunc(1, &funcId); - energyLib.GetMsrName(1, szName); - - if (funcId != 1) { - continue; - } - energyLib.GetPowerData(0, 1, data, &nData); - power += data[0]; // power in W %6.2f - - // Now check for DRAM and add it to total power (i=0, j=4) - energyLib.GetMsrFunc(4, &funcId); - energyLib.GetMsrName(4, szName); - - if (funcId == 1) { - energyLib.GetPowerData(0, 4, data, &nData); - power += data[0]; // power in W %6.2f - } - - cout << power << endl; - - // Sleep for one second - Sleep(1000); - } - return 0; +/* + * 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 + */ + +#include + +#include + +#include +#include +#include "IntelPowerGadgetLib.h" + +using namespace std; + +int main() { + CIntelPowerGadgetLib energyLib; + + if (energyLib.IntelEnergyLibInitialize() == false) { + return 0; + } + + int nNodes = 0; + int nMsrs = 0; + + energyLib.GetNumNodes(&nNodes); + energyLib.GetNumMsrs(&nMsrs); + + while (true) { + if (!energyLib.ReadSample()) { + return 0; + } + + double data[3]; + int nData, funcId; + double power = 0; + wchar_t szName[MAX_PATH]; + + // Processor (i=0, j=1) + energyLib.GetMsrFunc(1, &funcId); + energyLib.GetMsrName(1, szName); + + if (funcId != 1) { + continue; + } + energyLib.GetPowerData(0, 1, data, &nData); + power += data[0]; // power in W %6.2f + + // Now check for DRAM and add it to total power (i=0, j=4) + energyLib.GetMsrFunc(4, &funcId); + energyLib.GetMsrName(4, szName); + + if (funcId == 1) { + energyLib.GetPowerData(0, 4, data, &nData); + power += data[0]; // power in W %6.2f + } + + cout << power << endl; + + // Sleep for one second + Sleep(1000); + } + return 0; } \ No newline at end of file diff --git a/config-installer.bat b/config-installer.bat index bdeb89e..5341e5e 100644 --- a/config-installer.bat +++ b/config-installer.bat @@ -1,26 +1,26 @@ -:: Copyright (c) 2021-2023, 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 - -@echo off -title JoularJX Installer Configurator - -echo Compiling and building JoularJX -call mvn clean install - -echo Compiling ProgramMonitor on Windows x64 -set DEVENV_COM=C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.com -cd PowerMonitor -"%DEVENV_COM%" PowerMonitor.sln /Build "Release|x64" -cd .. - -echo Copying files to install folder -copy config.properties install -copy target\joularjx-*.jar install -copy PowerMonitor\x64\Release\PowerMonitor.exe install +:: 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 + +@echo off +title JoularJX Installer Configurator + +echo Compiling and building JoularJX +call mvn clean install + +echo Compiling ProgramMonitor on Windows x64 +set DEVENV_COM=C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.com +cd PowerMonitor +"%DEVENV_COM%" PowerMonitor.sln /Build "Release|x64" +cd .. + +echo Copying files to install folder +copy config.properties install +copy target\joularjx-*.jar install +copy PowerMonitor\x64\Release\PowerMonitor.exe install pause \ No newline at end of file diff --git a/config.properties b/config.properties index b47a52a..3a118be 100644 --- a/config.properties +++ b/config.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2023, Adel Noureddine, Université de Pau et des Pays de l'Adour. +# 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) diff --git a/install/config.properties b/install/config.properties index b47a52a..3a118be 100644 --- a/install/config.properties +++ b/install/config.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2023, Adel Noureddine, Université de Pau et des Pays de l'Adour. +# 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) diff --git a/install/joularjx-2.8.1.jar b/install/joularjx-2.8.1.jar deleted file mode 100644 index 12994779a319898cbdfc3a8de65c5a7657362cf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46515 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 Z_vIv^L1)F^Cm3X4RiJ@<4+I1T_J2_d<%j?P diff --git a/install/joularjx-2.8.2.jar b/install/joularjx-2.8.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..390c2a186d3f32b71bfd88bb50f23f197ee3a393 GIT binary patch literal 47583 zcma&M18`^Gwlx~tb~;XeNjkP|+qUg=$F^^c zS~cg=m}^dXDNryNARs6ppj{sxb)f&p1O4}1MnqYFRzg;kPW~?p?Jo@Kf5FDUH!0Kp z{ze7{0{Z*)|G;DfWFF+fmcj*Oi-eX~%3bR%6<4LD2T_E0RM+Lq1w z+;cv!esdm(P#F;nN8mm+^~0)y;l_qZo8^!*KZ?cNc{M19rjoc#%d!P6gmh-Ny~)_Y zAe(wI3iI2;a{nCR*>C?&MEhT+{LA8<|6wuMUsLQH&He#__}>UyI~PY2V`B?jlYanX z{lCGMb}rTij+XBKz{2|nmXW>7KQMp%1JlON*23A&@gLZP|G;)MadNSC{s%I_KagFV zEv%jXAKd>r&;HA&|9hU<7`U3){sZ{GI{F{rza#eZ|8qS4XGawOk^67M^RMatUvmVV z;=#h=?{ZK^2LdAb2TKLaOl+Nh8d)1SId!R9c%zx&`)<{aTC;-s{b@?<{~?wTdod?3 zH3`BJD34MvAuY&m*=OJ;4&myyl%@d{+Gttj#&hl`)&vNpm`SIRscOou5^GYm>8kPE zR^@w9I=`Q~Dwg;Ye-L2nyPD>4{HtsF+xvOrzor8QTpt@LE06wy+EsZsRrJuKUhY-VvS9#Od%tBkTQahV+dHju|5W)p3u z-Gc|0Rn@gxoq2nZQsJa~3=lXjFC zy%h%@W~rhTVj5Zf0S>YYhY8QDBRiY|i$s!_eWdkVkx^~~0)2V6?ZIm;(re332?<$U zZNjB_*BHgNb-m+ZEg1RHx(Re8a1y3k?UtL$R=WQI&qFvk)Lp`D~pR;qiZam zI`i7c3EIlG;d-*p<$}5D#JadP7pFcs+@z9};UqqNBOd3P05vk3wM{Rx^=33Y9;^kA zYW>a9Z2TJotx4M&a9d)t^>S#4@dl5c2%Bds=ouyydd&AI3_lQ8AD~uh$o2wRT?uYd zofFko)~xxIVYxmAnT?!12fW?v%r8Cv!2=%|`+=?89oUw*o8#L#etm!%6Qk`U2188; zNoAg(A>M!@0Ve|wHSn-OxbJHm%zn-=ui?U;*)3_J`pOh5@?E}Y2gomn_$eccr0r(g zB%?agTZfVHt~$GWN*f}cE!sB?7*vp1xn*(&SY&jB%wlS6ZxB2%0tHQohS4WQx}aIc zj>!lRz5IXx9avJ|VfJHxxT>H`VM2zK^r%uoP8Z_-8#DA9HYX-TLRCmgL^D}X&uXMu zmT#p8qiGIBNiKEdl+;A~k=p-Zfc1sJ`0(`13&Ce~*ZSIY% zgRMCpXgV#+$}pN2?>}Oe^p?(cT>+`Bm+G7|*{~H*G?o(J>O%!JCJW5RQQ^V_8RPy6 z33uB=6B@!|#)j!WTT16`i*l=QkJ%XLhkj~uXCEOO%>rzNJkO)b0tekPE3R$fwGztT z3V4Thkm)C2z^?*Fz=;fSvOh+{H7GXV%<&&DS~ z1b`67z8>2ggtU(RghVHj?msYX+V!?z zm31^x-2*L~6=}e!TIA%6Q+FfMxe9c+yfQqsxVVNJs4dpT&&Z948AngeCc-8BT!-&H z&rhn$4ll$?N1-yYccX zg6UAz3$YD_^SnU&U{dFRB@<=RS5IWk6U0H<{rge{U+AQKJikQ&8lZ7u^AMv?=+aqR z=MBbbXBg#&JorrWum}z+K&DRcunajK>`)swoT@!lwKUo^5LHgWtnx?ViMauzF(;kCuhhPd4F&}<=5Wzb@F-9oqUoYb65E#Oq*b76|#18of7++D2 z>|A!v?lDxX6RNKt#c5STX&>D!_1P!OBRElZai0l{Z^4cm3;=!ON~sk)mTK_Q!}jQf zEy9hTGD7XLv@3KOHd8PO@-U;~>POv<2&~?FRn_1*VLTe<2uBQ)h0x~mw0ok8T%$A@!caR@(@kgi~e7n=m zKj0s=!6Y{>+Qi*EG9b5m81(uq@~B&DE^;O+QC_9=d{fRnl44Vq5cV66yGXqU@52+_ zQ5zKYxS#pTOk5lv;m( zsb0@tg?9C~k^O^G`!69aWbg7XttJvv7u`<}7yJz*CUwoef~7GoD0-xXjDku*R2O2X zQkD-EbbxSc4#y3I7-SC|*4O-@@$~)f$)yK0K`%aog2kmLah_kYDXSIV6e0ThMmg@2 zIK)eS0tILFSW>9a9A9B0VKvYxH>XhgL&bJVrZ5YJGwQ$w+K!|P3j)r%8Te1uQt&a%LT1***NI%O z6q&rp@eYPfmb}o0UV3*!qhb+%4PCZlPa_GL36Y0JBG*;5NCyggAJNeTBY;o z7brm;4uor{;6hC*RkRNd7kR;hWCT_? za7~P!Gcp8rZC?~9Jzfnj^3V{}9p9<22wzogVzqQ8P@*U>&VXVTN=Rxxbq!%o?68C+ zc@L5!p^9NhO|(sT8uk)EM2m78B4P^BRJ)BNqHJ!pI})AB9@usU!K1W}zfk11xl_zIMA%%F z+oPgq2lgm9vgGos=-&ns)IXY%4c`NJ3pB14d7& zo&UIDY!VgYX+ClSwE$?z7^Xv!e-xm)f6;*(R4Z_Kg{QpAswzSVr1J&4CmMwXeh5jw zrT%kyj}tsY*?Raf&>?JmBM45cg~e87l%O=?R%0OQCEha=eggLBvlflh=89k{Z>&ML=s-&^MZ<*JrPbW>yJUDcQyq?;iUZ`8@r6v3 z3oUH9mSngVhGWCSui-)T+bwe9R-UpwqocyePF%P9s3d(O4~JX%^D7mHoLbw;+UVu{ zqqf^7W9vhS70I9nPyhj5uj60TT)7!vsKg zTyFhfR0&iGX(=u@LD@Q4xl69dAQB z`80;P-w^RC-qeN5-E14lMoS$|7h!_s7a$)a;1c8nm5?#-6^3QeNpFog@#a|^z;YjY zkNI3-*+DL4>kcp&Er(kb=T#(tHf#Sr9ww~y*EA0@#ocp@Pceaa|5RMaM)W--+NC%@I+&mrFwd`0}FFF4pf# z{S=#q)ZgPC`S2Sx9HVShBjPbytortbo_E<7C$)8%X7FhrnIjT-exB@XXI)`sSI*TV z!pqNr`&T(h#>R{G*K{bsY`B-jN448f712(6Rd11QmFyIor}Qf>1=C3Za>~2au}f{m zDjDc9ry4_sa0EP3AvqHU6)?dE1L3H}X@~xv3!|$6X6Vp?c#D?fj>HJZMqO9V>Q%^W zxAXP&(LwOE#@fSMH@8|Nn9*Gx0Bgg*+nL5KX-dnWYI4a6aDoiJPD_4lgBQuCe zg;U}5WTE*~hH0UDDm@}!i6ccKG0U0L;I=Kzk`Zr0A3Ma()fR*(S!<((IVa|Zq~l%< z;Bn1mbb>AuGN^E8iMr2x^Dilb_< zoxoHKE_^tu=nn-Bgvqd zUPzTnr~^V(Tc5_7m&V{kIp1&BxJx> zjkL8HVFiV5plpI{adqd21MX z>zH|aiM8M1Fzko5|L!o1XcU=4D(LBobb%X2%>~i-b)l~RD=zY|%9zHE!syk7F?pNZ z=+%cYnU7q5)uYguf?T!G$-=$M=cVD_*asK9#0ML^_y-@nxCcrTSV@k91ZVOjaZSl%Nt_=#bFA%(b5V^FbCb>` zg<7Y`5`;xv@mB@Qq&)m~5}vVJ2@gp4$q%6s2W_YMrETU@2k~vGuvRR}!_2@b_GysV zMbRAQ`}LPQC@l8COLvx`J)8yu#tR180a6aA-)kTt3N^>i4-njbwxYh+1>KnuZ!n^t zBAsE>*pH&T_W)5J7GA^Ag4Se42mC{QRGA^u^ssZPoQTrI@e&v|C0g4&Alm};6+zn8 ztTlVcpx4=@fT~91bql7eVl4+mo1v~o(C68L)*RRS`Co*tGvn^R5q1PTK@n#KxTUZ4 zDe(JA9*BDOV|ExYcO{;B_p9N!chduP>Tfd#g7l=kBurwA^%1&6j4bfxJmgqS8j?=) zY5$Oe7PgVkyRW({FRR}<1~~SK5zd39hcc%Raw+RZoTWxOuO?#b77nDMTndQ|inaJ# zp>MoUeN0SD9@@sCekNq#et&>*5DutR?QG(qR4t28+(-+2(7zGCOh`iicBC#(kpgL5O#Q4f;?dMkQzg;(`FiP8n|V5}?P^ zvEf9X`@dX`K9oQOu^kN{xQyDFy&zswJzuF22cdNbsY_;P(xqSvyM$p+nalaFzJdNd zsMvhihROv80;>C)H~IM=f(i*+XA^5R3tMA5H>ZDv6;Y~MYN%>xUkG3ngA6|aFhwqC zv_#^DT6IP z)9yUK6|;KHW9N&b|BeZMac716&SgDzZ-BgJ2Wa!%U%l z*nglCfB8?wmvw(?Vz?bCot2=@~^FN@aj( zS(=NMdWehhA;2;t&+GTOsKA!?Q)&jchcMS>wN$1d&=r|%wcvFikJxJu{EilYgSM_w zAXlXr0mvZ8!OOwHHZGpY7R?h5L;D4sb5*rhxo&TKf7uSyMLCXBL>gd3KZOa;{G@P+ z)K44LM@O^{&U{s#(?BHb*+d-mX3@PklTQZ4v-?-jvq+zdlPE2Y?^pPsoA{q!tUyagQrxd1SCr+K_P|L|O;UAJOOi30c*u_U6LU#tNQXPofIxb{FFUv1lq0;w zD*b>w0-Cb; zNlrDg)bJ}N76@iqz+8E)P7se^xf26qgQ=LyI!9n&=jV9LAS9X!GaJ(~7CcUYQjI7l zIF>Ryi%L%F5pZ@ww{6ExaS${Ogv__yCE=uzel&6$P)TPj8_AZYX5K0gX!#)`33jv# zdRVlSI!w7`;RN?(pk`ddFIe$I<`6o%M7+CrUx)MkK6yor%O-B*GH(x&p?=

l-f3Z=ngmB&hjFXlb+=fn_bqa@HtBFT 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 PGLUL`5D={LAD{jQ2kq%W literal 0 HcmV?d00001 diff --git a/install/linux-install.sh b/install/linux-install.sh index 2efcd0c..ccf46e2 100644 --- a/install/linux-install.sh +++ b/install/linux-install.sh @@ -1,23 +1,23 @@ -#!/bin/sh - -# Copyright (c) 2021-2023, 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 - -INSTALLATION_PATH=/opt/joularjx - -read -p "Installation to $INSTALLATION_PATH. Continue ([y]/n)? " USER_CONFIRMATION -echo -if [ "$USER_CONFIRMATION" = "y" ] -then - mkdir $INSTALLATION_PATH - cp joularjx-*.jar $INSTALLATION_PATH - cp config.properties $INSTALLATION_PATH - - echo "Installation complete. JoularJX files installed in $INSTALLATION_PATH" +#!/bin/sh + +# 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 + +INSTALLATION_PATH=/opt/joularjx + +read -p "Installation to $INSTALLATION_PATH. Continue ([y]/n)? " USER_CONFIRMATION +echo +if [ "$USER_CONFIRMATION" = "y" ] +then + mkdir $INSTALLATION_PATH + cp joularjx-*.jar $INSTALLATION_PATH + cp config.properties $INSTALLATION_PATH + + echo "Installation complete. JoularJX files installed in $INSTALLATION_PATH" fi \ No newline at end of file diff --git a/install/windows-install.bat b/install/windows-install.bat index 8eb6dbc..d27f382 100644 --- a/install/windows-install.bat +++ b/install/windows-install.bat @@ -1,25 +1,25 @@ -:: Copyright (c) 2021-2023, 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 - -@echo off -title JoularJX Windows Installer - -set INSTALLATION_PATH=C:\joularjx - -set USER_CONFIRMATION=y -set /p USER_CONFIRMATION=Installation to %INSTALLATION_PATH%. Continue ([y]/n)? -if /i not "%USER_CONFIRMATION%" == "y" goto :eof - -md %INSTALLATION_PATH% -copy joularjx-*.jar %INSTALLATION_PATH% -copy config.properties %INSTALLATION_PATH% -copy PowerMonitor.exe %INSTALLATION_PATH% - -echo Installation complete. JoularJX files installed in %INSTALLATION_PATH% +:: 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 + +@echo off +title JoularJX Windows Installer + +set INSTALLATION_PATH=C:\joularjx + +set USER_CONFIRMATION=y +set /p USER_CONFIRMATION=Installation to %INSTALLATION_PATH%. Continue ([y]/n)? +if /i not "%USER_CONFIRMATION%" == "y" goto :eof + +md %INSTALLATION_PATH% +copy joularjx-*.jar %INSTALLATION_PATH% +copy config.properties %INSTALLATION_PATH% +copy PowerMonitor.exe %INSTALLATION_PATH% + +echo Installation complete. JoularJX files installed in %INSTALLATION_PATH% pause \ No newline at end of file diff --git a/pom.xml b/pom.xml index e01caaf..fe1eb64 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@