diff --git a/config.yml.example b/config.yml.example index e59a4886b..97639f8ed 100644 --- a/config.yml.example +++ b/config.yml.example @@ -30,6 +30,7 @@ measurement: memory.total.cgroup.container.provider.MemoryTotalCgroupContainerProvider: 100 memory.energy.RAPL.MSR.system.provider.MemoryEnergyRaplMsrSystemProvider: 100 network.io.cgroup.container.provider.NetworkIoCgroupContainerProvider: 100 +# psu.energy.ac.system.provider.PsuEnergyAcSystemProvider: 100 admin: # This address will get an email, when a new project was added through the frontend diff --git a/frontend/js/stats.js b/frontend/js/stats.js index 015e184e0..5faf35f79 100644 --- a/frontend/js/stats.js +++ b/frontend/js/stats.js @@ -19,6 +19,11 @@ const metrics_info = { SI_conversion_factor: 1000, unit_after_conversion: 'J' }, + psu_energy_ac_system: { + unit: 'mJ', + SI_conversion_factor: 1000, + unit_after_conversion: 'J' + }, memory_energy_rapl_msr_system: { unit: 'mJ', SI_conversion_factor: 1000, @@ -153,7 +158,7 @@ const fillProjectTab = (selector, data) => { } const getMetrics = (stats_data, style='apex') => { - const metrics = {cpu_utilization_containers: [], cpu_utilization_system: [], mem_total: [], network_io: {}, series: {}, atx_energy: 0, cpu_energy: 0, memory_energy: 0} + const metrics = {cpu_utilization_containers: [], cpu_utilization_system: [], mem_total: [], network_io: {}, series: {}, atx_energy: 0, psu_ac_energy: 0, cpu_energy: 0, memory_energy: 0} let accumulate = 0; @@ -184,6 +189,8 @@ const getMetrics = (stats_data, style='apex') => { if (accumulate === 1) metrics.cpu_energy += value; } else if (metric_name == 'atx_energy_dc_channel') { if (accumulate === 1) metrics.atx_energy += value; + } else if (metric_name == 'psu_energy_ac_system') { + if (accumulate === 1) metrics.psu_ac_energy += value; } else if (metric_name == 'memory_energy_rapl_msr_system') { if (accumulate === 1) metrics.memory_energy += value; } else if (metric_name == 'memory_total_cgroup_container') { @@ -345,6 +352,10 @@ const createGraph = (element, data, labels, title) => { const fillAvgContainers = (stats_data, metrics) => { +<<<<<<< HEAD +======= + const psu_ac_energy_in_mWh = ((metrics.psu_ac_energy) / 3600) * 1000; +>>>>>>> dev const atx_energy_in_mWh = ((metrics.atx_energy) / 3600) * 1000; const cpu_energy_in_mWh = ((metrics.cpu_energy) / 3600) * 1000; const memory_energy_in_mWh = ((metrics.memory_energy) / 3600) * 1000; @@ -365,6 +376,8 @@ const fillAvgContainers = (stats_data, metrics) => { else if(total_CO2_in_kg < 0.0001) co2_display = { value: total_CO2_in_kg*(10**6), unit: 'mg'}; else if(total_CO2_in_kg < 0.1) co2_display = { value: total_CO2_in_kg*(10**3), unit: 'g'}; + if(psu_ac_energy_in_mWh) document.querySelector("#psu-ac-energy").innerText = psu_ac_energy_in_mWh.toFixed(2) + " mWh" + if(atx_energy_in_mWh) document.querySelector("#atx-energy").innerText = atx_energy_in_mWh.toFixed(2) + " mWh" if(cpu_energy_in_mWh) document.querySelector("#cpu-energy").innerText = cpu_energy_in_mWh.toFixed(2) + " mWh" if(cpu_energy_in_mWh) document.querySelector("#component-energy").innerText = (cpu_energy_in_mWh+memory_energy_in_mWh).toFixed(2) + " mWh" @@ -373,6 +386,10 @@ const fillAvgContainers = (stats_data, metrics) => { if(cpu_energy_in_mWh) document.querySelector("#component-power").innerText = ((metrics.cpu_energy+metrics.memory_energy)/stats_data.project.measurement_duration_in_s).toFixed(2) + " W" if(atx_energy_in_mWh) document.querySelector("#atx-power").innerText = (metrics.atx_energy / stats_data.project.measurement_duration_in_s).toFixed(2) + " W" +<<<<<<< HEAD +======= + if(psu_ac_energy_in_mWh) document.querySelector("#psu-ac-power").innerText = (metrics.psu_ac_energy / stats_data.project.measurement_duration_in_s).toFixed(2) + " W" +>>>>>>> dev if(network_io) document.querySelector("#network-io").innerText = network_io.toFixed(2) + " MB" diff --git a/frontend/stats.html b/frontend/stats.html index 1706bb5e3..ac79edecf 100644 --- a/frontend/stats.html +++ b/frontend/stats.html @@ -252,6 +252,30 @@

