├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .gitignore ├── CODE-OF-CONDUCT.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── LICENSE.txt ├── Microsoft.Crank.sln ├── NOTICE.txt ├── NuGet.config ├── README.md ├── azure-pipelines-release.yml ├── azure-pipelines.yml ├── azure-pr-pipelines.yml ├── build.cmd ├── build.sh ├── docker └── agent │ ├── Dockerfile │ ├── build.sh │ ├── run.sh │ └── stop.sh ├── docs ├── README.md ├── benchmarking_docker.md ├── development.md ├── dotnet_versions.md ├── event_counters.md ├── getting_started.md ├── local_application.md ├── measurements.md ├── microbenchmarks.md ├── post_processing.md ├── precommands.md ├── reference │ ├── architecture.md │ └── benchmarks.svg ├── setup_linux.md └── storing_results.md ├── eng ├── Build.props ├── PoliCheckExclusions.xml ├── Publishing.props ├── Signing.props ├── Version.Details.xml ├── Versions.props ├── common │ ├── BuildConfiguration │ │ └── build-configuration.json │ ├── CIBuild.cmd │ ├── PSScriptAnalyzerSettings.psd1 │ ├── README.md │ ├── SetupNugetSources.ps1 │ ├── SetupNugetSources.sh │ ├── build.ps1 │ ├── build.sh │ ├── cibuild.sh │ ├── cross │ │ ├── arm │ │ │ ├── sources.list.bionic │ │ │ ├── sources.list.focal │ │ │ ├── sources.list.jammy │ │ │ ├── sources.list.jessie │ │ │ ├── sources.list.xenial │ │ │ ├── sources.list.zesty │ │ │ └── tizen │ │ │ │ └── tizen.patch │ │ ├── arm64 │ │ │ ├── sources.list.bionic │ │ │ ├── sources.list.buster │ │ │ ├── sources.list.focal │ │ │ ├── sources.list.jammy │ │ │ ├── sources.list.stretch │ │ │ ├── sources.list.xenial │ │ │ ├── sources.list.zesty │ │ │ └── tizen │ │ │ │ └── tizen.patch │ │ ├── armel │ │ │ ├── armel.jessie.patch │ │ │ ├── sources.list.jessie │ │ │ └── tizen │ │ │ │ └── tizen.patch │ │ ├── armv6 │ │ │ └── sources.list.buster │ │ ├── build-android-rootfs.sh │ │ ├── build-rootfs.sh │ │ ├── ppc64le │ │ │ └── sources.list.bionic │ │ ├── riscv64 │ │ │ └── sources.list.sid │ │ ├── s390x │ │ │ └── sources.list.bionic │ │ ├── tizen-build-rootfs.sh │ │ ├── tizen-fetch.sh │ │ └── toolchain.cmake │ ├── darc-init.ps1 │ ├── darc-init.sh │ ├── dotnet-install.cmd │ ├── dotnet-install.ps1 │ ├── dotnet-install.sh │ ├── enable-cross-org-publishing.ps1 │ ├── generate-locproject.ps1 │ ├── generate-sbom-prep.ps1 │ ├── generate-sbom-prep.sh │ ├── helixpublish.proj │ ├── init-tools-native.cmd │ ├── init-tools-native.ps1 │ ├── init-tools-native.sh │ ├── internal-feed-operations.ps1 │ ├── internal-feed-operations.sh │ ├── internal │ │ ├── Directory.Build.props │ │ ├── NuGet.config │ │ └── Tools.csproj │ ├── loc │ │ └── P22DotNetHtmlLocalization.lss │ ├── msbuild.ps1 │ ├── msbuild.sh │ ├── native │ │ ├── CommonLibrary.psm1 │ │ ├── common-library.sh │ │ ├── init-compiler.sh │ │ ├── init-distro-rid.sh │ │ ├── init-os-and-arch.sh │ │ ├── install-cmake-test.sh │ │ ├── install-cmake.sh │ │ └── install-tool.ps1 │ ├── pipeline-logging-functions.ps1 │ ├── pipeline-logging-functions.sh │ ├── post-build │ │ ├── add-build-to-channel.ps1 │ │ ├── check-channel-consistency.ps1 │ │ ├── nuget-validation.ps1 │ │ ├── post-build-utils.ps1 │ │ ├── publish-using-darc.ps1 │ │ ├── sourcelink-validation.ps1 │ │ ├── symbols-validation.ps1 │ │ └── trigger-subscriptions.ps1 │ ├── retain-build.ps1 │ ├── sdk-task.ps1 │ ├── sdl │ │ ├── NuGet.config │ │ ├── configure-sdl-tool.ps1 │ │ ├── execute-all-sdl-tools.ps1 │ │ ├── extract-artifact-archives.ps1 │ │ ├── extract-artifact-packages.ps1 │ │ ├── init-sdl.ps1 │ │ ├── packages.config │ │ ├── run-sdl.ps1 │ │ ├── sdl.ps1 │ │ └── trim-assets-version.ps1 │ ├── templates-official │ │ ├── job │ │ │ ├── job.yml │ │ │ ├── onelocbuild.yml │ │ │ ├── publish-build-assets.yml │ │ │ ├── source-build.yml │ │ │ └── source-index-stage1.yml │ │ ├── jobs │ │ │ ├── codeql-build.yml │ │ │ ├── jobs.yml │ │ │ └── source-build.yml │ │ ├── post-build │ │ │ ├── common-variables.yml │ │ │ ├── post-build.yml │ │ │ ├── setup-maestro-vars.yml │ │ │ └── trigger-subscription.yml │ │ ├── steps │ │ │ ├── add-build-to-channel.yml │ │ │ ├── build-reason.yml │ │ │ ├── component-governance.yml │ │ │ ├── enable-internal-runtimes.yml │ │ │ ├── execute-codeql.yml │ │ │ ├── execute-sdl.yml │ │ │ ├── generate-sbom.yml │ │ │ ├── get-delegation-sas.yml │ │ │ ├── get-federated-access-token.yml │ │ │ ├── publish-logs.yml │ │ │ ├── retain-build.yml │ │ │ ├── send-to-helix.yml │ │ │ └── source-build.yml │ │ └── variables │ │ │ ├── pool-providers.yml │ │ │ └── sdl-variables.yml │ ├── templates │ │ ├── job │ │ │ ├── execute-sdl.yml │ │ │ ├── job.yml │ │ │ ├── onelocbuild.yml │ │ │ ├── publish-build-assets.yml │ │ │ ├── source-build.yml │ │ │ └── source-index-stage1.yml │ │ ├── jobs │ │ │ ├── codeql-build.yml │ │ │ ├── jobs.yml │ │ │ └── source-build.yml │ │ ├── post-build │ │ │ ├── common-variables.yml │ │ │ ├── post-build.yml │ │ │ ├── setup-maestro-vars.yml │ │ │ └── trigger-subscription.yml │ │ ├── steps │ │ │ ├── add-build-to-channel.yml │ │ │ ├── build-reason.yml │ │ │ ├── component-governance.yml │ │ │ ├── enable-internal-runtimes.yml │ │ │ ├── execute-codeql.yml │ │ │ ├── execute-sdl.yml │ │ │ ├── generate-sbom.yml │ │ │ ├── get-delegation-sas.yml │ │ │ ├── get-federated-access-token.yml │ │ │ ├── publish-logs.yml │ │ │ ├── retain-build.yml │ │ │ ├── run-on-unix.yml │ │ │ ├── run-on-windows.yml │ │ │ ├── run-script-ifequalelse.yml │ │ │ ├── send-to-helix.yml │ │ │ ├── source-build.yml │ │ │ ├── telemetry-end.yml │ │ │ └── telemetry-start.yml │ │ └── variables │ │ │ ├── pool-providers.yml │ │ │ └── sdl-variables.yml │ ├── tools.ps1 │ └── tools.sh └── dependencies.props ├── global.json ├── samples ├── hello │ ├── Program.cs │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── hello.benchmarks.yml │ └── hello.csproj ├── local │ └── local.benchmarks.yml ├── micro │ ├── Md5VsSha256.cs │ ├── Program.cs │ ├── dotnet.benchmarks.yml │ ├── micro.benchmarks.yml │ └── micro.csproj ├── netty │ └── netty.benchmarks.yml ├── post │ ├── Program.cs │ └── post.csproj ├── precommand │ └── precommand.benchmarks.yml └── scripts │ └── scripts.benchmarks.yml ├── src ├── Microsoft.Crank.Agent │ ├── CGroup.cs │ ├── CGroupV1.cs │ ├── CGroupV2.cs │ ├── CompositeRelayServer.cs │ ├── Controllers │ │ ├── HomeController.cs │ │ └── JobsController.cs │ ├── Dumper.Windows.cs │ ├── Dumper.cs │ ├── GZipFileResult.cs │ ├── Git.cs │ ├── JobContext.cs │ ├── JobResult.cs │ ├── JobsApis.cs │ ├── Log.cs │ ├── MachineCounters │ │ ├── MachineCountersController.cs │ │ ├── MachineCountersEventSource.cs │ │ └── OS │ │ │ ├── IMachinePerformanceCounterEmitter.cs │ │ │ ├── LinuxMachineCpuUsageEmitter.cs │ │ │ ├── WindowsMachineCpuUsageEmitter.cs │ │ │ └── WindowsProcessCpuTimeEmitter.cs │ ├── Measurements.cs │ ├── Microsoft.Crank.Agent.csproj │ ├── MstatDumper.cs │ ├── NativeMethods.txt │ ├── PackageTypes.cs │ ├── ProcessResult.cs │ ├── ProcessUtil.cs │ ├── README.md │ ├── Repository │ │ ├── IIdentifiable.cs │ │ ├── IJobRepository.cs │ │ └── InMemoryJobRepository.cs │ ├── Startup.cs │ ├── TraceExtensions.cs │ ├── WindowsLimiter.cs │ └── applicationHost.config ├── Microsoft.Crank.AzureDevOpsWorker │ ├── DevopsMessage.cs │ ├── DotNetToolSettings.xml │ ├── Job.cs │ ├── JobPayload.cs │ ├── Microsoft.Crank.AzureDevOpsWorker.csproj │ ├── ProcessResult.cs │ ├── Program.cs │ ├── Records.cs │ ├── RetryHandler.cs │ └── TimeSpanConverter.cs ├── Microsoft.Crank.Controller │ ├── Configuration.cs │ ├── ControllerException.cs │ ├── CounterProfile.cs │ ├── Documentation.cs │ ├── DotNetToolSettings.xml │ ├── ExcludeOptions.cs │ ├── ExecutionResult.cs │ ├── Headers.cs │ ├── Ignore │ │ ├── IgnoreFile.cs │ │ └── IgnoreRule.cs │ ├── JobConnection.cs │ ├── JobDeadlockException.cs │ ├── JobDefinition.cs │ ├── JobSerializer.cs │ ├── JobView.cs │ ├── JsonTypeResolver.cs │ ├── Log.cs │ ├── Microsoft.Crank.Controller.csproj │ ├── ProcessResult.cs │ ├── ProcessUtil.cs │ ├── Program.cs │ ├── README.md │ ├── ResultComparer.cs │ ├── ResultTable.cs │ ├── ScriptConsole.cs │ ├── ScriptFile.cs │ ├── VariableParser.cs │ ├── VersionChecker.cs │ ├── WebUtils.cs │ ├── benchmarks.schema.json │ └── default.config.yml ├── Microsoft.Crank.EventSources │ ├── BenchmarksEventSource.cs │ ├── Microsoft.Crank.EventSources.csproj │ └── Operations.cs ├── Microsoft.Crank.JobOjectWrapper │ ├── Microsoft.Crank.JobObjectWrapper.csproj │ └── Program.cs ├── Microsoft.Crank.Jobs.Bombardier │ ├── Microsoft.Crank.Jobs.Bombardier.csproj │ ├── Program.cs │ └── bombardier.yml ├── Microsoft.Crank.Jobs.H2Load │ ├── Microsoft.Crank.Jobs.H2Load.csproj │ ├── Program.cs │ └── h2load.yml ├── Microsoft.Crank.Jobs.HttpClient │ ├── Microsoft.Crank.Jobs.HttpClient.csproj │ ├── Program.cs │ ├── Runner.cs │ ├── ScriptConsole.cs │ ├── Timeline.cs │ ├── TimelineFactory.cs │ ├── WorkerResult.cs │ ├── httpclient.yml │ └── scripts │ │ ├── log.js │ │ ├── script.js │ │ └── urls.js ├── Microsoft.Crank.Jobs.K6 │ ├── Microsoft.Crank.Jobs.K6.csproj │ ├── Program.cs │ ├── k6.yml │ └── scripts │ │ └── default.js ├── Microsoft.Crank.Jobs.PipeliningClient │ ├── HttpConnection.cs │ ├── HttpResponse.cs │ ├── Microsoft.Crank.Jobs.PipeliningClient.csproj │ ├── Program.cs │ ├── SequenceReaderExtensions.cs │ ├── WorkerResult.cs │ └── pipelining.yml ├── Microsoft.Crank.Jobs.Wrk │ ├── Microsoft.Crank.Jobs.Wrk.csproj │ ├── Program.cs │ ├── WrkProcess.cs │ ├── scripts │ │ └── pipeline.lua │ └── wrk.yml ├── Microsoft.Crank.Jobs.Wrk2 │ ├── Microsoft.Crank.Jobs.Wrk2.csproj │ ├── Program.cs │ └── wrk2.yml ├── Microsoft.Crank.Models │ ├── Attachment.cs │ ├── AttachmentViewModel.cs │ ├── CommandDefinition.cs │ ├── Database.cs │ ├── Dependency.cs │ ├── DotnetCounter.cs │ ├── DumpTypeOption.cs │ ├── EnvironmentData.cs │ ├── Job.cs │ ├── JobResults.cs │ ├── JobState.cs │ ├── JobStatistics.cs │ ├── Measurement.cs │ ├── MeasurementMetadata.cs │ ├── Microsoft.Crank.Models.csproj │ ├── OperatingSystem.cs │ ├── RollingLog.cs │ ├── Scheme.cs │ ├── ScriptType.cs │ ├── Security │ │ ├── CertificateOptions.cs │ │ └── CertificateOptionsExtensions.cs │ ├── Source.cs │ └── WebHost.cs ├── Microsoft.Crank.PullRequestBot │ ├── BotOptions.cs │ ├── Command.cs │ ├── Configuration.cs │ ├── CredentialsHelper.cs │ ├── JsonTypeResolver.cs │ ├── Microsoft.Crank.PullRequestBot.csproj │ ├── Program.cs │ ├── PullRequestBotException.cs │ ├── README.md │ ├── pullrequestbot.schema.json │ ├── sample.config.json │ └── sample.config.yml └── Microsoft.Crank.RegressionBot │ ├── BotOptions.cs │ ├── Configuration.cs │ ├── CredentialsHelper.cs │ ├── JsonTypeResolver.cs │ ├── Microsoft.Crank.RegressionBot.csproj │ ├── Models │ ├── BenchmarksResult.cs │ ├── DependencyChange.cs │ ├── Regression.cs │ └── Report.cs │ ├── Probe.cs │ ├── Program.cs │ ├── Queries.cs │ ├── RegressionBotException.cs │ ├── Rule.cs │ ├── Source.cs │ ├── SourceSection.cs │ ├── regressionbot.schema.json │ ├── sample.config.json │ └── sample.config.yml └── test ├── Microsoft.Crank.IntegrationTests ├── AgentFixture.cs ├── AzureWorkerTests.cs ├── CommonTests.cs ├── GitIgnoreTests.cs ├── Microsoft.Crank.IntegrationTests.csproj ├── SkipOnLinuxAttribute.cs ├── SkipOnMacOsAttribute.cs ├── SkipOnWindowsAttribute.cs └── assets │ ├── hello.benchmarks.yml │ ├── multiclient.benchmarks.yml │ ├── post.benchmarks.yml │ ├── precommands.benchmarks.yml │ └── scripts.benchmarks.yml └── Microsoft.Crank.RegressionBot.Tests ├── Microsoft.Crank.RegressionBot.Tests.csproj ├── TemplateTests.cs └── assets ├── regressions1.json ├── regressions2.json ├── template1.fluid └── template2.fluid /.dockerignore: -------------------------------------------------------------------------------- 1 | .git* 2 | .dockerignore 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Don't use tabs for indentation. 7 | [*] 8 | indent_style = space 9 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 10 | 11 | # Code files 12 | [*.{cs,csx,vb,vbx}] 13 | indent_size = 4 14 | 15 | # Xml project files 16 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,xml}] 17 | indent_size = 2 18 | 19 | # Xml config files 20 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 21 | indent_size = 2 22 | 23 | # JSON files 24 | [*.json] 25 | indent_size = 2 26 | 27 | # Dotnet code style settings: 28 | [*.cs] 29 | # Sort using and Import directives with System.* appearing first 30 | dotnet_sort_system_directives_first = true 31 | 32 | # Don't use this. qualifier 33 | dotnet_style_qualification_for_field = false:suggestion 34 | dotnet_style_qualification_for_property = false:suggestion 35 | 36 | # use int x = .. over Int32 37 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 38 | 39 | # use int.MaxValue over Int32.MaxValue 40 | dotnet_style_predefined_type_for_member_access = true:suggestion 41 | 42 | # Require var all the time. 43 | csharp_style_var_for_built_in_types = true:suggestion 44 | csharp_style_var_when_type_is_apparent = true:suggestion 45 | csharp_style_var_elsewhere = true:suggestion 46 | 47 | # Disallow throw expressions. 48 | csharp_style_throw_expression = false:suggestion 49 | 50 | # Newline settings 51 | csharp_new_line_before_open_brace = all 52 | csharp_new_line_before_else = true 53 | csharp_new_line_before_catch = true 54 | csharp_new_line_before_finally = true 55 | csharp_new_line_before_members_in_object_initializers = true 56 | csharp_new_line_before_members_in_anonymous_types = true 57 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.doc diff=astextplain 2 | *.DOC diff=astextplain 3 | *.docx diff=astextplain 4 | *.DOCX diff=astextplain 5 | *.dot diff=astextplain 6 | *.DOT diff=astextplain 7 | *.pdf diff=astextplain 8 | *.PDF diff=astextplain 9 | *.rtf diff=astextplain 10 | *.RTF diff=astextplain 11 | 12 | *.jpg binary 13 | *.png binary 14 | *.gif binary 15 | 16 | *.cs text=auto diff=csharp 17 | *.vb text=auto 18 | *.resx text=auto 19 | *.c text=auto 20 | *.cpp text=auto 21 | *.cxx text=auto 22 | *.h text=auto 23 | *.hxx text=auto 24 | *.py text=auto 25 | *.rb text=auto 26 | *.java text=auto 27 | *.html text=auto 28 | *.htm text=auto 29 | *.css text=auto 30 | *.scss text=auto 31 | *.sass text=auto 32 | *.less text=auto 33 | *.js text=auto 34 | *.lisp text=auto 35 | *.clj text=auto 36 | *.sql text=auto 37 | *.php text=auto 38 | *.lua text=auto 39 | *.m text=auto 40 | *.asm text=auto 41 | *.erl text=auto 42 | *.fs text=auto 43 | *.fsx text=auto 44 | *.hs text=auto 45 | 46 | *.csproj text=auto 47 | *.vbproj text=auto 48 | *.fsproj text=auto 49 | *.dbproj text=auto 50 | *.sln text=auto eol=crlf 51 | *.sh eol=lf -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant 4 | to clarify expected behavior in our community. 5 | 6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 7 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(CopyrightNetFoundation) 7 | 8 | 9 | MIT 10 | Microsoft 11 | 12 | 13 | 14 | 15 | 16 | Microsoft Crank 17 | https://github.com/dotnet/crank 18 | git 19 | $(MSBuildThisFileDirectory) 20 | 21 | false 22 | 23 | 24 | false 25 | 26 | 27 | $(NoWarn);8002 28 | latest 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\common\Build.ps1""" -restore -build %*" 3 | exit /b %ErrorLevel% 4 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source="${BASH_SOURCE[0]}" 4 | 5 | # resolve $SOURCE until the file is no longer a symlink 6 | while [[ -h $source ]]; do 7 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 8 | source="$(readlink "$source")" 9 | 10 | # if $source was a relative symlink, we need to resolve it relative to the path where the 11 | # symlink file was located 12 | [[ $source != /* ]] && source="$scriptroot/$source" 13 | done 14 | 15 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 16 | "$scriptroot/eng/common/build.sh" --build --restore $@ 17 | -------------------------------------------------------------------------------- /docker/agent/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cpuname=$(uname -p) 4 | docker build -t crank-agent --build-arg CPUNAME=$cpuname -f Dockerfile ../../ -------------------------------------------------------------------------------- /docker/agent/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | url="http://*:5001" 4 | name="crank-agent" 5 | others="" 6 | dockerargs="" 7 | 8 | while [ $# -ne 0 ] 9 | do 10 | case "$1" in 11 | --url) 12 | shift 13 | url="$1" 14 | shift 15 | ;; 16 | --name) 17 | shift 18 | name="$1" 19 | shift 20 | ;; 21 | *) 22 | others+=" $1" 23 | shift 24 | ;; 25 | esac 26 | done 27 | 28 | if [ -n "CRANK_AGENT_AZURE_RELAY_CERT_CLIENT_ID" ] 29 | then 30 | dockerargs+=" --env CRANK_AGENT_AZURE_RELAY_CERT_CLIENT_ID" 31 | fi 32 | 33 | if [ -n "CRANK_AGENT_AZURE_RELAY_CERT_TENANT_ID" ] 34 | then 35 | dockerargs+=" --env CRANK_AGENT_AZURE_RELAY_CERT_TENANT_ID" 36 | fi 37 | 38 | if [ -n "CRANK_AGENT_AZURE_RELAY_CERT_PATH" ] 39 | then 40 | dockerargs+=" -v $CRANK_AGENT_AZURE_RELAY_CERT_PATH:/certs/relay.pfx --env CRANK_AGENT_AZURE_RELAY_CERT_PATH=/certs/relay.pfx" 41 | fi 42 | 43 | # cgroupfs is mapped to allow docker to create cgroups without permissions issues (cgroup v2) 44 | # docker.sock is mapped to be able to manage other docker instances from this one 45 | docker run -it --name $name -d --network host --restart always \ 46 | --log-opt max-size=1G --privileged \ 47 | -v /sys/fs/cgroup/:/sys/fs/cgroup/ \ 48 | -v /var/run/docker.sock:/var/run/docker.sock $dockerargs \ 49 | crank-agent \ 50 | --url $url $others 51 | -------------------------------------------------------------------------------- /docker/agent/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | NAME="$1" 4 | shift 5 | 6 | if [ -z "$NAME" ] 7 | then 8 | NAME="crank-agent" 9 | fi 10 | 11 | docker stop "$NAME" 12 | docker rm "$NAME" 13 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 📖 Microsoft.Crank documentation 2 | 3 | ## Tutorials 4 | 5 | | Topic | Description | 6 | |-------|-------------| 7 | |**[Getting Started](getting_started.md)** | Writing your first benchmark. 8 | |**[Benchmarking local applications](local_application.md)** | Send local application source to the agent. 9 | |**[Benchmarking Docker containers](benchmarking_docker.md)** | Run Docker containers. 10 | |**[Running micro-benchmarks](microbenchmarks.md)** | Run BenchmarkDotNet benchmarks. 11 | |**[Setting up an agent on Linux](setup_linux.md)** | How to install and update the agent on a Linux machine. 12 | 13 | ## Guides 14 | 15 | | Topic | Description| 16 | |-------|------------| 17 | |**[Storing results](storing_results.md)** | Storing results locally or in a SQL Server database. 18 | |**[Using different .NET versions](dotnet_versions.md)** | Benchmarking with different .NET versions. 19 | |**[Collecting event counters](event_counters.md)** | Collecting predefined and custom event counters. 20 | |**[Post-processing results](post_processing.md)** | Adding custom results and running scripts. 21 | |**[Running pre-commands](precommands.md)** | Running commands before the job is pushed to the agent. 22 | |**[Reporting custom measurements](measurements.md)** | How to push custom measurement from a job. 23 | 24 | 25 | ## Reference documentation 26 | 27 | | Area | Description | 28 | |------|-------------| 29 | |**[crank command line reference](../src/Microsoft.Crank.Controller/README.md)** | Documentation for `crank` commands. 30 | |**[`benchmarks.yaml` Schema](../src/Microsoft.Crank.Controller/benchmarks.schema.json)** | `benchmarks.yaml` configuration. 31 | |**[Architecture](reference/architecture.md)** | Architecture of Microsoft Crank 32 | -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | ## Running from source 2 | 3 | Crank can be started from its source code by executing these commands: 4 | 5 | ### Crank Agent 6 | 7 | ``` 8 | cd ./src/Microsoft.Crank.Agent 9 | dotnet run 10 | ``` 11 | 12 | ### Crank Controller 13 | 14 | ``` 15 | cd ./src/Microsoft.Crank.Controller 16 | dotnet run --config ../../samples/hello/hello.benchmarks.yml --scenario hello --profile local 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/reference/architecture.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | The benchmarking infrastructure is a simple client-server design. The benchmark controller orchestrates jobs across one or more agents and polls for status. 4 | 5 | The agent runs on each machine that wants to execute jobs and has exposes a simple CRUD HTTP API that can be used to manage the queue of jobs. The job queue on the agent side executes jobs serially. 6 | 7 | See the [diagram](#diagram) for more details. 8 | 9 | ## Jobs, Scenarios, and Profiles 10 | 11 | Jobs are individual units of execution. A job can be encapsulated by a Dockerfile, or a .NET project. Scenarios are a list of jobs that the controller will orchestrate. 12 | 13 | ```yaml 14 | imports: 15 | - https://raw.githubusercontent.com/dotnet/crank/main/src/Microsoft.Crank.Jobs.Bombardier/bombardier.yml 16 | 17 | jobs: 18 | server: 19 | sources: 20 | crank: 21 | repository: https://github.com/dotnet/crank 22 | branchOrCommit: main 23 | project: crank/samples/hello/hello.csproj 24 | 25 | scenarios: 26 | hello: 27 | application: 28 | job: server 29 | load: 30 | job: bombardier 31 | variables: 32 | serverPort: 5000 33 | path: / 34 | ``` 35 | 36 | In the above manifest, there are 2 jobs defined: 37 | 1. The "server" job 38 | 2. The "bombardier" job (defined in the imports section) 39 | 40 | The server job runs a hello world ASP.NET Core application and the bombardier job is a benchmarking tools with specific variables defined to exert load on the server job. We specify a variable called serverPort to tell the client what port to hit on the server job. 41 | 42 | ## Diagram 43 | 44 |

