Bases: PowerProfiler
A wrapper class for energy monitoring across various devices including CPU, GPU, and DRAM.
This class facilitates aggregation, coordination of execution, and formatting of the output
for measured energy values from different devices.
Attributes:
-
energy_unit
(str)
–
The energy unit for the final result report (e.g., 'J' for joule, 'Wh' for Watt-hour, 'kWh' for kilowatt-hour).
-
power_devices
(str)
–
A string containing the list of specified devices to profile.
-
record
(dict)
–
A dictionary to contain the recorded measurements.
-
thread
(Thread)
–
The main Python Thread instance that coordinates measurement from other subprocess threads.
-
interval
(float)
–
A float value to specify the sampling frequency of measurements.
-
power_objects
(list)
–
A list that stores different instances of measurements classes for various devices.
-
intel
(bool)
–
A boolean value indicating the presence (True) or absence (False) of an Intel CPU.
-
amd
(bool)
–
A boolean value indicating the presence (True) or absence (False) of an AMD CPU.
Methods:
-
start
–
Begins monitoring energy usage from the specified list of devices.
-
stop
–
Stops the energy monitoring process and agregate results.
-
get_power_consumption
–
Continuously get energy usage from all specified power monitoring instances.
-
__set_power
–
Create instances of power monitoring classes based on the specified power devices ("e.g., "cpu, Ram, gpu").
-
get_all_power
–
Get energy usage from all specified power monitoring instances at a specific sampling period.
Initialize the PowerWrapper instance.
Parameters:
-
config_file
(str, default:
'config_energy.json'
)
–
Path to the configuration file to use. If not provided, the default energy unit is Watt-hour with sampling frequency of one(1) second and measurements are across both CPU GPU and RAM
Source code in ea2p/src/wrapper.py
| def __init__(self, config_file="config_energy.json"):
"""
Initialize the PowerWrapper instance.
Parameters:
config_file (str): Path to the configuration file to use. If not provided, the default energy unit is Watt-hour with sampling frequency of one(1) second and measurements are across both CPU GPU and RAM
"""
super().__init__()
with open(config_file, 'r') as file:
config = json.load(file)
self.power_devices = config.get('devices_list').lower()
self.energy_unit = config.get('energy_unit').lower()
self.record = {}
self.thread = None
self.interval = config.get('sampling_freq')
self.amd = False
self.intel = False
self.intel_ram = False
self.power_objects = self.__set_power(self.power_devices)
|
__get_powerlog_file
Retrieve the log file where PowerLog logs are written.
Source code in ea2p/src/power.py
| def __get_powerlog_file(self):
"""
Retrieve the log file where PowerLog logs are written.
"""
|
__set_power
__set_power(power_devices)
Create instances of power monitoring classes based on the specified power devices.
Parameters:
-
power_devices
(str)
–
A comma-separated string specifying the power devices to monitor.
Returns:
-
power_objects ( list
) –
A list of power monitoring instances, respectivelly for each device in the devices list.
Source code in ea2p/src/wrapper.py
| def __set_power(self, power_devices):
"""
Create instances of power monitoring classes based on the specified power devices.
Parameters:
power_devices (str): A comma-separated string specifying the power devices to monitor.
Returns:
power_objects (list): A list of power monitoring instances, respectivelly for each device in the devices list.
"""
cpu_brand = ""
power_objects = list()
if ("cpu" not in power_devices) and ("gpu" not in power_devices) and ("ram" not in power_devices):
raise ValueError("Please specify at least one device type to monitor in [cpu, gpu, ram] ")
if "cpu" in power_devices:
cpu_brand = cpuinfo.get_cpu_info()['brand_raw']
if "Core(TM)" in cpu_brand:
self.intel = True
self.intel_power = PowerClientIntel()
elif "Xeon" in cpu_brand:
self.intel = True
self.intel_power = PowerServerIntel()
elif "AMD" in cpu_brand:
self.amd_power = PowerAmdCpu()
self.amd = True
LOGGER.info("AMD found")
else:
raise SystemError(
"Unable to detect the CPU informations of your system. "
"Try to remove CPU in your config_energy.json file "
"to monitor other components like RAM or GPU energies "
)
if "gpu" in power_devices:
try:
subprocess.check_output('nvidia-smi')
power_objects.append(PowerNvidia())
except Exception:
pass
try:
subprocess.check_output('rocminfo')
power_objects.append(PowerAmdGpu())
except Exception:
pass
if "ram" in power_devices and not ("Xeon" in cpu_brand):
power_objects.append(PowerRam())
return power_objects
|
get_all_power
get_all_power(power_objects)
Get energy usage from all specified power monitoring instances at a specific sampling period.
Parameters:
-
power_objects
(list)
–
List of power monitoring instances, respectivelly for each device in the devices list.
Source code in ea2p/src/wrapper.py
| def get_all_power(self, power_objects):
"""
Get energy usage from all specified power monitoring instances at a specific sampling period.
Parameters:
power_objects (list): List of power monitoring instances, respectivelly for each device in the devices list.
"""
energy_usage = {}
for obj in power_objects:
energy_usage.update(obj.append_energy_usage())
self.power_draws.append(energy_usage)
|
get_power_consumption
get_power_consumption(power_objects)
Continuously get energy usage from all specified power monitoring instances.
Parameters:
-
power_objects
(list)
–
List of power monitoring instances, respectivelly for each device in the devices list.
Source code in ea2p/src/wrapper.py
| def get_power_consumption(self, power_objects):
"""
Continuously get energy usage from all specified power monitoring instances.
Parameters:
power_objects (list): List of power monitoring instances, respectivelly for each device in the devices list.
"""
if self.amd:
self.amd_power.start()
if power_objects and self.intel:
self.get_all_power(power_objects)
while getattr(self.thread, "do_run", True):
self.get_all_power(power_objects)
self.intel_record.append(self.intel_power.append_energy_usage())
time.sleep(self.interval)
self.get_all_power(power_objects)
elif power_objects:
self.get_all_power(power_objects)
while getattr(self.thread, "do_run", True):
self.get_all_power(power_objects)
time.sleep(self.interval)
self.get_all_power(power_objects)
elif self.intel:
while getattr(self.thread, "do_run", True):
self.intel_record.append(self.intel_power.append_energy_usage())
time.sleep(self.interval)
|
start
Start the power monitoring process. This function creates the main threads to coordinate subprocesses
that profile energy/power on different devices.
This function initializes threads to profile power consumption on various devices concurrently. Each thread
corresponds to a specific device and is responsible for initiating the power profiling process for that device.
The devices are specified in a list of device names. Power profiling subprocesses for each device are
coordinated through separate threads to ensure parallel execution.
Example
PowerWrapper wrapper = PowerWrapper()
wrapper.start()
Note
This function assumes the existence of a class or function responsible for profiling power consumption
on individual devices. The actual power profiling logic should be implemented within the respective
threads or subprocesses.
Source code in ea2p/src/wrapper.py
| def start(self):
"""
Start the power monitoring process. This function creates the main threads to coordinate subprocesses
that profile energy/power on different devices.
This function initializes threads to profile power consumption on various devices concurrently. Each thread
corresponds to a specific device and is responsible for initiating the power profiling process for that device.
The devices are specified in a list of device names. Power profiling subprocesses for each device are
coordinated through separate threads to ensure parallel execution.
Example:
PowerWrapper wrapper = PowerWrapper()
wrapper.start()
Note:
This function assumes the existence of a class or function responsible for profiling power consumption
on individual devices. The actual power profiling logic should be implemented within the respective
threads or subprocesses.
"""
LOGGER.info("Starting CPU power monitoring...")
self.start_time = time.time()
self.power_draws = []
self.intel_record = []
self.record = {}
if self.thread and self.thread.is_alive():
self.stop_thread()
self.thread.join()
self.thread = threading.Thread(target=self.get_power_consumption, args=(self.power_objects,))
# self.thread.do_run = True
self.thread.start()
|
stop
Stop the power monitoring process and collect/aggregate the final power consumption data.
This function stops the power monitoring process by terminating the main threads responsible for coordinating
the profiling of energy/power consumption on various devices. It ensures the orderly shutdown of all
power profiling subprocesses and releases any associated resources. Additionally, it collects and aggregates
data from the different devices' profiling, allowing for further analysis or reporting.
Example
PowerWrapper wrapper = PowerWrapper()
wrapper.stop()
Source code in ea2p/src/wrapper.py
| def stop(self):
"""
Stop the power monitoring process and collect/aggregate the final power consumption data.
This function stops the power monitoring process by terminating the main threads responsible for coordinating
the profiling of energy/power consumption on various devices. It ensures the orderly shutdown of all
power profiling subprocesses and releases any associated resources. Additionally, it collects and aggregates
data from the different devices' profiling, allowing for further analysis or reporting.
Example:
PowerWrapper wrapper = PowerWrapper()
wrapper.stop()
"""
if self.thread and self.thread.is_alive():
# self.stop_thread()
self.thread.do_run = False
self.thread.join()
end_time = time.time()
usages = pd.DataFrame(self.power_draws)
cpu_energy = pd.DataFrame()
usages = usages.sum().to_frame().T
usages = usages * self.interval / 3600 # convert watt to watt-hour for RAM and GPU especially
if self.amd:
self.amd_power.stop()
cpu_energy = self.amd_power.parse_log()
usages = pd.concat([cpu_energy, usages], axis=1)
if self.intel:
self.intel_record.append(self.intel_power.append_energy_usage())
cpu_energy = pd.DataFrame(self.intel_record)
cpu_energy = cpu_energy.diff().fillna(cpu_energy)
cpu_energy = cpu_energy.iloc[1:, :]
cpu_energy = cpu_energy.mask(cpu_energy.lt(0)).ffill().fillna(0)
cpu_energy = cpu_energy.sum().to_frame().T
usages = pd.concat([cpu_energy, usages], axis=1)
if self.energy_unit=="j":
usages = usages * WH_TO_JOULE
elif self.energy_unit=="wh":
pass
elif self.energy_unit=="kwh":
usages = usages * WH_TO_KW
else :
LOGGER.info("WARRNING : The specified energy unit is not supported. "
"Please try to specify J or WH or KWH in the energy config file. "
"Otherwise, the default unit of WH is used")
usages[TOTAL_CPU_TIME] = end_time - self.start_time
self.record = usages.round(5)
|
stop_thread
Stops the recording thread.
Source code in ea2p/src/power.py
| def stop_thread(self):
"""
Stops the recording thread.
"""
self.thread.do_run = False
self.thread.join()
|