Run the build below normal priority.

The build compiles on every processor for ten minutes and more while the
job screen invites the player to keep using the PC. build.Run now starts
make_game.py with Windows' below-normal priority class, which the
compilers and the other processes the build starts take over from it, so
the build gives way to what the player does and loses nothing on an idle
PC.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-10 15:32:48 -05:00
parent c02b62826d
commit ef30a23969
2 changed files with 24 additions and 1 deletions

View File

@@ -14,6 +14,11 @@ RUN = ('import os, runpy, sys; p = sys.argv[1]; s = sys.argv[2]; sys.argv = sys.
'runpy.run_path(s, run_name="__main__")')
CREATE_NO_WINDOW = 0x08000000
CREATE_NEW_PROCESS_GROUP = 0x00000200
# The build runs below normal priority: a compile on every processor for ten minutes and more otherwise takes the
# PC from whatever the player does meanwhile, which the job screen invites ("Keep using your PC if you like"). On an
# idle PC it costs nothing. Windows hands a below-normal process's class on to the processes it starts, so the
# compilers, the lifter's workers and the shader preparation that make_game.py starts run that way too.
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
def command(layout, args):
@@ -61,7 +66,7 @@ class Run:
self.error = None
kw = {}
if os.name == 'nt':
kw['creationflags'] = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP
kw['creationflags'] = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | BELOW_NORMAL_PRIORITY_CLASS
else:
kw['start_new_session'] = True
env = dict(os.environ, PYTHONUNBUFFERED='1', PYTHONIOENCODING='utf-8')

View File

@@ -2743,6 +2743,24 @@ class JobTest(Tmp):
App.job_finished(a)
self.assertEqual(a.message, 'The game is built. Select Play.')
@unittest.skipUnless(os.name == 'nt', 'Windows priority classes')
def test_the_build_and_what_it_starts_run_below_normal_priority(self):
"""build.Run starts the build below normal priority, and the processes the build starts (the compilers)
get that class from it, so a build on every processor leaves the PC usable."""
script = self.tmp / 'priority.py'
script.write_text(
'import ctypes, subprocess, sys\n'
'k = ctypes.windll.kernel32\n'
'k.GetCurrentProcess.restype = ctypes.c_void_p\n'
'k.GetPriorityClass.argtypes = [ctypes.c_void_p]\n'
'print(sys.argv[1], hex(k.GetPriorityClass(k.GetCurrentProcess())), flush=True)\n'
'if sys.argv[1] == "build":\n'
' subprocess.run([sys.executable, __file__, "compiler"])\n')
lines = []
run = build.Run([sys.executable, str(script), 'build'], lambda ev: None, lines.append)
self.assertEqual(run.wait(), 0, lines)
self.assertEqual(lines, ['build 0x4000', 'compiler 0x4000']) # BELOW_NORMAL_PRIORITY_CLASS
def test_an_install_goes_on_from_the_unpacked_game_files(self):
"""Begin Installation into a folder whose game files an earlier run unpacked builds on from them (--rebuild
for this processor's level), so a moved or deleted dump is not asked for; without them it reads the dump."""