Example #1
0
def get_commit_date(framework: str,
                    commit_sha: str,
                    repository: str = None) -> str:
    '''
    Gets the .NET Core committer date using the GitHub Web API from the
    repository.
    '''
    if not framework:
        raise ValueError('Target framework was not defined.')
    if not commit_sha:
        raise ValueError('.NET Commit sha was not defined.')

    url = None
    urlformat = 'https://api.github.com/repos/%s/%s/commits/%s'
    if repository is None:
        # The origin of the repo where the commit belongs to has changed
        # between release. Here we attempt to naively guess the repo.
        core_sdk_frameworks = ChannelMap.get_supported_frameworks()
        core_sdk_frameworks.remove('netcoreapp2.1')
        repo = 'core-sdk' if framework in core_sdk_frameworks else 'cli'
        url = urlformat % ('dotnet', repo, commit_sha)
    else:
        owner, repo = get_repository(repository)
        url = urlformat % (owner, repo, commit_sha)

    build_timestamp = None
    with urlopen(url) as response:
        getLogger().info("Commit: %s", url)
        item = loads(response.read().decode('utf-8'))
        build_timestamp = item['commit']['committer']['date']

    if not build_timestamp:
        raise RuntimeError('Could not get timestamp for commit %s' %
                           commit_sha)
    return build_timestamp
Example #2
0
 def get_target_framework_moniker(framework: str) -> str:
     '''
     Translates framework name to target framework moniker (TFM)
     To run CoreRT benchmarks we need to run the host BDN process as latest
     .NET Core the host process will build and run CoreRT benchmarks
     '''
     return ChannelMap.get_target_framework_moniker("main") if framework == 'corert' else framework
Example #3
0
def __process_arguments(args: list):
    parser = ArgumentParser(
        description='DotNet Cli wrapper.',
        allow_abbrev=False
    )
    subparsers = parser.add_subparsers(
        title='Subcommands',
        description='Supported DotNet Cli subcommands',
        dest='install',
    )
    subparsers.required = True

    install_parser = subparsers.add_parser(
        'install',
        allow_abbrev=False,
        help='Installs dotnet cli',
    )

    install_parser.add_argument(
        '--channels',
        dest='channels',
        required=False,
        nargs='+',
        default=['main'],
        choices= ChannelMap.get_supported_channels(),
        help='Download DotNet Cli from the Channel specified.'
    )

    install_parser = __add_arguments(install_parser)

    # private install arguments.
    install_parser.add_argument(
        '--install-dir',
        dest='install_dir',
        required=False,
        type=str,
        help='''Path to where to install dotnet. Note that binaries will be '''
             '''placed directly in a given directory.''',
    )
    install_parser.add_argument(
        '-v', '--verbose',
        required=False,
        default=False,
        action='store_true',
        help='Turns on verbosity (default "False")',
    )
    return parser.parse_args(args)
Example #4
0
def init_tools(architecture: str, dotnet_versions: str,
               target_framework_monikers: list, verbose: bool) -> None:
    '''
    Install tools used by this repository into the tools folder.
    This function writes a semaphore file when tools have been successfully
    installed in order to avoid reinstalling them on every rerun.
    '''
    getLogger().info('Installing tools.')
    channels = [
        ChannelMap.get_channel_from_target_framework_moniker(
            target_framework_moniker)
        for target_framework_moniker in target_framework_monikers
    ]

    dotnet.install(
        architecture=architecture,
        channels=channels,
        versions=dotnet_versions,
        verbose=verbose,
    )
Example #5
0
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
Example #6
0
def add_arguments(parser: ArgumentParser) -> ArgumentParser:
    '''Adds new arguments to the specified ArgumentParser object.'''

    if not isinstance(parser, ArgumentParser):
        raise TypeError('Invalid parser.')

    # Download DotNet Cli
    dotnet.add_arguments(parser)
    micro_benchmarks.add_arguments(parser)

    parser.add_argument('--channel',
                        dest='channel',
                        required=True,
                        choices=ChannelMap.get_supported_channels(),
                        type=str,
                        help='Channel to download product from')

    parser.add_argument('--branch',
                        dest='branch',
                        required=False,
                        type=str,
                        help='Product branch.')
    parser.add_argument('--commit-sha',
                        dest='commit_sha',
                        required=False,
                        type=str,
                        help='Product commit sha.')
    parser.add_argument('--repository',
                        dest='repository',
                        required=False,
                        type=str,
                        help='Product repository.')
    parser.add_argument('--queue',
                        dest='queue',
                        default='testQueue',
                        required=False,
                        type=str,
                        help='Test queue')
    parser.add_argument('--build-number',
                        dest='build_number',
                        default='1234.1',
                        required=False,
                        type=str,
                        help='Build number')

    parser.add_argument('--locale',
                        dest='locale',
                        default='en-US',
                        required=False,
                        type=str,
                        help='Locale')
    parser.add_argument('--perf-hash',
                        dest='perf_hash',
                        default='testSha',
                        required=False,
                        type=str,
                        help='Sha of the performance repo')

    parser.add_argument('--get-perf-hash',
                        dest="get_perf_hash",
                        required=False,
                        action='store_true',
                        default=False,
                        help='Discover the hash of the performance repository')

    parser.add_argument('--output-file',
                        dest='output_file',
                        required=False,
                        default=os.path.join(
                            get_tools_directory(),
                            'machine-setup' + global_extension),
                        type=str,
                        help='Filename to write the setup script to')

    parser.add_argument('--install-dir',
                        dest='install_dir',
                        required=False,
                        type=str,
                        help='Directory to install dotnet to')

    # Generic arguments.
    parser.add_argument(
        '-q',
        '--quiet',
        required=False,
        default=False,
        action='store_true',
        help='Turns off verbosity.',
    )

    parser.add_argument(
        '--build-configs',
        dest="build_configs",
        required=False,
        nargs='+',
        default=[],
        help='Configurations used in the build in key=value format')

    return parser
