// This file is for internal AMD use.
// If you are interested in running your own Jenkins, please raise a github issue for assistance.
@NonCPS
def getPrComments(pullRequest) {
ArrayList comments = pullRequest.comments.toList()
return comments
}
def truncateLongResults(results, maxLength = 60000) {
def truncatedMessage = "\n```\n\n**Results truncated, see full report in workspace**"
if (results.length() > maxLength) {
def truncateIndex = results.lastIndexOf('\n', maxLength)
return results.substring(0, truncateIndex) + truncatedMessage
}
return results
}
def withSSH(platform, pipeline) {
withCredentials(
[
sshUserPrivateKey(credentialsId:"github-rocmmathlibrariesbot-ssh_key-mathci_enterprise_job", keyFileVariable:"PUBLIC_KEY_FILE"),
sshUserPrivateKey(credentialsId:"github_enterprise-a1_mlselibci_npi-ssh_key-mathci_enterprise_job", keyFileVariable: "ENTERPRISE_KEY_FILE"),
]
)
{
configFileProvider(
[configFile(fileId: 'github-enterprise-known-hosts', variable: 'ENTERPRISE_KNOWN_HOSTS'),
configFile(fileId: 'github-enterprise-ssh-config', variable: 'ENTERPRISE_SSH_CONFIG')])
{
def sshBlock = """
mkdir -p ~/.ssh/
cat ${ENTERPRISE_KNOWN_HOSTS} >> ~/.ssh/known_hosts
eval `ssh-agent -s`
ssh-add ${PUBLIC_KEY_FILE}
ssh-add ${ENTERPRISE_KEY_FILE}
ssh-add -L
cat ${ENTERPRISE_SSH_CONFIG} >> ~/.ssh/config
"""
pipeline(sshBlock)
}
}
}
def runCompileCommand(platform, project, jobName, boolean codeCoverage=false, boolean enableTimers=false, String target='', boolean useYamlCpp=true, boolean staticAnalysis=false)
{
project.paths.construct_build_prefix()
String codeCovFlag = codeCoverage ? '-DROCROLLER_ENABLE_COVERAGE=ON -DROCROLLER_BUILD_SHARED_LIBS=OFF' : ''
String timerFlag = enableTimers ? '-DROCROLLER_ENABLE_TIMERS=ON' : ''
String yamlBackendFlag = useYamlCpp ? '' : '-DROCROLLER_ENABLE_YAML_CPP=OFF'
String useCppCheck = staticAnalysis ? '-DROCROLLER_ENABLE_CPPCHECK=ON' : ''
withSSH(platform) {
sshBlock ->
def command = """#!/usr/bin/env bash
set -ex
cd ${project.paths.project_build_prefix}
${sshBlock}
mkdir -p build
cd build
# Check that all tests are included.
../scripts/check_included_tests.py
# Detect pytest installation location
echo "Detecting pytest installation..."
PYTEST_PATH=""
if command -v pytest &>/dev/null; then
echo "pytest found at: \$(which pytest)"
PYTEST_PREFIX=\$(python3 -c "import sys; print(sys.prefix)")
echo "Python prefix: \$PYTEST_PREFIX"
PYTEST_PATH=";\$PYTEST_PREFIX"
elif python3 -c "import pytest" &>/dev/null; then
echo "pytest found as Python module"
PYTEST_PREFIX=\$(python3 -c "import sys; print(sys.prefix)")
echo "Python prefix: \$PYTEST_PREFIX"
PYTEST_PATH=";\$PYTEST_PREFIX"
else
echo "Warning: pytest not found, searching filesystem..."
echo "Running: find /usr /opt /home -name 'pytest' -type f 2>/dev/null | head -5"
find /usr /opt /home -name 'pytest' -type f 2>/dev/null | head -5 || echo "No pytest found via system search"
echo "Running: find /usr -name '*pytest*' -type d 2>/dev/null | head -5"
find /usr -name '*pytest*' -type d 2>/dev/null | head -5 || echo "No pytest directories found"
fi
cmake ../ \\
${codeCovFlag} ${timerFlag} ${yamlBackendFlag} ${useCppCheck}\\
-DCMAKE_CXX_COMPILER=/opt/rocm/bin/amdclang++ \\
-DCMAKE_BUILD_TYPE=Release \\
-DROCROLLER_ENABLE_FETCH=ON \\
-DCMAKE_PREFIX_PATH="/opt/rocm;/opt/rocm/llvm\$PYTEST_PATH"
ccache --print-stats
make -j ${target}
ccache --print-stats
"""
platform.runCommand(this, command)
}
}
def runTestCommand (platform, project)
{
def command = """#!/usr/bin/env bash
set -ex
cd ${project.paths.project_build_prefix}
# Run sharded tests (auto-detects ncores/2, respecting cgroups)
scripts/run-tests-sharded precheckin-mci build
"""
try
{
platform.runCommand(this, command)
}
finally
{
junit "${project.paths.project_build_prefix}/build/test_report/**/*.xml"
}
}
def runCodeCovTestCommand(platform, project)
{
String masterURL = env.CHANGE_ID ? env.JOB_URL.replace("PR-${env.CHANGE_ID}", env.CHANGE_TARGET) : env.JOB_URL
def compareCommand = """#!/usr/bin/env bash
set -ex
bash `pwd`/${project.paths.project_build_prefix}/scripts/codecov \\
-g ${platform.gpu} \\
-b `pwd`/${project.paths.project_build_prefix}/build \\
-u ${masterURL}/lastSuccessfulBuild/artifact/*zip*/archive.zip
"""
platform.runCommand(this, compareCommand)
platform.archiveArtifacts(this, "${project.paths.project_build_prefix}/build/code_cov_${platform.gpu}.*")
publishHTML([allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: false,
reportDir: "${project.paths.project_build_prefix}/build/",
reportFiles: "code_cov_${platform.gpu}_html/index.html,code_cov_diff_${platform.gpu}.html",
reportName: "Code coverage ${platform.gpu} report",
reportTitles: "Report,Diff"])
publishHTML([allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: false,
reportDir: "${project.paths.project_build_prefix}/python_cov_html/",
reportFiles: "index.html",
reportName: "Python Code coverage ${platform.gpu} report",
reportTitles: "Report"])
if (env.CHANGE_ID)
{
def commentString = "# Code Coverage Report for ${platform.gpu}\n\n"
def results = readFile("${project.paths.project_src_prefix}/build/code_cov_${platform.gpu}.formatted")
def new_uncovered_lines = readFile("${project.paths.project_src_prefix}/build/new_uncovered_lines.txt").trim()
commentString += "## Summary\n\n"
commentString += "${results}\n\n"
if ("${new_uncovered_lines}" != "0")
{
commentString += "**This PR adds/edits _${new_uncovered_lines}_ newly uncovered lines.**\n\n"
}
commentString += "## Artifacts\n\n"
commentString += "* [HTML Coverage Report and Diff](${JOB_URL}/Code_20coverage_20${platform.gpu}_20report) \n"
commentString += "* [File Coverage Summary](${JOB_URL}/lastSuccessfulBuild/artifact/${project.paths.src_prefix}/rocroller/shared/rocroller/build/code_cov_${platform.gpu}.report/*view*/) \n"
commentString += "* [Diff Text File](${JOB_URL}/lastSuccessfulBuild/artifact/${project.paths.src_prefix}/rocroller/shared/rocroller/build/code_cov_${platform.gpu}.diff/*view*/) \n"
commentString += "* [Full Text Coverage Report](${JOB_URL}/lastSuccessfulBuild/artifact/${project.paths.src_prefix}/rocroller/shared/rocroller/build/code_cov_${platform.gpu}.zip) \n"
commentString += "* [Python Coverage Report](${JOB_URL}/Python_20Code_20coverage_20${platform.gpu}_20report) \n"
commentString += "\n"
commentString += "## Commit Hashes\n\n"
for(parentHash in project.gitParentHashes) {
commentString += "* ${parentHash} \n"
}
boolean commentExists = false
for (prComment in getPrComments(pullRequest)) {
if (prComment.body.contains("# Code Coverage Report for ${platform.gpu}"))
{
commentExists = true
prComment.body = commentString
}
}
if (!commentExists) {
def comment = pullRequest.comment(commentString)
}
}
}
def runBuildDocsCommand(platform, project)
{
project.paths.construct_build_prefix()
withSSH(platform) {
sshBlock ->
def command = """#!/usr/bin/env bash
set -ex
cd ${project.paths.project_build_prefix}
${sshBlock}
# Detect pytest installation location
echo "Detecting pytest installation..."
PYTEST_PATH=""
if command -v pytest &>/dev/null; then
echo "pytest found at: \$(which pytest)"
PYTEST_PREFIX=\$(python3 -c "import sys; print(sys.prefix)")
echo "Python prefix: \$PYTEST_PREFIX"
PYTEST_PATH=";\$PYTEST_PREFIX"
elif python3 -c "import pytest" &>/dev/null; then
echo "pytest found as Python module"
PYTEST_PREFIX=\$(python3 -c "import sys; print(sys.prefix)")
echo "Python prefix: \$PYTEST_PREFIX"
PYTEST_PATH=";\$PYTEST_PREFIX"
else
echo "Warning: pytest not found, searching filesystem..."
echo "Running: find /usr /opt /home -name 'pytest' -type f 2>/dev/null | head -5"
find /usr /opt /home -name 'pytest' -type f 2>/dev/null | head -5 || echo "No pytest found via system search"
echo "Running: find /usr -name '*pytest*' -type d 2>/dev/null | head -5"
find /usr -name '*pytest*' -type d 2>/dev/null | head -5 || echo "No pytest directories found"
fi
cmake --preset docs -B build -S . -DCMAKE_PREFIX_PATH="/opt/rocm;/opt/rocm/llvm\$PYTEST_PATH"
cmake --build build --target docs
"""
platform.runCommand(this, command)
}
publishHTML([allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: false,
reportDir: "${project.paths.project_build_prefix}/docs/build/sphinx/html/",
reportFiles: "index.html",
reportName: "Generated Docs",
reportTitles: "Docs"])
if (env.CHANGE_ID)
{
def commentTitle = "# Generated Documentation"
def commentString = "${commentTitle}\n\n"
commentString += "* [Link to view Generated Docs.](${JOB_URL}/Generated_20Docs) \n\n"
boolean commentExists = false
for (prComment in getPrComments(pullRequest)) {
if (prComment.body.contains(commentTitle))
{
commentExists = true
prComment.body = commentString
}
}
if (!commentExists) {
def comment = pullRequest.comment(commentString)
}
}
}
def runPerformanceCommand (platform, project)
{
String masterURL = env.CHANGE_ID ? env.JOB_URL.replace("PR-${env.CHANGE_ID}", env.CHANGE_TARGET) : env.JOB_URL
withSSH(platform){
sshBlock ->
def rrperfSuite = platform.jenkinsLabel.contains('gfx12') ? "all_gfx120X" : "all"
if (env.CHANGE_ID)
{
// either a label or a parameter can block comparison to master branch
def masterCompare = !(
pullRequest.labels.any { it == "ci:no-build-master" || it == "ci:no-build-target" }
)
if (masterCompare && (params?."Build target branch for comparison" != null))
{
masterCompare = params."Build target branch for comparison"
}
String masterCompareCommand
if (masterCompare)
{
masterCompareCommand = """
./scripts/rrperf autoperf \\
--suite ${rrperfSuite} \\
--clonedir "./performance_build_${platform.gpu}" \\
--rundir "./performance_${platform.gpu}" \\
--plot_median --normalize \\
--x_value "commit" \\
--no-fail=remotes/origin/${env.CHANGE_TARGET} \\
"remotes/origin/${env.CHANGE_TARGET}"
mv ./performance_build_${platform.gpu}/**/comparison*.html \\
performance_comparison_${platform.gpu}.html
./scripts/rrperf compare \\
\$(ls -trd ./performance_build_${platform.gpu}/performance_${platform.gpu}/*) \\
> performance_comparison_${platform.gpu}.md
./scripts/rrperf compare --format resource_md \\
\$(ls -trd ./performance_build_${platform.gpu}/performance_${platform.gpu}/*) \\
> resource_comparison_${platform.gpu}.md
"""
}
else
{
masterCompareCommand = """
mkdir -p performance_build_${platform.gpu}
./scripts/rrperf autoperf \\
--suite ${rrperfSuite} \\
--rundir "./performance_build_${platform.gpu}/performance_${platform.gpu}"
cat ./performance_build_${platform.gpu}/performance_${platform.gpu}/**/*.log >> performance_${platform.gpu}_logs.txt
#Get Master Results
ARTIFACT_URL_PREFIX="${masterURL}/lastSuccessfulBuild/artifact"
if wget \${ARTIFACT_URL_PREFIX}/*zip*/archive.zip; then
unzip archive.zip
else
echo "WARNING: No lastSuccessfulBuild found at \${ARTIFACT_URL_PREFIX}"
fi
if [ -f archive/*/*/performance_${platform.gpu}_last.zip ]; then
#Unzip last run's results
mv archive/*/*/performance_${platform.gpu}_last.zip ./performance_${platform.gpu}_master.zip
unzip performance_${platform.gpu}_master.zip -d ./performance_${platform.gpu}_master
# Clean up zip files and extracted contents
rm -rf archive.zip archive performance_${platform.gpu}_master.zip
#Compare Results to Master
./scripts/rrperf compare \\
--plot_median --normalize \\
--x_value "commit" \\
--format "html" \\
./performance_${platform.gpu}_master/performance_${platform.gpu}/* \\
./performance_build_${platform.gpu}/performance_${platform.gpu}/* \\
> performance_comparison_${platform.gpu}.html
./scripts/rrperf compare \\
./performance_${platform.gpu}_master/performance_${platform.gpu}/* \\
./performance_build_${platform.gpu}/performance_${platform.gpu}/* \\
> performance_comparison_${platform.gpu}.md
./scripts/rrperf compare --format resource_md \\
./performance_${platform.gpu}_master/performance_${platform.gpu}/* \\
./performance_build_${platform.gpu}/performance_${platform.gpu}/* \\
> resource_comparison_${platform.gpu}.md
else
touch performance_comparison_${platform.gpu}.html
touch performance_comparison_${platform.gpu}.md
touch resource_comparison_${platform.gpu}.md
echo "Skipped ${env.CHANGE_TARGET} compare for ${platform.gpu}, no archived performance_${platform.gpu}_last.zip found."
fi
"""
}
def command = """#!/usr/bin/env bash
set -ex
cd ${project.paths.project_build_prefix}/
${sshBlock}
#Run Performance Test
export LD_LIBRARY_PATH="\${LD_LIBRARY_PATH}:${project.paths.project_build_prefix}/build/"
export ROCROLLER_BUILD_DIR="\$(pwd)/build"
${masterCompareCommand}
#Zip archive
zip -r performance_${platform.gpu}_archive.zip \\
"./performance_build_${platform.gpu}/performance_${platform.gpu}"
# boost has files with UTF-8 characters that cannot be parsed by the HTML publisher
rm -rf build/_deps
rm -rf performance_build*/**/**/_deps
"""
platform.runCommand(this, command)
platform.archiveArtifacts(this, "${project.paths.project_build_prefix}/performance_${platform.gpu}_archive.zip")
publishHTML([allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: false,
reportDir: "${project.paths.project_build_prefix}/",
reportFiles: "performance_comparison_${platform.gpu}.html",
reportName: "Performance Report for ${platform.gpu}",
reportTitles: "Report"])
def perfCommentTitle = "# Performance Report for ${platform.gpu}"
def perfCommentString = "${perfCommentTitle}\n\n"
def perfResults = readFile("${project.paths.project_build_prefix}/performance_comparison_${platform.gpu}.md").trim()
perfResults = truncateLongResults(perfResults)
def estimateString = masterCompare ? "" : " (estimated due to skipped ${env.CHANGE_TARGET} build)"
perfCommentString += "## Results${estimateString}\n\n"
perfCommentString += "Links
\n\n"
perfCommentString += "* [HTML Report](${JOB_URL}/Performance_20Report_20for_20${platform.gpu}) \n"
perfCommentString += "* [Job Link](${env.BUILD_URL}) \n"
perfCommentString += "* [Result Archive](${JOB_URL}/lastSuccessfulBuild/artifact/${project.paths.src_prefix}/rocroller/shared/rocroller/performance_${platform.gpu}_archive.zip) \n"
perfCommentString += "Links
\n\n"
resCommentString += "* [HTML Report](${JOB_URL}/Performance_20Report_20for_20${platform.gpu}) \n"
resCommentString += "* [Job Link](${env.BUILD_URL}) \n"
resCommentString += "* [Result Archive](${JOB_URL}/lastSuccessfulBuild/artifact/${project.paths.src_prefix}/rocroller/shared/rocroller/performance_${platform.gpu}_archive.zip) \n"
resCommentString += "