歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

Linux實時性能的研究及測試

操作系統分為實時操作系統和分時操作系統,這是由他們的應用范圍來決定的,我們通常所用的Windows,Linux都是基於分時的通用操作系統,實時操作系統比較有名的是wind river公司的vxworks,加拿大的QNX還有基於linux的xenomai, RTLinux等等,實時操作系統和分時操作系統最大的區別就是實時操作系統的任務都能保證在固定的時間內完成,必須在規定的時間內完成,哪怕一次任務有9999次在規定的時間內完成,只有一次沒有在規定的時間內完成,那麼這個系統也不能稱之為實時的操作系統。

網上查了些資料,對這些操作系統都做了比較,然而意見不一,有人說vxworks好,有人說QNX好…….,想了一下還不如自己想個辦法來對這些系統的實時性進行測試,到時候一目了然,黑貓白貓抓住老鼠才是貓。

硬件平台x86_64, 軟件平台Linux+xenomai,既然要測實時性能,就要說說有哪些因素影響Linux實時性能,大概有以下幾點
  1. 內核進入臨界區會屏蔽所有中斷,即Linux內核有大量的不可搶占去,這裡說的是2.6以後的內核,因為2.4之前的內核都是不可搶占的,實時性更差
  2. 虛擬內存存取時間的不確定性
  3. 內核粗糙的時鐘粒度

最初我的想法是測出中斷延遲時間,也就是硬件產生一個中斷,到cpu開始執行該中斷服務程序的時間。為什麼會存在這段時間,就是上面所說的第一點,當硬件產生一個中斷時,內核可能在某個臨界區內,如果響應了該中斷,可能會對臨界區內的資源造成不同步,所以屏蔽了中斷,也就延遲了中斷,明白了這段時間的存在,我們就有了目標。

中斷延遲時間一般在us級別,因為Linux的系統時鐘一般為10ms到1ms之間,所以我們不可能用Linux的內核定時器來產生中斷然後記錄產生中斷的時間

X86下有三種定時器
         RTC定時器      頻率在2-8192HZ之間,精度太低,不可能達到us級
         PIC可編程中斷定時器    一般將其變成為1000HZ或者100HZ,精度也不能滿足要求
         TSC時間戳計數器    這個是cpu主頻相對應的,即cpu時鐘信號來一次,該計數器加一次,不過這個是個計數器,不能像定時器一樣產生中斷,到現在也沒有想到用什麼硬件定時器的方法來產生中斷,如果哪位讀者或者網友知道望不吝賜教,感激不盡。
 
我想到用軟中斷的方法來模擬硬中斷,即向進程發送一個信號,然後該進程調用信號處理程序,發送信號之後,馬上計時,這個要通過讀取TSC寄存器,獲得cpu經歷了多少個時鐘,然後在信號處理程序的入口處再一次讀取TSC寄存區,得到此時cpu經歷的時鐘數,兩次相減就得到從發送信號到進入信號處理程序cpu所經歷的時鐘數,然後除以cpu的主頻,就得到了具體的時間。
 
下面是測試程序的部分源碼
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#if defined(__i386__)

static __inline__ unsigned long long rdtsc(void)          //32位系統下讀取TSC計數器的值
{
  unsigned long long int x;
     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
     return x;                                                               //
}                                                                          

#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void)    //64位系統下讀取TSC計數器的值
{
  unsigned hi, lo;
  __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
  return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

#endif

volatile int end;
int sum;
void signal_handler(int signal)
{
  end = rdtsc();
  /*int i=0;
  for(; i< 0 ; ++i)
        {
           sum+=1;
        }
  */
}
int main(void)
{
        signal(SIGUSR1, signal_handler);
        volatile int start = 0;
        register int end_new = 0;
        int loop;
        char result[50] = {''};
        int fd = open("result_load.txt", O_CREAT|O_RDWR);
        const int MAX_COUNT = 10000000;
        const float CPU_MHZ = 3093.059;    //use cat /proc/cpuinfo get the value
        const float CPU_tick_count_per_second = CPU_MHZ*1000*1000;

       for(loop =0; loop<1000;loop++)      //測試10000次
       {
        printf("start to send signal.n");
        start = rdtsc();                     //開始計數
        kill(getpid(),SIGUSR1);              //立即發送信號
        printf("runtickcount:%d,runtime:%f/sn",end-start,(end -start)/CPU_tick_count_per_second);
        sleep(1);
        sprintf(result, "run time:%fn", ((end-start)/CPU_tick_count_per_second));
        write(fd, result, 50);
       }
        return 0;
}

運行此程序就可以得到系統對軟終端的響應時間,上面的情況是在系統沒有負載的情況下,現實應用中系統往往是有負載的,甚至有很重的負載,所以我們為了模擬真實情況,對系統加了一些負載,寫了如下幾個負載,充分利用到系統各方面的資源

1) 創建4個進程反復進行內存的分配和釋放操作; (利用內存)

2) 創建4個進程反復進行大文件的寫操作         (利用磁盤IO)

3) 創建四個進程反復的進行開平方操作           (利用CPU)

加了這樣的負載以後,系統的負載已經很重了,差一點的機器會出現交互響應很慢,甚至不能交互,下面是負載程序的源代碼
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>

#define MALLOC_COUNT 2000000000
#define BUFFER_SIZE  1000
char std_buf[3] = "xffxffxff";

void xad_fill_buf(char pattern[3], unsigned long bufsize, char *buf)
{
    int loop;
    for (loop = 0; loop < (bufsize / 3); loop++)
   {
    *buf++ = pattern[0];
    *buf++ = pattern[1];
    *buf++ = pattern[2];
    }
}

int main()
{
 double a = 2.0, b = 3.0, c = 4.0, d = 5.0;
 int i,j;
 int count = 0;
 int total_bytes = 0;
 pid_t pid1, pid2, pid3, pid4, pid5;
 FILE* f;
 double array[4]={a, b, c, d};

for(i=0;i<4;i++)                 //四個開平方的進程
{
 if(fork() == 0)
   {
    for(j=0;j<1000000;j++)
         printf("The sqrt(a) is:%fn",sqrt(array[i]));
    exit(0);
   }
}

 
 for(i=0;i<4;i++)           //四個分配釋放內存的進程
  {
   if(fork() == 0)
    {
     for(i=0;i<400;i++)
          {
       char *p = (char*)malloc(MALLOC_COUNT);
           printf("200M memeory allocated.n");
       sleep(1);
           //free(p);
       }
     return 0;
    }
  }
 

for(i=0;i<4;i++)             //四個寫大文件的進程
  {
   if(fork() == 0)
   {

   char filename[10];
   char buf[BUFFER_SIZE];
   sprintf(filename, "file_%d", i);
   int fd = open(filename, O_RDWR|O_CREAT);
   if(fd<0)
    {
     printf("Create file failed.n");
     exit(-1);
    }

   if((f = fdopen(fd, "r+")) == NULL)
    {
     strerror("errorn");
     exit(-1);
    }
 

   while( (fwrite(&buf, 1, BUFFER_SIZE,f)) == BUFFER_SIZE)
    {
     count++;
     xad_fill_buf(std_buf, BUFFER_SIZE, buf);
     if(count == 100000)
    {
         total_bytes+=100;                                         //每次寫100M
         printf("%dM has written to the disk.n", total_bytes);
         count = 0;
    }
    }
   exit(0);
   }
  }

 
 return 0;
}

最後給出測試結果,我的平台上沒有負載測試的時間如下圖

下面是有負載時測試的輸出,左邊為負載程序運行,右邊為延遲時間

Copyright © Linux教程網 All Rights Reserved