Beispiel #1
0
 def check_metrics(self, metrics):
     """Checks compatibility of PAPI metrics.
     
     Extracts all PAPI metrics from `metrics` and executes papi_event_chooser to check compatibility.
     
     Args:
         metrics (list): List of metrics.
         
     Raises:
         ConfigurationError: PAPI metrics are not compatible on the current host.
     """
     papi_metrics = self.parse_metrics(metrics)
     if not papi_metrics:
         return
     self.install()
     event_chooser_cmd = os.path.join(self.bin_path, 'papi_event_chooser')
     cmd = [event_chooser_cmd, 'PRESET'] + papi_metrics
     try:
         util.get_command_output(cmd)
     except CalledProcessError as err:
         for line in err.output.split('\n'):
             if "can't be counted with others" in line:
                 parts = line.split()
                 try:
                     event = parts[1]
                     code = int(parts[-1])
                 except (IndexError, ValueError):
                     continue
                 if code == -1:
                     why = ": %s is not compatible with other events" % event
                 elif code == -8:
                     why = ": %s cannot be counted due to resource limitations" % event
                 else:
                     why = ": %s is not supported on this host" % event
                 break
             elif "can't be found" in line:
                 parts = line.split()
                 try:
                     event = parts[1]
                 except IndexError:
                     continue
                 why = ": event %s is not available on the current host" % event
                 break
         else:
             why = ', and output from papi_event_chooser was not parsable.'
         err = ConfigurationError(("PAPI metrics [%s] are not compatible on the current host%s."
                                   "\n\nYou may ignore this warning if you are cross-compiling.") %
                                  (', '.join(papi_metrics), why),
                                  "Use papi_avail to check metric availability.",
                                  "Spread the desired metrics over multiple measurements.",
                                  "Choose fewer metrics.")
         LOGGER.warning(err)
Beispiel #2
0
    def check_metrics(self, metrics):
        """Checks compatibility of PAPI metrics.

        Extracts all PAPI metrics from `metrics` and executes papi_event_chooser to check compatibility.

        Args:
            metrics (list): List of metrics.

        Raises:
            ConfigurationError: PAPI metrics are not compatible on the current host.
        """
        papi_metrics = self.parse_metrics(metrics)
        if not papi_metrics:
            return
        self.install()
        event_chooser_cmd = os.path.join(self.bin_path, 'papi_event_chooser')
        cmd = [event_chooser_cmd, 'PRESET'] + papi_metrics
        try:
            util.get_command_output(cmd)
        except CalledProcessError as err:
            for line in err.output.split('\n'):
                if "can't be counted with others" in line:
                    parts = line.split()
                    try:
                        event = parts[1]
                        code = int(parts[-1])
                    except (IndexError, ValueError):
                        continue
                    if code == -1:
                        why = ": %s is not compatible with other events" % event
                    elif code == -8:
                        why = ": %s cannot be counted due to resource limitations" % event
                    else:
                        why = ": %s is not supported on this host" % event
                    break
                elif "can't be found" in line:
                    parts = line.split()
                    try:
                        event = parts[1]
                    except IndexError:
                        continue
                    why = ": event %s is not available on the current host" % event
                    break
            else:
                why = ', and output from papi_event_chooser was not parsable.'
            raise ConfigurationError(
                ("PAPI metrics [%s] are not compatible on the current host%s.")
                % (', '.join(papi_metrics), why),
                "Use papi_avail to check metric availability.",
                "Spread the desired metrics over multiple measurements.",
                "Choose fewer metrics.",
                "You may ignore this if you are cross-compiling.")
Beispiel #3
0
 def xml_event_info(self):
     if not self._xml_event_info:
         self.install()
         xml_event_info = util.get_command_output(
             os.path.join(self.bin_path, 'papi_xml_event_info'))
         self._xml_event_info = ElementTree.fromstring(xml_event_info)
     return self._xml_event_info
