1
0
mirror of https://github.com/ARM-software/devlib.git synced 2024-10-05 18:30:50 +01:00

Merge pull request #3 from derkling/drk-for-master

Fixes and additions for master
This commit is contained in:
setrofim 2015-11-13 08:24:09 +00:00
commit f46057f836
2 changed files with 195 additions and 116 deletions

View File

@ -22,9 +22,7 @@ from devlib.utils.misc import list_to_ranges, isiterable
from devlib.utils.types import boolean from devlib.utils.types import boolean
class CgroupController(object): class Controller(object):
kind = 'cpuset'
def __new__(cls, arg): def __new__(cls, arg):
if isinstance(arg, cls): if isinstance(arg, cls):
@ -32,98 +30,90 @@ class CgroupController(object):
else: else:
return object.__new__(cls, arg) return object.__new__(cls, arg)
def __init__(self, mount_name): def __init__(self, kind):
self.mount_name = 'devlib_'+kind
self.kind = kind
self.target = None
self.logger = logging.getLogger('cgroups.'+self.kind)
self.mount_point = None self.mount_point = None
self.mount_name = mount_name self._cgroups = {}
self.logger = logging.getLogger(self.kind)
def probe(self, target): def probe(self, target):
raise NotImplementedError() try:
exists = target.execute('{} grep {} /proc/cgroups'\
.format(target.busybox, self.kind))
except TargetError:
return False
return True
def mount(self, device, mount_root): def mount(self, target, mount_root):
self.target = device
self.mount_point = device.path.join(mount_root, self.mount_name) mounted = target.list_file_systems()
mounted = self.target.list_file_systems() if self.mount_name in [e.device for e in mounted]:
if self.mount_point in [e.mount_point for e in mounted]: # Identify mount point if controller is already in use
self.logger.debug('controller is already mounted.') self.mount_point = [
fs.mount_point
for fs in mounted
if fs.device == self.mount_name
][0]
else: else:
self.target.execute('mkdir -p {} 2>/dev/null'.format(self.mount_point), # Mount the controller if not already in use
as_root=True) self.mount_point = target.path.join(mount_root, self.mount_name)
self.target.execute('mount -t cgroup -o {} {} {}'.format(self.kind, target.execute('mkdir -p {} 2>/dev/null'\
.format(self.mount_point), as_root=True)
target.execute('mount -t cgroup -o {} {} {}'\
.format(self.kind,
self.mount_name, self.mount_name,
self.mount_point), self.mount_point),
as_root=True) as_root=True)
self.logger.info('Controller %s mounted under: %s',
self.kind, self.mount_point)
class CpusetGroup(object): # Mark this contoller as available
self.target = target
def __init__(self, controller, name, cpus, mems): # Create root control group
self.controller = controller self.cgroup('/')
self.target = controller.target
self.name = name
if name == 'root':
self.directory = controller.mount_point
else:
self.directory = self.target.path.join(controller.mount_point, name)
self.target.execute('mkdir -p {}'.format(self.directory), as_root=True)
self.cpus_file = self.target.path.join(self.directory, 'cpuset.cpus')
self.mems_file = self.target.path.join(self.directory, 'cpuset.mems')
self.tasks_file = self.target.path.join(self.directory, 'tasks')
self.set(cpus, mems)
def set(self, cpus, mems): def cgroup(self, name):
if isiterable(cpus): if not self.target:
cpus = list_to_ranges(cpus) raise RuntimeError('CGroup creation failed: {} controller not mounted'\
if isiterable(mems): .format(self.kind))
mems = list_to_ranges(mems) if name not in self._cgroups:
self.target.write_value(self.cpus_file, cpus) self._cgroups[name] = CGroup(self, name)
self.target.write_value(self.mems_file, mems) return self._cgroups[name]
def get(self): def exists(self, name):
cpus = self.target.read_value(self.cpus_file) if not self.target:
mems = self.target.read_value(self.mems_file) raise RuntimeError('CGroup creation failed: {} controller not mounted'\
return (cpus, mems) .format(self.kind))
if name not in self._cgroups:
self._cgroups[name] = CGroup(self, name, create=False)
return self._cgroups[name].existe()
def get_tasks(self): def list_all(self):
task_ids = self.target.read_value(self.tasks_file).split() self.logger.debug('Listing groups for %s controller', self.kind)
return map(int, task_ids) output = self.target.execute('{} find {} -type d'\
.format(self.target.busybox, self.mount_point))
def add_tasks(self, tasks): cgroups = []
for tid in tasks: for cg in output.split('\n'):
self.add_task(tid) cg = cg.replace(self.mount_point + '/', '/')
cg = cg.replace(self.mount_point, '/')
def add_task(self, tid): cg = cg.strip()
self.target.write_value(self.tasks_file, tid, verify=False) if cg == '':
continue
self.logger.debug('Populate %s cgroup: %s', self.kind, cg)
class CpusetController(CgroupController): cgroups.append(cg)
return cgroups
name = 'cpuset'
def __init__(self, *args, **kwargs):
super(CpusetController, self).__init__(*args, **kwargs)
self.groups = {}
def probe(self, target):
return target.config.is_enabled('cpusets')
def mount(self, device, mount_root):
super(CpusetController, self).mount(device, mount_root)
self.create_group('root', self.target.list_online_cpus(), 0)
def create_group(self, name, cpus, mems):
if not hasattr(self, 'target'):
raise RuntimeError('Attempting to create group for unmounted controller {}'.format(self.kind))
if name in self.groups:
raise ValueError('Group {} already exists'.format(name))
self.groups[name] = CpusetGroup(self, name, cpus, mems)
def move_tasks(self, source, dest): def move_tasks(self, source, dest):
try: try:
source_group = self.groups[source] srcg = self._cgroups[source]
dest_group = self.groups[dest] dstg = self._cgroups[dest]
command = 'for task in $(cat {}); do echo $task>{}; done' command = 'for task in $(cat {}); do echo $task>{}; done'
self.target.execute(command.format(source_group.tasks_file, dest_group.tasks_file), self.target.execute(command.format(srcg.tasks_file, dstg.tasks_file),
# this will always fail as some of the tasks # this will always fail as some of the tasks
# are kthreads that cannot be migrated, but we # are kthreads that cannot be migrated, but we
# don't care about those, so don't check exit # don't care about those, so don't check exit
@ -132,61 +122,146 @@ class CpusetController(CgroupController):
except KeyError as e: except KeyError as e:
raise ValueError('Unkown group: {}'.format(e)) raise ValueError('Unkown group: {}'.format(e))
def move_all_tasks_to(self, target_group): def move_all_tasks_to(self, dest):
for group in self.groups: for cgroup in self._cgroups:
if group != target_group: if cgroup != dest:
self.move_tasks(group, target_group) self.move_tasks(cgroup, dest)
def __getattr__(self, name): class CGroup(object):
def __init__(self, controller, name, create=True):
self.logger = logging.getLogger('cgroups.' + controller.kind)
self.target = controller.target
self.controller = controller
self.name = name
# Control cgroup path
self.directory = controller.mount_point
if name != '/':
self.directory = self.target.path.join(controller.mount_point, name[1:])
# Setup path for tasks file
self.tasks_file = self.target.path.join(self.directory, 'tasks')
self.procs_file = self.target.path.join(self.directory, 'cgroup.procs')
if not create:
return
self.logger.info('Creating cgroup %s', self.directory)
self.target.execute('[ -d {0} ] || mkdir -p {0}'\
.format(self.directory), as_root=True)
def exists(self):
try: try:
return self.groups[name] self.target.execute('[ -d {0} ]'\
except KeyError: .format(self.directory))
raise AttributeError(name) return True
except TargetError:
return False
def get(self):
conf = {}
logging.debug('Reading %s attributes from:',
self.controller.kind)
logging.debug(' %s',
self.directory)
output = self.target.execute('{} grep \'\' {}/{}.*'.format(
self.target.busybox,
self.directory,
self.controller.kind))
for res in output.split('\n'):
if res.find(self.controller.kind) < 0:
continue
res = res.split('.')[1]
attr = res.split(':')[0]
value = res.split(':')[1]
conf[attr] = value
return conf
def set(self, **attrs):
for idx in attrs:
if isiterable(attrs[idx]):
attrs[idx] = list_to_ranges(attrs[idx])
# Build attribute path
path = '{}.{}'.format(self.controller.kind, idx)
path = self.target.path.join(self.directory, path)
self.logger.debug('Set attribute [%s] to: %s"',
path, attrs[idx])
# Set the attribute value
self.target.write_value(path, attrs[idx])
def get_tasks(self):
task_ids = self.target.read_value(self.tasks_file).split()
logging.debug('Tasks: %s', task_ids)
return map(int, task_ids)
def add_task(self, tid):
self.target.write_value(self.tasks_file, tid, verify=False)
def add_tasks(self, tasks):
for tid in tasks:
self.add_task(tid)
def add_proc(self, pid):
self.target.write_value(self.procs_file, pid, verify=False)
CgroupSubsystemEntry = namedtuple('CgroupSubsystemEntry', 'name hierarchy num_cgroups enabled') CgroupSubsystemEntry = namedtuple('CgroupSubsystemEntry', 'name hierarchy num_cgroups enabled')
class CgroupsModule(Module): class CgroupsModule(Module):
name = 'cgroups' name = 'cgroups'
controller_cls = [
CpusetController,
]
cgroup_root = '/sys/fs/cgroup' cgroup_root = '/sys/fs/cgroup'
@staticmethod @staticmethod
def probe(target): def probe(target):
return target.config.has('cgroups') and target.is_rooted return target.config.has('cgroups') and target.is_rooted
def __init__(self, target): def __init__(self, target):
super(CgroupsModule, self).__init__(target) super(CgroupsModule, self).__init__(target)
self.logger = logging.getLogger('CGroups')
# Initialize controllers mount point
mounted = self.target.list_file_systems() mounted = self.target.list_file_systems()
if self.cgroup_root not in [e.mount_point for e in mounted]: if self.cgroup_root not in [e.mount_point for e in mounted]:
self.target.execute('mount -t tmpfs {} {}'.format('cgroup_root', self.cgroup_root), self.target.execute('mount -t tmpfs {} {}'\
.format('cgroup_root',
self.cgroup_root),
as_root=True) as_root=True)
else: else:
self.logger.debug('cgroup_root already mounted at {}'.format(self.cgroup_root)) self.logger.debug('cgroup_root already mounted at %s',
self.controllers = [] self.cgroup_root)
for cls in self.controller_cls:
controller = cls('devlib_{}'.format(cls.name)) # Load list of available controllers
if controller.probe(self.target): controllers = []
if controller.mount_name in [e.device for e in mounted]: subsys = self.list_subsystems()
self.logger.debug('controller {} is already mounted.'.format(controller.kind)) for (n, h, c, e) in subsys:
else: controllers.append(n)
self.logger.info('Available controllers: %s', controllers)
# Initialize controllers
self.controllers = {}
for idx in controllers:
controller = Controller(idx)
self.logger.debug('Init %s controller...', controller.kind)
if not controller.probe(self.target):
continue
try: try:
controller.mount(self.target, self.cgroup_root) controller.mount(self.target, self.cgroup_root)
except TargetError: except TargetError:
message = 'cgroups {} controller is not supported by the target' message = 'cgroups {} controller is not supported by the target'
raise TargetError(message.format(controller.kind)) raise TargetError(message.format(controller.kind))
self.logger.debug('Controller %s enabled', controller.kind)
self.controllers[idx] = controller
def list_subsystems(self): def list_subsystems(self):
subsystems = [] subsystems = []
for line in self.target.execute('cat /proc/cgroups').split('\n')[1:]: for line in self.target.execute('{} cat /proc/cgroups'\
.format(self.target.busybox)).split('\n')[1:]:
line = line.strip() line = line.strip()
if not line or line.startswith('#'): if not line or line.startswith('#'):
continue continue
@ -198,9 +273,9 @@ class CgroupsModule(Module):
return subsystems return subsystems
def get_cgroup_controller(self, kind): def controller(self, kind):
for controller in self.controllers: if kind not in self.controllers:
if controller.kind == kind: self.logger.warning('Controller %s not available', kind)
return controller return None
raise ValueError(kind) return self.controllers[kind]

View File

@ -57,6 +57,10 @@ def ssh_get_shell(host, username, password=None, keyfile=None, port=None, timeou
conn.login(host, username, password, port=port, login_timeout=timeout) conn.login(host, username, password, port=port, login_timeout=timeout)
except EOF: except EOF:
raise TargetError('Could not connect to {}; is the host name correct?'.format(host)) raise TargetError('Could not connect to {}; is the host name correct?'.format(host))
conn.setwinsize(500,200)
conn.sendline('')
conn.prompt()
conn.setecho(False)
return conn return conn