예제 #1
0
    def _set_launch_distance(self):
        """Set launch distance limits to driver."""

        try:
            limit_path = self._basedir / "ldist_max_nsec"
            with self._proc.open(limit_path, "r") as fobj:
                ldist_max = fobj.read().strip()

            limit_path = self._basedir / "ldist_min_nsec"
            with self._proc.open(limit_path, "r") as fobj:
                ldist_min = fobj.read().strip()
        except Error as err:
            raise Error(
                f"failed to read launch distance limit from '{limit_path}'"
                f"{self._proc.hostmsg}:\n{err}")

        ldist_min = Trivial.str_to_num(ldist_min)
        ldist_max = Trivial.str_to_num(ldist_max)
        from_path = self._basedir / "ldist_from_nsec"
        to_path = self._basedir / "ldist_to_nsec"

        for ldist, ldist_path in zip_longest(self._ldist, [from_path, to_path],
                                             fillvalue=self._ldist[-1]):
            if ldist < ldist_min or ldist > ldist_max:
                raise Error(
                    f"launch distance '{ldist}' is out of range, it should be in range of "
                    f"[{ldist_min},{ldist_max}]")
            if not FSHelpers.exists(ldist_path, proc=self._proc):
                raise Error(
                    f"path i'{ldist_path}' does not exist{self._proc.hostmsg}")
            # open()/write() doesn't work for this file when done over SSH.
            self._proc.run_verify(f"echo {ldist} > {ldist_path}", shell=True)
예제 #2
0
    def __init__(self, devid, cpunum, proc):
        """The class constructor. The arguments are the same as in '_WultDeviceBase.__init__()'."""

        super().__init__(devid, cpunum, proc)

        self._pci_info = None
        self._devpath = None
        self._captured = None

        path = Path(f"/sys/bus/pci/devices/{self._devid}")
        if not FSHelpers.exists(path, proc=proc):
            raise ErrorNotFound(f"cannot find device '{self._devid}'{self._proc.hostmsg}:\n"
                                f"path {path} does not exist")

        self._devpath = FSHelpers.abspath(path, proc=self._proc)
        self._pci_info = LsPCI.LsPCI(proc).get_info(Path(self._devpath).name)

        if self.supported_devices and self._pci_info['devid'] not in self.supported_devices:
            supported = ["%s - %s" % (key, val) for key, val in self.supported_devices.items()]
            supported = "\n * ".join(supported)
            raise ErrorNotSupported(f"PCI device '{self._pci_info['pciaddr']}' (PCI ID "
                                    f"{self._pci_info['devid']}) is not supported by wult driver "
                                    f"{self.drvname}.\nHere is the list of supported PCI IDs:\n* "
                                    f"{supported}")

        self.info["name"] = "Intel I210"
        self.info["devid"] = self._pci_info["pciaddr"]
        if self.supported_devices:
            self.info["descr"] = self.supported_devices[self._pci_info['devid']]
        else:
            self.info["name"] = self._pci_info["name"]
            self.info["descr"] = self.info['name'].capitalize()

        self.info["descr"] += f". PCI address {self._pci_info['pciaddr']}, Vendor ID " \
                              f"{self._pci_info['vendorid']}, Device ID {self._pci_info['devid']}."
예제 #3
0
    def start(self):
        """Start the latency measurements."""

        # Sanity check.
        if not FSHelpers.exists(self._enable_path, proc=self._proc):
            raise Error(
                f"path {self._enable_path} does not exist{self._proc.hostmsg}")

        self._proc.run_verify(f"echo 1 > {self._enable_path}", shell=True)
예제 #4
0
    def bind(self, drvname):
        """Bind the PCI device to driver 'drvname'."""

        _LOG.debug("binding device '%s' to driver '%s'%s",
                   self._pci_info["pciaddr"], drvname, self._proc.hostmsg)

        failmsg = f"failed to bind device '{self._pci_info['pciaddr']}' to driver '{drvname}'" \
                  f"{self._proc.hostmsg}"

        self._dmesg_capture()

        drvpath = Path(f"/sys/bus/pci/drivers/{drvname}")
        if not FSHelpers.exists(drvpath, proc=self._proc):
            raise Error(f"{failmsg}':\npath '{drvpath}' does not exist{self._proc.hostmsg}")

        cur_drvname = self.get_driver_name()
        if cur_drvname == drvname:
            _LOG.debug("device '%s' is already bound to driver '%s'%s",
                       self._pci_info["pciaddr"], drvname, self._proc.hostmsg)
            return

        if cur_drvname:
            raise Error(f"{failmsg}:\nit is already bound to driver '{cur_drvname}'")

        # At this point we do not know if the driver supports this PCI ID. So start with the
        # assumption that it does not, in which case writing to the 'new_id' file should do both:
        # * make the driver aware of the PCI ID
        # * bind the device
        path = f"{drvpath}/new_id"
        val = f"{self._pci_info['vendorid']} {self._pci_info['devid']}"
        bound = True

        try:
            with self._proc.open(path, "wt") as fobj:
                _LOG.debug("writing '%s' to file '%s'", val, path)
                fobj.write(val)
        except Error as err:
            bound = False

        if not bound:
            # Probably the driver already knows about this PCI ID. Use the 'bind' file in this case.
            path = f"{drvpath}/bind"
            val = self._pci_info["pciaddr"]
            with self._proc.open(path, "wt") as fobj:
                _LOG.debug("writing '%s' to file '%s'", val, path)
                try:
                    fobj.write(val)
                except Error as err:
                    raise Error(f"{failmsg}:\n{err}\n{self._get_new_dmesg()}")

        # Verify that the device is bound to the driver.
        if not self._get_driver()[1]:
            raise Error(f"{failmsg}\n{self._get_new_dmesg()}")

        _LOG.debug("binded device '%s' to driver '%s'%s\n%s", self._pci_info["pciaddr"], drvname,
                   self._proc.hostmsg, self._get_new_dmesg())
