Skip to content

Commit d41d19b

Browse files
authored
Merge pull request #1157 from goneng/fix_high_cpu
GUI: Reduce CPU usage by adding sleep intervals to UI wait loops
2 parents da8299d + 4ce91ca commit d41d19b

13 files changed

+55
-55
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# OpenCore Legacy Patcher changelog
22

3+
## 2.4.0
4+
- Reduce CPU usage on main UI thread
5+
36
## 2.3.2
47
- Resolve erroring in Passwords app and Safari Autofill on T1 Macs running 15.4 or later
58
- Increment binaries:

opencore_legacy_patcher/application_entry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def _generate_base_data(self) -> None:
130130

131131
if not any(x in sys.argv for x in ignore_args):
132132
while self.constants.unpack_thread.is_alive():
133-
time.sleep(0.1)
133+
time.sleep(self.constants.thread_sleep_interval)
134134

135135
arguments.arguments(self.constants)
136136

opencore_legacy_patcher/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ def __init__(self) -> None:
155155
self.unpack_thread = None # Determine if unpack thread finished (threading.Thread)
156156
self.update_stage: int = 0 # Determine update stage (see gui_support.py)
157157
self.log_filepath: Path = None # Path to log file
158+
self.thread_sleep_interval: float = 0.1 # Sleep interval between UI updates (seconds) - reduce refresh-rate to reduce CPU-usage
159+
self.thread_nap_interval: float = 0.01 # Short Sleep interval between UI updates (seconds) - for faster UI updates of the progress bar
158160

159161
self.commit_info: tuple = (None, None, None) # Commit info (Branch, Commit Date, Commit URL)
160162

opencore_legacy_patcher/wx_gui/gui_build.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import logging
77
import threading
88
import traceback
9+
import time
910

1011
from .. import constants
1112

