LINUX.ORG.RU

Простой скрипт для предотвращения ухода компа в сон

 ,


0

1

Сделал под свои нужды. Никаких конфигов, параметров командной строки итд :-) Хотите - берите, хотите - не берите.

Скрипт срабатывает при сетевой активности (upload+download > 50Mb / 5min), дисковой активности (IO > 25Mb/min), и активности процессора.

#!/usr/bin/env python3

'''
Monitor network traffic, disk I/O and CPU usage.
If they excel some given values, prevent computer from suspending.

Author: Joseph Botosh <rumly111@gmail.com>

License: GPLv2
'''

import time
import dbus
import logging


def int_from_file(fn : str) -> int:
    with open(fn, 'rt') as f:
        return int(f.readline())


class IntFile:
    def __init__(self, fname):
        self.fname = fname
        self._last = None
        self.history = []

    def update(self):
        n = int_from_file(self.fname)
        if self._last is not None:
            self.history.append(n - self._last)
        self._last = n
        if len(self.history) > 7200:
            self.history = self.history[3600:]

    def total(self, period: int):
        return sum(self.history[-period:])


class CpuInfo:
    def __init__(self):
        self._prevstats = None
        self.history = [0]

    def update(self):
        stats = []
        with open('/proc/stat', 'rt') as f:
            for l in f.readlines():
                stats = l.split()
                if stats[0] == 'cpu':
                    break

        stats = [float(s) for s in stats[1:]]
        # https://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux
        user,nice,system,idle,iowait,irq,softrig,steal,_,_ = stats
        Idle = idle + iowait
        NonIdle = user + nice + system + irq + softrig + steal
        Total = Idle + NonIdle

        if self._prevstats is not None:
            ps = self._prevstats
            cpu_perc = (NonIdle - ps['NonIdle']) / (Total - ps['Total']) * 100
            self.history.append(cpu_perc)
            
        self._prevstats = {'Total':Total, 'Idle':Idle, 'NonIdle':NonIdle}

        if len(self.history) > 7200:
            self.history = self.history[3600:]

    def average(self, period : int):
        return sum(self.history[-period:]) / min(len(self.history) or 1, period)


class DiskIO:
    def __init__(self):
        self.history = [0]
        self._prevstats = None

    def update(self):
        stats = []
        with open('/proc/diskstats', 'rt') as f:
            for l in f.readlines():
                stats = l.split()
                if stats[2] == 'sda':
                    break

        stats = [int(s) for s in stats[3:]]

        read_bytes = stats[2] * 512
        write_bytes = stats[6] * 512

        if self._prevstats is not None:
            ps = self._prevstats
            diskio_rw = (read_bytes - ps['read']) + (write_bytes - ps['write'])
            self.history.append(diskio_rw)

        self._prevstats = {'read':read_bytes, 'write':write_bytes}
        
        if len(self.history) > 7200:
            self.history = self.history[3600:]

    def total(self, period : int):
        return sum(self.history[-period:])


class SuspendInhibitor:
    def __init__(self, dbus_iface : dbus.Interface):
        self.__cookie = 0
        self.__enabled = False
        self.__dbus_iface = dbus_iface

    @property
    def enabled(self):
        return self.__enabled

    def set_enabled(self, e: bool, msg: str = ''):
        if e and not self.__enabled:
            self.__cookie = self.__dbus_iface.Inhibit('DoNotSleep',0,msg,4)
            self.__enabled = True
            logging.info('Inhibit [msg:"{}", cookie:{}]'.format(msg,self.__cookie))
        elif not e and self.__enabled:
            self.__dbus_iface.Uninhibit(self.__cookie)
            self.__enabled = False
            logging.info('Uninhibit [cookie:{}]'.format(self.__cookie))

