Files
NuGet.Client/scripts/perftests/PerformanceTestUtilities.ps1
dotnet-maestro[bot] 5314ef624e [dev] Source code updates from dotnet/dotnet (#7559)
[dev] Source code updates from dotnet/dotnet


 - [nuget-client] Source update 50dbab4 → 50dbab4
Diff: https://github.com/dotnet/dotnet/compare/50dbab4de210e882172b07934e9666313b7065f1..50dbab4de210e882172b07934e9666313b7065f1

From: https://github.com/dotnet/dotnet/commit/50dbab4de210e882172b07934e9666313b7065f1
To: https://github.com/dotnet/dotnet/commit/50dbab4de210e882172b07934e9666313b7065f1

The following files had conflicts that were resolved by a user:

- build/common.project.props

 - trying to fix code flow issues

 - source build should use newer sdk
2026-07-15 00:13:25 +00:00

573 lines
20 KiB
PowerShell

# Contains all the utility methods used by the performance tests.
# The format of the URL is assumed to be https://github.com/NuGet/NuGet.Client.git. The result would be NuGet-Client-git
function GenerateNameFromGitUrl([string]$gitUrl)
{
return $gitUrl.Substring($($gitUrl.LastIndexOf('/') + 1)).Replace('.','-')
}
# Appends the log time in front of the log statement with the color specified.
function Log([string]$logStatement, [string]$color)
{
if([string]::IsNullOrEmpty($color))
{
Write-Host "$($(Get-Date).ToString()): $logStatement"
}
else
{
Write-Host "$($(Get-Date).ToString()): $logStatement" -ForegroundColor $color
}
}
# Given a relative path, gets the absolute path from the current directory
function GetAbsolutePath([string]$Path)
{
$Path = [System.IO.Path]::Combine((pwd).Path, $Path);
$Path = [System.IO.Path]::GetFullPath($Path);
return $Path;
}
# Writes the content to the given path. Creates the folder structure if needed
function OutFileWithCreateFolders([string]$path, [string]$content)
{
$folder = [System.IO.Path]::GetDirectoryName($path)
If(!(Test-Path $folder))
{
& New-Item -ItemType Directory -Force -Path $folder > $null
}
Add-Content -Path $path -Value $content
}
# Gets a list of all the files recursively in the given folder
Function GetFiles(
[Parameter(Mandatory = $True)]
[string] $folderPath,
[string] $pattern)
{
If (Test-Path $folderPath)
{
$files = Get-ChildItem -Path $folderPath -Filter $pattern -Recurse -File
Return $files
}
Return $Null
}
# Gets a list of all the nupkgs recursively in the given folder
Function GetPackageFiles(
[Parameter(Mandatory = $True)]
[string] $folderPath)
{
Return GetFiles $folderPath "*.nupkg"
}
Function GetFilesInfo([System.IO.FileInfo[]] $files)
{
If ($files -eq $Null)
{
$count = 0
$totalSizeInMB = 0
}
Else
{
$count = $files.Count
$totalSizeInMB = ($files | Measure-Object -Property Length -Sum).Sum / 1000000
}
Return @{
Count = $count
TotalSizeInMB = $totalSizeInMB
}
}
# Determines if the client is dotnet.exe by checking the path.
function GetClientName([string]$nugetClient)
{
return [System.IO.Path]::GetFileName($nugetClient)
}
function IsClientDotnetExe([string]$nugetClient)
{
return $nugetClient.EndsWith("dotnet.exe")
}
function IsClientMSBuildExe([string]$nugetClient)
{
return $nugetClient.EndsWith("MSBuild.exe", "CurrentCultureIgnoreCase")
}
# Downloads the repository at the given path.
Function DownloadRepository([string] $repository, [string] $commitHash, [string] $sourceFolderPath)
{
If (Test-Path $sourceFolderPath)
{
Log "Skipping the cloning of $repository as $sourceFolderPath is not empty. Running git clean" -color "Yellow"
git -C $sourceFolderPath clean -xdf | out-null
}
Else
{
git clone $repository $sourceFolderPath
git -C $sourceFolderPath checkout $commitHash | out-null
}
}
# Find the appropriate solution file for the repository. Looks for a solution file matching the repo name,
# if not it takes the first available sln file in the repo.
Function GetSolutionFilePath([string] $repository, [string] $sourceFolderPath)
{
$gitRepoName = $repository.Substring($($repository.LastIndexOf('/') + 1))
$potentialSolutionFilePath = [System.IO.Path]::Combine($sourceFolderPath, "$($gitRepoName.Substring(0, $gitRepoName.Length - 4)).sln")
If (Test-Path $potentialSolutionFilePath)
{
$solutionFilePath = $potentialSolutionFilePath
}
Else
{
$possibleSln = Get-ChildItem $sourceFolderPath *.sln | Where-Object{$_.FullName -notlike '*.slnf'}
If ($possibleSln.Length -eq 0)
{
Log "No solution files found in $sourceFolderPath" "red"
}
Else
{
$solutionFilePath = $possibleSln[0] | Select-Object -f 1 | Select-Object -ExpandProperty FullName
}
}
Return $solutionFilePath
}
# Given a repository and a hash, checks out the revision in the given source directory. The return is a solution file if found.
Function SetupGitRepository([string] $repository, [string] $commitHash, [string] $sourceFolderPath)
{
Log "Setting up $repository into $sourceFolderPath"
DownloadRepository $repository $commitHash $sourceFolderPath
$solutionFilePath = GetSolutionFilePath $repository $sourceFolderPath
Log "Completed the repository setup. The solution file is $solutionFilePath" -color "Green"
Return $solutionFilePath
}
# runs locals clear all with the given client
# If the client is msbuild.exe, the locals clear all *will* be run with dotnet.exe
Function LocalsClearAll([string] $nugetClientFilePath)
{
$nugetClientFilePath = GetAbsolutePath $nugetClientFilePath
If ($(IsClientDotnetExe $nugetClientFilePath))
{
. $nugetClientFilePath nuget locals -c all *>>$null
}
Elseif($(IsClientMSBuildExe $nugetClientFilePath))
{
. dotnet.exe nuget locals -c all *>>$null
}
Else
{
. $nugetClientFilePath locals -clear all -Verbosity quiet
}
}
# Gets the client version
Function GetClientVersion([string] $nugetClientFilePath)
{
$nugetClientFilePath = GetAbsolutePath $nugetClientFilePath
If (IsClientDotnetExe $nugetClientFilePath)
{
$version = . $nugetClientFilePath --version
}
ElseIf($(IsClientMSBuildExe $nugetClientFilePath))
{
$clientDir = Split-Path -Path $nugetClientFilePath
$nugetClientPath = Resolve-Path (Join-Path -Path $clientDir -ChildPath "../../../../Common7/IDE/CommonExtensions/Microsoft/NuGet/NuGet.Build.Tasks.dll")
$versionInfo = Get-ChildItem $nugetClientPath | % versioninfo | Select-Object FileVersion
Return $(($versionInfo -split '\n')[0]).TrimStart("@{").TrimEnd('}').Substring("FileVersion=".Length)
}
Else
{
$output = . $nugetClientFilePath
$version = $(($output -split '\n')[0]).Substring("NuGet Version: ".Length)
}
Return $version
}
# Gets the default test folder
Function GetDefaultNuGetTestFolder()
{
Return $Env:UserProfile
}
# Gets the NuGet folders path where all of the discardable data from the tests will be put.
Function GetNuGetFoldersPath([string] $testFoldersPath)
{
$nugetFoldersPath = [System.IO.Path]::Combine($testFoldersPath, "np")
return GetAbsolutePath $nugetFoldersPath
}
# Sets up the global packages folder, http cache and plugin caches and cleans them before starting.
Function SetupNuGetFolders([string] $nugetClientFilePath, [string] $nugetFoldersPath)
{
$Env:NUGET_PACKAGES = [System.IO.Path]::Combine($nugetFoldersPath, "gpf")
$Env:NUGET_HTTP_CACHE_PATH = [System.IO.Path]::Combine($nugetFoldersPath, "hcp")
$Env:NUGET_PLUGINS_CACHE_PATH = [System.IO.Path]::Combine($nugetFoldersPath, "pcp")
# This environment variable is not recognized by any NuGet client.
$Env:NUGET_SOLUTION_PACKAGES_FOLDER_PATH = [System.IO.Path]::Combine($nugetFoldersPath, "sp")
LocalsClearAll $nugetClientFilePath
}
# Cleanup the nuget folders and delete the nuget folders path.
# This should only be invoked by the the performance tests
Function CleanNuGetFolders([string] $nugetClientFilePath, [string] $nugetFoldersPath)
{
Log "Cleanup the NuGet folders - global packages folder, http/plugins caches. Client: $nugetClientFilePath. Folders: $nugetFoldersPath"
LocalsClearAll $nugetClientFilePath
Remove-Item $nugetFoldersPath -Recurse -Force -ErrorAction Ignore
[Environment]::SetEnvironmentVariable("NUGET_PACKAGES", $Null)
[Environment]::SetEnvironmentVariable("NUGET_HTTP_CACHE_PATH", $Null)
[Environment]::SetEnvironmentVariable("NUGET_PLUGINS_CACHE_PATH", $Null)
[Environment]::SetEnvironmentVariable("NUGET_SOLUTION_PACKAGES_FOLDER_PATH", $Null)
[Environment]::SetEnvironmentVariable("NUGET_FOLDERS_PATH", $Null)
}
# Given a repository, a client and directories for the results/logs, runs the configured performance tests.
Function RunPerformanceTestsOnGitRepository(
[string] $nugetClientFilePath,
[string] $sourceRootFolderPath,
[string] $repoUrl,
[string] $commitHash,
[string] $resultsFolderPath,
[string] $nugetFoldersPath,
[string] $logsFolderPath,
[int] $iterationCount,
[string] $additionalOptions)
{
$testCaseName = GenerateNameFromGitUrl $repoUrl
$resultsFilePath = [System.IO.Path]::Combine($resultsFolderPath, "$testCaseName.csv")
$solutionFilePath = SetupGitRepository -repository $repoUrl -commitHash $commitHash -sourceFolderPath $([System.IO.Path]::Combine($sourceRootFolderPath, $testCaseName))
$sb = [scriptblock]::Create("$PSScriptRoot\RunPerformanceTests.ps1 -nugetClientFilePath ""$nugetClientFilePath"" -solutionFilePath $solutionFilePath -resultsFilePath $resultsFilePath -logsFolderPath $logsFolderPath -nugetFoldersPath $nugetFoldersPath -iterationCount $iterationCount " + $additionalOptions)
SetupNuGetFolders $nugetClientFilePath $nugetFoldersPath
& $sb
}
Function GetProcessorInfo()
{
$processorInfo = Get-WmiObject Win32_processor
Return @{
Name = $processorInfo | Select-Object -ExpandProperty Name
NumberOfCores = $processorInfo | Select-Object -ExpandProperty NumberOfCores
NumberOfLogicalProcessors = $processorInfo | Select-Object -ExpandProperty NumberOfLogicalProcessors
}
}
Function LogDotNetSdkInfo()
{
Try
{
$currentVersion = dotnet --version
$currentSdk = dotnet --list-sdks | Where { $_.StartsWith("$currentVersion ") } | Select -First 1
Log "Using .NET Core SDK $currentSdk."
}
Catch [System.Management.Automation.CommandNotFoundException]
{
Log ".NET Core SDK not found." -Color "Yellow"
}
}
# Note: System.TimeSpan rounds to the nearest millisecond.
Function ParseElapsedTime(
[Parameter(Mandatory = $True)]
[decimal] $value,
[Parameter(Mandatory = $True)]
[string] $unit)
{
Switch ($unit)
{
"ms" { Return [System.TimeSpan]::FromMilliseconds($value) }
"sec" { Return [System.TimeSpan]::FromSeconds($value) }
"min" { Return [System.TimeSpan]::FromMinutes($value) }
Default { throw "Unsupported unit of time: $unit" }
}
}
Function ExtractRestoreElapsedTime(
[Parameter(Mandatory = $True)]
[string[]] $lines)
{
# All packages listed in packages.config are already installed.
$prefix = "Restore completed in "
$lines = $lines | Where { $_.IndexOf($prefix) -gt -1 }
ForEach ($line In $lines)
{
$index = $line.IndexOf($prefix)
$parts = $line.Substring($index + $prefix.Length).Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
$value = [System.Double]::Parse($parts[0])
$unit = $parts[1]
$temp = ParseElapsedTime $value $unit
If ($elapsedTime -eq $Null -Or $elapsedTime -lt $temp)
{
$elapsedTime = $temp
}
}
Return $elapsedTime
}
# Plugins cache is only available in 4.8+. We need to be careful when using that switch for older clients because it may blow up.
# The logs location is optional
Function RunRestore(
[string] $solutionFilePath,
[string] $nugetClientFilePath,
[string] $resultsFile,
[string] $logsFolderPath,
[string] $scenarioName,
[string] $solutionName,
[string] $testRunId,
[switch] $isPackagesConfig,
[switch] $cleanGlobalPackagesFolder,
[switch] $cleanHttpCache,
[switch] $cleanPluginsCache,
[switch] $killMsBuildAndDotnetExeProcesses,
[switch] $force,
[switch] $staticGraphRestore,
[switch] $cleanRepository,
[switch] $useLocallyBuiltNuGet,
[switch] $forceLegacyResolverFallback)
{
$isClientDotnetExe = IsClientDotnetExe $nugetClientFilePath
$isClientMSBuild = IsClientMSBuildExe $nugetClientFilePath
If ($isClientDotnetExe -And $isPackagesConfig)
{
Log "dotnet.exe does not support packages.config restore." "Red"
Return
}
Log "Running $nugetClientFilePath restore with cleanGlobalPackagesFolder:$cleanGlobalPackagesFolder cleanHttpCache:$cleanHttpCache cleanPluginsCache:$cleanPluginsCache killMsBuildAndDotnetExeProcesses:$killMsBuildAndDotnetExeProcesses force:$force staticGraphRestore:$staticGraphRestore cleanRepository:$cleanRepository"
$solutionPackagesFolderPath = $Env:NUGET_SOLUTION_PACKAGES_FOLDER_PATH
# Cleanup if necessary
If ($cleanGlobalPackagesFolder -Or $cleanHttpCache -Or $cleanPluginsCache)
{
If ($cleanGlobalPackagesFolder -And $cleanHttpCache -And $cleanPluginsCache)
{
$localsArguments = "all"
}
ElseIf ($cleanGlobalPackagesFolder -And $cleanHttpCache)
{
$localsArguments = "http-cache global-packages"
}
ElseIf ($cleanGlobalPackagesFolder)
{
$localsArguments = "global-packages"
}
ElseIf ($cleanHttpCache)
{
$localsArguments = "http-cache"
}
Else
{
Log "Too risky to invoke a locals clear with the specified parameters." "yellow"
}
If ($isClientDotnetExe)
{
. $nugetClientFilePath nuget locals -c $localsArguments *>>$null
}
ElseIf($isClientMSBuild)
{
. dotnet.exe nuget locals -c $localsArguments *>>$null
}
Else
{
. $nugetClientFilePath locals -clear $localsArguments -Verbosity quiet
}
If ($isPackagesConfig -And ($cleanGlobalPackagesFolder -Or $cleanHttpCache))
{
Remove-Item $solutionPackagesFolderPath -Recurse -Force -ErrorAction Ignore > $Null
mkdir $solutionPackagesFolderPath > $Null
}
}
if($cleanRepository)
{
$repositoryPath = [System.IO.Path]::GetDirectoryName($solutionFilePath)
git -C $repositoryPath clean -xdf | out-null
}
if($killMsBuildAndDotnetExeProcesses)
{
Stop-Process -name msbuild*,dotnet* -Force
}
$arguments = [System.Collections.Generic.List[string]]::new()
If ($isClientMSBuild)
{
$arguments.Add("/t:restore")
}
Else
{
$arguments.Add("restore")
}
$arguments.Add($solutionFilePath)
If ($isPackagesConfig)
{
If ($isClientDotnetExe)
{
$arguments.Add("--packages")
}
Else
{
$arguments.Add("-PackagesDirectory")
}
$arguments.Add($Env:NUGET_SOLUTION_PACKAGES_FOLDER_PATH)
}
If ($force)
{
If ($isClientDotnetExe)
{
$arguments.Add("--force")
}
ElseIf($isClientMSBuild)
{
$arguments.Add("/p:RestoreForce=true")
}
Else
{
$arguments.Add("-Force")
}
}
If (!$isClientDotnetExe -And !$isClientMSBuild)
{
$arguments.Add("-NonInteractive")
}
If($isClientDotnetExe -Or $isClientMSBuild)
{
If ($staticGraphRestore)
{
$staticGraphOutputValue = "true"
$arguments.Add("/p:RestoreUseStaticGraphEvaluation=true")
}
Else
{
$staticGraphOutputValue = "false"
}
}
Else
{
$staticGraphOutputValue = "N/A"
}
If($isClientDotnetExe -Or $isClientMSBuild)
{
# Always disable NuGetAudit. It's something impacted by the time of execution, and not helpful in these type of performance tests.
$arguments.Add("/p:NuGetAudit=false")
}
if(($isClientDotnetExe -Or $isClientMSBuild) -And $forceLegacyResolverFallback)
{
$arguments.Add("/p:RestoreUseLegacyDependencyResolver=true")
}
if($useLocallyBuiltNuGet)
{
if($isClientMSBuild)
{
$NETFramework = "net472"
$Configuration = "release"
$packDllPath = Join-Path $NuGetClientRoot "artifacts\NuGet.Build.Tasks.Pack\bin\$Configuration\$NETFramework\NuGet.Build.Tasks.Pack.dll"
$packTargetsPath = Join-Path $NuGetClientRoot "artifacts\NuGet.Build.Tasks.Pack\bin\$Configuration\$NETFramework\NuGet.Build.Tasks.Pack.targets"
$nugetRestoreTargetsPath = Join-Path $NuGetClientRoot "artifacts\NuGet.Build.Tasks\bin\$Configuration\$NETFramework\NuGet.targets"
$nugetPropsPath = Join-Path $NuGetClientRoot "artifacts\NuGet.Build.Tasks\bin\$Configuration\$NETFramework\NuGet.props"
$consoleExePath = Join-Path $NuGetClientRoot "artifacts\NuGet.Build.Tasks.Console\bin\$Configuration\$NETFramework\NuGet.Build.Tasks.Console.exe"
$arguments.Add("/p:NuGetRestoreTargets=$nugetRestoreTargetsPath");
$arguments.Add("/p:NuGetPropsFile=$nugetPropsPath");
$arguments.Add("/p:NuGetBuildTasksPackTargets=$packTargetsPath");
$arguments.Add("/p:NuGetConsoleProcessFileName=$consoleExePath");
$arguments.Add("/p:ImportNuGetBuildTasksPackTargetsFromSdk=true");
$arguments.Add("/p:NuGetPackTaskAssemblyFile=$packDllPath");
}
else
{
Log "Locally built NuGet can only be used with msbuild.exe" "red"
}
}
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$logs = . $nugetClientFilePath $arguments | Out-String
if($LASTEXITCODE -ne 0)
{
throw "The command `"$nugetClientFilePath $arguments`" finished with exit code $LASTEXITCODE.`n" + $logs
}
$totalTime = $stopwatch.Elapsed.TotalSeconds
$restoreCoreTime = ExtractRestoreElapsedTime $logs
If ($restoreCoreTime -ne $Null)
{
$restoreCoreTime = $restoreCoreTime.TotalSeconds
}
if(![string]::IsNullOrEmpty($logsFolderPath))
{
$logFile = [System.IO.Path]::Combine($logsFolderPath, "restoreLog-$([System.IO.Path]::GetFileNameWithoutExtension($solutionFilePath))-$(get-date -f yyyyMMddTHHmmssffff).txt")
OutFileWithCreateFolders $logFile $logs
}
$folderPath = $Env:NUGET_PACKAGES
$globalPackagesFolderNupkgFilesInfo = GetFilesInfo(GetPackageFiles $folderPath)
$globalPackagesFolderFilesInfo = GetFilesInfo(GetFiles $folderPath)
$folderPath = $Env:NUGET_HTTP_CACHE_PATH
$httpCacheFilesInfo = GetFilesInfo(GetFiles $folderPath)
$folderPath = $Env:NUGET_PLUGINS_CACHE_PATH
$pluginsCacheFilesInfo = GetFilesInfo(GetFiles $folderPath)
$clientName = GetClientName $nugetClientFilePath
$clientVersion = GetClientVersion $nugetClientFilePath
If (!(Test-Path $resultsFilePath))
{
$columnHeaders = "Client Name,Client Version,Locally Built NuGet,Solution Name,Test Run ID,Scenario Name,Total Time (seconds),Core Restore Time (seconds),Force,Static Graph," + `
"Global Packages Folder .nupkg Count,Global Packages Folder .nupkg Size (MB),Global Packages Folder File Count,Global Packages Folder File Size (MB),Clean Global Packages Folder," + `
"HTTP Cache File Count,HTTP Cache File Size (MB),Clean HTTP Cache,Plugins Cache File Count,Plugins Cache File Size (MB),Clean Plugins Cache,Kill MSBuild and dotnet Processes,Clean git repo,Force Legacy resolver," + `
"Processor Name,Processor Physical Core Count,Processor Logical Core Count"
OutFileWithCreateFolders $resultsFilePath $columnHeaders
}
$data = "$clientName,$clientVersion,$useLocallyBuiltNuGet,$solutionName,$testRunId,$scenarioName,$totalTime,$restoreCoreTime,$force,$staticGraphOutputValue," + `
"$($globalPackagesFolderNupkgFilesInfo.Count),$($globalPackagesFolderNupkgFilesInfo.TotalSizeInMB),$($globalPackagesFolderFilesInfo.Count),$($globalPackagesFolderFilesInfo.TotalSizeInMB),$cleanGlobalPackagesFolder," + `
"$($httpCacheFilesInfo.Count),$($httpCacheFilesInfo.TotalSizeInMB),$cleanHttpCache,$($pluginsCacheFilesInfo.Count),$($pluginsCacheFilesInfo.TotalSizeInMB),$cleanPluginsCache,$killMsBuildAndDotnetExeProcesses,$cleanRepository,$forceLegacyResolverFallback," + `
"$($processorInfo.Name),$($processorInfo.NumberOfCores),$($processorInfo.NumberOfLogicalProcessors)"
Add-Content -Path $resultsFilePath -Value $data
Log "Finished measuring in $totalTime sec"
}