@@ -101,12 +102,12 @@ def _invoke_build(self) -> None:
101102
"""
102103
while gui_support.PayloadMount(self.constants, self).is_unpack_finished() is False:
103104
wx.Yield()
105+
time.sleep(self.constants.thread_sleep_interval)
104106

105107
thread = threading.Thread(target=self._build)
106108
thread.start()
107109

108-
while thread.is_alive():
109-
wx.Yield()
110+
gui_support.wait_for_thread(thread)
110111

111112
self.return_button.Enable()
112113

opencore_legacy_patcher/wx_gui/gui_cache_os_update.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,11 @@ def _metallib_thread_spawn():
7676
if results[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED] is True:
7777
kdk_thread = threading.Thread(target=_kdk_thread_spawn)
7878
kdk_thread.start()
79-
while kdk_thread.is_alive():
80-
wx.Yield()
79+
gui_support.wait_for_thread(kdk_thread)
8180
if results[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_REQUIRED] is True:
8281
metallib_thread = threading.Thread(target=_metallib_thread_spawn)
8382
metallib_thread.start()
84-
while metallib_thread.is_alive():
85-
wx.Yield()
83+
gui_support.wait_for_thread(metallib_thread)
8684

8785

8886
download_objects = {
@@ -149,8 +147,7 @@ def _validate_kdk_checksum_thread():
149147
kdk_checksum_thread = threading.Thread(target=_validate_kdk_checksum_thread)
150148
kdk_checksum_thread.start()
151149

152-
while kdk_checksum_thread.is_alive():
153-
wx.Yield()
150+
gui_support.wait_for_thread(kdk_checksum_thread)
154151

155152
if self.kdk_checksum_result is False:
156153
logging.error("KDK checksum validation failed")
@@ -172,8 +169,7 @@ def _install_kdk_thread():
172169
kdk_install_thread = threading.Thread(target=_install_kdk_thread)
173170
kdk_install_thread.start()
174171

175-
while kdk_install_thread.is_alive():
176-
wx.Yield()
172+
gui_support.wait_for_thread(kdk_install_thread)
177173

178174
if self.kdk_install_result is False:
179175
logging.info("Failed to install KDK")
@@ -194,8 +190,7 @@ def _install_metallib_thread():
194190
metallib_install_thread = threading.Thread(target=_install_metallib_thread)
195191
metallib_install_thread.start()
196192

197-
while metallib_install_thread.is_alive():
198-
wx.Yield()
193+
gui_support.wait_for_thread(metallib_install_thread)
199194

200195
if self.metallib_install_result is False:
201196
logging.info("Failed to install Metallib")

opencore_legacy_patcher/wx_gui/gui_download.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import wx
66
import logging
7+
import time
78

89
from .. import constants
910

@@ -86,6 +87,7 @@ def _generate_elements(self, frame: wx.Dialog = None) -> None:
8687
label_amount.Centre(wx.HORIZONTAL)
8788

8889
wx.Yield()
90+
time.sleep(self.constants.thread_sleep_interval)
8991

9092
if self.download_obj.download_complete is False and self.user_cancelled is False:
9193
wx.MessageBox(f"Download failed: \n{self.download_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)

opencore_legacy_patcher/wx_gui/gui_install_oc.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,7 @@ def _display_disks(self) -> None:
103103
thread = threading.Thread(target=self._fetch_disks)
104104
thread.start()
105105

106-
while thread.is_alive():
107-
wx.Yield()
108-
continue
106+
gui_support.wait_for_thread(thread)
109107

110108
self.progress_bar_animation.stop_pulse()
111109
self.progress_bar.Hide()
@@ -281,8 +279,7 @@ def _invoke_install_oc(self, partition: dict) -> None:
281279
thread = threading.Thread(target=self._install_oc, args=(partition,))
282280
thread.start()
283281

284-
while thread.is_alive():
285-
wx.Yield()
282+
gui_support.wait_for_thread(thread)
286283

287284
if self.result is True:
288285
if self.constants.update_stage != gui_support.AutoUpdateStages.INACTIVE and self.constants.detected_os >= os_data.os_data.big_sur:

opencore_legacy_patcher/wx_gui/gui_macos_installer_download.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ def _fetch_installers():
149149
thread = threading.Thread(target=_fetch_installers)
150150
thread.start()
151151

152-
while thread.is_alive():
153-
wx.Yield()
152+
gui_support.wait_for_thread(thread)
154153

155154
progress_bar_animation.stop_pulse()
156155
progress_bar.Hide()
@@ -412,8 +411,7 @@ def extract_installer():
412411
self.Show()
413412

414413
# Wait for thread to finish
415-
while thread.is_alive():
416-
wx.Yield()
414+
gui_support.wait_for_thread(thread)
417415

418416
progress_bar_animation.stop_pulse()
419417
progress_bar.Hide()

opencore_legacy_patcher/wx_gui/gui_macos_installer_flash.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ def fetch_installers():
8888
thread = threading.Thread(target=fetch_installers)
8989
thread.start()
9090

91-
while thread.is_alive():
92-
wx.Yield()
91+
gui_support.wait_for_thread(thread)
9392

9493
frame_modal = wx.Dialog(self, title=self.title, size=(350, 200))
9594

@@ -180,8 +179,7 @@ def _fetch_disks():
180179
thread = threading.Thread(target=_fetch_disks)
181180
thread.start()
182181

183-
while thread.is_alive():
184-
wx.Yield()
182+
gui_support.wait_for_thread(thread)
185183

186184
self.frame_modal = wx.Dialog(self, title=self.title, size=(350, 200))
187185

@@ -317,7 +315,9 @@ def _flash():
317315
except:
318316
bytes_written = 0
319317
wx.CallAfter(progress_bar.SetValue, bytes_written)
318+
320319
wx.Yield()
320+
time.sleep(self.constants.thread_sleep_interval)
321321

322322
if self.result is False:
323323
logging.error("Failed to flash installer, cannot continue.")
@@ -370,8 +370,7 @@ def prepare_script(self, installer_path: str, disk: str, constants: constants.Co
370370
thread = threading.Thread(target=prepare_script, args=(self, installer_path, disk, self.constants))
371371
thread.start()
372372

373-
while thread.is_alive():
374-
wx.Yield()
373+
gui_support.wait_for_thread(thread)
375374

376375
return self.prepare_result
377376

@@ -399,10 +398,11 @@ def _flash_installer(self, disk) -> bool:
399398
return False
400399

401400
logging.info("Successfully created macOS installer")
402-
while thread.is_alive():
403-
# wait for download_thread to finish
404-
# though highly unlikely this thread is still alive (flashing an Installer will take a while)
405-
time.sleep(0.1)
401+
402+
# wait for download_thread to finish
403+
# though highly unlikely this thread is still alive (flashing an Installer will take a while)
404+
gui_support.wait_for_thread(thread)
405+
406406
logging.info("Installing Root Patcher to drive")
407407
self._install_installer_pkg(disk)
408408

@@ -617,8 +617,7 @@ def _integrity_check():
617617

618618
thread = threading.Thread(target=_integrity_check)
619619
thread.start()
620-
while thread.is_alive():
621-
wx.Yield()
620+
gui_support.wait_for_thread(thread)
622621

623622
if error_message == "":
624623
logging.info("Installer pkg validated")

opencore_legacy_patcher/wx_gui/gui_support.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,19 @@ def emit(self, record: logging.LogRecord):
263263
wx.CallAfter(self.text_box.AppendText, self.format(record) + '\n')
264264

265265

266+
def wait_for_thread(thread: threading.Thread, sleep_interval=None):
267+
"""
268+
Waits for a thread to finish while processing UI events at regular intervals
269+
to prevent UI freezing and excessive CPU usage.
270+
"""
271+
# Use the passed sleep_interval, or get from global_constants
272+
interval = sleep_interval if sleep_interval is not None else constants.Constants().thread_sleep_interval
273+
274+
while thread.is_alive():
275+
wx.Yield()
276+
time.sleep(interval)
277+
278+
266279
class RestartHost:
267280
"""
268281
Restarts the host machine

0 commit comments

Comments
 (0)