Beispiel #4
0
    def probe(cls, absolute_path, candidates=None):
        """Determine the compiler family of a given command.

        Executes the command with :any:`version_flags` from all families
        and compares the output against :any:`family_regex`.

        Args:
            absolute_path (str): Absolute path to a compiler command.
            candidates (list): If present, a list of families that are most likely.

        Raises:
            ConfigurationError: Compiler family could not be determined.

        Returns:
            _CompilerFamily: The compiler's family.
        """
        try:
            return cls._probe_cache[absolute_path]
        except KeyError:
            pass
        LOGGER.debug("Probing compiler '%s' to discover compiler family", absolute_path)
        messages = []
        stdout = None
        # Settle down pylint... the __instances__ member is created by __new__
        # pylint: disable=no-member
        if candidates:
            candidate_kbases = {candidate.kbase for candidate in candidates}
            families = candidates + [inst for inst in cls.__instances__ 
                                     if inst not in candidates and inst.kbase in candidate_kbases]
        else:
            families = cls.__instances__
        basename = os.path.basename(absolute_path)
        with_regex, without_regex = [], []
        for family in families:
            if basename in family.commands:
                (with_regex if family.family_regex else without_regex).append(family)
        for family in with_regex:
            cmd = [absolute_path] + family.version_flags
            try:
                stdout = util.get_command_output(cmd)
            except CalledProcessError as err:
                messages.append(err.output)
                LOGGER.debug("%s returned %d: %s", cmd, err.returncode, err.output)
                # Keep going: Cray compilers return nonzero on version flag
            if stdout:
                if re.search(family.family_regex, stdout):
                    LOGGER.debug("'%s' is a %s compiler", absolute_path, family.name)
                    cls._probe_cache[absolute_path] = family
                    return family
                else:
                    LOGGER.debug("'%s' is not a %s compiler", absolute_path, family.name)
        if len(without_regex) > 0:
            guess = without_regex[0]
            if len(without_regex) > 1:
                LOGGER.warning(("Assuming '%s' is a %s compiler but it could be to any of these: %s\n"
                                "If this assumption is incorrect then you should manually specify your compilers"), 
                               absolute_path, guess.name, ', '.join([family.name for family in without_regex]))
            return guess
        raise ConfigurationError("Cannot determine compiler family: %s" % '\n'.join(messages))
Beispiel #5
0
 def _probe_wrapper(self):
     if not self.info.family.show_wrapper_flags:
         return None
     LOGGER.debug("Probing %s wrapper '%s'", self.info.short_descr,
                  self.absolute_path)
     cmd = [self.absolute_path] + self.info.family.show_wrapper_flags
     try:
         stdout = util.get_command_output(cmd)
     except CalledProcessError:
         # If this command didn't accept show_wrapper_flags then it's not a compiler wrapper to begin with,
         # i.e. another command just happens to be the same as a known compiler command.
         raise ConfigurationError(
             "'%s' isn't actually a %s since it doesn't accept arguments %s."
             % (self.absolute_path, self.info.short_descr,
                self.info.family.show_wrapper_flags))
     # Assume the longest line starting with a known compiler command is the wrapped compiler followed by arguments.
     known_commands = set(info.command for info in _CompilerInfo.all())
     for line in sorted(stdout.split('\n'), key=len, reverse=True):
         if not line:
             continue
         parts = line.split()
         wrapped_command = parts[0]
         wrapped_args = parts[1:]
         if os.path.basename(wrapped_command) not in known_commands:
             continue
         wrapped_absolute_path = util.which(wrapped_command)
         if not wrapped_absolute_path:
             continue
         if wrapped_absolute_path == self.absolute_path:
             # A wrapper that wraps itself isn't a wrapper, e.g. compilers that ignore invalid arguments
             # when version flags are present.
             return None
         try:
             wrapped = InstalledCompiler.probe(wrapped_command)
         except ConfigurationError:
             # wrapped_command might not be a real compiler command so keep trying
             continue
         # The wrapper must be able to perform the same role as the wrapped compiler
         role = self.info.role.keyword.split('_')[1:]
         wrapped_role = wrapped.info.role.keyword.split('_')[1:]
         if role != wrapped_role:
             raise ConfigurationError(
                 "Cannot use '%s' as a %s: wrapped compiler '%s' is a %s" %
                 (self.command, self.info.short_descr, wrapped.command,
                  wrapped.info.short_descr))
         LOGGER.info("%s '%s' wraps '%s'", self.info.short_descr,
                     self.absolute_path, wrapped.absolute_path)
         try:
             self._parse_wrapped_args(wrapped_args)
         except IndexError:
             LOGGER.warning(
                 "Unexpected output from compiler wrapper '%s'."
                 " TAU will attempt to continue but may fail later on.",
                 self.absolute_path)
         return wrapped
     return None
