Skip to content

PR: number_of_cpu function logic for Darwin and some error handling #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion eco2ai/tools/tools_cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ def number_of_cpu(ignore_warnings=True):
processor_string = dictionary['Џа®жҐбб®а(л)']
if 'Процессор(ы)' in dictionary:
processor_string = dictionary['Процессор(ы)']
cpu_num = int(re.findall(r'- (\d)\.', processor_string)[0])
# Use regex for multi-digit CPU numbers
match = re.findall(r'- (\d+)\.', processor_string)
cpu_num = int(match[0]) if match else 1
except:
if not ignore_warnings:
warnings.warn(
Expand All @@ -271,7 +273,26 @@ def number_of_cpu(ignore_warnings=True):
# message="\nIt's impossible to determine cpu number correctly\nFor now, number of cpu devices is set to 1\n\n",
# category=NoNeededLibrary
# )
try:
# Try to get the number of physical CPU packages
out = subprocess.check_output(
["sysctl", "-n", "hw.packages"], text=True).strip()
cpu_num = int(out)
except (subprocess.CalledProcessError, ValueError): cpu_num = 0

if cpu_num <= 0:
try:
# Fallback: number of physical cores
out = subprocess.check_output(["sysctl", "-n", "hw.physicalcpu"], text=True).strip()
cpu_num = int(out)
except (subprocess.CalledProcessError, ValueError):
if not ignore_warnings:
warnings.warn(
"Unable to determine the number of CPU sockets on Darwin; defaulting to 1",
category=UserWarning
)
cpu_num = 1

else:
cpu_num = 1
return cpu_num
Expand Down
105 changes: 60 additions & 45 deletions eco2ai/tools/tools_gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,17 @@ def gpu_memory(self):
"""
if not self.is_gpu_available:
return None
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_memory = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_memory.append(pynvml.nvmlDeviceGetMemoryInfo(handle))
pynvml.nvmlShutdown()
return gpus_memory
try:
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_memory = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_memory.append(pynvml.nvmlDeviceGetMemoryInfo(handle))
pynvml.nvmlShutdown()
return gpus_memory
except Exception:
return None # standardized error return

def gpu_temperature(self):
"""
Expand All @@ -130,14 +133,17 @@ def gpu_temperature(self):
"""
if not self.is_gpu_available:
return None
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_temps = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_temps.append(pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU))
pynvml.nvmlShutdown()
return gpus_temps
try:
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_temps = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_temps.append(pynvml.nvmlDeviceGetTemperature(handle, pynvml.NVML_TEMPERATURE_GPU))
pynvml.nvmlShutdown()
return gpus_temps
except Exception:
return None

def gpu_power(self):
"""
Expand All @@ -155,14 +161,17 @@ def gpu_power(self):
"""
if not self.is_gpu_available:
return None
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_powers = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_powers.append(pynvml.nvmlDeviceGetPowerUsage(handle))
pynvml.nvmlShutdown()
return gpus_powers
try:
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_powers = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_powers.append(pynvml.nvmlDeviceGetPowerUsage(handle))
pynvml.nvmlShutdown()
return gpus_powers
except Exception:
return None

def gpu_power_limit(self):
"""
Expand All @@ -180,18 +189,19 @@ def gpu_power_limit(self):
"""
if not self.is_gpu_available:
return None
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_limits = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_limits.append(pynvml.nvmlDeviceGetEnforcedPowerLimit(handle))
pynvml.nvmlShutdown()
return gpus_limits
try:
pynvml.nvmlInit()
deviceCount = pynvml.nvmlDeviceGetCount()
gpus_limits = []
for i in range(deviceCount):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
gpus_limits.append(pynvml.nvmlDeviceGetEnforcedPowerLimit(handle))
pynvml.nvmlShutdown()
return gpus_limits
except Exception:
return None

def name(
self,
):
def name(self,):
"""
This class method returns GPU name if there are any GPU visible
or it returns empty string. All the GPU devices are intended to be of the same model
Expand All @@ -216,11 +226,14 @@ def name(
pynvml.nvmlDeviceGetPowerUsage(handle)
gpus_name.append(pynvml.nvmlDeviceGetName(handle))
pynvml.nvmlShutdown()
return gpus_name[0].encode().decode("UTF-8")
except:
if gpus_name:
return gpus_name[0].encode().decode("UTF-8")
else:
return ""
except Exception:
return ""

def gpu_num(self):
def gpu_num(self) -> int:
"""
This class method returns number of visible GPU devices.
Pynvml library is used.
Expand All @@ -243,11 +256,11 @@ def gpu_num(self):
pynvml.nvmlDeviceGetPowerUsage(handle)
pynvml.nvmlShutdown()
return deviceCount
except:
except Exception:
return 0


def is_gpu_available():
def is_gpu_available() -> bool:
"""
This function checks if there are any available GPU devices
All the GPU devices are intended to be of the same model
Expand All @@ -272,7 +285,7 @@ def is_gpu_available():
gpus_powers.append(pynvml.nvmlDeviceGetPowerUsage(handle))
pynvml.nvmlShutdown()
return True
except pynvml.NVMLError:
except Exception: # catch all exceptions for robustness
return False


Expand All @@ -298,10 +311,12 @@ def all_available_gpu():
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
pynvml.nvmlDeviceGetPowerUsage(handle)
gpus_name.append(pynvml.nvmlDeviceGetName(handle))
string = f"""Seeable gpu device(s):
if gpus_name:
string = f"""Seeable gpu device(s):
{gpus_name[0].decode("UTF-8")}: {deviceCount} device(s)"""
print(string)
print(string)
else:
print("There is no any available gpu device(s)")
pynvml.nvmlShutdown()
except:
except Exception:
print("There is no any available gpu device(s)")

5 changes: 3 additions & 2 deletions eco2ai/tools/tools_ram.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _get_memory_used(self,):
return memory_percent * total_memory / 100


def calculate_consumption(self):
def calculate_consumption(self) -> float:
"""
This class method calculates RAM power consumption.

Expand All @@ -97,7 +97,8 @@ def calculate_consumption(self):
time_period = time.time() - self._start
self._start = time.time()
consumption = self._get_memory_used() * (3 / 8) * time_period / FROM_WATTs_TO_kWATTh

if consumption < 0: # ensure no negative values
consumption = 0
self._consumption += consumption
# print(self._consumption)
return consumption
12 changes: 7 additions & 5 deletions eco2ai/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class NotNeededExtensionError(Exception):
pass


def available_devices():
def available_devices() -> None:
"""
This function prints all the available CPU & GPU devices

Expand Down Expand Up @@ -118,11 +118,11 @@ def define_carbon_index(
carbon_index_table_name = resource_stream('eco2ai', 'data/carbon_index.csv').name
if alpha_2_code is None:
try:
ip_dict = eval(requests.get("https://ipinfo.io/").content)
ip_dict = json.loads(requests.get("https://ipinfo.io/").content) # safer than eval
except:
ip_dict = eval(requests.get("https://ipinfo.io/").content.decode('ascii'))
country = ip_dict['country']
region = ip_dict['region']
ip_dict = json.loads(requests.get("https://ipinfo.io/").content.decode('ascii'))
country = ip_dict.get('country', None)
region = ip_dict.get('region', None)
else:
country = alpha_2_code
if emission_level is not None:
Expand Down Expand Up @@ -507,6 +507,8 @@ def summary(
if not filename.endswith('.csv'):
raise NotNeededExtensionError('File need to be with extension \'.csv\'')
df = pd.read_csv(filename)
if df.empty:
raise ValueError("CSV file is empty, cannot summarize.")
projects = np.unique(df['project_name'].values)
summary_data = []
columns = [
Expand Down