-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: intel support for powermetrics (#12)
* refactor: rename constants * doc: clean-up, add JoularJX as inspiration * refactor: introduce CPU class to handle different powermetrics output For some reason, this refactor breaks the process handling! 🤔 * feat: add Intel support for powermetrics-based measures
- Loading branch information
Showing
9 changed files
with
326 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,9 @@ | ||
# power-server | ||
|
||
This project is meant to provide a REST endpoint streaming power consumption | ||
This project is meant to provide a REST endpoint streaming power consumption, inspired | ||
by [JoularJX](https://github.com/joular/joularjx) but focusing on exposing power information and metadata over REST | ||
without further processing. | ||
|
||
This project uses Quarkus, the Supersonic Subatomic Java Framework. | ||
|
||
If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . | ||
|
||
## Running the application in dev mode | ||
|
||
You can run your application in dev mode that enables live coding using: | ||
```shell script | ||
./mvnw compile quarkus:dev | ||
``` | ||
|
||
> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/. | ||
## Packaging and running the application | ||
|
||
The application can be packaged using: | ||
```shell script | ||
./mvnw package | ||
``` | ||
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. | ||
Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. | ||
|
||
The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. | ||
|
||
If you want to build an _über-jar_, execute the following command: | ||
```shell script | ||
./mvnw package -Dquarkus.package.type=uber-jar | ||
``` | ||
|
||
The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. | ||
|
||
## Creating a native executable | ||
|
||
You can create a native executable using: | ||
```shell script | ||
./mvnw package -Dnative | ||
``` | ||
|
||
Or, if you don't have GraalVM installed, you can run the native executable build in a container using: | ||
```shell script | ||
./mvnw package -Dnative -Dquarkus.native.container-build=true | ||
``` | ||
|
||
You can then execute your native executable with: `./target/power-server-1.0.0-SNAPSHOT-runner` | ||
|
||
If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling. | ||
|
||
## Provided Code | ||
|
||
### RESTEasy Reactive | ||
|
||
Easily start your Reactive RESTful Web Services | ||
|
||
[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources) | ||
If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
...er/src/main/java/io/github/metacosm/power/sensors/macos/powermetrics/AppleSiliconCPU.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package io.github.metacosm.power.sensors.macos.powermetrics; | ||
|
||
import io.github.metacosm.power.SensorMetadata; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import static io.github.metacosm.power.sensors.macos.powermetrics.MacOSPowermetricsSensor.*; | ||
|
||
class AppleSiliconCPU extends io.github.metacosm.power.sensors.macos.powermetrics.CPU { | ||
private static final SensorMetadata.ComponentMetadata cpuComponent = new SensorMetadata.ComponentMetadata(CPU, 0, "CPU power", true, "mW"); | ||
private static final SensorMetadata.ComponentMetadata gpuComponent = new SensorMetadata.ComponentMetadata(GPU, 1, "GPU power", true, "mW"); | ||
private static final SensorMetadata.ComponentMetadata aneComponent = new SensorMetadata.ComponentMetadata(ANE, 2, "Apple Neural Engine power", false, "mW"); | ||
private static final SensorMetadata.ComponentMetadata cpuShareComponent = new SensorMetadata.ComponentMetadata(CPU_SHARE, 3, "Computed share of CPU", false, "decimal percentage"); | ||
private static final String COMBINED = "Combined"; | ||
private static final String POWER_INDICATOR = " Power: "; | ||
private static final int POWER_INDICATOR_LENGTH = POWER_INDICATOR.length(); | ||
|
||
public AppleSiliconCPU() { | ||
|
||
} | ||
|
||
@Override | ||
public void addComponentIfFound(String line, Map<String, SensorMetadata.ComponentMetadata> components) { | ||
// looking for line fitting the: "<name> Power: xxx mW" pattern, where "name" will be a considered metadata component | ||
final var powerIndex = line.indexOf(" Power"); | ||
// lines with `-` as the second char are disregarded as of the form: "E-Cluster Power: 6 mW" which fits the metadata pattern but shouldn't be considered | ||
if (powerIndex >= 0 && '-' != line.charAt(1)) { | ||
addComponentTo(line.substring(0, powerIndex), components); | ||
} | ||
} | ||
|
||
private static void addComponentTo(String name, Map<String, SensorMetadata.ComponentMetadata> components) { | ||
switch (name) { | ||
case CPU, GPU, ANE: | ||
// already pre-added | ||
break; | ||
case COMBINED: | ||
// should be ignored | ||
break; | ||
default: | ||
components.put(name, new SensorMetadata.ComponentMetadata(name, components.size(), name, false, "mW")); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean doneExtractingPowerComponents(String line, HashMap<String, Number> powerComponents) { | ||
// looking for line fitting the: "<name> Power: xxx mW" pattern and add all of the associated values together | ||
final var powerIndex = line.indexOf(POWER_INDICATOR); | ||
// 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 (powerIndex >= 0 && '-' != line.charAt(1) && !line.startsWith("Combined")) { | ||
// get component name | ||
final var name = line.substring(0, powerIndex); | ||
// extract power value | ||
final int value; | ||
try { | ||
value = Integer.parseInt(line.substring(powerIndex + POWER_INDICATOR_LENGTH, line.indexOf('m') - 1)); | ||
} catch (Exception e) { | ||
throw new IllegalStateException("Cannot parse power value from line '" + line + "'", e); | ||
} | ||
powerComponents.put(name, value); | ||
} | ||
|
||
// we break out once we 've found all the extracted components (in this case, only cpuShare is not extracted) | ||
return powerComponents.size() == metadata().componentCardinality() - 1; | ||
} | ||
|
||
@Override | ||
boolean doneAfterComponentsInitialization(Map<String, SensorMetadata.ComponentMetadata> components) { | ||
// init map with known components | ||
components.put(MacOSPowermetricsSensor.CPU, cpuComponent); | ||
components.put(GPU, gpuComponent); | ||
components.put(ANE, aneComponent); | ||
components.put(CPU_SHARE, cpuShareComponent); | ||
return false; | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
server/src/main/java/io/github/metacosm/power/sensors/macos/powermetrics/CPU.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package io.github.metacosm.power.sensors.macos.powermetrics; | ||
|
||
import io.github.metacosm.power.SensorMetadata; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
abstract class CPU { | ||
private SensorMetadata metadata; | ||
|
||
void addComponentIfFound(String line, Map<String, SensorMetadata.ComponentMetadata> components) { | ||
throw new IllegalStateException("Shouldn't be called as this processing is unneeded for this implementation"); | ||
} | ||
|
||
abstract boolean doneExtractingPowerComponents(String line, HashMap<String, Number> powerComponents); | ||
|
||
SensorMetadata metadata() { | ||
return metadata; | ||
} | ||
|
||
void setMetadata(SensorMetadata metadata) { | ||
this.metadata = metadata; | ||
} | ||
|
||
abstract boolean doneAfterComponentsInitialization(Map<String, SensorMetadata.ComponentMetadata> components); | ||
} |
41 changes: 41 additions & 0 deletions
41
server/src/main/java/io/github/metacosm/power/sensors/macos/powermetrics/IntelCPU.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package io.github.metacosm.power.sensors.macos.powermetrics; | ||
|
||
import io.github.metacosm.power.SensorMetadata; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import static io.github.metacosm.power.sensors.macos.powermetrics.MacOSPowermetricsSensor.CPU_SHARE; | ||
import static io.github.metacosm.power.sensors.macos.powermetrics.MacOSPowermetricsSensor.PACKAGE; | ||
|
||
class IntelCPU extends CPU { | ||
|
||
private static final SensorMetadata.ComponentMetadata packageComponent = new SensorMetadata.ComponentMetadata(PACKAGE, 0, "Intel energy model derived package power (CPUs+GT+SA)", true, "W"); | ||
private static final SensorMetadata.ComponentMetadata cpuShareComponent = new SensorMetadata.ComponentMetadata(CPU_SHARE, 1, "Computed share of CPU", false, "decimal percentage"); | ||
|
||
@Override | ||
public boolean doneExtractingPowerComponents(String line, HashMap<String, Number> powerComponents) { | ||
// line should look like: Intel energy model derived package power (CPUs+GT+SA): 8.53W | ||
final var powerIndex = line.indexOf("Intel "); | ||
if(powerIndex >= 0) { | ||
final var powerStartIndex = line.indexOf(':') + 1; | ||
final float value; | ||
try { | ||
value = Float.parseFloat(line.substring(powerStartIndex, line.indexOf('W'))); | ||
} catch (Exception e) { | ||
throw new IllegalStateException("Cannot parse power value from line '" + line + "'", e); | ||
} | ||
powerComponents.put(PACKAGE, value); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
@Override | ||
boolean doneAfterComponentsInitialization(Map<String, SensorMetadata.ComponentMetadata> components) { | ||
components.put(PACKAGE, packageComponent); | ||
components.put(CPU_SHARE, cpuShareComponent); | ||
return true; | ||
} | ||
} |
Oops, something went wrong.