Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running benchmarks in Linux environment. #10782

Merged
merged 6 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions eng/ci/host.benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,30 +44,46 @@ extends:
- stage: Setup
displayName: Setup & start agents
jobs:
# WINDOWS
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
parameters:
functionAppName: HelloHttpNet9
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
parameters:
functionAppName: HelloHttpNet9NoProxy

# LINUX
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
parameters:
functionAppName: HelloHttpNet9
agentName: HelloHttpNet9_APP
os: Linux
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
parameters:
agentName: HelloHttpNet9NoProxy_APP
functionAppName: HelloHttpNet9NoProxy
functionAppName: HelloHttpNet9NoProxy
os: Linux

- stage: Run
displayName: Run Benchmarks
dependsOn: [] # Force this stage to run independently and in parallel with other stages.
jobs:
# WINDOWS
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
parameters:
description: .NET9 Web Application
functionAppName: HelloHttpNet9 # App with ASP.NET Integration
additionalCrankArgs: $(AdditionalCrankArguments) # Pipeline variable to pass additional arguments to crank command.
storeResultsInDatabase: ${{ variables.storeBenchmarkResultsInDatabase }}
agentName: HelloHttpNet9_APP
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
parameters:
description: .NET9 Worker Application
functionAppName: HelloHttpNet9NoProxy # App without ASP.NET Integration
additionalCrankArgs: $(AdditionalCrankArguments)
storeResultsInDatabase: ${{ variables.storeBenchmarkResultsInDatabase }}
agentName: HelloHttpNet9NoProxy_APP

# LINUX
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
parameters:
description: .NET9 Web Application
functionAppName: HelloHttpNet9
os: Linux
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
parameters:
description: .NET9 Worker Application
functionAppName: HelloHttpNet9NoProxy
os: Linux
99 changes: 48 additions & 51 deletions eng/ci/templates/official/jobs/run-benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,40 @@ parameters:
type: string
- name: description
type: string
- name: storeResultsInDatabase
kshyju marked this conversation as resolved.
Show resolved Hide resolved
type: boolean
default: false
- name: additionalCrankArgs
type: string
default: ''
- name: agentName
- name: os
type: string
default: Windows
values:
- Windows
- Linux

jobs:
- job: ${{ parameters.functionAppName }}

- job: ${{ parameters.functionAppName }}_${{ parameters.os }}

${{ if eq(parameters.os, 'Linux') }}:
pool:
name: 1es-pool-azfunc-benchmarking-large
image: 1es-ubuntu-22.04-benchmark-runner-vanilla
os: linux
${{ else }}:
pool:
name: 1es-pool-azfunc-benchmarking-large
image: 1es-windows-2022-benchmark-runner-vanilla
os: windows

variables:
agentName: ${{ parameters.agentName }}
agentId: ${{ parameters.functionAppName }}${{ parameters.os }}
runDescription: ${{ parameters.description }}
functionApp: ${{ parameters.functionAppName }}
benchmarkArtifactName: benchmark_results_$(functionApp)
benchmarkArtifactName: benchmark_results_$(Agent.OS)_$(functionApp)
functionAppOutputPath: $(Build.ArtifactStagingDirectory)/FunctionApps/$(functionApp)
benchmarkResultsJsonPath: $(Build.ArtifactStagingDirectory)/BenchmarkResults/$(Build.BuildNumber)_$(functionApp).json
functionsWorkerRuntime: 'dotnet-isolated'
configFilePath: "./eng/perf/http.benchmarks.yml"
hostLocation: "./../../"
baselineBenchmarkResultFilePath: ''
baselineBenchmarkResultsDownloadDir: $(Pipeline.Workspace)/BenchmarkBaselineResult
appAgentIpAddress: ''
appAgentHostName: ''

templateContext:
inputs:
Expand All @@ -46,7 +55,7 @@ jobs:
steps:

- task: AzureKeyVault@2
condition: and(succeeded(), eq('${{ parameters.storeResultsInDatabase }}', true))
condition: and(succeeded(), eq(variables['storeBenchmarkResultsInDatabase'], true))
inputs:
azureSubscription: Azure-Functions-Host-CI-internal
KeyVaultName: functions-perf-crank-kv
Expand All @@ -61,27 +70,13 @@ jobs:
- script: dotnet tool install -g Microsoft.Crank.Controller --version "0.2.0-*"
displayName: Install Microsoft.Crank.Controller tool

- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
displayName: Start crank-agent

- task: CopyFiles@2
displayName: Copy benchmark apps to temp location
inputs:
kshyju marked this conversation as resolved.
Show resolved Hide resolved
SourceFolder: '$(Build.SourcesDirectory)/test/Performance/Apps'
Contents: '**/*'
TargetFolder: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps'
CleanTargetFolder: true

