Commit 246edb75 authored by Swann Perarnau's avatar Swann Perarnau

[refactor] Move control scheme to its own module

The "control" part of the NRM is bound to change and become more complex
in the near future, so move it in its own module.

This refactor also introduce some controller logic. Control is split
into 3 steps: planning, execution and updates. The goal is to use this
new code organization as a way to abstract different control policies
that could be implemented later.

Note that we might at some point move into a "control manager" and a
bunch of "policies" and "actuators", as a way of matching typical
control theory vocabulary.
parent f85f04bb
from __future__ import print_function
import logging
logger = logging.getLogger('nrm')
class Action(object):
"""Information about a control action."""
def __init__(self, target, command):
self.target = target
self.command = command
class Controller(object):
"""Implements a control loop for resource management."""
def __init__(self, am, cm, rm):
self.application_manager = am
self.container_manager = cm
self.resource_manager = rm
def planify(self, target, machineinfo):
"""Plan the next action for the control loop."""
total_power = machineinfo['energy']['power']['total']
if total_power < target:
for identity, application in \
self.application_manager.applications.iteritems():
if 'i' in application.get_allowed_thread_requests():
return Action(application, 'i')
elif total_power > target:
for identity, application in \
self.application_manager.applications.iteritems():
if 'd' in application.get_allowed_thread_requests():
return Action(application, 'd')
return None
def execute(self, action):
"""Build the action for the appropriate manager."""
assert action
target_threads = action.target.threads
update = {'type': 'application',
'command': 'threads',
'uuid': action.target.uuid,
'event': 'threads',
}
if action.command == 'i':
payload = target_threads['cur'] + 1
elif action.command == 'd':
payload = target_threads['cur'] - 1
else:
assert False, "impossible command"
update['payload'] = payload
return update
def update(self, action, request):
"""Update tracking across the board to reflect the last action."""
assert action
action.target.do_thread_transition(action.command)
......@@ -2,6 +2,7 @@ from __future__ import print_function
from applications import ApplicationManager
from containers import ContainerManager
from controller import Controller
from functools import partial
import json
import logging
......@@ -126,29 +127,11 @@ class Daemon(object):
logger.info("sending sensor message: %r", msg)
def do_control(self):
total_power = self.machine_info['energy']['power']['total']
for identity, application in \
self.application_manager.applications.iteritems():
update = {'type': 'application',
'command': 'threads',
'uuid': identity,
'event': 'threads',
}
if total_power < self.target:
if 'i' in application.get_allowed_thread_requests():
update['payload'] = application.threads['cur'] + 1
self.downstream_pub.send_json(update)
application.do_thread_transition('i')
elif total_power > self.target:
if 'd' in application.get_allowed_thread_requests():
update['payload'] = application.threads['cur'] - 1
self.downstream_pub.send_json(update)
application.do_thread_transition('d')
else:
continue
logger.info("application now in state: %s",
application.thread_state)
action = self.controller.planify(self.target, self.machine_info)
if action:
msg = self.controller.execute(action)
self.downstream_pub.send_json(msg)
self.controller.update(action, msg)
def do_signal(self, signum, frame):
if signum == signal.SIGINT:
......@@ -237,6 +220,9 @@ class Daemon(object):
self.resource_manager = ResourceManager()
self.container_manager = ContainerManager(self.resource_manager)
self.application_manager = ApplicationManager()
self.controller = Controller(self.application_manager,
self.container_manager,
self.resource_manager)
# create sensor manager and make first measurement
self.sensor = sensor.SensorManager()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment