powerpolicy.py 5.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
""" Power Policy Module:
    This module provides the interfaces that enable use of policies to control
    processor power using controls available in the processor.
    E.g. Dynamic Duty Cycle Modulation (DDCM), Dynamic Voltage
    and Frequency Scaling (DVFS) and Power capping

    The policies target problems like workload imbalance, memory saturation
    seen very often in parallel applications.

    To mitigate workload imbalance the policies adapt core frequencies to
    workload characteristics through use of core-specific power controls.
    The user can choose from three policies - DDCM, DVFS and a combination of
    DVFS and DDCM to mitiage  workload imbalance in parallel applications that
    use barrier synchronizations.
    The effective frequency of cpus not on the critical path of execution is
    reduced thereby lowering energy with little or no adverse impact on
    performance.

    Additional information:

    Bhalachandra, Sridutt, Allan Porterfield, Stephen L. Olivier, and Jan F.
    Prins. "An adaptive core-specific runtime for energy efficiency." In 2017
    IEEE International Parallel and Distributed Processing Symposium (IPDPS),
    pp. 947-956. 2017.

    Note: Power controls (DVFS, DDCM and power capping) needs to be enabled
    before using these interfaces. Please check your architecture specification
    for supported power contols and related information.
"""
import ddcmpolicy


class PowerPolicyManager:
    """ Used for power policy application """

    def __init__(self, ncpus=0, policy='NONE', damper=0.1, slowdown=1.1):
        self.policy = policy
        self.damper = damper
        self.slowdown = slowdown

        # TODO: Need to set this based on container configuration
        self.ncpus = ncpus

        # Intiliaze all power interfaces
        self.ddcmpolicy = ddcmpolicy.DDCMPolicy()

        # Power levels
        self.maxdclevel = self.ddcmpolicy.maxdclevel
        # TODO: Need to set this value when DVFS policies are added
        self.maxfreqlevel = -1
        # TODO: Need to only allow power changes to cpus in container
        self.dclevel = dict.fromkeys(range(0, self.ncpus), self.maxdclevel)
        self.freqlevel = dict.fromkeys(range(0, self.ncpus), self.maxfreqlevel)

        # Book-keeping
        self.damperexits = 0
        self.slowdownexits = 0
        self.prevtolalphasetime = 10000.0   # Random large value

    def run_policy(self, cpu, startcompute, endcompute, startbarrier,
                   endbarrier):
        # Select and invoke appropriate power policy
        # TODO: Need to add a better policy selection logic in addition to user
        # specified
        ret, value = self.invoke_policy(cpu, self.policy, self.dclevel[cpu],
                                        self.freqlevel[cpu], startcompute,
                                        endcompute, startbarrier, endbarrier)
        if self.policy == 'DDCM' and ret in ['DDCM', 'SLOWDOWN']:
            self.dclevel[cpu] = value

    def invoke_policy(self, cpu, policy, dclevel, freqlevel, startcompute,
                      endcompute, startbarrier, endbarrier):
        # Run with no policy
        if policy == "NONE":
            return 'NONE', -1

        # Calculate time spent in computation, barrier in current phase along
        # with total phase time
        computetime = endcompute - startcompute
        barriertime = endbarrier - startbarrier
        totalphasetime = computetime + barriertime

        # If the current phase length is less than the damper value, then do
        # not use policy. This avoids use of policy during startup operation
        # insignificant phases
        if totalphasetime < self.damper:
            self.damperexits += 1
            return 'DAMPER', -1

        # Reset value for next phase
        self.prevtolalphasetime = totalphasetime

        # If the current phase has slowed down beyond the threshold set, then
        # reset power. This helps correct error in policy application or acts
        # as a rudimentary way to detect phase change
        if(dclevel < self.ddcmpolicy.maxdclevel and totalphasetime >
                self.slowdown * self.prevtolalphasetime):
            self.ddcmpolicy.dc.reset(cpu)
            newdclevel = self.ddcmpolicy.maxdclevel

            return 'SLOWDOWN', newdclevel

        # Invoke the correct policy based on operation module
        if policy == "DDCM":
            newdclevel = self.ddcmpolicy.execute(cpu, dclevel, computetime,
                                                 totalphasetime)

        # TODO: Add DVFS and Combined policies

            return 'DDCM', newdclevel

    def print_policy_stats(self, resetflag=False):
        # Get statistics for policy run
        print('PowerPolicyManager: DamperExits %d SlowdownExits %d' %
              (self.damperexits, self.slowdownexits))
        self.ddcmpolicy.print_stats(resetflag)

        if resetflag:
            self.damperexits = 0
            self.slowdownexits = 0

    def power_reset(self, cpu):
        # Reset all power controls
        self.ddcmpolicy.dc.reset(cpu)

        self.dclevel[cpu] = self.maxdclevel

    def power_check(self, cpu):
        # Check status of all power controls
        return self.ddcmpolicy.dc.check(cpu)