Add Theory of Change Framework preprint #1428
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Runs a pyinstrument profiling session on the scale_run profiling model, | |
# capturing the profiling result and sending it to the TLOmodel-profiling | |
# repository for processing and display. | |
# | |
# Profiling script executed is src/scripts/profiling/run-profiling.py. | |
# Output is the .pyisession file from the profiler, placed into results/ | |
# results/ folder is then pushed to the TLOmodel-profiling repo, results branch. | |
name: Run profiling | |
on: | |
workflow_dispatch: | |
# Allow profiling to be triggered by comments on pull requests | |
# Trigger is /run profiling | |
issue_comment: | |
types: | |
- created | |
# Profile the model every Saturday at 00:00, | |
# on the HEAD of master | |
schedule: | |
- cron: 0 0 * * 6 | |
concurrency: | |
# Prevent multiple profiling runs from happening on the same | |
# commit simultaneously. | |
# This ensures we don't overwrite the artifact to be uploaded | |
# with another run that uses the same name, before the results | |
# can be processed. | |
group: profiling-${{ github.workflow }}-${{ github.ref }} | |
jobs: | |
set-variables: | |
name: Create unique output file identifier and artifact name | |
runs-on: ubuntu-latest | |
if: (github.event_name != 'issue_comment') || ((github.event_name == 'issue_comment') && (github.event.comment.body == '/run profiling')) | |
outputs: | |
profiling-output-dir: profiling_results/ | |
profiling-filename: ${{ steps.set-profiling-filename.outputs.name }} | |
artifact-name: ${{ steps.set-artifact-name.outputs.name }} | |
profiling-on-sha: ${{ steps.determine-correct-sha.outputs.result }} | |
profiling-event-trigger: ${{ steps.set-github-info.outputs.event }} | |
steps: | |
- id: determine-if-pr-comment | |
name: Determine if this is a PR comment | |
run: | | |
if ! [ -z "${{ github.event.issue.pull_request }}" ]; then echo "is-pr=true" >> "${GITHUB_OUTPUT}"; else echo "is-pr=false" >> "${GITHUB_OUTPUT}"; fi | |
- id: determine-correct-sha | |
name: Determine the SHA to run profiling on | |
uses: actions/github-script@v7 | |
with: | |
result-encoding: string | |
script: | | |
if ("${{ steps.determine-if-pr-comment.outputs.is-pr }}" === "true") { | |
const { data: pr } = await github.rest.pulls.get({ | |
owner: context.issue.owner, | |
repo: context.issue.repo, | |
pull_number: context.issue.number, | |
}); | |
return pr.head.sha; | |
}; | |
return context.sha; | |
- id: set-profiling-filename | |
name: Set profiling output file name | |
run: | | |
echo "name=${GITHUB_EVENT_NAME}_${GITHUB_RUN_NUMBER}_${{ steps.determine-correct-sha.outputs.result }}" >> "${GITHUB_OUTPUT}" | |
- id: set-artifact-name | |
name: Set artifact name | |
run: | | |
echo "name=profiling_results_${GITHUB_RUN_NUMBER}" >> "${GITHUB_OUTPUT}" | |
- id: set-github-info | |
name: Fix Git and GitHub information when passing between workflows | |
run: | | |
echo "sha=${{ steps.determine-correct-sha.outputs.result }}" >> "${GITHUB_OUTPUT}" | |
echo "event=${GITHUB_EVENT_NAME}" >> "${GITHUB_OUTPUT}" | |
profile-on-comment: | |
name: Comment triggered profiling | |
if: github.event_name == 'issue_comment' | |
needs: set-variables | |
uses: ./.github/workflows/run-on-comment.yml | |
with: | |
runs-on: '["self-hosted", "profiling"]' | |
keyword: profiling | |
commands: | | |
tox -vv -e profile -- \ | |
--html \ | |
--flat-html \ | |
--root-output-dir ${{ needs.set-variables.outputs.profiling-output-dir }} \ | |
--output-name ${{ needs.set-variables.outputs.profiling-filename }} \ | |
--additional-stats \ | |
sha=${{ needs.set-variables.outputs.profiling-on-sha }} \ | |
trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} \ | |
--disable-log-output-to-stdout | |
description: Profiled run of the model | |
timeout-minutes: 8640 | |
application-organization: UCL | |
artifact-path: ${{ needs.set-variables.outputs.profiling-output-dir }} | |
artifact-name: ${{ needs.set-variables.outputs.artifact-name }} | |
artifact-retention-days: 1 | |
secrets: | |
application-id: ${{ secrets.COMMENT_BOT_APP_ID }} | |
application-private-key: ${{ secrets.COMMENT_BOT_APP_PRIVATE_KEY }} | |
profile-on-dispatch: | |
name: Scheduled / dispatch triggered profiling | |
if: ${{ github.event_name != 'issue_comment' }} | |
needs: set-variables | |
runs-on: [self-hosted, profiling] | |
timeout-minutes: 8640 | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.sha }} | |
lfs: true | |
## The profile environment produces outputs in the /results directory | |
- name: Run profiling in dev environment | |
run: | | |
tox -vv -e profile -- \ | |
--html \ | |
--flat-html \ | |
--root-output-dir ${{ needs.set-variables.outputs.profiling-output-dir }} \ | |
--output-name ${{ needs.set-variables.outputs.profiling-filename }} \ | |
--additional-stats \ | |
sha=${{ needs.set-variables.outputs.profiling-on-sha }} \ | |
trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} \ | |
--disable-log-output-to-stdout | |
## Upload the output as an artifact so we can push it to the profiling repository | |
- name: Save results as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ${{ needs.set-variables.outputs.artifact-name }} | |
path: ${{ needs.set-variables.outputs.profiling-output-dir }} | |
retention-days: 1 | |
upload-profiling-results: | |
name: Upload profiling results | |
# Run on GH runners to free up self-hosted machines; | |
# because we need Docker for the workflow call below, | |
# and because we're now just pushing results files to another repo | |
runs-on: ubuntu-latest | |
# Only run this step if exactly one of the previous two jobs ran successfully | |
# see https://stackoverflow.com/a/68952093 for more details | |
# NOTE: We need to explicitly depend on set-variables to access the artifact name | |
needs: [set-variables, profile-on-comment, profile-on-dispatch] | |
if: | | |
always() && ( | |
(needs.profile-on-comment.result == 'success' && needs.profile-on-dispatch.result == 'skipped') || | |
(needs.profile-on-comment.result == 'skipped' && needs.profile-on-dispatch.result == 'success') | |
) | |
steps: | |
- name: Download the profiling results | |
uses: actions/download-artifact@v4 | |
with: | |
name: ${{ needs.set-variables.outputs.artifact-name }} | |
path: ${{ needs.set-variables.outputs.profiling-output-dir }} | |
## The token provided needs contents and pages access to the target repo | |
## Token can be (re)generated by a member of the UCL organisation, | |
## the current member is the rc-softdev-admin. | |
## [17-07-2024] New token generated, will expire 10-07-2025 | |
- name: Push results to profiling repository | |
uses: dmnemec/copy_file_to_another_repo_action@v1.1.1 | |
env: | |
API_TOKEN_GITHUB: ${{ secrets.PROFILING_REPO_ACCESS }} | |
with: | |
source_file: ${{ needs.set-variables.outputs.profiling-output-dir }} | |
destination_repo: UCL/TLOmodel-profiling | |
destination_folder: . | |
destination_branch: results | |
user_email: rsd-notifications@ucl.ac.uk | |
user_name: rc-softdev-admin | |
- name: Trigger website rebuild | |
uses: peter-evans/repository-dispatch@v3 | |
with: | |
token: ${{ secrets.PROFILING_REPO_ACCESS }} | |
repository: UCL/TLOmodel-profiling | |
event-type: new-profiling-results |