- task: DotNetCoreCLI@2
displayName: Publish $(functionApp) app
inputs:
command: publish
publishWebProjects: false
zipAfterPublish: false
modifyOutputPath: false
projects: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)/HelloHttp.csproj'
arguments: -c Release -o $(functionAppOutputPath) -f net9.0
workingDirectory: $(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)
- ${{ if eq(parameters.os, 'Windows') }}:
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
displayName: Start crank-agent
- ${{ else }}:
- script: |
nohup crank-agent &
displayName: Start crank-agent

- task: AzureCLI@2
displayName: Get Remote Agent IP Address
Expand All @@ -99,12 +94,12 @@ jobs:
--auth-mode login `
--table-name $(BenchmarkAgentInfoTableName) `
--partition-key $(Build.BuildNumber) `
--row-key $(agentName) `
--select AgentIPAddress
--row-key $(agentId) `
--select HostName

if ($Entity) {
$AgentIPAddress = ($Entity | ConvertFrom-Json).AgentIPAddress
Write-Host "##vso[task.setvariable variable=appAgentIpAddress]$AgentIPAddress"
$HostName = ($Entity | ConvertFrom-Json).HostName
Write-Host "##vso[task.setvariable variable=appAgentHostName]$HostName"
break
} else {
Write-Host "Entity not found. Retrying in 30 seconds..."
Expand All @@ -120,25 +115,24 @@ jobs:

- pwsh: |
$crankArgs = "--config $(configFilePath) --scenario hellohttp --profile win2022 --load.options.reuseBuild true --description `"$(runDescription)`" --command-line-property --no-measurements --json $(benchmarkResultsJsonPath) --property sourceVersion=$(Build.SourceVersion) --property buildNumber=$(Build.BuildNumber) --property buildId=$(Build.BuildId) --property sourceBranch=$(Build.SourceBranch) --variable FunctionsWorkerRuntime=$(functionsWorkerRuntime) --variable HostLocation=$(hostLocation) --variable FunctionAppPath=$(functionAppOutputPath)"
$crankArgs += " --variable CrankAgentAppVm=$(appAgentIpAddress) --variable CrankAgentLoadVm=localhost --variable AspNetUrls=http://$(appAgentIpAddress):5000"
$crankArgs += " ${{ parameters.additionalCrankArgs }}"
$crankArgs += " --variable CrankAgentAppVm=$(appAgentHostName) --variable CrankAgentLoadVm=localhost --variable AspNetUrls=http://$(appAgentHostName):5000"
$crankArgs += " $(AdditionalCrankArguments)"
$command = "crank $crankArgs"

