From 317af12003ec072ae17fae272a701f2b901e624a Mon Sep 17 00:00:00 2001 From: Will Dean Date: Fri, 13 Dec 2024 16:49:04 +0100 Subject: [PATCH 1/7] copy from pymc-marketing --- .github/workflows/slow-tests-issue.yml | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/slow-tests-issue.yml diff --git a/.github/workflows/slow-tests-issue.yml b/.github/workflows/slow-tests-issue.yml new file mode 100644 index 0000000000..bcd29519ff --- /dev/null +++ b/.github/workflows/slow-tests-issue.yml @@ -0,0 +1,30 @@ +# Taken from https://github.com/pymc-labs/pymc-marketing/tree/main/.github/workflows/slow-tests-issue.yml +--- +name: Slow Tests Issue Body + +on: + workflow_dispatch: + schedule: + - cron: '0 */6 * * *' + +permissions: + issues: write + +jobs: + update-comment: + runs-on: ubuntu-latest + steps: + - name: Install ZSH + run: sudo apt-get update && sudo apt-get install -y zsh + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Trigger the script + working-directory: scripts/slowest_tests + shell: zsh {0} + run: source update-slowest-times-issue.sh + env: + GITHUB_TOKEN: ${{ github.token }} From 6fbfac8dc22c8360b7aba59228d9f31e662ef83f Mon Sep 17 00:00:00 2001 From: Will Dean Date: Fri, 13 Dec 2024 16:50:15 +0100 Subject: [PATCH 2/7] add comment to run pre-commit --- .github/workflows/slow-tests-issue.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/slow-tests-issue.yml b/.github/workflows/slow-tests-issue.yml index bcd29519ff..643853f617 100644 --- a/.github/workflows/slow-tests-issue.yml +++ b/.github/workflows/slow-tests-issue.yml @@ -1,4 +1,5 @@ # Taken from https://github.com/pymc-labs/pymc-marketing/tree/main/.github/workflows/slow-tests-issue.yml +# See the scripts in the `scripts/slowest_tests` directory for more information --- name: Slow Tests Issue Body From 2abb7668269e04088844c9a96bc1f0d65bbc47f7 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Fri, 13 Dec 2024 17:18:27 +0100 Subject: [PATCH 3/7] add scripts --- scripts/slowest_tests/extract-slow-tests.py | 80 +++++++++++++++++++ .../update-slowest-times-issue.sh | 62 ++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 scripts/slowest_tests/extract-slow-tests.py create mode 100644 scripts/slowest_tests/update-slowest-times-issue.sh diff --git a/scripts/slowest_tests/extract-slow-tests.py b/scripts/slowest_tests/extract-slow-tests.py new file mode 100644 index 0000000000..3a06e4a68b --- /dev/null +++ b/scripts/slowest_tests/extract-slow-tests.py @@ -0,0 +1,80 @@ +"""This script parses the GitHub action log for test times. + +Taken from https://github.com/pymc-labs/pymc-marketing/tree/main/scripts/slowest_tests/extract-slow-tests.py + +""" + +import re +import sys +from pathlib import Path + + +start_pattern = re.compile(r"==== slow") +separator_pattern = re.compile(r"====") +time_pattern = re.compile(r"(\d+\.\d+)s ") + + +def extract_lines(lines: list[str]) -> list[str]: + times = [] + + in_section = False + for line in lines: + detect_start = start_pattern.search(line) + detect_end = separator_pattern.search(line) + + if detect_start: + in_section = True + + if in_section: + times.append(line) + + if not detect_start and in_section and detect_end: + break + + return times + + +def trim_up_to_match(pattern, string: str) -> str: + match = pattern.search(string) + if not match: + return "" + + return string[match.start() :] + + +def trim(pattern, lines: list[str]) -> list[str]: + return [trim_up_to_match(pattern, line) for line in lines] + + +def strip_ansi(text: str) -> str: + ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") + return ansi_escape.sub("", text) + + +def format_times(times: list[str]) -> list[str]: + return ( + trim(separator_pattern, times[:1]) + + trim(time_pattern, times[1:-1]) + + [strip_ansi(line) for line in trim(separator_pattern, times[-1:])] + ) + + +def read_lines_from_stdin(): + return sys.stdin.read().splitlines() + + +def read_from_file(file: Path): + """For testing purposes.""" + return file.read_text().splitlines() + + +def main(read_lines): + lines = read_lines() + times = extract_lines(lines) + parsed_times = format_times(times) + print("\n".join(parsed_times)) + + +if __name__ == "__main__": + read_lines = read_lines_from_stdin + main(read_lines) diff --git a/scripts/slowest_tests/update-slowest-times-issue.sh b/scripts/slowest_tests/update-slowest-times-issue.sh new file mode 100644 index 0000000000..6227dae48f --- /dev/null +++ b/scripts/slowest_tests/update-slowest-times-issue.sh @@ -0,0 +1,62 @@ +#!/bin/zsh + +DRY_RUN=false + +owner=pymc-devs +repo=pytensor +issue_number=1124 +title="Speed up test times :rocket:" +workflow=Tests +latest_id=$(gh run list --workflow $workflow --status success --limit 1 --json databaseId --jq '.[0].databaseId') +jobs=$(gh api /repos/$owner/$repo/actions/runs/$latest_id/jobs --jq '.jobs | map({name: .name, run_id: .run_id, id: .id})') + +all_times="" +echo "$jobs" | jq -c '.[]' | while read -r job; do + id=$(echo $job | jq -r '.id') + name=$(echo $job | jq -r '.name') + run_id=$(echo $job | jq -r '.run_id') + + echo "Processing job: $name (ID: $id, Run ID: $run_id)" + times=$(gh run view --job $id --log | python extract-slow-tests.py) + + if [ -z "$times" ]; then + # Some of the jobs are non-test jobs, so we skip them + continue + fi + + echo $times + + top="
$name\n\n\n\`\`\`" + bottom="\`\`\`\n\n
" + + formatted_times="$top\n$times\n$bottom" + + if [ -n "$all_times" ]; then + all_times="$all_times\n$formatted_times" + else + all_times="$formatted_times" + fi +done + +run_date=$(date +"%Y-%m-%d") +body=$(cat << EOF +If you are motivated to help speed up some tests, we would appreciate it! + +Here are some of the slowest test times: + +$all_times + +You can find more information on how to contribute [here](https://pytensor.readthedocs.io/en/latest/dev_start_guide.html) + +Automatically generated by [GitHub Action](https://github.com/pymc-devs/pytensor/blob/main/.github/workflows/slow-tests-issue.yml) +Latest run date: $run_date +EOF +) + +if [ "$DRY_RUN" = true ]; then + echo "Dry run, not updating issue" + echo $body + exit +fi +echo $body | gh issue edit $issue_number --body-file - --title "$title" +echo "Updated issue $issue_number with all times" From bac6795edeaf02ec75c50722cd71ebad99d4ba11 Mon Sep 17 00:00:00 2001 From: Will Dean Date: Fri, 13 Dec 2024 18:13:24 +0100 Subject: [PATCH 4/7] add filter condition --- .../update-slowest-times-issue.sh | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/slowest_tests/update-slowest-times-issue.sh b/scripts/slowest_tests/update-slowest-times-issue.sh index 6227dae48f..897bbca3ca 100644 --- a/scripts/slowest_tests/update-slowest-times-issue.sh +++ b/scripts/slowest_tests/update-slowest-times-issue.sh @@ -10,17 +10,41 @@ workflow=Tests latest_id=$(gh run list --workflow $workflow --status success --limit 1 --json databaseId --jq '.[0].databaseId') jobs=$(gh api /repos/$owner/$repo/actions/runs/$latest_id/jobs --jq '.jobs | map({name: .name, run_id: .run_id, id: .id})') +# Skip 3.10, float32, and Benchmark tests +function skip_job() { + name=$1 + if [[ $name == *"py3.10"* ]]; then + return 0 + fi + + if [[ $name == *"float32 1"* ]]; then + return 0 + fi + + if [[ $name == *"Benchmark"* ]]; then + return 0 + fi + + return 1 +} + all_times="" echo "$jobs" | jq -c '.[]' | while read -r job; do id=$(echo $job | jq -r '.id') name=$(echo $job | jq -r '.name') run_id=$(echo $job | jq -r '.run_id') + if skip_job $name; then + echo "Skipping $name" + continue + fi + echo "Processing job: $name (ID: $id, Run ID: $run_id)" times=$(gh run view --job $id --log | python extract-slow-tests.py) if [ -z "$times" ]; then # Some of the jobs are non-test jobs, so we skip them + echo "No tests found for '$name', skipping" continue fi From a5895c7653a8274acc45003ca987b783a8a208ec Mon Sep 17 00:00:00 2001 From: Will Dean Date: Fri, 13 Dec 2024 18:35:25 +0100 Subject: [PATCH 5/7] remove the prefix --- scripts/slowest_tests/update-slowest-times-issue.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/slowest_tests/update-slowest-times-issue.sh b/scripts/slowest_tests/update-slowest-times-issue.sh index 897bbca3ca..d2f69ed9c6 100644 --- a/scripts/slowest_tests/update-slowest-times-issue.sh +++ b/scripts/slowest_tests/update-slowest-times-issue.sh @@ -28,6 +28,12 @@ function skip_job() { return 1 } +# Remove common prefix from the name +function remove_prefix() { + name=$1 + echo $name | sed -e 's/^ubuntu-latest test py3.12 : fast-compile 0 : float32 0 : //' +} + all_times="" echo "$jobs" | jq -c '.[]' | while read -r job; do id=$(echo $job | jq -r '.id') @@ -50,6 +56,8 @@ echo "$jobs" | jq -c '.[]' | while read -r job; do echo $times + name=$(remove_prefix $name) + top="
$name\n\n\n\`\`\`" bottom="\`\`\`\n\n
" From 88d487669a90715700ee0fe9c3d413cb35960b6c Mon Sep 17 00:00:00 2001 From: Will Dean Date: Sat, 14 Dec 2024 06:15:42 +0100 Subject: [PATCH 6/7] add human readable time difference --- .../update-slowest-times-issue.sh | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/scripts/slowest_tests/update-slowest-times-issue.sh b/scripts/slowest_tests/update-slowest-times-issue.sh index d2f69ed9c6..6e3daf5128 100644 --- a/scripts/slowest_tests/update-slowest-times-issue.sh +++ b/scripts/slowest_tests/update-slowest-times-issue.sh @@ -8,7 +8,7 @@ issue_number=1124 title="Speed up test times :rocket:" workflow=Tests latest_id=$(gh run list --workflow $workflow --status success --limit 1 --json databaseId --jq '.[0].databaseId') -jobs=$(gh api /repos/$owner/$repo/actions/runs/$latest_id/jobs --jq '.jobs | map({name: .name, run_id: .run_id, id: .id})') +jobs=$(gh api /repos/$owner/$repo/actions/runs/$latest_id/jobs --jq '.jobs | map({name: .name, run_id: .run_id, id: .id, started_at: .started_at, completed_at: .completed_at})') # Skip 3.10, float32, and Benchmark tests function skip_job() { @@ -34,11 +34,31 @@ function remove_prefix() { echo $name | sed -e 's/^ubuntu-latest test py3.12 : fast-compile 0 : float32 0 : //' } +function human_readable_time() { + started_at=$1 + completed_at=$2 + + start_seconds=$(date -d "$started_at" +%s) + end_seconds=$(date -d "$completed_at" +%s) + + seconds=$(($end_seconds - $start_seconds)) + + if [ $seconds -lt 60 ]; then + echo "$seconds seconds" + else + echo "$(date -u -d @$seconds +'%-M minutes %-S seconds')" + fi +} + all_times="" echo "$jobs" | jq -c '.[]' | while read -r job; do id=$(echo $job | jq -r '.id') name=$(echo $job | jq -r '.name') run_id=$(echo $job | jq -r '.run_id') + started_at=$(echo $job | jq -r '.started_at') + completed_at=$(echo $job | jq -r '.completed_at') + + human_readable=$(human_readable_time $started_at $completed_at) if skip_job $name; then echo "Skipping $name" @@ -56,9 +76,13 @@ echo "$jobs" | jq -c '.[]' | while read -r job; do echo $times + human_readable=$(human_readable_time $started_at $completed_at) + + echo $human_readable + name=$(remove_prefix $name) - top="
$name\n\n\n\`\`\`" + top="
($human_readable) $name\n\n\n\`\`\`" bottom="\`\`\`\n\n
" formatted_times="$top\n$times\n$bottom" From cb4dcec0a36b7cd7a0128f21cb7e7b3b5424923f Mon Sep 17 00:00:00 2001 From: Will Dean Date: Sat, 14 Dec 2024 06:33:41 +0100 Subject: [PATCH 7/7] remove duplication --- scripts/slowest_tests/update-slowest-times-issue.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/slowest_tests/update-slowest-times-issue.sh b/scripts/slowest_tests/update-slowest-times-issue.sh index 6e3daf5128..b1c0c15789 100644 --- a/scripts/slowest_tests/update-slowest-times-issue.sh +++ b/scripts/slowest_tests/update-slowest-times-issue.sh @@ -58,8 +58,6 @@ echo "$jobs" | jq -c '.[]' | while read -r job; do started_at=$(echo $job | jq -r '.started_at') completed_at=$(echo $job | jq -r '.completed_at') - human_readable=$(human_readable_time $started_at $completed_at) - if skip_job $name; then echo "Skipping $name" continue @@ -77,9 +75,6 @@ echo "$jobs" | jq -c '.[]' | while read -r job; do echo $times human_readable=$(human_readable_time $started_at $completed_at) - - echo $human_readable - name=$(remove_prefix $name) top="
($human_readable) $name\n\n\n\`\`\`"