예제 #5
0
    def _get_driver(self):
        """
        Find out whether the PCI device is bound to any driver. If it is not, returns the
        '(None, None)' tuple. Otherwise returns a tuple of:
         * driver name
         * driver sysfs path
        """

        drvpath = Path(f"{self._devpath}/driver")
        if not FSHelpers.exists(drvpath, proc=self._proc):
            return (None, None)

        drvpath = FSHelpers.abspath(drvpath, proc=self._proc)
        drvname = Path(drvpath).name
        return (drvname, drvpath)
예제 #6
0
    def _get_hw_addr(self):
        """
        Return the hardware address for the NIC corresponding to the network interface. Typically
        the hardware address is a PCI address, such as '0000:04:00.0'.
        """

        # The "device" symlink leads to the sysfs subdirectory corresponding to the underlying NIC.
        path = self._sysfsbase / "device"
        if not FSHelpers.exists(path, proc=self._proc):
            raise ErrorNotFound(
                f"cannot find network interface '{self.ifname}':\n"
                f"path '{path}' does not exist{self._proc.hostmsg}'")

        # The name of the subdirectory is the hardware address.
        path = FSHelpers.abspath(path, proc=self._proc)
        return path.name
예제 #7
0
def is_deploy_needed(proc, toolname, helperpath=None):
    """
    Wult and other tools require additional helper programs and drivers to be installed on the
    measured system. This function tries to analyze the measured system and figure out whether
    drivers and helper programs are present and up-to-date. Returns 'True' if re-deployment is
    needed, and 'False' otherwise.

    This function works by simply matching the modification date of sources and binaries for every
    required helper and driver. If sources have later date, then re-deployment is probably needed.
      * proc - the 'Proc' or 'SSH' object associated with the measured system.
      * toolname - name of the tool to check the necessity of deployment for (e.g., "wult").
      * helperpath - optional path to the helper program that is required to be up-to-date for
                     'toolname' to work correctly. If 'helperpath' is not given, default paths
                     are used to locate helper program.
    """

    def get_path_pairs(proc, toolname, helperpath):
        """
        Yield paths for 'toolname' driver and helpertool source code and deployables. Arguments are
        same as in 'is_deploy_needed()'.
        """

        lproc = Procs.Proc()

        for path, is_drv in [(_DRV_SRC_SUBPATH, True), (_HELPERS_SRC_SUBPATH, False)]:
            srcpath = FSHelpers.search_for_app_data(toolname, path / toolname, default=None)
            # Some tools may not have helpers.
            if not srcpath:
                continue

            for deployable in _get_deployables(srcpath, lproc):
                deploypath = None
                # Deployable can be driver module or helpertool.
                if is_drv:
                    deploypath = _get_module_path(proc, deployable)
                else:
                    if helperpath and helperpath.name == deployable:
                        deploypath = helperpath
                    else:
                        deploypath = get_helpers_deploy_path(proc, toolname)
                        deploypath = Path(deploypath, "bin", deployable)
                yield srcpath, deploypath

    def get_newest_mtime(path):
        """Scan items in 'path' and return newest modification time among entries found."""

        newest = 0
        for _, fpath, _ in FSHelpers.lsdir(path, must_exist=False):
            mtime = os.path.getmtime(fpath)
            if mtime > newest:
                newest = mtime

        if not newest:
            raise Error(f"no files found in '{path}'")
        return newest

    delta = 0
    if proc.is_remote:
        # We are about to get timestamps for local and remote files. Take into account the possible
        # time shift between local and remote systems.

        remote_time = proc.run_verify("date +%s")[0].strip()
        delta = time.time() - float(remote_time)

    for srcpath, deploypath in get_path_pairs(proc, toolname, helperpath):
        if not deploypath or not FSHelpers.exists(deploypath, proc):
            return True

        srcmtime = get_newest_mtime(srcpath)
        if srcmtime + delta > FSHelpers.get_mtime(deploypath, proc):
            return True

    return False