Beispiel #6
0
def push_test_workdir():
    """Create a new working directory for a unit test.

    Sets the current working directory and :any:`tempfile.tempdir` to the newly created test directory.

    Directories created via this method are tracked.  If any of them exist when the program exits then
    an error message is shown for each.
    """
    path = tempfile.mkdtemp()
    try:
        test_src = os.path.join(TAUCMDR_HOME, '.testfiles', 'foo_launcher')
        test_dst = os.path.join(path, 'foo_launcher')
        shutil.copy(test_src, test_dst)
        get_command_output('%s/foo_launcher' % path)
    except OSError:
        shutil.rmtree(path)
        path = tempfile.mkdtemp(dir=os.getcwd())
    _DIR_STACK.append(path)
    _CWD_STACK.append(os.getcwd())
    _TEMPDIR_STACK.append(tempfile.tempdir)
    os.chdir(path)
    tempfile.tempdir = path
Beispiel #7
0
 def _probe_wrapper(self):
     if not self.info.family.show_wrapper_flags:
         return None
     LOGGER.debug("Probing %s wrapper '%s'", self.info.short_descr, self.absolute_path)
     cmd = [self.absolute_path] + self.info.family.show_wrapper_flags
     try:
         stdout = util.get_command_output(cmd)
     except CalledProcessError:
         # If this command didn't accept show_wrapper_flags then it's not a compiler wrapper to begin with,
         # i.e. another command just happens to be the same as a known compiler command.
         raise ConfigurationError("'%s' isn't actually a %s since it doesn't accept arguments %s." % 
                                  (self.absolute_path, self.info.short_descr, self.info.family.show_wrapper_flags))
     # Assume the longest line starting with a known compiler command is the wrapped compiler followed by arguments.
     known_commands = set(info.command for info in _CompilerInfo.all())
     for line in sorted(stdout.split('\n'), key=len, reverse=True):
         if not line:
             continue
         parts = line.split()
         wrapped_command = parts[0]
         wrapped_args = parts[1:]
         if os.path.basename(wrapped_command) not in known_commands:
             continue
         wrapped_absolute_path = util.which(wrapped_command)
         if not wrapped_absolute_path:
             continue
         if wrapped_absolute_path == self.absolute_path:
             # A wrapper that wraps itself isn't a wrapper, e.g. compilers that ignore invalid arguments
             # when version flags are present.
             return None
         try:
             wrapped = InstalledCompiler.probe(wrapped_command)
         except ConfigurationError:
             # wrapped_command might not be a real compiler command so keep trying
             continue
         # The wrapper must be able to perform the same role as the wrapped compiler
         role = self.info.role.keyword.split('_')[1:]
         wrapped_role = wrapped.info.role.keyword.split('_')[1:]
         if role != wrapped_role:
             raise ConfigurationError("Cannot use '%s' as a %s: wrapped compiler '%s' is a %s" %
                                      (self.command, self.info.short_descr, 
                                       wrapped.command, wrapped.info.short_descr))
         LOGGER.info("%s '%s' wraps '%s'", self.info.short_descr, self.absolute_path, wrapped.absolute_path)
         try:
             self._parse_wrapped_args(wrapped_args)
         except IndexError:
             LOGGER.warning("Unexpected output from compiler wrapper '%s'."
                            " TAU will attempt to continue but may fail later on.", self.absolute_path)
         return wrapped
     return None
Beispiel #8
0
 def _get_cmake(self):
     cmake = util.which('cmake')
     if not cmake:
         raise ConfigurationError("'cmake' not found in PATH.")
     try:
         stdout = util.get_command_output([cmake, '--version'])
     except (CalledProcessError, OSError) as err:
         raise ConfigurationError("Failed to get CMake version: %s" % err)
     for line in stdout.split('\n'):
         if 'cmake version' in line:
             verstr = (line.split('cmake version ')[1]).split('-')[0]
             version = tuple(int(x) for x in verstr.split('.'))
             if version < (2, 8):
                 raise ConfigurationError("CMake version 2.8 or higher required.")
             break
     else:
         LOGGER.warning("Cannot determine CMake version.  CMake 2.8 or higher is required.")
     return cmake
