linux内核中一个有趣的函数calibrate_delay()。calibrate_delay()函数能计算出cpu在一秒钟内执行了多少次一个极短的循环,计算出来的值经过处理后得到BogoMIPS值,
    BogoBogus()的意思,MIPSmillions of instructionspersecond(百万条指令每秒)的缩写。这样我们就知道了其实这个函数是linux内核中一个cpu性能测试函数。由于内核对这个数值的需求不高,所以内核使用了一个十分简单而有效的算法用于得到这个值。这个值虽然不准确,但也足以令我们心动。如果你想了解自己机器的BogoMIPS,你能察看/proc/cpuinfo文件中的最后一行(可能是其他行),下面是Dm355cpuinfo的内容。

 

# cat /proc/cpuinfo 

Processor       : ARM926EJ-Sid(wb) rev 5 (v5l)

BogoMIPS        : 107.72

Features        : swp half thumb fastmult edsp java

CPU implementer : 0x41

CPU architecture: 5TEJ

CPU variant     : 0x0

CPU part        : 0x926

CPU revision    : 5

Cache type      : write-back

Cache clean     : cp15 c7 ops

Cache lockdown  : format C

Cache format    : Harvard

I size          : 16384

I assoc         : 4

I line length   : 32

I sets          : 128

D size          : 8192

D assoc         : 4

D line length   : 32

D sets          : 64

 

Hardware        : DaVinci DM355 EVM

Revision        : 3500000

Serial          : 0000000000000000

