Skip to content

Commit bf4e09d

Browse files
committed
Merge remote-tracking branch 'upstream/main' into frem-expansion
2 parents 1112189 + 99b1a2a commit bf4e09d

File tree

4,832 files changed

+309210
-270076
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

4,832 files changed

+309210
-270076
lines changed

.ci/metrics/metrics.py

Lines changed: 230 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import collections
22
import datetime
3+
import dateutil
34
import github
5+
import json
46
import logging
57
import os
68
import requests
@@ -41,7 +43,7 @@
4143
# This means we essentially have a list of workflows sorted by creation date,
4244
# and that's all we can deduce from it. So for each iteration, we'll blindly
4345
# process the last N workflows.
44-
GITHUB_WORKFLOWS_MAX_PROCESS_COUNT = 1000
46+
GITHUB_WORKFLOWS_MAX_PROCESS_COUNT = 2000
4547
# Second reason for the cut: reaching a workflow older than X.
4648
# This means we will miss long-tails (exceptional jobs running for more than
4749
# X hours), but that's also the case with the count cutoff above.
@@ -53,6 +55,18 @@
5355
# by trial and error).
5456
GRAFANA_METRIC_MAX_AGE_MN = 120
5557

58+
# Lists the BuildKite jobs we want to track. Maps the BuildKite job name to
59+
# the metric name in Grafana. This is important not to lose metrics history
60+
# if the workflow name changes.
61+
BUILDKITE_WORKFLOW_TO_TRACK = {
62+
":linux: Linux x64": "buildkite_linux",
63+
":windows: Windows x64": "buildkite_windows",
64+
}
65+
66+
# Number of builds to fetch per page. Since we scrape regularly, this can
67+
# remain small.
68+
BUILDKITE_GRAPHQL_BUILDS_PER_PAGE = 50
69+
5670
@dataclass
5771
class JobMetrics:
5872
job_name: str
@@ -70,6 +84,191 @@ class GaugeMetric:
7084
time_ns: int
7185

7286