if ('${{ parameters.storeResultsInDatabase }}' -eq 'true') {
if ('${{ variables['storeBenchmarkResultsInDatabase'] }}' -eq 'true') {
$command += " --table HttpBenchmarks --sql `"$(BenchmarkResultsSqlConnectionString)`""
}

Write-Host "Running command: $command"
Invoke-Expression $command
displayName: 'Run Benchmark'
displayName: Run Benchmark

# Retrieve function host logs
- pwsh: |
$url = "http://$(appAgentIpAddress):5010/jobs/1/output"
$url = "http://$(appAgentHostName):5010/jobs/1/output"
Write-Host "Fetching logs from: $url"
$response = Invoke-WebRequest -Uri $url -Method GET -UseBasicParsing
Write-Host $response.Content
displayName: 'Fetch Function Host Logs'
displayName: Fetch Function Host Logs

# Tag the build as a baseline if it originates from the specified branch.
# Baseline builds serve as reference points for performance comparisons in future builds.
Expand All @@ -152,14 +146,17 @@ jobs:
- pwsh: |
$baselineDir = "$(baselineBenchmarkResultsDownloadDir)"
$fileNamePattern = "*_$(functionApp).json"
$baselineFile = Get-ChildItem -Path $baselineDir -Filter $fileNamePattern | Select-Object -First 1

if ($baselineFile) {
Write-Host "Found baseline benchmark result file: $($baselineFile.FullName)"
Write-Host "##vso[task.setvariable variable=baselineBenchmarkResultFilePath]$($baselineFile.FullName)"
} else {
Write-Host "No baseline benchmark result file found."
if (Test-Path $baselineDir -PathType Container) {
$baselineFile = Get-ChildItem -Path $baselineDir -Filter $fileNamePattern | Select-Object -First 1

if ($baselineFile) {
Write-Host "Found baseline benchmark result file: $($baselineFile.FullName)"
Write-Host "##vso[task.setvariable variable=baselineBenchmarkResultFilePath]$($baselineFile.FullName)"
}
}

Write-Host "No baseline benchmark result file found."
jviau marked this conversation as resolved.
Show resolved Hide resolved
displayName: 'Set Baseline Benchmark Result File Path'

# Compare results with baseline
Expand Down
74 changes: 48 additions & 26 deletions eng/ci/templates/official/jobs/setup-benchmark-agents.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
parameters:
- name: functionAppName
type: string
- name: agentName
- name: os
jviau marked this conversation as resolved.
Show resolved Hide resolved
type: string
default: Windows
values:
- Windows
- Linux

jobs:
- job: ${{ parameters.functionAppName }}
- job: ${{ parameters.functionAppName }}_${{ parameters.os }}

${{ if eq(parameters.os, 'Linux') }}:
pool:
name: 1es-pool-azfunc-benchmarking-large
image: 1es-ubuntu-22.04-benchmark-runner-vanilla
os: linux
${{ else }}:
pool:
name: 1es-pool-azfunc-benchmarking-large
image: 1es-windows-2022-benchmark-runner-vanilla
os: windows

variables:
agentName: ${{ parameters.agentName }}
agentId: ${{ parameters.functionAppName }}${{ parameters.os }}
functionApp: ${{ parameters.functionAppName }}
functionAppOutputPath: $(Build.ArtifactStagingDirectory)/FunctionApps/$(functionApp)

steps:

- template: /eng/ci/templates/install-dotnet.yml@self

# Adds the Ubuntu 20.04 security repository to Ubuntu 22.04 and installs libssl1.1, which is unavailable by default.
jviau marked this conversation as resolved.
Show resolved Hide resolved
- script: |
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
sudo apt update && sudo apt install -y libssl1.1
displayName: "Install libssl1.1 on Ubuntu 22.04"
condition: eq(variables['Agent.OS'], 'Linux')
jviau marked this conversation as resolved.
Show resolved Hide resolved

- script: dotnet tool install -g Microsoft.Crank.Agent --version "0.2.0-*"
displayName: Install Microsoft.Crank.Agent tool

- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
displayName: Start crank agent

- pwsh: |
dotnet --info
displayName: Print .NET info
- ${{ if eq(parameters.os, 'Windows') }}:
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
displayName: Start crank-agent
- ${{ else }}:
- script: |
nohup crank-agent &
displayName: Start crank-agent

- task: CopyFiles@2
displayName: Copy benchmark apps to temp location
Expand All @@ -41,22 +65,20 @@ jobs:
zipAfterPublish: false
modifyOutputPath: false
projects: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)/HelloHttp.csproj'
arguments: -c Release -o $(functionAppOutputPath) -f net9.0 -v n
arguments: -c Release -o $(functionAppOutputPath) -f net9.0
workingDirectory: $(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)

- script: |
netsh advfirewall firewall add rule name="Open Port 5000" dir=in action=allow protocol=TCP localport=5000
netsh advfirewall firewall add rule name="Open Port 5010" dir=in action=allow protocol=TCP localport=5010
displayName: Open port 5000 and 5010
- ${{ if eq(parameters.os, 'Windows') }}:
- script: |
netsh advfirewall firewall add rule name="Open Port 5000" dir=in action=allow protocol=TCP localport=5000
netsh advfirewall firewall add rule name="Open Port 5010" dir=in action=allow protocol=TCP localport=5010
displayName: Open port 5000 and 5010

- task: PowerShell@2
displayName: Get Agent IP Address
inputs:
targetType: 'inline'
script: |
$ipAddress = (Test-Connection -ComputerName (hostname) -Count 1).IPv4Address.IPAddressToString
Write-Host "IP Address: $ipAddress"
Write-Host "##vso[task.setvariable variable=agentIp]$ipAddress"
- pwsh: |
$HostName = [System.Net.Dns]::GetHostName()
Write-Host "##vso[task.setvariable variable=machineHostName]$HostName"
Write-Host "HostName: $HostName"
displayName: Get Machine Info

- task: AzureCLI@2
displayName: Persist Agent IP Address
Expand All @@ -69,7 +91,7 @@ jobs:
--auth-mode login `
--account-name $(StorageAccount) `
--table-name $(BenchmarkAgentInfoTableName) `
--entity PartitionKey=$(Build.BuildNumber) RowKey=$(agentName) AgentName=$(agentName) AgentIPAddress=$(agentIp)
--entity PartitionKey=$(Build.BuildNumber) RowKey=$(agentId) AgentId=$(agentId) HostName=$(machineHostName)

- pwsh: |
$url = "http://localhost:5010/jobs/all"
Expand All @@ -80,9 +102,9 @@ jobs:
while ($attempt -lt $maxAttempts) {
$response = Invoke-WebRequest -Uri $url -Method Get -ErrorAction Stop
$data = $response.Content | ConvertFrom-Json
$completedJobCount = ($data | Where-Object { $_.state -eq "Deleted" }).Count
$completedJobCount = ($data | Where-Object { $_.state -eq "Deleted" }).Count

if ($completedJobCount -gt 0) {
if ($completedJobCount -gt 0) {
Write-Host "Found at least 1 job with 'state' = 'Deleted'. Exiting task."
exit 0
}
Expand All @@ -108,4 +130,4 @@ jobs:
--auth-mode login `
--account-name $(StorageAccount) `
--table-name $(BenchmarkAgentInfoTableName) `
--partition-key $(Build.BuildNumber) --row-key=$(agentName)
--partition-key $(Build.BuildNumber) --row-key=$(agentId)
Loading