compound metrics

+
+
+
PSU AC Energy
+
+
+
+ N/A +
+
+
+
+
+
+
+
PSU AC Power
+
+
+
+ N/A +
+
+
+
+
ATX Energy
diff --git a/tools/metric_providers/psu/energy/ac/system/README.md b/tools/metric_providers/psu/energy/ac/system/README.md new file mode 100644 index 000000000..321b1bdcb --- /dev/null +++ b/tools/metric_providers/psu/energy/ac/system/README.md @@ -0,0 +1,11 @@ +Slimmed down version of check_gude.py from https://github.com/gudesystems/check_gude.py +for the Blauer Engel für Software Measurements +=============== + +This script expects the GUDE Powermeter to be fixed on the IP 192.168.178.32 + +- Create **venv**: `python3 -m venv venv` +- Activate: `source venv/bin/activate` +- Install requests: `pip3 install requests` +- Run: `python3 check_gude.py` + diff --git a/tools/metric_providers/psu/energy/ac/system/check_gude_modified.py b/tools/metric_providers/psu/energy/ac/system/check_gude_modified.py new file mode 100755 index 000000000..ad7ab1c72 --- /dev/null +++ b/tools/metric_providers/psu/energy/ac/system/check_gude_modified.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +import requests +import json +import time +import subprocess + +def main(resolution): + url = f'http://192.168.178.32/status.json' + + ONLY_VALUES = 0x4000 + cgi = {'components': ONLY_VALUES} # simple-sensors + and only values + + resolution = float(resolution); + + target_sleep_time = resolution/1000.0 + + while True: # loop until CTRL+C + timestamp_before = time.time_ns() + time.sleep(target_sleep_time) + + data = json.loads(requests.get(url, params=cgi, verify=False, auth=None).text) + + # print(data) # DEBUG + timestamp_after = time.time_ns() + effective_sleep_time = timestamp_after - timestamp_before + # print(effective_sleep_time / 1_000_000_000) # DEBUG + conversion_factor = effective_sleep_time / 1_000_000 # we want microjoule. Therefore / 10**9 to get seconds and then * 10**3 to get mJ + print(int(timestamp_after / 1_000), int(data["sensor_values"][0]['values'][0][4]['v']*conversion_factor), flush=True) + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("-i", type=str, help="Resolution") + + args = parser.parse_args() + + if args.i is None: + parser.print_help() + print("Please supply -i to set resolution in milliseconds") + exit(2) + + main(args.i) diff --git a/tools/metric_providers/psu/energy/ac/system/provider.py b/tools/metric_providers/psu/energy/ac/system/provider.py new file mode 100644 index 000000000..d8851dc15 --- /dev/null +++ b/tools/metric_providers/psu/energy/ac/system/provider.py @@ -0,0 +1,49 @@ +import sys, os +import subprocess + +if __name__ == "__main__": + sys.path.append(os.path.dirname(os.path.abspath(__file__))+'/../../../../..') +from metric_providers.base import BaseMetricProvider + +class PsuEnergyAcSystemProvider(BaseMetricProvider): + def __init__(self, resolution): + self._current_dir = os.path.dirname(os.path.abspath(__file__)) + self._metric_name = "psu_energy_ac_system" + self._metrics = {"time":int, "value":int} + self._resolution = resolution + super().__init__() + + def start_profiling(self, containers=None): + call_string = f"{self._current_dir}/check_gude_modified.py -i {self._resolution}" + + call_string += f" > {self._filename}" + + print(call_string) + + self._ps = subprocess.Popen( + [call_string], + shell=True, + preexec_fn=os.setsid, + stderr=subprocess.PIPE + # since we are launching the command with shell=True we cannot use ps.terminate() / ps.kill(). + # This would just kill the executing shell, but not it's child and make the process an orphan. + # therefore we use os.setsid here and later call os.getpgid(pid) to get process group that the shell + # and the process are running in. These we then can send the signal to and kill them + ) + + +if __name__ == "__main__": + import time + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("container_id", help="Please provide the container_id") + args = parser.parse_args() + + o = PsuEnergyAcSystemProvider(resolution=100) + + print("Starting to profile") + o.start_profiling() + time.sleep(2) + o.stop_profiling() + print("Done, check ", o._filename)