diff --git a/tuned-add-app-sensor-profile.patch b/tuned-add-app-sensor-profile.patch new file mode 100644 index 0000000000000000000000000000000000000000..90113c9eb9ebea8b7696193d92332aad459d6893 --- /dev/null +++ b/tuned-add-app-sensor-profile.patch @@ -0,0 +1,232 @@ +From e8fb537645141bc87425b481e48f8484f05725b8 Mon Sep 17 00:00:00 2001 +From: hubin +Date: Sat, 15 Jul 2023 12:17:36 +0800 +Subject: [PATCH] tuned: add app-sensor profile + +add application plugin and process monitor support for app-sensor profile. + +if switch to app-sensor, apps given in app-sensor conf file will be +monitored, and actions given repectively in app-sensor conf file will +be executed when the monitored app starts or quits. + +Signed-off-by: hubin +--- + profiles/app-sensor/tuned.conf | 23 ++++++++ + tuned/monitors/monitor_process.py | 83 ++++++++++++++++++++++++++++ + tuned/plugins/plugin_application.py | 84 +++++++++++++++++++++++++++++ + 3 files changed, 190 insertions(+) + create mode 100644 profiles/app-sensor/tuned.conf + create mode 100644 tuned/monitors/monitor_process.py + create mode 100644 tuned/plugins/plugin_application.py + +diff --git a/profiles/app-sensor/tuned.conf b/profiles/app-sensor/tuned.conf +new file mode 100644 +index 0000000..771e6ae +--- /dev/null ++++ b/profiles/app-sensor/tuned.conf +@@ -0,0 +1,23 @@ ++[main] ++summary=dynamic tuning for configured apps ++ ++[application] ++# Define list of monitored apps, separated by comma. ++# Only apps declared in name will be monitored and execute defined action when app starts and quits. ++# Definition syntax: ++# name={app1},{app2},... ++# for example: ++# name=redis,mysql ++name= ++ ++# Define action or rollback action for each monitored app. ++# No definition or blank action means no action. ++# Definition syntax: ++# {app}_action={command} ++# {app}_rollback_action={command} ++# for example: ++# redis_action="sysctl -w kernel.sched_min_granularity_ns=10000000" ++# redis_rollback_action="sysctl -w kernel.sched_min_granularity_ns=3000000" ++# mysql_action= ++# mysql_rollback_action= ++ +diff --git a/tuned/monitors/monitor_process.py b/tuned/monitors/monitor_process.py +new file mode 100644 +index 0000000..524b27a +--- /dev/null ++++ b/tuned/monitors/monitor_process.py +@@ -0,0 +1,83 @@ ++import psutil ++import tuned.monitors ++import tuned.logs ++ ++log = tuned.logs.get() ++ ++ ++class ProcessMonitor(tuned.monitors.Monitor): ++ app_program_dict = { ++ "mysql": ["mysqld"], ++ "redis": ["redis-server"], ++ "nginx": ["nginx"], ++ "unixbench": ["Run"], ++ "unixbench-arithoh": ["arithoh"], ++ "unixbench-context1": ["context1"], ++ "unixbench-dhry2": ["dhry2"], ++ "unixbench-dhry2reg": ["dhry2reg"], ++ "unixbench-double": ["double"], ++ "unixbench-execl": ["execl"], ++ "unixbench-float": ["float"], ++ "unixbench-fstime": ["fstime"], ++ "unixbench-gfx-x11": ["gfx-x11"], ++ "unixbench-hanoi": ["hanoi"], ++ "unixbench-int": ["int"], ++ "unixbench-long": ["long"], ++ "unixbench-looper": ["looper"], ++ "unixbench-pipe": ["pipe"], ++ "unixbench-register": ["register"], ++ "unixbench-short": ["short"], ++ "unixbench-spawn": ["spawn"], ++ "unixbench-syscall": ["syscall"], ++ "unixbench-whetstone-double": ["whetstone-double"], ++ "fio": ["fio"], ++ "iozone": ["iozone"], ++ "lmbench": ["lmbench"], ++ "netperf": ["netperf"] ++ } ++ ++ pid_set = set() ++ pid_app_dict = {} ++ ++ @classmethod ++ def _init_available_devices(cls): ++ cls._available_devices = set(["application"]) ++ cls._load["application"] = set() ++ ++ @classmethod ++ def update(cls): ++ cur_pids = set(psutil.pids()) ++ prev_pids = cls.pid_set ++ ++ # collect new pid and gone pid ++ new_pids = cur_pids - prev_pids ++ gone_pids = prev_pids - cur_pids ++ ++ # deal with gone pids ++ if len(gone_pids) > 0: ++ log.debug(f"find {len(gone_pids)} processes gone") ++ for pid in gone_pids: ++ cls.pid_set.remove(pid) ++ if pid in cls.pid_app_dict: ++ log.debug(f"app process gone: {cls.pid_app_dict[pid]} (pid {pid})") ++ cls.pid_app_dict.pop(pid) ++ ++ # deal with new pids ++ if len(new_pids) > 0: ++ log.debug(f"find {len(new_pids)} processes created") ++ for pid in new_pids: ++ try: ++ process = psutil.Process(pid) ++ process_name = process.name() ++ except psutil.NoSuchProcess: ++ continue ++ cls.pid_set.add(pid) ++ # match process name with known applications ++ for app in cls.app_program_dict: ++ if process_name in cls.app_program_dict[app]: ++ cls.pid_app_dict[pid] = app ++ log.debug(f"app process created: {cls.pid_app_dict[pid]} (pid {pid})") ++ break ++ ++ # output current running applications ++ cls._load["application"] = set(cls.pid_app_dict.values()) +diff --git a/tuned/plugins/plugin_application.py b/tuned/plugins/plugin_application.py +new file mode 100644 +index 0000000..946d284 +--- /dev/null ++++ b/tuned/plugins/plugin_application.py +@@ -0,0 +1,84 @@ ++import subprocess ++from . import base ++from . import exceptions ++import tuned.logs ++from tuned.utils.commands import commands ++ ++log = tuned.logs.get() ++ ++ACTION_TIMEOUT = 180 ++ ++class ApplicationPlugin(base.Plugin): ++ """ ++ `application`: ++ ++ Dynamically executes the optimization action according to the application ++ running situation. ++ """ ++ last_apps_running = set() ++ ++ def __init__(self, *args, **kwargs): ++ super(ApplicationPlugin, self).__init__(*args, **kwargs) ++ self._has_dynamic_options = True ++ ++ def _instance_init(self, instance): ++ instance._has_static_tuning = False ++ instance._has_dynamic_tuning = True ++ # save all options ++ instance.option_dict = {} ++ for option, value in list(instance.options.items()): ++ instance.option_dict[option] = value ++ log.debug(f"{option}: {value}") ++ instance._load_monitor = self._monitors_repository.create("process", None) ++ ++ def _instance_cleanup(self, instance): ++ if instance._load_monitor is not None: ++ self._monitors_repository.delete(instance._load_monitor) ++ instance._load_monitor = None ++ instance.option_dict.clear() ++ ++ def _instance_update_dynamic(self, instance, device): ++ if "name" not in instance.option_dict: ++ return ++ applications_monitored = set([app.strip() for app in instance.option_dict["name"].split(',')]) ++ if not applications_monitored: ++ return ++ apps_running = applications_monitored.intersection(instance._load_monitor.get_load()["application"]) ++ log.debug("running: " + str(apps_running)) ++ new_apps = apps_running - self.last_apps_running ++ gone_apps = self.last_apps_running - apps_running ++ if len(new_apps) > 0: ++ log.info("new apps: " + str(new_apps)) ++ if len(gone_apps) > 0: ++ log.info("gone apps: " + str(gone_apps)) ++ for app in gone_apps: ++ self._execute_action(instance, app, rollback=True) ++ for app in new_apps: ++ self._execute_action(instance, app, rollback=False) ++ self.last_apps_running = apps_running ++ ++ def _instance_unapply_dynamic(self, instance, device): ++ # restore previous value ++ pass ++ ++ def _execute_action(self, instance, app, rollback=False): ++ # find action ++ if rollback: ++ option = f"{app}_rollback_action" ++ else: ++ option = f"{app}_action" ++ if option not in instance.option_dict: ++ return ++ action = str(instance.option_dict[option]) ++ # remove wrapping " or ' in action ++ if len(action) >= 2 and (action[0] == '"' or action[0] == "'") and action[0] == action[-1]: ++ action = action[1:-1] ++ # execute action for app ++ if len(action): ++ log.info(f"{option}: {action}") ++ try: ++ p = subprocess.Popen(action, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) ++ retval = p.wait(ACTION_TIMEOUT) ++ log.info(f"{option}: return {retval}") ++ except Exception as e: ++ log.info(f"{option}: {str(e)}") +-- +2.33.0 + diff --git a/tuned.spec b/tuned.spec index 8f521ad0c6b6e225e40bf2ede70f01c36325bbff..71fa736c0608a973c8e0bd2a35cd349f9fc18914 100644 --- a/tuned.spec +++ b/tuned.spec @@ -1,7 +1,7 @@ Summary: A system tuning service for Linux Name: tuned Version: 2.19.0 -Release: 3 +Release: 4 License: GPLv2+ Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}.tar.gz#/%{name}-%{version}%{?prerel2}.tar.gz URL: http://www.tuned-project.org/ @@ -34,6 +34,7 @@ Patch0: bugfix-tuned-2.8.0-restart-after-kill-dbus.patch Patch1: tuned-2.18.0-rhel-8-profiles.patch Patch2: tuned-2.18.0-sd-load-balance.patch Patch3: change-the-default-percentage-when-dirty-data-starts.patch +Patch4: tuned-add-app-sensor-profile.patch Provides: tuned-gtk Provides: tuned-utils @@ -297,6 +298,9 @@ fi %{_mandir}/man7/tuned-profiles-spectrumscale-ece.7* %changelog +* Sat Jul 15 2023 hubin - 2.19.0-4 +- tuned: add application plugin and process monitor for app-sensor profile + * Mon Dec 26 2022 hongrongxuan - 2.19.0-3 - change the default percentage when dirty data starts writeback