Пример #1
0
def read_smap_file():
    total = 0
    fp = open(proc_path("self/smaps"), "rb")
    with fp:
        for line in fp:
            # Include both Private_Clean and Private_Dirty sections.
            line = line.rstrip()
            if line.startswith(b"Private_") and line.endswith(b'kB'):
                parts = line.split()
                total += int(parts[1]) * 1024
    return total
Пример #2
0
def read_smap_file():
    total = 0
    fp = open(proc_path("self/smaps"), "rb")
    with fp:
        for line in fp:
            # Include both Private_Clean and Private_Dirty sections.
            line = line.rstrip()
            if line.startswith(b"Private_") and line.endswith(b'kB'):
                parts = line.split()
                total += int(parts[1]) * 1024
    return total
Пример #3
0
    def read_rcu_nocbs(self):
        cmdline = self.read_first_line(proc_path('cmdline'))
        if not cmdline:
            return

        match = re.search(r'\brcu_nocbs=([^ ]+)', cmdline)
        if not match:
            return

        cpus = match.group(1)
        return parse_cpu_list(cpus)
Пример #4
0
    def read_rcu_nocbs(self):
        cmdline = self.read_first_line(proc_path('cmdline'))
        if not cmdline:
            return

        match = re.search(r'\brcu_nocbs=([^ ]+)', cmdline)
        if not match:
            return

        cpus = match.group(1)
        return parse_cpu_list(cpus)
Пример #5
0
def read_proc(path):
    path = proc_path(path)
    try:
        fp = open_text(path)
        try:
            for line in fp:
                yield line.rstrip()
        finally:
            # don't use context manager to support StringIO on Python 2
            # for unit tests
            fp.close()
    except (OSError, IOError):
        return
Пример #6
0
def check_tracking_memory():
    mem_thread = PeakMemoryUsageThread()
    try:
        mem_thread.get()
    except IOError as exc:
        path = proc_path("self/smaps")
        return "unable to read %s: %s" % (path, exc)

    if not mem_thread.peak_usage:
        return "memory usage is zero"

    # it seems to work
    return None
Пример #7
0
def read_proc(path):
    path = proc_path(path)
    try:
        fp = open_text(path)
        try:
            for line in fp:
                yield line.rstrip()
        finally:
            # don't use context manager to support StringIO on Python 2
            # for unit tests
            fp.close()
    except (OSError, IOError):
        return
Пример #8
0
def check_tracking_memory():
    mem_thread = PeakMemoryUsageThread()
    try:
        mem_thread.get()
    except IOError as exc:
        path = proc_path("self/smaps")
        return "unable to read %s: %s" % (path, exc)

    if not mem_thread.peak_usage:
        return "memory usage is zero"

    # it seems to work
    return None
Пример #9
0
class ASLR(Operation):
    # randomize_va_space procfs existed prior to 2.6.12-rc2 (2005)
    # which is first commit of the Linux git repository

    STATE = {
        '0': 'No randomization',
        '1': 'Conservative randomization',
        '2': 'Full randomization'
    }
    path = proc_path("sys/kernel/randomize_va_space")

    @classmethod
    def available(cls):
        return os.path.exists(cls.path)

    def __init__(self, system):
        Operation.__init__(self, 'ASLR', system)

    def show(self):
        line = self.read_first_line(self.path)
        try:
            state = self.STATE[line]
        except KeyError:
            self.error("Failed to read %s" % self.path)
            return

        self.log_state(state)
        self.tuned_for_benchmarks = (line == '2')
        if not self.tuned_for_benchmarks:
            self.advice("Enable full randomization: write 2 into %s" %
                        self.path)

    def write(self, tune):
        value = self.read_first_line(self.path)
        if not value:
            return

        new_value = '2'
        if new_value == value:
            return

        try:
            write_text(self.path, new_value)
        except IOError as exc:
            self.check_permission_error(exc)
            self.error("Failed to write into %s: %s" % (self.path, exc))
        else:
            self.log_action("Full randomization enabled: %r written into %s" %
                            (new_value, self.path))