87+
def buildkite_fetch_page_build_list(
88+
buildkite_token: str, after_cursor: str = None
89+
) -> list[dict[str, str]]:
90+
"""Fetches a page of the build list using the GraphQL BuildKite API.
91+
92+
Returns the BUILDKITE_GRAPHQL_BUILDS_PER_PAGE last running/queued builds,
93+
or the BUILDKITE_GRAPHQL_BUILDS_PER_PAGE running/queued builds
94+
older than the one pointer by |after_cursor| if provided.
95+
The |after_cursor| value is taken from the previous page returned by the
96+
API.
97+
98+
Args:
99+
buildkite_token: the secret token to authenticate GraphQL requests.
100+
after_cursor: cursor after which to start the page fetch.
101+
102+
Returns:
103+
The most recent builds after cursor (if set) with the following format:
104+
[
105+
{
106+
"cursor": <value>,
107+
"number": <build-number>,
108+
}
109+
]
110+
"""
111+
112+
BUILDKITE_GRAPHQL_QUERY = """
113+
query OrganizationShowQuery {{
114+
organization(slug: "llvm-project") {{
115+
pipelines(search: "Github pull requests", first: 1) {{
116+
edges {{
117+
node {{
118+
builds (state: [CANCELING, CREATING, FAILING, RUNNING], first: {PAGE_SIZE}, after: {AFTER}) {{
119+
edges {{
120+
cursor
121+
node {{
122+
number
123+
}}
124+
}}
125+
}}
126+
}}
127+
}}
128+
}}
129+
}}
130+
}}
131+
"""
132+
query = BUILDKITE_GRAPHQL_QUERY.format(
133+
PAGE_SIZE=BUILDKITE_GRAPHQL_BUILDS_PER_PAGE,
134+
AFTER="null" if after_cursor is None else '"{}"'.format(after_cursor),
135+
)
136+
query = json.dumps({"query": query})
137+
url = "https://graphql.buildkite.com/v1"
138+
headers = {
139+
"Authorization": "Bearer " + buildkite_token,
140+
"Content-Type": "application/json",
141+
}
142+
data = requests.post(url, data=query, headers=headers).json()
143+
# De-nest the build list.
144+
if "errors" in data:
145+
logging.info("Failed to fetch BuildKite jobs: {}".format(data["errors"]))
146+
return []
147+
builds = data["data"]["organization"]["pipelines"]["edges"][0]["node"]["builds"][
148+
"edges"
149+
]
150+
# Fold cursor info into the node dictionnary.
151+
return [{**x["node"], "cursor": x["cursor"]} for x in builds]
152+
153+
154+
def buildkite_get_build_info(build_number: str) -> dict:
155+
"""Returns all the info associated with the provided build number.
156+
157+
Note: for unknown reasons, graphql returns no jobs for a given build,
158+
while this endpoint does, hence why this uses this API instead of graphql.
159+
160+
Args:
161+
build_number: which build number to fetch info for.
162+
163+
Returns:
164+
The info for the target build, a JSON dictionnary.
165+
"""
166+
167+
URL = "https://buildkite.com/llvm-project/github-pull-requests/builds/{}.json"
168+
return requests.get(URL.format(build_number)).json()
169+
170+
171+
def buildkite_get_incomplete_tasks(buildkite_token: str) -> list:
172+
"""Returns all the running/pending BuildKite builds.
173+
174+
Args:
175+
buildkite_token: the secret token to authenticate GraphQL requests.
176+
last_cursor: the cursor to stop at if set. If None, a full page is fetched.
177+
"""
178+
output = []
179+
cursor = None
180+
while True:
181+
page = buildkite_fetch_page_build_list(buildkite_token, cursor)
182+
if len(page) == 0:
183+
break
184+
cursor = page[-1]["cursor"]
185+
output += page
186+
return output
187+
188+
189+
def buildkite_get_metrics(
190+
buildkite_token: str, previously_incomplete: set[int]
191+
) -> (list[JobMetrics], set[int]):
192+
"""Returns a tuple with:
193+
194+
- the metrics recorded for newly completed workflow jobs.
195+
- the set of workflow still running now.
196+
197+
Args:
198+
buildkite_token: the secret token to authenticate GraphQL requests.
199+
previously_incomplete: the set of running workflows the last time this
200+
function was called.
201+
"""
202+
203+
running_builds = buildkite_get_incomplete_tasks(buildkite_token)
204+
incomplete_now = set([x["number"] for x in running_builds])
205+
output = []
206+
207+
for build_id in previously_incomplete:
208+
if build_id in incomplete_now:
209+
continue
210+
211+
info = buildkite_get_build_info(build_id)
212+
metric_timestamp = dateutil.parser.isoparse(info["finished_at"])
213+
for job in info["jobs"]:
214+
# This workflow is not interesting to us.
215+
if job["name"] not in BUILDKITE_WORKFLOW_TO_TRACK:
216+
continue
217+
218+
created_at = dateutil.parser.isoparse(job["created_at"])
219+
scheduled_at = (
220+
created_at
221+
if job["scheduled_at"] is None
222+
else dateutil.parser.isoparse(job["scheduled_at"])
223+
)
224+
started_at = (
225+
scheduled_at
226+
if job["started_at"] is None
227+
else dateutil.parser.isoparse(job["started_at"])
228+
)
229+
if job["canceled_at"] is None:
230+
finished_at = (
231+
started_at
232+
if job["finished_at"] is None
233+
else dateutil.parser.isoparse(job["finished_at"])
234+
)
235+
else:
236+
finished_at = dateutil.parser.isoparse(job["canceled_at"])
237+
238+
job_name = BUILDKITE_WORKFLOW_TO_TRACK[job["name"]]
239+
queue_time = (started_at - scheduled_at).seconds
240+
run_time = (finished_at - started_at).seconds
241+
status = bool(job["passed"])
242+
243+
# Grafana will refuse to ingest metrics older than ~2 hours, so we
244+
# should avoid sending historical data.
245+
metric_age_mn = (
246+
datetime.datetime.now(datetime.timezone.utc) - metric_timestamp
247+
).total_seconds() / 60
248+
if metric_age_mn > GRAFANA_METRIC_MAX_AGE_MN:
249+
logging.warning(
250+
f"Job {job['name']} from workflow {build_id} dropped due"
251+
+ f" to staleness: {metric_age_mn}mn old."
252+
)
253+
continue
254+
255+
metric_timestamp_ns = int(metric_timestamp.timestamp()) * 10**9
256+
workflow_id = build_id
257+
workflow_name = "Github pull requests"
258+
output.append(
259+
JobMetrics(
260+
job_name,
261+
queue_time,
262+
run_time,
263+
status,
264+
metric_timestamp_ns,
265+
workflow_id,
266+
workflow_name,
267+
)
268+
)
269+
270+
return output, incomplete_now
271+
73272
def github_get_metrics(
74273
github_repo: github.Repository, last_workflows_seen_as_completed: set[int]
75274
) -> tuple[list[JobMetrics], int]:
@@ -168,8 +367,24 @@ def github_get_metrics(
168367
created_at = job.created_at
169368
started_at = job.started_at
170369
completed_at = job.completed_at
171-
queue_time = started_at - created_at
172-
run_time = completed_at - started_at
370+
371+
# GitHub API can return results where the started_at is slightly
372+
# later then the created_at (or completed earlier than started).
373+
# This would cause a -23h59mn delta, which will show up as +24h
374+
# queue/run time on grafana.
375+
if started_at < created_at:
376+
logging.info(
377+
"Workflow {} started before being created.".format(task.id)
378+
)
379+
queue_time = datetime.timedelta(seconds=0)
380+
else:
381+
queue_time = started_at - created_at
382+
if completed_at < started_at:
383+
logging.info("Workflow {} finished before starting.".format(task.id))
384+
run_time = datetime.timedelta(seconds=0)
385+
else:
386+
run_time = completed_at - started_at
387+
173388
if run_time.seconds == 0:
174389
continue
175390

@@ -179,7 +394,7 @@ def github_get_metrics(
179394
datetime.datetime.now(datetime.timezone.utc) - completed_at
180395
).total_seconds() / 60
181396
if metric_age_mn > GRAFANA_METRIC_MAX_AGE_MN:
182-
logging.info(
397+
logging.warning(
183398
f"Job {job.id} from workflow {task.id} dropped due"
184399
+ f" to staleness: {metric_age_mn}mn old."
185400
)
@@ -276,23 +491,33 @@ def upload_metrics(workflow_metrics, metrics_userid, api_key):
276491
def main():
277492
# Authenticate with Github
278493
github_auth = Auth.Token(os.environ["GITHUB_TOKEN"])
494+
buildkite_token = os.environ["BUILDKITE_TOKEN"]
279495
grafana_api_key = os.environ["GRAFANA_API_KEY"]
280496
grafana_metrics_userid = os.environ["GRAFANA_METRICS_USERID"]
281497

282498
# The last workflow this script processed.
283499
# Because the Github queries are broken, we'll simply log a 'processed'
284500
# bit for the last COUNT_TO_PROCESS workflows.
285501
gh_last_workflows_seen_as_completed = set()
502+
# Stores the list of pending/running builds in BuildKite we need to check
503+
# at the next iteration.
504+
bk_incomplete = set()
286505

287506
# Enter the main loop. Every five minutes we wake up and dump metrics for
288507
# the relevant jobs.
289508
while True:
290509
github_object = Github(auth=github_auth)
291510
github_repo = github_object.get_repo("llvm/llvm-project")
292511

293-
metrics, gh_last_workflows_seen_as_completed = github_get_metrics(
512+
gh_metrics, gh_last_workflows_seen_as_completed = github_get_metrics(
294513
github_repo, gh_last_workflows_seen_as_completed
295514
)
515+
516+
bk_metrics, bk_incomplete = buildkite_get_metrics(
517+
buildkite_token, bk_incomplete
518+
)
519+
520+
metrics = gh_metrics + bk_metrics
296521
upload_metrics(metrics, grafana_metrics_userid, grafana_api_key)
297522
logging.info(f"Uploaded {len(metrics)} metrics")
298523

.ci/metrics/requirements.lock.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,18 @@ pynacl==1.5.0 \
247247
--hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \
248248
--hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543
249249
# via pygithub
250+
python-dateutil==2.9.0.post0 \
251+
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
252+
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
253+
# via -r ./requirements.txt
250254
requests==2.32.3 \
251255
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
252256
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
253257
# via pygithub
258+
six==1.17.0 \
259+
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
260+
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
261+
# via python-dateutil
254262
typing-extensions==4.12.2 \
255263
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
256264
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8

.ci/metrics/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pygithub==2.5.0
2+
python-dateutil==2.9.0.post0

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
fetch-depth: 1
6666
- name: Get subprojects that have doc changes
6767
id: docs-changed-subprojects
68-
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8 # v45.0.7
68+
uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
6969
with:
7070
files_yaml: |
7171
llvm:

.github/workflows/libcxx-build-and-test.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
stage1:
3838
if: github.repository_owner == 'llvm'
3939
runs-on: libcxx-self-hosted-linux
40-
container: ghcr.io/llvm/libcxx-linux-builder:b319dfef21f6c7b0bc6a356d6b9f41a3b3b98ae9
40+
container: ghcr.io/llvm/libcxx-linux-builder:b6bb9dc5abd7c6452c13a53fa8949cb259db459b
4141
continue-on-error: false
4242
strategy:
4343
fail-fast: false
@@ -75,7 +75,7 @@ jobs:
7575
stage2:
7676
if: github.repository_owner == 'llvm'
7777
runs-on: libcxx-self-hosted-linux
78-
container: ghcr.io/llvm/libcxx-linux-builder:b319dfef21f6c7b0bc6a356d6b9f41a3b3b98ae9
78+
container: ghcr.io/llvm/libcxx-linux-builder:b6bb9dc5abd7c6452c13a53fa8949cb259db459b
7979
needs: [ stage1 ]
8080
continue-on-error: false
8181
strategy:
@@ -167,7 +167,7 @@ jobs:
167167
- config: 'generic-msan'
168168
machine: libcxx-self-hosted-linux
169169
runs-on: ${{ matrix.machine }}
170-
container: ghcr.io/llvm/libcxx-linux-builder:b319dfef21f6c7b0bc6a356d6b9f41a3b3b98ae9
170+
container: ghcr.io/llvm/libcxx-linux-builder:b6bb9dc5abd7c6452c13a53fa8949cb259db459b
171171
steps:
172172
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
173173
- name: ${{ matrix.config }}

.github/workflows/pr-code-format.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232

3333
- name: Get changed files
3434
id: changed-files
35-
uses: tj-actions/changed-files@fea790cb660e33aef4bdf07304e28fedd77dfa13 # v39.2.4
35+
uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
3636
with:
3737
separator: ","
3838
skip_initial_fetch: true

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ class BinaryContext {
12951295
void foldFunction(BinaryFunction &ChildBF, BinaryFunction &ParentBF);
12961296

12971297
/// Add a Section relocation at a given \p Address.
1298-
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t Type,
1298+
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint32_t Type,
12991299
uint64_t Addend = 0, uint64_t Value = 0);
13001300

13011301
/// Return a relocation registered at a given \p Address, or nullptr if there
@@ -1308,7 +1308,7 @@ class BinaryContext {
13081308
}
13091309

13101310
/// Register dynamic relocation at \p Address.
1311-
void addDynamicRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t Type,
1311+
void addDynamicRelocation(uint64_t Address, MCSymbol *Symbol, uint32_t Type,
13121312
uint64_t Addend, uint64_t Value = 0);
13131313

13141314
/// Return a dynamic relocation registered at a given \p Address, or nullptr

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ class BinaryFunction {
12601260
/// Register relocation type \p RelType at a given \p Address in the function
12611261
/// against \p Symbol.
12621262
/// Assert if the \p Address is not inside this function.
1263-
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t RelType,
1263+
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint32_t RelType,
12641264
uint64_t Addend, uint64_t Value);
12651265

12661266
/// Return the name of the section this function originated from.

0 commit comments

Comments
 (0)