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

Diff for /prex-old/dev/power/cpufreq.c between version 1.1.1.1 and 1.1.1.1.2.1

version 1.1.1.1, 2008/06/03 10:38:42 version 1.1.1.1.2.1, 2008/08/13 17:12:25
Line 1 
Line 1 
 /*-  /*-
  * Copyright (c) 2007, Kohsuke Ohtani   * Copyright (c) 2007-2008, Kohsuke Ohtani
  * All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
Line 31 
Line 31 
  * cpufreq.c - CPU frequency control   * cpufreq.c - CPU frequency control
  */   */
   
   /*
    * Dynamic voltage scaling (DVS)
    *
    * DVS is widely used with mobile systems to save the processor
    * power consumption, with minimum impact on performance.
    * The basic idea is come from the fact the power consumption is
    * proportional to V^2 x f, where V is voltage and f is frequency.
    * Since processor does not always require the full performance,
    * we can reduce power consumption by lowering voltage and frequeceny.
    */
   
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
 #include <driver.h>  #include <driver.h>
 #include <pm.h>  #include <pm.h>
 #include "dvs.h"  #include <cpu.h>
   #include <cpufreq.h>
   
 /* #define DEBUG_CPUFREQ 1 */  /* #define DEBUG_CPUFREQ 1 */
   
 #ifdef DEBUG_CPUFREQ  #ifdef DEBUG_CPUFREQ
 #define cf_printf(fmt, args...) printk("cpufreq: " fmt, ## args)  #define DPRINTF(a) printf a
 #else  #else
 #define cf_printf(fmt...)        do {} while (0)  #define DPRINTF(a)
 #endif  #endif
   
   /*
    * DVS parameters
    */
   #define INTERVAL_MSEC           50
   #define INTERVAL_TICK           msec_to_tick(INTERVAL_MSEC)
   #define WEIGHT                  20
   
 static int cpufreq_open(device_t dev, int mode);  static int cpufreq_open(device_t dev, int mode);
 static int cpufreq_ioctl(device_t dev, int cmd, u_long arg);  static int cpufreq_ioctl(device_t dev, u_long cmd, void *arg);
 static int cpufreq_close(device_t dev);  static int cpufreq_close(device_t dev);
 static int cpufreq_init(void);  static int cpufreq_init(void);
   
