🎈 perf: 增加自定义tuned profile

This commit is contained in:
linxin
2023-11-06 18:30:45 +08:00
parent c101145ef9
commit 27d98f4113
4 changed files with 221 additions and 0 deletions

View File

@@ -180,6 +180,7 @@
- {role: tsg-os-logo, tags: tsg-os-logo}
- {role: cm-cache, tags: cm-cache}
- {role: exporter, tags: exporter}
- {role: tuned, tags: tuned}
- hosts: TSG-X-NXR620G40-R01-P0906-init
remote_user: root

View File

@@ -0,0 +1,173 @@
From 4daf99fc2cb6d873e804d24d56ddd849fc4e514b Mon Sep 17 00:00:00 2001
From: Adriaan Schmidt <adriaan.schmidt@siemens.com>
Date: Wed, 10 Aug 2022 05:05:03 +0000
Subject: [PATCH] feat(scheduler): match thread names in addition to process
names
This is a first try at matching thread names (comm) in addition to
the process cmdline for changing scheduling policies and priorities
with the `scheduler` plugin.
It adds an optional second regex field to the end of `group.*`
options (defaults to ".*"). The first regex is to match the
process cmdline, the second one is used to match the thread's
comm. If both match, scheduling options are applied.
Note that you can have multiple `group.*` options with the
same process regex and different thread regexes. You can even have
one rule to match a specific thread name, and another with no thread
regex (matching all threads). In this case you need to assign rule
priorities (higher number -> higher priority).
Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
---
profiles/realtime-virtual-guest/tuned.conf | 2 +-
profiles/realtime-virtual-host/tuned.conf | 2 +-
tuned/plugins/plugin_scheduler.py | 67 ++++++++++++++++------
3 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/profiles/realtime-virtual-guest/tuned.conf b/profiles/realtime-virtual-guest/tuned.conf
index a381f413..288f9d03 100644
--- a/profiles/realtime-virtual-guest/tuned.conf
+++ b/profiles/realtime-virtual-guest/tuned.conf
@@ -22,7 +22,7 @@ non_isolated_cores=${f:cpulist_invert:${isolated_cores}}
assert2=${f:assertion:isolated_cores contains online CPU(s):${isolated_cores_expanded}:${isolated_cores_online_expanded}}
[scheduler]
-# group.group_name=rule_priority:scheduler_policy:scheduler_priority:core_affinity_in_hex:process_name_regex
+# group.group_name=rule_priority:scheduler_policy:scheduler_priority:core_affinity_in_hex:process_name_regex[:thread_name_regex]
# for i in `pgrep ksoftirqd` ; do grep Cpus_allowed_list /proc/$i/status ; done
group.ksoftirqd=0:f:2:*:^\[ksoftirqd
group.ktimers=0:f:2:*:^\[ktimers
diff --git a/profiles/realtime-virtual-host/tuned.conf b/profiles/realtime-virtual-host/tuned.conf
index b0e8846c..0f520dfe 100644
--- a/profiles/realtime-virtual-host/tuned.conf
+++ b/profiles/realtime-virtual-host/tuned.conf
@@ -27,7 +27,7 @@ non_isolated_cores=${f:cpulist_invert:${isolated_cores}}
assert2=${f:assertion:isolated_cores contains online CPU(s):${isolated_cores_expanded}:${isolated_cores_online_expanded}}
[scheduler]
-# group.group_name=rule_priority:scheduler_policy:scheduler_priority:core_affinity_in_hex:process_name_regex
+# group.group_name=rule_priority:scheduler_policy:scheduler_priority:core_affinity_in_hex:process_name_regex[:thread_name_regex]
# for i in `pgrep ksoftirqd` ; do grep Cpus_allowed_list /proc/$i/status ; done
group.ksoftirqd=0:f:2:*:^\[ksoftirqd
group.ktimers=0:f:2:*:^\[ktimers
diff --git a/tuned/plugins/plugin_scheduler.py b/tuned/plugins/plugin_scheduler.py
index 10ff4e7a..74678d99 100644
--- a/tuned/plugins/plugin_scheduler.py
+++ b/tuned/plugins/plugin_scheduler.py
@@ -565,10 +565,11 @@ def _get_cmdline(self, process):
if not isinstance(process, procfs.process):
pid = process
process = procfs.process(pid)
- cmdline = procfs.process_cmdline(process)
+ cmd = procfs.process_cmdline(process)
+ comm = process['stat']['comm']
if self._is_kthread(process):
- cmdline = "[" + cmdline + "]"
- return cmdline
+ return "[" + cmd + "]", "[" + comm + "]"
+ return cmd, comm
# Raises OSError, IOError
def get_processes(self):
@@ -582,7 +583,7 @@ def get_processes(self):
processes[pid] = cmd
if "threads" in proc:
for pid in proc["threads"].keys():
- cmd = self._get_cmdline(proc)
+ cmd = self._get_cmdline(pid)
processes[pid] = cmd
except (OSError, IOError) as e:
if e.errno == errno.ENOENT \
@@ -817,7 +818,16 @@ def _convert_sched_cfg(self, vals):
(scheduler, priority) = self._convert_sched_params(
scheduler, priority)
affinity = self._convert_affinity(affinity)
- return (rule_prio, scheduler, priority, affinity, regex)
+ # split regex into two, one to match the cmdline, and one the comm
+ # if there is only one regex for the cmdline, then the comm is matched by ".*"
+ # allow escaping of colons in regexes (-> '\:' is not a delimiter in the split)
+ regexes = re.split(r'(?<!\\):', regex, 1)
+ r1 = regexes[0].replace(r'\:', ':')
+ try:
+ r2 = regexes[1].replace(r'\:', ':')
+ except IndexError:
+ r2 = ".*"
+ return (rule_prio, scheduler, priority, affinity, r1, r2)
def _cgroup_create_group(self, cgroup):
path = "%s/%s" % (self._cgroup_mount_point, cgroup)
@@ -934,24 +944,34 @@ def _instance_apply_static(self, instance):
sched_cfg = sorted(buf, key=lambda option_vals: option_vals[1][0])
sched_all = dict()
# for runtime tuning
+ # _sched_lookup is a dict mapping a cmdline regex to a list of scheduling
+ # parameters, each with a secondary regex to match the comm, sorted from lowest
+ # to highest priority
instance._sched_lookup = {}
- for option, (rule_prio, scheduler, priority, affinity, regex) \
+ for option, (rule_prio, scheduler, priority, affinity, regex, regex2) \
in sched_cfg:
try:
- r = re.compile(regex)
+ r1 = re.compile(regex)
except re.error as e:
log.error("error compiling regular expression: '%s'" % str(regex))
continue
- processes = [(pid, cmd) for pid, cmd in ps.items() if re.search(r, cmd) is not None]
+ try:
+ r2 = re.compile(regex2)
+ except re.error as e:
+ log.error("error compiling regular expression: '%s'" % str(regex2))
+ continue
+ processes = [(pid, cmd) for pid, cmd in ps.items() if re.search(r1, cmd[0]) is not None and re.search(r2, cmd[1]) is not None]
#cmd - process name, option - group name
- sched = dict([(pid, (cmd, option, scheduler, priority, affinity, regex))
+ sched = dict([(pid, (cmd, option, scheduler, priority, affinity))
for pid, cmd in processes])
sched_all.update(sched)
# make any contained regexes non-capturing: replace "(" with "(?:",
# unless the "(" is preceded by "\" or followed by "?"
regex = re.sub(r"(?<!\\)\((?!\?)", "(?:", str(regex))
- instance._sched_lookup[regex] = [scheduler, priority, affinity]
- for pid, (cmd, option, scheduler, priority, affinity, regex) \
+ if not regex in instance._sched_lookup:
+ instance._sched_lookup[regex] = []
+ instance._sched_lookup[regex].append([scheduler, priority, affinity, r2])
+ for pid, (cmd, option, scheduler, priority, affinity) \
in sched_all.items():
self._tune_process(pid, cmd, scheduler,
priority, affinity)
@@ -1060,14 +1080,23 @@ def _add_pid(self, instance, pid, r):
log.error("Failed to get cmdline of PID %d: %s"
% (pid, e))
return
- v = self._cmd.re_lookup(instance._sched_lookup, cmd, r)
- if v is not None and not pid in self._scheduler_original:
- log.debug("tuning new process '%s' with PID '%d' by '%s'" % (cmd, pid, str(v)))
- (sched, prio, affinity) = v
- self._tune_process(pid, cmd, sched, prio,
- affinity)
- self._storage.set(self._scheduler_storage_key,
- self._scheduler_original)
+ # first match against cmdline, uses the optimized re_lookup
+ vs = self._cmd.re_lookup(instance._sched_lookup, cmd[0], r)
+ if vs is not None and not pid in self._scheduler_original:
+ tune_v = None
+ # second match against comm, reversed to start with the highest priority
+ for v in reversed(vs):
+ if re.search(v[3], cmd[1]) is not None:
+ tune_v = v[:3]
+ break
+
+ if tune_v is not None:
+ log.debug("tuning new process '%s' with PID '%d' by '%s'" % (cmd, pid, str(tune_v)))
+ (sched, prio, affinity) = tune_v
+ self._tune_process(pid, cmd, sched, prio,
+ affinity)
+ self._storage.set(self._scheduler_storage_key,
+ self._scheduler_original)
def _remove_pid(self, instance, pid):
if pid in self._scheduler_original:

View File

@@ -0,0 +1,12 @@
[main]
include=cpu-partitioning
summary=Optimize for tsg-os device CPU partitioning
[scheduler]
group.default=0:*:0:${not_isolated_cpumask}:.*:.*
group.isolate=1:*:0:*:.*:^(telegraf|sapp_marsio_.*|sce:worker-.*|lcore-worker-.*|.*pmd.*|.*PMD.*|DPDK|.*qemu-kvm.*|contrail-vroute|lcore-slave-.*|rte_mp_handle|rte_mp_async|eal-intr-thread)$
isolated_cores=${isolated_cores}
ps_blacklist=^telegraf;^sapp_marsio_.*;^sce:worker-.*;^lcore-worker-.*;.*pmd.*;.*PMD.*;^DPDK;.*qemu-kvm.*;^contrail-vroute$;^lcore-slave-.*;^rte_mp_handle$;^rte_mp_async$;^eal-intr-thread$
perf_process_fork=True
perf_mmap_pages=4096
runtime=1

View File

@@ -0,0 +1,35 @@
- name: "Tuned: copy patch file to dest"
copy:
src: "{{ role_path }}/files/{{ item }}"
dest: /tmp
mode: 0755
with_items:
- 371.patch
when: runtime_env == 'TSG-X-P0906'
- name: "Create /etc/tuned/tsg-os-cpu-partitioning directory if it does not exist"
file:
path: "{{ item }}"
state: directory
mode: '0755'
with_items:
- /etc/tuned/tsg-os-cpu-partitioning
- name: "Tuned: copy patch file to dest"
copy:
src: "{{ role_path }}/files/{{ item }}"
dest: /etc/tuned/tsg-os-cpu-partitioning/tuned.conf
mode: 0755
with_items:
- tuned.conf
when: runtime_env == 'TSG-X-P0906'
- name: "patch plugin_scheduler.py"
shell: cd /usr/lib/python3.6/site-packages && patch -p1 -t < /tmp/371.patch || true
when: runtime_env == 'TSG-X-P0906'
- name: "apply tsg-os-cpu-partitioning profile"
shell: echo tsg-os-cpu-partitioning >/etc/tuned/active_profile
when: runtime_env == 'TSG-X-P0906'