Beispiel #9
0
 def _get_cmake(self):
     cmake = util.which('cmake')
     if not cmake:
         raise ConfigurationError("'cmake' not found in PATH.")
     try:
         stdout = util.get_command_output([cmake, '--version'])
     except (CalledProcessError, OSError) as err:
         raise ConfigurationError("Failed to get CMake version: %s" % err)
     for line in stdout.split('\n'):
         if 'cmake version' in line:
             verstr = (line.split('cmake version ')[1]).split('-')[0]
             version = tuple(int(x) for x in verstr.split('.'))
             if version < (2, 8):
                 raise ConfigurationError(
                     "CMake version 2.8 or higher required.")
             break
     else:
         LOGGER.warning(
             "Cannot determine CMake version.  CMake 2.8 or higher is required."
         )
     return cmake
Beispiel #10
0
 def version_string(self):
     """Get the compiler's self-reported version info.
     
     Usually whatever the compiler prints when the --version flag is provided.
     
     Returns:
         str: The compilers' version string.
     """
     if self._version_string is None:
         cmd = [self.absolute_path] + self.info.family.version_flags
         try:
             self._version_string = util.get_command_output(cmd)
         except CalledProcessError:
             raise ConfigurationError("Compiler command '%s' failed." % ' '.join(cmd),
                                      "Check that this command works outside of TAU.",
                                      "Check loaded modules and environment variables.",
                                      "Verify that the compiler's license is valid.")
         except OSError:
             raise ConfigurationError("Compiler '%s' no longer exists or is not executable" % 
                                      self.absolute_path)
     return self._version_string
Beispiel #11
0
 def version_string(self):
     """Get the compiler's self-reported version info.
     
     Usually whatever the compiler prints when the --version flag is provided.
     
     Returns:
         str: The compilers' version string.
     """
     if self._version_string is None:
         cmd = [self.absolute_path] + self.info.family.version_flags
         try:
             self._version_string = util.get_command_output(cmd)
         except CalledProcessError:
             raise ConfigurationError("Compiler command '%s' failed." % ' '.join(cmd),
                                      "Check that this command works outside of TAU.",
                                      "Check loaded modules and environment variables.",
                                      "Verify that the compiler's license is valid.")
         except OSError:
             raise ConfigurationError("Compiler '%s' no longer exists or is not executable" % 
                                      self.absolute_path)
     return self._version_string
Beispiel #12
0
 def verify(self):
     super(ScorepInstallation, self).verify()
     # Use Score-P's `scorep-info` command to check if this Score-P installation
     # was configured with the flags we need.
     cmd = [os.path.join(self.bin_path, 'scorep-info'), 'config-summary']
     try:
         stdout = util.get_command_output(cmd)
     except CalledProcessError as err:
         raise SoftwarePackageError("%s failed with return code %d: %s" %
                                    (cmd, err.returncode, err.output))
     flags = self._get_flags()
     found_flags = set()
     extra_flags = set()
     in_section = False
     for line in stdout.splitlines():
         if line.startswith('Configure command:'):
             in_section = True
             continue
         elif in_section:
             line = line.replace('./configure', '')
             if not line.startswith(' '):
                 break
             for flag in flags:
                 if "'%s'" % flag in line:
                     found_flags.add(flag)
                     break
             else:
                 extra_flags.add(line.replace('\\', '').strip())
     # Some extra flags are harmless
     for flag in list(extra_flags):
         if flag.startswith("'--prefix="):
             extra_flags.remove(flag)
     if found_flags != set(flags):
         raise SoftwarePackageError(
             "Score-P installation at '%s' was not configured with flags %s"
             % (self.install_prefix, ' '.join(flags)))
     if extra_flags:
         raise SoftwarePackageError(
             "Score-P installation at '%s' was configured with extra flags %s"
             % (self.install_prefix, ' '.join(extra_flags)))
 def verify(self):
     super(ScorepInstallation, self).verify()
     # Use Score-P's `scorep-info` command to check if this Score-P installation
     # was configured with the flags we need.
     cmd = [os.path.join(self.bin_path, 'scorep-info'), 'config-summary']
     try:
         stdout = util.get_command_output(cmd)
     except CalledProcessError as err:
         raise SoftwarePackageError("%s failed with return code %d: %s" % (cmd, err.returncode, err.output))
     flags = self._get_flags()
     found_flags = set()
     extra_flags = set()
     in_section = False
     for line in stdout.splitlines():
         if line.startswith('Configure command:'):
             in_section = True
             continue
         elif in_section:
             line = line.replace('./configure', '')
             if not line.startswith(' '):
                 break
             for flag in flags:
                 if ("'%s'" % flag) in line:
                     found_flags.add(flag)
                     break
             else:
                 extra_flags.add(line.replace('\\', '').strip())
     # Some extra flags are harmless
     for flag in list(extra_flags):
         if flag.startswith("'--prefix="):
             extra_flags.remove(flag)
     if found_flags != set(flags):
         raise SoftwarePackageError("Score-P installation at '%s' was not configured with flags %s" % 
                                    (self.install_prefix, ' '.join(flags)))
     if extra_flags:
         raise SoftwarePackageError("Score-P installation at '%s' was configured with extra flags %s" % 
                                    (self.install_prefix, ' '.join(extra_flags)))
