Skip to content

Commit

Permalink
Add support for running benchmarks in Linux environment.
Browse files Browse the repository at this point in the history
  • Loading branch information
kshyju committed Feb 3, 2025
1 parent cfa63f6 commit ae07266
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 82 deletions.
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
104 changes: 52 additions & 52 deletions eng/ci/templates/official/jobs/run-benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,36 @@ parameters:
type: string
- name: description
type: string
- name: storeResultsInDatabase
type: boolean
default: false
- name: additionalCrankArgs
- name: os
type: string
default: ''
- name: agentName
type: string

default: 'Windows'
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 +51,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 @@ -62,26 +67,13 @@ jobs:
displayName: Install Microsoft.Crank.Controller tool

- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
displayName: Start crank-agent
displayName: Start crank-agent(Windows)
condition: eq(variables['Agent.OS'], 'Windows_NT')

- task: CopyFiles@2
displayName: Copy benchmark apps to temp location
inputs:
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)
- script: |
nohup crank-agent &
displayName: Start crank-agent(Linux)
condition: eq(variables['Agent.OS'], 'Linux')
- task: AzureCLI@2
displayName: Get Remote Agent IP Address
Expand All @@ -99,12 +91,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 +112,30 @@ 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'
if ($IsWindows) {
$response = Invoke-WebRequest -Uri $url -Method GET -UseBasicParsing
} else {
$response = curl -s $url
}
Write-Host $response
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 +149,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."
displayName: 'Set Baseline Benchmark Result File Path'
# Compare results with baseline
Expand Down
67 changes: 46 additions & 21 deletions eng/ci/templates/official/jobs/setup-benchmark-agents.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
parameters:
- name: functionAppName
type: string
- name: agentName
- name: os
type: string
default: Windows

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.
- 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')
- 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
displayName: Start crank-agent(Windows)
condition: eq(variables['Agent.OS'], 'Windows_NT')

- pwsh: |
dotnet --info
displayName: Print .NET info
- script: |
nohup crank-agent &
displayName: Start crank-agent(Linux)
condition: eq(variables['Agent.OS'], 'Linux')
- task: CopyFiles@2
displayName: Copy benchmark apps to temp location
Expand All @@ -48,15 +70,13 @@ jobs:
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
condition: eq(variables['Agent.OS'], 'Windows_NT')
- 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 +89,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 @@ -78,11 +98,16 @@ jobs:
$attempt = 0
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
if ($IsWindows) {
$response = Invoke-WebRequest -Uri $url -Method Get -ErrorAction Stop
$data = $response.Content | ConvertFrom-Json
$completedJobCount = ($data | Where-Object { $_.state -eq "Deleted" }).Count
} else {
$response = curl -s -X GET $url
$completedJobCount = ($response | jq '[.[] | select(.state=="Deleted")] | length')
}
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 +133,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)

0 comments on commit ae07266

Please sign in to comment.