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 1 commit
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
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
kshyju marked this conversation as resolved.
Show resolved Hide resolved
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:
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)
- 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
jviau marked this conversation as resolved.
Show resolved Hide resolved
}

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."
jviau marked this conversation as resolved.
Show resolved Hide resolved
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
jviau marked this conversation as resolved.
Show resolved Hide resolved
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.
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'
jviau marked this conversation as resolved.
Show resolved Hide resolved
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)
Loading