def add_arguments(parser: ArgumentParser) -> ArgumentParser: ''' Adds new arguments to the specified ArgumentParser object. ''' def __dotnet_configuration(configuration: str) -> str: for config in get_supported_configurations(): is_valid = config.casefold() == configuration.casefold() if is_valid: return config raise ArgumentTypeError( 'Unknown configuration: {}.'.format(configuration)) supported_configurations = get_supported_configurations() parser.add_argument( '-c', '--configuration', required=False, default=supported_configurations[0], choices=supported_configurations, type=__dotnet_configuration, help=SUPPRESS, ) parser.add_argument( '-f', '--frameworks', required=False, choices=ChannelMap.get_supported_frameworks(), nargs='+', help='''The framework to build/run for. ''' '''The target framework must also be specified in the project ''' '''file.''', ) parser.add_argument( '--incremental', required=False, default='yes', choices=['yes', 'no'], type=str, help='''Controls whether previous packages/bin/obj folders should ''' '''be kept or removed before the dotnet restore/build/run are ''' '''executed (Default yes).''', ) # BenchmarkDotNet parser.add_argument( '--enable-hardware-counters', dest='enable_pmc', required=False, default=False, action='store_true', help='''Enables the following performance metric counters: ''' '''BranchMispredictions+CacheMisses+InstructionRetired''', ) parser.add_argument( '--filter', required=False, nargs='+', help='Glob patterns to execute benchmarks that match.', ) def __valid_file_path(file_path: str) -> str: '''Verifies that specified file path exists.''' file_path = path.abspath(file_path) if not path.isfile(file_path): raise ArgumentTypeError('{} does not exist.'.format(file_path)) return file_path parser.add_argument( '--corerun', dest='corerun', required=False, nargs='+', type=__valid_file_path, help='Full path to CoreRun.exe (corerun on Unix)', ) parser.add_argument( '--cli', dest='cli', required=False, type=__valid_file_path, help='Full path to dotnet.exe', ) def __get_bdn_arguments(user_input: str) -> list: file = StringIO(user_input) reader = csv.reader(file, delimiter=' ') for args in reader: return args return [] parser.add_argument( '--wasm', dest='wasm', required=False, default=False, action='store_true', help='Tests should be run with the wasm runtime' ) parser.add_argument( '--bdn-arguments', dest='bdn_arguments', required=False, type=__get_bdn_arguments, help='''Command line arguments to be passed to the BenchmarkDotNet ''' '''harness.''', ) parser.add_argument( '--bdn-artifacts', dest='bdn_artifacts', required=False, type=str, help='''Path to artifacts directory to be passed to the BenchmarkDotNet ''' '''harness.''', ) def __valid_dir_path(file_path: str) -> str: '''Verifies that specified file path exists.''' file_path = path.abspath(file_path) if not path.isdir(file_path): raise ArgumentTypeError('{} does not exist.'.format(file_path)) return file_path def __csproj_file_path(file_path: str) -> dotnet.CSharpProjFile: file_path = __valid_file_path(file_path) return dotnet.CSharpProjFile( file_name=file_path, working_directory=path.dirname(file_path) ) microbenchmarks_csproj = path.join( get_repo_root_path(), 'src', 'benchmarks', 'micro', 'MicroBenchmarks.csproj' ) parser.add_argument( '--csproj', dest='csprojfile', required=False, type=__csproj_file_path, default=dotnet.CSharpProjFile( file_name=microbenchmarks_csproj, working_directory=path.dirname(microbenchmarks_csproj) ), help='''C# project file name with the benchmarks to build/run. ''' '''The default project is the MicroBenchmarks.csproj''' ) def __absolute_path(file_path: str) -> str: ''' Return a normalized absolutized version of the specified file_path path. ''' return path.abspath(file_path) parser.add_argument( '--bin-directory', dest='bin_directory', required=False, default=path.join(get_repo_root_path(), 'artifacts', 'bin'), type=__absolute_path, help='Root of the bin directory', ) return parser
def install( architecture: str, channels: list, versions: str, verbose: bool, install_dir: str = None) -> None: ''' Downloads dotnet cli into the tools folder. ''' __log_script_header("Downloading DotNet Cli") if not install_dir: install_dir = __get_directory(architecture) if not path.exists(install_dir): makedirs(install_dir) getLogger().info("DotNet Install Path: '%s'", install_dir) # Download appropriate dotnet install script dotnetInstallScriptExtension = '.ps1' if platform == 'win32' else '.sh' dotnetInstallScriptName = 'dotnet-install' + dotnetInstallScriptExtension url = 'https://dot.net/v1/' dotnetInstallScriptUrl = url + dotnetInstallScriptName dotnetInstallScriptPath = path.join(install_dir, dotnetInstallScriptName) getLogger().info('Downloading %s', dotnetInstallScriptUrl) urlretrieve(dotnetInstallScriptUrl, dotnetInstallScriptPath) if platform != 'win32': chmod(dotnetInstallScriptPath, S_IRWXU) dotnetInstallInterpreter = [ 'powershell.exe', '-NoProfile', '-ExecutionPolicy', 'Bypass', dotnetInstallScriptPath ] if platform == 'win32' else [dotnetInstallScriptPath] # If Version is supplied, pull down the specified version common_cmdline_args = dotnetInstallInterpreter + [ '-InstallDir', install_dir, '-Architecture', architecture ] # Install Runtime/SDKs if versions: for version in versions: cmdline_args = common_cmdline_args + ['-Version', version] RunCommand(cmdline_args, verbose=verbose).run( get_repo_root_path() ) # Only check channels if versions are not supplied. # When we supply a version, but still pull down with -Channel, we will use # whichever sdk is newer. So if we are trying to check an older version, # or if there is a new version between when we start a run and when we actually # run, we will be testing the "wrong" version, ie, not the version we specified. if (not versions) and channels: for channel in channels: cmdline_args = common_cmdline_args + ['-Channel', channel] RunCommand(cmdline_args, verbose=verbose).run( get_repo_root_path() ) # Set DotNet Cli environment variables. environ['DOTNET_CLI_TELEMETRY_OPTOUT'] = '1' environ['DOTNET_MULTILEVEL_LOOKUP'] = '0' environ['UseSharedCompilation'] = 'false' environ['DOTNET_ROOT'] = install_dir # Add installed dotnet cli to PATH environ["PATH"] = install_dir + pathsep + environ["PATH"] # If we have copied dotnet from a different machine, it will not be executable. Fix this if platform != 'win32': chmod(path.join(install_dir, 'dotnet'), S_IRWXU)
def __main(args: list) -> int: validate_supported_runtime() args = __process_arguments(args) verbose = not args.quiet setup_loggers(verbose=verbose) # if repository is not set, then we are doing a core-sdk in performance repo run # if repository is set, user needs to supply the commit_sha if not ((args.commit_sha is None) == (args.repository is None)): raise ValueError( 'Either both commit_sha and repository should be set or neither') target_framework_monikers = micro_benchmarks \ .FrameworkAction \ .get_target_framework_monikers(args.frameworks) # Acquire necessary tools (dotnet, and BenchView) # For arm64 runs, download the x64 version so we can get the information we need, but set all variables # as if we were running normally. This is a workaround due to the fact that arm64 binaries cannot run # in the cross containers, so we are running the ci setup script in a normal ubuntu container architecture = 'x64' if args.architecture == 'arm64' else args.architecture init_tools(architecture=architecture, dotnet_versions=args.dotnet_versions, target_framework_monikers=target_framework_monikers, verbose=verbose) # dotnet --info dotnet.info(verbose=verbose) variable_format = 'set %s=%s\n' if sys.platform == 'win32' else 'export %s=%s\n' owner, repo = ('dotnet', 'core-sdk') if args.repository is None else ( dotnet.get_repository(args.repository)) config_string = ';'.join( args.build_configs) if sys.platform == 'win32' else '"%s"' % ';'.join( args.build_configs) is_netcoreapp_30 = False output = '' with push_dir(get_repo_root_path()): output = check_output(['git', 'rev-parse', 'HEAD']) decoded_lines = [] for line in output.splitlines(): decoded_lines = decoded_lines + [line.decode('utf-8')] decoded_output = ''.join(decoded_lines) perfHash = decoded_output if args.get_perf_hash else args.perf_hash for framework in target_framework_monikers: if framework.startswith('netcoreapp'): if framework == 'netcoreapp3.0': is_netcoreapp_30 = True target_framework_moniker = micro_benchmarks.FrameworkAction.get_target_framework_moniker( framework) dotnet_version = dotnet.get_dotnet_version( target_framework_moniker, args.cli) commit_sha = dotnet.get_dotnet_sdk( target_framework_moniker, args.cli) if args.commit_sha is None else args.commit_sha source_timestamp = dotnet.get_commit_date(target_framework_moniker, commit_sha, args.repository) branch = micro_benchmarks.FrameworkAction.get_branch( target_framework_moniker) if not args.branch else args.branch getLogger().info("Writing script to %s" % args.output_file) with open(args.output_file, 'w') as out_file: out_file.write(variable_format % ('PERFLAB_INLAB', '1')) out_file.write(variable_format % ('PERFLAB_REPO', '/'.join([owner, repo]))) out_file.write(variable_format % ('PERFLAB_BRANCH', branch)) out_file.write(variable_format % ('PERFLAB_PERFHASH', perfHash)) out_file.write(variable_format % ('PERFLAB_HASH', commit_sha)) out_file.write(variable_format % ('PERFLAB_QUEUE', args.queue)) out_file.write(variable_format % ('PERFLAB_BUILDNUM', args.build_number)) out_file.write(variable_format % ('PERFLAB_BUILDARCH', args.architecture)) out_file.write(variable_format % ('PERFLAB_LOCALE', args.locale)) out_file.write(variable_format % ('PERFLAB_BUILDTIMESTAMP', source_timestamp)) out_file.write(variable_format % ('PERFLAB_CONFIGS', config_string)) out_file.write(variable_format % ('DOTNET_VERSION', dotnet_version)) else: with open(args.output_file, 'w') as out_file: out_file.write(variable_format % ('PERFLAB_INLAB', '0')) # On non-windows platforms, delete dotnet, so that we don't have to deal with chmoding it on the helix machines # This is only necessary for netcoreapp3.0 if sys.platform != 'win32' and is_netcoreapp_30: dotnet.remove_dotnet(architecture)
def shutdown_server(verbose: bool) -> None: ''' Shuts down the dotnet server ''' cmdline = ['dotnet', 'build-server', 'shutdown'] RunCommand(cmdline, verbose=verbose).run(get_repo_root_path())
def bin_path(self) -> str: '''Gets the directory in which the built binaries will be placed.''' return path.join(get_repo_root_path(), 'bin')
def install( architecture: str, channels: list, versions: str, verbose: bool, install_dir: str = None) -> None: ''' Downloads dotnet cli into the tools folder. ''' __log_script_header("Downloading DotNet Cli") if not install_dir: install_dir = __get_directory(architecture) if not path.exists(install_dir): makedirs(install_dir) getLogger().info("DotNet Install Path: '%s'", install_dir) # Download appropriate dotnet install script dotnetInstallScriptExtension = '.ps1' if platform == 'win32' else '.sh' dotnetInstallScriptName = 'dotnet-install' + dotnetInstallScriptExtension url = 'https://dot.net/v1/' dotnetInstallScriptUrl = url + dotnetInstallScriptName dotnetInstallScriptPath = path.join(install_dir, dotnetInstallScriptName) getLogger().info('Downloading %s', dotnetInstallScriptUrl) count = 0 while count < 3: try: with urlopen(dotnetInstallScriptUrl, context=ssl._create_unverified_context()) as response: if "html" in response.info()['Content-Type']: count = count + 1 sleep(1) # sleep one second continue with open(dotnetInstallScriptPath, 'wb') as outfile: outfile.write(response.read()) break except Exception: count = count + 1 sleep(1) continue if count == 3: getLogger().error("Fatal error: could not download dotnet-install script") raise Exception("Fatal error: could not download dotnet-install script") if platform != 'win32': chmod(dotnetInstallScriptPath, S_IRWXU) dotnetInstallInterpreter = [ 'powershell.exe', '-NoProfile', '-ExecutionPolicy', 'Bypass', dotnetInstallScriptPath ] if platform == 'win32' else [dotnetInstallScriptPath] # If Version is supplied, pull down the specified version common_cmdline_args = dotnetInstallInterpreter + [ '-InstallDir', install_dir, '-Architecture', architecture ] # Install Runtime/SDKs if versions: for version in versions: cmdline_args = common_cmdline_args + ['-Version', version] RunCommand(cmdline_args, verbose=verbose, retry=1).run( get_repo_root_path() ) # Only check channels if versions are not supplied. # When we supply a version, but still pull down with -Channel, we will use # whichever sdk is newer. So if we are trying to check an older version, # or if there is a new version between when we start a run and when we actually # run, we will be testing the "wrong" version, ie, not the version we specified. if (not versions) and channels: for channel in channels: cmdline_args = common_cmdline_args + ['-Channel', ChannelMap.get_branch(channel)] if ChannelMap.get_quality_from_channel(channel) is not None: cmdline_args += ['-Quality', ChannelMap.get_quality_from_channel(channel)] RunCommand(cmdline_args, verbose=verbose, retry=1).run( get_repo_root_path() ) # Set DotNet Cli environment variables. environ['DOTNET_CLI_TELEMETRY_OPTOUT'] = '1' environ['DOTNET_MULTILEVEL_LOOKUP'] = '0' environ['UseSharedCompilation'] = 'false' environ['DOTNET_ROOT'] = install_dir # Add installed dotnet cli to PATH environ["PATH"] = install_dir + pathsep + environ["PATH"] # If we have copied dotnet from a different machine, then it may not be # marked as executable. Fix this. if platform != 'win32': chmod(path.join(install_dir, 'dotnet'), S_IRWXU)
def __main(args: list) -> int: validate_supported_runtime() args = __process_arguments(args) verbose = not args.quiet setup_loggers(verbose=verbose) # if repository is not set, then we are doing a core-sdk in performance repo run # if repository is set, user needs to supply the commit_sha if not ((args.commit_sha is None) == (args.repository is None)): raise ValueError('Either both commit_sha and repository should be set or neither') # Acquire necessary tools (dotnet) # For arm64 runs, download the x64 version so we can get the information we need, but set all variables # as if we were running normally. This is a workaround due to the fact that arm64 binaries cannot run # in the cross containers, so we are running the ci setup script in a normal ubuntu container architecture = 'x64' if args.architecture == 'arm64' else args.architecture init_tools( architecture=architecture, dotnet_versions=args.dotnet_versions, channel=args.channel, verbose=verbose, install_dir=args.install_dir ) # dotnet --info dotnet.info(verbose=verbose) # When running on internal repos, the repository comes to us incorrectly # (ie https://github.com/dotnet-coreclr). Replace dashes with slashes in that case. repo_url = None if args.repository is None else args.repository.replace('-','/') variable_format = 'set %s=%s\n' if sys.platform == 'win32' else 'export %s=%s\n' path_variable = 'set PATH=%%PATH%%;%s\n' if sys.platform == 'win32' else 'export PATH=$PATH:%s\n' dotnet_path = '%HELIX_CORRELATION_PAYLOAD%\dotnet' if sys.platform == 'win32' else '$HELIX_CORRELATION_PAYLOAD/dotnet' owner, repo = ('dotnet', 'core-sdk') if args.repository is None else (dotnet.get_repository(repo_url)) config_string = ';'.join(args.build_configs) if sys.platform == 'win32' else '"%s"' % ';'.join(args.build_configs) remove_dotnet = False output = '' with push_dir(get_repo_root_path()): output = check_output(['git', 'rev-parse', 'HEAD']) decoded_lines = [] for line in output.splitlines(): decoded_lines = decoded_lines + [line.decode('utf-8')] decoded_output = ''.join(decoded_lines) perfHash = decoded_output if args.get_perf_hash else args.perf_hash remove_frameworks = ['netcoreapp3.0', 'netcoreapp5.0'] framework = ChannelMap.get_target_framework_moniker(args.channel) if framework.startswith('netcoreapp'): if framework in remove_frameworks: remove_dotnet = True target_framework_moniker = dotnet.FrameworkAction.get_target_framework_moniker(framework) dotnet_version = dotnet.get_dotnet_version(target_framework_moniker, args.cli) commit_sha = dotnet.get_dotnet_sdk(target_framework_moniker, args.cli) if args.commit_sha is None else args.commit_sha source_timestamp = dotnet.get_commit_date(target_framework_moniker, commit_sha, repo_url) branch = ChannelMap.get_branch(args.channel) if not args.branch else args.branch getLogger().info("Writing script to %s" % args.output_file) with open(args.output_file, 'w') as out_file: out_file.write(variable_format % ('PERFLAB_INLAB', '1')) out_file.write(variable_format % ('PERFLAB_REPO', '/'.join([owner, repo]))) out_file.write(variable_format % ('PERFLAB_BRANCH', branch)) out_file.write(variable_format % ('PERFLAB_PERFHASH', perfHash)) out_file.write(variable_format % ('PERFLAB_HASH', commit_sha)) out_file.write(variable_format % ('PERFLAB_QUEUE', args.queue)) out_file.write(variable_format % ('PERFLAB_BUILDNUM', args.build_number)) out_file.write(variable_format % ('PERFLAB_BUILDARCH', args.architecture)) out_file.write(variable_format % ('PERFLAB_LOCALE', args.locale)) out_file.write(variable_format % ('PERFLAB_BUILDTIMESTAMP', source_timestamp)) out_file.write(variable_format % ('PERFLAB_CONFIGS', config_string)) out_file.write(variable_format % ('DOTNET_VERSION', dotnet_version)) out_file.write(variable_format % ('PERFLAB_TARGET_FRAMEWORKS', framework)) out_file.write(variable_format % ('DOTNET_CLI_TELEMETRY_OPTOUT', '1')) out_file.write(variable_format % ('DOTNET_MULTILEVEL_LOOKUP', '0')) out_file.write(variable_format % ('UseSharedCompilation', 'false')) out_file.write(variable_format % ('DOTNET_ROOT', dotnet_path)) out_file.write(path_variable % dotnet_path) else: with open(args.output_file, 'w') as out_file: out_file.write(variable_format % ('PERFLAB_INLAB', '0')) out_file.write(variable_format % ('PERFLAB_TARGET_FRAMEWORKS', framework)) out_file.write(path_variable % dotnet_path) # On non-windows platforms, delete dotnet, so that we don't have to deal with chmoding it on the helix machines # This is only necessary for netcoreapp3.0 and netcoreapp5.0 if sys.platform != 'win32' and remove_dotnet: dotnet.remove_dotnet(architecture) # The '_Framework' is needed for specifying frameworks in proj files and for building tools later in the pipeline __write_pipeline_variable('_Framework', framework)
def _get_gcinfra_path() -> str: return os.path.join(get_repo_root_path(), "src", "benchmarks", "gc")
__log_script_header("Running .NET micro benchmarks for '{}'".format( framework )) # dotnet run BENCHMARKS_CSPROJ.run(configuration, framework, verbose, *args) def __log_script_header(message: str): getLogger().info('-' * len(message)) getLogger().info(message) getLogger().info('-' * len(message)) BENCHMARKS_CSPROJ = dotnet.CSharpProject( working_directory=path.join( get_repo_root_path(), 'src', 'benchmarks', 'micro'), csproj_file='MicroBenchmarks.csproj' ) def __main(args: list) -> int: try: validate_supported_runtime() args = __process_arguments(args) configuration = args.configuration frameworks = args.frameworks incremental = args.incremental verbose = args.verbose setup_loggers(verbose=verbose)