platforms:
# Linux tests are built on the OSX machines.
# - OSX_x64
+ - Linux_arm
+ - Linux_arm64
+ - Linux_x64
+ - windows_x64
+ - windows_x86
+ - windows_arm64
+ - CoreClrTestBuildHost # Either OSX_x64 or Linux_x64
+ helixQueueGroup: ci
+ helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
+ jobParameters:
+ testGroup: outerloop
+ liveLibrariesBuildConfig: Release
+ collectionType: pmi
+ collectionName: tests
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ buildConfig: checked
+ platforms:
+ # Linux tests are built on the OSX machines.
+ # - OSX_x64
# TODO: Linux crossgen2 jobs crash during collection, and need to be investigated.
# - Linux_arm
# - Linux_arm64
platforms:
# Linux tests are built on the OSX machines.
# - OSX_x64
- - Linux_arm
- - Linux_arm64
+ #TODO: Need special handling of running "benchmark build" from inside TMP folder on helix machine.
+ # - Linux_arm
+ # - Linux_arm64
- Linux_x64
- windows_x64
- windows_x86
jobParameters:
testGroup: outerloop
liveLibrariesBuildConfig: Release
- collectionType: pmi
- collectionName: tests
-
+ collectionType: run
+ collectionName: benchmarks
- ${{ if eq(parameters.collectionName, 'libraries') }}:
- name: InputDirectory
value: '$(Core_Root_Dir)'
+ - ${{ if eq(parameters.collectionName, 'benchmarks') }}:
+ - name: InputDirectory
+ value: '$(Core_Root_Dir)'
- ${{ if eq(parameters.collectionName, 'tests') }}:
- name: InputDirectory
value: '$(managedTestArtifactRootFolderPath)'
steps:
- ${{ parameters.steps }}
- - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi-setup.py -source_directory $(Build.SourcesDirectory) -core_root_directory $(Core_Root_Dir) -arch $(archType) -mch_file_tag $(MchFileTag) -input_directory $(InputDirectory) -collection_name $(CollectionName) -collection_type $(CollectionType) -max_size 50 # size in MB
+ - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi_setup.py -source_directory $(Build.SourcesDirectory) -core_root_directory $(Core_Root_Dir) -arch $(archType) -mch_file_tag $(MchFileTag) -input_directory $(InputDirectory) -collection_name $(CollectionName) -collection_type $(CollectionType) -max_size 50 # size in MB
displayName: ${{ format('SuperPMI setup ({0})', parameters.osGroup) }}
# Run superpmi collection in helix
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
-constexpr GUID JITEEVersionIdentifier = { /* 6ca59d19-13a4-44f7-a184-e9cd1e8f57f8 */
- 0x6ca59d19,
- 0x13a4,
- 0x44f7,
- { 0xa1, 0x84, 0xe9, 0xcd, 0x1e, 0x8f, 0x57, 0xf8 }
+constexpr GUID JITEEVersionIdentifier = { /* af37688b-d4e5-4a41-a7ee-701728a470aa */
+ 0xaf37688b,
+ 0xd4e5,
+ 0x4a41,
+ {0xa7, 0xee, 0x70, 0x17, 0x28, 0xa4, 0x70, 0xaa}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
<Project Sdk="Microsoft.DotNet.Helix.Sdk" DefaultTargets="Test">
+ <!--
+ This is useful for local testing to print the produced helix items
+ To use this when you are changing how items are produced, uncomment the target
+ and replace the Project item at the top of the file with this:
+ <Project DefaultTargets="printItems">
+
+ Once you've done that you can run this to see the results:
+ dotnet msbuild .\superpmi.proj /v:n
+ -->
+
+ <!-- <PropertyGroup>
+ <HelixTargetQueues>Some_Queue</HelixTargetQueues>
+ <InputArtifacts>D:\git\runtime\workitem\pmiAssembliesDirectory\libraries</InputArtifacts>
+ <MchFileTag>x64.checked</MchFileTag>
+ <CollectionName>benchmarks</CollectionName>
+ <CollectionType>pmi</CollectionType>
+ </PropertyGroup>
+ <Target Name="printItems">
+ <Message Text="@(HelixWorkItem -> 'name: %(HelixWorkItem.Identity)
+ dir: %(HelixWorkItem.PayloadDirectory)
+ pre: %(HelixWorkItem.PreCommands)
+ command: %(HelixWorkItem.Command)
+ post: %(HelixWorkItem.PostCommands)
+ timeout: %(HelixWorkItem.Timeout) '"/>
+ </Target> -->
+
<PropertyGroup Condition="'$(AGENT_OS)' == 'Windows_NT'">
<FileSeparatorChar>\</FileSeparatorChar>
</PropertyGroup>
<PmiAssembliesPayload>$(WorkItemDirectory)\pmiAssembliesDirectory</PmiAssembliesPayload>
<PmiAssembliesDirectory>%HELIX_WORKITEM_PAYLOAD%\binaries</PmiAssembliesDirectory>
<SuperPMIDirectory>%HELIX_CORRELATION_PAYLOAD%\superpmi</SuperPMIDirectory>
+
+ <!-- Related to Benchmarks -->
+ <PerformanceDirectory>%HELIX_WORKITEM_PAYLOAD%\performance</PerformanceDirectory>
+
<OutputMchPath>%HELIX_WORKITEM_UPLOAD_ROOT%</OutputMchPath>
<!-- Workaround until https://github.com/dotnet/arcade/pull/6179 is not available -->
<HelixResultsDestinationDir>$(BUILD_SOURCESDIRECTORY)\artifacts\helixresults</HelixResultsDestinationDir>
<PmiAssembliesPayload>$(WorkItemDirectory)/pmiAssembliesDirectory</PmiAssembliesPayload>
<PmiAssembliesDirectory>$HELIX_WORKITEM_PAYLOAD/binaries</PmiAssembliesDirectory>
<SuperPMIDirectory>$HELIX_CORRELATION_PAYLOAD/superpmi</SuperPMIDirectory>
+
+ <!-- Related to Benchmarks -->
+ <PerformanceDirectory>$HELIX_WORKITEM_PAYLOAD/performance</PerformanceDirectory>
+
<OutputMchPath>$HELIX_WORKITEM_UPLOAD_ROOT</OutputMchPath>
<!-- Workaround until https://github.com/dotnet/arcade/pull/6179 is not available -->
<HelixResultsDestinationDir>$(BUILD_SOURCESDIRECTORY)/artifacts/helixresults</HelixResultsDestinationDir>
<WorkItemCommand>$(Python) $(WorkItemCommand) -assemblies $(PmiAssembliesDirectory) -arch $(Architecture) -build_type $(BuildConfig) -core_root $(SuperPMIDirectory)</WorkItemCommand>
</PropertyGroup>
+ <PropertyGroup Condition="'$(CollectionName)' == 'benchmarks'">
+ <WorkItemCommand>$(Python) $(SuperPMIDirectory)/superpmi_benchmarks.py -performance_directory $(PerformanceDirectory) -superpmi_directory $(SuperPMIDirectory) -core_root $(SuperPMIDirectory) -arch $(Architecture)</WorkItemCommand>
+ </PropertyGroup>
+
<PropertyGroup>
<EnableAzurePipelinesReporter>false</EnableAzurePipelinesReporter>
<EnableXUnitReporter>false</EnableXUnitReporter>
</HelixCorrelationPayload>
</ItemGroup>
- <ItemGroup>
+ <ItemGroup Condition="'$(CollectionName)' != 'benchmarks'">
<PartitionDirectories Include="$([System.IO.Directory]::GetDirectories($(InputArtifacts)))"/>
<Partition Include="@(PartitionDirectories -> '%(Filename)')" PmiAssemblies="%(Filename)" PartitionId="%(Filename)" />
</ItemGroup>
+ <PropertyGroup>
+ <PartitionCount>30</PartitionCount>
+ </PropertyGroup>
<ItemGroup>
+ <BDN_Partition Include="Partition0" Index="0" />
+ <BDN_Partition Include="Partition1" Index="1" />
+ <BDN_Partition Include="Partition2" Index="2" />
+ <BDN_Partition Include="Partition3" Index="3" />
+ <BDN_Partition Include="Partition4" Index="4" />
+ <BDN_Partition Include="Partition5" Index="5" />
+ <BDN_Partition Include="Partition6" Index="6" />
+ <BDN_Partition Include="Partition7" Index="7" />
+ <BDN_Partition Include="Partition8" Index="8" />
+ <BDN_Partition Include="Partition9" Index="9" />
+ <BDN_Partition Include="Partition10" Index="10" />
+ <BDN_Partition Include="Partition11" Index="11" />
+ <BDN_Partition Include="Partition12" Index="12" />
+ <BDN_Partition Include="Partition13" Index="13" />
+ <BDN_Partition Include="Partition14" Index="14" />
+ <BDN_Partition Include="Partition15" Index="15" />
+ <BDN_Partition Include="Partition16" Index="16" />
+ <BDN_Partition Include="Partition17" Index="17" />
+ <BDN_Partition Include="Partition18" Index="18" />
+ <BDN_Partition Include="Partition19" Index="19" />
+ <BDN_Partition Include="Partition20" Index="20" />
+ <BDN_Partition Include="Partition21" Index="21" />
+ <BDN_Partition Include="Partition22" Index="22" />
+ <BDN_Partition Include="Partition23" Index="23" />
+ <BDN_Partition Include="Partition24" Index="24" />
+ <BDN_Partition Include="Partition25" Index="25" />
+ <BDN_Partition Include="Partition26" Index="26" />
+ <BDN_Partition Include="Partition27" Index="27" />
+ <BDN_Partition Include="Partition28" Index="28" />
+ <BDN_Partition Include="Partition29" Index="29" />
+ </ItemGroup>
+
+ <ItemGroup Condition="'$(CollectionName)' != 'benchmarks'">
<HelixWorkItem Include="@(Partition)">
<OutputFileName>$(CollectionName).$(CollectionType).%(HelixWorkItem.PartitionId).$(MchFileTag)</OutputFileName>
<PayloadDirectory>$(PmiAssembliesPayload)$(FileSeparatorChar)$(CollectionName)$(FileSeparatorChar)%(HelixWorkItem.PmiAssemblies)</PayloadDirectory>
<DownloadFilesFromResults>%(OutputFileName).mch;%(OutputFileName).mch.mct;%(OutputFileName).log</DownloadFilesFromResults>
</HelixWorkItem>
</ItemGroup>
- <!--
- This is useful for local testing to print the produced helix items
- To use this when you are changing how items are produced, uncomment the target
- and replace the Project item at the top of the file with this:
- <Project DefaultTargets="printItems">
-
- Once you've done that you can run this to see the results:
- dotnet msbuild .\superpmi.proj /v:n
- -->
-<!--
- <PropertyGroup>
- <HelixTargetQueues>Some_Queue</HelixTargetQueues>
- <InputArtifacts>D:\git\runtime\workitem\pmiAssembliesDirectory\libraries</InputArtifacts>
- <MchFileTag>x64.checked</MchFileTag>
- <CollectionName>libraries</CollectionName>
- </PropertyGroup>
- <Target Name="printItems">
- <Message Text="@(HelixWorkItem -> 'name: %(HelixWorkItem.Identity)
- dir: %(HelixWorkItem.PayloadDirectory)
- pre: %(HelixWorkItem.PreCommands)
- command: %(HelixWorkItem.Command)
- post: %(HelixWorkItem.PostCommands)
- timeout: %(HelixWorkItem.Timeout) '"/>
- </Target> -->
-
+ <ItemGroup Condition="'$(CollectionName)' == 'benchmarks'">
+ <HelixWorkItem Include="@(BDN_Partition)">
+ <OutputFileName>$(CollectionName).$(CollectionType).%(HelixWorkItem.Index).$(MchFileTag)</OutputFileName>
+ <PayloadDirectory>$(WorkItemDirectory)</PayloadDirectory>
+ <Command>$(WorkItemCommand) -partition_count $(PartitionCount) -partition_index %(HelixWorkItem.Index) -output_mch_path $(OutputMchPath)$(FileSeparatorChar)%(OutputFileName).mch -log_file $(OutputMchPath)$(FileSeparatorChar)%(OutputFileName).log</Command>
+ <Timeout>$(WorkItemTimeout)</Timeout>
+ <DownloadFilesFromResults>%(OutputFileName).mch;%(OutputFileName).mch.mct;%(OutputFileName).log</DownloadFilesFromResults>
+ </HelixWorkItem>
+ </ItemGroup>
</Project>
Use with: "with TempDir() as temp_dir" to change to that directory and then automatically
change back to the original working directory afterwards and remove the temporary
- directory and its contents (if args.skip_cleanup is False).
+ directory and its contents (if skip_cleanup is False).
"""
- def __init__(self, path=None):
+ def __init__(self, path=None, skip_cleanup=False):
self.mydir = tempfile.mkdtemp() if path is None else path
self.cwd = None
+ self._skip_cleanup = skip_cleanup
def __enter__(self):
self.cwd = os.getcwd()
def __exit__(self, exc_type, exc_val, exc_tb):
os.chdir(self.cwd)
- # Note: we are using the global `args`, not coreclr_args. This works because
- # the `skip_cleanup` argument is not processed by CoreclrArguments, but is
- # just copied there.
- if not args.skip_cleanup:
+ if not self._skip_cleanup:
shutil.rmtree(self.mydir)
passed = False
try:
- with TempDir(self.coreclr_args.temp_dir) as temp_location:
+ with TempDir(self.coreclr_args.temp_dir, self.coreclr_args.skip_cleanup) as temp_location:
# Setup all of the temp locations
self.base_fail_mcl_file = os.path.join(temp_location, "basefail.mcl")
self.base_mch_file = os.path.join(temp_location, "base.mch")
files_with_asm_diffs = []
files_with_replay_failures = []
- with TempDir(self.coreclr_args.temp_dir) as temp_location:
+ with TempDir(self.coreclr_args.temp_dir, self.coreclr_args.skip_cleanup) as temp_location:
logging.debug("")
logging.debug("Temp Location: %s", temp_location)
logging.debug("")
--- /dev/null
+#!/usr/bin/env python3
+#
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+#
+#
+# Title: superpmi_benchmarks.py
+#
+# Notes:
+#
+# Script to perform the superpmi collection while executing the Microbenchmarks present
+# in https://github.com/dotnet/performance/tree/master/src/benchmarks/micro.
+
+import argparse
+import re
+import sys
+
+import stat
+from os import path
+from os.path import isfile
+from shutil import copyfile
+from coreclr_arguments import *
+from superpmi import ChangeDir, TempDir
+from superpmi_setup import run_command
+
+# Start of parser object creation.
+is_windows = platform.system() == "Windows"
+parser = argparse.ArgumentParser(description="description")
+
+parser.add_argument("-performance_directory", help="Path to performance directory")
+parser.add_argument("-superpmi_directory", help="Path to superpmi directory")
+parser.add_argument("-core_root", help="Path to Core_Root directory")
+parser.add_argument("-output_mch_path", help="Absolute path to the mch file to produce")
+parser.add_argument("-log_file", help="Name of the log file")
+parser.add_argument("-partition_count", help="Total number of partitions")
+parser.add_argument("-partition_index", help="Partition index to do the collection for")
+parser.add_argument("-arch", help="Architecture")
+
+
+def setup_args(args):
+ """ Setup the args for SuperPMI to use.
+
+ Args:
+ args (ArgParse): args parsed by arg parser
+
+ Returns:
+ args (CoreclrArguments)
+
+ """
+ coreclr_args = CoreclrArguments(args, require_built_core_root=False, require_built_product_dir=False,
+ require_built_test_dir=False, default_build_type="Checked")
+
+ coreclr_args.verify(args,
+ "performance_directory",
+ lambda performance_directory: os.path.isdir(performance_directory),
+ "performance_directory doesn't exist")
+
+ coreclr_args.verify(args,
+ "superpmi_directory",
+ lambda superpmi_directory: os.path.isdir(superpmi_directory),
+ "superpmi_directory doesn't exist")
+
+ coreclr_args.verify(args,
+ "output_mch_path",
+ lambda output_mch_path: not os.path.isfile(output_mch_path),
+ "output_mch_path already exist")
+
+ coreclr_args.verify(args,
+ "log_file",
+ lambda log_file: True, # not os.path.isfile(log_file),
+ "log_file already exist")
+
+ coreclr_args.verify(args,
+ "core_root",
+ lambda core_root: os.path.isdir(core_root),
+ "core_root doesn't exist")
+
+ coreclr_args.verify(args,
+ "partition_count",
+ lambda partition_count: partition_count.isnumeric(),
+ "Unable to set partition_count")
+
+ coreclr_args.verify(args,
+ "partition_index",
+ lambda partition_index: partition_index.isnumeric(),
+ "Unable to set partition_index")
+
+ coreclr_args.verify(args,
+ "arch",
+ lambda arch: arch.lower() in ["x86", "x64", "arm", "arm64"],
+ "Unable to set arch")
+
+ return coreclr_args
+
+
+def make_executable(file_name):
+ """Make file executable by changing the permission
+
+ Args:
+ file_name (string): file to execute
+ """
+ if is_windows:
+ return
+
+ print("Inside make_executable")
+ run_command(["ls", "-l", file_name])
+ os.chmod(file_name,
+ # read+execute for owner
+ (stat.S_IRUSR | stat.S_IXUSR) |
+ # read+execute for group
+ (stat.S_IRGRP | stat.S_IXGRP) |
+ # read+execute for other
+ (stat.S_IROTH | stat.S_IXOTH))
+ run_command(["ls", "-l", file_name])
+
+
+def build_and_run(coreclr_args, output_mch_name):
+ """Build the microbenchmarks and run them under "superpmi collect"
+
+ Args:
+ coreclr_args (CoreClrArguments): Arguments use to drive
+ output_mch_name (string): Name of output mch file name
+ """
+ arch = coreclr_args.arch
+ python_path = sys.executable
+ core_root = coreclr_args.core_root
+ superpmi_directory = coreclr_args.superpmi_directory
+ performance_directory = coreclr_args.performance_directory
+ log_file = coreclr_args.log_file
+ partition_count = coreclr_args.partition_count
+ partition_index = coreclr_args.partition_index
+ dotnet_directory = os.path.join(performance_directory, "tools", "dotnet", arch)
+ dotnet_exe = os.path.join(dotnet_directory, "dotnet")
+
+ artifacts_directory = os.path.join(performance_directory, "artifacts")
+ artifacts_packages_directory = os.path.join(artifacts_directory, "packages")
+ project_file = path.join(performance_directory, "src", "benchmarks", "micro", "MicroBenchmarks.csproj")
+ benchmarks_dll = path.join(artifacts_directory, "MicroBenchmarks.dll")
+
+ if is_windows:
+ shim_name = "%JitName%"
+ corerun_exe = "CoreRun.exe"
+ script_name = "run_microbenchmarks.bat"
+ else:
+ shim_name = "$JitName"
+ corerun_exe = "corerun"
+ script_name = "run_microbenchmarks.sh"
+
+ make_executable(dotnet_exe)
+
+ run_command(
+ [dotnet_exe, "restore", project_file, "--packages",
+ artifacts_packages_directory], _exit_on_fail=True)
+
+ run_command(
+ [dotnet_exe, "build", project_file, "--configuration", "Release",
+ "--framework", "net6.0", "--no-restore", "/p:NuGetPackageRoot=" + artifacts_packages_directory,
+ "-o", artifacts_directory], _exit_on_fail=True)
+
+ collection_command = f"{dotnet_exe} {benchmarks_dll} --filter \"*\" --corerun {path.join(core_root, corerun_exe)} --partition-count {partition_count} " \
+ f"--partition-index {partition_index} --envVars COMPlus_JitName:{shim_name} " \
+ "--iterationCount 1 --warmupCount 0 --invocationCount 1 --unrollFactor 1 --strategy ColdStart"
+
+ # Generate the execution script in Temp location
+ with TempDir() as temp_location:
+ script_name = path.join(temp_location, script_name)
+
+ contents = []
+ # Unset the JitName so dotnet process will not fail
+ if is_windows:
+ contents.append("set JitName=%COMPlus_JitName%")
+ contents.append("set COMPlus_JitName=")
+ else:
+ contents.append("#!/bin/bash")
+ contents.append("export JitName=$COMPlus_JitName")
+ contents.append("unset COMPlus_JitName")
+ contents.append(f"pushd {performance_directory}")
+ contents.append(collection_command)
+
+ with open(script_name, "w") as collection_script:
+ collection_script.write(os.linesep.join(contents))
+
+ print()
+ print(f"{script_name} contents:")
+ print("******************************************")
+ print(os.linesep.join(contents))
+ print("******************************************")
+
+ make_executable(script_name)
+
+ run_command([
+ python_path, path.join(superpmi_directory, "superpmi.py"), "collect", "-core_root", core_root,
+ # Disable ReadyToRun so we always JIT R2R methods and collect them
+ "--use_zapdisable",
+ "-output_mch_path", output_mch_name, "-log_file", log_file, "-log_level", "debug",
+ script_name], _exit_on_fail=True)
+
+
+def strip_unrelated_mc(coreclr_args, old_mch_filename, new_mch_filename):
+ """Perform the post processing of produced .mch file by stripping the method contexts
+ that are specific to BenchmarkDotnet boilerplate code and hard
+
+ Args:
+ coreclr_args (CoreclrArguments): Arguments
+ old_mch_filename (string): Name of source .mch file
+ new_mch_filename (string): Name of new .mch file to produce post-processing.
+ """
+ performance_directory = coreclr_args.performance_directory
+ core_root = coreclr_args.core_root
+ methods_to_strip_list = path.join(performance_directory, "methods_to_strip.mcl")
+
+ mcs_exe = path.join(core_root, "mcs")
+ mcs_command = [mcs_exe, "-dumpMap", old_mch_filename]
+
+ # Gather method list to strip
+ (mcs_out, _, return_code) = run_command(mcs_command)
+ if return_code != 0:
+ # If strip command fails, then just copy the old_mch to new_mch
+ print(f"-dumpMap failed. Copying {old_mch_filename} to {new_mch_filename}.")
+ copyfile(old_mch_filename, new_mch_filename)
+ copyfile(old_mch_filename + ".mct", new_mch_filename + ".mct")
+ return
+
+ method_context_list = mcs_out.decode("utf-8").split(os.linesep)
+ filtered_context_list = []
+
+ match_pattern = re.compile('^(\\d+),(BenchmarkDotNet|Perfolizer)')
+ print("Method indices to strip:")
+ for mc_entry in method_context_list:
+ matched = match_pattern.match(mc_entry)
+ if matched:
+ print(matched.group(1))
+ filtered_context_list.append(matched.group(1))
+ print(f"Total {len(filtered_context_list)} methods.")
+
+ with open(methods_to_strip_list, "w") as f:
+ f.write('\n'.join(filtered_context_list))
+
+ # Strip and produce new .mcs file
+ if run_command([mcs_exe, "-strip", methods_to_strip_list, old_mch_filename, new_mch_filename])[2] != 0:
+ # If strip command fails, then just copy the old_mch to new_mch
+ print(f"-strip failed. Copying {old_mch_filename} to {new_mch_filename}.")
+ copyfile(old_mch_filename, new_mch_filename)
+ copyfile(old_mch_filename + ".mct", new_mch_filename + ".mct")
+ return
+
+ # Create toc file
+ run_command([mcs_exe, "-toc", new_mch_filename])
+
+
+def main(main_args):
+ """ Main entry point
+
+ Args:
+ main_args ([type]): Arguments to the script
+ """
+ coreclr_args = setup_args(main_args)
+
+ all_output_mch_name = path.join(coreclr_args.output_mch_path + "_all.mch")
+ build_and_run(coreclr_args, all_output_mch_name)
+ if os.path.isfile(all_output_mch_name):
+ pass
+ else:
+ print("No mch file generated.")
+
+ strip_unrelated_mc(coreclr_args, all_output_mch_name, coreclr_args.output_mch_path)
+
+
+if __name__ == "__main__":
+ args = parser.parse_args()
+ sys.exit(main(args))
#!/usr/bin/env python3
#
-## Licensed to the .NET Foundation under one or more agreements.
-## The .NET Foundation licenses this file to you under the MIT license.
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
#
##
-# Title : superpmi-setup.py
+# Title : superpmi_setup.py
#
# Notes:
#
from os import linesep, listdir, path, walk
from os.path import isfile, join, getsize
from coreclr_arguments import *
+from superpmi import ChangeDir
# Start of parser object creation.
MAX_FILES_COUNT = 1500
+
def setup_args(args):
""" Setup the args for SuperPMI to use.
if file_size < max_size:
for p_index in partitions:
total_in_curr_par = sum(n for _, n in partitions[p_index])
- if (((total_in_curr_par + file_size) < max_size) and (len(partitions[p_index]) < MAX_FILES_COUNT)):
+ if ((total_in_curr_par + file_size) < max_size) and (len(partitions[p_index]) < MAX_FILES_COUNT):
partitions[p_index].append(curr_file)
found_bucket = True
break
return partitions
-def run_command(command_to_run, _cwd=None):
+def run_command(command_to_run, _exit_on_fail=False):
""" Runs the command.
Args:
command_to_run ([string]): Command to run along with arguments.
- _cmd (string): Current working directory.
+ _exit_on_fail (bool): If it should exit on failure.
+ Returns:
+ (string, string): Returns a tuple of stdout and stderr
"""
print("Running: " + " ".join(command_to_run))
- with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=_cwd) as proc:
- stdout, stderr = proc.communicate()
- if len(stdout) > 0:
- print(stdout.decode("utf-8"))
- if len(stderr) > 0:
- print(stderr.decode("utf-8"))
+ command_stdout = ""
+ command_stderr = ""
+ return_code = 1
+ with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc:
+ command_stdout, command_stderr = proc.communicate()
+ return_code = proc.returncode
+
+ if len(command_stdout) > 0:
+ print(command_stdout.decode("utf-8"))
+ if len(command_stderr) > 0:
+ print(command_stderr.decode("utf-8"))
+ if _exit_on_fail and return_code != 0:
+ print("Command failed. Exiting.")
+ sys.exit(1)
+ return command_stdout, command_stderr, return_code
def copy_directory(src_path, dst_path, verbose_output=True, match_func=lambda path: True):
shutil.copy2(f, dst_path_of_file)
-def partition_files(src_directory, dst_directory, max_size, exclude_directories=[], exclude_files=native_binaries_to_ignore):
+def partition_files(src_directory, dst_directory, max_size, exclude_directories=[],
+ exclude_files=native_binaries_to_ignore):
""" Copy bucketized files based on size to destination folder.
Args:
index += 1
+def setup_microbenchmark(workitem_directory, arch):
+ """ Perform setup of microbenchmarks
+
+ Args:
+ workitem_directory (string): Path to work
+ arch (string): Architecture for which dotnet will be installed
+ """
+ performance_directory = path.join(workitem_directory, "performance")
+
+ run_command(
+ ["git", "clone", "--quiet", "--depth", "1", "https://github.com/dotnet/performance", performance_directory])
+
+ with ChangeDir(performance_directory):
+ dotnet_directory = os.path.join(performance_directory, "tools", "dotnet", arch)
+ dotnet_install_script = os.path.join(performance_directory, "scripts", "dotnet.py")
+
+ if not isfile(dotnet_install_script):
+ print("Missing " + dotnet_install_script)
+ return
+
+ run_command(
+ get_python_name() + [dotnet_install_script, "install", "--architecture", arch, "--install-dir", dotnet_directory, "--verbose"])
+
+def get_python_name():
+ """Gets the python name
+
+ Returns:
+ string: Returns the appropriate python name depending on the OS.
+ """
+ if is_windows:
+ return ["py", "-3"]
+ else:
+ return ["python3"]
+
+
def set_pipeline_variable(name, value):
""" This method sets pipeline variable.
value (string): Value of the variable.
"""
define_variable_format = "##vso[task.setvariable variable={0}]{1}"
- print("{0} -> {1}".format(name, value)) # logging
- print(define_variable_format.format(name, value)) # set variable
+ print("{0} -> {1}".format(name, value)) # logging
+ print(define_variable_format.format(name, value)) # set variable
def main(main_args):
print('Copying {} -> {}'.format(coreclr_args.core_root_directory, superpmi_dst_directory))
copy_directory(coreclr_args.core_root_directory, superpmi_dst_directory, match_func=acceptable_copy)
- # Clone and build jitutils
- try:
- with tempfile.TemporaryDirectory() as jitutils_directory:
- run_command(
- ["git", "clone", "--quiet", "--depth", "1", "https://github.com/dotnet/jitutils", jitutils_directory])
- # Set dotnet path to run bootstrap
- os.environ["PATH"] = path.join(source_directory, ".dotnet") + os.pathsep + os.environ["PATH"]
- bootstrap_file = "bootstrap.cmd" if is_windows else "bootstrap.sh"
- run_command([path.join(jitutils_directory, bootstrap_file)], jitutils_directory)
-
- copy_files(path.join(jitutils_directory, "bin"), superpmi_dst_directory, [path.join(jitutils_directory, "bin", "pmi.dll")])
- except PermissionError as pe_error:
- # Details: https://bugs.python.org/issue26660
- print('Ignoring PermissionError: {0}'.format(pe_error))
-
# Workitem directories
workitem_directory = path.join(source_directory, "workitem")
- pmiassemblies_directory = path.join(workitem_directory, "pmiAssembliesDirectory")
-
- # NOTE: we can't use the build machine ".dotnet" to run on all platforms. E.g., the Windows x86 build uses a
- # Windows x64 .dotnet\dotnet.exe that can't load a 32-bit shim. Thus, we always use corerun from Core_Root to invoke crossgen2.
- # The following will copy .dotnet to the correlation payload in case we change our mind, and need or want to use it for some scenarios.
-
- # # Copy ".dotnet" to correlation_payload_directory for crossgen2 job; it is needed to invoke crossgen2.dll
- # if coreclr_args.collection_type == "crossgen2":
- # dotnet_src_directory = path.join(source_directory, ".dotnet")
- # dotnet_dst_directory = path.join(correlation_payload_directory, ".dotnet")
- # print('Copying {} -> {}'.format(dotnet_src_directory, dotnet_dst_directory))
- # copy_directory(dotnet_src_directory, dotnet_dst_directory, verbose_output=False)
-
- # payload
- input_artifacts = path.join(pmiassemblies_directory, coreclr_args.collection_name)
- exclude_directory = ['Core_Root'] if coreclr_args.collection_name == "tests" else []
- exclude_files = native_binaries_to_ignore
- if coreclr_args.collection_type == "crossgen2":
- print('Adding exclusions for crossgen2')
- # Currently, trying to crossgen2 R2RTest\Microsoft.Build.dll causes a pop-up failure, so exclude it.
- exclude_files += [ "Microsoft.Build.dll" ]
- partition_files(coreclr_args.input_directory, input_artifacts, coreclr_args.max_size, exclude_directory, exclude_files)
+ input_artifacts = ""
+
+ if coreclr_args.collection_name == "benchmarks":
+ # Setup microbenchmarks
+ setup_microbenchmark(workitem_directory, arch)
+ else:
+ # Setup for pmi/crossgen runs
+
+ # Clone and build jitutils
+ try:
+ with tempfile.TemporaryDirectory() as jitutils_directory:
+ run_command(
+ ["git", "clone", "--quiet", "--depth", "1", "https://github.com/dotnet/jitutils", jitutils_directory])
+ # Set dotnet path to run bootstrap
+ os.environ["PATH"] = path.join(source_directory, ".dotnet") + os.pathsep + os.environ["PATH"]
+ bootstrap_file = "bootstrap.cmd" if is_windows else "bootstrap.sh"
+ run_command([path.join(jitutils_directory, bootstrap_file)], jitutils_directory)
+
+ copy_files(path.join(jitutils_directory, "bin"), superpmi_dst_directory, [path.join(jitutils_directory, "bin", "pmi.dll")])
+ except PermissionError as pe_error:
+ # Details: https://bugs.python.org/issue26660
+ print('Ignoring PermissionError: {0}'.format(pe_error))
+
+ # NOTE: we can't use the build machine ".dotnet" to run on all platforms. E.g., the Windows x86 build uses a
+ # Windows x64 .dotnet\dotnet.exe that can't load a 32-bit shim. Thus, we always use corerun from Core_Root to invoke crossgen2.
+ # The following will copy .dotnet to the correlation payload in case we change our mind, and need or want to use it for some scenarios.
+
+ # # Copy ".dotnet" to correlation_payload_directory for crossgen2 job; it is needed to invoke crossgen2.dll
+ # if coreclr_args.collection_type == "crossgen2":
+ # dotnet_src_directory = path.join(source_directory, ".dotnet")
+ # dotnet_dst_directory = path.join(correlation_payload_directory, ".dotnet")
+ # print('Copying {} -> {}'.format(dotnet_src_directory, dotnet_dst_directory))
+ # copy_directory(dotnet_src_directory, dotnet_dst_directory, verbose_output=False)
+
+ # payload
+ pmiassemblies_directory = path.join(workitem_directory, "pmiAssembliesDirectory")
+ input_artifacts = path.join(pmiassemblies_directory, coreclr_args.collection_name)
+ exclude_directory = ['Core_Root'] if coreclr_args.collection_name == "tests" else []
+ exclude_files = native_binaries_to_ignore
+ if coreclr_args.collection_type == "crossgen2":
+ print('Adding exclusions for crossgen2')
+ # Currently, trying to crossgen2 R2RTest\Microsoft.Build.dll causes a pop-up failure, so exclude it.
+ exclude_files += [ "Microsoft.Build.dll" ]
+ partition_files(coreclr_args.input_directory, input_artifacts, coreclr_args.max_size, exclude_directory, exclude_files)
# Set variables
print('Setting pipeline variables:')
set_pipeline_variable("CorrelationPayloadDirectory", correlation_payload_directory)
set_pipeline_variable("WorkItemDirectory", workitem_directory)
set_pipeline_variable("InputArtifacts", input_artifacts)
- if is_windows:
- set_pipeline_variable("Python", "py -3")
- else:
- set_pipeline_variable("Python", "python3")
+ set_pipeline_variable("Python", ' '.join(get_python_name()))
set_pipeline_variable("Architecture", arch)
set_pipeline_variable("Creator", creator)
set_pipeline_variable("Queue", helix_queue)