real time performance test
總結一下這兩天做的一些事情,前幾天Boss交給我一個小任務,大概意思就是為公司的一個新的專案選定作業系統,這個專案對系統的實時性要求特別高,然後看看用什麼辦法能測量出作業系統的實時效能
先介紹下背景知識,作業系統分為實時作業系統和分時作業系統,這是由他們的應用範圍來決定的,我們通常所用的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] = {'\0'};
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/s\n",end-start,(end -start)/CPU_tick_count_per_second);
sleep(1);
sprintf(result, "run time:%f\n", ((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] = "\xff\xff\xff";
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:%f\n",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("error\n");
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;
}
最後給出測試結果,我的平臺上沒有負載測試的時間如下圖
下面是有負載時測試的輸出,左邊為負載程式執行,右邊為延遲時間
閱讀(1929) | 評論(12) | 轉發(3) | 給主人留下些什麼吧!~~
2013-01-21 10:55:50
kondykuang:博主你好,如果一個嵌入式linux系統主機 通過一個外部中斷接到一個FPGA(或者微控制器)板子上,使用FPGA模擬一個電平跳變。linuxkernel捕獲倒這個中斷,isr中操作linux主機的一個gpio輸出一個電平跳變。然後使用高取樣率的示波器同時捕獲中斷引腳 和GPIO的訊號,理論上可以得到輸入與響應間延時吧。
你好,這種方法應該是可以的,可能對示波器的要求會比較高,而且我想測通用Linux的實時性,不過確實是一種思路,謝謝你
回覆 | 舉報2013-01-19 22:01:34
博主你好,如果一個嵌入式linux系統主機 通過一個外部中斷接到一個FPGA(或者微控制器)板子上,使用FPGA模擬一個電平跳變。linuxkernel捕獲倒這個中斷,isr中操作linux主機的一個gpio輸出一個電平跳變。然後使用高取樣率的示波器同時捕獲中斷引腳 和GPIO的訊號,理論上可以得到輸入與響應間延時吧。
回覆 | 舉報2013-01-17 12:41:03
gfree_wind:對實時作業系統沒什麼研究,不過有個問題。
依賴於應用層的訊號處理來測量實時性,靠譜嗎?
我確實沒有想到什麼好的辦法,核心系統時鐘精度太低,核心定時器肯定不行,所以就不能再程式裡在特定時間產生中斷
回覆 | 舉報2013-01-17 12:26:30
對實時作業系統沒什麼研究,不過有個問題。
依賴於應用層的訊號處理來測量實時性,靠譜嗎?
2013-01-16 15:35:28
Bean_lee:看起來你理解的比較深,實時作業系統確實沒啥研究。
gettimeofday和xtime的定時精度,在這篇博文中測試過,可以看一下。
http://blog.csdn.net/yuanlulu/article/details/6023253