if __name__=='__main__':
    logging.basicConfig(level=logging.INFO, 
                        format='%(asctime)s %(message)s',
                        datefmt='%Y-%m-%d %H:%m:%S')

    bus = dbus.SessionBus()
    obj = bus.get_object('org.gnome.SessionManager','/org/gnome/SessionManager')
    iface = dbus.Interface(obj, 'org.gnome.SessionManager')

    net_inhibitor = SuspendInhibitor(iface)
    cpu_inhibitor = SuspendInhibitor(iface)
    diskio_inhibitor = SuspendInhibitor(iface)

    net_down = IntFile('/sys/class/net/wlp4s0/statistics/rx_bytes')
    net_up = IntFile('/sys/class/net/wlp4s0/statistics/tx_bytes')
    cpu_perc = CpuInfo()
    diskio_info = DiskIO()

    while True:
        for o in (net_down, net_up, cpu_perc, diskio_info):
            o.update()
        
        net_traffic = net_down.total(300) + net_up.total(300)

        if net_traffic > 50 * 1024 * 1024:
            net_inhibitor.set_enabled(True, 'Network traffic {} bytes/5min'.format(net_traffic))
        else:
            net_inhibitor.set_enabled(False)

        cpu_perc_avg = cpu_perc.average(60)

        if cpu_perc_avg > 55.0:
            cpu_inhibitor.set_enabled(True, 'CPU usage average {}%/1min'.format(cpu_perc_avg))
        else:
            cpu_inhibitor.set_enabled(False)

        diskio_bytes = diskio_info.total(60)
        # logging.debug('diskio_bytes (60s) = {}'.format(diskio_bytes))
        if diskio_bytes > 25 * 1024 * 1024:
            diskio_inhibitor.set_enabled(True, 'Disk IO {} bytes/1min'.format(diskio_bytes))
        else:
            diskio_inhibitor.set_enabled(False)

        time.sleep(1)

может лучше на git{hu,la}b (хотя бы gist)? накрайняк на pastebin. а сюда ссылку

eternal_sorrow ★★★★★ ()

Что ж, спасибо. А ты проверял, насколько грузит процессор сам питончик? Не будит ли скрипт сам себя?:)

Ещё можешь сделать задание пороговых значений через аргументы командной строки, это несложно (argparse)

Crocodoom ★★★★ ()
Последнее исправление: Crocodoom (всего исправлений: 1)

Хотите - берите, хотите - не берите

Как его брать если, сетевой интерфейс захардкожен, а у меня на десктопе их 3. )

Есть же /proc/net/dev.

vvn_black ★★★★★ ()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

Что ж, спасибо. А ты проверял, насколько грузит процессор сам питончик? Не будит ли скрипт сам себя?:)

Не думаю, что скрипт сильно грузит. Там простое чтение файлов раз в секунду, это мелочь.

rumly111 ()
Последнее исправление: rumly111 (всего исправлений: 1)
Ответ на: комментарий от rumly111

Ещё спорный вопрос, не давать спать по общему трафику за период или же по текущей скорости? По скорости даже проще, не нужен этот ад с 7200 замерами.

vvn_black ★★★★★ ()
Последнее исправление: vvn_black (всего исправлений: 1)

для предотвращения ухода компа в сон

возможно я чего-то не понимаю, но почему бы просто не отключить суспенд с гибернейтом?

anonymous ()
Ответ на: комментарий от vvn_black

Ещё спорный вопрос, не давать спать по общему трафику за период или же по текущей скорости? По скорости даже проще, не нужен этот ад с 7200 замерами.

Там замер раз в секунду, просто сохраняется история замеров для статистики. Таким образом я определяю, есть ли сейчас какя-то активная закачка, например фильм. А если какая-то программа просто периодически дёргает сеть, мне это не интересно.

rumly111 ()
Ответ на: комментарий от vvn_black

ад с 7200 замерами

А, понял вашу мысль. Можно было раз в 5 минут проверять траффик. Но я решил засунуть все проверки в один цикл, так что пока так.

rumly111 ()
Ответ на: комментарий от anonymous

Ему надо чтобы засыпалось нормально, но не когда он смотрит кинцо или ютабчик или оставил копировать 2тб помойку. У линуска с этим традиционно депры судя по всему.

anonymous ()

If they excel some given values

«Excel» и «exceed» оба переводятся как «превосходить», но «excel» имеет оттенок «быть лучше в чём-либо», а для количественного превосходства лучше подходит «exceed».

i-rinat ★★★★★ ()
Ответ на: комментарий от I-Love-Microsoft

Если это ноут, в кедах просто кликаешь по батарее на панели и там снимаешь галку «включить управление питанием». https://i.imgur.com/FiUpTB6.png

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.