Compare commits

...

No commits in common. "imports/c9-beta/tuned-2.16.0-3.el9" and "c8" have entirely different histories.

12 changed files with 824 additions and 1193 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/tuned-2.16.0.tar.gz
SOURCES/tuned-2.22.1.tar.gz

View File

@ -1 +1 @@
e20fcfb734f869fb175cb88dc7ef6e5eb3cd5946 SOURCES/tuned-2.16.0.tar.gz
60e206fe73ea537e64141f92b331f65879766f97 SOURCES/tuned-2.22.1.tar.gz

View File

@ -1,829 +0,0 @@
From 063277a05b3a174f9265d36032ca097ee5b7cc9c Mon Sep 17 00:00:00 2001
From: Jan Zerdik <jzerdik@redhat.com>
Date: Fri, 30 Jul 2021 11:48:59 +0200
Subject: [PATCH] Removing dependency on python-configobj.
Resolves: rhbz#1936386
Signed-off-by: Jan Zerdik <jzerdik@redhat.com>
---
recommend.conf | 2 +-
tests/unit/profiles/test_loader.py | 7 +++
tests/unit/profiles/test_locator.py | 18 ++++++-
tests/unit/profiles/test_variables.py | 32 ++++++++++++
tests/unit/utils/test_global_config.py | 13 ++++-
tuned-gui.py | 5 +-
tuned.spec | 3 +-
tuned/consts.py | 21 ++++++++
tuned/gtk/gui_plugin_loader.py | 43 +++++++++-------
tuned/gtk/gui_profile_loader.py | 71 ++++++++++++++++++--------
tuned/gtk/gui_profile_saver.py | 28 ++++++----
tuned/profiles/loader.py | 38 ++++++--------
tuned/profiles/locator.py | 25 ++++++---
tuned/profiles/variables.py | 27 +++++-----
tuned/utils/global_config.py | 55 +++++++++++++++-----
tuned/utils/profile_recommender.py | 19 ++++---
16 files changed, 288 insertions(+), 119 deletions(-)
create mode 100644 tests/unit/profiles/test_variables.py
diff --git a/recommend.conf b/recommend.conf
index f3442ca8..7561696c 100644
--- a/recommend.conf
+++ b/recommend.conf
@@ -29,7 +29,7 @@
# Limitation:
# Each profile can be specified only once, because there cannot be
# multiple sections in the configuration file with the same name
-# (ConfigObj limitation).
+# (ConfigParser limitation).
# If there is a need to specify the profile multiple times, unique
# suffix like ',ANYSTRING' can be used. Everything after the last ','
# is stripped by the parser, e.g.:
diff --git a/tests/unit/profiles/test_loader.py b/tests/unit/profiles/test_loader.py
index b6ea76e9..149353d8 100644
--- a/tests/unit/profiles/test_loader.py
+++ b/tests/unit/profiles/test_loader.py
@@ -46,6 +46,8 @@ def setUpClass(cls):
f.write('file_path=${i:PROFILE_DIR}/whatever\n')
f.write('script=random_name.sh\n')
f.write('[test_unit]\ntest_option=hello world\n')
+ f.write('devices=/dev/${variable1},/dev/${variable2}\n')
+ f.write('[variables]\nvariable1=net\nvariable2=cpu')
def setUp(self):
locator = profiles.Locator([self._profiles_dir])
@@ -105,6 +107,11 @@ def test_load_config_data(self):
self.assertEqual(config['test_unit']['test_option'],\
'hello world')
+ def test_variables(self):
+ config = self._loader.load(['dummy4'])
+ self.assertEqual(config.units['test_unit'].devices,\
+ '/dev/net,/dev/cpu')
+
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls._test_dir)
diff --git a/tests/unit/profiles/test_locator.py b/tests/unit/profiles/test_locator.py
index cce88daa..bf2906d7 100644
--- a/tests/unit/profiles/test_locator.py
+++ b/tests/unit/profiles/test_locator.py
@@ -30,7 +30,10 @@ def _create_profile(cls, load_dir, profile_name):
conf_name = os.path.join(profile_dir, "tuned.conf")
os.mkdir(profile_dir)
with open(conf_name, "w") as conf_file:
- pass
+ if profile_name != "custom":
+ conf_file.write("[main]\nsummary=this is " + profile_name + "\n")
+ else:
+ conf_file.write("summary=this is " + profile_name + "\n")
def test_init(self):
Locator([])
@@ -65,3 +68,16 @@ def test_ignore_nonexistent_dirs(self):
self.assertEqual(balanced, os.path.join(self._tmp_load_dirs[0], "balanced", "tuned.conf"))
known = locator.get_known_names()
self.assertListEqual(known, ["balanced", "powersafe"])
+
+ def test_get_known_names_summary(self):
+ self.assertEqual(("balanced", "this is balanced"), sorted(self.locator.get_known_names_summary())[0])
+
+ def test_get_profile_attrs(self):
+ attrs = self.locator.get_profile_attrs("balanced", ["summary", "wrong_attr"], ["this is default", "this is wrong attr"])
+ self.assertEqual([True, "balanced", "this is balanced", "this is wrong attr"], attrs)
+
+ attrs = self.locator.get_profile_attrs("custom", ["summary"], ["wrongly writen profile"])
+ self.assertEqual([True, "custom", "wrongly writen profile"], attrs)
+
+ attrs = self.locator.get_profile_attrs("different", ["summary"], ["non existing profile"])
+ self.assertEqual([False, "", "", ""], attrs)
diff --git a/tests/unit/profiles/test_variables.py b/tests/unit/profiles/test_variables.py
new file mode 100644
index 00000000..47fff2c1
--- /dev/null
+++ b/tests/unit/profiles/test_variables.py
@@ -0,0 +1,32 @@
+import unittest
+import tempfile
+import shutil
+from tuned.profiles import variables, profile
+
+class VariablesTestCase(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.test_dir = tempfile.mkdtemp()
+
+ with open(cls.test_dir + "/variables", 'w') as f:
+ f.write("variable1=var1\n")
+
+ def test_from_file(self):
+ v = variables.Variables()
+ v.add_from_file(self.test_dir + "/variables")
+ self.assertEqual("This is var1", v.expand("This is ${variable1}"))
+
+ def test_from_unit(self):
+ mock_unit = {
+ "include": self.test_dir + "/variables",
+ "variable2": "var2"
+ }
+ v = variables.Variables()
+ v.add_from_cfg(mock_unit)
+
+ self.assertEqual("This is var1 and this is var2", v.expand("This is ${variable1} and this is ${variable2}"))
+
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.test_dir)
diff --git a/tests/unit/utils/test_global_config.py b/tests/unit/utils/test_global_config.py
index 5b93888c..8981d544 100644
--- a/tests/unit/utils/test_global_config.py
+++ b/tests/unit/utils/test_global_config.py
@@ -12,7 +12,8 @@ def setUpClass(cls):
cls.test_dir = tempfile.mkdtemp()
with open(cls.test_dir + '/test_config','w') as f:
f.write('test_option = hello\ntest_bool = 1\ntest_size = 12MB\n'\
- + 'false_bool=0\n')
+ + 'false_bool=0\n'\
+ + consts.CFG_LOG_FILE_COUNT + " = " + str(consts.CFG_DEF_LOG_FILE_COUNT) + "1\n")
cls._global_config = global_config.GlobalConfig(\
cls.test_dir + '/test_config')
@@ -28,10 +29,18 @@ def test_get_size(self):
self.assertEqual(self._global_config.get_size('test_size'),\
12*1024*1024)
- self._global_config.set('test_size','bad_value')
+ self._global_config.set('test_size', 'bad_value')
self.assertIsNone(self._global_config.get_size('test_size'))
+ def test_default(self):
+ daemon = self._global_config.get(consts.CFG_DAEMON)
+ self.assertEqual(daemon, consts.CFG_DEF_DAEMON)
+
+ log_file_count = self._global_config.get(consts.CFG_LOG_FILE_COUNT)
+ self.assertIsNotNone(log_file_count)
+ self.assertNotEqual(log_file_count, consts.CFG_DEF_LOG_FILE_COUNT)
+
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.test_dir)
diff --git a/tuned-gui.py b/tuned-gui.py
index a2792792..3953f82f 100755
--- a/tuned-gui.py
+++ b/tuned-gui.py
@@ -48,7 +48,7 @@
import sys
import os
import time
-import configobj
+import collections
import subprocess
import tuned.logs
@@ -508,8 +508,7 @@ def on_click_button_confirm_profile_update(self, data):
def data_to_profile_config(self):
name = self._gobj('entryProfileName').get_text()
- config = configobj.ConfigObj(list_values = False,
- interpolation = False)
+ config = collections.OrderedDict()
activated = self._gobj('comboboxIncludeProfile').get_active()
model = self._gobj('comboboxIncludeProfile').get_model()
diff --git a/tuned.spec b/tuned.spec
index e3a494fd..7afe1935 100644
--- a/tuned.spec
+++ b/tuned.spec
@@ -66,9 +66,8 @@ BuildRequires: %{_py}, %{_py}-devel
%if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 )
BuildRequires: %{_py}-mock
%endif
-BuildRequires: %{_py}-configobj
BuildRequires: %{_py}-pyudev
-Requires: %{_py}-pyudev, %{_py}-configobj
+Requires: %{_py}-pyudev
Requires: %{_py}-linux-procfs, %{_py}-perf
%if %{without python3}
Requires: %{_py}-schedutils
diff --git a/tuned/consts.py b/tuned/consts.py
index 58cbf4a3..8eb075ba 100644
--- a/tuned/consts.py
+++ b/tuned/consts.py
@@ -16,6 +16,8 @@
LOAD_DIRECTORIES = ["/usr/lib/tuned", "/etc/tuned"]
PERSISTENT_STORAGE_DIR = "/var/lib/tuned"
PLUGIN_MAIN_UNIT_NAME = "main"
+# Magic section header because ConfigParser does not support "headerless" config
+MAGIC_HEADER_NAME = "this_is_some_magic_section_header_because_of_compatibility"
RECOMMEND_DIRECTORIES = ["/usr/lib/tuned/recommend.d", "/etc/tuned/recommend.d"]
TMP_FILE_SUFFIX = ".tmp"
@@ -79,6 +81,10 @@
PREFIX_PROFILE_FACTORY = "System"
PREFIX_PROFILE_USER = "User"
+# After adding new option to tuned-main.conf add here its name with CFG_ prefix
+# and eventually default value with CFG_DEF_ prefix (default is None)
+# and function for check with CFG_FUNC_ prefix
+# (see configobj for methods, default is get for string)
CFG_DAEMON = "daemon"
CFG_DYNAMIC_TUNING = "dynamic_tuning"
CFG_SLEEP_INTERVAL = "sleep_interval"
@@ -87,25 +93,40 @@
CFG_REAPPLY_SYSCTL = "reapply_sysctl"
CFG_DEFAULT_INSTANCE_PRIORITY = "default_instance_priority"
CFG_UDEV_BUFFER_SIZE = "udev_buffer_size"
+CFG_LOG_FILE_COUNT = "log_file_count"
+CFG_LOG_FILE_MAX_SIZE = "log_file_max_size"
CFG_UNAME_STRING = "uname_string"
CFG_CPUINFO_STRING = "cpuinfo_string"
# no_daemon mode
CFG_DEF_DAEMON = True
+CFG_FUNC_DAEMON = "getboolean"
# default configuration
CFG_DEF_DYNAMIC_TUNING = True
+CFG_FUNC_DYNAMIC_TUNING = "getboolean"
# how long to sleep before checking for events (in seconds)
CFG_DEF_SLEEP_INTERVAL = 1
+CFG_FUNC_SLEEP_INTERVAL = "getint"
# update interval for dynamic tuning (in seconds)
CFG_DEF_UPDATE_INTERVAL = 10
+CFG_FUNC_UPDATE_INTERVAL = "getint"
# recommend command availability
CFG_DEF_RECOMMEND_COMMAND = True
+CFG_FUNC_RECOMMEND_COMMAND = "getboolean"
# reapply system sysctl
CFG_DEF_REAPPLY_SYSCTL = True
+CFG_FUNC_REAPPLY_SYSCTL = "getboolean"
# default instance priority
CFG_DEF_DEFAULT_INSTANCE_PRIORITY = 0
+CFG_FUNC_DEFAULT_INSTANCE_PRIORITY = "getint"
# default pyudev.Monitor buffer size
CFG_DEF_UDEV_BUFFER_SIZE = 1024 * 1024
+# default log file count
+CFG_DEF_LOG_FILE_COUNT = 2
+CFG_FUNC_LOG_FILE_COUNT = "getint"
+# default log file max size
+CFG_DEF_LOG_FILE_MAX_SIZE = 1024 * 1024
+
PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"
diff --git a/tuned/gtk/gui_plugin_loader.py b/tuned/gtk/gui_plugin_loader.py
index d364602d..f943a220 100644
--- a/tuned/gtk/gui_plugin_loader.py
+++ b/tuned/gtk/gui_plugin_loader.py
@@ -25,25 +25,23 @@
'''
import importlib
-from validate import Validator
import tuned.consts as consts
import tuned.logs
-
-import configobj as ConfigObj
+try:
+ from configparser import ConfigParser, Error
+ from io import StringIO
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
+ from StringIO import StringIO
from tuned.exceptions import TunedException
+from tuned.utils.global_config import GlobalConfig
from tuned.admin.dbus_controller import DBusController
__all__ = ['GuiPluginLoader']
-global_config_spec = ['dynamic_tuning = boolean(default=%s)'
- % consts.CFG_DEF_DYNAMIC_TUNING,
- 'sleep_interval = integer(default=%s)'
- % consts.CFG_DEF_SLEEP_INTERVAL,
- 'update_interval = integer(default=%s)'
- % consts.CFG_DEF_UPDATE_INTERVAL]
-
class GuiPluginLoader():
@@ -84,19 +82,26 @@ def _load_global_config(self, file_name=consts.GLOBAL_CONFIG_FILE):
"""
try:
- config = ConfigObj.ConfigObj(file_name,
- configspec=global_config_spec,
- raise_errors = True, file_error = True, list_values = False, interpolation = False)
+ config_parser = ConfigParser()
+ config_parser.optionxform = str
+ with open(file_name) as f:
+ config_parser.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
+ config, functions = GlobalConfig.get_global_config_spec()
+ for option in config_parser.options(consts.MAGIC_HEADER_NAME):
+ if option in config:
+ try:
+ func = getattr(config_parser, functions[option])
+ config[option] = func(consts.MAGIC_HEADER_NAME, option)
+ except Error:
+ raise TunedException("Global TuneD configuration file '%s' is not valid."
+ % file_name)
+ else:
+ config[option] = config_parser.get(consts.MAGIC_HEADER_NAME, option, raw=True)
except IOError as e:
raise TunedException("Global TuneD configuration file '%s' not found."
% file_name)
- except ConfigObj.ConfigObjError as e:
+ except Error as e:
raise TunedException("Error parsing global TuneD configuration file '%s'."
% file_name)
- vdt = Validator()
- if not config.validate(vdt, copy=True):
- raise TunedException("Global TuneD configuration file '%s' is not valid."
- % file_name)
return config
-
diff --git a/tuned/gtk/gui_profile_loader.py b/tuned/gtk/gui_profile_loader.py
index c50dd9ff..dcd16b72 100644
--- a/tuned/gtk/gui_profile_loader.py
+++ b/tuned/gtk/gui_profile_loader.py
@@ -25,10 +25,17 @@
'''
import os
-import configobj
+try:
+ from configparser import ConfigParser, Error
+ from io import StringIO
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
+ from StringIO import StringIO
import subprocess
import json
import sys
+import collections
import tuned.profiles.profile as p
import tuned.consts
@@ -59,14 +66,21 @@ def set_raw_profile(self, profile_name, config):
profilePath = self._locate_profile_path(profile_name)
- config_lines = config.split('\n')
-
if profilePath == tuned.consts.LOAD_DIRECTORIES[1]:
file_path = profilePath + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
-
- config_obj = configobj.ConfigObj(infile=config_lines,list_values = False, interpolation = False)
- config_obj.filename = file_path
- config_obj.initial_comment = ('#', 'tuned configuration', '#')
+ config_parser = ConfigParser()
+ config_parser.optionxform = str
+ config_parser.readfp(StringIO(config))
+
+ config_obj = {
+ 'main': collections.OrderedDict(),
+ 'filename': file_path,
+ 'initial_comment': ('#', 'tuned configuration', '#')
+ }
+ for s in config_parser.sections():
+ config_obj['main'][s] = collections.OrderedDict()
+ for o in config_parser.options(s):
+ config_obj['main'][s][o] = config_parser.get(s, o, raw=True)
self._save_profile(config_obj)
self._refresh_profiles()
else:
@@ -76,8 +90,15 @@ def set_raw_profile(self, profile_name, config):
def load_profile_config(self, profile_name, path):
conf_path = path + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
- profile_config = configobj.ConfigObj(conf_path, list_values = False,
- interpolation = False)
+ config = ConfigParser()
+ config.optionxform = str
+ profile_config = collections.OrderedDict()
+ with open(conf_path) as f:
+ config.readfp(f)
+ for s in config.sections():
+ profile_config[s] = collections.OrderedDict()
+ for o in config.options(s):
+ profile_config[s][o] = config.get(s, o, raw=True)
return profile_config
def _locate_profile_path(self, profile_name):
@@ -95,11 +116,11 @@ def _load_all_profiles(self):
try:
self.profiles[profile] = p.Profile(profile,
self.load_profile_config(profile, d))
- except configobj.ParseError:
+ except Error:
pass
# print "can not make \""+ profile +"\" profile without correct config on path: " + d
-# except:
+# except:StringIO
# raise managerException.ManagerException("Can not make profile")
# print "can not make \""+ profile +"\" profile without correct config with path: " + d
@@ -113,20 +134,24 @@ def _refresh_profiles(self):
def save_profile(self, profile):
path = tuned.consts.LOAD_DIRECTORIES[1] + '/' + profile.name
- config = configobj.ConfigObj(list_values = False, interpolation = False)
- config.filename = path + '/' + tuned.consts.PROFILE_FILE
- config.initial_comment = ('#', 'tuned configuration', '#')
+ config = {
+ 'main': collections.OrderedDict(),
+ 'filename': path + '/' + tuned.consts.PROFILE_FILE,
+ 'initial_comment': ('#', 'tuned configuration', '#')
+ }
+ config['filename'] = path + '/' + tuned.consts.PROFILE_FILE
+ config['initial_comment'] = ('#', 'tuned configuration', '#')
try:
- config['main'] = profile.options
+ config['main']['main'] = profile.options
except KeyError:
- config['main'] = ''
+ config['main']['main'] = {}
# profile dont have main section
pass
for (name, unit) in list(profile.units.items()):
- config[name] = unit.options
+ config['main'][name] = unit.options
self._save_profile(config)
@@ -148,18 +173,20 @@ def update_profile(
if old_profile_name != profile.name:
self.remove_profile(old_profile_name, is_admin=is_admin)
- config = configobj.ConfigObj(list_values = False, interpolation = False)
- config.filename = path + '/' + tuned.consts.PROFILE_FILE
- config.initial_comment = ('#', 'tuned configuration', '#')
+ config = {
+ 'main': collections.OrderedDict(),
+ 'filename': path + '/' + tuned.consts.PROFILE_FILE,
+ 'initial_comment': ('#', 'tuned configuration', '#')
+ }
try:
- config['main'] = profile.options
+ config['main']['main'] = profile.options
except KeyError:
# profile dont have main section
pass
for (name, unit) in list(profile.units.items()):
- config[name] = unit.options
+ config['main'][name] = unit.options
self._save_profile(config)
diff --git a/tuned/gtk/gui_profile_saver.py b/tuned/gtk/gui_profile_saver.py
index b339cba1..24b0fe3a 100644
--- a/tuned/gtk/gui_profile_saver.py
+++ b/tuned/gtk/gui_profile_saver.py
@@ -1,7 +1,11 @@
import os
import sys
import json
-from configobj import ConfigObj
+try:
+ from configparser import ConfigParser
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser
if __name__ == "__main__":
@@ -11,13 +15,19 @@
if not os.path.exists(profile_dict['filename']):
os.makedirs(os.path.dirname(profile_dict['filename']))
- profile_configobj = ConfigObj()
- for section in profile_dict['sections']:
- profile_configobj[section] = profile_dict['main'][section]
-
- profile_configobj.filename = os.path.join('/etc','tuned',os.path.dirname(os.path.abspath(profile_dict['filename'])),'tuned.conf')
- profile_configobj.initial_comment = profile_dict['initial_comment']
-
- profile_configobj.write()
+ profile_configobj = ConfigParser()
+ profile_configobj.optionxform = str
+ for section, options in profile_dict['main'].items():
+ profile_configobj.add_section(section)
+ for option, value in options.items():
+ profile_configobj.set(section, option, value)
+
+ path = os.path.join('/etc','tuned',os.path.dirname(os.path.abspath(profile_dict['filename'])),'tuned.conf')
+ with open(path, 'w') as f:
+ profile_configobj.write(f)
+ with open(path, 'r+') as f:
+ content = f.read()
+ f.seek(0, 0)
+ f.write("\n".join(profile_dict['initial_comment']) + "\n" + content)
sys.exit(0)
diff --git a/tuned/profiles/loader.py b/tuned/profiles/loader.py
index 7f132b4f..31037182 100644
--- a/tuned/profiles/loader.py
+++ b/tuned/profiles/loader.py
@@ -1,6 +1,10 @@
import tuned.profiles.profile
import tuned.profiles.variables
-from configobj import ConfigObj, ConfigObjError
+try:
+ from configparser import ConfigParser, Error
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
import tuned.consts as consts
import os.path
import collections
@@ -96,30 +100,22 @@ def _expand_profile_dir(self, profile_dir, string):
def _load_config_data(self, file_name):
try:
- config_obj = ConfigObj(file_name, raise_errors = True, list_values = False, interpolation = False)
- except ConfigObjError as e:
+ config_obj = ConfigParser()
+ config_obj.optionxform=str
+ with open(file_name) as f:
+ config_obj.readfp(f)
+ except Error as e:
raise InvalidProfileException("Cannot parse '%s'." % file_name, e)
config = collections.OrderedDict()
- for section in list(config_obj.keys()):
- config[section] = collections.OrderedDict()
- try:
- keys = list(config_obj[section].keys())
- except AttributeError:
- raise InvalidProfileException("Error parsing section '%s' in file '%s'." % (section, file_name))
- for option in keys:
- config[section][option] = config_obj[section][option]
-
dir_name = os.path.dirname(file_name)
- # TODO: Could we do this in the same place as the expansion of other functions?
- for section in config:
- for option in config[section]:
+ for section in list(config_obj.sections()):
+ config[section] = collections.OrderedDict()
+ for option in config_obj.options(section):
+ config[section][option] = config_obj.get(section, option, raw=True)
config[section][option] = self._expand_profile_dir(dir_name, config[section][option])
-
- # TODO: HACK, this needs to be solved in a better way (better config parser)
- for unit_name in config:
- if "script" in config[unit_name] and config[unit_name].get("script", None) is not None:
- script_path = os.path.join(dir_name, config[unit_name]["script"])
- config[unit_name]["script"] = [os.path.normpath(script_path)]
+ if config[section].get("script") is not None:
+ script_path = os.path.join(dir_name, config[section]["script"])
+ config[section]["script"] = [os.path.normpath(script_path)]
return config
diff --git a/tuned/profiles/locator.py b/tuned/profiles/locator.py
index 3fd46916..994bdfb5 100644
--- a/tuned/profiles/locator.py
+++ b/tuned/profiles/locator.py
@@ -1,6 +1,12 @@
import os
import tuned.consts as consts
-from configobj import ConfigObj, ConfigObjError
+try:
+ from configparser import ConfigParser, Error
+ from io import StringIO
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
+ from StringIO import StringIO
class Locator(object):
"""
@@ -48,8 +54,12 @@ def parse_config(self, profile_name):
if config_file is None:
return None
try:
- return ConfigObj(config_file, list_values = False, interpolation = False)
- except (IOError, OSError, ConfigObjError) as e:
+ config = ConfigParser()
+ config.optionxform = str
+ with open(config_file) as f:
+ config.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
+ return config
+ except (IOError, OSError, Error) as e:
return None
# Get profile attributes (e.g. summary, description), attrs is list of requested attributes,
@@ -75,17 +85,16 @@ def get_profile_attrs(self, profile_name, attrs, defvals = None):
config = self.parse_config(profile_name)
if config is None:
return [False, "", "", ""]
- if consts.PLUGIN_MAIN_UNIT_NAME in config:
- d = config[consts.PLUGIN_MAIN_UNIT_NAME]
- else:
- d = dict()
+ main_unit_in_config = consts.PLUGIN_MAIN_UNIT_NAME in config.sections()
vals = [True, profile_name]
for (attr, defval) in zip(attrs, defvals):
if attr == "" or attr is None:
vals[0] = False
vals = vals + [""]
+ elif main_unit_in_config and attr in config.options(consts.PLUGIN_MAIN_UNIT_NAME):
+ vals = vals + [config.get(consts.PLUGIN_MAIN_UNIT_NAME, attr, raw=True)]
else:
- vals = vals + [d.get(attr, defval)]
+ vals = vals + [defval]
return vals
def list_profiles(self):
diff --git a/tuned/profiles/variables.py b/tuned/profiles/variables.py
index 2e101661..a9e27aea 100644
--- a/tuned/profiles/variables.py
+++ b/tuned/profiles/variables.py
@@ -4,7 +4,13 @@
from .functions import functions as functions
import tuned.consts as consts
from tuned.utils.commands import commands
-from configobj import ConfigObj, ConfigObjError
+try:
+ from configparser import ConfigParser, Error
+ from io import StringIO
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
+ from StringIO import StringIO
log = tuned.logs.get()
@@ -40,24 +46,21 @@ def add_variable(self, variable, value):
self._lookup_re[r'(?<!\\)\${' + re.escape(s) + r'}'] = v
self._lookup_env[self._add_env_prefix(s, consts.ENV_PREFIX)] = v
- def add_dict(self, d):
- for item in d:
- self.add_variable(item, d[item])
-
def add_from_file(self, filename):
if not os.path.exists(filename):
log.error("unable to find variables_file: '%s'" % filename)
return
try:
- config = ConfigObj(filename, raise_errors = True, file_error = True, list_values = False, interpolation = False)
- except ConfigObjError:
+ config = ConfigParser()
+ config.optionxform = str
+ with open(filename) as f:
+ config.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
+ except Error:
log.error("error parsing variables_file: '%s'" % filename)
return
- for item in config:
- if isinstance(config[item], dict):
- self.add_dict(config[item])
- else:
- self.add_variable(item, config[item])
+ for s in config.sections():
+ for o in config.options(s):
+ self.add_variable(o, config.get(s, o, raw=True))
def add_from_cfg(self, cfg):
for item in cfg:
diff --git a/tuned/utils/global_config.py b/tuned/utils/global_config.py
index 039dc9a4..f342700f 100644
--- a/tuned/utils/global_config.py
+++ b/tuned/utils/global_config.py
@@ -1,6 +1,11 @@
import tuned.logs
-from configobj import ConfigObj, ConfigObjError
-from validate import Validator
+try:
+ from configparser import ConfigParser, Error
+ from io import StringIO
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
+ from StringIO import StringIO
from tuned.exceptions import TunedException
import tuned.consts as consts
from tuned.utils.commands import commands
@@ -11,31 +16,55 @@
class GlobalConfig():
- global_config_spec = ["dynamic_tuning = boolean(default=%s)" % consts.CFG_DEF_DYNAMIC_TUNING,
- "sleep_interval = integer(default=%s)" % consts.CFG_DEF_SLEEP_INTERVAL,
- "update_interval = integer(default=%s)" % consts.CFG_DEF_UPDATE_INTERVAL,
- "recommend_command = boolean(default=%s)" % consts.CFG_DEF_RECOMMEND_COMMAND]
-
def __init__(self,config_file = consts.GLOBAL_CONFIG_FILE):
self._cfg = {}
self.load_config(file_name=config_file)
self._cmd = commands()
+ @staticmethod
+ def get_global_config_spec():
+ """
+ Easy validation mimicking configobj
+ Returns two dicts, firts with default values (default None)
+ global_default[consts.CFG_SOMETHING] = consts.CFG_DEF_SOMETHING or None
+ second with configobj function for value type (default "get" for string, others eg getboolean, getint)
+ global_function[consts.CFG_SOMETHING] = consts.CFG_FUNC_SOMETHING or get
+ }
+ """
+ options = [opt for opt in dir(consts)
+ if opt.startswith("CFG_") and
+ not opt.startswith("CFG_FUNC_") and
+ not opt.startswith("CFG_DEF_")]
+ global_default = dict((getattr(consts, opt), getattr(consts, "CFG_DEF_" + opt[4:], None)) for opt in options)
+ global_function = dict((getattr(consts, opt), getattr(consts, "CFG_FUNC_" + opt[4:], "get")) for opt in options)
+ return global_default, global_function
+
def load_config(self, file_name = consts.GLOBAL_CONFIG_FILE):
"""
Loads global configuration file.
"""
log.debug("reading and parsing global configuration file '%s'" % file_name)
try:
- self._cfg = ConfigObj(file_name, configspec = self.global_config_spec, raise_errors = True, \
- file_error = True, list_values = False, interpolation = False)
+ config_parser = ConfigParser()
+ config_parser.optionxform = str
+ with open(file_name) as f:
+ config_parser.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
+ self._cfg, _global_config_func = self.get_global_config_spec()
+ for option in config_parser.options(consts.MAGIC_HEADER_NAME):
+ if option in self._cfg:
+ try:
+ func = getattr(config_parser, _global_config_func[option])
+ self._cfg[option] = func(consts.MAGIC_HEADER_NAME, option)
+ except Error:
+ raise TunedException("Global TuneD configuration file '%s' is not valid."
+ % file_name)
+ else:
+ log.info("Unknown option '%s' in global config file '%s'." % (option, file_name))
+ self._cfg[option] = config_parser.get(consts.MAGIC_HEADER_NAME, option, raw=True)
except IOError as e:
raise TunedException("Global TuneD configuration file '%s' not found." % file_name)
- except ConfigObjError as e:
+ except Error as e:
raise TunedException("Error parsing global TuneD configuration file '%s'." % file_name)
- vdt = Validator()
- if (not self._cfg.validate(vdt, copy=True)):
- raise TunedException("Global TuneD configuration file '%s' is not valid." % file_name)
def get(self, key, default = None):
return self._cfg.get(key, default)
diff --git a/tuned/utils/profile_recommender.py b/tuned/utils/profile_recommender.py
index 580465bb..7300277b 100644
--- a/tuned/utils/profile_recommender.py
+++ b/tuned/utils/profile_recommender.py
@@ -3,7 +3,11 @@
import errno
import procfs
import subprocess
-from configobj import ConfigObj, ConfigObjError
+try:
+ from configparser import ConfigParser, Error
+except ImportError:
+ # python2.7 support, remove RHEL-7 support end
+ from ConfigParser import ConfigParser, Error
try:
import syspurpose.files
@@ -59,11 +63,14 @@ def process_config(self, fname, has_root=True):
try:
if not os.path.isfile(fname):
return None
- config = ConfigObj(fname, list_values = False, interpolation = False)
- for section in list(config.keys()):
+ config = ConfigParser()
+ config.optionxform = str
+ with open(fname) as f:
+ config.readfp(f)
+ for section in config.sections():
match = True
- for option in list(config[section].keys()):
- value = config[section][option]
+ for option in config.options(section):
+ value = config.get(section, option, raw=True)
if value == "":
value = r"^$"
if option == "virt":
@@ -117,7 +124,7 @@ def process_config(self, fname, has_root=True):
r = re.compile(r",[^,]*$")
matching_profile = r.sub("", section)
break
- except (IOError, OSError, ConfigObjError) as e:
+ except (IOError, OSError, Error) as e:
log.error("error processing '%s', %s" % (fname, e))
return matching_profile

View File

@ -1,121 +0,0 @@
From 438ff4f899f5eb4bc2ea679fdd2d3611f8e0d8ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
Date: Thu, 15 Jul 2021 20:48:54 +0200
Subject: [PATCH] scheduler: new option cgroup_ps_blacklist
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This option allows skipping processes belonging to the blacklisted
cgroups. It matches the regular expression against items from the
/proc/PID/cgroups. Items/lines from the /proc/PID/cgroups are separated
by commas ','. Each item consists of the:
hierarchy-ID:controller-list:cgroup-path
Example of the content on which the regular expression is run:
10:hugetlb:/,9:perf_event:/,8:blkio:/
For cgroups v2 the hierarchy-ID is 0 and the controller-list is ''.
For details see man cgroups.7. The only difference from the man
cgroups.7 is that it uses commas for separation of the items instead
of the new lines. The commas are added by the python-linux-procfs
(it's the behavior of the python-linux-procfs-0.6.3).
Multiple regular expressions can be separated by the semicolon ';'.
Examples:
[scheduler]
isolated_cores=1
cgroup_ps_blacklist=:/daemons\b
It will move all processes away from the core 1 except processes which
belongs to the cgroup '/daemons'. The '\b' is regular expression
metacharacter that matches word boundary (i.e. it matches only
'/daemons', not e.g. '/daemonset' or '/group/daemons'). In this example
we do not care about the hierarchy-ID and the controller-list.
[scheduler]
isolated_cores=1
cgroup_ps_blacklist=\b8:blkio:/,|$
In this example it skips processes belonging to the cgroup '/',
with hierarchy-ID 8 and controller-list blkio. The ',|$' is needed
because the '\b' matches word boundary and the non-alphanumeric
character '/' is not taken as a word, thus the '\b' will not match there.
[scheduler]
isolated_cores=1
cgroup_ps_blacklist=:/daemons\b;:/test\b
In this example two regular expressions are used which tries to match
'/daemons' and '/test' cgroup-path. If either matches (i.e. the OR operator),
the process is skipped (i.e. not moved away from the core 1).
Resolves: rhbz#1980715
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
---
tuned/plugins/plugin_scheduler.py | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tuned/plugins/plugin_scheduler.py b/tuned/plugins/plugin_scheduler.py
index e2f7ca2..8e77417 100644
--- a/tuned/plugins/plugin_scheduler.py
+++ b/tuned/plugins/plugin_scheduler.py
@@ -156,6 +156,7 @@ class SchedulerPlugin(base.Plugin):
# default is to whitelist all and blacklist none
self._ps_whitelist = ".*"
self._ps_blacklist = ""
+ self._cgroup_ps_blacklist_re = ""
self._cpus = perf.cpu_map()
self._scheduler_storage_key = self._storage_key(
command_name = "scheduler")
@@ -251,6 +252,7 @@ class SchedulerPlugin(base.Plugin):
"cgroup_mount_point_init": False,
"cgroup_groups_init": True,
"cgroup_for_isolated_cores": None,
+ "cgroup_ps_blacklist": None,
"ps_whitelist": None,
"ps_blacklist": None,
"default_irq_smp_affinity": "calc",
@@ -811,6 +813,14 @@ class SchedulerPlugin(base.Plugin):
elif event.type == perf.RECORD_EXIT:
self._remove_pid(instance, int(event.tid))
+ @command_custom("cgroup_ps_blacklist", per_device = False)
+ def _cgroup_ps_blacklist(self, enabling, value, verify, ignore_missing):
+ # currently unsupported
+ if verify:
+ return None
+ if enabling and value is not None:
+ self._cgroup_ps_blacklist_re = "|".join(["(%s)" % v for v in re.split(r"(?<!\\);", str(value))])
+
@command_custom("ps_whitelist", per_device = False)
def _ps_whitelist(self, enabling, value, verify, ignore_missing):
# currently unsupported
@@ -886,6 +896,9 @@ class SchedulerPlugin(base.Plugin):
if self._ps_blacklist != "":
psl = [v for v in psl if re.search(self._ps_blacklist,
self._get_stat_comm(v)) is None]
+ if self._cgroup_ps_blacklist_re != "":
+ psl = [v for v in psl if re.search(self._cgroup_ps_blacklist_re,
+ self._get_stat_cgroup(v)) is None]
psd = dict([(v.pid, v) for v in psl])
for pid in psd:
try:
@@ -911,6 +924,12 @@ class SchedulerPlugin(base.Plugin):
psd[pid]["threads"].values(),
affinity, True)
+ def _get_stat_cgroup(self, o):
+ try:
+ return o["cgroups"]
+ except (OSError, IOError, KeyError):
+ return ""
+
def _get_stat_comm(self, o):
try:
return o["stat"]["comm"]
--
2.31.1

View File

@ -0,0 +1,80 @@
diff --git a/profiles/cpu-partitioning/script.sh b/profiles/cpu-partitioning/script.sh
index ec422ca..cb378b7 100755
--- a/profiles/cpu-partitioning/script.sh
+++ b/profiles/cpu-partitioning/script.sh
@@ -2,6 +2,38 @@
. /usr/lib/tuned/functions
+no_balance_cpus_file=$STORAGE/no-balance-cpus.txt
+
+change_sd_balance_bit()
+{
+ local set_bit=$1
+ local flags_cur=
+ local file=
+ local cpu=
+
+ for cpu in $(cat $no_balance_cpus_file); do
+ for file in $(find /proc/sys/kernel/sched_domain/cpu$cpu -name flags -print); do
+ flags_cur=$(cat $file)
+ if [ $set_bit -eq 1 ]; then
+ flags_cur=$((flags_cur | 0x1))
+ else
+ flags_cur=$((flags_cur & 0xfffe))
+ fi
+ echo $flags_cur > $file
+ done
+ done
+}
+
+disable_balance_domains()
+{
+ change_sd_balance_bit 0
+}
+
+enable_balance_domains()
+{
+ change_sd_balance_bit 1
+}
+
start() {
mkdir -p "${TUNED_tmpdir}/etc/systemd"
mkdir -p "${TUNED_tmpdir}/usr/lib/dracut/hooks/pre-udev"
@@ -9,6 +41,9 @@ start() {
cp 00-tuned-pre-udev.sh "${TUNED_tmpdir}/usr/lib/dracut/hooks/pre-udev/"
setup_kvm_mod_low_latency
disable_ksm
+
+ echo "$TUNED_no_balance_cores_expanded" | sed 's/,/ /g' > $no_balance_cpus_file
+ disable_balance_domains
return "$?"
}
@@ -18,6 +53,7 @@ stop() {
teardown_kvm_mod_low_latency
enable_ksm
fi
+ enable_balance_domains
return "$?"
}
diff --git a/profiles/cpu-partitioning/tuned.conf b/profiles/cpu-partitioning/tuned.conf
index 11f03cf..a682c9c 100644
--- a/profiles/cpu-partitioning/tuned.conf
+++ b/profiles/cpu-partitioning/tuned.conf
@@ -35,8 +35,6 @@ no_balance_cores_expanded=${f:cpulist_unpack:${no_balance_cores}}
# Fail if isolated_cores contains CPUs which are not online
assert2=${f:assertion:isolated_cores contains online CPU(s):${isolated_cores_expanded}:${isolated_cores_online_expanded}}
-cmd_isolcpus=${f:regex_search_ternary:${no_balance_cores}:\s*[0-9]: isolcpus=${no_balance_cores}:}
-
[sysfs]
/sys/bus/workqueue/devices/writeback/cpumask = ${not_isolated_cpumask}
/sys/devices/virtual/workqueue/cpumask = ${not_isolated_cpumask}
@@ -62,4 +60,4 @@ priority=10
initrd_remove_dir=True
initrd_dst_img=tuned-initrd.img
initrd_add_dir=${tmpdir}
-cmdline_cpu_part=+nohz=on${cmd_isolcpus} nohz_full=${isolated_cores} rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} intel_pstate=disable nosoftlockup
+cmdline_cpu_part=+nohz=on nohz_full=${isolated_cores} rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} intel_pstate=disable nosoftlockup

View File

@ -0,0 +1,118 @@
diff --git a/tuned/consts.py b/tuned/consts.py
index 3749363..3b41ed9 100644
--- a/tuned/consts.py
+++ b/tuned/consts.py
@@ -1,4 +1,8 @@
import logging
+import string
+
+NAMES_ALLOWED_CHARS = string.ascii_letters + string.digits + " !@'+-.,/:;_$&*()%<=>?#[]{|}^~" + '"'
+NAMES_MAX_LENGTH = 4096
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py
index 6a59a1d..94e9022 100644
--- a/tuned/daemon/controller.py
+++ b/tuned/daemon/controller.py
@@ -182,6 +182,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
def switch_profile(self, profile_name, caller = None):
if caller == "":
return (False, "Unauthorized")
+ if not self._cmd.is_valid_name(profile_name):
+ return (False, "Invalid profile_name")
return self._switch_profile(profile_name, True)
@exports.export("", "(bs)")
@@ -255,8 +257,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
@exports.export("s", "(bsss)")
def profile_info(self, profile_name, caller = None):
- if caller == "":
- return tuple(False, "", "", "")
+ if caller == "" or not self._cmd.is_valid_name(profile_name):
+ return (False, "", "", "")
if profile_name is None or profile_name == "":
profile_name = self.active_profile()
return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""]))
@@ -287,7 +289,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
dictionary -- {plugin_name: {parameter_name: default_value}}
"""
if caller == "":
- return False
+ return {}
plugins = {}
for plugin_class in self._daemon.get_all_plugins():
plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1]
@@ -300,8 +302,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
@exports.export("s","s")
def get_plugin_documentation(self, plugin_name, caller = None):
"""Return docstring of plugin's class"""
- if caller == "":
- return False
+ if caller == "" or not self._cmd.is_valid_name(plugin_name):
+ return ""
return self._daemon.get_plugin_documentation(str(plugin_name))
@exports.export("s","a{ss}")
@@ -314,8 +316,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
Return:
dictionary -- {parameter_name: hint}
"""
- if caller == "":
- return False
+ if caller == "" or not self._cmd.is_valid_name(plugin_name):
+ return {}
return self._daemon.get_plugin_hints(str(plugin_name))
@exports.export("s", "b")
@@ -328,7 +330,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
Return:
bool -- True on success
"""
- if caller == "":
+ if caller == "" or not self._cmd.is_valid_name(path):
return False
if self._daemon._application and self._daemon._application._unix_socket_exporter:
self._daemon._application._unix_socket_exporter.register_signal_path(path)
@@ -342,6 +344,10 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
def instance_acquire_devices(self, devices, instance_name, caller = None):
if caller == "":
return (False, "Unauthorized")
+ if not self._cmd.is_valid_name(devices):
+ return (False, "Invalid devices")
+ if not self._cmd.is_valid_name(instance_name):
+ return (False, "Invalid instance_name")
found = False
for instance_target in self._daemon._unit_manager.instances:
if instance_target.name == instance_name:
@@ -388,6 +394,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
"""
if caller == "":
return (False, "Unauthorized", [])
+ if not self._cmd.is_valid_name(plugin_name):
+ return (False, "Invalid plugin_name", [])
if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
rets = "Plugin '%s' does not exist" % plugin_name
log.error(rets)
@@ -411,6 +419,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
"""
if caller == "":
return (False, "Unauthorized", [])
+ if not self._cmd.is_valid_name(instance_name):
+ return (False, "Invalid instance_name", [])
for instance in self._daemon._unit_manager.instances:
if instance.name == instance_name:
return (True, "OK", sorted(list(instance.processed_devices)))
diff --git a/tuned/utils/commands.py b/tuned/utils/commands.py
index ce51fc0..38d95ef 100644
--- a/tuned/utils/commands.py
+++ b/tuned/utils/commands.py
@@ -544,3 +544,7 @@ class commands:
import string
trans = string.maketrans(source_chars, dest_chars)
return text.translate(trans)
+
+ # Checks if name contains only valid characters and has valid length or is empty string or None
+ def is_valid_name(self, name):
+ return not name or (all(c in consts.NAMES_ALLOWED_CHARS for c in name) and len(name) <= consts.NAMES_MAX_LENGTH)

