@@ -8,7 +8,7 @@ import traceback
88import logging
99import time
1010from collections import defaultdict
11- from typing import List , Any , DefaultDict , Tuple
11+ from typing import List , Any , DefaultDict , Tuple , Optional
1212from collections .abc import Set
1313from pathlib import Path
1414import graphlib
@@ -302,117 +302,138 @@ def try_pick_some(
302302 if not ready :
303303 return []
304304
305- cpu_avail_percent = tools .get_avail_cpu_percent ()
305+ cpu_ratio = tools .get_running_task_cpu_ratio ()
306306 memory_avail = tools .get_avail_memory ()
307307
308308 ready_to_build = [pkg for pkg in ready if pkg not in running ]
309309 if not ready_to_build :
310310 return []
311311
312312 rusages = db .get_pkgs_last_rusage (ready_to_build )
313- ready2 = [pkg for pkg in ready_to_build
314- if (r := rusages .get (pkg )) and r .memory < memory_avail ]
315- if not ready2 :
316- if starving :
317- ready2 = sorted (
318- ready_to_build ,
319- key = lambda pkg : rusages .get (pkg ) and r .memory or 10 * 1024 ** 3 , # type: ignore
320- )
321- limit = 1
322- logger .info ('insufficient memory, starting only one build' )
323- else :
324- logger .info ('insufficient memory, not starting another concurrent build' )
325- return []
326-
327- ready2 .sort (key = lambda pkg : rusages .get (pkg ) and r .cputime or 3600 ) # type: ignore
328- if cpu_avail_percent < 0.5 :
313+ ready_to_build .sort (key = lambda pkg : rusages .get (pkg ) and r .cputime or 3600 ) # type: ignore
314+ if cpu_ratio < 1.0 :
329315 # low cpu usage, build a big package
330- ready2 .insert (0 , ready2 .pop ())
316+ ready_to_build .insert (0 , ready_to_build .pop ())
331317 else :
332318 logger .info ('high cpu usage, preferring low-cpu-usage builds' )
333319
334320 ret : list [PkgToBuild ] = []
335321
336- for pkg in ready2 :
337- to_build = PkgToBuild (pkg )
338-
339- if pkg in failed :
340- buildsorter .done (pkg )
341- if db .USE :
342- with db .get_session () as s :
343- db .mark_pkg_as (s , pkg , 'done' )
344- db .build_updated (s )
345- # marked as failed (by lilac loader), skip
322+ for pkg in ready_to_build :
323+ if (r := rusages .get (pkg )) and r .memory > memory_avail :
346324 continue
347325
348- if rs := build_reasons .get (pkg ):
349- if len (rs ) == 1 and isinstance (rs [0 ], BuildReason .FailedByDeps ):
350- ds = BUILD_DEPMAP [pkg ]
351- if not all (d .resolve () for d in ds ):
352- buildsorter .done (pkg )
353- if db .USE :
354- with db .get_session () as s :
355- db .mark_pkg_as (s , pkg , 'done' )
356- db .build_updated (s )
357- # deps are still missing, skip
358- continue
359- if on_build := next (
360- (r for r in rs if isinstance (rs [0 ], BuildReason .OnBuild )),
361- None
362- ):
363- update_on_build = on_build .update_on_build
364- if len (rs ) == 1 and any (
365- x .pkgbase in failed for x in update_on_build
366- ):
367- # on_build packages have failures, skip
368- buildsorter .done (pkg )
369- if db .USE :
370- with db .get_session () as s :
371- db .mark_pkg_as (s , pkg , 'done' )
372- db .build_updated (s )
373- continue
374- try :
375- if db .USE :
376- vers = db .get_update_on_build_vers (update_on_build )
377- else :
378- vers = []
379- if len (rs ) == 1 and vers and all (old == new for old , new in vers ):
380- # no need to rebuild
381- buildsorter .done (pkg )
382- with db .get_session () as s :
383- db .mark_pkg_as (s , pkg , 'done' )
384- db .build_updated (s )
385- continue
386- logger .debug ('on_build_vers: %r' , vers )
387- to_build = PkgToBuild (pkg , vers )
388- except Exception as e :
389- logger .exception ('get_update_on_build_vers' )
390- mod = repo .lilacinfos [pkg ]
391- l10n = intl .get_l10n ('mail' )
392- repo .send_error_report (
393- mod ,
394- subject = l10n .format_value ('update_on_build-error' ),
395- exc = e ,
396- )
397- continue
398-
399- if db .USE :
400- update_on_build = REPO .lilacinfos [pkg ].update_on_build
401- if update_on_build and not to_build .on_build_vers :
402- # Fill in on_build_vers for packages that are not triggered by OnBuild.
403- # Provide the last version string as both old and new since it's not
404- # triggered by a change of them.
405- vers = [
406- (new , new ) for _ , new in db .get_update_on_build_vers (update_on_build )
407- ]
408- to_build = PkgToBuild (pkg , vers )
326+ to_build = check_buildability (pkg , repo , buildsorter , failed )
327+ if to_build is None :
328+ continue
409329
410330 ret .append (to_build )
411331 if len (ret ) == limit :
412332 break
413333
334+ if r := rusages .get (pkg ):
335+ memory_avail -= r .memory
336+ else :
337+ memory_avail -= 10 * 1024 ** 3
338+
339+ if not ret :
340+ if starving :
341+ ready_to_build .sort (
342+ key = lambda pkg : rusages .get (pkg ) and r .memory or 10 * 1024 ** 3 , # type: ignore
343+ )
344+ logger .info ('insufficient memory, starting only one build' )
345+ for pkg in ready_to_build :
346+ to_build = check_buildability (pkg , repo , buildsorter , failed )
347+ if to_build is None :
348+ continue
349+ ret .append (to_build )
350+ break
351+ else :
352+ logger .info ('insufficient memory, not starting another concurrent build' )
353+
414354 return ret
415355
356+ def check_buildability (
357+ pkg : str ,
358+ repo : Repo ,
359+ buildsorter : BuildSorter ,
360+ failed : dict [str , tuple [str , ...]],
361+ ) -> Optional [PkgToBuild ]:
362+ to_build = PkgToBuild (pkg )
363+
364+ if pkg in failed :
365+ buildsorter .done (pkg )
366+ if db .USE :
367+ with db .get_session () as s :
368+ db .mark_pkg_as (s , pkg , 'done' )
369+ db .build_updated (s )
370+ # marked as failed (by lilac loader), skip
371+ return None
372+
373+ if rs := build_reasons .get (pkg ):
374+ if len (rs ) == 1 and isinstance (rs [0 ], BuildReason .FailedByDeps ):
375+ ds = BUILD_DEPMAP [pkg ]
376+ if not all (d .resolve () for d in ds ):
377+ buildsorter .done (pkg )
378+ if db .USE :
379+ with db .get_session () as s :
380+ db .mark_pkg_as (s , pkg , 'done' )
381+ db .build_updated (s )
382+ # deps are still missing, skip
383+ return None
384+ if on_build := next (
385+ (r for r in rs if isinstance (rs [0 ], BuildReason .OnBuild )),
386+ None
387+ ):
388+ update_on_build = on_build .update_on_build
389+ if len (rs ) == 1 and any (
390+ x .pkgbase in failed for x in update_on_build
391+ ):
392+ # on_build packages have failures, skip
393+ buildsorter .done (pkg )
394+ if db .USE :
395+ with db .get_session () as s :
396+ db .mark_pkg_as (s , pkg , 'done' )
397+ db .build_updated (s )
398+ return None
399+ try :
400+ if db .USE :
401+ vers = db .get_update_on_build_vers (update_on_build )
402+ else :
403+ vers = []
404+ if len (rs ) == 1 and vers and all (old == new for old , new in vers ):
405+ # no need to rebuild
406+ buildsorter .done (pkg )
407+ with db .get_session () as s :
408+ db .mark_pkg_as (s , pkg , 'done' )
409+ db .build_updated (s )
410+ return None
411+ logger .debug ('on_build_vers: %r' , vers )
412+ to_build = PkgToBuild (pkg , vers )
413+ except Exception as e :
414+ logger .exception ('get_update_on_build_vers' )
415+ mod = repo .lilacinfos [pkg ]
416+ l10n = intl .get_l10n ('mail' )
417+ repo .send_error_report (
418+ mod ,
419+ subject = l10n .format_value ('update_on_build-error' ),
420+ exc = e ,
421+ )
422+ return None
423+
424+ if db .USE :
425+ update_on_build = REPO .lilacinfos [pkg ].update_on_build
426+ if update_on_build and not to_build .on_build_vers :
427+ # Fill in on_build_vers for packages that are not triggered by OnBuild.
428+ # Provide the last version string as both old and new since it's not
429+ # triggered by a change of them.
430+ vers = [
431+ (new , new ) for _ , new in db .get_update_on_build_vers (update_on_build )
432+ ]
433+ to_build = PkgToBuild (pkg , vers )
434+
435+ return to_build
436+
416437def build_it (
417438 to_build : PkgToBuild , repo : Repo , buildsorter : BuildSorter ,
418439 built : set [str ], failed : dict [str , tuple [str , ...]],
0 commit comments