45 | 46 |

47 | -------------------------------------------------------------------------------- /docs/setup_linux.md: -------------------------------------------------------------------------------- 1 | ## Setting up an agent on Linux 2 | 3 | On Linux, it is recommended to setup the Agent using the Docker file provided in this repository. 4 | There instructions are valid for x86_64 and ARM64 (aka ARMv8 or AARCH64). 5 | 6 | ### Installing Docker 7 | 8 | - Install docker from the automated script 9 | 10 | ``` 11 | curl -sSL https://get.docker.com | sh 12 | ``` 13 | 14 | - Add the local account to the docker user group so that you can execute docker commands without sudo 15 | 16 | ``` 17 | sudo groupadd docker 18 | sudo usermod -aG docker $USER 19 | newgrp docker 20 | ``` 21 | 22 | - Reopen the session with the account 23 | - Check Docker is running 24 | 25 | ``` 26 | docker run hello-world 27 | ``` 28 | 29 | ### Starting the Agent 30 | 31 | - Clone the `crank` repository 32 | 33 | ``` 34 | mkdir ~/src 35 | cd ~/src 36 | git clone https://github.com/dotnet/crank 37 | ``` 38 | 39 | - Build and run the Agent docker image 40 | 41 | ``` 42 | cd ~/src/crank/docker/agent 43 | ./build.sh 44 | ./run.sh 45 | ``` 46 | 47 | This will build the image with all the dependencies (perfcollect, ...) and start a container named `crank-agent`. 48 | To stop the container, run `./stop.sh` 49 | 50 | ### Displaying the agent log 51 | 52 | To display the live log, run the following command: 53 | 54 | ``` 55 | docker logs -f --tail 100 crank-agent 56 | ``` 57 | 58 | ### Continuous integration 59 | 60 | In order to restart and update the agent regularly, the following cron job can be used. 61 | 62 | - Edit the crontab file: 63 | 64 | ``` 65 | crontab -e 66 | ``` 67 | 68 | - Add this entry: 69 | 70 | ``` 71 | 0 0 * * * cd [PATH_TO_CRANK]/src/crank/docker/agent; ./stop.sh; docker rm -f $(docker ps -a -q --filter "label=benchmarks"); docker system prune --all --force --volumes; git checkout -f master; git pull; ./build.sh; ./run.sh 72 | ``` 73 | 74 | This will stop any running agent, clean all docker images used to run benchmarks, update the GitHub repositor, build and restart the agent image. 75 | -------------------------------------------------------------------------------- /eng/Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /eng/PoliCheckExclusions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /eng/Publishing.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 6 | 7 | -------------------------------------------------------------------------------- /eng/Version.Details.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | https://github.com/dotnet/arcade 8 | 4246a31e5de9de87f760218c4f588cebf4661f45 9 | 10 | 11 | https://github.com/dotnet/arcade 12 | 4246a31e5de9de87f760218c4f588cebf4661f45 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /eng/Versions.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.2.0 5 | alpha 6 | 7 | 8 | -------------------------------------------------------------------------------- /eng/common/BuildConfiguration/build-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "RetryCountLimit": 1, 3 | "RetryByAnyError": false 4 | } 5 | -------------------------------------------------------------------------------- /eng/common/CIBuild.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0Build.ps1""" -restore -build -test -sign -pack -publish -ci %*" -------------------------------------------------------------------------------- /eng/common/PSScriptAnalyzerSettings.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | IncludeRules=@('PSAvoidUsingCmdletAliases', 3 | 'PSAvoidUsingWMICmdlet', 4 | 'PSAvoidUsingPositionalParameters', 5 | 'PSAvoidUsingInvokeExpression', 6 | 'PSUseDeclaredVarsMoreThanAssignments', 7 | 'PSUseCmdletCorrectly', 8 | 'PSStandardDSCFunctionsInResource', 9 | 'PSUseIdenticalMandatoryParametersForDSC', 10 | 'PSUseIdenticalParametersForDSC') 11 | } -------------------------------------------------------------------------------- /eng/common/README.md: -------------------------------------------------------------------------------- 1 | # Don't touch this folder 2 | 3 | uuuuuuuuuuuuuuuuuuuu 4 | u" uuuuuuuuuuuuuuuuuu "u 5 | u" u$$$$$$$$$$$$$$$$$$$$u "u 6 | u" u$$$$$$$$$$$$$$$$$$$$$$$$u "u 7 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u 8 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u 9 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u 10 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ 11 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ 12 | $ $$$" ... "$... ...$" ... "$$$ ... "$$$ $ 13 | $ $$$u `"$$$$$$$ $$$ $$$$$ $$ $$$ $$$ $ 14 | $ $$$$$$uu "$$$$ $$$ $$$$$ $$ """ u$$$ $ 15 | $ $$$""$$$ $$$$ $$$u "$$$" u$$ $$$$$$$$ $ 16 | $ $$$$....,$$$$$..$$$$$....,$$$$..$$$$$$$$ $ 17 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ 18 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u" 19 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u" 20 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u" 21 | "u "$$$$$$$$$$$$$$$$$$$$$$$$" u" 22 | "u "$$$$$$$$$$$$$$$$$$$$" u" 23 | "u """""""""""""""""" u" 24 | """""""""""""""""""" 25 | 26 | !!! Changes made in this directory are subject to being overwritten by automation !!! 27 | 28 | The files in this directory are shared by all Arcade repos and managed by automation. If you need to make changes to these files, open an issue or submit a pull request to https://github.com/dotnet/arcade first. 29 | -------------------------------------------------------------------------------- /eng/common/cibuild.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source="${BASH_SOURCE[0]}" 4 | 5 | # resolve $SOURCE until the file is no longer a symlink 6 | while [[ -h $source ]]; do 7 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 8 | source="$(readlink "$source")" 9 | 10 | # if $source was a relative symlink, we need to resolve it relative to the path where 11 | # the symlink file was located 12 | [[ $source != /* ]] && source="$scriptroot/$source" 13 | done 14 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 15 | 16 | . "$scriptroot/build.sh" --restore --build --test --pack --publish --ci $@ -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.bionic: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.focal: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ focal main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.jammy: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.jessie: -------------------------------------------------------------------------------- 1 | # Debian (sid) # UNSTABLE 2 | deb http://ftp.debian.org/debian/ sid main contrib non-free 3 | deb-src http://ftp.debian.org/debian/ sid main contrib non-free 4 | -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.xenial: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm/sources.list.zesty: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm/tizen/tizen.patch: -------------------------------------------------------------------------------- 1 | diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so 2 | --- a/usr/lib/libc.so 2016-12-30 23:00:08.284951863 +0900 3 | +++ b/usr/lib/libc.so 2016-12-30 23:00:32.140951815 +0900 4 | @@ -2,4 +2,4 @@ 5 | Use the shared library, but some functions are only in 6 | the static library, so try that secondarily. */ 7 | OUTPUT_FORMAT(elf32-littlearm) 8 | -GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-armhf.so.3 ) ) 9 | +GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-armhf.so.3 ) ) 10 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.bionic: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.buster: -------------------------------------------------------------------------------- 1 | deb http://deb.debian.org/debian buster main 2 | deb-src http://deb.debian.org/debian buster main 3 | 4 | deb http://deb.debian.org/debian-security/ buster/updates main 5 | deb-src http://deb.debian.org/debian-security/ buster/updates main 6 | 7 | deb http://deb.debian.org/debian buster-updates main 8 | deb-src http://deb.debian.org/debian buster-updates main 9 | 10 | deb http://deb.debian.org/debian buster-backports main contrib non-free 11 | deb-src http://deb.debian.org/debian buster-backports main contrib non-free 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.focal: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ focal main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ focal-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ focal-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.jammy: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ jammy-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.stretch: -------------------------------------------------------------------------------- 1 | deb http://deb.debian.org/debian stretch main 2 | deb-src http://deb.debian.org/debian stretch main 3 | 4 | deb http://deb.debian.org/debian-security/ stretch/updates main 5 | deb-src http://deb.debian.org/debian-security/ stretch/updates main 6 | 7 | deb http://deb.debian.org/debian stretch-updates main 8 | deb-src http://deb.debian.org/debian stretch-updates main 9 | 10 | deb http://deb.debian.org/debian stretch-backports main contrib non-free 11 | deb-src http://deb.debian.org/debian stretch-backports main contrib non-free 12 | 13 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.xenial: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/sources.list.zesty: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/arm64/tizen/tizen.patch: -------------------------------------------------------------------------------- 1 | diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so 2 | --- a/usr/lib64/libc.so 2016-12-30 23:00:08.284951863 +0900 3 | +++ b/usr/lib64/libc.so 2016-12-30 23:00:32.140951815 +0900 4 | @@ -2,4 +2,4 @@ 5 | Use the shared library, but some functions are only in 6 | the static library, so try that secondarily. */ 7 | OUTPUT_FORMAT(elf64-littleaarch64) 8 | -GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-aarch64.so.1 ) ) 9 | +GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-aarch64.so.1 ) ) 10 | -------------------------------------------------------------------------------- /eng/common/cross/armel/armel.jessie.patch: -------------------------------------------------------------------------------- 1 | diff -u -r a/usr/include/urcu/uatomic/generic.h b/usr/include/urcu/uatomic/generic.h 2 | --- a/usr/include/urcu/uatomic/generic.h 2014-10-22 15:00:58.000000000 -0700 3 | +++ b/usr/include/urcu/uatomic/generic.h 2020-10-30 21:38:28.550000000 -0700 4 | @@ -69,10 +69,10 @@ 5 | #endif 6 | #ifdef UATOMIC_HAS_ATOMIC_SHORT 7 | case 2: 8 | - return __sync_val_compare_and_swap_2(addr, old, _new); 9 | + return __sync_val_compare_and_swap_2((uint16_t*) addr, old, _new); 10 | #endif 11 | case 4: 12 | - return __sync_val_compare_and_swap_4(addr, old, _new); 13 | + return __sync_val_compare_and_swap_4((uint32_t*) addr, old, _new); 14 | #if (CAA_BITS_PER_LONG == 64) 15 | case 8: 16 | return __sync_val_compare_and_swap_8(addr, old, _new); 17 | @@ -109,7 +109,7 @@ 18 | return; 19 | #endif 20 | case 4: 21 | - __sync_and_and_fetch_4(addr, val); 22 | + __sync_and_and_fetch_4((uint32_t*) addr, val); 23 | return; 24 | #if (CAA_BITS_PER_LONG == 64) 25 | case 8: 26 | @@ -148,7 +148,7 @@ 27 | return; 28 | #endif 29 | case 4: 30 | - __sync_or_and_fetch_4(addr, val); 31 | + __sync_or_and_fetch_4((uint32_t*) addr, val); 32 | return; 33 | #if (CAA_BITS_PER_LONG == 64) 34 | case 8: 35 | @@ -187,7 +187,7 @@ 36 | return __sync_add_and_fetch_2(addr, val); 37 | #endif 38 | case 4: 39 | - return __sync_add_and_fetch_4(addr, val); 40 | + return __sync_add_and_fetch_4((uint32_t*) addr, val); 41 | #if (CAA_BITS_PER_LONG == 64) 42 | case 8: 43 | return __sync_add_and_fetch_8(addr, val); 44 | -------------------------------------------------------------------------------- /eng/common/cross/armel/sources.list.jessie: -------------------------------------------------------------------------------- 1 | # Debian (jessie) # Stable 2 | deb http://ftp.debian.org/debian/ jessie main contrib non-free 3 | deb-src http://ftp.debian.org/debian/ jessie main contrib non-free 4 | -------------------------------------------------------------------------------- /eng/common/cross/armel/tizen/tizen.patch: -------------------------------------------------------------------------------- 1 | diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so 2 | --- a/usr/lib/libc.so 2016-12-30 23:00:08.284951863 +0900 3 | +++ b/usr/lib/libc.so 2016-12-30 23:00:32.140951815 +0900 4 | @@ -2,4 +2,4 @@ 5 | Use the shared library, but some functions are only in 6 | the static library, so try that secondarily. */ 7 | OUTPUT_FORMAT(elf32-littlearm) 8 | -GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.3 ) ) 9 | +GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux.so.3 ) ) 10 | -------------------------------------------------------------------------------- /eng/common/cross/armv6/sources.list.buster: -------------------------------------------------------------------------------- 1 | deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi 2 | deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi 3 | -------------------------------------------------------------------------------- /eng/common/cross/ppc64le/sources.list.bionic: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/riscv64/sources.list.sid: -------------------------------------------------------------------------------- 1 | deb http://deb.debian.org/debian-ports sid main 2 | -------------------------------------------------------------------------------- /eng/common/cross/s390x/sources.list.bionic: -------------------------------------------------------------------------------- 1 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 2 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe 3 | 4 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 5 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe 6 | 7 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 8 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted 9 | 10 | deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 11 | deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse 12 | -------------------------------------------------------------------------------- /eng/common/cross/tizen-build-rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ARCH=$1 5 | LINK_ARCH=$ARCH 6 | 7 | case "$ARCH" in 8 | arm) 9 | TIZEN_ARCH="armv7hl" 10 | ;; 11 | armel) 12 | TIZEN_ARCH="armv7l" 13 | LINK_ARCH="arm" 14 | ;; 15 | arm64) 16 | TIZEN_ARCH="aarch64" 17 | ;; 18 | x86) 19 | TIZEN_ARCH="i686" 20 | ;; 21 | x64) 22 | TIZEN_ARCH="x86_64" 23 | LINK_ARCH="x86" 24 | ;; 25 | *) 26 | echo "Unsupported architecture for tizen: $ARCH" 27 | exit 1 28 | esac 29 | 30 | __CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 31 | __TIZEN_CROSSDIR="$__CrossDir/${ARCH}/tizen" 32 | 33 | if [[ -z "$ROOTFS_DIR" ]]; then 34 | echo "ROOTFS_DIR is not defined." 35 | exit 1; 36 | fi 37 | 38 | TIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp 39 | mkdir -p $TIZEN_TMP_DIR 40 | 41 | # Download files 42 | echo ">>Start downloading files" 43 | VERBOSE=1 $__CrossDir/tizen-fetch.sh $TIZEN_TMP_DIR $TIZEN_ARCH 44 | echo "<>Start constructing Tizen rootfs" 47 | TIZEN_RPM_FILES=`ls $TIZEN_TMP_DIR/*.rpm` 48 | cd $ROOTFS_DIR 49 | for f in $TIZEN_RPM_FILES; do 50 | rpm2cpio $f | cpio -idm --quiet 51 | done 52 | echo "<>Start configuring Tizen rootfs" 59 | ln -sfn asm-${LINK_ARCH} ./usr/include/asm 60 | patch -p1 < $__TIZEN_CROSSDIR/tizen.patch 61 | echo "<\\|?@*"() ]', '_' 11 | $SbomGenerationDir = Join-Path $ManifestDirPath $SafeArtifactName 12 | 13 | Write-Host "Artifact name before : $ArtifactName" 14 | Write-Host "Artifact name after : $SafeArtifactName" 15 | 16 | Write-Host "Creating dir $ManifestDirPath" 17 | 18 | # create directory for sbom manifest to be placed 19 | if (!(Test-Path -path $SbomGenerationDir)) 20 | { 21 | New-Item -ItemType Directory -path $SbomGenerationDir 22 | Write-Host "Successfully created directory $SbomGenerationDir" 23 | } 24 | else{ 25 | Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." 26 | } 27 | 28 | Write-Host "Updating artifact name" 29 | Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$SafeArtifactName" 30 | -------------------------------------------------------------------------------- /eng/common/generate-sbom-prep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source="${BASH_SOURCE[0]}" 4 | 5 | # resolve $SOURCE until the file is no longer a symlink 6 | while [[ -h $source ]]; do 7 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 8 | source="$(readlink "$source")" 9 | 10 | # if $source was a relative symlink, we need to resolve it relative to the path where the 11 | # symlink file was located 12 | [[ $source != /* ]] && source="$scriptroot/$source" 13 | done 14 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 15 | . $scriptroot/pipeline-logging-functions.sh 16 | 17 | # replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. 18 | artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" 19 | safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" 20 | 21 | manifest_dir=$1 22 | 23 | # Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly 24 | # with their own overwriting ours. So we create it as a sub directory of the requested manifest path. 25 | sbom_generation_dir="$manifest_dir/$safe_artifact_name" 26 | 27 | if [ ! -d "$sbom_generation_dir" ] ; then 28 | mkdir -p "$sbom_generation_dir" 29 | echo "Sbom directory created." $sbom_generation_dir 30 | else 31 | Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." 32 | fi 33 | 34 | echo "Artifact name before : "$artifact_name 35 | echo "Artifact name after : "$safe_artifact_name 36 | export ARTIFACT_NAME=$safe_artifact_name 37 | echo "##vso[task.setvariable variable=ARTIFACT_NAME]$safe_artifact_name" 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /eng/common/helixpublish.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | msbuild 5 | 6 | 7 | 8 | 9 | %(Identity) 10 | 11 | 12 | 13 | 14 | 15 | $(WorkItemDirectory) 16 | $(WorkItemCommand) 17 | $(WorkItemTimeout) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /eng/common/init-tools-native.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell -NoProfile -NoLogo -ExecutionPolicy ByPass -command "& """%~dp0init-tools-native.ps1""" %*" 3 | exit /b %ErrorLevel% -------------------------------------------------------------------------------- /eng/common/internal/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /eng/common/internal/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /eng/common/loc/P22DotNetHtmlLocalization.lss: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /eng/common/msbuild.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(PositionalBinding=$false)] 2 | Param( 3 | [string] $verbosity = 'minimal', 4 | [bool] $warnAsError = $true, 5 | [bool] $nodeReuse = $true, 6 | [switch] $ci, 7 | [switch] $prepareMachine, 8 | [switch] $excludePrereleaseVS, 9 | [string] $msbuildEngine = $null, 10 | [Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs 11 | ) 12 | 13 | . $PSScriptRoot\tools.ps1 14 | 15 | try { 16 | if ($ci) { 17 | $nodeReuse = $false 18 | } 19 | 20 | MSBuild @extraArgs 21 | } 22 | catch { 23 | Write-Host $_.ScriptStackTrace 24 | Write-PipelineTelemetryError -Category 'Build' -Message $_ 25 | ExitWithExitCode 1 26 | } 27 | 28 | ExitWithExitCode 0 -------------------------------------------------------------------------------- /eng/common/msbuild.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source="${BASH_SOURCE[0]}" 4 | 5 | # resolve $source until the file is no longer a symlink 6 | while [[ -h "$source" ]]; do 7 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 8 | source="$(readlink "$source")" 9 | # if $source was a relative symlink, we need to resolve it relative to the path where the 10 | # symlink file was located 11 | [[ $source != /* ]] && source="$scriptroot/$source" 12 | done 13 | scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" 14 | 15 | verbosity='minimal' 16 | warn_as_error=true 17 | node_reuse=true 18 | prepare_machine=false 19 | extra_args='' 20 | 21 | while (($# > 0)); do 22 | lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")" 23 | case $lowerI in 24 | --verbosity) 25 | verbosity=$2 26 | shift 2 27 | ;; 28 | --warnaserror) 29 | warn_as_error=$2 30 | shift 2 31 | ;; 32 | --nodereuse) 33 | node_reuse=$2 34 | shift 2 35 | ;; 36 | --ci) 37 | ci=true 38 | shift 1 39 | ;; 40 | --preparemachine) 41 | prepare_machine=true 42 | shift 1 43 | ;; 44 | *) 45 | extra_args="$extra_args $1" 46 | shift 1 47 | ;; 48 | esac 49 | done 50 | 51 | . "$scriptroot/tools.sh" 52 | 53 | if [[ "$ci" == true ]]; then 54 | node_reuse=false 55 | fi 56 | 57 | MSBuild $extra_args 58 | ExitWithExitCode 0 59 | -------------------------------------------------------------------------------- /eng/common/native/init-os-and-arch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Use uname to determine what the OS is. 4 | OSName=$(uname -s | tr '[:upper:]' '[:lower:]') 5 | 6 | if command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then 7 | OSName="android" 8 | fi 9 | 10 | case "$OSName" in 11 | freebsd|linux|netbsd|openbsd|sunos|android|haiku) 12 | os="$OSName" ;; 13 | darwin) 14 | os=osx ;; 15 | *) 16 | echo "Unsupported OS $OSName detected!" 17 | exit 1 ;; 18 | esac 19 | 20 | # On Solaris, `uname -m` is discouraged, see https://docs.oracle.com/cd/E36784_01/html/E36870/uname-1.html 21 | # and `uname -p` returns processor type (e.g. i386 on amd64). 22 | # The appropriate tool to determine CPU is isainfo(1) https://docs.oracle.com/cd/E36784_01/html/E36870/isainfo-1.html. 23 | if [ "$os" = "sunos" ]; then 24 | if uname -o 2>&1 | grep -q illumos; then 25 | os="illumos" 26 | else 27 | os="solaris" 28 | fi 29 | CPUName=$(isainfo -n) 30 | else 31 | # For the rest of the operating systems, use uname(1) to determine what the CPU is. 32 | CPUName=$(uname -m) 33 | fi 34 | 35 | case "$CPUName" in 36 | arm64|aarch64) 37 | arch=arm64 38 | ;; 39 | 40 | loongarch64) 41 | arch=loongarch64 42 | ;; 43 | 44 | riscv64) 45 | arch=riscv64 46 | ;; 47 | 48 | amd64|x86_64) 49 | arch=x64 50 | ;; 51 | 52 | armv7l|armv8l) 53 | if (NAME=""; . /etc/os-release; test "$NAME" = "Tizen"); then 54 | arch=armel 55 | else 56 | arch=arm 57 | fi 58 | ;; 59 | 60 | armv6l) 61 | arch=armv6 62 | ;; 63 | 64 | i[3-6]86) 65 | echo "Unsupported CPU $CPUName detected, build might not succeed!" 66 | arch=x86 67 | ;; 68 | 69 | s390x) 70 | arch=s390x 71 | ;; 72 | 73 | ppc64le) 74 | arch=ppc64le 75 | ;; 76 | *) 77 | echo "Unknown CPU $CPUName detected!" 78 | exit 1 79 | ;; 80 | esac 81 | -------------------------------------------------------------------------------- /eng/common/post-build/add-build-to-channel.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)][int] $BuildId, 3 | [Parameter(Mandatory=$true)][int] $ChannelId, 4 | [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, 5 | [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net', 6 | [Parameter(Mandatory=$false)][string] $MaestroApiVersion = '2019-01-16' 7 | ) 8 | 9 | try { 10 | . $PSScriptRoot\post-build-utils.ps1 11 | 12 | # Check that the channel we are going to promote the build to exist 13 | $channelInfo = Get-MaestroChannel -ChannelId $ChannelId 14 | 15 | if (!$channelInfo) { 16 | Write-PipelineTelemetryCategory -Category 'PromoteBuild' -Message "Channel with BAR ID $ChannelId was not found in BAR!" 17 | ExitWithExitCode 1 18 | } 19 | 20 | # Get info about which channel(s) the build has already been promoted to 21 | $buildInfo = Get-MaestroBuild -BuildId $BuildId 22 | 23 | if (!$buildInfo) { 24 | Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "Build with BAR ID $BuildId was not found in BAR!" 25 | ExitWithExitCode 1 26 | } 27 | 28 | # Find whether the build is already assigned to the channel or not 29 | if ($buildInfo.channels) { 30 | foreach ($channel in $buildInfo.channels) { 31 | if ($channel.Id -eq $ChannelId) { 32 | Write-Host "The build with BAR ID $BuildId is already on channel $ChannelId!" 33 | ExitWithExitCode 0 34 | } 35 | } 36 | } 37 | 38 | Write-Host "Promoting build '$BuildId' to channel '$ChannelId'." 39 | 40 | Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId 41 | 42 | Write-Host 'done.' 43 | } 44 | catch { 45 | Write-Host $_ 46 | Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to promote build '$BuildId' to channel '$ChannelId'" 47 | ExitWithExitCode 1 48 | } 49 | -------------------------------------------------------------------------------- /eng/common/post-build/check-channel-consistency.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)][string] $PromoteToChannels, # List of channels that the build should be promoted to 3 | [Parameter(Mandatory=$true)][array] $AvailableChannelIds # List of channel IDs available in the YAML implementation 4 | ) 5 | 6 | try { 7 | . $PSScriptRoot\post-build-utils.ps1 8 | 9 | if ($PromoteToChannels -eq "") { 10 | Write-PipelineTaskError -Type 'warning' -Message "This build won't publish assets as it's not configured to any Maestro channel. If that wasn't intended use Darc to configure a default channel using add-default-channel for this branch or to promote it to a channel using add-build-to-channel. See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#assigning-an-individual-build-to-a-channel for more info." 11 | ExitWithExitCode 0 12 | } 13 | 14 | # Check that every channel that Maestro told to promote the build to 15 | # is available in YAML 16 | $PromoteToChannelsIds = $PromoteToChannels -split "\D" | Where-Object { $_ } 17 | 18 | $hasErrors = $false 19 | 20 | foreach ($id in $PromoteToChannelsIds) { 21 | if (($id -ne 0) -and ($id -notin $AvailableChannelIds)) { 22 | Write-PipelineTaskError -Message "Channel $id is not present in the post-build YAML configuration! This is an error scenario. Please contact @dnceng." 23 | $hasErrors = $true 24 | } 25 | } 26 | 27 | # The `Write-PipelineTaskError` doesn't error the script and we might report several errors 28 | # in the previous lines. The check below makes sure that we return an error state from the 29 | # script if we reported any validation error 30 | if ($hasErrors) { 31 | ExitWithExitCode 1 32 | } 33 | 34 | Write-Host 'done.' 35 | } 36 | catch { 37 | Write-Host $_ 38 | Write-PipelineTelemetryError -Category 'CheckChannelConsistency' -Message "There was an error while trying to check consistency of Maestro default channels for the build and post-build YAML configuration." 39 | ExitWithExitCode 1 40 | } 41 | -------------------------------------------------------------------------------- /eng/common/post-build/nuget-validation.ps1: -------------------------------------------------------------------------------- 1 | # This script validates NuGet package metadata information using this 2 | # tool: https://github.com/NuGet/NuGetGallery/tree/jver-verify/src/VerifyMicrosoftPackage 3 | 4 | param( 5 | [Parameter(Mandatory=$true)][string] $PackagesPath, # Path to where the packages to be validated are 6 | [Parameter(Mandatory=$true)][string] $ToolDestinationPath # Where the validation tool should be downloaded to 7 | ) 8 | 9 | try { 10 | . $PSScriptRoot\post-build-utils.ps1 11 | 12 | $url = 'https://raw.githubusercontent.com/NuGet/NuGetGallery/3e25ad135146676bcab0050a516939d9958bfa5d/src/VerifyMicrosoftPackage/verify.ps1' 13 | 14 | New-Item -ItemType 'directory' -Path ${ToolDestinationPath} -Force 15 | 16 | Invoke-WebRequest $url -OutFile ${ToolDestinationPath}\verify.ps1 17 | 18 | & ${ToolDestinationPath}\verify.ps1 ${PackagesPath}\*.nupkg 19 | } 20 | catch { 21 | Write-Host $_.ScriptStackTrace 22 | Write-PipelineTelemetryError -Category 'NuGetValidation' -Message $_ 23 | ExitWithExitCode 1 24 | } 25 | -------------------------------------------------------------------------------- /eng/common/post-build/publish-using-darc.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)][int] $BuildId, 3 | [Parameter(Mandatory=$true)][int] $PublishingInfraVersion, 4 | [Parameter(Mandatory=$true)][string] $AzdoToken, 5 | [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net', 6 | [Parameter(Mandatory=$true)][string] $WaitPublishingFinish, 7 | [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, 8 | [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters 9 | ) 10 | 11 | try { 12 | . $PSScriptRoot\post-build-utils.ps1 13 | 14 | $darc = Get-Darc 15 | 16 | $optionalParams = [System.Collections.ArrayList]::new() 17 | 18 | if ("" -ne $ArtifactsPublishingAdditionalParameters) { 19 | $optionalParams.Add("--artifact-publishing-parameters") | Out-Null 20 | $optionalParams.Add($ArtifactsPublishingAdditionalParameters) | Out-Null 21 | } 22 | 23 | if ("" -ne $SymbolPublishingAdditionalParameters) { 24 | $optionalParams.Add("--symbol-publishing-parameters") | Out-Null 25 | $optionalParams.Add($SymbolPublishingAdditionalParameters) | Out-Null 26 | } 27 | 28 | if ("false" -eq $WaitPublishingFinish) { 29 | $optionalParams.Add("--no-wait") | Out-Null 30 | } 31 | 32 | & $darc add-build-to-channel ` 33 | --id $buildId ` 34 | --publishing-infra-version $PublishingInfraVersion ` 35 | --default-channels ` 36 | --source-branch main ` 37 | --azdev-pat "$AzdoToken" ` 38 | --bar-uri "$MaestroApiEndPoint" ` 39 | --ci ` 40 | @optionalParams 41 | 42 | if ($LastExitCode -ne 0) { 43 | Write-Host "Problems using Darc to promote build ${buildId} to default channels. Stopping execution..." 44 | exit 1 45 | } 46 | 47 | Write-Host 'done.' 48 | } 49 | catch { 50 | Write-Host $_ 51 | Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels." 52 | ExitWithExitCode 1 53 | } 54 | -------------------------------------------------------------------------------- /eng/common/retain-build.ps1: -------------------------------------------------------------------------------- 1 | 2 | Param( 3 | [Parameter(Mandatory=$true)][int] $buildId, 4 | [Parameter(Mandatory=$true)][string] $azdoOrgUri, 5 | [Parameter(Mandatory=$true)][string] $azdoProject, 6 | [Parameter(Mandatory=$true)][string] $token 7 | ) 8 | 9 | $ErrorActionPreference = 'Stop' 10 | Set-StrictMode -Version 2.0 11 | 12 | function Get-AzDOHeaders( 13 | [string] $token) 14 | { 15 | $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":${token}")) 16 | $headers = @{"Authorization"="Basic $base64AuthInfo"} 17 | return $headers 18 | } 19 | 20 | function Update-BuildRetention( 21 | [string] $azdoOrgUri, 22 | [string] $azdoProject, 23 | [int] $buildId, 24 | [string] $token) 25 | { 26 | $headers = Get-AzDOHeaders -token $token 27 | $requestBody = "{ 28 | `"keepForever`": `"true`" 29 | }" 30 | 31 | $requestUri = "${azdoOrgUri}/${azdoProject}/_apis/build/builds/${buildId}?api-version=6.0" 32 | write-Host "Attempting to retain build using the following URI: ${requestUri} ..." 33 | 34 | try { 35 | Invoke-RestMethod -Uri $requestUri -Method Patch -Body $requestBody -Header $headers -contentType "application/json" 36 | Write-Host "Updated retention settings for build ${buildId}." 37 | } 38 | catch { 39 | Write-Error "Failed to update retention settings for build: $_.Exception.Response.StatusDescription" 40 | exit 1 41 | } 42 | } 43 | 44 | Update-BuildRetention -azdoOrgUri $azdoOrgUri -azdoProject $azdoProject -buildId $buildId -token $token 45 | exit 0 46 | -------------------------------------------------------------------------------- /eng/common/sdl/NuGet.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /eng/common/sdl/init-sdl.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string] $GuardianCliLocation, 3 | [string] $Repository, 4 | [string] $BranchName='master', 5 | [string] $WorkingDirectory, 6 | [string] $GuardianLoggerLevel='Standard' 7 | ) 8 | 9 | $ErrorActionPreference = 'Stop' 10 | Set-StrictMode -Version 2.0 11 | $disableConfigureToolsetImport = $true 12 | $global:LASTEXITCODE = 0 13 | 14 | # `tools.ps1` checks $ci to perform some actions. Since the SDL 15 | # scripts don't necessarily execute in the same agent that run the 16 | # build.ps1/sh script this variable isn't automatically set. 17 | $ci = $true 18 | . $PSScriptRoot\..\tools.ps1 19 | 20 | # Don't display the console progress UI - it's a huge perf hit 21 | $ProgressPreference = 'SilentlyContinue' 22 | 23 | Add-Type -AssemblyName System.IO.Compression.FileSystem 24 | 25 | try { 26 | # if the folder does not exist, we'll do a guardian init and push it to the remote repository 27 | Write-Host 'Initializing Guardian...' 28 | Write-Host "$GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel" 29 | & $GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel 30 | if ($LASTEXITCODE -ne 0) { 31 | Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian init failed with exit code $LASTEXITCODE." 32 | ExitWithExitCode $LASTEXITCODE 33 | } 34 | # We create the mainbaseline so it can be edited later 35 | Write-Host "$GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline" 36 | & $GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline 37 | if ($LASTEXITCODE -ne 0) { 38 | Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian baseline failed with exit code $LASTEXITCODE." 39 | ExitWithExitCode $LASTEXITCODE 40 | } 41 | ExitWithExitCode 0 42 | } 43 | catch { 44 | Write-Host $_.ScriptStackTrace 45 | Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ 46 | ExitWithExitCode 1 47 | } 48 | -------------------------------------------------------------------------------- /eng/common/sdl/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /eng/common/sdl/run-sdl.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string] $GuardianCliLocation, 3 | [string] $WorkingDirectory, 4 | [string] $GdnFolder, 5 | [string] $UpdateBaseline, 6 | [string] $GuardianLoggerLevel='Standard' 7 | ) 8 | 9 | $ErrorActionPreference = 'Stop' 10 | Set-StrictMode -Version 2.0 11 | $disableConfigureToolsetImport = $true 12 | $global:LASTEXITCODE = 0 13 | 14 | try { 15 | # `tools.ps1` checks $ci to perform some actions. Since the SDL 16 | # scripts don't necessarily execute in the same agent that run the 17 | # build.ps1/sh script this variable isn't automatically set. 18 | $ci = $true 19 | . $PSScriptRoot\..\tools.ps1 20 | 21 | # We store config files in the r directory of .gdn 22 | $gdnConfigPath = Join-Path $GdnFolder 'r' 23 | $ValidPath = Test-Path $GuardianCliLocation 24 | 25 | if ($ValidPath -eq $False) 26 | { 27 | Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Invalid Guardian CLI Location." 28 | ExitWithExitCode 1 29 | } 30 | 31 | $gdnConfigFiles = Get-ChildItem $gdnConfigPath -Recurse -Include '*.gdnconfig' 32 | Write-Host "Discovered Guardian config files:" 33 | $gdnConfigFiles | Out-String | Write-Host 34 | 35 | Exec-BlockVerbosely { 36 | & $GuardianCliLocation run ` 37 | --working-directory $WorkingDirectory ` 38 | --baseline mainbaseline ` 39 | --update-baseline $UpdateBaseline ` 40 | --logger-level $GuardianLoggerLevel ` 41 | --config @gdnConfigFiles 42 | Exit-IfNZEC "Sdl" 43 | } 44 | } 45 | catch { 46 | Write-Host $_.ScriptStackTrace 47 | Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ 48 | ExitWithExitCode 1 49 | } 50 | -------------------------------------------------------------------------------- /eng/common/sdl/sdl.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Install-Gdn { 3 | param( 4 | [Parameter(Mandatory=$true)] 5 | [string]$Path, 6 | 7 | [string]$Source = "https://pkgs.dev.azure.com/dnceng/_packaging/Guardian1ESPTUpstreamOrgFeed/nuget/v3/index.json", 8 | 9 | # If omitted, install the latest version of Guardian, otherwise install that specific version. 10 | [string]$Version 11 | ) 12 | 13 | $ErrorActionPreference = 'Stop' 14 | Set-StrictMode -Version 2.0 15 | $disableConfigureToolsetImport = $true 16 | $global:LASTEXITCODE = 0 17 | 18 | # `tools.ps1` checks $ci to perform some actions. Since the SDL 19 | # scripts don't necessarily execute in the same agent that run the 20 | # build.ps1/sh script this variable isn't automatically set. 21 | $ci = $true 22 | . $PSScriptRoot\..\tools.ps1 23 | 24 | $argumentList = @("install", "Microsoft.Guardian.Cli.win-x64", "-Source $Source", "-OutputDirectory $Path", "-NonInteractive", "-NoCache") 25 | 26 | if ($Version) { 27 | $argumentList += "-Version $Version" 28 | } 29 | 30 | Start-Process nuget -Verbose -ArgumentList $argumentList -NoNewWindow -Wait 31 | 32 | $gdnCliPath = Get-ChildItem -Filter guardian.cmd -Recurse -Path $Path 33 | 34 | if (!$gdnCliPath) 35 | { 36 | Write-PipelineTelemetryError -Category 'Sdl' -Message 'Failure installing Guardian' 37 | } 38 | 39 | return $gdnCliPath.FullName 40 | } -------------------------------------------------------------------------------- /eng/common/templates-official/jobs/codeql-build.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md 3 | continueOnError: false 4 | # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job 5 | jobs: [] 6 | # Optional: if specified, restore and use this version of Guardian instead of the default. 7 | overrideGuardianVersion: '' 8 | 9 | jobs: 10 | - template: /eng/common/templates-official/jobs/jobs.yml 11 | parameters: 12 | enableMicrobuild: false 13 | enablePublishBuildArtifacts: false 14 | enablePublishTestResults: false 15 | enablePublishBuildAssets: false 16 | enablePublishUsingPipelines: false 17 | enableTelemetry: true 18 | 19 | variables: 20 | - group: Publish-Build-Assets 21 | # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in 22 | # sync with the packages.config file. 23 | - name: DefaultGuardianVersion 24 | value: 0.109.0 25 | - name: GuardianPackagesConfigFile 26 | value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config 27 | - name: GuardianVersion 28 | value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} 29 | 30 | jobs: ${{ parameters.jobs }} 31 | 32 | -------------------------------------------------------------------------------- /eng/common/templates-official/post-build/common-variables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - group: Publish-Build-Assets 3 | 4 | # Whether the build is internal or not 5 | - name: IsInternalBuild 6 | value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} 7 | 8 | # Default Maestro++ API Endpoint and API Version 9 | - name: MaestroApiEndPoint 10 | value: "https://maestro.dot.net" 11 | - name: MaestroApiAccessToken 12 | value: $(MaestroAccessToken) 13 | - name: MaestroApiVersion 14 | value: "2020-02-20" 15 | 16 | - name: SourceLinkCLIVersion 17 | value: 3.0.0 18 | - name: SymbolToolVersion 19 | value: 1.0.1 20 | 21 | - name: runCodesignValidationInjection 22 | value: false 23 | -------------------------------------------------------------------------------- /eng/common/templates-official/post-build/trigger-subscription.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ChannelId: 0 3 | 4 | steps: 5 | - task: PowerShell@2 6 | displayName: Triggering subscriptions 7 | inputs: 8 | filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 9 | arguments: -SourceRepo $(Build.Repository.Uri) 10 | -ChannelId ${{ parameters.ChannelId }} 11 | -MaestroApiAccessToken $(MaestroAccessToken) 12 | -MaestroApiEndPoint $(MaestroApiEndPoint) 13 | -MaestroApiVersion $(MaestroApiVersion) 14 | -------------------------------------------------------------------------------- /eng/common/templates-official/steps/add-build-to-channel.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ChannelId: 0 3 | 4 | steps: 5 | - task: PowerShell@2 6 | displayName: Add Build to Channel 7 | inputs: 8 | filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 9 | arguments: -BuildId $(BARBuildId) 10 | -ChannelId ${{ parameters.ChannelId }} 11 | -MaestroApiAccessToken $(MaestroApiAccessToken) 12 | -MaestroApiEndPoint $(MaestroApiEndPoint) 13 | -MaestroApiVersion $(MaestroApiVersion) 14 | -------------------------------------------------------------------------------- /eng/common/templates-official/steps/build-reason.yml: -------------------------------------------------------------------------------- 1 | # build-reason.yml 2 | # Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons 3 | # to include steps (',' separated). 4 | parameters: 5 | conditions: '' 6 | steps: [] 7 | 8 | steps: 9 | - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}: 10 | - ${{ parameters.steps }} 11 | - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}: 12 | - ${{ parameters.steps }} 13 | -------------------------------------------------------------------------------- /eng/common/templates-official/steps/component-governance.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | disableComponentGovernance: false 3 | componentGovernanceIgnoreDirectories: '' 4 | 5 | steps: 6 | - ${{ if eq(parameters.disableComponentGovernance, 'true') }}: 7 | - script: echo "##vso[task.setvariable variable=skipComponentGovernanceDetection]true" 8 | displayName: Set skipComponentGovernanceDetection variable 9 | - ${{ if ne(parameters.disableComponentGovernance, 'true') }}: 10 | - task: ComponentGovernanceComponentDetection@0 11 | continueOnError: true 12 | inputs: 13 | ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} -------------------------------------------------------------------------------- /eng/common/templates-official/steps/enable-internal-runtimes.yml: -------------------------------------------------------------------------------- 1 | # Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64' 2 | # variable with the base64-encoded SAS token, by default 3 | 4 | parameters: 5 | - name: federatedServiceConnection 6 | type: string 7 | default: 'dotnetbuilds-internal-read' 8 | - name: outputVariableName 9 | type: string 10 | default: 'dotnetbuilds-internal-container-read-token-base64' 11 | - name: expiryInHours 12 | type: number 13 | default: 1 14 | - name: base64Encode 15 | type: boolean 16 | default: true 17 | 18 | steps: 19 | - ${{ if ne(variables['System.TeamProject'], 'public') }}: 20 | - template: /eng/common/templates-official/steps/get-delegation-sas.yml 21 | parameters: 22 | federatedServiceConnection: ${{ parameters.federatedServiceConnection }} 23 | outputVariableName: ${{ parameters.outputVariableName }} 24 | expiryInHours: ${{ parameters.expiryInHours }} 25 | base64Encode: ${{ parameters.base64Encode }} 26 | storageAccount: dotnetbuilds 27 | container: internal 28 | permissions: rl 29 | -------------------------------------------------------------------------------- /eng/common/templates-official/steps/get-federated-access-token.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: federatedServiceConnection 3 | type: string 4 | - name: outputVariableName 5 | type: string 6 | - name: stepName 7 | type: string 8 | default: 'getFederatedAccessToken' 9 | - name: condition 10 | type: string 11 | default: '' 12 | # Resource to get a token for. Common values include: 13 | # - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps 14 | # - 'https://storage.azure.com/' for storage 15 | # Defaults to Azure DevOps 16 | - name: resource 17 | type: string 18 | default: '499b84ac-1321-427f-aa17-267ca6975798' 19 | - name: isStepOutputVariable 20 | type: boolean 21 | default: false 22 | 23 | steps: 24 | - task: AzureCLI@2 25 | displayName: 'Getting federated access token for feeds' 26 | name: ${{ parameters.stepName }} 27 | ${{ if ne(parameters.condition, '') }}: 28 | condition: ${{ parameters.condition }} 29 | inputs: 30 | azureSubscription: ${{ parameters.federatedServiceConnection }} 31 | scriptType: 'pscore' 32 | scriptLocation: 'inlineScript' 33 | inlineScript: | 34 | $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv 35 | if ($LASTEXITCODE -ne 0) { 36 | Write-Error "Failed to get access token for resource '${{ parameters.resource }}'" 37 | exit 1 38 | } 39 | Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" 40 | Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken" -------------------------------------------------------------------------------- /eng/common/templates-official/steps/publish-logs.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | StageLabel: '' 3 | JobLabel: '' 4 | 5 | steps: 6 | - task: Powershell@2 7 | displayName: Prepare Binlogs to Upload 8 | inputs: 9 | targetType: inline 10 | script: | 11 | New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ 12 | Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ 13 | continueOnError: true 14 | condition: always() 15 | 16 | - task: 1ES.PublishBuildArtifacts@1 17 | displayName: Publish Logs 18 | inputs: 19 | PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' 20 | PublishLocation: Container 21 | ArtifactName: PostBuildLogs 22 | continueOnError: true 23 | condition: always() 24 | -------------------------------------------------------------------------------- /eng/common/templates-official/steps/retain-build.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Optional azure devops PAT with build execute permissions for the build's organization, 3 | # only needed if the build that should be retained ran on a different organization than 4 | # the pipeline where this template is executing from 5 | Token: '' 6 | # Optional BuildId to retain, defaults to the current running build 7 | BuildId: '' 8 | # Azure devops Organization URI for the build in the https://dev.azure.com/ format. 9 | # Defaults to the organization the current pipeline is running on 10 | AzdoOrgUri: '$(System.CollectionUri)' 11 | # Azure devops project for the build. Defaults to the project the current pipeline is running on 12 | AzdoProject: '$(System.TeamProject)' 13 | 14 | steps: 15 | - task: powershell@2 16 | inputs: 17 | targetType: 'filePath' 18 | filePath: eng/common/retain-build.ps1 19 | pwsh: true 20 | arguments: > 21 | -AzdoOrgUri: ${{parameters.AzdoOrgUri}} 22 | -AzdoProject ${{parameters.AzdoProject}} 23 | -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} 24 | -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} 25 | displayName: Enable permanent build retention 26 | env: 27 | SYSTEM_ACCESSTOKEN: $(System.AccessToken) 28 | BUILD_ID: $(Build.BuildId) -------------------------------------------------------------------------------- /eng/common/templates-official/variables/sdl-variables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in 3 | # sync with the packages.config file. 4 | - name: DefaultGuardianVersion 5 | value: 0.109.0 6 | - name: GuardianPackagesConfigFile 7 | value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config -------------------------------------------------------------------------------- /eng/common/templates/jobs/codeql-build.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md 3 | continueOnError: false 4 | # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job 5 | jobs: [] 6 | # Optional: if specified, restore and use this version of Guardian instead of the default. 7 | overrideGuardianVersion: '' 8 | 9 | jobs: 10 | - template: /eng/common/templates/jobs/jobs.yml 11 | parameters: 12 | enableMicrobuild: false 13 | enablePublishBuildArtifacts: false 14 | enablePublishTestResults: false 15 | enablePublishBuildAssets: false 16 | enablePublishUsingPipelines: false 17 | enableTelemetry: true 18 | 19 | variables: 20 | - group: Publish-Build-Assets 21 | # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in 22 | # sync with the packages.config file. 23 | - name: DefaultGuardianVersion 24 | value: 0.109.0 25 | - name: GuardianPackagesConfigFile 26 | value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config 27 | - name: GuardianVersion 28 | value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} 29 | 30 | jobs: ${{ parameters.jobs }} 31 | 32 | -------------------------------------------------------------------------------- /eng/common/templates/post-build/common-variables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | - group: Publish-Build-Assets 3 | 4 | # Whether the build is internal or not 5 | - name: IsInternalBuild 6 | value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} 7 | 8 | # Default Maestro++ API Endpoint and API Version 9 | - name: MaestroApiEndPoint 10 | value: "https://maestro.dot.net" 11 | - name: MaestroApiAccessToken 12 | value: $(MaestroAccessToken) 13 | - name: MaestroApiVersion 14 | value: "2020-02-20" 15 | 16 | - name: SourceLinkCLIVersion 17 | value: 3.0.0 18 | - name: SymbolToolVersion 19 | value: 1.0.1 20 | 21 | - name: runCodesignValidationInjection 22 | value: false 23 | -------------------------------------------------------------------------------- /eng/common/templates/post-build/trigger-subscription.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ChannelId: 0 3 | 4 | steps: 5 | - task: PowerShell@2 6 | displayName: Triggering subscriptions 7 | inputs: 8 | filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 9 | arguments: -SourceRepo $(Build.Repository.Uri) 10 | -ChannelId ${{ parameters.ChannelId }} 11 | -MaestroApiAccessToken $(MaestroAccessToken) 12 | -MaestroApiEndPoint $(MaestroApiEndPoint) 13 | -MaestroApiVersion $(MaestroApiVersion) 14 | -------------------------------------------------------------------------------- /eng/common/templates/steps/add-build-to-channel.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ChannelId: 0 3 | 4 | steps: 5 | - task: PowerShell@2 6 | displayName: Add Build to Channel 7 | inputs: 8 | filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 9 | arguments: -BuildId $(BARBuildId) 10 | -ChannelId ${{ parameters.ChannelId }} 11 | -MaestroApiAccessToken $(MaestroApiAccessToken) 12 | -MaestroApiEndPoint $(MaestroApiEndPoint) 13 | -MaestroApiVersion $(MaestroApiVersion) 14 | -------------------------------------------------------------------------------- /eng/common/templates/steps/build-reason.yml: -------------------------------------------------------------------------------- 1 | # build-reason.yml 2 | # Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons 3 | # to include steps (',' separated). 4 | parameters: 5 | conditions: '' 6 | steps: [] 7 | 8 | steps: 9 | - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}: 10 | - ${{ parameters.steps }} 11 | - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}: 12 | - ${{ parameters.steps }} 13 | -------------------------------------------------------------------------------- /eng/common/templates/steps/component-governance.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | disableComponentGovernance: false 3 | componentGovernanceIgnoreDirectories: '' 4 | 5 | steps: 6 | - ${{ if eq(parameters.disableComponentGovernance, 'true') }}: 7 | - script: echo "##vso[task.setvariable variable=skipComponentGovernanceDetection]true" 8 | displayName: Set skipComponentGovernanceDetection variable 9 | - ${{ if ne(parameters.disableComponentGovernance, 'true') }}: 10 | - task: ComponentGovernanceComponentDetection@0 11 | continueOnError: true 12 | inputs: 13 | ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} -------------------------------------------------------------------------------- /eng/common/templates/steps/enable-internal-runtimes.yml: -------------------------------------------------------------------------------- 1 | # Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64' 2 | # variable with the base64-encoded SAS token, by default 3 | 4 | parameters: 5 | - name: federatedServiceConnection 6 | type: string 7 | default: 'dotnetbuilds-internal-read' 8 | - name: outputVariableName 9 | type: string 10 | default: 'dotnetbuilds-internal-container-read-token-base64' 11 | - name: expiryInHours 12 | type: number 13 | default: 1 14 | - name: base64Encode 15 | type: boolean 16 | default: true 17 | 18 | steps: 19 | - ${{ if ne(variables['System.TeamProject'], 'public') }}: 20 | - template: /eng/common/templates/steps/get-delegation-sas.yml 21 | parameters: 22 | federatedServiceConnection: ${{ parameters.federatedServiceConnection }} 23 | outputVariableName: ${{ parameters.outputVariableName }} 24 | expiryInHours: ${{ parameters.expiryInHours }} 25 | base64Encode: ${{ parameters.base64Encode }} 26 | storageAccount: dotnetbuilds 27 | container: internal 28 | permissions: rl 29 | -------------------------------------------------------------------------------- /eng/common/templates/steps/get-federated-access-token.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: federatedServiceConnection 3 | type: string 4 | - name: outputVariableName 5 | type: string 6 | - name: stepName 7 | type: string 8 | default: 'getFederatedAccessToken' 9 | - name: condition 10 | type: string 11 | default: '' 12 | # Resource to get a token for. Common values include: 13 | # - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps 14 | # - 'https://storage.azure.com/' for storage 15 | # Defaults to Azure DevOps 16 | - name: resource 17 | type: string 18 | default: '499b84ac-1321-427f-aa17-267ca6975798' 19 | - name: isStepOutputVariable 20 | type: boolean 21 | default: false 22 | 23 | steps: 24 | - task: AzureCLI@2 25 | displayName: 'Getting federated access token for feeds' 26 | name: ${{ parameters.stepName }} 27 | ${{ if ne(parameters.condition, '') }}: 28 | condition: ${{ parameters.condition }} 29 | inputs: 30 | azureSubscription: ${{ parameters.federatedServiceConnection }} 31 | scriptType: 'pscore' 32 | scriptLocation: 'inlineScript' 33 | inlineScript: | 34 | $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv 35 | if ($LASTEXITCODE -ne 0) { 36 | Write-Error "Failed to get access token for resource '${{ parameters.resource }}'" 37 | exit 1 38 | } 39 | Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" 40 | Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken" -------------------------------------------------------------------------------- /eng/common/templates/steps/publish-logs.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | StageLabel: '' 3 | JobLabel: '' 4 | 5 | steps: 6 | - task: Powershell@2 7 | displayName: Prepare Binlogs to Upload 8 | inputs: 9 | targetType: inline 10 | script: | 11 | New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ 12 | Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ 13 | continueOnError: true 14 | condition: always() 15 | 16 | - task: PublishBuildArtifacts@1 17 | displayName: Publish Logs 18 | inputs: 19 | PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' 20 | PublishLocation: Container 21 | ArtifactName: PostBuildLogs 22 | continueOnError: true 23 | condition: always() 24 | -------------------------------------------------------------------------------- /eng/common/templates/steps/retain-build.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Optional azure devops PAT with build execute permissions for the build's organization, 3 | # only needed if the build that should be retained ran on a different organization than 4 | # the pipeline where this template is executing from 5 | Token: '' 6 | # Optional BuildId to retain, defaults to the current running build 7 | BuildId: '' 8 | # Azure devops Organization URI for the build in the https://dev.azure.com/ format. 9 | # Defaults to the organization the current pipeline is running on 10 | AzdoOrgUri: '$(System.CollectionUri)' 11 | # Azure devops project for the build. Defaults to the project the current pipeline is running on 12 | AzdoProject: '$(System.TeamProject)' 13 | 14 | steps: 15 | - task: powershell@2 16 | inputs: 17 | targetType: 'filePath' 18 | filePath: eng/common/retain-build.ps1 19 | pwsh: true 20 | arguments: > 21 | -AzdoOrgUri: ${{parameters.AzdoOrgUri}} 22 | -AzdoProject ${{parameters.AzdoProject}} 23 | -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} 24 | -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} 25 | displayName: Enable permanent build retention 26 | env: 27 | SYSTEM_ACCESSTOKEN: $(System.AccessToken) 28 | BUILD_ID: $(Build.BuildId) -------------------------------------------------------------------------------- /eng/common/templates/steps/run-on-unix.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | agentOs: '' 3 | steps: [] 4 | 5 | steps: 6 | - ${{ if ne(parameters.agentOs, 'Windows_NT') }}: 7 | - ${{ parameters.steps }} 8 | -------------------------------------------------------------------------------- /eng/common/templates/steps/run-on-windows.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | agentOs: '' 3 | steps: [] 4 | 5 | steps: 6 | - ${{ if eq(parameters.agentOs, 'Windows_NT') }}: 7 | - ${{ parameters.steps }} 8 | -------------------------------------------------------------------------------- /eng/common/templates/steps/run-script-ifequalelse.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # if parameter1 equals parameter 2, run 'ifScript' command, else run 'elsescript' command 3 | parameter1: '' 4 | parameter2: '' 5 | ifScript: '' 6 | elseScript: '' 7 | 8 | # name of script step 9 | name: Script 10 | 11 | # display name of script step 12 | displayName: If-Equal-Else Script 13 | 14 | # environment 15 | env: {} 16 | 17 | # conditional expression for step execution 18 | condition: '' 19 | 20 | steps: 21 | - ${{ if and(ne(parameters.ifScript, ''), eq(parameters.parameter1, parameters.parameter2)) }}: 22 | - script: ${{ parameters.ifScript }} 23 | name: ${{ parameters.name }} 24 | displayName: ${{ parameters.displayName }} 25 | env: ${{ parameters.env }} 26 | condition: ${{ parameters.condition }} 27 | 28 | - ${{ if and(ne(parameters.elseScript, ''), ne(parameters.parameter1, parameters.parameter2)) }}: 29 | - script: ${{ parameters.elseScript }} 30 | name: ${{ parameters.name }} 31 | displayName: ${{ parameters.displayName }} 32 | env: ${{ parameters.env }} 33 | condition: ${{ parameters.condition }} -------------------------------------------------------------------------------- /eng/common/templates/variables/sdl-variables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in 3 | # sync with the packages.config file. 4 | - name: DefaultGuardianVersion 5 | value: 0.109.0 6 | - name: GuardianPackagesConfigFile 7 | value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config -------------------------------------------------------------------------------- /eng/dependencies.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13.0.3 4 | 10.0.0 5 | 5.1.5 6 | 1.10.4 7 | 3.0.0 8 | 8.0.0 9 | 10 | 11 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.115", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | }, 7 | "tools": { 8 | "dotnet": "8.0.115" 9 | }, 10 | "msbuild-sdks": { 11 | "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.25230.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/hello/Program.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.Hosting; 12 | using Microsoft.Extensions.Logging; 13 | 14 | namespace hello 15 | { 16 | public class Program 17 | { 18 | public static void Main(string[] args) 19 | { 20 | CreateHostBuilder(args).Build().Run(); 21 | } 22 | 23 | public static IHostBuilder CreateHostBuilder(string[] args) => 24 | Host.CreateDefaultBuilder(args) 25 | .ConfigureWebHostDefaults(webBuilder => 26 | { 27 | webBuilder.UseStartup(); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /samples/hello/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/hello/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /samples/hello/hello.benchmarks.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - https://raw.githubusercontent.com/dotnet/crank/main/src/Microsoft.Crank.Jobs.Bombardier/bombardier.yml 3 | 4 | jobs: 5 | server: 6 | sources: 7 | crank: 8 | repository: https://github.com/dotnet/crank 9 | branchOrCommit: main 10 | project: crank/samples/hello/hello.csproj 11 | readyStateText: Application started. 12 | 13 | scenarios: 14 | hello: 15 | application: 16 | job: server 17 | load: 18 | job: bombardier 19 | variables: 20 | serverPort: 5000 21 | path: / 22 | 23 | profiles: 24 | local: 25 | variables: 26 | serverAddress: localhost 27 | jobs: 28 | application: 29 | endpoints: 30 | - http://localhost:5010 31 | load: 32 | endpoints: 33 | - http://localhost:5010 34 | -------------------------------------------------------------------------------- /samples/hello/hello.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/local/local.benchmarks.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - https://raw.githubusercontent.com/dotnet/crank/main/src/Microsoft.Crank.Jobs.Bombardier/bombardier.yml 3 | 4 | jobs: 5 | server: 6 | sources: 7 | hello-sample: 8 | localFolder: ../../samples/hello 9 | project: hello-sample/hello.csproj 10 | readyStateText: Application started. 11 | 12 | scenarios: 13 | hello: 14 | application: 15 | job: server 16 | load: 17 | job: bombardier 18 | variables: 19 | serverPort: 5000 20 | path: / 21 | 22 | profiles: 23 | local: 24 | variables: 25 | serverAddress: localhost 26 | jobs: 27 | application: 28 | endpoints: 29 | - http://localhost:5010 30 | load: 31 | endpoints: 32 | - http://localhost:5010 33 | -------------------------------------------------------------------------------- /samples/micro/Md5VsSha256.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Security.Cryptography; 7 | using BenchmarkDotNet.Attributes; 8 | 9 | namespace Micro 10 | { 11 | public class Md5VsSha256 12 | { 13 | [Params(100, 500)] 14 | public int N { get; set;} 15 | private readonly byte[] data; 16 | 17 | private readonly SHA256 sha256 = SHA256.Create(); 18 | private readonly MD5 md5 = MD5.Create(); 19 | 20 | public Md5VsSha256() 21 | { 22 | data = new byte[N]; 23 | new Random(42).NextBytes(data); 24 | } 25 | 26 | [Benchmark] 27 | public byte[] Sha256() => sha256.ComputeHash(data); 28 | 29 | [Benchmark] 30 | public byte[] Md5() => md5.ComputeHash(data); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/micro/Program.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using BenchmarkDotNet.Running; 10 | 11 | namespace Micro 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/micro/dotnet.benchmarks.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | dotnet: 3 | sources: 4 | performance: 5 | repository: https://github.com/dotnet/performance 6 | branchOrCommit: main 7 | project: performance/src/benchmarks/micro/MicroBenchmarks.csproj 8 | variables: 9 | filterArg: "*" 10 | jobArg: short 11 | arguments: --job {{jobArg}} --filter {{filterArg}} --memory 12 | framework: netcoreapp3.1 13 | options: 14 | benchmarkDotNet: true 15 | 16 | scenarios: 17 | 18 | Linq: 19 | application: 20 | job: dotnet 21 | variables: 22 | filterArg: "*LinqBenchmarks*" 23 | 24 | Sockets: 25 | application: 26 | job: dotnet 27 | variables: 28 | filterArg: "*SocketSendReceivePerfTest*" 29 | 30 | profiles: 31 | local: 32 | jobs: 33 | application: 34 | endpoints: 35 | - http://localhost:5010 36 | -------------------------------------------------------------------------------- /samples/micro/micro.benchmarks.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | benchmarks: 3 | sources: 4 | micro: 5 | localFolder: . 6 | project: micro/micro.csproj 7 | variables: 8 | filterArg: "*" 9 | jobArg: short 10 | arguments: --job {{jobArg}} --filter {{filterArg}} --memory 11 | options: 12 | benchmarkDotNet: true 13 | 14 | scenarios: 15 | Md5VsSha256: 16 | application: 17 | job: benchmarks 18 | 19 | profiles: 20 | local: 21 | jobs: 22 | application: 23 | endpoints: 24 | - http://localhost:5010 25 | -------------------------------------------------------------------------------- /samples/micro/micro.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples/netty/netty.benchmarks.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - https://raw.githubusercontent.com/dotnet/crank/main/src/Microsoft.Crank.Jobs.Wrk/wrk.yml 3 | 4 | variables: 5 | localEndpoint: http://localhost:5010 6 | 7 | jobs: 8 | server: 9 | sources: 10 | techempower: 11 | repository: https://github.com/TechEmpower/FrameworkBenchmarks 12 | branchOrCommit: master 13 | dockerFile: techempower/frameworks/Java/netty/netty.dockerfile 14 | dockerImageName: netty 15 | dockerContextDirectory: techempower/frameworks/Java/netty 16 | port: 8080 17 | 18 | scenarios: 19 | netty: 20 | application: 21 | job: server 22 | load: 23 | job: wrk 24 | variables: 25 | serverPort: 8080 26 | path: /plaintext 27 | 28 | profiles: 29 | local: 30 | variables: 31 | serverAddress: localhost 32 | jobs: 33 | application: 34 | endpoints: 35 | - "{{ localEndpoint }}" 36 | load: 37 | endpoints: 38 | - "{{ localEndpoint }}" 39 | -------------------------------------------------------------------------------- /samples/post/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http.Json; 2 | 3 | Console.WriteLine("Application started."); 4 | 5 | var agentUrl = args[0]; 6 | 7 | Console.WriteLine($"BaseAddress: {agentUrl}"); 8 | 9 | using var httpClient = new HttpClient(); 10 | 11 | var response = await httpClient.PostAsync($"{agentUrl}/metadata?name=cpu&aggregate=max&reduce=max&format=n0&longDescription=Long%20description&shortDescription=Short%20description", new StringContent("")); 12 | 13 | Console.WriteLine(response); 14 | 15 | response = await httpClient.PostAsync($"{agentUrl}/measurement?name=cpu×tamp=2024-02-23T14:00:00Z&value=123.456", new StringContent("")); 16 | 17 | Console.WriteLine(response); 18 | 19 | var statistics = new 20 | { 21 | Metadata = new[] 22 | { 23 | new 24 | { 25 | Name = "metadata1", 26 | Aggregate = "Max", 27 | Reduce = "Max", 28 | Format = "n0", 29 | LongDescription = "Long description 1", 30 | ShortDescription = "Short description 1" 31 | }, 32 | new 33 | { 34 | Name = "metadata2", 35 | Aggregate = "Min", 36 | Reduce = "Min", 37 | Format = "n2", 38 | LongDescription = "Long description 2", 39 | ShortDescription = "Short description 2" 40 | } 41 | }, 42 | 43 | Measurements = new[] 44 | { 45 | new 46 | { 47 | Name = "metadata1", 48 | Timestamp = "2024-02-23T14:00:00Z", 49 | Value = 123.456M 50 | }, 51 | new 52 | { 53 | Name = "metadata2", 54 | Timestamp = "2024-02-23T14:00:00Z", 55 | Value = 123.456M 56 | } 57 | } 58 | }; 59 | 60 | 61 | response = await httpClient.PostAsJsonAsync($"{agentUrl}/statistics", statistics); 62 | 63 | Console.WriteLine(response); 64 | -------------------------------------------------------------------------------- /samples/post/post.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples/precommand/precommand.benchmarks.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - https://raw.githubusercontent.com/dotnet/crank/main/src/Microsoft.Crank.Jobs.Bombardier/bombardier.yml 3 | 4 | commands: 5 | # Assumes that the crank repository is the working directory 6 | buildHello: 7 | - condition: job.environment.platform == "windows" 8 | scriptType: batch 9 | script: dotnet build -c Release -f net8.0 .\samples\hello\hello.csproj 10 | - condition: job.environment.platform != "windows" 11 | scriptType: bash 12 | script: dotnet build -c Release -f net8.0 ./samples/hello/hello.csproj 13 | 14 | jobs: 15 | server: 16 | sources: 17 | hello: 18 | localFolder: ../../artifacts/bin/hello/Release/net8.0 19 | executable: dotnet 20 | arguments: hello/hello.dll 21 | noBuild: true 22 | beforeJob: 23 | - buildHello 24 | readyStateText: Application started. 25 | 26 | scenarios: 27 | hello: 28 | application: 29 | job: server 30 | load: 31 | job: bombardier 32 | variables: 33 | serverPort: 5000 34 | path: / 35 | 36 | profiles: 37 | local: 38 | variables: 39 | serverAddress: localhost 40 | jobs: 41 | application: 42 | endpoints: 43 | - http://localhost:5010 44 | load: 45 | endpoints: 46 | - http://localhost:5010 47 | -------------------------------------------------------------------------------- /samples/scripts/scripts.benchmarks.yml: -------------------------------------------------------------------------------- 1 | defaultScripts: 2 | - | 3 | console.log("this section is loaded by default and before named scripts") 4 | 5 | function percentile(items, th) { 6 | var ordered = items.sort((a, b) => a - b); // by default sort() uses ordinal comparison 7 | index = Math.max(0, Math.round(ordered.length * th / 100) - 1); 8 | return ordered[index]; 9 | } 10 | 11 | scripts: 12 | 13 | # displays a message using all different colors 14 | say_hello: | 15 | console.log("hello") 16 | console.info("world") 17 | console.warn("this is") 18 | console.error("scary") 19 | 20 | # records the current date and time as a custom property 21 | add_current_time: | 22 | benchmarks.properties["time"] = new Date().toISOString(); 23 | 24 | # calculats the allocations per request by using results from application and load 25 | add_allocations_per_request: | 26 | var allocations = benchmarks.jobs.application.results["runtime-counter/alloc-rate"] 27 | var rps = benchmarks.jobs.load.results["wrk/requests"]; 28 | benchmarks.jobs.application.results["alloc-per-request"] = allocations / rps; 29 | 30 | # computes the 95th percentile of the working set from all the data points (measurements) 31 | add_p95_memory: | 32 | var memories = benchmarks.jobs.application.measurements[0] 33 | .filter(m => m.name == "benchmarks/working-set") 34 | .map(x => x.value); 35 | var value = percentile(memories, 95); 36 | console.info(`p95 of working set is ${value}`); 37 | benchmarks.jobs.application.results["benchmarks/working-set/p95"] = value; 38 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/CompositeRelayServer.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Microsoft.AspNetCore.Hosting.Server; 11 | using Microsoft.AspNetCore.Http.Features; 12 | 13 | namespace Microsoft.Crank.Agent 14 | { 15 | public class CompositeServer : IServer 16 | { 17 | private readonly IEnumerable _servers; 18 | 19 | public CompositeServer(IEnumerable servers) 20 | { 21 | if (servers == null) 22 | { 23 | throw new ArgumentNullException(nameof(servers)); 24 | } 25 | 26 | if (servers.Count() < 2) 27 | { 28 | throw new ArgumentException("Expected at least 2 servers.", nameof(servers)); 29 | } 30 | 31 | _servers = servers; 32 | } 33 | public IFeatureCollection Features => _servers.First().Features; 34 | 35 | public void Dispose() 36 | { 37 | foreach (var server in _servers) 38 | { 39 | server.Dispose(); 40 | } 41 | } 42 | 43 | public async Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) where TContext : notnull 44 | { 45 | foreach (var server in _servers) 46 | { 47 | await server.StartAsync(application, cancellationToken); 48 | } 49 | } 50 | 51 | public async Task StopAsync(CancellationToken cancellationToken) 52 | { 53 | foreach (var server in _servers) 54 | { 55 | await server.StopAsync(cancellationToken); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Reflection; 7 | using Microsoft.AspNetCore.Mvc; 8 | 9 | namespace Microsoft.Crank.Agent.Controllers 10 | { 11 | [Route("")] 12 | public class HomeController : Controller 13 | { 14 | [HttpGet] 15 | public IActionResult Index() 16 | { 17 | return RedirectToAction("GetQueue", "Jobs"); 18 | } 19 | 20 | [HttpGet("info")] 21 | public IActionResult Info() 22 | { 23 | return Json(new 24 | { 25 | hw = Startup.Hardware.ToString(), 26 | env = Startup.HardwareVersion.ToString(), 27 | os = Startup.OperatingSystem.ToString(), 28 | arch = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString(), 29 | proc = Environment.ProcessorCount, 30 | version = typeof(HomeController).GetTypeInfo().Assembly.GetCustomAttribute()?.InformationalVersion 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/GZipFileResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Globalization; 6 | using System.IO; 7 | using System.IO.Compression; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Http; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.Net.Http.Headers; 12 | 13 | public class GZipFileResult : ActionResult 14 | { 15 | public GZipFileResult(string filename) 16 | { 17 | FileName = filename; 18 | } 19 | 20 | public string FileName { get; set; } 21 | 22 | public override async Task ExecuteResultAsync(ActionContext context) 23 | { 24 | context.HttpContext.Response.Headers.Append(HeaderNames.Vary, HeaderNames.ContentEncoding); 25 | await using var stream = File.OpenRead(FileName); 26 | 27 | context.HttpContext.Response.Headers["FileLength"] = new FileInfo(FileName).Length.ToString(CultureInfo.InvariantCulture); 28 | 29 | if (context.HttpContext.Request.Headers.TryGetValue(HeaderNames.AcceptEncoding, out var acceptEncoding) 30 | && acceptEncoding.ToString().Contains("gzip")) 31 | { 32 | await using var gzipStream = new GZipStream(context.HttpContext.Response.Body, CompressionLevel.Fastest); 33 | 34 | context.HttpContext.Response.Headers[HeaderNames.ContentEncoding] = "gzip"; 35 | await stream.CopyToAsync(gzipStream); 36 | await stream.FlushAsync(); 37 | await gzipStream.FlushAsync(); 38 | } 39 | else 40 | { 41 | await stream.CopyToAsync(context.HttpContext.Response.Body); 42 | await stream.FlushAsync(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/JobContext.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Microsoft.Crank.Models; 11 | using Microsoft.Diagnostics.NETCore.Client; 12 | 13 | namespace Microsoft.Crank.Agent 14 | { 15 | /// 16 | /// Contains the state of a Job when it's run by the Agent. 17 | /// 18 | public class JobContext 19 | { 20 | public Job Job { get; set; } 21 | public Process Process { get; set; } 22 | public string WorkingDirectory { get; set; } 23 | public Timer Timer { get; set; } 24 | public bool Disposed { get; set; } 25 | public string BenchmarksDir { get; set; } 26 | public DateTime StartMonitorTime { get; set; } = DateTime.UtcNow; 27 | public DateTime NextMeasurement { get; set; } = DateTime.UtcNow; 28 | 29 | public string TempDir { get; set; } 30 | public bool TempDirUsesSourceKey { get; set; } 31 | public Dictionary SourceDirs { get; set; } = new(); 32 | public string DockerImage { get; set; } 33 | public string DockerContainerId { get; set; } 34 | 35 | public ulong EventPipeSessionId { get; set; } 36 | public Task EventPipeTask { get; set; } 37 | public bool EventPipeTerminated { get; set; } 38 | 39 | public EventPipeSession EventPipeSession { get; set; } 40 | public Task CountersTask { get; set; } 41 | public TaskCompletionSource CountersCompletionSource { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/JobResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Crank.Models; 8 | 9 | namespace Microsoft.Crank.Agent 10 | { 11 | public class JobResult 12 | { 13 | public JobResult(Job job, IUrlHelper urlHelper) 14 | { 15 | Id = job.Id; 16 | RunId = job.RunId; 17 | State = job.State.ToString(); 18 | DetailsUrl = urlHelper.ActionLink("GetById", "Jobs", new { Id }); 19 | BuildLogsUrl = urlHelper.ActionLink("BuildLog", "Jobs", new { Id }); 20 | OutputLogsUrl = urlHelper.ActionLink("Output", "Jobs", new { Id }); 21 | } 22 | 23 | public int Id { get; set; } 24 | public string RunId { get; set; } 25 | public string State { get; set;} 26 | public string DetailsUrl { get; set; } 27 | public string BuildLogsUrl { get; set; } 28 | public string OutputLogsUrl { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/MachineCounters/MachineCountersEventSource.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.Tracing; 2 | 3 | namespace Microsoft.Crank.Agent.MachineCounters 4 | { 5 | [EventSource(Name = "MachineCountersEventSource")] 6 | internal class MachineCountersEventSource : EventSource 7 | { 8 | /// 9 | /// Should not be disposed -> is a singleton for the application lifetime 10 | /// 11 | public static readonly MachineCountersEventSource Log = new MachineCountersEventSource(); 12 | 13 | public void WriteCounterValue(string counterName, double value) 14 | => WriteEvent(1, counterName, value); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/MachineCounters/OS/IMachinePerformanceCounterEmitter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Microsoft.Crank.Agent.MachineCounters.OS 4 | { 5 | internal interface IMachinePerformanceCounterEmitter : IDisposable 6 | { 7 | string MeasurementName { get; } 8 | string CounterName { get; } 9 | 10 | bool TryStart(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/Measurements.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Crank.Agent 2 | { 3 | public class Measurements 4 | { 5 | public const string BenchmarksCpu = "benchmarks/cpu"; 6 | public const string BenchmarksCpuRaw = "benchmarks/cpu/raw"; 7 | public const string BenchmarksWorkingSet = "benchmarks/working-set"; 8 | public const string BenchmarksPrivateMemory = "benchmarks/private-memory"; 9 | public const string BenchmarksBuildTime = "benchmarks/build-time"; 10 | public const string BenchmarksStartTime = "benchmarks/start-time"; 11 | public const string BenchmarksPublishedSize = "benchmarks/published-size"; 12 | public const string BenchmarksPublishedNativeAOTSizeRaw = "benchmarks/published-nativeaot-size/raw"; 13 | public const string BenchmarksSymbolsSize = "benchmarks/symbols-size"; 14 | public const string BenchmarksMemorySwap = "benchmarks/memory/swap"; 15 | public const string BenchmarksCpuPeriodsTotal = "benchmarks/cpu/periods/total"; 16 | public const string BenchmarksCpuPeriodsThrottled = "benchmarks/cpu/periods/throttled"; 17 | public const string BenchmarksCpuThrottled = "benchmarks/cpu/throttled"; 18 | public const string BenchmarksNetSdkVersion = "netSdkVersion"; 19 | public const string BenchmarksAspNetCoreVersion = "AspNetCoreVersion"; 20 | public const string BenchmarksNetCoreAppVersion = "NetCoreAppVersion"; 21 | 22 | public const string BenchmarksCpuGlobal = "benchmarks/cpu/global"; 23 | public const string BenchmarksProcessCpuFormat = "benchmarks/{0}/cpu"; 24 | public static string GetBenchmarkProcessCpu(string processName) => string.Format(BenchmarksProcessCpuFormat, processName); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | AdjustTokenPrivileges 2 | AssignProcessToJobObject 3 | CloseHandle 4 | CreateIoCompletionPort 5 | CreateJobObject 6 | CreateProcess 7 | DebugActiveProcessStop 8 | DebugSetProcessKillOnExit 9 | DuplicateHandle 10 | DuplicateTokenEx 11 | GetConsoleWindow 12 | GetCurrentProcess 13 | GetExitCodeProcess 14 | GetProcessAffinityMask 15 | GetProcessGroupAffinity 16 | GetNumaHighestNodeNumber 17 | GetNumaNodeProcessorMaskEx 18 | GetSystemCpuSetInformation 19 | IsProcessInJob 20 | LookupPrivilegeValue 21 | NtQueryInformationProcess 22 | OpenJobObject 23 | OpenProcess 24 | OpenProcessToken 25 | ResumeThread 26 | ReadProcessMemory 27 | QueryInformationJobObject 28 | SetInformationJobObject 29 | ShowWindow 30 | TerminateJobObject 31 | TerminateProcess 32 | VirtualAllocEx 33 | VirtualFreeEx 34 | WaitForSingleObject 35 | WriteProcessMemory 36 | 37 | GROUP_AFFINITY 38 | IO_COUNTERS 39 | JOBOBJECT_BASIC_ACCOUNTING_INFORMATION 40 | JOBOBJECT_CPU_RATE_CONTROL_INFORMATION 41 | JOBOBJECT_EXTENDED_LIMIT_INFORMATION 42 | JOBOBJECT_NET_RATE_CONTROL_INFORMATION 43 | TOKEN_PRIVILEGES 44 | 45 | FILE_ACCESS_RIGHTS 46 | INFINITE 47 | INVALID_HANDLE_VALUE 48 | JOB_OBJECT_ASSIGN_PROCESS 49 | JOB_OBJECT_LIMIT 50 | JOB_OBJECT_MSG_END_OF_JOB_TIME 51 | JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 52 | JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 53 | JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 54 | JOB_OBJECT_MSG_END_OF_PROCESS_TIME 55 | JOB_OBJECT_MSG_EXIT_PROCESS 56 | JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 57 | JOB_OBJECT_MSG_NEW_PROCESS 58 | JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 59 | JOB_OBJECT_NET_RATE_CONTROL_MAX_DSCP_TAG 60 | JOB_OBJECT_SET_ATTRIBUTES 61 | JOB_OBJECT_SET_SECURITY_ATTRIBUTES 62 | JOB_OBJECT_QUERY 63 | JOB_OBJECT_TERMINATE 64 | PROCESS_CREATION_FLAGS 65 | PROCESSINFOCLASS 66 | WIN32_ERROR 67 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/PackageTypes.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Agent 6 | { 7 | internal enum PackageTypes 8 | { 9 | Sdk, 10 | NetCoreApp, 11 | AspNetCore, 12 | WindowsDesktop 13 | } 14 | } -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/ProcessResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Agent 6 | { 7 | public class ProcessResult 8 | { 9 | public ProcessResult(int exitCode, string standardOutput, string standardError) 10 | { 11 | ExitCode = exitCode; 12 | StandardOutput = standardOutput; 13 | StandardError = standardError; 14 | } 15 | 16 | public string StandardOutput { get; } 17 | public string StandardError { get; } 18 | public int ExitCode { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/Repository/IIdentifiable.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Repository 6 | { 7 | public interface IIdentifiable 8 | { 9 | int Id { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/Repository/IJobRepository.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | using Microsoft.Crank.Models; 7 | 8 | namespace Repository 9 | { 10 | public interface IJobRepository 11 | { 12 | Job Add(Job item); 13 | IEnumerable GetAll(); 14 | Job Find(int id); 15 | Job Remove(int id); 16 | void Update(Job item); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Agent/Repository/InMemoryJobRepository.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Concurrent; 7 | using System.Collections.Generic; 8 | using Microsoft.Crank.Models; 9 | 10 | namespace Repository 11 | { 12 | public class InMemoryJobRepository : IJobRepository 13 | { 14 | private readonly object _lock = new object(); 15 | private readonly ConcurrentDictionary _items = new ConcurrentDictionary(); 16 | private int _nextId = 1; 17 | 18 | public Job Add(Job item) 19 | { 20 | if (item.Id != 0) 21 | { 22 | throw new ArgumentException("item.Id must be 0."); 23 | } 24 | 25 | lock (_lock) 26 | { 27 | var id = _nextId; 28 | _nextId++; 29 | item.Id = id; 30 | _items[id] = item; 31 | return item; 32 | } 33 | } 34 | 35 | public Job Find(int id) 36 | { 37 | _items.TryGetValue(id, out var job); 38 | 39 | return job; 40 | } 41 | 42 | public IEnumerable GetAll() 43 | { 44 | return _items.Values; 45 | } 46 | 47 | public Job Remove(int id) 48 | { 49 | _items.TryRemove(id, out var job); 50 | 51 | return job; 52 | } 53 | 54 | public void Update(Job item) 55 | { 56 | var oldItem = Find(item.Id); 57 | 58 | if (!object.ReferenceEquals(item, oldItem)) 59 | { 60 | _items[item.Id] = item; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/DotNetToolSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/Microsoft.Crank.AzureDevOpsWorker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Execute crank jobs added to an Azure Service Bus queue by Azure DevOps. 6 | crank-azdo 7 | crank-azdo 8 | true 9 | true 10 | Exe 11 | Microsoft 12 | Microsoft.Crank.AzureDevOpsWorker 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | true 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/ProcessResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.AzureDevOpsWorker 6 | { 7 | public class ProcessResult 8 | { 9 | public ProcessResult(int exitCode, string output, string error) 10 | { 11 | ExitCode = exitCode; 12 | Output = output; 13 | Error = error; 14 | } 15 | 16 | public string Error { get; } 17 | public int ExitCode { get; } 18 | public string Output { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/Records.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Crank.AzureDevOpsWorker 2 | { 3 | public class Records 4 | { 5 | public int Count { get; set; } 6 | public Record[] Value { get; set; } 7 | } 8 | 9 | public class Record 10 | { 11 | public string Id { get; set; } 12 | public string State { get; set; } // "completed", "pending" 13 | public string Result { get; set; } // "succeeded", "skipped", "failed", null 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/RetryHandler.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Net.Http; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Microsoft.Crank.AzureDevOpsWorker 11 | { 12 | internal class RetryHandler : DelegatingHandler 13 | { 14 | private const int MaxRetries = 3; 15 | 16 | public RetryHandler(HttpMessageHandler innerHandler) 17 | : base(innerHandler) 18 | { } 19 | 20 | protected override async Task SendAsync( 21 | HttpRequestMessage request, 22 | CancellationToken cancellationToken) 23 | { 24 | HttpResponseMessage response = null; 25 | for (var i = 0; i < MaxRetries; i++) 26 | { 27 | response = await base.SendAsync(request, cancellationToken); 28 | if (response.IsSuccessStatusCode) 29 | { 30 | return response; 31 | } 32 | 33 | Console.WriteLine($"Request failed ({response.StatusCode}), retrying..."); 34 | 35 | response.Dispose(); 36 | 37 | // Wait 1 second before retrying 38 | await Task.Delay(1000, cancellationToken); 39 | } 40 | 41 | return response; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.AzureDevOpsWorker/TimeSpanConverter.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Text.Json; 7 | using System.Text.Json.Serialization; 8 | 9 | namespace Microsoft.Crank.AzureDevOpsWorker 10 | { 11 | public class TimeSpanConverter : JsonConverter 12 | { 13 | public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 14 | { 15 | return TimeSpan.Parse(reader.GetString()); 16 | } 17 | 18 | public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) 19 | { 20 | writer.WriteStringValue(value.ToString()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ControllerException.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | 7 | namespace Microsoft.Crank.Controller 8 | { 9 | public class ControllerException : Exception 10 | { 11 | public ControllerException(string message) : base(message) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/CounterProfile.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Microsoft.Crank.Controller 10 | { 11 | public class CounterProfile 12 | { 13 | public string Name { get; set; } 14 | public string DisplayName { get; set; } 15 | public string Description { get; set; } 16 | public string Format { get; set; } 17 | public Func, double> Compute { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/DotNetToolSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ExcludeOptions.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Controller 6 | { 7 | public struct ExcludeOptions 8 | { 9 | public static readonly ExcludeOptions Empty = new ExcludeOptions(); 10 | 11 | public int Low; 12 | public int High; 13 | public string Job; 14 | public string Result; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ExecutionResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Microsoft.Crank.Models; 7 | 8 | namespace Microsoft.Crank.Controller 9 | { 10 | public class ExecutionResult 11 | { 12 | public int ReturnCode { get; set; } 13 | 14 | public JobResults JobResults { get; set; } = new JobResults(); 15 | 16 | public Benchmark[] Benchmarks { get; set; } = Array.Empty(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/Headers.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.Crank.Controller 2 | { 3 | public enum Headers 4 | { 5 | None, 6 | Html, 7 | Plaintext, 8 | Json 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/JobDeadlockException.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | 7 | namespace Microsoft.Crank.Controller 8 | { 9 | public class JobDeadlockException : Exception 10 | { 11 | public JobDeadlockException() : base() 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/JobDefinition.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using Newtonsoft.Json.Linq; 8 | 9 | namespace Microsoft.Crank.Controller 10 | { 11 | class JobDefinition : Dictionary 12 | { 13 | public JobDefinition() : base(StringComparer.OrdinalIgnoreCase) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/JobView.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Controller 6 | { 7 | public class JobView 8 | { 9 | public int Id { get; set; } 10 | public string RunId { get; set; } 11 | public string State { get; set;} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/JsonTypeResolver.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Globalization; 7 | using YamlDotNet.Core.Events; 8 | using YamlDotNet.Serialization; 9 | 10 | namespace Microsoft.Crank.Controller 11 | { 12 | /// Provides types resolution for YAML 13 | /// Without this booleans and numbers are parsed as strings 14 | public class JsonTypeResolver : INodeTypeResolver 15 | { 16 | public bool Resolve(NodeEvent nodeEvent, ref Type currentType) 17 | { 18 | if (nodeEvent is Scalar scalar && scalar.IsPlainImplicit) 19 | { 20 | if (decimal.TryParse(scalar.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) 21 | { 22 | currentType = typeof(decimal); 23 | return true; 24 | } 25 | else if (bool.TryParse(scalar.Value, out var b)) 26 | { 27 | currentType = typeof(bool); 28 | return true; 29 | } 30 | } 31 | 32 | return false; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/Microsoft.Crank.Controller.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Schedules jobs on the benchmarks agent. 6 | crank 7 | crank 8 | true 9 | true 10 | Exe 11 | Microsoft 12 | Microsoft.Crank.Controller 13 | 12.0 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ProcessResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.PullRequestBot 6 | { 7 | public class ProcessResult 8 | { 9 | public ProcessResult(int exitCode, string standardOutput, string standardError) 10 | { 11 | ExitCode = exitCode; 12 | StandardOutput = standardOutput; 13 | StandardError = standardError; 14 | } 15 | 16 | public string StandardOutput { get; } 17 | public string StandardError { get; } 18 | public int ExitCode { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ScriptConsole.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Linq; 7 | 8 | namespace Microsoft.Crank.Controller 9 | { 10 | public class ScriptConsole 11 | { 12 | public bool HasErrors { get; private set; } 13 | 14 | public void Log(params object[] args) 15 | { 16 | if (args == null || args.Length == 0) 17 | { 18 | return; 19 | } 20 | 21 | Console.WriteLine(String.Join(" ", args)); 22 | } 23 | 24 | public void Info(params object[] args) 25 | { 26 | if (args == null || args.Length == 0) 27 | { 28 | return; 29 | } 30 | 31 | Console.ForegroundColor = ConsoleColor.Green; 32 | Console.WriteLine(String.Join(" ", args)); 33 | Console.ResetColor(); 34 | } 35 | 36 | public void Warn(params object[] args) 37 | { 38 | if (args == null || args.Length == 0) 39 | { 40 | return; 41 | } 42 | 43 | Console.ForegroundColor = ConsoleColor.DarkYellow; 44 | Console.WriteLine(String.Join(" ", args)); 45 | Console.ResetColor(); 46 | } 47 | 48 | public void Error(params object[] args) 49 | { 50 | if (args == null || args.Length == 0) 51 | { 52 | return; 53 | } 54 | 55 | Console.ForegroundColor = ConsoleColor.Red; 56 | Console.WriteLine(String.Join(" ", args)); 57 | Console.ResetColor(); 58 | 59 | HasErrors = true; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/ScriptFile.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.IO; 7 | 8 | namespace Microsoft.Crank.Controller 9 | { 10 | public class ScriptFile 11 | { 12 | public string ReadFile(string filename) 13 | { 14 | if (string.IsNullOrEmpty(filename)) 15 | { 16 | return null; 17 | } 18 | 19 | return File.ReadAllText(filename); 20 | } 21 | 22 | public void WriteFile(string filename, string data) 23 | { 24 | if (String.IsNullOrEmpty(filename)) 25 | { 26 | return; 27 | } 28 | 29 | File.WriteAllText(filename, data); 30 | } 31 | 32 | public bool Exists(string filename) 33 | { 34 | return !String.IsNullOrEmpty(filename) && File.Exists(filename); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Controller/VariableParser.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Globalization; 7 | using McMaster.Extensions.CommandLineUtils.Abstractions; 8 | using Newtonsoft.Json.Linq; 9 | 10 | namespace Microsoft.Crank.Controller 11 | { 12 | public class VariableParser : IValueParser 13 | { 14 | public Type TargetType { get; } = typeof(ValueTuple); 15 | 16 | public object Parse(string argName, string value, CultureInfo culture) 17 | { 18 | if (string.IsNullOrWhiteSpace(value)) 19 | { 20 | return default(ValueTuple); 21 | } 22 | 23 | var fragments = value!.Split('=', 2); 24 | 25 | var variableKey = fragments[0].Trim(); 26 | 27 | try 28 | { 29 | // variable value, a json format value, such as json object, array, number, etc. 30 | var variableValue = JToken.Parse(fragments[1].Trim()); 31 | 32 | return (variableKey, variableValue); 33 | } 34 | catch (Exception ex) 35 | { 36 | throw new FormatException( 37 | $"Invalid {argName} argument: '{variableKey}' is not a valid JSON value.", 38 | ex); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.EventSources/Microsoft.Crank.EventSources.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | Helper classes to register metrics with the Microsoft.Crank tools. 7 | true 8 | Microsoft 9 | Microsoft.Crank.EventSources 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.EventSources/Operations.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.EventSources 6 | { 7 | public enum Operations 8 | { 9 | First, 10 | Last, 11 | Avg, 12 | Sum, 13 | Median, 14 | Max, 15 | Min, 16 | Count, 17 | All, 18 | Delta // Difference between min and max of the set 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.JobOjectWrapper/Microsoft.Crank.JobObjectWrapper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.JobOjectWrapper/Program.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Diagnostics; 6 | 7 | if (args.Length == 0) 8 | { 9 | Console.WriteLine("Arguments are missing."); 10 | Environment.Exit(-1); 11 | } 12 | 13 | var time = 1000; 14 | Console.WriteLine("Job Object Wrapper"); 15 | Console.WriteLine($"Waiting for Job Object to be setup... {time}"); 16 | 17 | await Task.Delay(time); 18 | 19 | var process = new Process() 20 | { 21 | StartInfo = { 22 | FileName = args[0], 23 | Arguments = string.Join(" ", args[1..]), 24 | UseShellExecute = false 25 | } 26 | }; 27 | 28 | Console.WriteLine("Starting process..."); 29 | Console.WriteLine($"Filename: {process.StartInfo.FileName}"); 30 | Console.WriteLine($"Args: {process.StartInfo.Arguments}"); 31 | 32 | process.Start(); 33 | Console.Error.WriteLine($"##ChildProcessId:{process.Id}"); 34 | process.WaitForExit(); 35 | 36 | await Task.Delay(1000); 37 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Bombardier/Microsoft.Crank.Jobs.Bombardier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.H2Load/Microsoft.Crank.Jobs.H2Load.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.H2Load/h2load.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | headers: 3 | none: '' 4 | grpc: '--header "content-type: application/grpc" --header "TE: trailers"' 5 | grpcDeadline: '--header "content-type: application/grpc" --header "TE: trailers" --header "grpc-timeout: 100S"' 6 | presetHeaders: none 7 | 8 | jobs: 9 | h2LoadClient: 10 | source: 11 | repository: https://github.com/dotnet/crank.git 12 | branchOrCommit: main 13 | project: src/Microsoft.Crank.Jobs.H2Load/Microsoft.Crank.Jobs.H2Load.csproj 14 | sourceKey: h2load 15 | noBuild: true 16 | readyStateText: H2Load Client 17 | waitForExit: true 18 | variables: 19 | threads: 1 20 | streams: 1 21 | connections: 1 22 | requests: 0 23 | duration: 15 24 | warmup: 5 25 | protocol: h2c 26 | body: '' 27 | bodyFile: '' # url for a file to use as the body content 28 | presetHeaders: none 29 | serverScheme: http 30 | serverAddress: localhost 31 | serverPort: 5000 32 | arguments: "-c {{connections}} -t {{threads}} -m {{streams}} -d {{duration}} -w {{warmup}} -n {{requests}} -u {% if serverUri == blank %} {{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}} {% else %} {{serverUri}}:{{serverPort}}{{path}} {% endif %} -p {{ protocol }} {{headers[presetHeaders]}} {% if body != blank %} --body {{ body }} {% endif %} {% if bodyFile != blank %} --bodyFile {{ bodyFile }} {% endif %}" 33 | options: 34 | requiredOperatingSystem: linux 35 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/Microsoft.Crank.Jobs.HttpClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | Latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/Runner.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Net.Http; 6 | using Jint; 7 | 8 | namespace Microsoft.Crank.Jobs.HttpClientClient 9 | { 10 | internal class Worker 11 | { 12 | public HttpMessageInvoker Invoker { get; set; } 13 | public SocketsHttpHandler Handler { get; set; } 14 | public Engine Script { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/ScriptConsole.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Linq; 7 | 8 | namespace Microsoft.Crank.Jobs.HttpClientClient 9 | { 10 | internal class ScriptConsole 11 | { 12 | public bool HasErrors { get; private set; } 13 | 14 | public void Log(params object[] args) 15 | { 16 | Console.WriteLine(String.Join(" ", args.Select(x => x.ToString()))); 17 | } 18 | 19 | public void Info(params object[] args) 20 | { 21 | Console.ForegroundColor = ConsoleColor.Green; 22 | Console.WriteLine(String.Join(" ", args.Select(x => x.ToString()))); 23 | Console.ResetColor(); 24 | } 25 | 26 | public void Warn(params object[] args) 27 | { 28 | Console.ForegroundColor = ConsoleColor.DarkYellow; 29 | Console.WriteLine(String.Join(" ", args.Select(x => x.ToString()))); 30 | Console.ResetColor(); 31 | } 32 | 33 | public void Error(params object[] args) 34 | { 35 | Console.ForegroundColor = ConsoleColor.Red; 36 | Console.WriteLine(String.Join(" ", args.Select(x => x.ToString()))); 37 | Console.ResetColor(); 38 | 39 | HasErrors = true; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/Timeline.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Net.Http; 8 | 9 | namespace Microsoft.Crank.Jobs.HttpClientClient 10 | { 11 | internal class Timeline 12 | { 13 | public Uri Uri { get; set; } 14 | public TimeSpan Delay { get; set; } 15 | public HttpMethod Method { get; set; } 16 | public Dictionary Headers { get; set; } = new Dictionary(); 17 | public HttpContent HttpContent { get; set; } 18 | public string MimeType { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/WorkerResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | 7 | namespace Microsoft.Crank.Jobs.HttpClientClient 8 | { 9 | public class WorkerResult 10 | { 11 | public long AverageRps => (long)(TotalRequests / (Stopped - Started).TotalSeconds); 12 | public long TotalRequests => Status1xx + Status2xx + Status3xx + Status4xx + Status5xx; 13 | public double LatencyMeanMs { get; set; } 14 | public double LatencyMaxMs { get; set; } 15 | public long ThroughputBps { get; set; } 16 | public long DurationMs => (long)(Stopped - Started).TotalMilliseconds; 17 | public long BadResponses => Status1xx + Status4xx + Status5xx; 18 | public DateTime Started { get; set; } 19 | public DateTime Stopped { get; set; } 20 | public int Status1xx { get; set; } 21 | public int Status2xx { get; set; } 22 | public int Status3xx { get; set; } 23 | public int Status4xx { get; set; } 24 | public int Status5xx { get; set; } 25 | public int SocketErrors { get; set; } 26 | public int Connections { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/scripts/log.js: -------------------------------------------------------------------------------- 1 | // Logs all request and their result 2 | 3 | function request(request, warmup) { 4 | console.info(`url: ${request.requestUri}`); 5 | } 6 | 7 | function response(response, warmup) { 8 | console.warn(`status: ${response.statusCode}`); 9 | } 10 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/scripts/script.js: -------------------------------------------------------------------------------- 1 | // Sample script file for HttpClient Crank client 2 | 3 | // This script has the same lifetime as the HttpClient thread. 4 | 5 | // Available properties: 6 | // - console 7 | // log(args) 8 | // info(args) 9 | // warn(args) 10 | // error(args) 11 | // hasErrors: bool 12 | 13 | function initialize(url, connections, warmup, duration, headers, version, quiet) { 14 | 15 | // Invoked before the client is created. Once per thread. 16 | // url: String 17 | // connections: Number 18 | // warmup: Number 19 | // duration: Number 20 | // headers: List (Array) 21 | // version: String 22 | // quiet: Boolean 23 | } 24 | 25 | function start(handler, requests) { 26 | 27 | // Invoked before the benchmark is started. Once per thread. 28 | // handler: System.Net.Http.SocketsHttpHandler 29 | // requests: List (Array) 30 | 31 | } 32 | 33 | function request(request, warmup) { 34 | 35 | // Invoked when a request is created. 36 | // request: System.Net.Http.HttpRequestMessage 37 | // warmup: bool 38 | 39 | } 40 | 41 | function response(response, warmup) { 42 | 43 | // Invoked when a request is created. 44 | // response: System.Net.Http.HttpResponseMessage 45 | // warmup: bool 46 | 47 | } 48 | 49 | function error(exception) { 50 | 51 | // Invoked when an error occurs 52 | // exception: System.Exception 53 | 54 | } 55 | 56 | function stop(handler) { 57 | 58 | // Invoked when a client is stopped. 59 | // handler: System.Net.Http.SocketsHttpHandler 60 | 61 | } -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.HttpClient/scripts/urls.js: -------------------------------------------------------------------------------- 1 | // Add custom requests dynamically 2 | 3 | function start(handler, requests) { 4 | requests.Clear(); 5 | requests.Add(new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://orchardcore.net")); 6 | } 7 | 8 | function request(request, warmup) { 9 | console.warn(`url: ${request.requestUri}`); 10 | } 11 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.K6/Microsoft.Crank.Jobs.K6.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.K6/k6.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | k6: 3 | source: 4 | repository: https://github.com/dotnet/crank.git 5 | branchOrCommit: main 6 | project: src/Microsoft.Crank.Jobs.K6/Microsoft.Crank.Jobs.K6.csproj 7 | sourceKey: k6 8 | noBuild: true 9 | readyStateText: K6 Client 10 | waitForExit: true 11 | variables: 12 | presetHeaders: none 13 | connections: 256 14 | warmup: 15 15 | duration: 15 16 | requests: 0 17 | rate: 0 18 | serverScheme: http 19 | serverAddress: localhost 20 | serverPort: 5000 21 | path: 22 | arguments: '--vus {{connections}} --warmup {{warmup}} --duration {{duration}} {% if requests != 0 %} --iterations {{requests}} {% endif %} {% if rate != 0 %} --rps {{ rate }} {% endif %} -e URL={{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}} -e HEADERS={{presetHeaders}}' 23 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.K6/scripts/default.js: -------------------------------------------------------------------------------- 1 | import http from 'k6/http'; 2 | import { textSummary } from 'https://jslib.k6.io/k6-summary/0.1.0/index.js'; 3 | 4 | const url = __ENV.URL; 5 | const presetHeaders = __ENV.HEADERS 6 | 7 | export const options = { 8 | summaryTrendStats: ['avg', 'min', 'max', 'p(50)', 'p(75)', 'p(90)', 'p(95)', 'p(99)'] 9 | }; 10 | 11 | export default function () { 12 | 13 | var headers = { 14 | none: {}, 15 | plaintext: { 'Accept': 'text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7', 'Connection': 'keep-alive' }, 16 | html: { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Connection': 'keep-alive' }, 17 | json: { 'Accept': 'application/json,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7', 'Connection': 'keep-alive' }, 18 | connectionclose: { 'Connection': 'close' }, 19 | } 20 | 21 | const params = { 22 | // c.f. https://grafana.com/docs/k6/latest/javascript-api/k6-http/params/ 23 | headers: headers[presetHeaders] 24 | }; 25 | 26 | http.get(url, params); 27 | // console.log(url); 28 | } 29 | 30 | export function handleSummary(data) { 31 | // c.f. https://k6.io/docs/results-output/end-of-test/custom-summary/ 32 | return { 33 | 'stdout': textSummary(data, { indent: ' ', enableColors: false }), // Show the text summary to stdout... 34 | 'summary.json': JSON.stringify(data) // and saves the raw data as JSON in a file 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.PipeliningClient/HttpResponse.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Jobs.PipeliningClient 6 | { 7 | public enum HttpResponseState 8 | { 9 | StartLine, 10 | Headers, 11 | Body, 12 | ChunkedBody, 13 | Completed, 14 | Error 15 | } 16 | 17 | public class HttpResponse 18 | { 19 | public HttpResponseState State { get; set; } = HttpResponseState.StartLine; 20 | public int StatusCode { get; set; } 21 | public long ContentLength { get; set; } 22 | public long ContentLengthRemaining { get; set; } 23 | public bool HasContentLengthHeader { get; set; } 24 | public int LastChunkRemaining { get; set; } 25 | 26 | public void Reset() 27 | { 28 | State = HttpResponseState.StartLine; 29 | StatusCode = default; 30 | ContentLength = default; 31 | ContentLengthRemaining = default; 32 | HasContentLengthHeader = default; 33 | LastChunkRemaining = default; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.PipeliningClient/Microsoft.Crank.Jobs.PipeliningClient.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.PipeliningClient/SequenceReaderExtensions.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Buffers; 7 | 8 | namespace Microsoft.Crank.Jobs.PipeliningClient 9 | { 10 | public static class SequenceReaderExtensions 11 | { 12 | public static bool TryReadTo(this ref SequenceReader sequenceReader, out ReadOnlySpan span, ReadOnlySpan delimiter, bool advancePastDelimiter = true) where T : unmanaged, IEquatable 13 | { 14 | if (sequenceReader.TryReadTo(out ReadOnlySequence sequence, delimiter, advancePastDelimiter)) 15 | { 16 | span = sequence.IsSingleSegment ? sequence.FirstSpan : sequence.ToArray(); 17 | return true; 18 | } 19 | span = default; 20 | return false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.PipeliningClient/WorkerResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | namespace Microsoft.Crank.Jobs.PipeliningClient 9 | { 10 | public class WorkerResult 11 | { 12 | public int Status1xx { get; set; } 13 | public int Status2xx { get; set; } 14 | public int Status3xx { get; set; } 15 | public int Status4xx { get; set; } 16 | public int Status5xx { get; set; } 17 | public int SocketErrors { get; set; } 18 | public List StatusCodes { get; set; } = new(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.PipeliningClient/pipelining.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | headers: 3 | none: '' 4 | plaintext: '--header "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7"' 5 | html: '--header "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"' 6 | json: '--header "Accept: application/json,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7"' 7 | connectionclose: '--header "Connection: close"' 8 | presetHeaders: none 9 | 10 | jobs: 11 | pipelining: 12 | source: 13 | repository: https://github.com/dotnet/crank.git 14 | branchOrCommit: main 15 | project: src/Microsoft.Crank.Jobs.PipeliningClient/Microsoft.Crank.Jobs.PipeliningClient.csproj 16 | readyStateText: Pipelining Client 17 | isConsoleApp: true 18 | waitForExit: true 19 | variables: 20 | connections: 256 21 | warmup: 15 22 | duration: 15 23 | pipeline: 1 24 | presetHeaders: none 25 | serverScheme: http 26 | serverAddress: localhost 27 | serverPort: 5000 28 | path: / 29 | customHeaders: [ ] # list of headers with the format: ': ', e.g. [ 'content-type: application/json' ]. In yml should look like: - "content-type: application/json" 30 | detailedResponseStats: false 31 | verboseConnectionLogs: false 32 | arguments: "--url \"{{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}}\" --connections {{connections}} --warmup {{warmup}} --duration {{duration}} --pipeline {{pipeline}} {{headers[presetHeaders]}} {% for h in customHeaders %}{% assign s = h | split : ':' %}--header \"{{ s[0] }}: {{ s[1] | strip }}\" {% endfor %} {% if detailedResponseStats == true %} --detailedResponseStats {% endif %} {% if verboseConnectionLogs == true %} --verboseConnectionLogs {% endif %}" 33 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Wrk/Microsoft.Crank.Jobs.Wrk.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Wrk/Program.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Threading.Tasks; 8 | 9 | namespace Microsoft.Crank.Wrk 10 | { 11 | class Program 12 | { 13 | static async Task Main(string[] args) 14 | { 15 | if (Environment.OSVersion.Platform != PlatformID.Unix) 16 | { 17 | Console.WriteLine($"Platform not supported: {Environment.OSVersion.Platform}"); 18 | return -1; 19 | } 20 | 21 | Console.WriteLine("WRK Client"); 22 | Console.WriteLine("args: " + string.Join(' ', args)); 23 | 24 | await WrkProcess.MeasureFirstRequest(args); 25 | 26 | await WrkProcess.DownloadWrkAsync(); 27 | return await WrkProcess.RunAsync(args); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Wrk/scripts/pipeline.lua: -------------------------------------------------------------------------------- 1 | init = function(args) 2 | local r = {} 3 | local depth = tonumber(args[1]) or 1 4 | for i=1,depth do 5 | r[i] = wrk.format() 6 | end 7 | req = table.concat(r) 8 | end 9 | 10 | request = function() 11 | return req 12 | end -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Wrk2/Microsoft.Crank.Jobs.Wrk2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Jobs.Wrk2/wrk2.yml: -------------------------------------------------------------------------------- 1 | # Warning 2 | # wrk2 might not return any value if the duration is too small (<15s) 3 | 4 | variables: 5 | headers: 6 | none: '' 7 | plaintext: '--header "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7" --header "Connection: keep-alive"' 8 | html: '--header "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" --header "Connection: keep-alive"' 9 | json: '--header "Accept: application/json,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7" --header "Connection: keep-alive"' 10 | connectionclose: '--header "Connection: close"' 11 | presetHeaders: none 12 | 13 | jobs: 14 | wrk2: 15 | source: 16 | repository: https://github.com/dotnet/crank.git 17 | branchOrCommit: main 18 | project: src/Microsoft.Crank.Jobs.Wrk2/Microsoft.Crank.Jobs.Wrk2.csproj 19 | isConsoleApp: true 20 | waitForExit: true 21 | variables: 22 | connections: 256 23 | duration: 15 24 | timeout: # timeout in seconds (optional) 25 | warmup: 15 26 | threads: 32 27 | rate: 500 28 | serverScheme: http 29 | serverAddress: localhost 30 | serverPort: 5000 31 | path: / 32 | customHeaders: [ ] # list of headers with the format: ': ', e.g. [ 'content-type: application/json' ] 33 | arguments: "-c {{connections}} -d {{duration}}s -w {{warmup}}s {% if timeout != blank %} --timeout {{timeout}}s {% endif %} -t {{threads}} {{headers[presetHeaders]}} {% for h in customHeaders %}{% assign s = h | split : ':' %}--header \"{{ s[0] }}: {{ s[1] | strip }}\" {% endfor %} -R {{rate}} -L {% if serverUri == blank %} {{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}} {% else %} {{serverUri}}:{{serverPort}}{{path}} {% endif %}" 34 | options: 35 | requiredOperatingSystem: linux 36 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Attachment.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public class Attachment 8 | { 9 | public string Filename { get; set; } 10 | public string TempFilename { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/AttachmentViewModel.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Microsoft.AspNetCore.Http; 6 | 7 | namespace Microsoft.Crank.Models 8 | { 9 | public class AttachmentViewModel 10 | { 11 | public int Id { get; set; } 12 | public string DestinationFilename { get; set; } 13 | public IFormFile Content { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/CommandDefinition.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.Crank.Models 8 | { 9 | public class CommandDefinition 10 | { 11 | public string Condition { get; set; } = "true"; 12 | public ScriptType ScriptType { get; set; } = ScriptType.Powershell; 13 | public string Script { get; set; } 14 | public string FilePath { get; set; } 15 | public bool ContinueOnError { get; set; } = false; 16 | public List SuccessExitCodes { get; set; } = new List { 0 }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Database.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum Database 8 | { 9 | None, 10 | PostgreSql, 11 | SqlServer, 12 | MySql, 13 | MongoDb, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Dependency.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public class Dependency 8 | { 9 | public string Id { get; set; } 10 | public string[] Names { get; set; } 11 | public string RepositoryUrl { get; set; } 12 | public string Version { get; set; } 13 | public string CommitHash { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/DotnetCounter.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public class DotnetCounter 8 | { 9 | /// 10 | /// Provider name, e.g., System.Runtime 11 | /// 12 | public string Provider { get; set; } 13 | 14 | /// 15 | /// Name of the counter, cpu-usage 16 | /// 17 | public string Name { get; set; } 18 | 19 | /// 20 | /// Name of the measurement, runtime/cpu-usage 21 | /// 22 | public string Measurement { get; set; } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/DumpTypeOption.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | /// 8 | /// The dump type determines the kinds of information that are collected from the process. 9 | /// 10 | public enum DumpTypeOption 11 | { 12 | Full, // The largest dump containing all memory including the module images. 13 | 14 | Heap, // A large and relatively comprehensive dump containing module lists, thread lists, all 15 | // stacks, exception information, handle information, and all memory except for mapped images. 16 | 17 | Mini, // A small dump containing module lists, thread lists, exception information and all stacks. 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/EnvironmentData.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace Microsoft.Crank.Models 9 | { 10 | /// 11 | /// A model that stores information about the environment of the current process. 12 | /// This is useful when defining conditions for pre or post commands on the controller. 13 | /// 14 | public class EnvironmentData 15 | { 16 | private static readonly string platform = GetCurrentPlatform(); 17 | private static readonly string architecture = RuntimeInformation.OSArchitecture.ToString(); 18 | 19 | public string Platform => platform; 20 | public string Architecture => architecture; 21 | 22 | private static string GetCurrentPlatform() 23 | { 24 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 25 | { 26 | return "windows"; 27 | } 28 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 29 | { 30 | return "linux"; 31 | } 32 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 33 | { 34 | return "osx"; 35 | } 36 | else 37 | { 38 | // Windows, Linux, and OSX are the only platforms that have predefined OSPlatform instances. 39 | return "other"; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/JobState.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum JobState 8 | { 9 | New, // The job was submitted 10 | Initializing, // The job is processed, the driver update it or submit attachments 11 | Waiting, // The job is ready to start, following a POST from the client to /start 12 | Starting, // The application has been started, the server is waiting for it to be responsive 13 | Running, // The application is running 14 | Failed, 15 | Stopping, 16 | Stopped, 17 | TraceCollecting, // The driver has requested the trace to be collected 18 | TraceCollected, 19 | Deleting, 20 | Deleted, 21 | NotSupported, // The job is not supported by the server 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/JobStatistics.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.Crank.Models 8 | { 9 | public class JobStatistics 10 | { 11 | public List Metadata = new List(); 12 | public List Measurements = new List(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Measurement.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Newtonsoft.Json; 7 | 8 | namespace Microsoft.Crank.Models 9 | { 10 | public class Measurement 11 | { 12 | public const string Delimiter = "$$Delimiter$$"; 13 | 14 | public DateTime Timestamp { get; set; } 15 | public string Name { get; set; } 16 | public object Value { get; set; } 17 | 18 | [JsonIgnore] 19 | public bool IsDelimiter => String.Equals(Name, Delimiter, StringComparison.OrdinalIgnoreCase); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/MeasurementMetadata.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Newtonsoft.Json; 6 | using Newtonsoft.Json.Converters; 7 | 8 | namespace Microsoft.Crank.Models 9 | { 10 | public class MeasurementMetadata 11 | { 12 | public string Source { get; set; } 13 | public string Name { get; set; } 14 | 15 | /// 16 | /// An operation used to aggregate the value across multiple sources returning the same measurement 17 | /// 18 | [JsonConverter(typeof(StringEnumConverter))] 19 | public Operation Reduce { get; set; } 20 | 21 | /// 22 | /// An operation used to aggregate the measures from the same source 23 | /// 24 | [JsonConverter(typeof(StringEnumConverter))] 25 | public Operation Aggregate { get; set; } 26 | 27 | public string ShortDescription { get; set; } 28 | public string LongDescription { get; set; } 29 | 30 | // A custom C# format string used for numerical values, e.g. "n0" 31 | public string Format { get; set; } 32 | } 33 | 34 | public enum Operation 35 | { 36 | First, 37 | Last, 38 | Avg, 39 | Sum, 40 | Median, 41 | Max, 42 | Min, 43 | Count, 44 | All, 45 | Delta // Difference between min and max of the set 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Microsoft.Crank.Models.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Class to transfer data to/from the benchmark server. 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/OperatingSystem.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum OperatingSystem 8 | { 9 | Linux, 10 | Windows, 11 | OSX 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/Scheme.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum Scheme 8 | { 9 | Http, 10 | Https, 11 | H2, 12 | H2c 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/ScriptType.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum ScriptType 8 | { 9 | Batch, 10 | Bash, 11 | Powershell, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.Models/WebHost.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.Models 6 | { 7 | public enum WebHost 8 | { 9 | KestrelSockets, 10 | KestrelLibuv, 11 | HttpSys, 12 | IISInProcess, 13 | IISOutOfProcess, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/Command.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Octokit; 6 | 7 | namespace Microsoft.Crank.PullRequestBot 8 | { 9 | public class Command 10 | { 11 | public PullRequest PullRequest { get; set; } 12 | public string[] Benchmarks { get; set; } 13 | public string[] Profiles { get; set; } 14 | public string[] Components { get; set; } 15 | public string Arguments { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/Configuration.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using Newtonsoft.Json.Linq; 8 | 9 | namespace Microsoft.Crank.PullRequestBot 10 | { 11 | public class Configuration 12 | { 13 | public string Defaults { get; set; } 14 | public Dictionary Variables { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); 15 | public Dictionary Components { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); 16 | public Dictionary Profiles { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); 17 | public Dictionary Benchmarks { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); 18 | } 19 | 20 | public class Profile 21 | { 22 | public string Description { get; set; } 23 | public string Arguments { get; set; } 24 | } 25 | 26 | public class Benchmark 27 | { 28 | public string Description { get; set; } 29 | public string Arguments { get; set; } 30 | public Dictionary Variables { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); 31 | } 32 | 33 | public class Build 34 | { 35 | public string Script { get; set; } 36 | public string Arguments { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/JsonTypeResolver.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Globalization; 7 | using YamlDotNet.Core.Events; 8 | using YamlDotNet.Serialization; 9 | 10 | namespace Microsoft.Crank.PullRequestBot 11 | { 12 | /// Provides types resolution for YAML 13 | /// Without this booleans and numbers are parsed as strings 14 | public class JsonTypeResolver : INodeTypeResolver 15 | { 16 | public bool Resolve(NodeEvent nodeEvent, ref Type currentType) 17 | { 18 | if (nodeEvent is Scalar scalar && scalar.IsPlainImplicit) 19 | { 20 | if (decimal.TryParse(scalar.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) 21 | { 22 | currentType = typeof(decimal); 23 | return true; 24 | } 25 | else if (bool.TryParse(scalar.Value, out _)) 26 | { 27 | currentType = typeof(bool); 28 | return true; 29 | } 30 | } 31 | 32 | return false; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/Microsoft.Crank.PullRequestBot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Runs benchmarks out of GitHub pull-requests. 6 | crank-pr 7 | crank-pr 8 | true 9 | true 10 | Exe 11 | Microsoft 12 | Microsoft.Crank.PullRequestBot 13 | 9.0 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/PullRequestBotException.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | 7 | namespace Microsoft.Crank.PullRequestBot 8 | { 9 | public class PullRequestBotException : Exception 10 | { 11 | public PullRequestBotException(string message) : base(message) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/sample.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./pullrequestbot.schema.json", 3 | "defaults": "--config https://github.com/aspnet/Benchmarks/blob/main/build/azure.profile.yml?raw=true --application.framework net8.0 ", // --relay AZURE_RELAY 4 | "components": { 5 | "kestrel": { 6 | "script": "call ./src/Servers/Kestrel/build.cmd -noBuildJava -noBuildNodeJs -c release -noBuildNative /p:BuildIisNativeProjects=false", 7 | "arguments": "--application.options.outputFiles ./artifacts/bin/Microsoft.AspNetCore.Server.Kestrel/release/net8.0/" 8 | }, 9 | "mvc": { 10 | "script": "REM Build MVC", 11 | "arguments": "" 12 | } 13 | }, 14 | "profiles": { 15 | "aspnet-perf-lin": { 16 | "description": "INTEL/Linux 12 Cores", 17 | "arguments": "--profile aspnet-perf-lin" 18 | }, 19 | "aspnet-perf-win": { 20 | "description": "INTEL/Windows 12 Cores", 21 | "arguments": "--profile aspnet-perf-win" 22 | } 23 | }, 24 | "benchmarks": { 25 | "plaintext": { 26 | "description": "TechEmpower Plaintext Scenario - ASP.NET Middleware", 27 | "arguments": "--config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/plaintext.benchmarks.yml --scenario plaintext" 28 | }, 29 | "json": { 30 | "description": "TechEmpower JSON Scenario - ASP.NET Middleware", 31 | "arguments": "--config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/json.benchmarks.yml --scenario json" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.PullRequestBot/sample.config.yml: -------------------------------------------------------------------------------- 1 | # multi-line script used to build the project 2 | components: 3 | kestrel: 4 | script: | 5 | call ./src/Servers/Kestrel/build.cmd -noBuildJava -noBuildNodeJs -c release -noBuildNative /p:BuildIisNativeProjects=false 6 | REM call ./.dotnet/dotnet.exe build-server shutdown 7 | REM call taskkill /F /IM dotnet.exe # also kills main process in dotnet.exe 8 | 9 | arguments: 10 | --application.options.outputFiles ./artifacts/bin/Microsoft.AspNetCore.Server.Kestrel/release/net8.0/ 11 | mvc: 12 | script: | 13 | echo FAKE MVC BUILD 14 | # ./src/Servers/Kestrel/build.sh -c release 15 | arguments: 16 | --application.options.outputFiles ./artifacts/bin/Microsoft.AspNetCore.MVC/release/net8.0/ 17 | 18 | # default arguments that are always used on crank commands 19 | defaults: --config https://github.com/aspnet/Benchmarks/blob/main/build/azure.profile.yml?raw=true --application.framework net8.0 # --relay AZURE_RELAY 20 | 21 | # the first value is the default if none is specified 22 | profiles: 23 | aspnet-perf-lin: 24 | description: INTEL/Linux 12 Cores 25 | arguments: --profile aspnet-perf-lin 26 | 27 | aspnet-perf-win: 28 | description: INTEL/Windows 12 Cores 29 | arguments: --profile aspnet-perf-win 30 | 31 | benchmarks: 32 | plaintext: 33 | description: TechEmpower Plaintext Scenario - ASP.NET Middleware 34 | arguments: --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/plaintext.benchmarks.yml --scenario plaintext 35 | 36 | json: 37 | description: TechEmpower JSON Scenario - ASP.NET Middleware 38 | arguments: --config https://raw.githubusercontent.com/aspnet/Benchmarks/main/scenarios/json.benchmarks.yml --scenario json 39 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Configuration.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.Crank.RegressionBot 8 | { 9 | public class Configuration 10 | { 11 | public Dictionary Templates { get; set; } = new Dictionary(); 12 | public List Sources { get; set; } = new List(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/JsonTypeResolver.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Globalization; 7 | using YamlDotNet.Core.Events; 8 | using YamlDotNet.Serialization; 9 | 10 | namespace Microsoft.Crank.RegressionBot 11 | { 12 | /// Provides types resolution for YAML 13 | /// Without this booleans and numbers are parsed as strings 14 | public class JsonTypeResolver : INodeTypeResolver 15 | { 16 | public bool Resolve(NodeEvent nodeEvent, ref Type currentType) 17 | { 18 | if (nodeEvent is Scalar scalar && scalar.IsPlainImplicit) 19 | { 20 | if (decimal.TryParse(scalar.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) 21 | { 22 | currentType = typeof(decimal); 23 | return true; 24 | } 25 | else if (bool.TryParse(scalar.Value, out var b)) 26 | { 27 | currentType = typeof(bool); 28 | return true; 29 | } 30 | } 31 | 32 | return false; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Microsoft.Crank.RegressionBot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | PreserveNewest 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Models/BenchmarksResult.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Newtonsoft.Json.Linq; 7 | 8 | namespace Microsoft.Crank.RegressionBot.Models 9 | { 10 | public class BenchmarksResult 11 | { 12 | public int Id { get; set; } 13 | public bool Excluded { get; set; } 14 | public DateTimeOffset DateTimeUtc { get; set; } 15 | public string Session { get; set; } 16 | public string Scenario { get; set; } 17 | public string Description { get; set; } 18 | public string Document { get; set; } 19 | 20 | [MessagePack.IgnoreMember] 21 | private JObject _data; 22 | 23 | [MessagePack.IgnoreMember] 24 | [System.Text.Json.Serialization.JsonIgnore] 25 | public JObject Data => _data ??= JObject.Parse(Document); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Models/DependencyChange.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.RegressionBot.Models 6 | { 7 | public enum ChangeTypes 8 | { 9 | Diff, 10 | New, 11 | Removed 12 | } 13 | 14 | public class DependencyChange 15 | { 16 | /// 17 | /// e.g., "application", "load" 18 | /// 19 | public string Job { get; set; } 20 | 21 | /// 22 | /// e.g, "+kL3IPaqvdVHIVR8mUBvrw==" 23 | /// 24 | public string Id { get; set; } 25 | 26 | /// 27 | /// e.g, "Microsoft.AspNetCore.App" 28 | /// 29 | public string[] Names { get; set; } 30 | 31 | /// 32 | /// e.g., "https://github.com/dotnet/runtime" 33 | /// 34 | public string RepositoryUrl { get; set; } 35 | 36 | /// 37 | /// e.g., "6.0.0-preview.5.21228.5" 38 | /// 39 | public string PreviousVersion { get; set; } 40 | 41 | /// 42 | /// e.g., "6.0.0-preview.5.21228.5" 43 | /// 44 | public string CurrentVersion { get; set; } 45 | 46 | /// 47 | /// e.g., "52c1d0b9b72f09fa7cf1f491d1c147dc173b7d60" 48 | /// 49 | public string PreviousCommitHash { get; set; } 50 | 51 | /// 52 | /// e.g., "52c1d0b9b72f09fa7cf1f491d1c147dc173b7d60" 53 | /// 54 | public string CurrentCommitHash { get; set; } 55 | 56 | public ChangeTypes ChangeType { get; set; } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Models/Report.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.Crank.RegressionBot.Models 8 | { 9 | /// 10 | /// This class is used as a model for template reports. 11 | /// 12 | public class Report 13 | { 14 | public List Regressions { get; set; } = new List(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Probe.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Microsoft.Crank.RegressionBot 9 | { 10 | public class Probe 11 | { 12 | // The JSON path to the value 13 | public string Path { get; set; } 14 | 15 | // The minimum value triggering an issue 16 | public double Threshold { get; set; } = 1; 17 | 18 | public ThresholdUnits Unit { get; set; } = ThresholdUnits.StDev; 19 | } 20 | 21 | public enum ThresholdUnits 22 | { 23 | None, 24 | StDev, 25 | Percent, 26 | Absolute 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Queries.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | namespace Microsoft.Crank.RegressionBot 6 | { 7 | public static class Queries 8 | { 9 | public const string Latest = """ 10 | SELECT * 11 | FROM ( 12 | SELECT TOP (10000) * -- Bounded to prevent from downloading too many records 13 | FROM [dbo].[{0}] -- Substitute table name 14 | ORDER BY [Id] DESC 15 | ) ORDERED 16 | WHERE [DateTimeUtc] >= @startDate 17 | """; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/RegressionBotException.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | 7 | namespace Microsoft.Crank.RegressionBot 8 | { 9 | public class RegressionBotException : Exception 10 | { 11 | public RegressionBotException(string message) : base(message) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/Rule.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace Microsoft.Crank.RegressionBot 9 | { 10 | public class Rule 11 | { 12 | internal Regex IncludeRegex { get; set; } 13 | internal Regex ExcludeRegex { get; set; } 14 | 15 | public string Include { get; set; } 16 | 17 | public string Exclude { get; set; } 18 | 19 | /// 20 | /// Gets or sets the list of labels to assign to the issues 21 | /// 22 | public List Labels { get; set; } = new List(); 23 | 24 | /// 25 | /// Gets or sets the list of users that are cced in the issue 26 | /// 27 | public List Owners = new List(); 28 | 29 | /// 30 | /// Gets or sets whether the regressions on the scenario should be ignored 31 | /// 32 | public bool? IgnoreRegressions { get; set; } 33 | public bool? IgnoreErrors { get; set; } 34 | public bool? IgnoreFailures { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Microsoft.Crank.RegressionBot/SourceSection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.Crank.RegressionBot 8 | { 9 | public class SourceSection 10 | { 11 | // Whether the bot checks if the benchmarks are still run regularly. 12 | public bool HealthCheck { get; set; } = false; 13 | 14 | // List of measurements that are checked against for regressions. 15 | public List Probes { get; set; } = new List(); 16 | 17 | // Labels added to the issues created. 18 | public List Labels = new List(); 19 | 20 | // Labels added to the issues created. 21 | public List Owners = new List(); 22 | 23 | // The name of the template to use to render regressions for this source. 24 | public string Template { get; set; } = ""; 25 | 26 | // The templated title of the issue. Leave empty for an auto-generated one. 27 | public string Title { get; set; } = ""; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/Microsoft.Crank.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | Microsoft.Crank.IntegrationTests 6 | true 7 | true 8 | XUnit 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/SkipOnLinuxAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Xunit; 3 | 4 | namespace Microsoft.Crank.IntegrationTests 5 | { 6 | class SkipOnLinuxAttribute : FactAttribute 7 | { 8 | public SkipOnLinuxAttribute(string message = null) 9 | { 10 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 11 | { 12 | Skip = message ?? "Test ignored on Linux"; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/SkipOnMacOsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Xunit; 3 | 4 | namespace Microsoft.Crank.IntegrationTests 5 | { 6 | class SkipOnMacOsAttribute : FactAttribute 7 | { 8 | public SkipOnMacOsAttribute(string message = null) 9 | { 10 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 11 | { 12 | Skip = message ?? "Test ignored on OSX"; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/SkipOnWindowsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Xunit; 3 | 4 | namespace Microsoft.Crank.IntegrationTests 5 | { 6 | class SkipOnWindowsAttribute : FactAttribute 7 | { 8 | public SkipOnWindowsAttribute(string message = null) 9 | { 10 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 11 | { 12 | Skip = message ?? "Test ignored on Windows"; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/assets/hello.benchmarks.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | server: 3 | sources: 4 | hello: 5 | localFolder: '../hello' 6 | project: hello/hello.csproj 7 | readyStateText: Application started. 8 | bombardier: 9 | sources: 10 | local: 11 | # uploading the whole source folder since it requires other libraries 12 | localFolder: '../src' 13 | destinationFolder: '' 14 | project: Microsoft.Crank.Jobs.Bombardier/Microsoft.Crank.Jobs.Bombardier.csproj 15 | readyStateText: Bombardier Client 16 | waitForExit: true 17 | variables: 18 | connections: 256 19 | warmup: 3 20 | duration: 3 21 | requests: 0 22 | rate: 0 23 | transport: fasthttp # | http1 | http2 24 | serverScheme: http 25 | serverAddress: localhost 26 | serverPort: 5000 27 | customHeaders: [ ] # list of headers with the format: ': ', e.g. [ 'content-type: application/json' ] 28 | arguments: "-c {{connections}} -w {{warmup}} -d {{duration}} -n {{requests}} --insecure -l {% if rate != 0 %} --rate {{ rate }} {% endif %} {% if transport %} --{{ transport}} {% endif %} {{headers[presetHeaders]}} {% for h in customHeaders %}{% assign s = h | split : ':' %}--header \"{{ s[0] }}: {{ s[1] | strip }}\" {% endfor %} {{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}}" 29 | 30 | scenarios: 31 | hello: 32 | application: 33 | job: server 34 | load: 35 | job: bombardier 36 | variables: 37 | path: / 38 | 39 | profiles: 40 | local: 41 | variables: 42 | serverPort: 5000 43 | serverAddress: localhost 44 | jobs: 45 | application: 46 | endpoints: 47 | - http://localhost:5010 48 | load: 49 | endpoints: 50 | - http://localhost:5010 51 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/assets/multiclient.benchmarks.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | server: 3 | sources: 4 | hello: 5 | localFolder: '../hello' 6 | project: hello/hello.csproj 7 | readyStateText: Application started. 8 | bombardier: 9 | sources: 10 | local: 11 | # uploading the whole source folder since it requires other libraries 12 | localFolder: '../src' 13 | destinationFolder: '' 14 | project: Microsoft.Crank.Jobs.Bombardier/Microsoft.Crank.Jobs.Bombardier.csproj 15 | readyStateText: Bombardier Client 16 | waitForExit: true 17 | variables: 18 | connections: 256 19 | warmup: 3 20 | duration: 3 21 | requests: 0 22 | rate: 0 23 | transport: fasthttp # | http1 | http2 24 | serverScheme: http 25 | serverAddress: localhost 26 | serverPort: 5000 27 | arguments: "-c {{connections}} -w {{warmup}} -d {{duration}} -n {{requests}} --insecure -l {% if rate != 0 %} --rate {{ rate }} {% endif %} {% if transport %} --{{ transport}} {% endif %} {{headers[presetHeaders]}} {{serverScheme}}://{{serverAddress}}:{{serverPort}}{{path}}" 28 | 29 | scenarios: 30 | hello: 31 | application: 32 | job: server 33 | load: 34 | job: bombardier 35 | variables: 36 | path: / 37 | 38 | profiles: 39 | local: 40 | variables: 41 | serverPort: 5000 42 | serverAddress: localhost 43 | jobs: 44 | application: 45 | endpoints: 46 | - http://localhost:5010 47 | load: 48 | endpoints: 49 | - http://localhost:5010 50 | - http://localhost:5010 51 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/assets/post.benchmarks.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | post: 3 | sources: 4 | post: 5 | localFolder: '../post' 6 | project: post/post.csproj 7 | readyStateText: Application started. 8 | waitForExit: true 9 | arguments: '{{jobUrl}}' # http://localhost:5010/Jobs/1 10 | noClean: true 11 | 12 | scenarios: 13 | post: 14 | application: 15 | job: post 16 | 17 | profiles: 18 | local: 19 | jobs: 20 | application: 21 | endpoints: 22 | - http://localhost:5010 23 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.IntegrationTests/assets/scripts.benchmarks.yml: -------------------------------------------------------------------------------- 1 | results: # creates results from measurements 2 | 3 | - name: my/result 4 | description: Custom result (s) 5 | format: n2 6 | 7 | onResultsCreating: 8 | - | 9 | console.log("a default script") 10 | 11 | scripts: 12 | 13 | # records the current date and time as a custom property 14 | add_current_time: | 15 | benchmarks.properties["time"] = new Date().toISOString(); 16 | 17 | onResultsCreated: 18 | - | 19 | benchmarks.jobs.application.results["my/result"] = 123; 20 | -------------------------------------------------------------------------------- /test/Microsoft.Crank.RegressionBot.Tests/Microsoft.Crank.RegressionBot.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Microsoft.Crank.RegressionBotTests 6 | true 7 | true 8 | XUnit 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------