View File

@ -0,0 +1,88 @@
diff --git a/profiles/latency-performance/tuned.conf b/profiles/latency-performance/tuned.conf
index 1dec690..e592138 100644
--- a/profiles/latency-performance/tuned.conf
+++ b/profiles/latency-performance/tuned.conf
@@ -35,3 +35,17 @@ vm.dirty_background_ratio=3
# 100 tells the kernel to aggressively swap processes out of physical memory
# and move them to swap cache
vm.swappiness=10
+
+[scheduler]
+runtime=0
+# ktune sysctl settings for rhel6 servers, maximizing i/o throughput
+#
+# Minimal preemption granularity for CPU-bound tasks:
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
+sched_min_granularity_ns = 3000000
+sched_wakeup_granularity_ns = 4000000
+
+# The total time the scheduler will consider a migrated process
+# "cache hot" and thus less likely to be re-migrated
+# (system default is 500000, i.e. 0.5 ms)
+sched_migration_cost_ns = 5000000
diff --git a/profiles/sap-hana/tuned.conf b/profiles/sap-hana/tuned.conf
index aeecf53..1b15ea3 100644
--- a/profiles/sap-hana/tuned.conf
+++ b/profiles/sap-hana/tuned.conf
@@ -20,3 +20,8 @@ kernel.numa_balancing = 0
vm.dirty_ratio = 40
vm.dirty_background_ratio = 10
vm.swappiness = 10
+
+[scheduler]
+runtime=0
+sched_min_granularity_ns = 3000000
+sched_wakeup_granularity_ns = 4000000
diff --git a/profiles/throughput-performance/tuned.conf b/profiles/throughput-performance/tuned.conf
index e4e832f..3d9c42f 100644
--- a/profiles/throughput-performance/tuned.conf
+++ b/profiles/throughput-performance/tuned.conf
@@ -67,9 +67,33 @@ vm.swappiness=10
# on older kernels
net.core.somaxconn=>2048
+[scheduler]
+runtime=0
+# ktune sysctl settings for rhel6 servers, maximizing i/o throughput
+#
+# Minimal preemption granularity for CPU-bound tasks:
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
+sched_min_granularity_ns = 10000000
+
+# SCHED_OTHER wake-up granularity.
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
+#
+# This option delays the preemption effects of decoupled workloads
+# and reduces their over-scheduling. Synchronous workloads will still
+# have immediate wakeup/sleep latencies.
+sched_wakeup_granularity_ns = 15000000
+
# Marvell ThunderX
[sysctl.thunderx]
type=sysctl
uname_regex=aarch64
cpuinfo_regex=${thunderx_cpuinfo_regex}
kernel.numa_balancing=0
+
+# AMD
+[scheduler.amd]
+type=scheduler
+uname_regex=x86_64
+cpuinfo_regex=${amd_cpuinfo_regex}
+runtime=0
+sched_migration_cost_ns=5000000
diff --git a/profiles/virtual-host/tuned.conf b/profiles/virtual-host/tuned.conf
index 5301d9f..24d0fb4 100644
--- a/profiles/virtual-host/tuned.conf
+++ b/profiles/virtual-host/tuned.conf
@@ -14,3 +14,10 @@ vm.dirty_background_ratio = 5
[cpu]
# Setting C3 state sleep mode/power savings
force_latency=cstate.id_no_zero:3|70
+
+[scheduler]
+runtime=0
+# The total time the scheduler will consider a migrated process
+# "cache hot" and thus less likely to be re-migrated
+# (system default is 500000, i.e. 0.5 ms)
+sched_migration_cost_ns = 5000000

