Skip to content

Commit e57d37f

Browse files
authored
Add support for running benchmarks in Linux environment. (#10782)
* Add support for running benchmarks in Linux environment. * Remove verbose output for publish benchmark app step * Using template if else instead of condition on task. Using "Invoke-WebRequest" for both windows and Linux. * Fixed displayName to be consistent. * printing the error message conditionally. * remove `condition` for install libssl1.1 step
1 parent 52bd774 commit e57d37f

File tree

3 files changed

+122
-85
lines changed

3 files changed

+122
-85
lines changed

eng/ci/host.benchmarks.yml

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,46 @@ extends:
4444
- stage: Setup
4545
displayName: Setup & start agents
4646
jobs:
47+
# WINDOWS
48+
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
49+
parameters:
50+
functionAppName: HelloHttpNet9
51+
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
52+
parameters:
53+
functionAppName: HelloHttpNet9NoProxy
54+
55+
# LINUX
4756
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
4857
parameters:
4958
functionAppName: HelloHttpNet9
50-
agentName: HelloHttpNet9_APP
59+
os: Linux
5160
- template: /eng/ci/templates/official/jobs/setup-benchmark-agents.yml@self
5261
parameters:
53-
agentName: HelloHttpNet9NoProxy_APP
54-
functionAppName: HelloHttpNet9NoProxy
62+
functionAppName: HelloHttpNet9NoProxy
63+
os: Linux
5564

5665
- stage: Run
5766
displayName: Run Benchmarks
5867
dependsOn: [] # Force this stage to run independently and in parallel with other stages.
5968
jobs:
69+
# WINDOWS
6070
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
6171
parameters:
6272
description: .NET9 Web Application
6373
functionAppName: HelloHttpNet9 # App with ASP.NET Integration
64-
additionalCrankArgs: $(AdditionalCrankArguments) # Pipeline variable to pass additional arguments to crank command.
65-
storeResultsInDatabase: ${{ variables.storeBenchmarkResultsInDatabase }}
66-
agentName: HelloHttpNet9_APP
6774
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
6875
parameters:
6976
description: .NET9 Worker Application
7077
functionAppName: HelloHttpNet9NoProxy # App without ASP.NET Integration
71-
additionalCrankArgs: $(AdditionalCrankArguments)
72-
storeResultsInDatabase: ${{ variables.storeBenchmarkResultsInDatabase }}
73-
agentName: HelloHttpNet9NoProxy_APP
78+
79+
# LINUX
80+
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
81+
parameters:
82+
description: .NET9 Web Application
83+
functionAppName: HelloHttpNet9
84+
os: Linux
85+
- template: /eng/ci/templates/official/jobs/run-benchmarks.yml@self
86+
parameters:
87+
description: .NET9 Worker Application
88+
functionAppName: HelloHttpNet9NoProxy
89+
os: Linux

eng/ci/templates/official/jobs/run-benchmarks.yml

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,40 @@ parameters:
33
type: string
44
- name: description
55
type: string
6-
- name: storeResultsInDatabase
7-
type: boolean
8-
default: false
9-
- name: additionalCrankArgs
10-
type: string
11-
default: ''
12-
- name: agentName
6+
- name: os
137
type: string
8+
default: Windows
9+
values:
10+
- Windows
11+
- Linux
1412

1513
jobs:
16-
- job: ${{ parameters.functionAppName }}
17-
14+
- job: ${{ parameters.functionAppName }}_${{ parameters.os }}
15+
16+
${{ if eq(parameters.os, 'Linux') }}:
17+
pool:
18+
name: 1es-pool-azfunc-benchmarking-large
19+
image: 1es-ubuntu-22.04-benchmark-runner-vanilla
20+
os: linux
21+
${{ else }}:
22+
pool:
23+
name: 1es-pool-azfunc-benchmarking-large
24+
image: 1es-windows-2022-benchmark-runner-vanilla
25+
os: windows
26+
1827
variables:
19-
agentName: ${{ parameters.agentName }}
28+
agentId: ${{ parameters.functionAppName }}${{ parameters.os }}
2029
runDescription: ${{ parameters.description }}
2130
functionApp: ${{ parameters.functionAppName }}
22-
benchmarkArtifactName: benchmark_results_$(functionApp)
31+
benchmarkArtifactName: benchmark_results_$(Agent.OS)_$(functionApp)
2332
functionAppOutputPath: $(Build.ArtifactStagingDirectory)/FunctionApps/$(functionApp)
2433
benchmarkResultsJsonPath: $(Build.ArtifactStagingDirectory)/BenchmarkResults/$(Build.BuildNumber)_$(functionApp).json
2534
functionsWorkerRuntime: 'dotnet-isolated'
2635
configFilePath: "./eng/perf/http.benchmarks.yml"
2736
hostLocation: "./../../"
2837
baselineBenchmarkResultFilePath: ''
2938
baselineBenchmarkResultsDownloadDir: $(Pipeline.Workspace)/BenchmarkBaselineResult
30-
appAgentIpAddress: ''
39+
appAgentHostName: ''
3140

3241
templateContext:
3342
inputs:
@@ -46,7 +55,7 @@ jobs:
4655
steps:
4756

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

64-
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
65-
displayName: Start crank-agent
66-
67-
- task: CopyFiles@2
68-
displayName: Copy benchmark apps to temp location
69-
inputs:
70-
SourceFolder: '$(Build.SourcesDirectory)/test/Performance/Apps'
71-
Contents: '**/*'
72-
TargetFolder: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps'
73-
CleanTargetFolder: true
74-
75-
- task: DotNetCoreCLI@2
76-
displayName: Publish $(functionApp) app
77-
inputs:
78-
command: publish
79-
publishWebProjects: false
80-
zipAfterPublish: false
81-
modifyOutputPath: false
82-
projects: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)/HelloHttp.csproj'
83-
arguments: -c Release -o $(functionAppOutputPath) -f net9.0
84-
workingDirectory: $(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)
73+
- ${{ if eq(parameters.os, 'Windows') }}:
74+
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
75+
displayName: Start crank-agent
76+
- ${{ else }}:
77+
- script: |
78+
nohup crank-agent &
79+
displayName: Start crank-agent
8580
8681
- task: AzureCLI@2
8782
displayName: Get Remote Agent IP Address
@@ -99,12 +94,12 @@ jobs:
9994
--auth-mode login `
10095
--table-name $(BenchmarkAgentInfoTableName) `
10196
--partition-key $(Build.BuildNumber) `
102-
--row-key $(agentName) `
103-
--select AgentIPAddress
97+
--row-key $(agentId) `
98+
--select HostName
10499
105100
if ($Entity) {
106-
$AgentIPAddress = ($Entity | ConvertFrom-Json).AgentIPAddress
107-
Write-Host "##vso[task.setvariable variable=appAgentIpAddress]$AgentIPAddress"
101+
$HostName = ($Entity | ConvertFrom-Json).HostName
102+
Write-Host "##vso[task.setvariable variable=appAgentHostName]$HostName"
108103
break
109104
} else {
110105
Write-Host "Entity not found. Retrying in 30 seconds..."
@@ -120,25 +115,24 @@ jobs:
120115
121116
- pwsh: |
122117
$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)"
123-
$crankArgs += " --variable CrankAgentAppVm=$(appAgentIpAddress) --variable CrankAgentLoadVm=localhost --variable AspNetUrls=http://$(appAgentIpAddress):5000"
124-
$crankArgs += " ${{ parameters.additionalCrankArgs }}"
118+
$crankArgs += " --variable CrankAgentAppVm=$(appAgentHostName) --variable CrankAgentLoadVm=localhost --variable AspNetUrls=http://$(appAgentHostName):5000"
119+
$crankArgs += " $(AdditionalCrankArguments)"
125120
$command = "crank $crankArgs"
126121
127-
if ('${{ parameters.storeResultsInDatabase }}' -eq 'true') {
122+
if ('${{ variables['storeBenchmarkResultsInDatabase'] }}' -eq 'true') {
128123
$command += " --table HttpBenchmarks --sql `"$(BenchmarkResultsSqlConnectionString)`""
129124
}
130125
131126
Write-Host "Running command: $command"
132127
Invoke-Expression $command
133-
displayName: 'Run Benchmark'
128+
displayName: Run Benchmark
134129
135-
# Retrieve function host logs
136130
- pwsh: |
137-
$url = "http://$(appAgentIpAddress):5010/jobs/1/output"
131+
$url = "http://$(appAgentHostName):5010/jobs/1/output"
138132
Write-Host "Fetching logs from: $url"
139133
$response = Invoke-WebRequest -Uri $url -Method GET -UseBasicParsing
140134
Write-Host $response.Content
141-
displayName: 'Fetch Function Host Logs'
135+
displayName: Fetch Function Host Logs
142136
143137
# Tag the build as a baseline if it originates from the specified branch.
144138
# Baseline builds serve as reference points for performance comparisons in future builds.
@@ -152,13 +146,18 @@ jobs:
152146
- pwsh: |
153147
$baselineDir = "$(baselineBenchmarkResultsDownloadDir)"
154148
$fileNamePattern = "*_$(functionApp).json"
155-
$baselineFile = Get-ChildItem -Path $baselineDir -Filter $fileNamePattern | Select-Object -First 1
156149
157-
if ($baselineFile) {
158-
Write-Host "Found baseline benchmark result file: $($baselineFile.FullName)"
159-
Write-Host "##vso[task.setvariable variable=baselineBenchmarkResultFilePath]$($baselineFile.FullName)"
150+
if (Test-Path $baselineDir -PathType Container) {
151+
$baselineFile = Get-ChildItem -Path $baselineDir -Filter $fileNamePattern | Select-Object -First 1
152+
153+
if ($baselineFile) {
154+
Write-Host "Found baseline benchmark result file: $($baselineFile.FullName)"
155+
Write-Host "##vso[task.setvariable variable=baselineBenchmarkResultFilePath]$($baselineFile.FullName)"
156+
} else {
157+
Write-Host "No baseline benchmark result file matching the pattern '$fileNamePattern' found in directory '$baselineDir'."
158+
}
160159
} else {
161-
Write-Host "No baseline benchmark result file found."
160+
Write-Host "The specified directory '$baselineDir' does not exist."
162161
}
163162
displayName: 'Set Baseline Benchmark Result File Path'
164163

eng/ci/templates/official/jobs/setup-benchmark-agents.yml

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,53 @@
11
parameters:
22
- name: functionAppName
33
type: string
4-
- name: agentName
4+
- name: os
55
type: string
6+
default: Windows
7+
values:
8+
- Windows
9+
- Linux
10+
611
jobs:
7-
- job: ${{ parameters.functionAppName }}
12+
- job: ${{ parameters.functionAppName }}_${{ parameters.os }}
13+
14+
${{ if eq(parameters.os, 'Linux') }}:
15+
pool:
16+
name: 1es-pool-azfunc-benchmarking-large
17+
image: 1es-ubuntu-22.04-benchmark-runner-vanilla
18+
os: linux
19+
${{ else }}:
20+
pool:
21+
name: 1es-pool-azfunc-benchmarking-large
22+
image: 1es-windows-2022-benchmark-runner-vanilla
23+
os: windows
824

925
variables:
10-
agentName: ${{ parameters.agentName }}
26+
agentId: ${{ parameters.functionAppName }}${{ parameters.os }}
1127
functionApp: ${{ parameters.functionAppName }}
1228
functionAppOutputPath: $(Build.ArtifactStagingDirectory)/FunctionApps/$(functionApp)
1329

1430
steps:
1531

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

34+
- ${{ if eq(parameters.os, 'Linux') }}:
35+
# Adds the Ubuntu 20.04 security repository to Ubuntu 22.04 and installs libssl1.1, which is unavailable by default.
36+
- script: |
37+
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
38+
sudo apt update && sudo apt install -y libssl1.1
39+
displayName: "Install libssl1.1 on Ubuntu 22.04"
40+
1841
- script: dotnet tool install -g Microsoft.Crank.Agent --version "0.2.0-*"
1942
displayName: Install Microsoft.Crank.Agent tool
2043

21-
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
22-
displayName: Start crank agent
23-
24-
- pwsh: |
25-
dotnet --info
26-
displayName: Print .NET info
44+
- ${{ if eq(parameters.os, 'Windows') }}:
45+
- pwsh: Start-Process powershell -ArgumentList '-NoExit', '-Command', 'crank-agent'
46+
displayName: Start crank-agent
47+
- ${{ else }}:
48+
- script: |
49+
nohup crank-agent &
50+
displayName: Start crank-agent
2751
2852
- task: CopyFiles@2
2953
displayName: Copy benchmark apps to temp location
@@ -41,22 +65,20 @@ jobs:
4165
zipAfterPublish: false
4266
modifyOutputPath: false
4367
projects: '$(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)/HelloHttp.csproj'
44-
arguments: -c Release -o $(functionAppOutputPath) -f net9.0 -v n
68+
arguments: -c Release -o $(functionAppOutputPath) -f net9.0
4569
workingDirectory: $(Build.ArtifactStagingDirectory)/PerformanceTestApps/$(functionApp)
4670

47-
- script: |
48-
netsh advfirewall firewall add rule name="Open Port 5000" dir=in action=allow protocol=TCP localport=5000
49-
netsh advfirewall firewall add rule name="Open Port 5010" dir=in action=allow protocol=TCP localport=5010
50-
displayName: Open port 5000 and 5010
71+
- ${{ if eq(parameters.os, 'Windows') }}:
72+
- script: |
73+
netsh advfirewall firewall add rule name="Open Port 5000" dir=in action=allow protocol=TCP localport=5000
74+
netsh advfirewall firewall add rule name="Open Port 5010" dir=in action=allow protocol=TCP localport=5010
75+
displayName: Open port 5000 and 5010
5176
52-
- task: PowerShell@2
53-
displayName: Get Agent IP Address
54-
inputs:
55-
targetType: 'inline'
56-
script: |
57-
$ipAddress = (Test-Connection -ComputerName (hostname) -Count 1).IPv4Address.IPAddressToString
58-
Write-Host "IP Address: $ipAddress"
59-
Write-Host "##vso[task.setvariable variable=agentIp]$ipAddress"
77+
- pwsh: |
78+
$HostName = [System.Net.Dns]::GetHostName()
79+
Write-Host "##vso[task.setvariable variable=machineHostName]$HostName"
80+
Write-Host "HostName: $HostName"
81+
displayName: Get Machine Info
6082
6183
- task: AzureCLI@2
6284
displayName: Persist Agent IP Address
@@ -69,7 +91,7 @@ jobs:
6991
--auth-mode login `
7092
--account-name $(StorageAccount) `
7193
--table-name $(BenchmarkAgentInfoTableName) `
72-
--entity PartitionKey=$(Build.BuildNumber) RowKey=$(agentName) AgentName=$(agentName) AgentIPAddress=$(agentIp)
94+
--entity PartitionKey=$(Build.BuildNumber) RowKey=$(agentId) AgentId=$(agentId) HostName=$(machineHostName)
7395
7496
- pwsh: |
7597
$url = "http://localhost:5010/jobs/all"
@@ -80,9 +102,9 @@ jobs:
80102
while ($attempt -lt $maxAttempts) {
81103
$response = Invoke-WebRequest -Uri $url -Method Get -ErrorAction Stop
82104
$data = $response.Content | ConvertFrom-Json
83-
$completedJobCount = ($data | Where-Object { $_.state -eq "Deleted" }).Count
105+
$completedJobCount = ($data | Where-Object { $_.state -eq "Deleted" }).Count
84106
85-
if ($completedJobCount -gt 0) {
107+
if ($completedJobCount -gt 0) {
86108
Write-Host "Found at least 1 job with 'state' = 'Deleted'. Exiting task."
87109
exit 0
88110
}
@@ -108,4 +130,4 @@ jobs:
108130
--auth-mode login `
109131
--account-name $(StorageAccount) `
110132
--table-name $(BenchmarkAgentInfoTableName) `
111-
--partition-key $(Build.BuildNumber) --row-key=$(agentName)
133+
--partition-key $(Build.BuildNumber) --row-key=$(agentId)

0 commit comments

Comments
 (0)