@@ -58,11 +58,15 @@ def __init__(self):
5858 return
5959 self ._initialized = True
6060 self ._conn = None
61+ self ._available = False
6162 self ._smc_lock = threading .Lock ()
62- self ._iokit = ctypes .cdll .LoadLibrary ('/System/Library/Frameworks/IOKit.framework/IOKit' )
63- self ._cf = ctypes .cdll .LoadLibrary ('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation' )
64- self ._setup_functions ()
65- self ._open ()
63+ try :
64+ self ._iokit = ctypes .cdll .LoadLibrary ('/System/Library/Frameworks/IOKit.framework/IOKit' )
65+ self ._cf = ctypes .cdll .LoadLibrary ('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation' )
66+ self ._setup_functions ()
67+ self ._open ()
68+ except Exception as e :
69+ logger .warning (f"SMC init failed: { e } " )
6670
6771 def _setup_functions (self ):
6872 iokit = self ._iokit
@@ -80,6 +84,8 @@ def _setup_functions(self):
8084 iokit .IOServiceOpen .restype = ctypes .c_uint32
8185 iokit .IOServiceClose .argtypes = [ctypes .c_uint32 ]
8286 iokit .IOServiceClose .restype = ctypes .c_uint32
87+ iokit .IOObjectRelease .argtypes = [ctypes .c_uint32 ]
88+ iokit .IOObjectRelease .restype = ctypes .c_uint32
8389
8490 self ._mach_task_self = ctypes .cdll .LoadLibrary ('/usr/lib/libSystem.B.dylib' ).mach_task_self
8591 self ._mach_task_self .restype = ctypes .c_uint32
@@ -102,10 +108,12 @@ def _open(self):
102108 return
103109 conn = ctypes .c_uint32 ()
104110 result = self ._iokit .IOServiceOpen (service , self ._mach_task_self (), 0 , ctypes .byref (conn ))
111+ self ._iokit .IOObjectRelease (service )
105112 if result != 0 :
106113 logger .warning (f"Could not open Apple SMC connection: { result :#x} " )
107114 return
108115 self ._conn = conn .value
116+ self ._available = True
109117
110118 def _fcc (self , s ):
111119 return int .from_bytes (s .encode ('ascii' ), byteorder = 'big' )
@@ -121,7 +129,7 @@ def _smc_call(self, buf):
121129 return result , out
122130
123131 def read_key (self , key_name ):
124- if not self ._conn :
132+ if not self ._available :
125133 return None
126134 with self ._smc_lock :
127135 try :
@@ -208,7 +216,6 @@ def __init__(self):
208216 self ._sub = None
209217 self ._channels = None
210218 self ._last_sample = None
211- self ._last_delta = None
212219 self ._last_time = None
213220 self ._sample_interval = 1.0
214221 self ._data_lock = threading .Lock ()
@@ -339,7 +346,7 @@ def _sample_loop(self):
339346 parsed = self ._parse_delta (delta , dt )
340347 with self ._data_lock :
341348 self ._parsed = parsed
342- self ._last_delta = delta
349+ self ._cf . CFRelease ( delta )
343350 self ._cf .CFRelease (self ._last_sample )
344351 else :
345352 self ._cf .CFRelease (self ._last_sample )
@@ -352,8 +359,6 @@ def _sample_loop(self):
352359 def _parse_delta (self , delta , dt ):
353360 result = {
354361 'energy' : {},
355- 'cpu_freq' : math .nan ,
356- 'gpu_freq' : math .nan ,
357362 'cpu_power' : math .nan ,
358363 'gpu_power' : math .nan ,
359364 'dram_power' : math .nan ,
@@ -374,11 +379,8 @@ def _parse_delta(self, delta, dt):
374379
375380 count = cf .CFArrayGetCount (channels_arr )
376381 energy_values = {}
377- cpu_residencies = {}
378- gpu_residencies = {}
379382
380383 SIMPLE_FORMAT = 1
381- STATE_FORMAT = 2
382384
383385 for i in range (count ):
384386 ch = cf .CFArrayGetValueAtIndex (channels_arr , i )
@@ -394,28 +396,6 @@ def _parse_delta(self, delta, dt):
394396 val = iorep .IOReportSimpleGetIntegerValue (ch , None )
395397 energy_values [name ] = val
396398
397- elif "CPU Stats" in group and fmt == STATE_FORMAT :
398- state_count = iorep .IOReportStateGetCount (ch )
399- if state_count > 0 :
400- states = {}
401- for si in range (state_count ):
402- residency = iorep .IOReportStateGetResidency (ch , si )
403- sname_cf = iorep .IOReportStateGetNameForIndex (ch , si )
404- sname = self ._cfstr_to_str (sname_cf )
405- states [sname ] = residency
406- cpu_residencies [name ] = states
407-
408- elif "GPU Stats" in group and fmt == STATE_FORMAT :
409- state_count = iorep .IOReportStateGetCount (ch )
410- if state_count > 0 :
411- states = {}
412- for si in range (state_count ):
413- residency = iorep .IOReportStateGetResidency (ch , si )
414- sname_cf = iorep .IOReportStateGetNameForIndex (ch , si )
415- sname = self ._cfstr_to_str (sname_cf )
416- states [sname ] = residency
417- gpu_residencies [name ] = states
418-
419399 result ['energy' ] = energy_values
420400
421401 cpu_total_energy = 0
@@ -565,21 +545,21 @@ class Cpu(sensors.Cpu):
565545 def percentage (interval : float ) -> float :
566546 try :
567547 return psutil .cpu_percent (interval = interval )
568- except :
548+ except Exception :
569549 return math .nan
570550
571551 @staticmethod
572552 def frequency () -> float :
573553 try :
574554 return psutil .cpu_freq ().current
575- except :
555+ except Exception :
576556 return math .nan
577557
578558 @staticmethod
579559 def load () -> Tuple [float , float , float ]:
580560 try :
581561 return psutil .getloadavg ()
582- except :
562+ except Exception :
583563 return math .nan , math .nan , math .nan
584564
585565 @staticmethod
@@ -675,13 +655,19 @@ def fan_percent() -> float:
675655 def frequency () -> float :
676656 return math .nan
677657
658+ _gpu_detected = None
659+
678660 @staticmethod
679661 def is_available () -> bool :
662+ if Gpu ._gpu_detected is not None :
663+ return Gpu ._gpu_detected
680664 agx = _get_agx ()
681665 model = agx .get ('model' , '' )
682666 if model :
683667 logger .info (f"Detected Apple GPU: { model } ({ agx .get ('gpu-core-count' , '?' )} cores)" )
668+ Gpu ._gpu_detected = True
684669 return True
670+ Gpu ._gpu_detected = False
685671 return False
686672
687673
@@ -690,28 +676,28 @@ class Memory(sensors.Memory):
690676 def swap_percent () -> float :
691677 try :
692678 return psutil .swap_memory ().percent
693- except :
679+ except Exception :
694680 return math .nan
695681
696682 @staticmethod
697683 def virtual_percent () -> float :
698684 try :
699685 return psutil .virtual_memory ().percent
700- except :
686+ except Exception :
701687 return math .nan
702688
703689 @staticmethod
704690 def virtual_used () -> int :
705691 try :
706692 return psutil .virtual_memory ().total - psutil .virtual_memory ().available
707- except :
693+ except Exception :
708694 return - 1
709695
710696 @staticmethod
711697 def virtual_free () -> int :
712698 try :
713699 return psutil .virtual_memory ().available
714- except :
700+ except Exception :
715701 return - 1
716702
717703
@@ -720,21 +706,21 @@ class Disk(sensors.Disk):
720706 def disk_usage_percent () -> float :
721707 try :
722708 return psutil .disk_usage ("/" ).percent
723- except :
709+ except Exception :
724710 return math .nan
725711
726712 @staticmethod
727713 def disk_used () -> int :
728714 try :
729715 return psutil .disk_usage ("/" ).used
730- except :
716+ except Exception :
731717 return - 1
732718
733719 @staticmethod
734720 def disk_free () -> int :
735721 try :
736722 return psutil .disk_usage ("/" ).free
737- except :
723+ except Exception :
738724 return - 1
739725
740726
@@ -750,17 +736,15 @@ def stats(if_name, interval) -> Tuple[int, int, int, int]:
750736
751737 if if_name != "" :
752738 if if_name in pnic_after :
753- try :
739+ if if_name in PNIC_BEFORE :
754740 upload_rate = (pnic_after [if_name ].bytes_sent - PNIC_BEFORE [if_name ].bytes_sent ) / interval
755741 uploaded = pnic_after [if_name ].bytes_sent
756742 download_rate = (pnic_after [if_name ].bytes_recv - PNIC_BEFORE [if_name ].bytes_recv ) / interval
757743 downloaded = pnic_after [if_name ].bytes_recv
758- except :
759- pass
760- PNIC_BEFORE .update ({if_name : pnic_after [if_name ]})
744+ PNIC_BEFORE [if_name ] = pnic_after [if_name ]
761745 else :
762746 logger .warning ("Network interface '%s' not found. Check names in config.yaml." % if_name )
763747
764748 return upload_rate , uploaded , download_rate , downloaded
765- except :
749+ except Exception :
766750 return - 1 , - 1 , - 1 , - 1
0 commit comments