@@ -306,6 +306,60 @@ def _normalize_branch_name(branch):
306306 return branch
307307
308308
309+ def _graalpython_commit_is_ancestor_of_branch (commit , branch ):
310+ """Return True if the GraalPy commit is already reachable from the branch."""
311+ # Check the remote-tracking branch, not the local branch or HEAD. Regular branch-run
312+ # workspaces may put a synthetic merge commit on a local branch, while origin/<branch>
313+ # still represents the target branch state used to decide whether the GraalPy commit has
314+ # really landed.
315+ return _graalpython_merge_base_with_branch (commit , branch ) == commit
316+
317+
318+ def _graalpython_merge_base_with_branch (commit , branch ):
319+ if not commit or not branch or not SUITE .vc :
320+ return None
321+ merge_base = SUITE .vc .git_command (
322+ SUITE .dir ,
323+ ["merge-base" , commit , f"origin/{ branch } " ],
324+ abortOnError = False ,
325+ )
326+ return merge_base .strip () if merge_base else None
327+
328+
329+ def _graalpython_target_branch_profile_candidates (commit , branch , max_age_days ):
330+ """Return target-branch ancestor commits that may have CI-generated PGO profiles."""
331+ merge_base = _graalpython_merge_base_with_branch (commit , branch )
332+ if not merge_base :
333+ return []
334+
335+ commit_ts = SUITE .vc .git_command (
336+ SUITE .dir ,
337+ ["show" , "-s" , "--format=%ct" , merge_base ],
338+ abortOnError = False ,
339+ )
340+ if not commit_ts :
341+ return []
342+ try :
343+ since_ts = int (commit_ts .strip ()) - max_age_days * 24 * 60 * 60
344+ except ValueError :
345+ mx .warn (f"Cannot parse commit timestamp for GraalPy PGO profile search: { commit_ts !r} " )
346+ return []
347+
348+ candidates = SUITE .vc .git_command (
349+ SUITE .dir ,
350+ ["rev-list" , "--first-parent" , f"--since=@{ since_ts } " , merge_base ],
351+ abortOnError = False ,
352+ )
353+ return candidates .splitlines () if candidates else []
354+
355+
356+ def _graalpython_pgo_profile_exists (path ):
357+ try :
358+ return os .path .isfile (path or "" ) and os .path .getsize (path ) > 0
359+ except OSError :
360+ return False
361+
362+
309363def _graalpython_target_import_commit (target_branch ):
310364 """Return the GraalPy commit imported by the target branch's VM suite.
311365
@@ -458,55 +512,70 @@ def libpythonvm_build_args():
458512 profile_source_commit = source_commit
459513 profile_source_branch = source_branch
460514 profile_source_reason = "current GraalPy commit"
515+ profile_source_candidates = [(profile_source_commit , profile_source_branch , profile_source_reason )]
461516 override = os .environ .get ("GRAALPY_PGO_PROFILE_SOURCE_COMMIT" )
462517 if override :
463518 profile_source_commit = override .strip ()
464519 if not re .match (r"^[0-9a-f]{40}$" , profile_source_commit ):
465520 mx .abort (f"GRAALPY_PGO_PROFILE_SOURCE_COMMIT must be a 40-character lowercase git commit, got: { override } " )
466521 profile_source_reason = "GRAALPY_PGO_PROFILE_SOURCE_COMMIT"
522+ profile_source_candidates = [(profile_source_commit , profile_source_branch , profile_source_reason )]
467523 elif (
468524 target_branch
469525 and source_branch
470526 and source_branch != target_branch
471527 and not (source_branch == MAIN_BRANCH or source_branch .startswith (("release/" , "cpu/" )))
528+ and not _graalpython_commit_is_ancestor_of_branch (source_commit , target_branch )
472529 ):
473- # Feature branch merge commits can import a fresh GraalPy revision that
474- # has no released-product profile yet. Use the target branch's imported
475- # GraalPy commit so product-ee consumes the profile that already belongs
476- # to the baseline product launcher.
530+ # Feature branch commits usually have no released-product profile yet,
531+ # but use one if it was explicitly generated. Otherwise prefer the
532+ # nearest available target-branch ancestor profile, then fall back to
533+ # the VM suite's target import for compatibility with older CI workspaces.
534+ profile_search_days = 14
535+ target_candidates = _graalpython_target_branch_profile_candidates (
536+ source_commit , target_branch , profile_search_days
537+ )
477538 target_import_commit = _graalpython_target_import_commit (target_branch )
478- if target_import_commit :
479- profile_source_commit = target_import_commit
480- profile_source_branch = target_branch
481- profile_source_reason = f"target branch import from { target_branch } "
482- elif require_profile :
483- mx .abort ("\n " .join ([
484- "Could not resolve the GraalPy PGO profile source commit from the target branch import." ,
485- f"GraalPy source commit: { source_commit } " ,
486- f"Source branch: { source_branch or '<unknown>' } " ,
487- f"Target branch: { target_branch or '<unknown>' } " ,
488- "Expected to read vm/mx.vm/suite.py from the target branch and find the graalpython import version." ,
489- "Set GRAALPY_PGO_PROFILE_SOURCE_COMMIT=<40-character-commit> to override this lookup for debugging." ,
490- ]))
491- else :
492- mx .warn ("Falling back to the current GraalPy commit for PGO profile lookup because the target branch import could not be resolved" )
539+ profile_source_candidates = [
540+ (source_commit , source_branch , "current GraalPy branch commit" ),
541+ ] + [
542+ (commit , target_branch , f"target branch ancestor from { target_branch } " )
543+ for commit in target_candidates
544+ ]
545+ if (
546+ target_import_commit
547+ and target_import_commit not in {commit for commit , _ , _ in profile_source_candidates }
548+ ):
549+ profile_source_candidates .append (
550+ (target_import_commit , target_branch , f"target branch import from { target_branch } " )
551+ )
493552 artifact_name = f"{ GRAALPY_PGO_PROFILE_ARTIFACT_GROUP } /{ GRAALPY_PGO_PROFILE_ARTIFACT_PREFIX } { profile_source_commit } "
494553 mx .log (f"GraalPy source commit for PGO profile lookup: { source_commit } " )
495- mx .log (f"GraalPy PGO profile source commit: { profile_source_commit } ({ profile_source_reason } )" )
496554
497555 if script := os .environ .get ("ARTIFACT_DOWNLOAD_SCRIPT" ):
498556 # This is always available in the GraalPy CI
499557 profile = f"cached_profile.iprof.gz"
500- run (
501- [
502- sys .executable ,
503- script ,
504- artifact_name ,
505- profile ,
506- ],
507- nonZeroIsFatal = False ,
508- )
558+ for candidate_commit , candidate_branch , candidate_reason in profile_source_candidates :
559+ profile_source_commit = candidate_commit
560+ profile_source_branch = candidate_branch
561+ profile_source_reason = candidate_reason
562+ artifact_name = f"{ GRAALPY_PGO_PROFILE_ARTIFACT_GROUP } /{ GRAALPY_PGO_PROFILE_ARTIFACT_PREFIX } { profile_source_commit } "
563+ mx .log (f"GraalPy PGO profile source commit: { profile_source_commit } ({ profile_source_reason } )" )
564+ if os .path .exists (profile ):
565+ os .remove (profile )
566+ run (
567+ [
568+ sys .executable ,
569+ script ,
570+ artifact_name ,
571+ profile ,
572+ ],
573+ nonZeroIsFatal = False ,
574+ )
575+ if _graalpython_pgo_profile_exists (profile ):
576+ break
509577 elif not require_profile :
578+ mx .log (f"GraalPy PGO profile source commit: { profile_source_commit } ({ profile_source_reason } )" )
510579 # Locally, we try to get a reasonable profile
511580 get_profile = mx .command_function ('python-get-latest-profile' , fatalIfMissing = False )
512581 if get_profile :
@@ -522,7 +591,7 @@ def libpythonvm_build_args():
522591 except BaseException :
523592 pass
524593
525- profile_missing = not profile or not os . path . isfile (profile )
594+ profile_missing = not _graalpython_pgo_profile_exists (profile )
526595 if require_profile and profile_missing :
527596 mx .abort ("\n " .join ([
528597 "GRAALPY_REQUIRE_PGO_PROFILE is set, but no CI generated GraalPy PGO profile was found." ,
@@ -550,7 +619,7 @@ def libpythonvm_build_args():
550619 mx .warn ("PGO profile must exist for benchmarking and release, creating one now..." )
551620 profile = graalpy_native_pgo_build_and_test ()
552621
553- if os . path . isfile (profile or "" ):
622+ if _graalpython_pgo_profile_exists (profile ):
554623 print (invert (f"Automatically chose PGO profile { profile } . To disable this, set GRAALPY_PGO_PROFILE to an empty string'" , blinking = True ), file = sys .stderr )
555624 build_args += [
556625 f"--pgo={ profile } " ,
0 commit comments