Example #7
0
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)

    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

    framework = ChannelMap.get_target_framework_moniker(args.channel)
    if framework.startswith('netcoreapp'):
        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)

    # The '_Framework' is needed for specifying frameworks in proj files and for building tools later in the pipeline
    __write_pipeline_variable('_Framework', framework)
Example #8
0
def add_arguments(parser: ArgumentParser) -> ArgumentParser:
    '''Adds new arguments to the specified ArgumentParser object.'''

    if not isinstance(parser, ArgumentParser):
        raise TypeError('Invalid parser.')

    # Download DotNet Cli
    dotnet.add_arguments(parser)
    micro_benchmarks.add_arguments(parser)

    parser.add_argument('--channel',
                        dest='channel',
                        required=True,
                        choices=ChannelMap.get_supported_channels(),
                        type=str,
                        help='Channel to download product from')
    parser.add_argument('--no-pgo',
                        dest='pgo_status',
                        required=False,
                        action='store_const',
                        const='nopgo')
    parser.add_argument('--dynamic-pgo',
                        dest='pgo_status',
                        required=False,
                        action='store_const',
                        const='dynamicpgo')
    parser.add_argument('--full-pgo',
                        dest='pgo_status',
                        required=False,
                        action='store_const',
                        const='fullpgo')
    parser.add_argument('--branch',
                        dest='branch',
                        required=False,
                        type=str,
                        help='Product branch.')
    parser.add_argument('--commit-sha',
                        dest='commit_sha',
                        required=False,
                        type=str,
                        help='Product commit sha.')
    parser.add_argument('--repository',
                        dest='repository',
                        required=False,
                        type=str,
                        help='Product repository.')
    parser.add_argument('--queue',
                        dest='queue',
                        default='testQueue',
                        required=False,
                        type=str,
                        help='Test queue')
    parser.add_argument('--build-number',
                        dest='build_number',
                        default='1234.1',
                        required=False,
                        type=str,
                        help='Build number')

    parser.add_argument('--locale',
                        dest='locale',
                        default='en-US',
                        required=False,
                        type=str,
                        help='Locale')
    parser.add_argument('--perf-hash',
                        dest='perf_hash',
                        default='testSha',
                        required=False,
                        type=str,
                        help='Sha of the performance repo')

    parser.add_argument('--get-perf-hash',
                        dest="get_perf_hash",
                        required=False,
                        action='store_true',
                        default=False,
                        help='Discover the hash of the performance repository')

    parser.add_argument('--output-file',
                        dest='output_file',
                        required=False,
                        default=os.path.join(
                            get_tools_directory(),
                            'machine-setup' + global_extension),
                        type=str,
                        help='Filename to write the setup script to')

    parser.add_argument('--install-dir',
                        dest='install_dir',
                        required=False,
                        type=str,
                        help='Directory to install dotnet to')

    parser.add_argument('--not-in-lab',
                        dest='not_in_lab',
                        required=False,
                        action='store_true',
                        default=False,
                        help='Indicates that this is not running in perflab')

    def __is_valid_dotnet_path(dp: str) -> str:
        if not os.path.isdir(dp):
            raise ArgumentTypeError('Path {} does not exist'.format(dp))
        if not os.path.isfile(os.path.join(dp, 'dotnet')):
            raise ArgumentTypeError('Could not find dotnet in {}'.format(dp))
        return dp

    parser.add_argument('--dotnet-path',
                        dest='dotnet_path',
                        required=False,
                        type=__is_valid_dotnet_path,
                        help='Path to a custom dotnet')

    # Generic arguments.
    parser.add_argument(
        '-q',
        '--quiet',
        required=False,
        default=False,
        action='store_true',
        help='Turns off verbosity.',
    )

    parser.add_argument(
        '--build-configs',
        dest="build_configs",
        required=False,
        nargs='+',
        default=[],
        help='Configurations used in the build in key=value format')

    parser.add_argument('--maui-version',
                        dest='maui_version',
                        default='',
                        required=False,
                        type=str,
                        help='Version of Maui used to build app packages')
    return parser
Example #9
0
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)