diff --git a/.gitignore b/.gitignore index d1f3790..080d699 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ MANIFEST # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest -*.spec # Installer logs pip-log.txt diff --git a/.travis.yml b/.travis.yml index 90e4a0c..52c7e65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,11 @@ language: python sudo: required -before_install: - - sudo apt-get install -y pylint3 - script: - sudo make install - - sudo make systemd + - sudo systemctl enable --now nohang - sudo systemctl stop nohang.service - - make pylint - - oom-sort -h - oom-sort @@ -21,6 +16,7 @@ script: - nohang -v - nohang -cc /etc/nohang/nohang.conf + - nohang -cc /etc/nohang/nohang-desktop.conf - nohang -cc nohang/test.conf - nohang -p diff --git a/Makefile b/Makefile index 8bab84a..ae25266 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ LOGDIR ?= /var/log SYSTEMDUNITDIR ?= /etc/systemd/system all: - @ echo "Use: make install, make systemd, make uninstall" + @ echo "Use: make install, make uninstall" install: install -d $(DESTDIR)$(BINDIR) @@ -14,7 +14,7 @@ install: install -m0755 nohang/nohang $(DESTDIR)$(BINDIR)/nohang install -m0755 tools/oom-sort $(DESTDIR)$(BINDIR)/oom-sort install -m0755 tools/psi-top $(DESTDIR)$(BINDIR)/psi-top - install -m0755 tools/psi-monitor $(DESTDIR)$(BINDIR)/psi-monitor + install -m0755 tools/psi2log $(DESTDIR)$(BINDIR)/psi2log install -d $(DESTDIR)$(CONFDIR)/nohang -git describe --tags --long --dirty > version @@ -24,38 +24,7 @@ install: install -m0644 nohang/nohang.conf $(DESTDIR)$(CONFDIR)/nohang/nohang.conf install -m0644 nohang/nohang.conf $(DESTDIR)$(CONFDIR)/nohang/nohang.conf.default install -m0644 nohang/nohang-desktop.conf $(DESTDIR)$(CONFDIR)/nohang/nohang-desktop.conf - - install -d $(DESTDIR)$(CONFDIR)/logrotate.d - install -m0644 nohang/nohang.logrotate $(DESTDIR)$(CONFDIR)/logrotate.d/nohang - - install -d $(DESTDIR)$(MANDIR) - gzip -c nohang/nohang.1 > $(DESTDIR)$(MANDIR)/nohang.1.gz - gzip -c tools/oom-sort.1 > $(DESTDIR)$(MANDIR)/oom-sort.1.gz - gzip -c tools/psi-top.1 > $(DESTDIR)$(MANDIR)/psi-top.1.gz - gzip -c tools/psi-monitor.1 > $(DESTDIR)$(MANDIR)/psi-monitor.1.gz - - -install -d $(DESTDIR)$(SYSTEMDUNITDIR) - -sed "s|:TARGET_BIN:|$(BINDIR)|g;s|:TARGET_CONF:|$(CONFDIR)|g" nohang/nohang.service.in > nohang.service - -install -m0644 nohang.service $(DESTDIR)$(SYSTEMDUNITDIR)/nohang.service - -rm -fv nohang.service - -chcon -t systemd_unit_file_t $(DESTDIR)$(SYSTEMDUNITDIR)/nohang.service - -install-desktop: - install -d $(DESTDIR)$(BINDIR) - - install -m0755 nohang/nohang $(DESTDIR)$(BINDIR)/nohang - install -m0755 tools/oom-sort $(DESTDIR)$(BINDIR)/oom-sort - install -m0755 tools/psi-top $(DESTDIR)$(BINDIR)/psi-top - install -m0755 tools/psi-monitor $(DESTDIR)$(BINDIR)/psi-monitor - - install -d $(DESTDIR)$(CONFDIR)/nohang - -git describe --tags --long --dirty > version - -install -m0644 version $(DESTDIR)$(CONFDIR)/nohang/version - -rm -fv version - - install -m0644 nohang/nohang-desktop.conf $(DESTDIR)$(CONFDIR)/nohang/nohang.conf install -m0644 nohang/nohang-desktop.conf $(DESTDIR)$(CONFDIR)/nohang/nohang-desktop.conf.default - install -m0644 nohang/nohang.conf $(DESTDIR)$(CONFDIR)/nohang/nohang.conf.default install -d $(DESTDIR)$(CONFDIR)/logrotate.d install -m0644 nohang/nohang.logrotate $(DESTDIR)$(CONFDIR)/logrotate.d/nohang @@ -64,40 +33,36 @@ install-desktop: gzip -c nohang/nohang.1 > $(DESTDIR)$(MANDIR)/nohang.1.gz gzip -c tools/oom-sort.1 > $(DESTDIR)$(MANDIR)/oom-sort.1.gz gzip -c tools/psi-top.1 > $(DESTDIR)$(MANDIR)/psi-top.1.gz - gzip -c tools/psi-monitor.1 > $(DESTDIR)$(MANDIR)/psi-monitor.1.gz + gzip -c tools/psi2log.1 > $(DESTDIR)$(MANDIR)/psi2log.1.gz -install -d $(DESTDIR)$(SYSTEMDUNITDIR) -sed "s|:TARGET_BIN:|$(BINDIR)|g;s|:TARGET_CONF:|$(CONFDIR)|g" nohang/nohang.service.in > nohang.service + -sed "s|:TARGET_BIN:|$(BINDIR)|g;s|:TARGET_CONF:|$(CONFDIR)|g" nohang/nohang-desktop.service.in > nohang-desktop.service -install -m0644 nohang.service $(DESTDIR)$(SYSTEMDUNITDIR)/nohang.service + -install -m0644 nohang-desktop.service $(DESTDIR)$(SYSTEMDUNITDIR)/nohang-desktop.service -rm -fv nohang.service + -rm -fv nohang-desktop.service -chcon -t systemd_unit_file_t $(DESTDIR)$(SYSTEMDUNITDIR)/nohang.service + -chcon -t systemd_unit_file_t $(DESTDIR)$(SYSTEMDUNITDIR)/nohang-desktop.service + -systemctl daemon-reload uninstall: # 'make uninstall' must not fail with error if systemctl is unavailable or returns error -systemctl stop nohang.service || true + -systemctl stop nohang-desktop.service || true -systemctl disable nohang.service || true + -systemctl disable nohang-desktop.service || true -systemctl daemon-reload rm -fv $(DESTDIR)$(BINDIR)/nohang rm -fv $(DESTDIR)$(BINDIR)/oom-sort rm -fv $(DESTDIR)$(BINDIR)/psi-top - rm -fv $(DESTDIR)$(BINDIR)/psi-monitor + rm -fv $(DESTDIR)$(BINDIR)/psi2log rm -fv $(DESTDIR)$(MANDIR)/nohang.1.gz rm -fv $(DESTDIR)$(MANDIR)/oom-sort.1.gz rm -fv $(DESTDIR)$(MANDIR)/psi-top.1.gz - rm -fv $(DESTDIR)$(MANDIR)/psi-monitor.1.gz + rm -fv $(DESTDIR)$(MANDIR)/psi2log.1.gz rm -fv $(DESTDIR)$(SYSTEMDUNITDIR)/nohang.service + rm -fv $(DESTDIR)$(SYSTEMDUNITDIR)/nohang-desktop.service rm -fvr $(DESTDIR)$(CONFDIR)/nohang/ rm -fvr $(DESTDIR)$(CONFDIR)/logrotate.d/nohang rm -fvr $(DESTDIR)$(LOGDIR)/nohang/ - -systemd: - -systemctl daemon-reload - -systemctl enable nohang.service - -systemctl restart nohang - -systemctl status nohang - -pylint: - -pylint3 -E nohang/nohang - -pylint3 -E tools/oom-sort - -pylint3 -E tools/psi-top - -pylint3 -E tools/psi-monitor diff --git a/README.md b/README.md index 153eef9..26fb440 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,11 @@ Of course, you can also [download more RAM](https://downloadmoreram.com/), tune ## Demo -- `nohang` prevents Out Of Memory with GUI notifications: [https://youtu.be/ChTNu9m7uMU](https://youtu.be/ChTNu9m7uMU) (just old demo without swap space). -- `nohang` prevents Out Of Memory with GUI notifications: [https://youtu.be/UCwZS5uNLu0](https://youtu.be/UCwZS5uNLu0) (running multiple fast memory hogs at the same time without swap space). -- `nohang` prevents Out Of Memory with GUI notifications: [https://youtu.be/PLVWgNrVNlc](https://youtu.be/PLVWgNrVNlc) (opening multiple chromium tabs with 2.3 GiB memory and 1.8 GiB swap space on zram). +`nohang` prevents Out Of Memory with GUI notifications: + +- [https://youtu.be/ChTNu9m7uMU](https://youtu.be/ChTNu9m7uMU) - just old demo without swap space. +- [https://youtu.be/UCwZS5uNLu0](https://youtu.be/UCwZS5uNLu0) - running multiple fast memory hogs at the same time without swap space. +- [https://youtu.be/PLVWgNrVNlc](https://youtu.be/PLVWgNrVNlc) - opening multiple chromium tabs with 2.3 GiB memory and 1.8 GiB swap space on zram. ## Requirements @@ -109,21 +111,30 @@ $ sudo systemctl enable --now nohang #### To install on Debian and Ubuntu please make a deb package. -To install the latest version on any distro: +#### To install the latest version on any distro: ```bash $ git clone https://github.com/hakavlad/nohang.git $ cd nohang -$ sudo make install # `sudo make install-desktop` to enable GUI notifications by default +$ sudo make install ``` -To enable and start on systems with systemd: -```bash -$ sudo make systemd +`nohang` package comes with two systemd units that run with different config files: `nohang.conf` and `nohang-desktop.conf`. + +To enable and start unit without GUI notifications: +``` +$ sudo systemctl enable nohang +$ sudo systemctl start nohang ``` -To enable and start on systems without systemd please make a PR to fix Makefile. +To enable and start unit with GUI notifications: +``` +$ sudo systemctl enable nohang-desktop +$ sudo systemctl start nohang-desktop +``` -To uninstall: +#### To enable and start on systems without systemd please make a PR to fix Makefile. + +#### To uninstall: ```bash $ sudo make uninstall ``` @@ -460,7 +471,7 @@ some 0.00 0.18 0.30 | full 0.00 0.18 0.30 /system.slice/systemd-log ``` -### psi-monitor +### psi2log It needs `Linux` >= 4.20 with `CONFIG_PSI=y`. @@ -468,8 +479,8 @@ It needs `Linux` >= 4.20 with `CONFIG_PSI=y`. Output example ``` -$ psi-monitor -Starting psi-monitor +$ psi2log +Starting psi2log target: SYSTEM_WIDE period: 2 ------------------------------------------------------------------------------------------------------------------ @@ -491,8 +502,8 @@ full memory 2.68 7.69 2.56 ----------- ------ ------ ------ some io 20.24 26.90 8.61 full io 18.80 23.16 7.35 -$ psi-monitor -t /user.slice -l pm.log -Starting psi-monitor +$ psi2log -t /user.slice -l pm.log +Starting psi2log target: /user.slice period: 2 log file: pm.log @@ -523,8 +534,13 @@ full io 0.54 7.52 6.80 ## Contribution -Use cases, feature requests and any questions are [welcome](https://github.com/hakavlad/nohang/issues). +- Use cases, feature requests and any questions are [welcome](https://github.com/hakavlad/nohang/issues). +- Pull requests in `dev` branch are welcome. ## Changelog See [CHANGELOG.md](https://github.com/hakavlad/nohang/blob/master/CHANGELOG.md) + +## Status + +Copr automated dev build: [![Copr automated dev build status](https://copr.fedorainfracloud.org/coprs/atim/nohang-dev/package/nohang-dev/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/atim/nohang-dev/package/nohang-dev/) diff --git a/nohang/nohang b/nohang/nohang index 892363a..ee49b10 100755 --- a/nohang/nohang +++ b/nohang/nohang @@ -168,9 +168,9 @@ def pop(cmd, username): if swap_total == 0: - wait_time = 2 + wait_time = 5 else: - wait_time = 20 + wait_time = 25 t3 = monotonic() @@ -271,11 +271,14 @@ def send_notify_warn(): else: title = 'Low memory' + body = 'Save your unsaved data!' + """" body = 'MemAvail: {}%\nSwapFree: {}%'.format( round(mem_available / mem_total * 100), round(swap_free / (swap_total + 0.1) * 100) ) + """ start_thread(send_notification, title, body) @@ -289,7 +292,7 @@ def send_notify(threshold, name, pid): pid: str process pid """ - title = 'Freeze prevention' + title = 'System hang prevention' if hide_corrective_action_type: body = 'Corrective action applied' @@ -314,7 +317,7 @@ def send_notify_etc(pid, name, command): name: str process name pid: str process pid """ - title = 'Freeze prevention' + title = 'System hang prevention' if hide_corrective_action_type: body = 'Corrective action applied' else: diff --git a/nohang/nohang-desktop.conf b/nohang/nohang-desktop.conf index ea08288..db79e7c 100644 --- a/nohang/nohang-desktop.conf +++ b/nohang/nohang-desktop.conf @@ -124,7 +124,7 @@ post_action_gui_notifications = True Type: boolean Valid values: True and False -hide_corrective_action_type = True +hide_corrective_action_type = False 4.2. Low memory warnings @@ -263,12 +263,9 @@ forbid_negative_badness = True Example: @BADNESS_ADJ_RE_NAME -500 /// ^sshd$ - Prefer firefox tabs -@BADNESS_ADJ_RE_NAME 300 /// ^Web Content$ - 7.3.2. Matching CGroup_v1-line with RE patterns -@BADNESS_ADJ_RE_CGROUP_V1 -50 /// ^/system\.slice/ + @BADNESS_ADJ_RE_CGROUP_V1 -50 /// ^/system\.slice/ @BADNESS_ADJ_RE_CGROUP_V1 50 /// /foo\.service$ diff --git a/nohang/nohang-desktop.service.in b/nohang/nohang-desktop.service.in new file mode 100644 index 0000000..bf7e19b --- /dev/null +++ b/nohang/nohang-desktop.service.in @@ -0,0 +1,28 @@ +[Unit] +Description=Highly configurable OOM prevention daemon +Documentation=man:nohang(1) https://github.com/hakavlad/nohang +Conflicts=nohang.service +After=system.slice + +[Service] +ExecStart=:TARGET_BIN:/nohang --config :TARGET_CONF:/nohang/nohang-desktop.conf +Restart=always +RestartSec=0 +KillMode=mixed +TasksMax=100 +Nice=-15 +CPUSchedulingResetOnFork=true +OOMScoreAdjust=-10 +UMask=0027 +PrivateTmp=true +RestrictRealtime=yes +MemoryDenyWriteExecute=yes +ProtectKernelModules=true +SystemCallArchitectures=native +ReadOnlyPaths=/ +ReadWritePaths=/tmp /var /run /dev/shm +CapabilityBoundingSet=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID +AmbientCapabilities=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID + +[Install] +WantedBy=multi-user.target diff --git a/nohang/nohang.conf b/nohang/nohang.conf index 141257d..62fd2ca 100644 --- a/nohang/nohang.conf +++ b/nohang/nohang.conf @@ -124,7 +124,7 @@ post_action_gui_notifications = False Type: boolean Valid values: True and False -hide_corrective_action_type = True +hide_corrective_action_type = False 4.2. Low memory warnings diff --git a/rpm/nohang-dev.spec b/rpm/nohang-dev.spec new file mode 100644 index 0000000..0a4c55d --- /dev/null +++ b/rpm/nohang-dev.spec @@ -0,0 +1,124 @@ +### Automated build version of dev branch + +%define build_timestamp %{lua: print(os.date("%Y%m%d.%H"))} +%global appname nohang + +Name: %{appname}-dev +Version: 0.1 +Release: %{build_timestamp}%{?dist} +Summary: Highly configurable OOM prevention daemon + +License: MIT +URL: https://github.com/hakavlad/nohang +Source0: %{url}/archive/dev/%{name}-%{build_timestamp}.tar.gz +BuildArch: noarch + +%if 0%{?el7} +BuildRequires: systemd +%else +BuildRequires: systemd-rpm-macros +%endif +Requires: logrotate +%if 0%{?fedora} || 0%{?rhel} >= 8 +Recommends: %{name}-desktop +%endif +%{?systemd_requires} + +%description +Nohang is a highly configurable daemon for Linux which is able to correctly +prevent out of memory (OOM) and keep system responsiveness in low +memory conditions. + +To enable and start: + + systemctl enable --now %{appname} + + +%package desktop +Summary: Desktop version of %{name} +BuildArch: noarch + +Requires: %{name} = %{version}-%{release} +Requires: libnotify + +%description desktop +Desktop version of %{name}. + + +%prep +%autosetup -n %{appname}-dev-%{version} + + +%build +%make_build + + +%install +%make_install BINDIR=%{_bindir} CONFDIR=%{_sysconfdir} SYSTEMDUNITDIR=%{_unitdir} +echo "v%{version}-%{build_timestamp}" > %{buildroot}%{_sysconfdir}/%{appname}/version + + +%post +%systemd_post %{appname}.service + +%preun +%systemd_preun %{appname}.service + +%postun +%systemd_postun_with_restart %{appname}.service + +### Desktop +%post desktop +%systemd_post %{appname}-desktop.service + +%preun desktop +%systemd_preun %{appname}-desktop.service + +%postun desktop +%systemd_postun_with_restart %{appname}-desktop.service + + +%files +%license LICENSE +%doc README.md CHANGELOG.md +%{_bindir}/%{appname} +%{_bindir}/oom-sort +%{_bindir}/psi-top +%{_bindir}/psi2log +%{_mandir}/man1/* +%{_sysconfdir}/%{appname}/%{appname}.conf.default +%{_sysconfdir}/%{appname}/version +%{_sysconfdir}/logrotate.d/%{appname} +%{_unitdir}/%{appname}.service +%dir %{_sysconfdir}/%{appname}/ +%config(noreplace) %{_sysconfdir}/%{appname}/%{appname}.conf + +%files desktop +%{_sysconfdir}/%{appname}/%{appname}-desktop.conf.default +%{_unitdir}/%{appname}-desktop.service +%config(noreplace) %{_sysconfdir}/%{appname}/%{appname}-desktop.conf + + +%changelog +* Sun Nov 17 2019 Artem Polishchuk - 0.1-16.20191117gitaef8af6 +- Update to latest git snapshot + +* Mon Oct 14 2019 Artem Polishchuk - 0.1-15.20191005git2a3209c +- Update to latest git snapshot + +* Thu Sep 19 2019 Artem Polishchuk - 0.1-14.20190919git286ed84 +- Update to latest git snapshot + +* Tue Sep 10 2019 Artem Polishchuk - 0.1-10.20190910gite442e41 +- Update to latest git snapshot +- Add 'desktop' package + +* Thu Sep 05 2019 Artem Polishchuk - 0.1-8.20190905git6db1833 +- Update to latest git snapshot + +* Sun Sep 01 2019 Artem Polishchuk - 0.1-7.20190901git4c1b5ee +- Update to latest git snapshot + +* Sat Aug 31 2019 Artem Polishchuk - 0.1-5.20190831gitf3baa58 +- Initial package + diff --git a/tools/psi-monitor.1 b/tools/psi-monitor.1 deleted file mode 100644 index 262d94f..0000000 --- a/tools/psi-monitor.1 +++ /dev/null @@ -1,5 +0,0 @@ -.TH psi-monitor 1 - -.SH NAME - -psi-monitor \- PSI metrics monitor diff --git a/tools/psi-monitor b/tools/psi2log similarity index 99% rename from tools/psi-monitor rename to tools/psi2log index 4ea6162..321da05 100755 --- a/tools/psi-monitor +++ b/tools/psi2log @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""psi-monitor""" +"""psi2log""" import os from time import sleep @@ -186,7 +186,7 @@ if separate_log: level=logging.INFO, format="%(asctime)s: %(message)s") -log('Starting psi-monitor') +log('Starting psi2log') log('target: {}'.format(target)) log('period: {}'.format(period)) if log_file is not None: diff --git a/tools/psi2log.1 b/tools/psi2log.1 new file mode 100644 index 0000000..46b61b0 --- /dev/null +++ b/tools/psi2log.1 @@ -0,0 +1,5 @@ +.TH psi2log 1 + +.SH NAME + +psi2log \- PSI metrics monitor and logger