View File

@ -0,0 +1,11 @@
diff --git a/profiles/postgresql/tuned.conf b/profiles/postgresql/tuned.conf
index 88da8e4..4fd3810 100644
--- a/profiles/postgresql/tuned.conf
+++ b/profiles/postgresql/tuned.conf
@@ -55,3 +55,6 @@ sched_min_granularity_ns = 10000000
# "cache hot" and thus less likely to be re-migrated
# (system default is 500000, i.e. 0.5 ms)
sched_migration_cost_ns = 50000000
+
+[scheduler.amd]
+enabled=false

View File

@ -0,0 +1,54 @@
From 7557cf975282326cdbfe55b7b803d8075ff37cba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
Date: Tue, 12 Mar 2024 20:25:43 +0100
Subject: [PATCH] epyc-eda: added new profile for EDA compute workloads on AMD
EPYC CPUs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
---
man/tuned-profiles.7 | 4 ++++
profiles/epyc-eda/tuned.conf | 14 ++++++++++++++
2 files changed, 18 insertions(+)
create mode 100644 profiles/epyc-eda/tuned.conf
diff --git a/man/tuned-profiles.7 b/man/tuned-profiles.7
index 10cad7b..600e8bb 100644
--- a/man/tuned-profiles.7
+++ b/man/tuned-profiles.7
@@ -141,6 +141,10 @@ profiles (e.g. throughput\-performance profile), example:
Profile optimized for AWS EC2 instances. It is based on the
throughput\-performance profile.
+.TP
+.BI "epyc-eda"
+Profile optimized for EDA compute workloads on AMD EPYC CPUs.
+
.SH "FILES"
.nf
.I /etc/tuned/*
diff --git a/profiles/epyc-eda/tuned.conf b/profiles/epyc-eda/tuned.conf
new file mode 100644
index 0000000..482d404
--- /dev/null
+++ b/profiles/epyc-eda/tuned.conf
@@ -0,0 +1,14 @@
+#
+# tuned configuration
+#
+
+[main]
+summary=Optimize for EDA compute workloads on AMD EPYC CPUs
+description=Configures virtual memory, CPU governors, and network settings for EDA compute workloads.
+include=throughput-performance
+
+# AMD
+[scheduler.amd]
+type=scheduler
+#Allow processes to rapidly move between cores to avoid idle time and maximize CPU usage
+sched_migration_cost_ns=10000
--
2.44.0

View File

@ -0,0 +1,28 @@
From 04ead944fdf640ed986331179e533542efc934c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
Date: Mon, 8 Apr 2024 11:03:47 +0200
Subject: [PATCH] sap-netweaver: increased vm.max_map_count
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Resolves: RHEL-31757
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
---
profiles/sap-netweaver/tuned.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/profiles/sap-netweaver/tuned.conf b/profiles/sap-netweaver/tuned.conf
index a1cfd17..81c4d44 100644
--- a/profiles/sap-netweaver/tuned.conf
+++ b/profiles/sap-netweaver/tuned.conf
@@ -10,4 +10,4 @@ include=throughput-performance
kernel.sem = 32000 1024000000 500 32000
kernel.shmall = 18446744073692774399
kernel.shmmax = 18446744073692774399
-vm.max_map_count = 2000000
+vm.max_map_count = 2147483647
--
2.44.0

View File

@ -0,0 +1,97 @@
diff --git a/tuned/plugins/plugin_disk.py b/tuned/plugins/plugin_disk.py
index 1438e35..d6feb06 100644
--- a/tuned/plugins/plugin_disk.py
+++ b/tuned/plugins/plugin_disk.py
@@ -100,19 +100,20 @@ class DiskPlugin(hotplug.Plugin):
self._devices_supported = True
self._use_hdparm = True
self._free_devices = set()
- self._hdparm_apm_devices = set()
+ self._hdparm_apm_device_support = dict()
for device in self._hardware_inventory.get_devices("block"):
if self._device_is_supported(device):
self._free_devices.add(device.sys_name)
- if self._use_hdparm and self._is_hdparm_apm_supported(device.sys_name):
- self._hdparm_apm_devices.add(device.sys_name)
-
self._assigned_devices = set()
def _get_device_objects(self, devices):
return [self._hardware_inventory.get_device("block", x) for x in devices]
def _is_hdparm_apm_supported(self, device):
+ if not self._use_hdparm:
+ return False
+ if device in self._hdparm_apm_device_support:
+ return self._hdparm_apm_device_support[device]
(rc, out, err_msg) = self._cmd.execute(["hdparm", "-C", "/dev/%s" % device], \
no_errors = [errno.ENOENT], return_err=True)
if rc == -errno.ENOENT:
@@ -122,10 +123,13 @@ class DiskPlugin(hotplug.Plugin):
elif rc:
log.info("Device '%s' not supported by hdparm" % device)
log.debug("(rc: %s, msg: '%s')" % (rc, err_msg))
+ self._hdparm_apm_device_support[device] = False
return False
elif "unknown" in out:
log.info("Driver for device '%s' does not support apm command" % device)
+ self._hdparm_apm_device_support[device] = False
return False
+ self._hdparm_apm_device_support[device] = True
return True
@classmethod
@@ -232,7 +236,7 @@ class DiskPlugin(hotplug.Plugin):
return not "standby" in out and not "sleeping" in out
def _instance_update_dynamic(self, instance, device):
- if not device in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
return
load = instance._load_monitor.get_device_load(device)
if load is None:
@@ -315,7 +319,7 @@ class DiskPlugin(hotplug.Plugin):
# At the moment we support dynamic tuning just for devices compatible with hdparm apm commands
# If in future will be added new functionality not connected to this command,
# it is needed to change it here
- if device not in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
log.info("There is no dynamic tuning available for device '%s' at time" % device)
else:
super(DiskPlugin, self)._instance_apply_dynamic(instance, device)
@@ -350,7 +354,7 @@ class DiskPlugin(hotplug.Plugin):
@command_set("apm", per_device=True)
def _set_apm(self, value, device, sim, remove):
- if device not in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
if not sim:
log.info("apm option is not supported for device '%s'" % device)
return None
@@ -366,7 +370,7 @@ class DiskPlugin(hotplug.Plugin):
@command_get("apm")
def _get_apm(self, device, ignore_missing=False):
- if device not in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
if not ignore_missing:
log.info("apm option is not supported for device '%s'" % device)
return None
@@ -390,7 +394,7 @@ class DiskPlugin(hotplug.Plugin):
@command_set("spindown", per_device=True)
def _set_spindown(self, value, device, sim, remove):
- if device not in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
if not sim:
log.info("spindown option is not supported for device '%s'" % device)
return None
@@ -406,7 +410,7 @@ class DiskPlugin(hotplug.Plugin):
@command_get("spindown")
def _get_spindown(self, device, ignore_missing=False):
- if device not in self._hdparm_apm_devices:
+ if not self._is_hdparm_apm_supported(device):
if not ignore_missing:
log.info("spindown option is not supported for device '%s'" % device)
return None

View File

@ -34,28 +34,23 @@
Summary: A dynamic adaptive system tuning daemon
Name: tuned
Version: 2.16.0
Release: 3%{?prerel1}%{?dist}
Version: 2.22.1
Release: 6%{?prerel1}%{?dist}
License: GPLv2+
Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
# RHEL-9 specific recommend.conf:
# RHEL-8 specific recommend.conf:
Source1: recommend.conf
URL: http://www.tuned-project.org/
BuildArch: noarch
BuildRequires: systemd, desktop-file-utils
%if 0%{?rhel}
BuildRequires: asciidoc
%else
BuildRequires: asciidoctor
%endif
Requires(post): systemd, virt-what
Requires(preun): systemd
Requires(postun): systemd
BuildRequires: make
BuildRequires: %{_py}, %{_py}-devel
# BuildRequires for 'make test'
# python-mock is needed for python-2.7, but it's not available on RHEL-7
%if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 )
# python-mock is needed for python-2.7, but it's not available on RHEL-7, only in the EPEL
%if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 || 0%{?epel})
BuildRequires: %{_py}-mock
%endif
BuildRequires: %{_py}-pyudev
@ -81,22 +76,36 @@ Requires: virt-what, ethtool, gawk
Requires: util-linux, dbus, polkit
%if 0%{?fedora} > 22 || 0%{?rhel} > 7
Recommends: dmidecode
Recommends: hdparm
# i686 excluded
Recommends: kernel-tools
Recommends: kmod
Requires: hdparm
Requires: kmod
Requires: iproute
%endif
# syspurpose
%if 0%{?rhel} > 8
Requires: subscription-manager
# not on CentOS
%if 0%{!?centos:1}
Recommends: subscription-manager
%endif
%else
%if 0%{?rhel} > 7
Requires: python3-syspurpose
%endif
%endif
# rhbz#1980715
Patch0: tuned-2.16.0-scheduler-cgroups-exclude.patch
# rhbz#1936386
Patch1: tuned-2.16.0-configobj-drop.patch
# Revert upstream profiles changes which have not been approved for RHEL-8 (yet)
Patch0: tuned-2.22.0-rhel-8-profiles.patch
# Revert no balancing cores to use SD_LOAD_BALANCE (see rhbz#1874596 for details)
Patch1: tuned-2.21.0-sd-load-balance.patch
# epyc-eda TuneD profile only for RHEL-8 (see RHEL-27528 for details)
Patch2: tuned-2.22.1-profile-epyc-eda.patch
# Update vm.max_map_count in the sap-netweaver profile (see RHEL-32124 for details)
Patch3: tuned-2.22.1-sap-vm-max-map-count.patch
Patch4: tuned-2.21.1-CVE-2024-52337.patch
# Make hdparm device checks lazy (see RHEL-71457 for details)
Patch5: tuned-2.22.1-use-hdparm-lazily.patch
# Disable the amd.scheduler plug-in instance in the postgresql profile (see RHEL-70470 for details)
Patch6: tuned-2.22.1-postgresql-disable-amd-instance.patch
%description
The tuned package contains a daemon that tunes system settings dynamically.
@ -205,7 +214,6 @@ Summary: Additional tuned profile(s) targeted to Network Function Virtualization
Requires: %{name} = %{version}
Requires: %{name}-profiles-realtime = %{version}
Requires: tuna
Requires: nmap-ncat
%description profiles-nfv-host
Additional tuned profile(s) targeted to Network Function Virtualization (NFV) host.
@ -249,10 +257,28 @@ Requires: %{name} = %{version}
%description profiles-postgresql
Additional tuned profile(s) targeted to PostgreSQL server loads.
%package profiles-openshift
Summary: Additional TuneD profile(s) optimized for OpenShift
Requires: %{name} = %{version}
%description profiles-openshift
Additional TuneD profile(s) optimized for OpenShift.
%package ppd
Summary: PPD compatibility daemon
Requires: %{name} = %{version}
# The compatibility daemon is swappable for power-profiles-daemon
Provides: ppd-service
Conflicts: ppd-service
%description ppd
An API translation daemon that allows applications to easily transition
to TuneD from power-profiles-daemon (PPD).
%prep
%autosetup -p1 -n %{name}-%{version}%{?prerel2}
# Replace the upstream recommend.conf with a RHEL-9-specific one
# Replace the upstream recommend.conf with a RHEL-8-specific one
rm -f recommend.conf
cp -p %{SOURCE1} recommend.conf
@ -265,9 +291,7 @@ make html %{make_python_arg}
%install
make install DESTDIR=%{buildroot} DOCDIR=%{docdir} %{make_python_arg}
%if 0%{?rhel}
sed -i 's/\(dynamic_tuning[ \t]*=[ \t]*\).*/\10/' %{buildroot}%{_sysconfdir}/tuned/tuned-main.conf
%endif
make install-ppd DESTDIR=%{buildroot} DOCDIR=%{docdir} %{make_python_arg}
%if ! 0%{?rhel}
# manual
@ -290,10 +314,9 @@ touch %{buildroot}%{_sysconfdir}/modprobe.d/kvm.rt.tuned.conf
# validate desktop file
desktop-file-validate %{buildroot}%{_datadir}/applications/tuned-gui.desktop
# Run tests on RHEL > 7 or non RHEL
# We cannot run tests on RHEL-7 because there is no python-mock package and
# On RHEL-7 EPEL is needed, because there is no python-mock package and
# python-2.7 doesn't have mock built-in
%if 0%{?rhel} > 7 || ! 0%{?rhel}
%if 0%{?rhel} >= 8 || 0%{?epel} || ! 0%{?rhel}
%check
make test %{make_python_arg}
%endif
@ -395,6 +418,7 @@ fi
%exclude %{_sysconfdir}/tuned/realtime-virtual-guest-variables.conf
%exclude %{_sysconfdir}/tuned/realtime-virtual-host-variables.conf
%exclude %{_sysconfdir}/tuned/cpu-partitioning-variables.conf
%exclude %{_sysconfdir}/tuned/cpu-partitioning-powersave-variables.conf
%exclude %{_prefix}/lib/tuned/default
%exclude %{_prefix}/lib/tuned/desktop-powersave
%exclude %{_prefix}/lib/tuned/laptop-ac-powersave
@ -404,6 +428,7 @@ fi
%exclude %{_prefix}/lib/tuned/spindown-disk
%exclude %{_prefix}/lib/tuned/sap-netweaver
%exclude %{_prefix}/lib/tuned/sap-hana
%exclude %{_prefix}/lib/tuned/sap-hana-kvm-guest
%exclude %{_prefix}/lib/tuned/mssql
%exclude %{_prefix}/lib/tuned/oracle
%exclude %{_prefix}/lib/tuned/atomic-host
@ -412,8 +437,12 @@ fi
%exclude %{_prefix}/lib/tuned/realtime-virtual-guest
%exclude %{_prefix}/lib/tuned/realtime-virtual-host
%exclude %{_prefix}/lib/tuned/cpu-partitioning
%exclude %{_prefix}/lib/tuned/cpu-partitioning-powersave
%exclude %{_prefix}/lib/tuned/spectrumscale-ece
%exclude %{_prefix}/lib/tuned/postgresql
%exclude %{_prefix}/lib/tuned/openshift
%exclude %{_prefix}/lib/tuned/openshift-control-plane
%exclude %{_prefix}/lib/tuned/openshift-node
%{_prefix}/lib/tuned
%dir %{_sysconfdir}/tuned
%dir %{_sysconfdir}/tuned/recommend.d
@ -424,7 +453,6 @@ fi
%config(noreplace) %verify(not size mtime md5) %{_sysconfdir}/tuned/post_loaded_profile
%config(noreplace) %{_sysconfdir}/tuned/tuned-main.conf
%config(noreplace) %verify(not size mtime md5) %{_sysconfdir}/tuned/bootcmdline
%{_sysconfdir}/dbus-1/system.d/com.redhat.tuned.conf
%verify(not size mtime md5) %{_sysconfdir}/modprobe.d/tuned.conf
%{_tmpfilesdir}/tuned.conf
%{_unitdir}/tuned.service
@ -436,6 +464,7 @@ fi
%{_mandir}/man8/tuned*
%dir %{_datadir}/tuned
%{_datadir}/tuned/grub2
%{_datadir}/dbus-1/system.d/com.redhat.tuned.conf
%{_datadir}/polkit-1/actions/com.redhat.tuned.policy
%ghost %{_sysconfdir}/modprobe.d/kvm.rt.tuned.conf
%{_prefix}/lib/kernel/install.d/92-tuned.install
@ -475,6 +504,7 @@ fi
%files profiles-sap-hana
%{_prefix}/lib/tuned/sap-hana
%{_prefix}/lib/tuned/sap-hana-kvm-guest
%{_mandir}/man7/tuned-profiles-sap-hana.7*
%files profiles-mssql
@ -510,7 +540,9 @@ fi
%files profiles-cpu-partitioning
%config(noreplace) %{_sysconfdir}/tuned/cpu-partitioning-variables.conf
%config(noreplace) %{_sysconfdir}/tuned/cpu-partitioning-powersave-variables.conf
%{_prefix}/lib/tuned/cpu-partitioning
%{_prefix}/lib/tuned/cpu-partitioning-powersave
%{_mandir}/man7/tuned-profiles-cpu-partitioning.7*
%files profiles-spectrumscale
@ -531,50 +563,213 @@ fi
%{_prefix}/lib/tuned/postgresql
%{_mandir}/man7/tuned-profiles-postgresql.7*
%changelog
* Wed Aug 18 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.16.0-3
- scheduler: allow exclude of processes from the specific cgroup(s)
Resolves: rhbz#1980715
- Switched to the configparser from the configobj
Resolves: rhbz#1936386
%files profiles-openshift
%{_prefix}/lib/tuned/openshift
%{_prefix}/lib/tuned/openshift-control-plane
%{_prefix}/lib/tuned/openshift-node
%{_mandir}/man7/tuned-profiles-openshift.7*
* Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 2.16.0-2
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
%files ppd
%{_sbindir}/tuned-ppd
%{_unitdir}/tuned-ppd.service
%{_datadir}/dbus-1/system-services/net.hadess.PowerProfiles.service
%{_datadir}/dbus-1/system.d/net.hadess.PowerProfiles.conf
%{_datadir}/polkit-1/actions/net.hadess.PowerProfiles.policy
%config(noreplace) %{_sysconfdir}/tuned/ppd.conf
%changelog
* Mon Jan 06 2025 Pavol Žáčik <pzacik@redhat.com> - 2.22.1-6
- Make hdparm device checks lazy
Resolves: RHEL-71457
- Disable the amd.scheduler plug-in instance in the postgresql profile
Resolves: RHEL-70470
* Mon Nov 18 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.1-5
- Added sanity checks for API methods parameters, (CVE-2024-52337)
Resolves: RHEL-66614
* Fri May 3 2024 Pavol Žáčik <pzacik@redhat.com> - 2.22.1-4.1
- sap-netweaver: increase vm.max_map_count
resolves: RHEL-32124
* Wed Mar 13 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.1-4
- release bump due to broken c8s
related: RHEL-27528
* Wed Mar 13 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.1-3
- release bump
related: RHEL-27528
* Tue Mar 12 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.1-2
- profiles: added epyc-eda profile
resolves: RHEL-27528
* Thu Feb 22 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.1-1
- new release
- rebased tuned to latest upstream
related: RHEL-17119
- renamed intel_uncore plugin to uncore
- network-throughput: increased net.ipv4.tcp_rmem default value
* Fri Feb 16 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.0-1
- new release
- rebased tuned to latest upstream
related: RHEL-17119
- lower CPU usage by using runtime=0 in profiles using scheduler plugin
resolves: RHEL-6869
* Fri Feb 9 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.22.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: RHEL-17119
- print all arguments of failing commands in error messages
- plugin_sysctl: added support for sysctl names with slash
- tuned-adm: added support for moving devices between plugin instances
- api: added methods for retrieval of plugin instances and devices
- plugin_cpu: amd-pstate mentioned instead of just intel_pstate
- hotplug: do not report ENOENT errors on device remove
- plugin_sysctl: expand variables when reporting overrides
- plugin_acpi: new plugin which handles ACPI platform_profile
- plugin_bootloader: skip calling rpm-ostree kargs in no-op case
- plugin_cpu: support cstate settings of pm_qos_resume_latency_us
- scheduler: add option for ignoring IRQs affinity
- plugin_intel_uncore: new plugin for uncore setting
* Tue Aug 29 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.21.0-1
- new release
- api: fixed stop method not to require any parameter
resolves: rhbz#2235638
* Sun Aug 20 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.21.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#2182119
- sap-hana: new profile sap-hana-kvm-guest
resolves: rhbz#2173740
- serialized SIGHUP handler to prevent possible bootcmdline corruption
resolves: rhbz#2215298
* Fri Feb 17 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.20.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#2133814
* Wed Feb 15 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.20.0-0.2.rc1
- post RC.1 fixes
related: rhbz#2133814
- fixed possible traceback on SIGHUP
* Wed Feb 8 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.20.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#2133814
- systemd: relax polkit requirement
resolves: rhbz#2065591
- sysvinit: fixed path
- plugin_cpu: added support for pm_qos_resume_latency_us
- do not exit on duplicate config lines
resolves: rhbz#2071418
- profiles: new cpu-partitioning-powersave profile
- profiles: new profile for AWS EC2
- API: add support for moving devices between instances
- D-Bus: send tracebacks through D-Bus only in debug mode
- Makefile: added fix for python-3.12
- throughput-performance: set net.core.somaxconn to at least 2048
resolves: rhbz#1998310
- plugin_scheduler: do not leak FDs from the perf
resolves: rhbz#2080227
- plugin_cpu: added support for intel_pstate scaling driver
- added support for the API access through the Unix Domain Socket
* Fri Aug 19 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.19.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#2057602
* Tue Aug 9 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.19.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#2057602
- fixed parsing of inline comments
resolves: rhbz#2060138
- added support for quotes in isolated_cores specification
resolves: rhbz#1891036
- recommend: preset balanced profile for notebook, laptop or portable if
syspurpose is not defined
resolves: rhbz#1896717
* Wed Jun 8 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.18.0-3
- bootloader: do not hardcode device to initrd
resolves: rhbz#2050246
* Thu Feb 10 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.18.0-2
- openshift/atomic: increased nf_conntrack_hashsize
resolves: rhbz#2052886
* Wed Feb 9 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.18.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#2003833
- tuned-gui: fixed creation of new profile
* Wed Feb 2 2022 Jaroslav Škarvada <jskarvad@redhat.com> - 2.18.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#2003833
- profiles: fix improper parsing of include directive
resolves: rhbz#2017924
- disk: added support for the nvme
resolves: rhbz#1854816
- cpu: extended cstate force_latency syntax to allow skipping zero latency
resolves: rhbz#2002744
- net: added support for the txqueuelen
resolves: rhbz#2015044
- bootloader: on s390(x) remove TuneD variables from the BLS
resolves: rhbz#1978786
- daemon: don't do full rollback on systemd failure
resolves: rhbz#2011459
* Wed Jul 21 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.16.0-1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1944643
- realtime: disabled kvm.nx_huge_page kernel module option in
realtime-virtual-host profile
resolves: rhbz#1976825
- realtime: explicitly set 'irqaffinity=~<isolated_cpu_mask>' in kernel
command line
resolves: rhbz#1974820
- scheduler: added abstraction for the sched_* and numa_* variables which
were previously accessible through the sysctl
resolves: rhbz#1952687
- recommend: fixed wrong profile on ppc64le bare metal servers
resolves: rhbz#1959889
related: rhbz#1936426
* Thu May 27 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.15.0-6
- Dropped python-schedutils
Resolves: rhbz#1964680
* Wed Jul 7 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.16.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1936426
- realtime: "isolate_managed_irq=Y" should be mentioned in
"/etc/tuned/realtime-virtual-*-variables.conf"
resolves: rhbz#1817827
- realtime: changed tuned default to "isolcpus=domain,managed_irq,X-Y"
resolves: rhbz#1820626
- applying a profile with multiple inheritance where parents include a common
ancestor fails
resolves: rhbz#1825882
- failure in moving i40e IRQ threads to housekeeping CPUs from isolated CPUs
resolves: rhbz#1933069
- sort network devices before matching by regex
resolves: rhbz#1939970
- net: fixed traceback while adjusting the netdev queue count
resolves: rhbz#1943291
- net: fixed traceback if the first listed device returns netlink error
resolves: rhbz#1944686
- realtime: improve verification
resolves: rhbz#1947858
- bootloader: add support for the rpm-ostree
resolves: rhbz#1950164
- net: fixed traceback if a device channel contains n/a
resolves: rhbz#1974071
- mssql: updated the profile
resolves: rhbz#1942733
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 2.15.0-5
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Wed Apr 21 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.15.0-3
- updated mssql profile
resolves: rhbz#1942733
* Mon Apr 12 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.15.0-4
- updated syspurpose requirement for RHEL-9
resolves: rhbz#1948764
* Mon Feb 08 2021 Jan Zerdik <jzerdik@redhat.com> - 2.15.0-3
- used RHEL recommend.conf
resolves: rhbz#1921016
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.15.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Fri Feb 19 2021 Jaroslav Škarvada <jskarvad@redhat.com> - 2.15.0-2
- realtime: added support for netdev_queue_count and extended plugin_net
resolves: rhbz#1951992
* Thu Dec 17 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.15.0-1
- new release
@ -598,16 +793,20 @@ fi
- bootloader: fixed cmdline duplication with BLS and grub2-mkconfig
resolves: rhbz#1777874
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.14.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Thu Oct 1 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-4
- realtime-virtual-host: remove lapic advancement calculation and
related qemu-kvm-tools-rhev requirement
Resolves: rhbz#1845717
* Fri Jul 3 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-2
* Fri Jul 3 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-3
- scheduler: fixed isolated_cores to work with cgroups
related: rhbz#1784648
* Tue Jun 30 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-2
- throughput-performance: fix performance regression on AMD platforms
related: rhbz#1746957
* Mon Jun 22 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-1
* Mon Jun 15 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.14.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#1792264
@ -635,14 +834,25 @@ fi
- scheduler: added support for cgroups
resolves: rhbz#1784648
* Tue May 26 2020 Miro Hrončok <mhroncok@redhat.com> - 2.13.0-4
- Rebuilt for Python 3.9
* Mon Mar 23 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-6
- realtime: added conditional support for managed_irq
Resolves: rhbz#1797025
* Mon Apr 06 2020 Miro Hrončok <mhroncok@redhat.com> - 2.13.0-3
- Build without unittest2
* Wed Feb 12 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-5
- profiles: renamed sst profile to intel-sst
related: rhbz#1743879
* Fri Jan 31 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.13.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Fri Feb 07 2020 Ondřej Lysoněk <olysonek@redhat.com> - 2.13.0-4
- Add accelerator-performance profile
- Resolves: rhbz#1795604
* Tue Jan 14 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-3
- tuned-profiles-nfv-host: added ncat requirement
resolves: rhbz#1779117
* Tue Jan 7 2020 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-2
- profiles: define variables before use
resolves: rhbz#1788102
* Wed Dec 11 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-1
- new release
@ -652,8 +862,6 @@ fi
resolves: rhbz#1779821
- latency-performance: updated tuning
resolves: rhbz#1779759
- added sst profile
resolves: rhbz#1743879
* Sun Dec 1 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.13.0-0.1.rc1
- new release
@ -674,19 +882,18 @@ fi
- realtime: added nowatchdog kernel command line option
resolves: rhbz#1767614
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 2.12.0-4
- Rebuilt for Python 3.8.0rc1 (#1748018)
* Fri Aug 16 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.12.0-3
- used C-states in latency specification
related: rhbz#1737628
* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 2.12.0-3
- Rebuilt for Python 3.8
* Sat Jul 27 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.12.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Fri Aug 16 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.12.0-2
- plugin_cpu: latency can be now specified as C-state
resolves: rhbz#1737628
* Thu Jun 27 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.12.0-1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1685585
related: rhbz#1685585
* Wed Jun 12 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.12.0-0.1.rc1
- new release
@ -711,78 +918,59 @@ fi
- fixed handling of devices that have been removed and re-attached
resolves: rhbz#1677730
* Thu Mar 21 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.11.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#1643654
- used dmidecode only on x86 architectures
resolves: rhbz#1688371
- recommend: fixed to work without tuned daemon running
resolves: rhbz#1687397
- powertop2tuned: added support for wakeup tuning (powertop-2.10)
resolves: rhbz#1690354
* Sun Mar 10 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.11.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1643654
- use online CPUs for cpusets calculations instead of present CPUs
resolves: rhbz#1613478
- realtime-virtual-guest: run script.sh
related: rhbz#1616043
- make python-dmidecode a weak dependency
resolves: rhbz#1565598
- make virtual-host identical to latency-performance
resolves: rhbz#1588932
- added support for Boot loader specification (BLS)
resolves: rhbz#1576435
- scheduler: keep polling file objects alive long enough
resolves: rhbz#1659140
- mssql: updated tuning
resolves: rhbz#1660178
- s2kb: fixed to be compatible with python3
resolves: rhbz#1684122
- profiles: fallback to the 'powersave' scaling governor
resolves: rhbz#1679205
- disable KSM only once, re-enable it only on full rollback
resolves: rhbz#1622239
- functions: reworked setup_kvm_mod_low_latency to count with kernel changes
resolves: rhbz#1649408
- updated virtual-host profile
resolves: rhbz#1569375
- added log message for unsupported parameters in plugin_net
resolves: rhbz#1533852
- added range feature for cpu exclusion
resolves: rhbz#1533908
- make a copy of devices when verifying tuning
resolves: rhbz#1592743
- fixed disk plugin/plugout problem
resolves: rhbz#1595156
- fixed unit configuration reading
resolves: rhbz#1613379
- reload profile configuration on SIGHUP
resolves: rhbz#1631744
- use built-in functionality to apply system sysctl
resolves: rhbz#1663412
* Sun Feb 03 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.10.0-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Fri Jan 25 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-6
* Fri Feb 22 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-15
- Fixed disk plugin to correctly match devices with python3
Resolves: rhbz#1676513
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.10.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Tue Jan 8 2019 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-14
- Updated mssql tuning
Resolves: rhbz#1660178
* Fri Dec 14 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-13
- Fix excessive CPU usage in the scheduler plugin
- Resolves: rhbz#1659140
* Mon Dec 10 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-12
- Added workaround for s390x zipl not supporting multiple initrds
Related: rhbz#1576435
* Sun Dec 9 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-11
- Added support for BLS
Resolves: rhbz#1576435
* Thu Dec 6 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-10
- Reworked setup_kvm_mod_low_latency to count with kernel changes
Resolves: rhbz#1653819
* Tue Nov 27 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-9
- realtime-virtual-guest/host: start/stop rt-entsk daemon on
initialization/shutdown
resolves: rhbz#1619822
* Tue Nov 27 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-8
- Disable ksm once, re-enable it on full rollback
Resolves: rhbz#1652076
* Wed Oct 10 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-7
- Make python3-dmidecode a weak dependency as it's x86_64 only
- Resolves: rhbz#1565598
* Tue Oct 09 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-6
- Fix rules for profile recommendation
- Resolves: rhbz#1565598
* Wed Aug 8 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-5
- use online CPUs for cpusets calculations instead of present CPUs
resolves: rhbz#1613832
* Wed Jul 11 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-4
- Fix a traceback in tuned-gui
* Tue Jul 10 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-3
- Used python intepreter path from the rpm macro
* Tue Jul 10 2018 Ondřej Lysoněk <olysonek@redhat.com> - 2.10.0-2
- tuned-adm: Fix a traceback when run without action specified
- Fixed compatibility with python-3.7
* Mon Jul 9 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-2
- used python intepreter path from the rpm macro
* Wed Jul 4 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-1
- new release
@ -791,30 +979,20 @@ fi
- IRQ affinity handled by scheduler plugin
resolves: rhbz#1590937
* Mon Jun 11 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-0.1.rc1
* Mon Jun 25 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.10.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1546598
- script: show stderr output in the log
resolves: rhbz#1536476
- realtime-virtual-host: script.sh: add error checking
resolves: rhbz#1461509
- man: improved tuned-profiles-cpu-partitioning.7
resolves: rhbz#1548148
- bootloader: check if grub2_cfg_file_name is None in _remove_grub2_tuning()
resolves: rhbz#1571403
- plugin_scheduler: whitelist/blacklist processed also for thread names
resolves: rhbz#1512295
- bootloader: patch all GRUB2 config files
resolves: rhbz#1556990
- profiles: added mssql profile
resolves: rhbz#1442122
- tuned-adm: print log excerpt when changing profile
resolves: rhbz#1538745
- cpu-partitioning: use no_balance_cores instead of no_rebalance_cores
resolves: rhbz#1550573
- sysctl: support assignment modifiers as other plugins do
resolves: rhbz#1564092
- oracle: fixed ip_local_port_range parity warning
resolves: rhbz#1527219
- Fix verifying cpumask on systems with more than 32 cores
@ -822,93 +1000,20 @@ fi
- oracle: updated the profile to be in sync with KCS 39188
resolves: rhbz#1447323
* Fri Mar 23 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-9
- Used weak deps for tuned-profiles-nfv-host-bin
* Fri Jun 8 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-10.20180430git5d0a9d91
- Fixed python3-gobject-base requirement
* Wed Mar 21 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-8
- Dropped tuned-profiles-nfv-host-bin, now provided by standalone package
* Thu May 17 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-9.20180430git5d0a9d91
- Bumped release to fix conflict caused by automerge
* Fri Mar 2 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-7
- Dropped exlusive arch in tuned-profiles-nfv-host-bin (it seems it
blocked all tuned packages on non x86 architectures)
* Mon Apr 30 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-1.20180430git5d0a9d91
- New version
- Dropped plugin-disk-traceback-fix patch (upstreamed)
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.9.0-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Mon Feb 05 2018 Iryna Shcherbina <ishcherb@redhat.com> - 2.9.0-5
- Update Python 2 dependency declarations to new packaging standards
(See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3)
* Wed Jan 31 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-4
- Fixed perf requirement, explicitly require python2-perf
* Sat Jan 06 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.9.0-3
- Remove obsolete scriptlets
* Mon Nov 13 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-2
- added tscdeadline_latency.flat benchmark
resolves: rhbz#1504680
* Sun Oct 29 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-1
- new release
- rebased tuned to latest upstream
related: rhbz#1467576
* Fri Oct 20 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-0.2.rc2
- new release
- rebased tuned to latest upstream
related: rhbz#1467576
- fixed expansion of the variables in the 'devices' section
related: rhbz#1490399
- cpu-partitioning: add no_rebalance_cores= option
resolves: rhbz#1497182
* Thu Oct 12 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.9.0-0.1.rc1
- new release
- rebased tuned to latest upstream
resolves: rhbz#1467576
- added recommend.d functionality
resolves: rhbz#1459146
- recommend: added support for matching of processes
resolves: rhbz#1461838
- plugin_video: added support for the 'dpm' power method
resolves: rhbz#1417659
- list available profiles on 'tuned-adm profile'
resolves: rhbz#988433
- cpu-partitioning: used tuned instead of tuna for cores isolation
resolves: rhbz#1442229
- inventory: added workaround for pyudev < 0.18
resolves: rhbz#1251240
- realtime: used skew_tick=1 in kernel cmdline
resolves: rhbz#1447938
- realtime-virtual-guest: re-assigned kernel thread priorities
resolves: rhbz#1452357
- bootloader: splitted string for removal from cmdline
resolves: rhbz#1461279
- network-latency: added skew_tick=1 kernel command line parameter
resolves: rhbz#1451073
- bootloader: accepted only certain values for initrd_remove_dir
resolves: rhbz#1455161
- increased udev monitor buffer size, made it configurable
resolves: rhbz#1442306
- bootloader: don't add nonexistent overlay image to grub.cfg
resolves: rhbz#1454340
- plugin_cpu: don't log error in execute() if EPB is not supported
resolves: rhbz#1443182
- sap-hana: fixed description of the sap-hana profiles
resolves: rhbz#1482005
- plugin_systemd: on full_rollback notify about need of initrd regeneration
resolves: rhbz#1469258
- don't log errors about missing files on verify with ignore_missing set
resolves: rhbz#1451435
- plugin_scheduler: improved logging
resolves: rhbz#1474961
- improved checking if we are rebooting or not
resolves: rhbz#1475571
- started dbus exports after a profile is applied
resolves: rhbz#1443142
- sap-hana: changed force_latency to 70
resolves: rhbz#1501252
* Fri Mar 23 2018 Jaroslav Škarvada <jskarvad@redhat.com> - 2.8.0-6
- Dropped qemu-kvm-tools-rhev requirement, now satisfied by
tuned-profiles-nfv-host-bin
Related: rhbz#1504681
* Mon Aug 21 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.8.0-5
- kernel-tools made weak dependency