Re: [PATCH v6 1/2] rteval: Added functionality to allow user to set the cstate of specified cpus when running rteval

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Fri, 2 Aug 2024, Anubhav Shelat wrote:

> We would like to be able to set the idle states of CPUs while running
> rteval.
> 
> This patch adds the file cpupower.py and option '--idle-set' within
> rteval to use cpupower. The set idle state is applied to the cpulist
> given by '--measurement-cpulist'.
> 
> cpupower.py provides the infrastructure to interface and execute the cpupower
> command, and the options in rteval-cmd let the user specify the idle state
> to be set and the CPUs to set it on.
> 
> Signed-off-by: Anubhav Shelat <ashelat@xxxxxxxxxx>
> ---
>  rteval-cmd                             |  11 ++-
>  rteval/cpupower.py                     | 125 +++++++++++++++++++++++++
>  rteval/modules/__init__.py             |   2 +-
>  rteval/modules/measurement/__init__.py |   2 +
>  4 files changed, 138 insertions(+), 2 deletions(-)
>  create mode 100644 rteval/cpupower.py
> 
> diff --git a/rteval-cmd b/rteval-cmd
> index 19c82a0b64b3..6e7d8f5d99cb 100755
> --- a/rteval-cmd
> +++ b/rteval-cmd
> @@ -29,6 +29,7 @@ from rteval.Log import Log
>  from rteval import RtEval, rtevalConfig
>  from rteval.modules.loads import LoadModules
>  from rteval.modules.measurement import MeasurementModules
> +from rteval import cpupower
>  from rteval.version import RTEVAL_VERSION
>  from rteval.systopology import SysTopology, parse_cpulist_from_config
>  from rteval.modules.loads.kcompile import ModuleParameters
> @@ -149,7 +150,7 @@ def parse_options(cfg, parser, cmdargs):
>      parser.add_argument("--noload", dest="rteval___noload",
>                          action="store_true", default=False,
>                          help="only run the measurements (don't run loads)")
> -
> +
>  
>      if not cmdargs:
>          cmdargs = ["--help"]
> @@ -402,6 +403,10 @@ if __name__ == '__main__':
>          if not os.path.isdir(rtevcfg.workdir):
>              raise RuntimeError(f"work directory {rtevcfg.workdir} does not exist")
>  
> +        # if idle-set has been specified, enable the idle state via cpupower
> +        if msrcfg.idlestate:
> +            cpupower_controller = cpupower.Cpupower(msrcfg.cpulist, msrcfg.idlestate, logger=logger)
> +            cpupower_controller.enable_idle_state()
>  
>          rteval = RtEval(config, loadmods, measuremods, logger)
>          rteval.Prepare(rtevcfg.onlyload)
> @@ -421,6 +426,10 @@ if __name__ == '__main__':
>              ec = rteval.Measure()
>              logger.log(Log.DEBUG, f"exiting with exit code: {ec}")
>  
> +        # restore previous idle state settings
> +        if msrcfg.idlestate:
> +            cpupower_controller.restore_idle_states()
> +
>          sys.exit(ec)
>      except KeyboardInterrupt:
>          sys.exit(0)
> diff --git a/rteval/cpupower.py b/rteval/cpupower.py
> new file mode 100644
> index 000000000000..37c4d33f1df4
> --- /dev/null
> +++ b/rteval/cpupower.py
> @@ -0,0 +1,125 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +# Copyright 2024    Anubhav Shelat <ashelat@xxxxxxxxxx>
> +""" Object to execute cpupower tool """
> +
> +import subprocess
> +import os
> +import shutil
> +import sys
> +from rteval.Log import Log
> +from rteval.systopology import SysTopology as SysTop
> +from rteval import cpulist_utils
> +
> +PATH = '/sys/devices/system/cpu/'
> +
> +class Cpupower:
> +    """ class to store data for executing cpupower and restoring idle state configuration """
> +    def __init__(self, cpulist, idlestate, logger=None):
> +        if not self.cpupower_present():
> +            print('cpupower not found')
> +            sys.exit(1)
> +
> +        self.__idle_state = int(idlestate)
> +        self.__states = os.listdir(PATH + 'cpu0/cpuidle/')
> +        # self.__idle_states is a dict with cpus as keys,
> +        # and another dict as the value. The value dict
> +        # has idle states as keys and a boolean as the
> +        # value indicating if the state is disabled.
> +        self.__idle_states = {}
> +        self.__name = "cpupower"
> +        self.__online_cpus = SysTop().online_cpus()
> +        self.__cpulist = cpulist
> +        self.__logger = logger
> +
> +
> +    def _log(self, logtype, msg):
> +        """ Common log function for rteval modules """
> +        if self.__logger:
> +            self.__logger.log(logtype, f"[{self.__name}] {msg}")
> +
> +
> +    def enable_idle_state(self):
> +        """ Use cpupower to set the idle state """
> +        self.get_idle_states()
> +
> +        # ensure that idle state is in range of available idle states
> +        if self.__idle_state > len(self.__states) - 1 or self.__idle_state < 0:
> +            print(f'Idle state {self.__idle_state} is out of range')
> +            sys.exit(1)
> +
> +        # enable all idle states to a certain depth, and disable any deeper idle states
> +        with open(os.devnull, 'wb') as buffer:
> +            for state in self.__states:
> +                s = state.strip("state")
> +                if int(s) > self.__idle_state:
> +                    self.run_cpupower(['cpupower', '-c', self.__cpulist,'idle-set', '-d', s], buffer)
> +                else:
> +                    self.run_cpupower(['cpupower', '-c', self.__cpulist,'idle-set', '-e', s], buffer)
> +
> +        self._log(Log.DEBUG, f'Idle state depth {self.__idle_state} enabled on CPUs {self.__cpulist}')
> +
> +
> +    def run_cpupower(self, args, output_buffer=None):
> +        """ execute cpupower """
> +        try:
> +            subprocess.run(args, check=True, stdout=output_buffer)
> +        except subprocess.CalledProcessError:
> +            print('cpupower failed')
> +            sys.exit(1)
> +
> +
> +    def get_idle_states(self):
> +        """ Store the current idle state setting """
> +        for cpu in self.__online_cpus:
> +            self.__idle_states[cpu] = {}
> +            for state in self.__states:
> +                fp = os.path.join(PATH, 'cpu' + str(cpu) + '/cpuidle/' + state + '/disable')
> +                self.__idle_states[cpu][state] = self.read_idle_state(fp)
> +
> +
> +    def restore_idle_states(self):
> +        """ restore the idle state setting """
> +        for cpu, states in self.__idle_states.items():
> +            for state, disabled in states.items():
> +                fp = os.path.join(PATH, 'cpu' + str(cpu) + '/cpuidle/' + state + '/disable')
> +                self.write_idle_state(fp, disabled)
> +        self._log(Log.DEBUG, 'Idle state settings restored')
> +
> +
> +    def read_idle_state(self, file):
> +        """ read the disable value for an idle state """
> +        with open(file, 'r', encoding='utf-8') as f:
> +            return f.read(1)
> +
> +
> +    def write_idle_state(self, file, state):
> +        """ write the disable value for and idle state """
> +        with open(file, 'w', encoding='utf-8') as f:
> +            f.write(state)
> +
> +
> +    def get_idle_info(self):
> +        """ execute cpupower idle-info """
> +        self.run_cpupower(['cpupower', 'idle-info'])
> +
> +
> +    def cpupower_present(self):
> +        """ check if cpupower is downloaded """
> +        return shutil.which("cpupower") is not None
> +
> +
> +if __name__ == '__main__':
> +    l = Log()
> +    l.SetLogVerbosity(Log.DEBUG)
> +
> +    online_cpus = cpulist_utils.collapse_cpulist(SysTop().online_cpus())
> +    idlestate = '1'
> +    info = True
> +
> +    cpupower = Cpupower(online_cpus, idlestate, logger=l)
> +    if idlestate:
> +        cpupower.enable_idle_state()
> +        cpupower.restore_idle_states()
> +    print()
> +    cpupower.get_idle_info()
> diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py
> index d7792108d5b8..acd6330788e2 100644
> --- a/rteval/modules/__init__.py
> +++ b/rteval/modules/__init__.py
> @@ -282,7 +282,7 @@ reference from the first import"""
>          grparser.add_argument(f'--{self.__modtype}-cpulist',
>                              dest=f'{self.__modtype}___cpulist', action='store', default="",
>                              help=f'CPU list where {self.__modtype} modules will run',
> -                            metavar='LIST')
> +                            metavar='CPULIST')
>  
>          for (modname, mod) in list(self.__modsloaded.items()):
>              opts = mod.ModuleParameters()
> diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py
> index ecadd0885991..9314d1cb6bbc 100644
> --- a/rteval/modules/measurement/__init__.py
> +++ b/rteval/modules/measurement/__init__.py
> @@ -38,6 +38,8 @@ class MeasurementModules(RtEvalModules):
>                                default=self._cfg.GetSection("measurement").setdefault("run-on-isolcpus", "false").lower()
>                                        == "true",
>                                help="Include isolated CPUs in default cpulist")
> +        grparser.add_argument('--idle-set', dest='measurement___idlestate', metavar='IDLESTATE',
> +                        default=None, help='Idle state depth to set on cpus running measurement modules')
>  
>  
>      def Setup(self, modparams):
> -- 
> 2.45.2
> 
> 
> 

Signed-off-by: John Kacur <jkacur@xxxxxxxxxx>





[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux