controller.py 4.61 KB
Newer Older
1 2 3
from __future__ import print_function

import logging
Valentin Reis's avatar
Valentin Reis committed
4
import time
5
import math
6 7

logger = logging.getLogger('nrm')
Valentin Reis's avatar
Valentin Reis committed
8
logger_power = logging.getLogger('power')
9

10

11 12 13 14
class Action(object):

    """Information about a control action."""

15
    def __init__(self, target, command, delta):
16 17
        self.target = target
        self.command = command
18 19
        self.delta = delta

20

21 22 23 24 25 26 27 28 29 30 31
class PowerActuator(object):

    """Actuator in charge of power control."""

    def __init__(self, sm):
        self.sensor_manager = sm

    def available_actions(self, target):
        actions = []
        pl = self.sensor_manager.get_powerlimits()
        logger.info("power limits: %r:", pl)
32 33
        if target == 'i':
            for k in pl:
34
                r = range(int(pl[k]['curW'])+1, int(pl[k]['maxW']))
35 36 37
                actions.extend([Action(k, s, s - r[0]) for s in r])
        elif target == 'd':
            for k in pl:
38 39
                r = range(1, int(pl[k]['curW']))
                actions.extend([Action(k, s, r[-1] - s) for s in r])
40 41 42
        return actions

    def execute(self, action):
Valentin Reis's avatar
Valentin Reis committed
43 44 45 46
        logger.info("changing power limit. command: %r, delta: %r, target: %r",
                    action.command, action.delta, action.target)
        # sensor_manager is a SensorManager, which is not only about sensing
        # but also about setting power limits.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
        self.sensor_manager.set_powerlimit(action.target, action.command)

    def update(self, action):
        pass


class DiscretizedPowerActuator(object):

    """Actuator in charge of power control via discretization."""

    def __init__(self, sm, lowerboundwatts, k):
        self.sensor_manager = sm
        self.lowerboundwatts = lowerboundwatts  # the minimal cpu wattage
        self.k = k  # the number of arms

    def available_actions(self):
        actions = []
        pl = self.sensor_manager.get_powerlimits()
        logger.info("BanditPowerActuator: power limits %r", pl)
        maxW = int(pl[[k for k, i in pl.items()][0]]['maxW'])
        if maxW < self.lowerboundwatts:
            logger.error("BanditPowerActuator: The provided power lowerbound\
                          is higher than the available maximum CPU wattage.")
        rangeW = maxW - self.lowerboundwatts
        arms = [self.lowerboundwatts + (float(a)*rangeW/float(self.k))
                for a in range(1, self.k+1)]
        logger.info("BanditPowerActuator: discretized power limits: %r:", arms)
        actions = [Action([k for k, i in pl.items()][0], int(math.floor(a)), 0)
                   for a in arms]
        return(actions)

    def execute(self, action):
        logger.info("changing power limit: %r, %r",
                    action.command, action.delta)
        self.sensor_manager.set_powerlimit(action.target, action.command)
82 83 84 85

    def update(self, action):
        pass

86 87 88 89 90

class Controller(object):

    """Implements a control loop for resource management."""

91
    def __init__(self, actuators, strategy):
92
        self.actuators = actuators
93 94 95

    def planify(self, target, machineinfo):
        """Plan the next action for the control loop."""
96 97 98 99 100 101 102
        # current_e = float(machineinfo['energy']['energy']
        #                  ['cumulative']['package-0'])/(1000*1000) # in joules
        # In joules:
        current_p = float(machineinfo['energy']['power']['p0'])/(1000*1000)
        current_p = float(machineinfo['energy']['power']['p1'])/(1000*1000)
        logger_power.info("%s %s %s" % (time.time(), current_p, current_p))
        return (None, None)
103

104
    def execute(self, action, actuator):
105
        """Build the action for the appropriate manager."""
106
        actuator.execute(action)
107

108
    def update(self, action, actuator):
109
        """Update tracking across the board to reflect the last action."""
110
        actuator.update(action)
111 112 113 114

    def run_policy(self, containers):
        """Run policies on containers with policies set."""
        for container in containers:
115
            pp = containers[container].power
116 117 118 119 120 121 122 123 124 125 126 127
            if pp['policy']:
                apps = self.actuators[0].application_manager.applications
                if apps:
                    app = next(apps[a] for a in apps if apps[a].container_uuid
                               == container)
                    ids = containers[container].resources['cpus']
                    # Run policy only if all phase contexts have been received
                    if not filter(lambda i: not app.phase_contexts[i]['set'],
                                  ids):
                        pp['manager'].run_policy(app.phase_contexts)
                        if filter(lambda i: app.phase_contexts[i]['set'], ids):
                            logger.debug("Phase context not reset %r", app)