Пример #10
0
class PerfEvent(Operation):
    # Minimise time spent by the Linux perf kernel profiler.

    BENCHMARK_RATE = 1
    path = proc_path("sys/kernel/perf_event_max_sample_rate")

    @classmethod
    def available(cls):
        return os.path.exists(cls.path)

    def __init__(self, system):
        Operation.__init__(self, 'Perf event', system)

    def read_max_sample_rate(self):
        line = self.read_first_line(self.path)
        if not line:
            return None
        return int(line)

    def show(self):
        max_sample_rate = self.read_max_sample_rate()
        if not max_sample_rate:
            return

        self.log_state("Maximum sample rate: %s per second" % max_sample_rate)
        self.tuned_for_benchmarks = (max_sample_rate == self.BENCHMARK_RATE)
        if not self.tuned_for_benchmarks:
            self.advice("Set max sample rate to %s" % self.BENCHMARK_RATE)

    def write(self, tune):
        if tune:
            new_rate = self.BENCHMARK_RATE
        else:
            new_rate = 100000

        max_sample_rate = self.read_max_sample_rate()
        if max_sample_rate == new_rate:
            return

        try:
            write_text(self.path, str(new_rate))
        except IOError as exc:
            self.check_permission_error(exc)
            self.error("Failed to write into %s: %s" % (self.path, exc))
        else:
            self.log_action("Max sample rate set to %s per second" % new_rate)
Пример #11
0
def get_isolated_cpus():
    """Get the list of isolated CPUs.

    Return a sorted list of CPU identifiers, or return None if no CPU is
    isolated.
    """
    # The cpu/isolated sysfs was added in Linux 4.2
    # (commit 59f30abe94bff50636c8cad45207a01fdcb2ee49)
    path = sysfs_path('devices/system/cpu/isolated')
    isolated = read_first_line(path)
    if isolated:
        return parse_cpu_list(isolated)

    cmdline = read_first_line(proc_path('cmdline'))
    if cmdline:
        match = re.search(r'\bisolcpus=([^ ]+)', cmdline)
        if match:
            isolated = match.group(1)
            return parse_cpu_list(isolated)

    return None
Пример #12
0
def get_isolated_cpus():
    """Get the list of isolated CPUs.

    Return a sorted list of CPU identifiers, or return None if no CPU is
    isolated.
    """
    # The cpu/isolated sysfs was added in Linux 4.2
    # (commit 59f30abe94bff50636c8cad45207a01fdcb2ee49)
    path = sysfs_path('devices/system/cpu/isolated')
    isolated = read_first_line(path)
    if isolated:
        return parse_cpu_list(isolated)

    cmdline = read_first_line(proc_path('cmdline'))
    if cmdline:
        match = re.search(r'\bisolcpus=([^ ]+)', cmdline)
        if match:
            isolated = match.group(1)
            return parse_cpu_list(isolated)

    return None
Пример #13
0
class IRQAffinity(Operation):
    # /proc/irq/N/smp_affinity existed prior to 2.6.12-rc2 (2005)
    # which is first commit of the Linux git repository

    irq_path = proc_path('irq')

    @classmethod
    def available(cls):
        return os.path.exists(cls.irq_path)

    def __init__(self, system):
        Operation.__init__(self, 'IRQ affinity', system)
        self.irq_affinity_path = os.path.join(self.irq_path, "%s/smp_affinity")
        self.default_affinity_path = os.path.join(self.irq_path, 'default_smp_affinity')

        self.systemctl = True
        self.irqs = None

    def read_irqbalance_systemctl(self):
        cmd = ('systemctl', 'status', 'irqbalance')
        exitcode, stdout = get_output(cmd)
        if not stdout:
            # systemctl is not installed? ignore errors
            self.systemctl = False
            return

        match = re.search(r"^ *Loaded: (.*)$", stdout, flags=re.MULTILINE)
        if not match:
            self.error("Failed to parse systemctl loaded state: %r" % stdout)
            return
        self.systemctl = True

        loaded = match.group(1)
        if loaded.startswith('not-found'):
            # irqbalance service is not installed: do nothing
            return

        match = re.search(r"^ *Active: ([^ ]+)", stdout, flags=re.MULTILINE)
        if not match:
            self.error("Failed to parse systemctl active state: %r" % stdout)
            return

        active = match.group(1)
        if active in ('active', 'activating'):
            return True
        elif active in ('inactive', 'deactivating', 'dead'):
            return False
        else:
            self.error("Unknown service state: %r" % active)

    def read_irqbalance_service(self):
        cmd = ('service', 'irqbalance', 'status')
        exitcode, stdout = get_output(cmd)
        if not stdout:
            # failed to the the status: ignore
            return

        stdout = stdout.rstrip()
        state = stdout.split(' ', 1)[-1]
        if state.startswith('stop'):
            return False
        elif state.startswith('start'):
            return True
        else:
            self.error("Unknown service state: %r" % stdout)

    def read_irqbalance_state(self):
        active = self.read_irqbalance_systemctl()
        if self.systemctl is False:
            active = self.read_irqbalance_service()
        return active

    def parse_affinity(self, mask):
        mask = parse_cpu_mask(mask)
        cpus = []
        for cpu in range(self.system.logical_cpu_count):
            cpu_mask = 1 << cpu
            if cpu_mask & mask:
                cpus.append(cpu)
        return cpus

    def read_default_affinity(self):
        mask = self.read_first_line(self.default_affinity_path)
        if not mask:
            return

        return self.parse_affinity(mask)

    def get_irqs(self):
        if self.irqs is None:
            filenames = os.listdir(self.irq_path)
            self.irqs = [int(name) for name in filenames if name.isdigit()]
            self.irqs.sort()
        return self.irqs

    def read_irq_affinity(self, irq):
        path = self.irq_affinity_path % irq
        mask = self.read_first_line(path)
        if not mask:
            self.error("Failed to read %s" % path)
            return

        return self.parse_affinity(mask)

    def read_irqs_affinity(self):
        affinity = {}
        for irq in self.get_irqs():
            if self.permission_error:
                break
            cpus = self.read_irq_affinity(irq)
            if cpus is not None:
                affinity[irq] = cpus
        return affinity

    def show(self):
        irqbalance_active = self.read_irqbalance_state()
        if irqbalance_active is not None:
            state = 'active' if irqbalance_active else 'inactive'
            self.log_state("irqbalance service: %s" % state)

        default_smp_affinity = self.read_default_affinity()
        if default_smp_affinity:
            self.log_state("Default IRQ affinity: CPU %s"
                           % format_cpu_list(default_smp_affinity))

        irq_affinity = self.read_irqs_affinity()
        if irq_affinity:
            infos = {irq: 'CPU %s' % format_cpu_list(cpus)
                     for irq, cpus in irq_affinity.items()}
            infos = format_cpu_infos(infos)
            infos = ['IRQ %s' % info for info in infos]
            self.log_state('IRQ affinity: %s' % '; '.join(infos))

    def write_irqbalance_service(self, enable):
        irqbalance_active = self.read_irqbalance_state()
        if irqbalance_active is None:
            # systemd service missing or failed to get its state:
            # don't try to start/stop the irqbalance service
            return

        if irqbalance_active == enable:
            # service is already in the expected state: nothing to do
            return

        action = 'start' if enable else 'stop'
        if self.systemctl is False:
            cmd = ('service', 'irqbalance', action)
        else:
            cmd = ('systemctl', action, 'irqbalance')
        exitcode = run_cmd(cmd)
        if exitcode:
            self.error('Failed to %s irqbalance service: '
                       '%s failed with exit code %s'
                       % (action, ' '.join(cmd), exitcode))
            return

        action = 'Start' if enable else 'Stop'
        self.log_action("%s irqbalance service" % action)

    def write_default(self, new_affinity):
        default_smp_affinity = self.read_default_affinity()
        if new_affinity == default_smp_affinity:
            return

        mask = format_cpus_as_mask(new_affinity)
        try:
            write_text(self.default_affinity_path, mask)
        except IOError as exc:
            self.check_permission_error(exc)
            self.error("Failed to write %r into %s: %s"
                       % (mask, self.default_affinity_path, exc))
        else:
            self.log_action("Set default affinity to CPU %s"
                            % format_cpu_list(new_affinity))

    def write_irq(self, irq, cpus):
        path = self.irq_affinity_path % irq
        mask = format_cpus_as_mask(cpus)
        try:
            write_text(path, mask)
            return True
        except IOError as exc:
            self.check_permission_error(exc)
            # EIO means that the IRQ doesn't support SMP affinity:
            # ignore the error
            if exc.errno != errno.EIO:
                self.error("Failed to write %r into %s: %s"
                           % (mask, path, exc))
            return False

    def write_irqs(self, new_cpus):
        affinity = self.read_irqs_affinity()
        modified = []
        for irq in self.get_irqs():
            if self.permission_error:
                break

            cpus = affinity.get(irq)
            if new_cpus == cpus:
                continue

            if self.write_irq(irq, new_cpus):
                modified.append(irq)

        if modified:
            self.log_action("Set affinity of IRQ %s to CPU %s"
                            % (format_cpu_list(modified), format_cpu_list(new_cpus)))

    def write(self, tune):
        cpus = range(self.system.logical_cpu_count)
        if tune:
            excluded = set(self.system.cpus)
            # Only compute the subset if excluded is not the full list of cpus
            if excluded != set(cpus):
                cpus = (cpu for cpu in cpus if cpu not in excluded)
        cpus = list(cpus)

        self.write_irqbalance_service(not tune)
        self.write_default(cpus)
        self.write_irqs(cpus)