Merge branch 'redhat-performance:master' into test-fix
This commit is contained in:
commit
18af9e5799
51 changed files with 891 additions and 318 deletions
|
|
@ -227,4 +227,24 @@
|
|||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="com.redhat.tuned.get_instances">
|
||||
<description>Get list of active TuneD plugin instances</description>
|
||||
<message>Authentication is required to get list of active TuneD plugin instances</message>
|
||||
<defaults>
|
||||
<allow_any>yes</allow_any>
|
||||
<allow_inactive>yes</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="com.redhat.tuned.instance_get_devices">
|
||||
<description>Get list of devices assigned to the instance</description>
|
||||
<message>Authentication is required to get list of devices assigned to the instance</message>
|
||||
<defaults>
|
||||
<allow_any>yes</allow_any>
|
||||
<allow_inactive>yes</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
tuned\-adm - command line tool for switching between different tuning profiles
|
||||
.SH SYNOPSIS
|
||||
.B tuned\-adm
|
||||
.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend ]
|
||||
.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend " | " "instance_acquire_devices \fIdevices\fP \fIinstance\fP" " | " "get_instances \fI[plugin]\fP" " | " "instance_get_devices \fIinstance\fP" ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
This command line utility allows you to switch between user definable tuning
|
||||
|
|
@ -110,6 +110,23 @@ Enable automatic profile selection mode, switch to the recommended profile.
|
|||
.B profile_mode
|
||||
Show current profile selection mode.
|
||||
|
||||
.TP
|
||||
.B "instance_acquire_devices \fIdevices\fP \fIinstance\fP"
|
||||
Move all provided \fIdevices\fP under the given plugin \fIinstance\fP. The plugin
|
||||
instance is identified using its name from the TuneD profile.
|
||||
|
||||
The devices are specified using a comma-separated list. When moving a set of CPUs,
|
||||
it is possible to use the cpulist syntax by including the 'cpulist:' prefix.
|
||||
For instance, 'cpulist:0,2-4' will move the devices cpu0, cpu1, cpu2, and cpu4.
|
||||
|
||||
.TP
|
||||
.B "get_instances \fI[plugin]\fP"
|
||||
List active instances of a given plugin or all active instances if no plugin is specified.
|
||||
|
||||
.TP
|
||||
.B "instance_get_devices \fIinstance\fP"
|
||||
List devices currently assigned to a given instance.
|
||||
|
||||
.TP
|
||||
.B off
|
||||
Unload tunings.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ cpufreq_conservative=+r
|
|||
priority=10
|
||||
governor=conservative|powersave
|
||||
energy_perf_bias=normal
|
||||
energy_performance_preference=balance_performance
|
||||
|
||||
[audio]
|
||||
timeout=10
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
#
|
||||
# Core isolation
|
||||
#
|
||||
# The 'isolated_cores=' variable below controls which cores should be
|
||||
# isolated. By default we reserve 1 core per socket for housekeeping
|
||||
# and isolate the rest. But you can isolate any range as shown in the
|
||||
# examples below. Just remember to keep only one isolated_cores= line.
|
||||
#
|
||||
# Examples:
|
||||
# isolated_cores=2,4-7
|
||||
# isolated_cores=2-23
|
||||
#
|
||||
# Reserve 1 core per socket for housekeeping, isolate the rest.
|
||||
# Change this for a core list or range as shown above.
|
||||
isolated_cores=${f:calc_isolated_cores:1}
|
||||
|
||||
# To disable the kernel load balancing in certain isolated CPUs:
|
||||
|
|
|
|||
|
|
@ -566,7 +566,7 @@ disable_ksm()
|
|||
die "failed to create $KSM_MASK_FILE"
|
||||
fi
|
||||
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
|
||||
systemctl cat -- $KSM_SERVICES &> /dev/null || return
|
||||
systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
|
||||
systemctl --now --quiet mask $KSM_SERVICES
|
||||
# Unmerge all shared pages
|
||||
test -f $KSM_RUN_PATH && echo 2 > $KSM_RUN_PATH
|
||||
|
|
@ -578,7 +578,7 @@ enable_ksm()
|
|||
{
|
||||
if [ -f $KSM_MASK_FILE ]; then
|
||||
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
|
||||
systemctl cat -- $KSM_SERVICES &> /dev/null || return
|
||||
systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
|
||||
if systemctl --quiet unmask $KSM_SERVICES; then
|
||||
rm -f $KSM_MASK_FILE
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ summary=Optimize for low power consumption
|
|||
[cpu]
|
||||
governor=ondemand|powersave
|
||||
energy_perf_bias=powersave|power
|
||||
energy_performance_preference=power
|
||||
|
||||
[eeepc_she]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,21 @@
|
|||
#
|
||||
# Variable settings below override the definitions from the
|
||||
# /etc/tuned/realtime-variables.conf file.
|
||||
|
||||
#
|
||||
# Core isolation
|
||||
#
|
||||
# The 'isolated_cores=' variable below controls which cores should be
|
||||
# isolated. By default we reserve 1 core per socket for housekeeping
|
||||
# and isolate the rest. But you can isolate any range as shown in the
|
||||
# examples below. Just remember to keep only one isolated_cores= line.
|
||||
#
|
||||
# Examples:
|
||||
# isolated_cores=2,4-7
|
||||
# isolated_cores=2-23
|
||||
#
|
||||
# Reserve 1 core per socket for housekeeping, isolate the rest.
|
||||
# Change this for a core list or range as shown above.
|
||||
isolated_cores=${f:calc_isolated_cores:1}
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,12 +1,21 @@
|
|||
#
|
||||
# Variable settings below override the definitions from the
|
||||
# /etc/tuned/realtime-variables.conf file.
|
||||
|
||||
#
|
||||
# Core isolation
|
||||
#
|
||||
# The 'isolated_cores=' variable below controls which cores should be
|
||||
# isolated. By default we reserve 1 core per socket for housekeeping
|
||||
# and isolate the rest. But you can isolate any range as shown in the
|
||||
# examples below. Just remember to keep only one isolated_cores= line.
|
||||
#
|
||||
# Examples:
|
||||
# isolated_cores=2,4-7
|
||||
# isolated_cores=2-23
|
||||
#
|
||||
# Reserve 1 core per socket for housekeeping, isolate the rest.
|
||||
# Change this for a core list or range as shown above.
|
||||
isolated_cores=${f:calc_isolated_cores:1}
|
||||
|
||||
# Uncomment the 'isolate_managed_irq=Y' bellow if you want to move kernel
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
#
|
||||
# Core isolation
|
||||
#
|
||||
# The 'isolated_cores=' variable below controls which cores should be
|
||||
# isolated. By default we reserve 1 core per socket for housekeeping
|
||||
# and isolate the rest. But you can isolate any range as shown in the
|
||||
# examples below. Just remember to keep only one isolated_cores= line.
|
||||
#
|
||||
# Examples:
|
||||
# isolated_cores=2,4-7
|
||||
# isolated_cores=2-23
|
||||
#
|
||||
# Reserve 1 core per socket for housekeeping, isolate the rest.
|
||||
# Change this for a core list or range as shown above.
|
||||
isolated_cores=${f:calc_isolated_cores:1}
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ priority=10
|
|||
/sys/module/haltpoll/parameters/guest_halt_poll_grow_start=2400000
|
||||
|
||||
[bootloader]
|
||||
cmdline_saphana=skew_tick=1
|
||||
cmdline_saphana=skew_tick=1
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
summary=Optimize for server power savings
|
||||
|
||||
[cpu]
|
||||
energy_performance_preference=balance_power
|
||||
|
||||
[disk]
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ amd_cpuinfo_regex=model name\s+:.*\bAMD\b
|
|||
governor=performance
|
||||
energy_perf_bias=performance
|
||||
min_perf_pct=100
|
||||
energy_performance_preference=performance
|
||||
|
||||
# Marvell ThunderX
|
||||
[vm.thunderx]
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ class CommandsPlugin(Plugin):
|
|||
return {'size':'S','device_setting':'101'}
|
||||
|
||||
@decorators.command_set('size')
|
||||
def _set_size(self, new_size, sim):
|
||||
def _set_size(self, new_size, sim, remove):
|
||||
self._size = new_size
|
||||
return new_size
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ class CommandsPlugin(Plugin):
|
|||
return self._size
|
||||
|
||||
@decorators.command_set('device_setting',per_device = True)
|
||||
def _set_device_setting(self,value,device,sim):
|
||||
def _set_device_setting(self,value,device,sim,remove):
|
||||
device.setting = value
|
||||
return device.setting
|
||||
|
||||
|
|
|
|||
13
tuned-adm.py
13
tuned-adm.py
|
|
@ -97,6 +97,19 @@ if __name__ == "__main__":
|
|||
parser_profile_mode = subparsers.add_parser("profile_mode", help="show current profile selection mode")
|
||||
parser_profile_mode.set_defaults(action="profile_mode")
|
||||
|
||||
parser_instance_acquire_devices = subparsers.add_parser("instance_acquire_devices", help="acquire devices from other instances and assign them to the given instance")
|
||||
parser_instance_acquire_devices.set_defaults(action="instance_acquire_devices")
|
||||
parser_instance_acquire_devices.add_argument("devices", metavar="devices", type=str, help="comma-separated list of device names; may use the cpulist syntax if prefixed with 'cpulist:'")
|
||||
parser_instance_acquire_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance which should acquire the devices")
|
||||
|
||||
parser_get_instances = subparsers.add_parser("get_instances", help="list active instances of a given plugin or all active instances if no plugin is specified")
|
||||
parser_get_instances.set_defaults(action="get_instances")
|
||||
parser_get_instances.add_argument("plugin_name", metavar="plugin_name", type=str, nargs="?", default="", help="name of the plugin to restrict the list of instances to")
|
||||
|
||||
parser_instance_get_devices = subparsers.add_parser("instance_get_devices", help="list devices assigned to a given instance")
|
||||
parser_instance_get_devices.set_defaults(action="instance_get_devices")
|
||||
parser_instance_get_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance")
|
||||
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
options = vars(args)
|
||||
|
|
|
|||
228
tuned-gui.glade
228
tuned-gui.glade
|
|
@ -134,6 +134,137 @@
|
|||
<action-widget response="-1">buttonCancel1</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkMenu" id="menuAddPluginValue">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="AddPluginValueMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Add Value</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="add_plugin_value_to_treeview" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="AddCustomPluginValueItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Add Custom Value</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="add_custom_plugin_value_to_treeview" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="menuitem4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="DeleteValueMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Delete Value</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="delete_plugin_value_to_treeview" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkDialog" id="dialogAddCustomPluginValue">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox8">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area8">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button3">
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="xalign">0.40999999642372131</property>
|
||||
<property name="yalign">0.60000002384185791</property>
|
||||
<property name="image_position">bottom</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button4">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box13">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="Choose plugin value to add:1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Choose plugin value to add:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="placeholder_text" translatable="yes">Value ...</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="1">button3</action-widget>
|
||||
<action-widget response="-1">button4</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkDialog" id="dialogAddPlugin">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
|
|
@ -230,6 +361,99 @@
|
|||
<action-widget response="-1">buttonCloseAddPlugin</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkDialog" id="dialogAddPluginValue">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox5">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area5">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button1">
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="xalign">0.40999999642372131</property>
|
||||
<property name="yalign">0.60000002384185791</property>
|
||||
<property name="image_position">bottom</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button2">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box12">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="Choose plugin value to add:">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Choose plugin value to add:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="comboboxPluginsValues">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="1">button1</action-widget>
|
||||
<action-widget response="-1">button2</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkDialog" id="dialogYesNo">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
|
|
@ -1561,6 +1785,8 @@
|
|||
</object>
|
||||
<object class="GtkWindow" id="windowProfileEditorRaw">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="width-request">600</property>
|
||||
<property name="height-request">500</property>
|
||||
<signal name="delete-event" handler="on_delete_event" swapped="no"/>
|
||||
<child>
|
||||
<placeholder/>
|
||||
|
|
@ -1601,7 +1827,7 @@
|
|||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
|
|
|
|||
147
tuned-gui.py
147
tuned-gui.py
|
|
@ -41,7 +41,7 @@ except ValueError:
|
|||
"to be installed.")
|
||||
|
||||
try:
|
||||
from gi.repository import Gtk, GObject
|
||||
from gi.repository import Gtk, GObject, GLib
|
||||
except ImportError:
|
||||
raise ImportError("Gtk3 backend requires pygobject to be installed.")
|
||||
|
||||
|
|
@ -116,8 +116,8 @@ class Base(object):
|
|||
self.builder = Gtk.Builder()
|
||||
try:
|
||||
self.builder.add_from_file(GLADEUI)
|
||||
except GObject.GError as e:
|
||||
print("Error loading '%s'" % GLADEUI, file=sys.stderr)
|
||||
except GLib.GError as e:
|
||||
print("Error loading '%s', error: '%s'" % (GLADEUI, e), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
#
|
||||
|
|
@ -249,14 +249,14 @@ class Base(object):
|
|||
self.manager.get_profile(self.controller.active_profile())
|
||||
else:
|
||||
self.active_profile = None
|
||||
self._gobj('summaryProfileName').set_text(self.active_profile.name)
|
||||
try:
|
||||
self._gobj('summaryProfileName').set_text(self.active_profile.name)
|
||||
except AttributeError:
|
||||
self.error_dialog('No active profile set', '')
|
||||
try:
|
||||
self._gobj('summaryIncludedProfileName').set_text(self.active_profile.options['include'
|
||||
])
|
||||
except:
|
||||
|
||||
# keyerror probably
|
||||
|
||||
except (AttributeError, KeyError):
|
||||
self._gobj('summaryIncludedProfileName').set_text('None')
|
||||
|
||||
row = Gtk.ListBoxRow()
|
||||
|
|
@ -275,32 +275,33 @@ class Base(object):
|
|||
self._gobj('listboxSummaryOfActiveProfile').add(sep)
|
||||
sep.show()
|
||||
|
||||
for u in self.active_profile.units:
|
||||
row = Gtk.ListBoxRow()
|
||||
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
|
||||
spacing=0)
|
||||
hbox.set_homogeneous(True)
|
||||
row.add(hbox)
|
||||
label = Gtk.Label()
|
||||
label.set_markup(u)
|
||||
label.set_justify(Gtk.Justification.LEFT)
|
||||
hbox.pack_start(label, False, True, 1)
|
||||
if self.active_profile:
|
||||
for u in self.active_profile.units:
|
||||
row = Gtk.ListBoxRow()
|
||||
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
|
||||
spacing=0)
|
||||
hbox.set_homogeneous(True)
|
||||
row.add(hbox)
|
||||
label = Gtk.Label()
|
||||
label.set_markup(u)
|
||||
label.set_justify(Gtk.Justification.LEFT)
|
||||
hbox.pack_start(label, False, True, 1)
|
||||
|
||||
grid = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
|
||||
spacing=0)
|
||||
grid.set_homogeneous(True)
|
||||
for o in self.active_profile.units[u].options:
|
||||
label_option = Gtk.Label()
|
||||
label_option.set_markup(o + ' = ' + '<b>'
|
||||
+ self.active_profile.units[u].options[o]
|
||||
+ '</b>')
|
||||
grid.pack_start(label_option, False, True, 0)
|
||||
grid = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
|
||||
spacing=0)
|
||||
grid.set_homogeneous(True)
|
||||
for o in self.active_profile.units[u].options:
|
||||
label_option = Gtk.Label()
|
||||
label_option.set_markup(o + ' = ' + '<b>'
|
||||
+ self.active_profile.units[u].options[o]
|
||||
+ '</b>')
|
||||
grid.pack_start(label_option, False, True, 0)
|
||||
|
||||
hbox.pack_start(grid, False, True, 0)
|
||||
self._gobj('listboxSummaryOfActiveProfile').add(row)
|
||||
separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
|
||||
self._gobj('listboxSummaryOfActiveProfile').add(separator)
|
||||
separator.show()
|
||||
hbox.pack_start(grid, False, True, 0)
|
||||
self._gobj('listboxSummaryOfActiveProfile').add(row)
|
||||
separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
|
||||
self._gobj('listboxSummaryOfActiveProfile').add(separator)
|
||||
separator.show()
|
||||
|
||||
self._gobj('listboxSummaryOfActiveProfile').show_all()
|
||||
|
||||
|
|
@ -411,8 +412,8 @@ class Base(object):
|
|||
self._gobj('notebookPlugins').append_page_menu(
|
||||
self.treeview_for_data(
|
||||
config_options, plugin),
|
||||
Gtk.Label(plugin),
|
||||
Gtk.Label(plugin)
|
||||
Gtk.Label(label = plugin),
|
||||
Gtk.Label(label = plugin)
|
||||
)
|
||||
|
||||
self._gobj('notebookPlugins').show_all()
|
||||
|
|
@ -445,7 +446,7 @@ class Base(object):
|
|||
self.manager.set_raw_profile(profile_name,
|
||||
text_buffer.get_text(start, end, True))
|
||||
except Exception:
|
||||
self.error_dialog('Error while parsing raw configuration')
|
||||
self.error_dialog('Error while parsing raw configuration', '')
|
||||
return
|
||||
|
||||
self.error_dialog('Profile Editor will be closed.',
|
||||
|
|
@ -629,7 +630,7 @@ class Base(object):
|
|||
|
||||
for (name, unit) in list(profile.units.items()):
|
||||
self._gobj('notebookPlugins').append_page_menu(self.treeview_for_data(unit.options, unit.name),
|
||||
Gtk.Label(unit.name), Gtk.Label(unit.name))
|
||||
Gtk.Label(label = unit.name), Gtk.Label(label = unit.name))
|
||||
self._gobj('notebookPlugins').show_all()
|
||||
self._gobj('windowProfileEditor').show()
|
||||
|
||||
|
|
@ -639,11 +640,11 @@ class Base(object):
|
|||
"""
|
||||
|
||||
treestore = Gtk.ListStore(GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING)
|
||||
GObject.TYPE_STRING)
|
||||
|
||||
for (option, value) in list(data.items()):
|
||||
treestore.append([str(value), option])
|
||||
treeview = Gtk.TreeView(treestore)
|
||||
treeview = Gtk.TreeView(model = treestore)
|
||||
renderer = Gtk.CellRendererText()
|
||||
column_option = Gtk.TreeViewColumn('Option', renderer, text=0)
|
||||
column_value = Gtk.TreeViewColumn('Value', renderer, text=1)
|
||||
|
|
@ -694,7 +695,7 @@ class Base(object):
|
|||
|
||||
def execute_switch_tuned(self, switch, data):
|
||||
"""
|
||||
Suported switch_tuned_start_stop and switch_tuned_startup_start_stop.
|
||||
Supported switch_tuned_start_stop and switch_tuned_startup_start_stop.
|
||||
"""
|
||||
|
||||
if switch == self._gobj('switchTunedStartStop'):
|
||||
|
|
@ -798,8 +799,8 @@ class Base(object):
|
|||
|
||||
if event.button == 3:
|
||||
popup = Gtk.Menu()
|
||||
popup.append(Gtk.MenuItem('add'))
|
||||
popup.append(Gtk.MenuItem('delete'))
|
||||
popup.append(Gtk.MenuItem(label = 'add'))
|
||||
popup.append(Gtk.MenuItem(label = 'delete'))
|
||||
time = event.time
|
||||
self._gobj('menuAddPluginValue').popup(
|
||||
None,
|
||||
|
|
@ -818,6 +819,70 @@ class Base(object):
|
|||
return True
|
||||
return False
|
||||
|
||||
def add_plugin_value_to_treeview(self, action):
|
||||
notebook_plugins = self._gobj('notebookPlugins')
|
||||
current_plugin = \
|
||||
notebook_plugins.get_tab_label(notebook_plugins.get_nth_page(notebook_plugins.get_current_page())).get_text()
|
||||
current_plugin_options = \
|
||||
self.plugin_loader.plugins.get(current_plugin)
|
||||
curent_plugin_values_model = \
|
||||
notebook_plugins.get_nth_page(notebook_plugins.get_current_page()).get_model()
|
||||
|
||||
treestore_plugins_values = Gtk.ListStore(GObject.TYPE_STRING)
|
||||
|
||||
for (vl_name, vl_val) in current_plugin_options.items():
|
||||
if not self.liststore_contains_item(curent_plugin_values_model,
|
||||
vl_name):
|
||||
treestore_plugins_values.append([vl_name])
|
||||
|
||||
dialog_add_plugin_value = \
|
||||
self.builder.get_object('dialogAddPluginValue')
|
||||
dialog_add_plugin_value.connect('destroy', lambda d: \
|
||||
dialog_add_plugin_value.hide())
|
||||
combobox = self.builder.get_object('comboboxPluginsValues')
|
||||
combobox.set_model(treestore_plugins_values)
|
||||
|
||||
response = dialog_add_plugin_value.run()
|
||||
dialog_add_plugin_value.hide()
|
||||
|
||||
if response == 1:
|
||||
active = combobox.get_active_text()
|
||||
curent_plugin_values_model.append([current_plugin_options.get(active),
|
||||
active])
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_custom_plugin_value_to_treeview(self, action):
|
||||
notebook_plugins = self._gobj('notebookPlugins')
|
||||
curent_plugin_values_model = \
|
||||
notebook_plugins.get_nth_page(notebook_plugins.get_current_page()).get_model()
|
||||
|
||||
dialog_add_custom_plugin_value = \
|
||||
self.builder.get_object('dialogAddCustomPluginValue')
|
||||
text = self.builder.get_object('entry2')
|
||||
dialog_add_custom_plugin_value.connect('destroy', lambda d: \
|
||||
dialog_add_custom_plugin_value.hide())
|
||||
|
||||
response = dialog_add_custom_plugin_value.run()
|
||||
dialog_add_custom_plugin_value.hide()
|
||||
|
||||
if response == 1:
|
||||
curent_plugin_values_model.append(['', text.get_text()])
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_plugin_value_to_treeview(self, action):
|
||||
notebook_plugins = self._gobj('notebookPlugins')
|
||||
curent_plugin_values_tree = \
|
||||
notebook_plugins.get_nth_page(notebook_plugins.get_current_page())
|
||||
|
||||
(model, iter) = \
|
||||
curent_plugin_values_tree.get_selection().get_selected()
|
||||
if model is None or iter is None:
|
||||
return False
|
||||
model.remove(iter)
|
||||
return True
|
||||
|
||||
def _start_tuned(self):
|
||||
self._su_execute(['service', 'tuned', 'start'])
|
||||
time.sleep(10)
|
||||
|
|
|
|||
26
tuned.spec
26
tuned.spec
|
|
@ -44,9 +44,9 @@
|
|||
|
||||
Summary: A dynamic adaptive system tuning daemon
|
||||
Name: tuned
|
||||
Version: 2.20.0
|
||||
Version: 2.21.0
|
||||
Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist}
|
||||
License: GPLv2+
|
||||
License: GPL-2.0-or-later AND CC-BY-SA-3.0
|
||||
Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
|
||||
URL: http://www.tuned-project.org/
|
||||
BuildArch: noarch
|
||||
|
|
@ -557,6 +557,28 @@ fi
|
|||
%{_mandir}/man7/tuned-profiles-openshift.7*
|
||||
|
||||
%changelog
|
||||
* Tue Aug 29 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.21.0-1
|
||||
- new release
|
||||
- rebased tuned to latest upstream
|
||||
related: rhbz#2182117
|
||||
- api: fixed stop method not to require any parameter
|
||||
resolves: rhbz#2235637
|
||||
|
||||
* Sun Aug 20 2023 Jaroslav Škarvada <jskarvad@redhat.com> - 2.21.0-0.1.rc1
|
||||
- new release
|
||||
- rebased tuned to latest upstream
|
||||
resolves: rhbz#2182117
|
||||
- plugin_scheduler: fix perf fd leaks
|
||||
resolves: rhbz#2173938
|
||||
- allow skipping rollback when restarting TuneD or switching profile
|
||||
resolves: rhbz#2203142
|
||||
- function_calc_isolated_cores: no errors for offline CPUs
|
||||
resolves: rhbz#2217015
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -439,3 +439,39 @@ class Admin(object):
|
|||
def _action_list_plugins(self, verbose=False):
|
||||
print("Not supported in no_daemon mode.")
|
||||
return False
|
||||
|
||||
def _action_dbus_instance_acquire_devices(self, devices, instance):
|
||||
(ret, msg) = self._controller.instance_acquire_devices(devices, instance)
|
||||
if not ret:
|
||||
self._error("Unable to acquire devices: %s" % msg)
|
||||
return self._controller.exit(ret)
|
||||
|
||||
def _action_instance_acquire_devices(self, devices, instance):
|
||||
print("Not supported in no_daemon mode.")
|
||||
return False
|
||||
|
||||
def _action_dbus_get_instances(self, plugin_name):
|
||||
(ret, msg, pairs) = self._controller.get_instances(plugin_name)
|
||||
if not ret:
|
||||
self._error("Unable to list instances: %s" % msg)
|
||||
return self._controller.exit(False)
|
||||
for instance, plugin in pairs:
|
||||
print("%s (%s)" % (instance, plugin))
|
||||
return self._controller.exit(True)
|
||||
|
||||
def _action_get_instances(self, plugin_name):
|
||||
print("Not supported in no_daemon mode.")
|
||||
return False
|
||||
|
||||
def _action_dbus_instance_get_devices(self, instance):
|
||||
(ret, msg, devices) = self._controller.instance_get_devices(instance)
|
||||
if not ret:
|
||||
self._error("Unable to list devices: %s" % msg)
|
||||
return self._controller.exit(False)
|
||||
for device in devices:
|
||||
print(device)
|
||||
return self._controller.exit(True)
|
||||
|
||||
def _action_instance_get_devices(self, instance):
|
||||
print("Not supported in no_daemon mode.")
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -163,6 +163,15 @@ class DBusController(object):
|
|||
"""
|
||||
return self._call("get_plugin_hints", plugin_name)
|
||||
|
||||
def instance_acquire_devices(self, devices, instance):
|
||||
return self._call("instance_acquire_devices", devices, instance)
|
||||
|
||||
def get_instances(self, plugin_name):
|
||||
return self._call("get_instances", plugin_name)
|
||||
|
||||
def instance_get_devices(self, instance):
|
||||
return self._call("instance_get_devices", instance)
|
||||
|
||||
def exit(self, ret):
|
||||
self.set_action(None)
|
||||
self._ret = ret
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ SYSTEM_RELEASE_FILE = "/etc/system-release-cpe"
|
|||
FUNCTION_PREFIX = "function_"
|
||||
# prefix for exported environment variables when calling scripts
|
||||
ENV_PREFIX = "TUNED_"
|
||||
ROLLBACK_NOT_ON_EXIT = 0
|
||||
ROLLBACK_NONE = 0
|
||||
ROLLBACK_SOFT = 1
|
||||
ROLLBACK_FULL = 2
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class Application(object):
|
|||
signal.signal(signal_number, handler_wrapper)
|
||||
|
||||
def _init_signals(self):
|
||||
self._handle_signal(signal.SIGHUP, self._controller.reload)
|
||||
self._handle_signal(signal.SIGHUP, self._controller.sighup)
|
||||
self._handle_signal(signal.SIGINT, self._controller.terminate)
|
||||
self._handle_signal(signal.SIGTERM, self._controller.terminate)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
|||
def terminate(self):
|
||||
self._terminate.set()
|
||||
|
||||
def sighup(self):
|
||||
if not self._daemon._sighup_processing.is_set():
|
||||
self._daemon._sighup_processing.set()
|
||||
if not self.reload():
|
||||
self._daemon._sighup_processing.clear()
|
||||
|
||||
@exports.signal("sbs")
|
||||
def profile_changed(self, profile_name, result, errstr):
|
||||
pass
|
||||
|
|
@ -116,10 +122,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
|||
return False
|
||||
return self._daemon.start()
|
||||
|
||||
@exports.export("", "b")
|
||||
def stop(self, caller = None, profile_switch = False):
|
||||
if caller == "":
|
||||
return False
|
||||
def _stop(self, profile_switch = False):
|
||||
if not self._daemon.is_running():
|
||||
res = True
|
||||
else:
|
||||
|
|
@ -127,12 +130,18 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
|||
self._timer_store.cancel_all()
|
||||
return res
|
||||
|
||||
@exports.export("", "b")
|
||||
def stop(self, caller = None):
|
||||
if caller == "":
|
||||
return False
|
||||
return self._stop(profile_switch = False)
|
||||
|
||||
@exports.export("", "b")
|
||||
def reload(self, caller = None):
|
||||
if caller == "":
|
||||
return False
|
||||
if self._daemon.is_running():
|
||||
stop_ok = self.stop(profile_switch = True)
|
||||
stop_ok = self._stop(profile_switch = True)
|
||||
if not stop_ok:
|
||||
return False
|
||||
try:
|
||||
|
|
@ -364,3 +373,47 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
|||
log.info(rets)
|
||||
return (False, rets)
|
||||
return (True, "OK")
|
||||
|
||||
@exports.export("s", "(bsa(ss))")
|
||||
def get_instances(self, plugin_name, caller = None):
|
||||
"""Return a list of active instances of a plugin or all active instances
|
||||
|
||||
Parameters:
|
||||
plugin_name -- name of the plugin or an empty string
|
||||
|
||||
Return:
|
||||
bool -- True on success
|
||||
string -- error message or "OK"
|
||||
list of string pairs -- [(instance_name, plugin_name)]
|
||||
"""
|
||||
if caller == "":
|
||||
return (False, "Unauthorized", [])
|
||||
if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
|
||||
rets = "Plugin '%s' does not exist" % plugin_name
|
||||
log.error(rets)
|
||||
return (False, rets, [])
|
||||
instances = filter(lambda instance: instance.active, self._daemon._unit_manager.instances)
|
||||
if plugin_name != "":
|
||||
instances = filter(lambda instance: instance.plugin.name == plugin_name, instances)
|
||||
return (True, "OK", list(map(lambda instance: (instance.name, instance.plugin.name), instances)))
|
||||
|
||||
@exports.export("s", "(bsas)")
|
||||
def instance_get_devices(self, instance_name, caller = None):
|
||||
"""Return a list of devices assigned to an instance
|
||||
|
||||
Parameters:
|
||||
instance_name -- name of the instance
|
||||
|
||||
Return:
|
||||
bool -- True on success
|
||||
string -- error message or "OK"
|
||||
list of strings -- device names
|
||||
"""
|
||||
if caller == "":
|
||||
return (False, "Unauthorized", [])
|
||||
for instance in self._daemon._unit_manager.instances:
|
||||
if instance.name == instance_name:
|
||||
return (True, "OK", sorted(list(instance.processed_devices)))
|
||||
rets = "Instance '%s' not found" % instance_name
|
||||
log.error(rets)
|
||||
return (False, rets, [])
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class Daemon(object):
|
|||
self._terminate_profile_switch = threading.Event()
|
||||
# Flag which is set if there is no operation in progress
|
||||
self._not_used = threading.Event()
|
||||
# Flag which is set if SIGHUP is being processed
|
||||
self._sighup_processing = threading.Event()
|
||||
self._not_used.set()
|
||||
self._profile_applied = threading.Event()
|
||||
|
||||
|
|
@ -203,6 +205,7 @@ class Daemon(object):
|
|||
exports.start()
|
||||
profile_names = " ".join(self._active_profiles)
|
||||
self._notify_profile_changed(profile_names, True, "OK")
|
||||
self._sighup_processing.clear()
|
||||
|
||||
if self._daemon:
|
||||
# In python 2 interpreter with applied patch for rhbz#917709 we need to periodically
|
||||
|
|
@ -231,7 +234,7 @@ class Daemon(object):
|
|||
|
||||
# if terminating due to profile switch
|
||||
if self._terminate_profile_switch.is_set():
|
||||
full_rollback = consts.ROLLBACK_FULL
|
||||
rollback = consts.ROLLBACK_FULL
|
||||
else:
|
||||
# Assume only soft rollback is needed. Soft rollback means reverting all
|
||||
# non-persistent tunings applied by a plugin instance. In contrast to full
|
||||
|
|
@ -241,21 +244,21 @@ class Daemon(object):
|
|||
# perform full cleanup. If the system is not shutting down, it means that TuneD
|
||||
# was explicitly stopped by the user and in such case do the full cleanup. On
|
||||
# systems without systemd, full cleanup is never performed.
|
||||
full_rollback = consts.ROLLBACK_SOFT
|
||||
rollback = consts.ROLLBACK_SOFT
|
||||
if not self._full_rollback_required():
|
||||
log.info("terminating TuneD due to system shutdown / reboot")
|
||||
elif self._rollback == "not_on_exit":
|
||||
# no rollback on TuneD exit whatsoever
|
||||
full_rollback = consts.ROLLBACK_NOT_ON_EXIT
|
||||
rollback = consts.ROLLBACK_NONE
|
||||
log.info("terminating TuneD and not rolling back any changes due to '%s' option in '%s'" % (consts.CFG_ROLLBACK, consts.GLOBAL_CONFIG_FILE))
|
||||
else:
|
||||
if self._daemon:
|
||||
log.info("terminating TuneD, rolling back all changes")
|
||||
full_rollback = consts.ROLLBACK_FULL
|
||||
rollback = consts.ROLLBACK_FULL
|
||||
else:
|
||||
log.info("terminating TuneD in one-shot mode")
|
||||
if self._daemon:
|
||||
self._unit_manager.stop_tuning(full_rollback)
|
||||
self._unit_manager.stop_tuning(rollback)
|
||||
self._unit_manager.destroy_all()
|
||||
|
||||
def _save_active_profile(self, profile_names, manual):
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ __all__ = ['GuiPluginLoader']
|
|||
class GuiPluginLoader():
|
||||
|
||||
'''
|
||||
Class for scan, import and load actual avaible plugins.
|
||||
Class for scan, import and load actual variable plugins.
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
|
|
@ -53,7 +53,7 @@ class GuiPluginLoader():
|
|||
self._prefix = 'plugin_'
|
||||
self._sufix = '.py'
|
||||
self._dbus_controller = DBusController(consts.DBUS_BUS,
|
||||
consts.DBUS_INTERFACE, consts.DBUS_OBJECT
|
||||
consts.DBUS_INTERFACE, consts.DBUS_OBJECT
|
||||
)
|
||||
self._get_plugins()
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ class Plugin(object):
|
|||
def _instance_post_static(self, instance, enabling):
|
||||
pass
|
||||
|
||||
def _call_device_script(self, instance, script, op, devices, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _call_device_script(self, instance, script, op, devices, rollback = consts.ROLLBACK_SOFT):
|
||||
if script is None:
|
||||
return None
|
||||
if len(devices) == 0:
|
||||
|
|
@ -228,7 +228,7 @@ class Plugin(object):
|
|||
environ = os.environ
|
||||
environ.update(self._variables.get_env())
|
||||
arguments = [op]
|
||||
if full_rollback == consts.ROLLBACK_FULL:
|
||||
if rollback == consts.ROLLBACK_FULL:
|
||||
arguments.append("full_rollback")
|
||||
arguments.append(dev)
|
||||
log.info("calling script '%s' with arguments '%s'" % (script, str(arguments)))
|
||||
|
|
@ -298,11 +298,11 @@ class Plugin(object):
|
|||
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
|
||||
self._run_for_each_device(instance, self._instance_update_dynamic, instance.processed_devices.copy())
|
||||
|
||||
def instance_unapply_tuning(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def instance_unapply_tuning(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
"""
|
||||
Remove all tunings applied by the plugin instance.
|
||||
"""
|
||||
if full_rollback == consts.ROLLBACK_NOT_ON_EXIT:
|
||||
if rollback == consts.ROLLBACK_NONE:
|
||||
return
|
||||
|
||||
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
|
||||
|
|
@ -310,11 +310,11 @@ class Plugin(object):
|
|||
if instance.has_static_tuning:
|
||||
self._call_device_script(instance, instance.script_post,
|
||||
"unapply", instance.processed_devices,
|
||||
full_rollback = full_rollback)
|
||||
rollback = rollback)
|
||||
self._instance_pre_static(instance, False)
|
||||
self._instance_unapply_static(instance, full_rollback)
|
||||
self._instance_unapply_static(instance, rollback)
|
||||
self._instance_post_static(instance, False)
|
||||
self._call_device_script(instance, instance.script_pre, "unapply", instance.processed_devices, full_rollback = full_rollback)
|
||||
self._call_device_script(instance, instance.script_pre, "unapply", instance.processed_devices, rollback = rollback)
|
||||
|
||||
def _instance_apply_static(self, instance):
|
||||
self._execute_all_non_device_commands(instance)
|
||||
|
|
@ -328,7 +328,7 @@ class Plugin(object):
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
self._cleanup_all_device_commands(instance,
|
||||
instance.processed_devices)
|
||||
self._cleanup_all_non_device_commands(instance)
|
||||
|
|
@ -506,7 +506,7 @@ class Plugin(object):
|
|||
else:
|
||||
new_value = self._check_and_save_value(instance, command, device, new_value)
|
||||
if new_value is not None:
|
||||
command["set"](new_value, device, sim = False)
|
||||
command["set"](new_value, device, sim = False, remove = False)
|
||||
|
||||
def _execute_non_device_command(self, instance, command, new_value):
|
||||
if command["custom"] is not None:
|
||||
|
|
@ -514,7 +514,7 @@ class Plugin(object):
|
|||
else:
|
||||
new_value = self._check_and_save_value(instance, command, None, new_value)
|
||||
if new_value is not None:
|
||||
command["set"](new_value, sim = False)
|
||||
command["set"](new_value, sim = False, remove = False)
|
||||
|
||||
def _norm_value(self, value):
|
||||
v = self._cmd.unquote(str(value))
|
||||
|
|
@ -576,7 +576,7 @@ class Plugin(object):
|
|||
new_value = self._process_assignment_modifiers(new_value, current_value)
|
||||
if new_value is None:
|
||||
return None
|
||||
new_value = command["set"](new_value, device, True)
|
||||
new_value = command["set"](new_value, device, True, False)
|
||||
return self._verify_value(command["name"], new_value, current_value, ignore_missing, device)
|
||||
|
||||
def _verify_non_device_command(self, instance, command, new_value, ignore_missing):
|
||||
|
|
@ -586,7 +586,7 @@ class Plugin(object):
|
|||
new_value = self._process_assignment_modifiers(new_value, current_value)
|
||||
if new_value is None:
|
||||
return None
|
||||
new_value = command["set"](new_value, True)
|
||||
new_value = command["set"](new_value, True, False)
|
||||
return self._verify_value(command["name"], new_value, current_value, ignore_missing)
|
||||
|
||||
def _cleanup_all_non_device_commands(self, instance):
|
||||
|
|
@ -594,19 +594,19 @@ class Plugin(object):
|
|||
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
|
||||
self._cleanup_non_device_command(instance, command)
|
||||
|
||||
def _cleanup_all_device_commands(self, instance, devices):
|
||||
def _cleanup_all_device_commands(self, instance, devices, remove = False):
|
||||
for command in reversed([command for command in list(self._commands.values()) if command["per_device"]]):
|
||||
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
|
||||
for device in devices:
|
||||
self._cleanup_device_command(instance, command, device)
|
||||
self._cleanup_device_command(instance, command, device, remove)
|
||||
|
||||
def _cleanup_device_command(self, instance, command, device):
|
||||
def _cleanup_device_command(self, instance, command, device, remove = False):
|
||||
if command["custom"] is not None:
|
||||
command["custom"](False, None, device, False, False)
|
||||
else:
|
||||
old_value = self._storage_get(instance, command, device)
|
||||
if old_value is not None:
|
||||
command["set"](old_value, device, sim = False)
|
||||
command["set"](old_value, device, sim = False, remove = remove)
|
||||
self._storage_unset(instance, command, device)
|
||||
|
||||
def _cleanup_non_device_command(self, instance, command):
|
||||
|
|
@ -615,5 +615,5 @@ class Plugin(object):
|
|||
else:
|
||||
old_value = self._storage_get(instance, command)
|
||||
if old_value is not None:
|
||||
command["set"](old_value, sim = False)
|
||||
command["set"](old_value, sim = False, remove = False)
|
||||
self._storage_unset(instance, command)
|
||||
|
|
|
|||
|
|
@ -109,4 +109,4 @@ class Plugin(base.Plugin):
|
|||
def _removed_device_unapply_tuning(self, instance, device_name):
|
||||
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
|
||||
self._instance_unapply_dynamic(instance, device_name)
|
||||
self._cleanup_all_device_commands(instance, [device_name])
|
||||
self._cleanup_all_device_commands(instance, [device_name], remove = True)
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ class Instance(object):
|
|||
def update_tuning(self):
|
||||
self._plugin.instance_update_tuning(self)
|
||||
|
||||
def unapply_tuning(self, full_rollback = consts.ROLLBACK_SOFT):
|
||||
self._plugin.instance_unapply_tuning(self, full_rollback)
|
||||
def unapply_tuning(self, rollback = consts.ROLLBACK_SOFT):
|
||||
self._plugin.instance_unapply_tuning(self, rollback)
|
||||
|
||||
def destroy(self):
|
||||
self.unapply_tuning()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import tuned.logs
|
|||
from tuned.utils.commands import commands
|
||||
|
||||
import os
|
||||
import errno
|
||||
import struct
|
||||
import glob
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ class AudioPlugin(hotplug.Plugin):
|
|||
return "/sys/module/%s/parameters/power_save_controller" % device
|
||||
|
||||
@command_set("timeout", per_device = True)
|
||||
def _set_timeout(self, value, device, sim):
|
||||
def _set_timeout(self, value, device, sim, remove):
|
||||
try:
|
||||
timeout = int(value)
|
||||
except ValueError:
|
||||
|
|
@ -82,7 +83,8 @@ class AudioPlugin(hotplug.Plugin):
|
|||
if timeout >= 0:
|
||||
sys_file = self._timeout_path(device)
|
||||
if not sim:
|
||||
cmd.write_to_file(sys_file, "%d" % timeout)
|
||||
cmd.write_to_file(sys_file, "%d" % timeout, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return timeout
|
||||
else:
|
||||
return None
|
||||
|
|
@ -96,12 +98,13 @@ class AudioPlugin(hotplug.Plugin):
|
|||
return None
|
||||
|
||||
@command_set("reset_controller", per_device = True)
|
||||
def _set_reset_controller(self, value, device, sim):
|
||||
def _set_reset_controller(self, value, device, sim, remove):
|
||||
v = cmd.get_bool(value)
|
||||
sys_file = self._reset_controller_path(device)
|
||||
if os.path.exists(sys_file):
|
||||
if not sim:
|
||||
cmd.write_to_file(sys_file, v)
|
||||
cmd.write_to_file(sys_file, v, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return v
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ class BootloaderPlugin(base.Plugin):
|
|||
log.info("cannot find grub.cfg to patch")
|
||||
return
|
||||
for f in self._grub2_cfg_file_names:
|
||||
self._cmd.add_modify_option_in_file(f, {"set\s+" + consts.GRUB2_TUNED_VAR : "", "set\s+" + consts.GRUB2_TUNED_INITRD_VAR : ""}, add = False)
|
||||
self._cmd.add_modify_option_in_file(f, {r"set\s+" + consts.GRUB2_TUNED_VAR : "", r"set\s+" + consts.GRUB2_TUNED_INITRD_VAR : ""}, add = False)
|
||||
if self._initrd_dst_img_val is not None:
|
||||
log.info("removing initrd image '%s'" % self._initrd_dst_img_val)
|
||||
self._cmd.unlink(self._initrd_dst_img_val)
|
||||
|
|
@ -391,8 +391,8 @@ class BootloaderPlugin(base.Plugin):
|
|||
self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended))
|
||||
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
if full_rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
|
||||
if self._rpm_ostree:
|
||||
log.info("removing rpm-ostree tuning previously added by Tuned")
|
||||
self._remove_rpm_ostree_tuning()
|
||||
|
|
@ -403,9 +403,9 @@ class BootloaderPlugin(base.Plugin):
|
|||
|
||||
def _grub2_cfg_unpatch(self, grub2_cfg):
|
||||
log.debug("unpatching grub.cfg")
|
||||
cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_VAR + "\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
|
||||
cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_VAR + "\\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
|
||||
grub2_cfg = re.sub(r" *\$" + consts.GRUB2_TUNED_VAR, "", cfg, flags = re.MULTILINE)
|
||||
cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_INITRD_VAR + "\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
|
||||
cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_INITRD_VAR + "\\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
|
||||
grub2_cfg = re.sub(r" *\$" + consts.GRUB2_TUNED_INITRD_VAR, "", cfg, flags = re.MULTILINE)
|
||||
cfg = re.sub(consts.GRUB2_TEMPLATE_HEADER_BEGIN + r"\n", "", grub2_cfg, flags = re.MULTILINE)
|
||||
return re.sub(consts.GRUB2_TEMPLATE_HEADER_END + r"\n+", "", cfg, flags = re.MULTILINE)
|
||||
|
|
@ -480,7 +480,7 @@ class BootloaderPlugin(base.Plugin):
|
|||
grub2_cfg_new = grub2_cfg
|
||||
patch_initial = False
|
||||
for opt in d:
|
||||
(grub2_cfg_new, nsubs) = re.subn(r"\b(set\s+" + opt + "\s*=).*$", r"\1" + "\"" + self._cmd.escape(d[opt]) + "\"", grub2_cfg_new, flags = re.MULTILINE)
|
||||
(grub2_cfg_new, nsubs) = re.subn(r"\b(set\s+" + opt + r"\s*=).*$", r"\1" + "\"" + self._cmd.escape(d[opt]) + "\"", grub2_cfg_new, flags = re.MULTILINE)
|
||||
if nsubs < 1 or re.search(r"\$" + opt, grub2_cfg, flags = re.MULTILINE) is None:
|
||||
patch_initial = True
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from tuned.utils.commands import commands
|
|||
import tuned.consts as consts
|
||||
|
||||
import os
|
||||
import errno
|
||||
import struct
|
||||
import errno
|
||||
import platform
|
||||
|
|
@ -81,7 +82,8 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
|
||||
`energy_performance_preference`:::
|
||||
[option]`energy_performance_preference` supports managing energy
|
||||
vs. performance hints on some newer Intel processors. Multiple alternative
|
||||
vs. performance hints on newer Intel and AMD processors with active P-State
|
||||
CPU scaling drivers (intel_pstate or amd-pstate). Multiple alternative
|
||||
Energy Performance Preferences (EPP) values are supported. The alternative
|
||||
values are separated using the '|' character. Available values can be found
|
||||
in `energy_performance_available_preferences` file in `CPUFreq` policy
|
||||
|
|
@ -196,6 +198,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
self._is_amd = False
|
||||
self._has_energy_perf_bias = False
|
||||
self._has_intel_pstate = False
|
||||
self._has_amd_pstate = False
|
||||
self._has_pm_qos_resume_latency_us = None
|
||||
|
||||
self._min_perf_pct_save = None
|
||||
|
|
@ -240,15 +243,15 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
self._arch = platform.machine()
|
||||
|
||||
if self._arch in intel_archs:
|
||||
# Possible other x86 vendors (from arch/x86/kernel/cpu/*):
|
||||
# "CentaurHauls", "CyrixInstead", "Geode by NSC", "HygonGenuine", "GenuineTMx86",
|
||||
# "TransmetaCPU", "UMC UMC UMC"
|
||||
# Possible other x86 vendors (from arch/x86/kernel/cpu/*):
|
||||
# "CentaurHauls", "CyrixInstead", "Geode by NSC", "HygonGenuine", "GenuineTMx86",
|
||||
# "TransmetaCPU", "UMC UMC UMC"
|
||||
cpu = procfs.cpuinfo()
|
||||
vendor = cpu.tags.get("vendor_id")
|
||||
if vendor == "GenuineIntel":
|
||||
self._is_intel = True
|
||||
self._is_intel = True
|
||||
elif vendor == "AuthenticAMD" or vendor == "HygonGenuine":
|
||||
self._is_amd = True
|
||||
self._is_amd = True
|
||||
else:
|
||||
# We always assign Intel, unless we know better
|
||||
self._is_intel = True
|
||||
|
|
@ -256,12 +259,16 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
else:
|
||||
log.info("We are running on %s (non x86)" % self._arch)
|
||||
|
||||
if self._is_intel is True:
|
||||
if self._is_intel:
|
||||
# Check for x86_energy_perf_policy, ignore if not available / supported
|
||||
self._check_energy_perf_bias()
|
||||
# Check for intel_pstate
|
||||
self._check_intel_pstate()
|
||||
|
||||
if self._is_amd:
|
||||
# Check for amd-pstate
|
||||
self._check_amd_pstate()
|
||||
|
||||
def _check_energy_perf_bias(self):
|
||||
self._has_energy_perf_bias = False
|
||||
retcode_unsupported = 1
|
||||
|
|
@ -281,6 +288,11 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
if self._has_intel_pstate:
|
||||
log.info("intel_pstate detected")
|
||||
|
||||
def _check_amd_pstate(self):
|
||||
self._has_amd_pstate = os.path.exists("/sys/devices/system/cpu/amd_pstate")
|
||||
if self._has_amd_pstate:
|
||||
log.info("amd-pstate detected")
|
||||
|
||||
def _get_cpuinfo_flags(self):
|
||||
if self._flags is None:
|
||||
self._flags = procfs.cpuinfo().tags.get("flags", [])
|
||||
|
|
@ -377,8 +389,8 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
self._no_turbo_save = self._getset_intel_pstate_attr(
|
||||
"no_turbo", new_value)
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
super(CPULatencyPlugin, self)._instance_unapply_static(instance, full_rollback)
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
super(CPULatencyPlugin, self)._instance_unapply_static(instance, rollback)
|
||||
|
||||
if instance._first_instance and self._has_intel_pstate:
|
||||
self._set_intel_pstate_attr("min_perf_pct", self._min_perf_pct_save)
|
||||
|
|
@ -489,7 +501,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
return self._cmd.read_file("/sys/devices/system/cpu/%s/cpufreq/scaling_available_governors" % device).strip().split()
|
||||
|
||||
@command_set("governor", per_device=True)
|
||||
def _set_governor(self, governors, device, sim):
|
||||
def _set_governor(self, governors, device, sim, remove):
|
||||
if not self._check_cpu_can_change_governor(device):
|
||||
return None
|
||||
governors = str(governors)
|
||||
|
|
@ -506,7 +518,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
log.info("setting governor '%s' on cpu '%s'"
|
||||
% (governor, device))
|
||||
self._cmd.write_to_file("/sys/devices/system/cpu/%s/cpufreq/scaling_governor"
|
||||
% device, governor)
|
||||
% device, governor, no_error = [errno.ENOENT] if remove else False)
|
||||
break
|
||||
elif not sim:
|
||||
log.debug("Ignoring governor '%s' on cpu '%s', it is not supported"
|
||||
|
|
@ -535,7 +547,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
return "/sys/devices/system/cpu/cpufreq/%s/sampling_down_factor" % governor
|
||||
|
||||
@command_set("sampling_down_factor", per_device = True, priority = 10)
|
||||
def _set_sampling_down_factor(self, sampling_down_factor, device, sim):
|
||||
def _set_sampling_down_factor(self, sampling_down_factor, device, sim, remove):
|
||||
val = None
|
||||
|
||||
# hack to clear governors map when the profile starts unloading
|
||||
|
|
@ -558,7 +570,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
val = str(sampling_down_factor)
|
||||
if not sim:
|
||||
log.info("setting sampling_down_factor to '%s' for governor '%s'" % (val, governor))
|
||||
self._cmd.write_to_file(path, val)
|
||||
self._cmd.write_to_file(path, val, no_error = [errno.ENOENT] if remove else False)
|
||||
return val
|
||||
|
||||
@command_get("sampling_down_factor")
|
||||
|
|
@ -580,14 +592,14 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
return_err = True)
|
||||
return (retcode, err_msg)
|
||||
|
||||
def _intel_preference_path(self, cpu_id, available = False):
|
||||
def _pstate_preference_path(self, cpu_id, available = False):
|
||||
return "/sys/devices/system/cpu/cpufreq/policy%s/energy_performance_%s" % (cpu_id, "available_preferences" if available else "preference")
|
||||
|
||||
def _energy_perf_bias_path(self, cpu_id):
|
||||
return "/sys/devices/system/cpu/cpu%s/power/energy_perf_bias" % cpu_id
|
||||
|
||||
@command_set("energy_perf_bias", per_device=True)
|
||||
def _set_energy_perf_bias(self, energy_perf_bias, device, sim):
|
||||
def _set_energy_perf_bias(self, energy_perf_bias, device, sim, remove):
|
||||
if not self._is_cpu_online(device):
|
||||
log.debug("%s is not online, skipping" % device)
|
||||
return None
|
||||
|
|
@ -602,10 +614,11 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
if not sim:
|
||||
for val in vals:
|
||||
val = val.strip()
|
||||
if self._cmd.write_to_file(energy_perf_bias_path, val):
|
||||
log.info("energy_perf_bias successfully set to '%s' on cpu '%s'"
|
||||
% (val, device))
|
||||
break
|
||||
if self._cmd.write_to_file(energy_perf_bias_path, val, \
|
||||
no_error = [errno.ENOENT] if remove else False):
|
||||
log.info("energy_perf_bias successfully set to '%s' on cpu '%s'"
|
||||
% (val, device))
|
||||
break
|
||||
else:
|
||||
log.error("Failed to set energy_perf_bias on cpu '%s'. Is the value in the profile correct?"
|
||||
% device)
|
||||
|
|
@ -700,7 +713,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
return self._has_pm_qos_resume_latency_us
|
||||
|
||||
@command_set("pm_qos_resume_latency_us", per_device=True)
|
||||
def _set_pm_qos_resume_latency_us(self, pm_qos_resume_latency_us, device, sim):
|
||||
def _set_pm_qos_resume_latency_us(self, pm_qos_resume_latency_us, device, sim, remove):
|
||||
if not self._is_cpu_online(device):
|
||||
log.debug("%s is not online, skipping" % device)
|
||||
return None
|
||||
|
|
@ -718,7 +731,8 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
if not self._check_pm_qos_resume_latency_us(device):
|
||||
return None
|
||||
if not sim:
|
||||
self._cmd.write_to_file(self._pm_qos_resume_latency_us_path(device), latency)
|
||||
self._cmd.write_to_file(self._pm_qos_resume_latency_us_path(device), latency, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return latency
|
||||
|
||||
@command_get("pm_qos_resume_latency_us")
|
||||
|
|
@ -731,18 +745,19 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
return self._cmd.read_file(self._pm_qos_resume_latency_us_path(device), no_error=ignore_missing).strip()
|
||||
|
||||
@command_set("energy_performance_preference", per_device=True)
|
||||
def _set_energy_performance_preference(self, energy_performance_preference, device, sim):
|
||||
def _set_energy_performance_preference(self, energy_performance_preference, device, sim, remove):
|
||||
if not self._is_cpu_online(device):
|
||||
log.debug("%s is not online, skipping" % device)
|
||||
return None
|
||||
cpu_id = device.lstrip("cpu")
|
||||
if os.path.exists(self._intel_preference_path(cpu_id, True)):
|
||||
if os.path.exists(self._pstate_preference_path(cpu_id, True)):
|
||||
vals = energy_performance_preference.split('|')
|
||||
if not sim:
|
||||
avail_vals = set(self._cmd.read_file(self._intel_preference_path(cpu_id, True)).split())
|
||||
avail_vals = set(self._cmd.read_file(self._pstate_preference_path(cpu_id, True)).split())
|
||||
for val in vals:
|
||||
if val in avail_vals:
|
||||
self._cmd.write_to_file(self._intel_preference_path(cpu_id), val)
|
||||
self._cmd.write_to_file(self._pstate_preference_path(cpu_id), val, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
log.info("Setting energy_performance_preference value '%s' for cpu '%s'" % (val, device))
|
||||
break
|
||||
else:
|
||||
|
|
@ -752,7 +767,7 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
% device)
|
||||
return str(energy_performance_preference)
|
||||
else:
|
||||
log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without the intel_pstate driver.")
|
||||
log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without a P-state driver.")
|
||||
return None
|
||||
|
||||
@command_get("energy_performance_preference")
|
||||
|
|
@ -761,9 +776,9 @@ class CPULatencyPlugin(hotplug.Plugin):
|
|||
log.debug("%s is not online, skipping" % device)
|
||||
return None
|
||||
cpu_id = device.lstrip("cpu")
|
||||
# intel_pstate CPU scaling driver
|
||||
if os.path.exists(self._intel_preference_path(cpu_id, True)):
|
||||
return self._cmd.read_file(self._intel_preference_path(cpu_id)).strip()
|
||||
# read the EPP hint used by the intel_pstate and amd-pstate CPU scaling drivers
|
||||
if os.path.exists(self._pstate_preference_path(cpu_id, True)):
|
||||
return self._cmd.read_file(self._pstate_preference_path(cpu_id)).strip()
|
||||
else:
|
||||
log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without the intel_pstate driver.")
|
||||
log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without a P-state driver.")
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -335,10 +335,11 @@ class DiskPlugin(hotplug.Plugin):
|
|||
return self._sysfs_path(device, "queue/scheduler")
|
||||
|
||||
@command_set("elevator", per_device=True)
|
||||
def _set_elevator(self, value, device, sim):
|
||||
def _set_elevator(self, value, device, sim, remove):
|
||||
sys_file = self._elevator_file(device)
|
||||
if not sim:
|
||||
self._cmd.write_to_file(sys_file, value)
|
||||
self._cmd.write_to_file(sys_file, value, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return value
|
||||
|
||||
@command_get("elevator")
|
||||
|
|
@ -349,7 +350,7 @@ class DiskPlugin(hotplug.Plugin):
|
|||
return self._cmd.get_active_option(self._cmd.read_file(sys_file, no_error=ignore_missing))
|
||||
|
||||
@command_set("apm", per_device=True)
|
||||
def _set_apm(self, value, device, sim):
|
||||
def _set_apm(self, value, device, sim, remove):
|
||||
if device not in self._hdparm_apm_devices:
|
||||
if not sim:
|
||||
log.info("apm option is not supported for device '%s'" % device)
|
||||
|
|
@ -389,7 +390,7 @@ class DiskPlugin(hotplug.Plugin):
|
|||
return value
|
||||
|
||||
@command_set("spindown", per_device=True)
|
||||
def _set_spindown(self, value, device, sim):
|
||||
def _set_spindown(self, value, device, sim, remove):
|
||||
if device not in self._hdparm_apm_devices:
|
||||
if not sim:
|
||||
log.info("spindown option is not supported for device '%s'" % device)
|
||||
|
|
@ -428,14 +429,15 @@ class DiskPlugin(hotplug.Plugin):
|
|||
return v
|
||||
|
||||
@command_set("readahead", per_device=True)
|
||||
def _set_readahead(self, value, device, sim):
|
||||
def _set_readahead(self, value, device, sim, remove):
|
||||
sys_file = self._readahead_file(device)
|
||||
val = self._parse_ra(value)
|
||||
if val is None:
|
||||
log.error("Invalid readahead value '%s' for device '%s'" % (value, device))
|
||||
else:
|
||||
if not sim:
|
||||
self._cmd.write_to_file(sys_file, "%d" % val)
|
||||
self._cmd.write_to_file(sys_file, "%d" % val, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return val
|
||||
|
||||
@command_get("readahead")
|
||||
|
|
@ -471,10 +473,11 @@ class DiskPlugin(hotplug.Plugin):
|
|||
return self._sysfs_path(device, "queue/iosched/quantum")
|
||||
|
||||
@command_set("scheduler_quantum", per_device=True)
|
||||
def _set_scheduler_quantum(self, value, device, sim):
|
||||
def _set_scheduler_quantum(self, value, device, sim, remove):
|
||||
sys_file = self._scheduler_quantum_file(device)
|
||||
if not sim:
|
||||
self._cmd.write_to_file(sys_file, "%d" % int(value))
|
||||
self._cmd.write_to_file(sys_file, "%d" % int(value), \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return value
|
||||
|
||||
@command_get("scheduler_quantum")
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ class ModulesPlugin(base.Plugin):
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
if full_rollback == consts.ROLLBACK_FULL:
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
if rollback == consts.ROLLBACK_FULL:
|
||||
self._clear_modprobe_file()
|
||||
|
||||
def _clear_modprobe_file(self):
|
||||
|
|
|
|||
|
|
@ -329,6 +329,8 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
# parse features/coalesce config parameters (those defined in profile configuration)
|
||||
# context is for error message
|
||||
def _parse_config_parameters(self, value, context):
|
||||
# expand config variables
|
||||
value = self._variables.expand(value)
|
||||
# split supporting various dellimeters
|
||||
v = str(re.sub(r"(:\s*)|(\s+)|(\s*;\s*)|(\s*,\s*)", " ", value)).split()
|
||||
lv = len(v)
|
||||
|
|
@ -347,7 +349,7 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
# (rhbz#1225375)
|
||||
value = self._cmd.multiple_re_replace({
|
||||
"Adaptive RX:": "adaptive-rx:",
|
||||
"\s+TX:": "\nadaptive-tx:",
|
||||
"\\s+TX:": "\nadaptive-tx:",
|
||||
"rx-frame-low:": "rx-frames-low:",
|
||||
"rx-frame-high:": "rx-frames-high:",
|
||||
"tx-frame-low:": "tx-frames-low:",
|
||||
|
|
@ -366,7 +368,7 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
"receive-hashing:": "rxhash:",
|
||||
}, value)
|
||||
# remove empty lines, remove fixed parameters (those with "[fixed]")
|
||||
vl = [v for v in value.split('\n') if len(str(v)) > 0 and not re.search("\[fixed\]$", str(v))]
|
||||
vl = [v for v in value.split('\n') if len(str(v)) > 0 and not re.search(r"\[fixed\]$", str(v))]
|
||||
if len(vl) < 2:
|
||||
return None
|
||||
# skip first line (device name), split to key/value,
|
||||
|
|
@ -378,7 +380,7 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
return "/sys/module/nf_conntrack/parameters/hashsize"
|
||||
|
||||
@command_set("wake_on_lan", per_device=True)
|
||||
def _set_wake_on_lan(self, value, device, sim):
|
||||
def _set_wake_on_lan(self, value, device, sim, remove):
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
|
|
@ -404,14 +406,15 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
return value
|
||||
|
||||
@command_set("nf_conntrack_hashsize")
|
||||
def _set_nf_conntrack_hashsize(self, value, sim):
|
||||
def _set_nf_conntrack_hashsize(self, value, sim, remove):
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
hashsize = int(value)
|
||||
if hashsize >= 0:
|
||||
if not sim:
|
||||
self._cmd.write_to_file(self._nf_conntrack_hashsize_path(), hashsize)
|
||||
self._cmd.write_to_file(self._nf_conntrack_hashsize_path(), hashsize, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return hashsize
|
||||
else:
|
||||
return None
|
||||
|
|
@ -445,7 +448,7 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
return self._call_ip_link(args)
|
||||
|
||||
@command_set("txqueuelen", per_device=True)
|
||||
def _set_txqueuelen(self, value, device, sim):
|
||||
def _set_txqueuelen(self, value, device, sim, remove):
|
||||
if value is None:
|
||||
return None
|
||||
try:
|
||||
|
|
@ -485,7 +488,7 @@ class NetTuningPlugin(hotplug.Plugin):
|
|||
return res.group(1)
|
||||
|
||||
@command_set("mtu", per_device=True)
|
||||
def _set_mtu(self, value, device, sim):
|
||||
def _set_mtu(self, value, device, sim, remove):
|
||||
if value is None:
|
||||
return None
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ class SchedulerUtilsSchedutils(SchedulerUtils):
|
|||
return schedutils.get_priority_max(sched)
|
||||
|
||||
class SchedulerPlugin(base.Plugin):
|
||||
"""
|
||||
r"""
|
||||
`scheduler`::
|
||||
|
||||
Allows tuning of scheduling priorities, process/thread/IRQ
|
||||
|
|
@ -1003,8 +1003,8 @@ class SchedulerPlugin(base.Plugin):
|
|||
for cg in self._cgroups:
|
||||
self._cgroup_cleanup_tasks_one(cg)
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
super(SchedulerPlugin, self)._instance_unapply_static(instance, full_rollback)
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
super(SchedulerPlugin, self)._instance_unapply_static(instance, rollback)
|
||||
if self._daemon and instance._runtime_tuning:
|
||||
instance._terminate.set()
|
||||
instance._thread.join()
|
||||
|
|
@ -1414,12 +1414,13 @@ class SchedulerPlugin(base.Plugin):
|
|||
self._secure_boot_hint = False
|
||||
return data
|
||||
|
||||
def _set_sched_knob(self, prefix, namespace, knob, value, sim):
|
||||
def _set_sched_knob(self, prefix, namespace, knob, value, sim, remove = False):
|
||||
if value is None:
|
||||
return None
|
||||
if not sim:
|
||||
if not self._cmd.write_to_file(self._get_sched_knob_path(prefix, namespace, knob), value):
|
||||
log.error("Error writing value '%s' to '%s'" % (value, knob))
|
||||
if not self._cmd.write_to_file(self._get_sched_knob_path(prefix, namespace, knob), value, \
|
||||
no_error = [errno.ENOENT] if remove else False):
|
||||
log.error("Error writing value '%s' to '%s'" % (value, knob))
|
||||
return value
|
||||
|
||||
@command_get("sched_min_granularity_ns")
|
||||
|
|
@ -1427,77 +1428,77 @@ class SchedulerPlugin(base.Plugin):
|
|||
return self._get_sched_knob("", "sched", "min_granularity_ns")
|
||||
|
||||
@command_set("sched_min_granularity_ns")
|
||||
def _set_sched_min_granularity_ns(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "min_granularity_ns", value, sim)
|
||||
def _set_sched_min_granularity_ns(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "min_granularity_ns", value, sim, remove)
|
||||
|
||||
@command_get("sched_latency_ns")
|
||||
def _get_sched_latency_ns(self):
|
||||
return self._get_sched_knob("", "sched", "latency_ns")
|
||||
|
||||
@command_set("sched_latency_ns")
|
||||
def _set_sched_latency_ns(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "latency_ns", value, sim)
|
||||
def _set_sched_latency_ns(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "latency_ns", value, sim, remove)
|
||||
|
||||
@command_get("sched_wakeup_granularity_ns")
|
||||
def _get_sched_wakeup_granularity_ns(self):
|
||||
return self._get_sched_knob("", "sched", "wakeup_granularity_ns")
|
||||
|
||||
@command_set("sched_wakeup_granularity_ns")
|
||||
def _set_sched_wakeup_granularity_ns(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "wakeup_granularity_ns", value, sim)
|
||||
def _set_sched_wakeup_granularity_ns(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "wakeup_granularity_ns", value, sim, remove)
|
||||
|
||||
@command_get("sched_tunable_scaling")
|
||||
def _get_sched_tunable_scaling(self):
|
||||
return self._get_sched_knob("", "sched", "tunable_scaling")
|
||||
|
||||
@command_set("sched_tunable_scaling")
|
||||
def _set_sched_tunable_scaling(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "tunable_scaling", value, sim)
|
||||
def _set_sched_tunable_scaling(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "tunable_scaling", value, sim, remove)
|
||||
|
||||
@command_get("sched_migration_cost_ns")
|
||||
def _get_sched_migration_cost_ns(self):
|
||||
return self._get_sched_knob("", "sched", "migration_cost_ns")
|
||||
|
||||
@command_set("sched_migration_cost_ns")
|
||||
def _set_sched_migration_cost_ns(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "migration_cost_ns", value, sim)
|
||||
def _set_sched_migration_cost_ns(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "migration_cost_ns", value, sim, remove)
|
||||
|
||||
@command_get("sched_nr_migrate")
|
||||
def _get_sched_nr_migrate(self):
|
||||
return self._get_sched_knob("", "sched", "nr_migrate")
|
||||
|
||||
@command_set("sched_nr_migrate")
|
||||
def _set_sched_nr_migrate(self, value, sim):
|
||||
return self._set_sched_knob("", "sched", "nr_migrate", value, sim)
|
||||
def _set_sched_nr_migrate(self, value, sim, remove):
|
||||
return self._set_sched_knob("", "sched", "nr_migrate", value, sim, remove)
|
||||
|
||||
@command_get("numa_balancing_scan_delay_ms")
|
||||
def _get_numa_balancing_scan_delay_ms(self):
|
||||
return self._get_sched_knob("sched", "numa_balancing", "scan_delay_ms")
|
||||
|
||||
@command_set("numa_balancing_scan_delay_ms")
|
||||
def _set_numa_balancing_scan_delay_ms(self, value, sim):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_delay_ms", value, sim)
|
||||
def _set_numa_balancing_scan_delay_ms(self, value, sim, remove):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_delay_ms", value, sim, remove)
|
||||
|
||||
@command_get("numa_balancing_scan_period_min_ms")
|
||||
def _get_numa_balancing_scan_period_min_ms(self):
|
||||
return self._get_sched_knob("sched", "numa_balancing", "scan_period_min_ms")
|
||||
|
||||
@command_set("numa_balancing_scan_period_min_ms")
|
||||
def _set_numa_balancing_scan_period_min_ms(self, value, sim):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_period_min_ms", value, sim)
|
||||
def _set_numa_balancing_scan_period_min_ms(self, value, sim, remove):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_period_min_ms", value, sim, remove)
|
||||
|
||||
@command_get("numa_balancing_scan_period_max_ms")
|
||||
def _get_numa_balancing_scan_period_max_ms(self):
|
||||
return self._get_sched_knob("sched", "numa_balancing", "scan_period_max_ms")
|
||||
|
||||
@command_set("numa_balancing_scan_period_max_ms")
|
||||
def _set_numa_balancing_scan_period_max_ms(self, value, sim):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_period_max_ms", value, sim)
|
||||
def _set_numa_balancing_scan_period_max_ms(self, value, sim, remove):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_period_max_ms", value, sim, remove)
|
||||
|
||||
@command_get("numa_balancing_scan_size_mb")
|
||||
def _get_numa_balancing_scan_size_mb(self):
|
||||
return self._get_sched_knob("sched", "numa_balancing", "scan_size_mb")
|
||||
|
||||
@command_set("numa_balancing_scan_size_mb")
|
||||
def _set_numa_balancing_scan_size_mb(self, value, sim):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_size_mb", value, sim)
|
||||
def _set_numa_balancing_scan_size_mb(self, value, sim, remove):
|
||||
return self._set_sched_knob("sched", "numa_balancing", "scan_size_mb", value, sim, remove)
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@ class ScriptPlugin(base.Plugin):
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
args = ["stop"]
|
||||
if full_rollback == consts.ROLLBACK_FULL:
|
||||
if rollback == consts.ROLLBACK_FULL:
|
||||
args = args + ["full_rollback"]
|
||||
self._call_scripts(reversed(instance._scripts), args)
|
||||
super(ScriptPlugin, self)._instance_unapply_static(instance, full_rollback)
|
||||
super(ScriptPlugin, self)._instance_unapply_static(instance, rollback)
|
||||
|
|
|
|||
|
|
@ -86,13 +86,14 @@ class SCSIHostPlugin(hotplug.Plugin):
|
|||
return os.path.join("/sys/class/scsi_host/", str(device), "link_power_management_policy")
|
||||
|
||||
@command_set("alpm", per_device = True)
|
||||
def _set_alpm(self, policy, device, sim):
|
||||
def _set_alpm(self, policy, device, sim, remove):
|
||||
if policy is None:
|
||||
return None
|
||||
policy_file = self._get_alpm_policy_file(device)
|
||||
if not sim:
|
||||
if os.path.exists(policy_file):
|
||||
self._cmd.write_to_file(policy_file, policy)
|
||||
self._cmd.write_to_file(policy_file, policy, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
else:
|
||||
log.info("ALPM control file ('%s') not found, skipping ALPM setting for '%s'" % (policy_file, str(device)))
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import errno
|
||||
from . import base
|
||||
from .decorators import *
|
||||
import tuned.logs
|
||||
|
|
@ -63,13 +64,14 @@ class SelinuxPlugin(base.Plugin):
|
|||
pass
|
||||
|
||||
@command_set("avc_cache_threshold")
|
||||
def _set_avc_cache_threshold(self, value, sim):
|
||||
def _set_avc_cache_threshold(self, value, sim, remove):
|
||||
if value is None:
|
||||
return None
|
||||
threshold = int(value)
|
||||
if threshold >= 0:
|
||||
if not sim:
|
||||
self._cmd.write_to_file(self._cache_threshold_path, threshold)
|
||||
self._cmd.write_to_file(self._cache_threshold_path, threshold, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return threshold
|
||||
else:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ class ServicePlugin(base.Plugin):
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
for name, value in list(instance._services_original.items()):
|
||||
if value.cfg_file:
|
||||
self._init_handler.cfg_uninstall(name, value.cfg_file)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class SysctlPlugin(base.Plugin):
|
|||
|
||||
def _instance_apply_static(self, instance):
|
||||
for option, value in list(instance._sysctl.items()):
|
||||
original_value = _read_sysctl(option)
|
||||
original_value = self._read_sysctl(option)
|
||||
if original_value is None:
|
||||
log.error("sysctl option %s will not be set, failed to read the original value."
|
||||
% option)
|
||||
|
|
@ -77,130 +77,134 @@ class SysctlPlugin(base.Plugin):
|
|||
new_value, original_value)
|
||||
if new_value is not None:
|
||||
instance._sysctl_original[option] = original_value
|
||||
_write_sysctl(option, new_value)
|
||||
self._write_sysctl(option, new_value)
|
||||
|
||||
storage_key = self._storage_key(instance.name)
|
||||
self._storage.set(storage_key, instance._sysctl_original)
|
||||
|
||||
if self._global_cfg.get_bool(consts.CFG_REAPPLY_SYSCTL, consts.CFG_DEF_REAPPLY_SYSCTL):
|
||||
log.info("reapplying system sysctl")
|
||||
_apply_system_sysctl(instance._sysctl)
|
||||
self._apply_system_sysctl(instance._sysctl)
|
||||
|
||||
def _instance_verify_static(self, instance, ignore_missing, devices):
|
||||
ret = True
|
||||
# override, so always skip missing
|
||||
ignore_missing = True
|
||||
for option, value in list(instance._sysctl.items()):
|
||||
curr_val = _read_sysctl(option)
|
||||
curr_val = self._read_sysctl(option)
|
||||
value = self._process_assignment_modifiers(self._variables.expand(value), curr_val)
|
||||
if value is not None:
|
||||
if self._verify_value(option, self._cmd.remove_ws(value), self._cmd.remove_ws(curr_val), ignore_missing) == False:
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
for option, value in list(instance._sysctl_original.items()):
|
||||
_write_sysctl(option, value)
|
||||
self._write_sysctl(option, value)
|
||||
|
||||
|
||||
def _apply_system_sysctl(instance_sysctl):
|
||||
files = {}
|
||||
for d in SYSCTL_CONFIG_DIRS:
|
||||
try:
|
||||
flist = os.listdir(d)
|
||||
except OSError:
|
||||
continue
|
||||
for fname in flist:
|
||||
if not fname.endswith(".conf"):
|
||||
def _apply_system_sysctl(self, instance_sysctl):
|
||||
files = {}
|
||||
for d in SYSCTL_CONFIG_DIRS:
|
||||
try:
|
||||
flist = os.listdir(d)
|
||||
except OSError:
|
||||
continue
|
||||
if fname not in files:
|
||||
files[fname] = d
|
||||
for fname in flist:
|
||||
if not fname.endswith(".conf"):
|
||||
continue
|
||||
if fname not in files:
|
||||
files[fname] = d
|
||||
|
||||
for fname in sorted(files.keys()):
|
||||
d = files[fname]
|
||||
path = "%s/%s" % (d, fname)
|
||||
_apply_sysctl_config_file(path, instance_sysctl)
|
||||
_apply_sysctl_config_file("/etc/sysctl.conf", instance_sysctl)
|
||||
for fname in sorted(files.keys()):
|
||||
d = files[fname]
|
||||
path = "%s/%s" % (d, fname)
|
||||
self._apply_sysctl_config_file(path, instance_sysctl)
|
||||
self._apply_sysctl_config_file("/etc/sysctl.conf", instance_sysctl)
|
||||
|
||||
def _apply_sysctl_config_file(path, instance_sysctl):
|
||||
log.debug("Applying sysctl settings from file %s" % path)
|
||||
try:
|
||||
with open(path, "r") as f:
|
||||
for lineno, line in enumerate(f, 1):
|
||||
_apply_sysctl_config_line(path, lineno, line, instance_sysctl)
|
||||
log.debug("Finished applying sysctl settings from file %s"
|
||||
% path)
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
log.error("Error reading sysctl settings from file %s: %s"
|
||||
% (path, str(e)))
|
||||
def _apply_sysctl_config_file(self, path, instance_sysctl):
|
||||
log.debug("Applying sysctl settings from file %s" % path)
|
||||
try:
|
||||
with open(path, "r") as f:
|
||||
for lineno, line in enumerate(f, 1):
|
||||
self._apply_sysctl_config_line(path, lineno, line, instance_sysctl)
|
||||
log.debug("Finished applying sysctl settings from file %s"
|
||||
% path)
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
log.error("Error reading sysctl settings from file %s: %s"
|
||||
% (path, str(e)))
|
||||
|
||||
def _apply_sysctl_config_line(path, lineno, line, instance_sysctl):
|
||||
line = line.strip()
|
||||
if len(line) == 0 or line[0] == "#" or line[0] == ";":
|
||||
return
|
||||
tmp = line.split("=", 1)
|
||||
if len(tmp) != 2:
|
||||
log.error("Syntax error in file %s, line %d"
|
||||
% (path, lineno))
|
||||
return
|
||||
option, value = tmp
|
||||
option = option.strip()
|
||||
if len(option) == 0:
|
||||
log.error("Syntax error in file %s, line %d"
|
||||
% (path, lineno))
|
||||
return
|
||||
value = value.strip()
|
||||
if option in instance_sysctl and instance_sysctl[option] != value:
|
||||
log.info("Overriding sysctl parameter '%s' from '%s' to '%s'"
|
||||
% (option, instance_sysctl[option], value))
|
||||
def _apply_sysctl_config_line(self, path, lineno, line, instance_sysctl):
|
||||
line = line.strip()
|
||||
if len(line) == 0 or line[0] == "#" or line[0] == ";":
|
||||
return
|
||||
tmp = line.split("=", 1)
|
||||
if len(tmp) != 2:
|
||||
log.error("Syntax error in file %s, line %d"
|
||||
% (path, lineno))
|
||||
return
|
||||
option, value = tmp
|
||||
option = option.strip()
|
||||
if len(option) == 0:
|
||||
log.error("Syntax error in file %s, line %d"
|
||||
% (path, lineno))
|
||||
return
|
||||
value = value.strip()
|
||||
if option in instance_sysctl:
|
||||
instance_value = self._variables.expand(instance_sysctl[option])
|
||||
if instance_value != value:
|
||||
log.info("Overriding sysctl parameter '%s' from '%s' to '%s'"
|
||||
% (option, instance_value, value))
|
||||
self._write_sysctl(option, value, ignore_missing = True)
|
||||
|
||||
_write_sysctl(option, value, ignore_missing = True)
|
||||
def _get_sysctl_path(self, option):
|
||||
# The sysctl name in sysctl tool and in /proc/sys differs.
|
||||
# All dots (.) in sysctl name are represented by /proc/sys
|
||||
# directories and all slashes in the name (/) are converted
|
||||
# to dots (.) in the /proc/sys filenames.
|
||||
return "/proc/sys/%s" % self._cmd.tr(option, "./", "/.")
|
||||
|
||||
def _get_sysctl_path(option):
|
||||
return "/proc/sys/%s" % option.replace(".", "/")
|
||||
|
||||
def _read_sysctl(option):
|
||||
path = _get_sysctl_path(option)
|
||||
try:
|
||||
with open(path, "r") as f:
|
||||
line = ""
|
||||
for i, line in enumerate(f):
|
||||
if i > 0:
|
||||
log.error("Failed to read sysctl parameter '%s', multi-line values are unsupported"
|
||||
% option)
|
||||
return None
|
||||
value = line.strip()
|
||||
log.debug("Value of sysctl parameter '%s' is '%s'"
|
||||
% (option, value))
|
||||
return value
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
log.error("Failed to read sysctl parameter '%s', the parameter does not exist"
|
||||
% option)
|
||||
else:
|
||||
log.error("Failed to read sysctl parameter '%s': %s"
|
||||
% (option, str(e)))
|
||||
return None
|
||||
|
||||
def _write_sysctl(option, value, ignore_missing = False):
|
||||
path = _get_sysctl_path(option)
|
||||
if os.path.basename(path) in DEPRECATED_SYSCTL_OPTIONS:
|
||||
log.error("Refusing to set deprecated sysctl option %s"
|
||||
% option)
|
||||
return False
|
||||
try:
|
||||
log.debug("Setting sysctl parameter '%s' to '%s'"
|
||||
% (option, value))
|
||||
with open(path, "w") as f:
|
||||
f.write(value)
|
||||
return True
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
log_func = log.debug if ignore_missing else log.error
|
||||
log_func("Failed to set sysctl parameter '%s' to '%s', the parameter does not exist"
|
||||
def _read_sysctl(self, option):
|
||||
path = self._get_sysctl_path(option)
|
||||
try:
|
||||
with open(path, "r") as f:
|
||||
line = ""
|
||||
for i, line in enumerate(f):
|
||||
if i > 0:
|
||||
log.error("Failed to read sysctl parameter '%s', multi-line values are unsupported"
|
||||
% option)
|
||||
return None
|
||||
value = line.strip()
|
||||
log.debug("Value of sysctl parameter '%s' is '%s'"
|
||||
% (option, value))
|
||||
else:
|
||||
log.error("Failed to set sysctl parameter '%s' to '%s': %s"
|
||||
% (option, value, str(e)))
|
||||
return False
|
||||
return value
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
log.error("Failed to read sysctl parameter '%s', the parameter does not exist"
|
||||
% option)
|
||||
else:
|
||||
log.error("Failed to read sysctl parameter '%s': %s"
|
||||
% (option, str(e)))
|
||||
return None
|
||||
|
||||
def _write_sysctl(self, option, value, ignore_missing = False):
|
||||
path = self._get_sysctl_path(option)
|
||||
if os.path.basename(path) in DEPRECATED_SYSCTL_OPTIONS:
|
||||
log.error("Refusing to set deprecated sysctl option %s"
|
||||
% option)
|
||||
return False
|
||||
try:
|
||||
log.debug("Setting sysctl parameter '%s' to '%s'"
|
||||
% (option, value))
|
||||
with open(path, "w") as f:
|
||||
f.write(value)
|
||||
return True
|
||||
except (OSError, IOError) as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
log_func = log.debug if ignore_missing else log.error
|
||||
log_func("Failed to set sysctl parameter '%s' to '%s', the parameter does not exist"
|
||||
% (option, value))
|
||||
else:
|
||||
log.error("Failed to set sysctl parameter '%s' to '%s': %s"
|
||||
% (option, value, str(e)))
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class SysfsPlugin(base.Plugin):
|
|||
ret = False
|
||||
return ret
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
for key, value in list(instance._sysfs_original.items()):
|
||||
self._write_sysfs(key, value)
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ class SystemdPlugin(base.Plugin):
|
|||
conf = self._add_keyval(conf, consts.SYSTEMD_CPUAFFINITY_VAR, cpu_affinity_saved)
|
||||
self._write_systemd_system_conf(conf)
|
||||
|
||||
def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
|
||||
if full_rollback == consts.ROLLBACK_FULL:
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
if rollback == consts.ROLLBACK_FULL:
|
||||
log.info("removing '%s' systemd tuning previously added by TuneD" % consts.SYSTEMD_CPUAFFINITY_VAR)
|
||||
self._remove_systemd_tuning()
|
||||
log.console("you may need to manualy run 'dracut -f' to update the systemd configuration in initrd image")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from .decorators import *
|
|||
import tuned.logs
|
||||
from tuned.utils.commands import commands
|
||||
import glob
|
||||
import errno
|
||||
|
||||
log = tuned.logs.get()
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ class USBPlugin(base.Plugin):
|
|||
return "/sys/bus/usb/devices/%s/power/autosuspend" % device
|
||||
|
||||
@command_set("autosuspend", per_device=True)
|
||||
def _set_autosuspend(self, value, device, sim):
|
||||
def _set_autosuspend(self, value, device, sim, remove):
|
||||
enable = self._option_bool(value)
|
||||
if enable is None:
|
||||
return None
|
||||
|
|
@ -65,7 +66,8 @@ class USBPlugin(base.Plugin):
|
|||
val = "1" if enable else "0"
|
||||
if not sim:
|
||||
sys_file = self._autosuspend_sysfile(device)
|
||||
self._cmd.write_to_file(sys_file, val)
|
||||
self._cmd.write_to_file(sys_file, val, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return val
|
||||
|
||||
@command_get("autosuspend")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from .decorators import *
|
|||
import tuned.logs
|
||||
from tuned.utils.commands import commands
|
||||
import os
|
||||
import errno
|
||||
import re
|
||||
|
||||
log = tuned.logs.get()
|
||||
|
|
@ -76,7 +77,7 @@ class VideoPlugin(base.Plugin):
|
|||
}
|
||||
|
||||
@command_set("radeon_powersave", per_device=True)
|
||||
def _set_radeon_powersave(self, value, device, sim):
|
||||
def _set_radeon_powersave(self, value, device, sim, remove):
|
||||
sys_files = self._radeon_powersave_files(device)
|
||||
va = str(re.sub(r"(\s*:\s*)|(\s+)|(\s*;\s*)|(\s*,\s*)", " ", value)).split()
|
||||
if not os.path.exists(sys_files["method"]):
|
||||
|
|
@ -86,20 +87,25 @@ class VideoPlugin(base.Plugin):
|
|||
for v in va:
|
||||
if v in ["default", "auto", "low", "mid", "high"]:
|
||||
if not sim:
|
||||
if (self._cmd.write_to_file(sys_files["method"], "profile") and
|
||||
self._cmd.write_to_file(sys_files["profile"], v)):
|
||||
return v
|
||||
if (self._cmd.write_to_file(sys_files["method"], "profile", \
|
||||
no_error = [errno.ENOENT] if remove else False) and
|
||||
self._cmd.write_to_file(sys_files["profile"], v, \
|
||||
no_error = [errno.ENOENT] if remove else False)):
|
||||
return v
|
||||
elif v == "dynpm":
|
||||
if not sim:
|
||||
if (self._cmd.write_to_file(sys_files["method"], "dynpm")):
|
||||
return "dynpm"
|
||||
if (self._cmd.write_to_file(sys_files["method"], "dynpm", \
|
||||
no_error = [errno.ENOENT] if remove else False)):
|
||||
return "dynpm"
|
||||
# new DPM profiles, recommended to use if supported
|
||||
elif v in ["dpm-battery", "dpm-balanced", "dpm-performance"]:
|
||||
if not sim:
|
||||
state = v[len("dpm-"):]
|
||||
if (self._cmd.write_to_file(sys_files["method"], "dpm") and
|
||||
self._cmd.write_to_file(sys_files["dpm_state"], state)):
|
||||
return v
|
||||
if (self._cmd.write_to_file(sys_files["method"], "dpm", \
|
||||
no_error = [errno.ENOENT] if remove else False) and
|
||||
self._cmd.write_to_file(sys_files["dpm_state"], state, \
|
||||
no_error = [errno.ENOENT] if remove else False)):
|
||||
return v
|
||||
else:
|
||||
if not sim:
|
||||
log.warn("Invalid option for radeon_powersave.")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from .decorators import *
|
|||
import tuned.logs
|
||||
|
||||
import os
|
||||
import errno
|
||||
import struct
|
||||
import glob
|
||||
from tuned.utils.commands import commands
|
||||
|
|
@ -57,7 +58,7 @@ class VMPlugin(base.Plugin):
|
|||
return path
|
||||
|
||||
@command_set("transparent_hugepages")
|
||||
def _set_transparent_hugepages(self, value, sim):
|
||||
def _set_transparent_hugepages(self, value, sim, remove):
|
||||
if value not in ["always", "never", "madvise"]:
|
||||
if not sim:
|
||||
log.warn("Incorrect 'transparent_hugepages' value '%s'." % str(value))
|
||||
|
|
@ -72,7 +73,8 @@ class VMPlugin(base.Plugin):
|
|||
sys_file = os.path.join(self._thp_path(), "enabled")
|
||||
if os.path.exists(sys_file):
|
||||
if not sim:
|
||||
cmd.write_to_file(sys_file, value)
|
||||
cmd.write_to_file(sys_file, value, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return value
|
||||
else:
|
||||
if not sim:
|
||||
|
|
@ -81,8 +83,8 @@ class VMPlugin(base.Plugin):
|
|||
|
||||
# just an alias to transparent_hugepages
|
||||
@command_set("transparent_hugepage")
|
||||
def _set_transparent_hugepage(self, value, sim):
|
||||
self._set_transparent_hugepages(value, sim)
|
||||
def _set_transparent_hugepage(self, value, sim, remove):
|
||||
self._set_transparent_hugepages(value, sim, remove)
|
||||
|
||||
@command_get("transparent_hugepages")
|
||||
def _get_transparent_hugepages(self):
|
||||
|
|
@ -98,11 +100,12 @@ class VMPlugin(base.Plugin):
|
|||
return self._get_transparent_hugepages()
|
||||
|
||||
@command_set("transparent_hugepage.defrag")
|
||||
def _set_transparent_hugepage_defrag(self, value, sim):
|
||||
def _set_transparent_hugepage_defrag(self, value, sim, remove):
|
||||
sys_file = os.path.join(self._thp_path(), "defrag")
|
||||
if os.path.exists(sys_file):
|
||||
if not sim:
|
||||
cmd.write_to_file(sys_file, value)
|
||||
cmd.write_to_file(sys_file, value, \
|
||||
no_error = [errno.ENOENT] if remove else False)
|
||||
return value
|
||||
else:
|
||||
if not sim:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,12 @@ class calc_isolated_cores(base.Function):
|
|||
for cpu in glob.iglob(os.path.join(consts.SYSFS_CPUS_PATH, "cpu*")):
|
||||
cpuid = os.path.basename(cpu)[3:]
|
||||
if cpuid.isdecimal():
|
||||
socket = self._cmd.read_file(os.path.join(cpu, "topology/physical_package_id")).strip()
|
||||
physical_package_id = os.path.join(cpu, "topology/physical_package_id")
|
||||
# Show no errors when the physical_package_id file does not exist -- the CPU may be offline.
|
||||
if not os.path.exists(physical_package_id):
|
||||
log.debug("file '%s' does not exist, cpu%s offline?" % (physical_package_id, cpuid))
|
||||
continue
|
||||
socket = self._cmd.read_file(physical_package_id).strip()
|
||||
if socket.isdecimal():
|
||||
topo[socket] = topo.get(socket, []) + [cpuid]
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class Functions():
|
|||
sl = re.split(r'(?<!\\):', self._str[_from:self._cnt])
|
||||
if sl[0] != "${f":
|
||||
return
|
||||
sl = [str(v).replace("\:", ":") for v in sl]
|
||||
sl = [str(v).replace(r"\:", ":") for v in sl]
|
||||
if not re.match(r'\w+$', sl[1]):
|
||||
log.error("invalid function name '%s'" % sl[1])
|
||||
return
|
||||
|
|
@ -80,7 +80,7 @@ class Functions():
|
|||
self._esc = False
|
||||
self._cnt += 1
|
||||
if len(self._stack):
|
||||
log.error("invalid varialbe syntax, non pair '{' in: '%s'" % s)
|
||||
log.error("invalid variable syntax, non pair '{' in: '%s'" % s)
|
||||
return self._str
|
||||
|
||||
def expand(self, s):
|
||||
|
|
|
|||
|
|
@ -161,16 +161,16 @@ class Manager(object):
|
|||
self._try_call("update_tuning", None,
|
||||
instance.update_tuning)
|
||||
|
||||
# full_rollback is a helper telling plugins whether soft or full
|
||||
# rollback parameter is a helper telling plugins whether soft or full
|
||||
# rollback is needed, e.g. for bootloader plugin we need grub.cfg
|
||||
# tuning to persist across reboots and restarts of the daemon, so in
|
||||
# this case the full_rollback is usually set to consts.ROLLBACK_SOFT,
|
||||
# this case the rollback is usually set to consts.ROLLBACK_SOFT,
|
||||
# but we also need to clean it all up when TuneD is disabled or the
|
||||
# profile is changed. In this case the full_rollback is set to
|
||||
# profile is changed. In this case the rollback is set to
|
||||
# consts.ROLLBACK_FULL. In practice it means to remove all temporal
|
||||
# or helper files, unpatch third party config files, etc.
|
||||
def stop_tuning(self, full_rollback = consts.ROLLBACK_SOFT):
|
||||
def stop_tuning(self, rollback = consts.ROLLBACK_SOFT):
|
||||
self._hardware_inventory.stop_processing_events()
|
||||
for instance in reversed(self._instances):
|
||||
self._try_call("stop_tuning", None,
|
||||
instance.unapply_tuning, full_rollback)
|
||||
instance.unapply_tuning, rollback)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class commands:
|
|||
return {"Y":"1", "YES":"1", "T":"1", "TRUE":"1", "N":"0", "NO":"0", "F":"0", "FALSE":"0"}.get(v, value)
|
||||
|
||||
def remove_ws(self, s):
|
||||
return re.sub('\s+', ' ', str(s)).strip()
|
||||
return re.sub(r'\s+', ' ', str(s)).strip()
|
||||
|
||||
def unquote(self, v):
|
||||
return re.sub("^\"(.*)\"$", r"\1", v)
|
||||
|
|
@ -91,6 +91,17 @@ class commands:
|
|||
return None
|
||||
|
||||
def write_to_file(self, f, data, makedir = False, no_error = False):
|
||||
"""Write data to a file.
|
||||
|
||||
Parameters:
|
||||
f -- filename where to write
|
||||
data -- data to write
|
||||
makedir -- if True and the path doesn't exist, it will be created
|
||||
no_error -- if True errors are silenced, it can be also list of ignored errnos
|
||||
|
||||
Return:
|
||||
bool -- True on success
|
||||
"""
|
||||
self._debug("Writing to file: '%s' < '%s'" % (f, data))
|
||||
if makedir:
|
||||
d = os.path.dirname(f)
|
||||
|
|
@ -103,10 +114,11 @@ class commands:
|
|||
fd.write(str(data))
|
||||
fd.close()
|
||||
rc = True
|
||||
except (OSError,IOError) as e:
|
||||
except (OSError, IOError) as e:
|
||||
rc = False
|
||||
if not no_error:
|
||||
self._error("Writing to file '%s' error: '%s'" % (f, e))
|
||||
if isinstance(no_error, bool) and not no_error or \
|
||||
isinstance(no_error, list) and e.errno not in no_error:
|
||||
self._error("Writing to file '%s' error: '%s'" % (f, e))
|
||||
return rc
|
||||
|
||||
def read_file(self, f, err_ret = "", no_error = False):
|
||||
|
|
@ -235,13 +247,13 @@ class commands:
|
|||
err_out = err[:-1]
|
||||
if len(err_out) == 0:
|
||||
err_out = out[:-1]
|
||||
err_msg = "Executing %s error: %s" % (args[0], err_out)
|
||||
err_msg = "Executing '%s' error: %s" % (' '.join(args), err_out)
|
||||
if not return_err:
|
||||
self._error(err_msg)
|
||||
except (OSError, IOError) as e:
|
||||
retcode = -e.errno if e.errno is not None else -1
|
||||
if not abs(retcode) in no_errors and not 0 in no_errors:
|
||||
err_msg = "Executing %s error: %s" % (args[0], e)
|
||||
err_msg = "Executing '%s' error: %s" % (' '.join(args), e)
|
||||
if not return_err:
|
||||
self._error(err_msg)
|
||||
if return_err:
|
||||
|
|
@ -427,7 +439,7 @@ class commands:
|
|||
if s[0:8].lower() != "cpulist:":
|
||||
return [("cpu" + str(v)) for v in self.cpulist_unpack(s)]
|
||||
l = re.split(r"\s*(?<!\\),\s*", s)
|
||||
return [str(v).replace("\,", ",") for v in l]
|
||||
return [str(v).replace(r"\,", ",") for v in l]
|
||||
|
||||
# Do not make balancing on patched Python 2 interpreter (rhbz#1028122).
|
||||
# It means less CPU usage on patchet interpreter. On non-patched interpreter
|
||||
|
|
@ -523,3 +535,12 @@ class commands:
|
|||
f.write(profile_name + "\n")
|
||||
except (OSError,IOError) as e:
|
||||
raise TunedException("Failed to save the active post-loaded profile: %s" % e.strerror)
|
||||
|
||||
# Translates characters in 'text' from 'source_chars' to 'dest_chars'
|
||||
def tr(self, text, source_chars, dest_chars):
|
||||
try:
|
||||
trans = str.maketrans(source_chars, dest_chars)
|
||||
except AttributeError:
|
||||
import string
|
||||
trans = string.maketrans(source_chars, dest_chars)
|
||||
return text.translate(trans)
|
||||
|
|
|
|||
|
|
@ -25,19 +25,19 @@ else:
|
|||
delims = "".join(list(delimiters))
|
||||
# REs taken from the python-2.7 ConfigParser
|
||||
self.OPTCRE = re.compile(
|
||||
r'(?P<option>[^' + delims + '\s][^' + delims + ']*)'
|
||||
r'\s*(?P<vi>[' + delims + '])\s*'
|
||||
r'(?P<option>[^' + delims + r'\s][^' + delims + ']*)'
|
||||
r'\s*(?P<vi>[' + delims + r'])\s*'
|
||||
r'(?P<value>.*)$'
|
||||
)
|
||||
self.OPTCRE_NV = re.compile(
|
||||
r'(?P<option>[^' + delims + '\s][^' + delims + ']*)'
|
||||
r'(?P<option>[^' + delims + r'\s][^' + delims + ']*)'
|
||||
r'\s*(?:'
|
||||
r'(?P<vi>[' + delims + '])\s*'
|
||||
r'(?P<vi>[' + delims + r'])\s*'
|
||||
r'(?P<value>.*))?$'
|
||||
)
|
||||
cp.ConfigParser.__init__(self, *args, **kwargs)
|
||||
self._inline_comment_prefixes = inline_comment_prefixes or []
|
||||
self._re = re.compile("\s+(%s).*" % ")|(".join(list(self._inline_comment_prefixes)))
|
||||
self._re = re.compile(r"\s+(%s).*" % ")|(".join(list(self._inline_comment_prefixes)))
|
||||
|
||||
def read_string(self, string, source="<string>"):
|
||||
sfile = StringIO(string)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ class Nettool:
|
|||
p_ethtool = Popen(["ethtool", self._interface], \
|
||||
stdout=PIPE, stderr=PIPE, close_fds=True, \
|
||||
universal_newlines = True)
|
||||
p_filter = Popen(["sed", "s/^\s*//;s/:\s*/:\\n/g"], \
|
||||
p_filter = Popen(["sed", r"s/^\s*//;s/:\s*/:\n/g"], \
|
||||
stdin=p_ethtool.stdout, stdout=PIPE, \
|
||||
universal_newlines = True, \
|
||||
close_fds=True)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
TUNED_VERSION_MAJOR = 2
|
||||
TUNED_VERSION_MINOR = 20
|
||||
TUNED_VERSION_MINOR = 21
|
||||
TUNED_VERSION_PATCH = 0
|
||||
|
||||
TUNED_VERSION_STR = "%d.%d.%d" % (TUNED_VERSION_MAJOR, TUNED_VERSION_MINOR, TUNED_VERSION_PATCH)
|
||||
|
|
|
|||
Loading…
Reference in a new issue