Line 58 
Line 77 
         /* init */      cpufreq_init,          /* init */      cpufreq_init,
 };  };
   
   /*
    * Device I/O table
    */
 static struct devio cpufreq_io = {  static struct devio cpufreq_io = {
         /* open */      cpufreq_open,          /* open */      cpufreq_open,
         /* close */     cpufreq_close,          /* close */     cpufreq_close,
Line 67 
Line 89 
         /* event */     NULL,          /* event */     NULL,
 };  };
   
 static device_t cpufreq_dev;            /* Device object */  static device_t cpufreq_dev;    /* Device object */
   
   static int cpufreq_policy;      /* Frequecy control policy */
   
   static struct dpc dvs_dpc;      /* DPC object */
   
   static int dvs_capable;         /* True if the system has dvs capability */
   static int dvs_enabled;         /* True if dvs is enabled */
   
   static int cur_speed;           /* Current CPU speed (%) */
   static int max_speed;           /* Maximum CPU speed (%) */
   static int min_speed;           /* Minimum CPU speed (%) */
   
   static int run_cycles;    /* The non-idle CPU cycles in the last interval */
   static int idle_cycles;   /* The idle CPU cycles in the last interval */
   static int excess_cycles; /* The cycles left over from the last interval */
   
   static int avg_workload;        /* Average workload */
   static int avg_deadline;        /* Average deadline */
   
   static u_long elapsed_ticks;
   
   
 /*  /*
  * Frequecy control policy   * Predict CPU speed.
    *
    * DVS Algorithm: Weiser Style
    *
    *  If the utilization prediction x is high (over 70%), increase the
    *  speed by 20% of the maximum speed. If the utilization prediction
    *  is low (under 50%), decrease the speed by (60 - x)% of the
    *  maximum speed.
    *
    *  excess_cycles is defined as the number of uncompleted run cycles
    *  from the last interval. For example, if we find 70% activity
    *  when runnig at full speed, and their processor speed was set to
    *  50% during that interval, excess_cycles is set to 20%. This
    *  value (20%) is used to calculate the processor speed in the next
    *  interval.
    *
    * Refernce:
    *   M.Weiser, B.Welch, A.Demers, and S.Shenker,
    *   "Scheduling for Reduced CPU Energy", In Proceedings of the
    *   1st Symposium on Operating Systems Design and Implementation,
    *   pages 13-23, November 1994.
  */   */
 static int cpufreq_policy;  static int
   predict_cpu_speed(int speed)
   {
           int next_excess;
           int run_percent;
           int newspeed = speed;
   
           run_cycles += excess_cycles;
           run_percent = (run_cycles * 100) / (idle_cycles + run_cycles);
   
           next_excess = run_cycles - speed * (run_cycles + idle_cycles) / 100;
           if (next_excess < 0)
                   next_excess = 0;
   
           if (excess_cycles > idle_cycles)
                   newspeed = 100;
           else if (run_percent > 70)
                   newspeed = speed + 20;
           else if (run_percent < 50)
                   newspeed = speed - (60 - run_percent);
   
           if (newspeed > max_speed)
                   newspeed = max_speed;
           if (newspeed < min_speed)
                   newspeed = min_speed;
   
           DPRINTF(("DVS: run_percent=%d next_excess=%d newspeed=%d\n\n",
                    run_percent, next_excess, newspeed));
   
           excess_cycles = next_excess;
           return newspeed;
   }
   
   /*
    * Predict max CPU speed.
    *
    * DVS Algorithm: AVG<3>
    *
    *  Computes an exponentially moving average of the previous intervals.
    *  <wight> is the relative weighting of past intervals relative to
    *  the current interval.
    *
    *   predict = (weight x current + past) / (weight + 1)
    *
    * Refernce:
    *   K.Govil, E.Chan, H.Wasserman,
    *   "Comparing Algorithm for Dynamic Speed-Setting of a Low-Power CPU".
    *   Proc. 1st Int'l Conference on Mobile Computing and Networking,
    *   Nov 1995.
    */
 static int  static int
   predict_max_speed(int speed)
   {
           int new_workload;
           int new_deadline;
           int newspeed;
   
           new_workload = run_cycles * speed;
           new_deadline = (run_cycles + idle_cycles) * speed;
   
           avg_workload = (avg_workload * WEIGHT + new_workload) / (WEIGHT + 1);
           avg_deadline = (avg_deadline * WEIGHT + new_deadline) / (WEIGHT + 1);
   
           newspeed = avg_workload * 100 / avg_deadline;
   
           DPRINTF(("DVS: new_workload=%u new_deadline=%u\n",
                    new_workload, new_deadline));
           DPRINTF(("DVS: avg_workload=%u avg_deadline=%u\n",
                    avg_workload, avg_deadline));
           return newspeed;
   }
   
   /*
    * DPC routine to set CPU speed.
    *
    * This is kicked by dvs_tick() if it needed.
    */
   static void
   dpc_adjust_speed(void *arg)
   {
           int newspeed = (int)arg;
   
           DPRINTF(("DVS: new speed=%d\n", newspeed));
           cpu_setperf(newspeed);
           cur_speed = cpu_getperf();
   }
   
   /*
    * Timer hook routine called by tick handler.
    */
   static void
   dvs_tick(int idle)
   {
           int newspeed;
   
           elapsed_ticks++;
           if (idle)
                   idle_cycles++;
           else
                   run_cycles++;
   
           if (elapsed_ticks < INTERVAL_TICK)
                   return;
   
           /* Predict max CPU speed */
           max_speed = predict_max_speed(cur_speed);
   
           DPRINTF(("DVS: run_cycles=%d idle_cycles=%d cur_speed=%d "
                    "max_speed=%d\n",
                    run_cycles, idle_cycles, cur_speed, max_speed));
           /*
            * Predict next CPU speed
            */
           newspeed = predict_cpu_speed(cur_speed);
           if (newspeed != cur_speed) {
                   sched_dpc(&dvs_dpc, &dpc_adjust_speed, (void *)newspeed);
           }
           run_cycles = 0;
           idle_cycles = 0;
           elapsed_ticks = 0;
   }
   
   /*
    * Enable DVS operation
    */
   static void
   dvs_enable(void)
   {
   
           if (!dvs_capable)
                   return;
   
           run_cycles = 0;
           idle_cycles = 0;
           elapsed_ticks = 0;
   
           max_speed = 100;        /* max 100% */
           min_speed = 5;          /* min   5% */
           cur_speed = cpu_getperf();
   
           timer_hook(dvs_tick);
           dvs_enabled = 1;
   }
   
   /*
    * Disable DVS operation
    */
   static void
   dvs_disable(void)
   {
   
           if (!dvs_capable)
                   return;
   
           timer_hook(NULL);
   
           /* Set CPU speed to 100% */
           cpu_setperf(100);
           dvs_enabled = 0;
   }
   
   static int
 cpufreq_open(device_t dev, int mode)  cpufreq_open(device_t dev, int mode)
 {  {
   
Line 89 
Line 311 
 }  }
   
 static int  static int
 cpufreq_ioctl(device_t dev, int cmd, u_long arg)  cpufreq_ioctl(device_t dev, u_long cmd, void *arg)
 {  {
   
         return 0;          return 0;
Line 119 
Line 341 
 {  {
         int policy;          int policy;
   
           if (cpu_initperf())
                   return -1;
   
         /* Create device object */          /* Create device object */
         cpufreq_dev = device_create(&cpufreq_io, "cpufreq", DF_CHR);          cpufreq_dev = device_create(&cpufreq_io, "cpufreq", DF_CHR);
         ASSERT(cpufreq_dev);          ASSERT(cpufreq_dev);
   
         dvs_init();          dvs_capable = 1;
   
         policy = pm_getpolicy();          policy = pm_getpolicy();
         if (policy == PM_POWERSAVE)          if (policy == PM_POWERSAVE)

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.1.2.1

CVSweb