Beispiel #14
0
 def xml_event_info(self):
     if not self._xml_event_info:
         self.install()
         xml_event_info = util.get_command_output(os.path.join(self.bin_path, 'papi_xml_event_info'))
         self._xml_event_info = ElementTree.fromstring(xml_event_info)
     return self._xml_event_info
Beispiel #15
0
    def probe(cls, absolute_path, candidates=None):
        """Determine the compiler family of a given command.

        Executes the command with :any:`version_flags` from all families
        and compares the output against :any:`family_regex`.

        Args:
            absolute_path (str): Absolute path to a compiler command.
            candidates (list): If present, a list of families that are most likely.

        Raises:
            ConfigurationError: Compiler family could not be determined.

        Returns:
            _CompilerFamily: The compiler's family.
        """
        try:
            return cls._probe_cache[absolute_path]
        except KeyError:
            pass
        LOGGER.debug("Probing compiler '%s' to discover compiler family", absolute_path)
        messages = []
        stdout = None
        # Settle down pylint... the __instances__ member is created by __new__
        # pylint: disable=no-member
        if candidates:
            candidate_kbases = {candidate.kbase for candidate in candidates}
            families = candidates + [inst for inst in cls.__instances__ 
                                     if inst not in candidates and inst.kbase in candidate_kbases]
        else:
            families = cls.__instances__
        basename = os.path.basename(absolute_path)
        with_regex, without_regex = [], []
        for family in families:
            if basename in family.commands:
                (with_regex if family.family_regex else without_regex).append(family)
        for family in with_regex:
            cmd = [absolute_path] + family.version_flags
            try:
                stdout = util.get_command_output(cmd)
            except CalledProcessError as err:
                messages.append(err.output)
                LOGGER.debug("%s returned %d: %s", cmd, err.returncode, err.output)
                # Keep going: Cray compilers return nonzero on version flag
            if stdout:
                if re.search(family.family_regex, stdout, re.MULTILINE):
                    if family.show_wrapper_flags:
                        cmd = [absolute_path] + family.show_wrapper_flags
                        try:
                            stdout = util.get_command_output(cmd)
                        except CalledProcessError as err:
                            messages.append(err.output)
                            LOGGER.debug("%s returned %d: %s", cmd, err.returncode, err.output)
                        if stdout:
                            if re.search(family.family_regex, stdout, re.MULTILINE):
                                LOGGER.debug("'%s' is a %s compiler", absolute_path, family.name)
                                cls._probe_cache[absolute_path] = family
                                return family
                            else:
                                LOGGER.debug("'%s' is not a %s compiler", absolute_path, family.name)
                    else:
                        LOGGER.debug("'%s' is a %s compiler", absolute_path, family.name)
                        cls._probe_cache[absolute_path] = family
                        return family
                else:
                    LOGGER.debug("'%s' is not a %s compiler", absolute_path, family.name)
        if len(without_regex) > 0:
            guess = without_regex[0]
            if len(without_regex) > 1:
                LOGGER.warning(("Assuming '%s' is a %s compiler but it could be to any of these: %s\n"
                                "If this assumption is incorrect then you should manually specify your compilers"), 
                               absolute_path, guess.name, ', '.join([family.name for family in without_regex]))
            return guess
        raise ConfigurationError("Cannot determine compiler family: %s" % '\n'.join(messages))