[BACK]Return to dvs.c CVS log [TXT][DIR] Up to [local] / prex-old / dev / power

Annotation of prex-old/dev/power/dvs.c, Revision 1.1.1.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 2007, Kohsuke Ohtani
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. Neither the name of the author nor the names of any co-contributors
                     14:  *    may be used to endorse or promote products derived from this software
                     15:  *    without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * dvs.c - dynamic voltage scaling feature
                     32:  */
                     33:
                     34: /*
                     35:  * Dynamic voltage scaling (DVS) is widely used with mobile systems
                     36:  * to save the processor power consumption, with minimum impact on
                     37:  * performance. The basic idea is come from the fact the power
                     38:  * consumption is proportional to V^2 x f, where V is voltage and
                     39:  * f is frequency. Since processor does not always require the full
                     40:  * performance, we can reduce power consumption by lowering voltage
                     41:  * and frequeceny.
                     42:  */
                     43: #include <driver.h>
                     44: #include <pm.h>
                     45: #include "dvs.h"
                     46:
                     47: /* #define DEBUG_DVS 1 */
                     48:
                     49: #ifdef DEBUG_DVS
                     50: #define dvs_printf(fmt, args...)       printk("dvs: " fmt, ## args)
                     51: #else
                     52: #define dvs_printf(fmt...)             do {} while (0)
                     53: #endif
                     54:
                     55: #define INTERVAL_MSEC          50
                     56: #define INTERVAL_TICK          msec_to_tick(INTERVAL_MSEC)
                     57: #define WEIGHT                 20
                     58:
                     59: static struct dpc dvs_dpc;     /* DVC object */
                     60:
                     61: static int dvs_capable;                /* True if the system has dvs capability */
                     62: static int dvs_enabled;                /* True if dvs is enabled */
                     63:
                     64: static int cur_speed;          /* Current CPU speed (%) */
                     65: static int max_speed;          /* Maximum CPU speed (%) */
                     66: static int min_speed;          /* Minimum CPU speed (%) */
                     67:
                     68: static int run_cycles;   /* The non-idle CPU cycles in the last interval */
                     69: static int idle_cycles;          /* The idle CPU cycles in the last interval */
                     70: static int excess_cycles; /* The cycles left over from the last interval */
                     71:
                     72: static int avg_workload;       /* Average workload */
                     73: static int avg_deadline;       /* Average deadline */
                     74:
                     75: static u_long elapsed_ticks;
                     76:
                     77: /*
                     78:  * Predict CPU speed
                     79:  *
                     80:  * DVS Algorithm: Weiser Style
                     81:  *
                     82:  *  If the utilization prediction x is high (over 70%), increase the speed
                     83:  *  by 20% of the maximum speed. If the utilization prediction is low
                     84:  *  (under 50%), decrease the speed by (60 - x)% of the maximum speed.
                     85:  *
                     86:  *  excess_cycles is defined as the number of uncompleted run cycles from
                     87:  *  the last interval. For example, if we find 70% activity when runnig
                     88:  *  at full speed, and their processor speed was set to 50% during that
                     89:  *  interval, excess_cycles is set to 20%. This value (20%) is used to
                     90:  *  calculate the processor speed in the next interval.
                     91:  *
                     92:  * Refernce:
                     93:  *   M.Weiser, B.Welch, A.Demers, and S.Shenker,
                     94:  *   "Scheduling for Reduced CPU Energy", In Proceedings of the
                     95:  *   1st Symposium on Operating Systems Design and Implementation,
                     96:  *   pages 13-23, November 1994.
                     97:  */
                     98: static int
                     99: predict_cpu_speed(int speed)
                    100: {
                    101:        int next_excess;
                    102:        int run_percent;
                    103:        int newspeed = speed;
                    104:
                    105:        run_cycles += excess_cycles;
                    106:        run_percent = (run_cycles * 100) / (idle_cycles + run_cycles);
                    107:
                    108:        next_excess = run_cycles - speed * (run_cycles + idle_cycles) / 100;
                    109:        if (next_excess < 0)
                    110:                next_excess = 0;
                    111:
                    112:        if (excess_cycles > idle_cycles)
                    113:                newspeed = 100;
                    114:        else if (run_percent > 70)
                    115:                newspeed = speed + 20;
                    116:        else if (run_percent < 50)
                    117:                newspeed = speed - (60 - run_percent);
                    118:
                    119:        if (newspeed > max_speed)
                    120:                newspeed = max_speed;
                    121:        if (newspeed < min_speed)
                    122:                newspeed = min_speed;
                    123:
                    124:        dvs_printf("run_percent=%d next_excess=%d newspeed=%d\n\n",
                    125:                   run_percent, next_excess, newspeed);
                    126:
                    127:        excess_cycles = next_excess;
                    128:        return newspeed;
                    129: }
                    130:
                    131: /*
                    132:  * Predict max CPU speed
                    133:  *
                    134:  * DVS Algorithm: AVG<3>
                    135:  *
                    136:  *  Computes an exponentially moving average of the previous intervals.
                    137:  *  <wight> is the relative wighting of past intervals relative to
                    138:  *  the current interval.
                    139:  *
                    140:  *   predict = (weight x current + past) / (weight + 1)
                    141:  *
                    142:  * Refernce:
                    143:  *   K.Govil, E.Chan, H.Wasserman,
                    144:  *   "Comparing Algorithm for Dynamic Speed-Setting of a Low-Power CPU".
                    145:  *   Proc. 1st Int'l Conference on Mobile Computing and Networking, Nov 1995.
                    146:  */
                    147: static int
                    148: predict_max_speed(int speed)
                    149: {
                    150:        int new_workload;
                    151:        int new_deadline;
                    152:        int newspeed;
                    153:
                    154:        new_workload = run_cycles * speed;
                    155:        new_deadline = (run_cycles + idle_cycles) * speed;
                    156:
                    157:        avg_workload = (avg_workload * WEIGHT + new_workload) / (WEIGHT + 1);
                    158:        avg_deadline = (avg_deadline * WEIGHT + new_deadline) / (WEIGHT + 1);
                    159:
                    160:        newspeed = avg_workload * 100 / avg_deadline;
                    161:
                    162:        dvs_printf("new_workload=%u new_deadline=%u\n",
                    163:                   new_workload, new_deadline);
                    164:        dvs_printf("avg_workload=%u avg_deadline=%u\n",
                    165:                   avg_workload, avg_deadline);
                    166:        return newspeed;
                    167: }
                    168:
                    169: /*
                    170:  * DPC routine to set CPU speed.
                    171:  */
                    172: static void
                    173: dpc_adjust_speed(void *arg)
                    174: {
                    175:        int newspeed = (int)arg;
                    176:
                    177:        dvs_printf("dvs_adjust_speed: speed=%d\n", newspeed);
                    178:        cpu_setperf(newspeed);
                    179:        cur_speed = cpu_getperf();
                    180: }
                    181:
                    182: /*
                    183:  * Timer hook routine called by tick handler.
                    184:  */
                    185: static void
                    186: dvs_tick(int idle)
                    187: {
                    188:        int newspeed;
                    189:
                    190:        elapsed_ticks++;
                    191:        if (idle)
                    192:                idle_cycles++;
                    193:        else
                    194:                run_cycles++;
                    195:
                    196:        if (elapsed_ticks < INTERVAL_TICK)
                    197:                return;
                    198:
                    199:        /* Predict max CPU speed */
                    200:        max_speed = predict_max_speed(cur_speed);
                    201:
                    202:        dvs_printf("DVS: run_cycles=%d idle_cycles=%d cur_speed=%d max_speed=%d\n",
                    203:                   run_cycles, idle_cycles, cur_speed, max_speed);
                    204:        /*
                    205:         * Predict next CPU speed
                    206:         */
                    207:        newspeed = predict_cpu_speed(cur_speed);
                    208:        if (newspeed != cur_speed) {
                    209:                sched_dpc(&dvs_dpc, dpc_adjust_speed,
                    210:                          (void *)newspeed);
                    211:        }
                    212:        run_cycles = 0;
                    213:        idle_cycles = 0;
                    214:        elapsed_ticks = 0;
                    215: }
                    216:
                    217: /*
                    218:  * Enable DVS operation
                    219:  */
                    220: void
                    221: dvs_enable(void)
                    222: {
                    223:
                    224:        if (!dvs_capable)
                    225:                return;
                    226:
                    227:        run_cycles = 0;
                    228:        idle_cycles = 0;
                    229:        elapsed_ticks = 0;
                    230:
                    231:        max_speed = 100;        /* max 100% */
                    232:        min_speed = 5;          /* min   5% */
                    233:        cur_speed = cpu_getperf();
                    234:
                    235:        timer_hook(dvs_tick);
                    236:        dvs_enabled = 1;
                    237: }
                    238:
                    239: /*
                    240:  * Disable DVS operation
                    241:  */
                    242: void
                    243: dvs_disable(void)
                    244: {
                    245:
                    246:        if (!dvs_capable)
                    247:                return;
                    248:
                    249:        timer_hook(NULL);
                    250:
                    251:        /* Set CPU speed to 100% */
                    252:        cpu_setperf(100);
                    253:        dvs_enabled = 0;
                    254: }
                    255:
                    256: /*
                    257:  * Initialize dvs
                    258:  */
                    259: void
                    260: dvs_init(void)
                    261: {
                    262:
                    263:        if (cpu_initperf())
                    264:                return;
                    265:
                    266:        dvs_capable = 1;
                    267: }

CVSweb