在你知道了自己cpuBogoMIPS之后,如果你觉得不过瘾,那么让我们一起来看看calibrate_delay函数是怎么完成工作的。
   下面是calibrate_delay的原始码,我在每行之前都加上了行号,以便讲解。
   1 #define LPS_PREC 8
   2 void __init calibrate_delay(void)
   3 {
   4  unsigned long ticks,loopbit;
   5  int lps_precision=LPS_PREC
   6 
   7  loops_per_sec=(1>=1;
   26  loopbit=loop_per_sec;
   27  while(lps_precision-- && (loopbit >>=1) ) {
   28   loops_per_sec |= loopbit;
   29   ticks=jiffies;
   30   while(ticks==jiffies);
   31   ticks=jiffies;
   32   __delay(loops_per_sec);
   33   if(jiffies!=ticks) /* longer than 1 tick */
   34    loops_per_sec &=~loopbit;
   35  }
   36 /* finally,adjust loops per second in terms of seconds
   37 * instead of clocks */
   38  loops_per_sec *= HZ;
   39 /* Round the value and print it */
   40  printk(“%lu.%02lu BogoMIPSn”,
   41   (loops_per_sec+2500)/500000,
   42   ((loops_per_sec+2500)/5000) % 100);
   43 }
   对calibrate_delay()函数分析如下:
   1 定义计算BogoMIPS的精度,这个值越大,则计算出的BogoMIPS越精确。
   7 loops_per_sec为每秒钟执行一个极短的循环的次数。
   9 printk()是内核消息日志打印函数,用法同printf()函数。
   10 1021行,是第一次计算loops_per_sec的值,这次计算只是个粗略的计算,为下面的计算打好基础。
 
  11 1116行,是用于等待一个新的定时器滴答(他大概是百万分之一秒)的开始。能想象我们要计算loops_per_sec的值,能在一个滴答的开始时,即时重复执行一个极短的循环,当一个滴答结束时,这个循环执行了多少次就是我们需求的初步的值,再用他乘以一秒钟内的滴答数就是
loops_per_sec的值。
   12 系统用jiffies全局变量记录了从系统开始工作到目前为止,所经过的滴答数。他会被内核自动更新。这行语句用于记录当前滴答数到tick变量中。
   13 注意这是个没有循环体得空循环,第14行仅有一个号。这条循环语句是通过判断tick的值和jiffies的值是否不同,来判断jiffies是否变化,即是否一个新的滴答开始了
   16 记录下新的滴答数以备后用。
   17 根据loops_per_sec值进行延时(及执行loop_per_sec次极短循环)。
   18以下三行用于判断执行的延时是否超过一个滴答。一般loops_per_sec的初始值并不大,所以循环会逐步加大loops_per_sec的值,直到延时超过一个滴答。我们能看出,前一次loops_per_sec的值还因太小不合适时,经过一次增大,他提高了两倍,满足了循环条件,跳出循环,而这个值实在是误差太大,所以我们还要经过第二次计算。这里还要注意的是通过上面的分析,我们能知道更加精确的loops_per_sec的值应该在目前的值和他的一半之间。
   23 这里开始就是第二次计算了。他用折半查找法在我们上面所说的范围内计算出了更精确的loops_per_sec的值。
   25 义查找范围的最小值,我把他称为起点。
   26 定义查找范围,这样我们就能看到loop_per_sec的值在起点起点加范围(终点)之间。
   27 进入循环,将查找范围减半。
   28 重新定义起点,起点在原起点加27行减半范围处,即新起点在原先起点和终点的中间。这时我们能看出loops_per_sec新起点新起点加减半范围(新终点)之间。
   29 2932行和第1217行一致,都是等待新的滴答,执行延时。
   33 如果延时过短,说明loops_per_sec的值小了,将会跳过这部分,再次进入循环。他将是通过不断的折半方式来增大。如果延时过长,说明loops_per_sec的值大了,将起点重新返回原起点,当再次进入循环,由于范围减半,故能达到减小的效果。
  38计算出每秒执行极短循环的次数。从这里我们能看出他似乎是个死循环,所以加入了lps_precision变量,来控制循环,即LPS_PREC越大,循环次数越多,越精确。可能这些不太好懂,总的说来,他首先将loop_per_sec的值定为原估算值的1/2,作为起点值(我这样称呼他),以估算值为终点值.然后找出起点值到终点值的中间值.用上面相同的方法执行一段时间的延时循环.如果延时超过了一个tick,说明loop_per_sec值偏大,则仍以原起点值为起点值,以原中间值为终点值,以起点值和终点值的中间为中间值继续进行查找,如果没有超过一个tick,说明loop_per_sec偏小,则以原中间值为起点值,以原终点值为终点值继续查找。
   40 BogoMIPS,并打印。
   至此,我们就分析完了calibrate_delay()函数。

下面是一个dm355 CPU速度的分析函数:

int CheckCpuSpeed( void )

{

      static int CurrentStatus = -255;

      int fd_cpu = -1;

      int ret = -1;

      char StrBuffer[300];

      char TmpBuf[50];

      char *pStr = NULL;

      float cpu_mips = 0;

      char delima_buf[] = ":/r/n ";

 

      if( CurrentStatus >= -1 )

      {

            fprintf(stderr,"CPU CurrentStatus is = %d /n", CurrentStatus);

            return CurrentStatus;

      }

     

 

      fd_cpu = open("/proc/cpuinfo", O_RDONLY);

      if( fd_cpu < 0 )

      {

            ERR("CheckCpuSpeed open file fail /n");

            ret = -1;

            goto CHECK_CPU_END;

           

      }

 

      ret = read(fd_cpu,  StrBuffer, sizeof(StrBuffer)-1);

      if( ret <= 0 )

      {

            ERR("read device error !!");

            ret = -1;

            goto CHECK_CPU_END;

 

      }

 

      ret = -1;

      StrBuffer[sizeof(StrBuffer)-1] = '/0';

      pStr = strtok(StrBuffer,delima_buf );

     

      while( pStr != NULL )

      {

            sscanf( pStr,"%s",TmpBuf);

           

            if( strncmp(TmpBuf, "BogoMIPS", sizeof("BogoMIPS")) == 0 )

            {

                 

                  pStr = strtok(NULL, delima_buf);

 

                  sscanf( pStr,"%f",&cpu_mips);

                 

                  fprintf(stderr,"CPU MIPS = %f /n", cpu_mips);

                 

                  if( cpu_mips > 133.0 && cpu_mips < 135.0 )

                  {

                        /*high version*/

                        fprintf(stderr,"CPU is 270Mhz/n");

                        ret = 1;

                        goto CHECK_CPU_END;

                  }

                  else

                  {

                        /*normal version*/

                        fprintf(stderr,"CPU is 216Mhz/n");

                        ret = 0;

                        goto CHECK_CPU_END;

                  }

                 

            }

           

            pStr = strtok(NULL, delima_buf);

           

      }

 

CHECK_CPU_END:

 

      if( fd_cpu >= 0 )

            close(fd_cpu);

 

 

      CurrentStatus = ret;

     

      return ret;

 

     

}

   linux内核中一个有趣的函数calibrate_delay()。calibrate_delay()函数能计算出cpu在一秒钟内执行了多少次一个极短的循环,计算出来的值经过处理后得到BogoMIPS值,
    BogoBogus()的意思,MIPSmillions of instructionspersecond(百万条指令每秒)的缩写。这样我们就知道了其实这个函数是linux内核中一个cpu性能测试函数。由于内核对这个数值的需求不高,所以内核使用了一个十分简单而有效的算法用于得到这个值。这个值虽然不准确,但也足以令我们心动。如果你想了解自己机器的BogoMIPS,你能察看/proc/cpuinfo文件中的最后一行(可能是其他行),下面是Dm355cpuinfo的内容。

 

# cat /proc/cpuinfo 

Processor       : ARM926EJ-Sid(wb) rev 5 (v5l)

BogoMIPS        : 107.72

Features        : swp half thumb fastmult edsp java

CPU implementer : 0x41

CPU architecture: 5TEJ

CPU variant     : 0x0

CPU part        : 0x926

CPU revision    : 5

Cache type      : write-back

Cache clean     : cp15 c7 ops

Cache lockdown  : format C

Cache format    : Harvard

I size          : 16384

I assoc         : 4

I line length   : 32

I sets          : 128

D size          : 8192

D assoc         : 4

D line length   : 32

D sets          : 64

 

Hardware        : DaVinci DM355 EVM

Revision        : 3500000

Serial          : 0000000000000000

在你知道了自己cpuBogoMIPS之后,如果你觉得不过瘾,那么让我们一起来看看calibrate_delay函数是怎么完成工作的。
   下面是calibrate_delay的原始码,我在每行之前都加上了行号,以便讲解。
   1 #define LPS_PREC 8
   2 void __init calibrate_delay(void)
   3 {
   4  unsigned long ticks,loopbit;
   5  int lps_precision=LPS_PREC
   6 
   7  loops_per_sec=(1>=1;
   26  loopbit=loop_per_sec;
   27  while(lps_precision-- && (loopbit >>=1) ) {
   28   loops_per_sec |= loopbit;
   29   ticks=jiffies;
   30   while(ticks==jiffies);
   31   ticks=jiffies;
   32   __delay(loops_per_sec);
   33   if(jiffies!=ticks) /* longer than 1 tick */
   34    loops_per_sec &=~loopbit;
   35  }
   36 /* finally,adjust loops per second in terms of seconds
   37 * instead of clocks */
   38  loops_per_sec *= HZ;
   39 /* Round the value and print it */
   40  printk(“%lu.%02lu BogoMIPSn”,
   41   (loops_per_sec+2500)/500000,
   42   ((loops_per_sec+2500)/5000) % 100);
   43 }
   对calibrate_delay()函数分析如下:
   1 定义计算BogoMIPS的精度,这个值越大,则计算出的BogoMIPS越精确。
   7 loops_per_sec为每秒钟执行一个极短的循环的次数。
   9 printk()是内核消息日志打印函数,用法同printf()函数。
   10 1021行,是第一次计算loops_per_sec的值,这次计算只是个粗略的计算,为下面的计算打好基础。
 
  11 1116行,是用于等待一个新的定时器滴答(他大概是百万分之一秒)的开始。能想象我们要计算loops_per_sec的值,能在一个滴答的开始时,即时重复执行一个极短的循环,当一个滴答结束时,这个循环执行了多少次就是我们需求的初步的值,再用他乘以一秒钟内的滴答数就是
loops_per_sec的值。
   12 系统用jiffies全局变量记录了从系统开始工作到目前为止,所经过的滴答数。他会被内核自动更新。这行语句用于记录当前滴答数到tick变量中。
   13 注意这是个没有循环体得空循环,第14行仅有一个号。这条循环语句是通过判断tick的值和jiffies的值是否不同,来判断jiffies是否变化,即是否一个新的滴答开始了
   16 记录下新的滴答数以备后用。
   17 根据loops_per_sec值进行延时(及执行loop_per_sec次极短循环)。
   18以下三行用于判断执行的延时是否超过一个滴答。一般loops_per_sec的初始值并不大,所以循环会逐步加大loops_per_sec的值,直到延时超过一个滴答。我们能看出,前一次loops_per_sec的值还因太小不合适时,经过一次增大,他提高了两倍,满足了循环条件,跳出循环,而这个值实在是误差太大,所以我们还要经过第二次计算。这里还要注意的是通过上面的分析,我们能知道更加精确的loops_per_sec的值应该在目前的值和他的一半之间。
   23 这里开始就是第二次计算了。他用折半查找法在我们上面所说的范围内计算出了更精确的loops_per_sec的值。
   25 义查找范围的最小值,我把他称为起点。
   26 定义查找范围,这样我们就能看到loop_per_sec的值在起点起点加范围(终点)之间。
   27 进入循环,将查找范围减半。
   28 重新定义起点,起点在原起点加27行减半范围处,即新起点在原先起点和终点的中间。这时我们能看出loops_per_sec新起点新起点加减半范围(新终点)之间。
   29 2932行和第1217行一致,都是等待新的滴答,执行延时。
   33 如果延时过短,说明loops_per_sec的值小了,将会跳过这部分,再次进入循环。他将是通过不断的折半方式来增大。如果延时过长,说明loops_per_sec的值大了,将起点重新返回原起点,当再次进入循环,由于范围减半,故能达到减小的效果。
  38计算出每秒执行极短循环的次数。从这里我们能看出他似乎是个死循环,所以加入了lps_precision变量,来控制循环,即LPS_PREC越大,循环次数越多,越精确。可能这些不太好懂,总的说来,他首先将loop_per_sec的值定为原估算值的1/2,作为起点值(我这样称呼他),以估算值为终点值.然后找出起点值到终点值的中间值.用上面相同的方法执行一段时间的延时循环.如果延时超过了一个tick,说明loop_per_sec值偏大,则仍以原起点值为起点值,以原中间值为终点值,以起点值和终点值的中间为中间值继续进行查找,如果没有超过一个tick,说明loop_per_sec偏小,则以原中间值为起点值,以原终点值为终点值继续查找。
   40 BogoMIPS,并打印。
   至此,我们就分析完了calibrate_delay()函数。

下面是一个dm355 CPU速度的分析函数:

int CheckCpuSpeed( void )

{

      static int CurrentStatus = -255;

      int fd_cpu = -1;

      int ret = -1;

      char StrBuffer[300];

      char TmpBuf[50];

      char *pStr = NULL;

      float cpu_mips = 0;

      char delima_buf[] = ":/r/n ";

 

      if( CurrentStatus >= -1 )

      {

            fprintf(stderr,"CPU CurrentStatus is = %d /n", CurrentStatus);

            return CurrentStatus;

      }

     

 

      fd_cpu = open("/proc/cpuinfo", O_RDONLY);

      if( fd_cpu < 0 )

      {

            ERR("CheckCpuSpeed open file fail /n");

            ret = -1;

            goto CHECK_CPU_END;

           

      }

 

      ret = read(fd_cpu,  StrBuffer, sizeof(StrBuffer)-1);

      if( ret <= 0 )

      {

            ERR("read device error !!");

            ret = -1;

            goto CHECK_CPU_END;

 

      }

 

      ret = -1;

      StrBuffer[sizeof(StrBuffer)-1] = '/0';

      pStr = strtok(StrBuffer,delima_buf );

     

      while( pStr != NULL )

      {

            sscanf( pStr,"%s",TmpBuf);

           

            if( strncmp(TmpBuf, "BogoMIPS", sizeof("BogoMIPS")) == 0 )

            {

                 

                  pStr = strtok(NULL, delima_buf);

 

                  sscanf( pStr,"%f",&cpu_mips);

                 

                  fprintf(stderr,"CPU MIPS = %f /n", cpu_mips);

                 

                  if( cpu_mips > 133.0 && cpu_mips < 135.0 )

                  {

                        /*high version*/

                        fprintf(stderr,"CPU is 270Mhz/n");

                        ret = 1;

                        goto CHECK_CPU_END;

                  }

                  else

                  {

                        /*normal version*/

                        fprintf(stderr,"CPU is 216Mhz/n");

                        ret = 0;

                        goto CHECK_CPU_END;

                  }

                 

            }

           

            pStr = strtok(NULL, delima_buf);

           

      }

 

CHECK_CPU_END:

 

      if( fd_cpu >= 0 )

            close(fd_cpu);

 

 

      CurrentStatus = ret;

     

      return ret;

 

     

}

 

 

Logo

更多推荐