創提部落格
希望我們能與您分享和探討成長中的點點滴滴
通過DT10檢測多工阻塞鎖死問題
分享到
DT10是新一代的動態測試工具,可以長時間跟蹤記錄目的程式執行情況,獲取目的程式動態執行資料,説明進行難於重現的Bug錯誤分析,覆蓋率檢測,性能測試,變數跟蹤,多工程式等等功能。
VxWorks在國內航太軍工、軌道交通等即時性要求較高的領域應用非常廣泛,其提供多工,中斷等機制較好的滿足即時嵌入式領域的需求,然而開發VxWorks多工程式過程中,常常碰到令人頭疼的多工程式阻塞或鎖死等問題,例如某個task所佔用時間過長導致其他task不能正常執行等等問題。
本文介紹如何通過DT10檢測和調試VxWorks程式多工阻塞鎖死相關問題。
一、VxWorks環境
啟動FTP Server,並設置Users/rights…
啟動VxWorks目標板,如下圖所示VxWorks啟動成功:
啟動Target Server和Shell:
二、兩個簡單Tornado事例程式
Multi_Task.c
“
#include "vxworks.h"
#include "semLib.h"
#include "stdio.h"
#define TEST_NUM 10
SEM_ID semB;
int global;
int isTask1Running=1;
int isTask2Running=1;
static void task1(void)
{
int i=0;
while(i<TEST_NUM)
{
printf("<taske1
semTake(semB,WAIT_FOREVER);
printf("<taske1>
global++;
printf("<taske1>
taskDelay(100);
semGive(semB);
printf("
i++;
}
isTask1Running=0;
}
static void task2(void)
{
int i=0;
while(i<TEST_NUM)
{
printf("<taske2>
semTake(semB,WAIT_FOREVER);
printf("
global--;
printf("
taskDelay(200);
semGive(semB);
printf("<taske2>
i++;
}
isTask2Running=0;
}
{
while((isTask1Running==1)||(isTask2Running==1))
{
taskDelay(100);
}
printf("Bye Bye, Both Task1 and Task2 are finished!");
}
{
int taskId1,taskId2;
int t1_pri=91;
int t2_pri=90;
semB=semBCreate(SEM_Q_FIFO,SEM_FULL);
taskId1=taskSpawn("t1",t1_pri,0x100,0x1000,task1,
0,0,0,0,0,0,0,0,0,0);
taskId2=taskSpawn("t2",t2_pri,0x100,0x1000,task2,
0,0,0,0,0,0,0,0,0,0);
taskId2=taskSpawn("t3",t1_pri+1,0x100,0x1000,task3,
0,0,0,0,0,0,0,0,0,0);
}
#include "semLib.h"
#include "taskLib.h"
#include "stdio.h"
voidtaskB();
SEM_ID sem_2;
{
sem_2 = semMCreate(SEM_Q_FIFO);
0,0,0,0,0,0,0,0,0,0);
0,0,0,0,0,0,0,0,0,0);
}
the 2 tasks
-------------------------------------------------*/
voidtaskA()
{
semTake(sem_1, WAIT_FOREVER);
printf("Task A took sem_1, try to take sem_2\n");
}
{
semTake(sem_2, WAIT_FOREVER);
printf("Task B took sem_2, try to take sem_1\n");
}
”
上述兩段程式均使用了VxWorks庫函數taskSpawn創建多個task。 multi_task.c檔中創建了三個task,task1, task2會設置標誌isTask1Running, isTask2Running,當task1,task2結束後,task3才結束。Dead_lock.c檔中創建taskA, taskB,並通過信號量進行同步。當然,如果你仔細研究代碼,這兩段代碼中,均存在某個task不能正常結束的情況。
下面我們將通過DT10提供的相關debug和測試的功能,幫助查找並定位相關問題。
三、創建DT10工程
在DT10中點擊File->New創建一個工程,並設定工程名稱,指定被測試檔目錄和DT10工程存放路徑,設定Connection方式(DT10支援多種與目的機的連接方式)為Ethernet(Without Tracer),工程創建好後,如下圖:
然後點擊Plan->New Test Point Insertion…,對test.c檔自動插入FuncIn, FuncOut測試點。測試點插入完畢後,如下圖。DT10除了支援FuncIn,FuncOut測試點,還支援CPU壓力測試點,變數測試點,Event Trigger測試點等,説明使用者對系統的CPU,任務,變數等進行監控。
測試點插入後,我們在VxWorks構建環境Tornado中重新對上述專案進行編譯連結,如下圖:
四、執行程式並收集測試結果
1. 啟動DT10監聽測試結果程式,如下圖:
2. 在Tornado Shell中啟動被測試程式,直接在Shell中鍵入vxmain即可,如下圖:
五、分析測試結果
通過DT10自動插入測試點,程式在執行過程中,在每個測試點位置,目的程式會發出一個信號告知DT10程式執行到該測試點,這樣DT10收集所有測試日誌資料後,然後通過DT10的分析功能,可以得到包括每個函數的執行時間,代碼的覆蓋率資訊,以及程式執行路徑等圖形化報告,下面我們重點介紹通過DT10的哪些功能,説明我們定位程式鎖死或阻塞的問題。
1. 通過測試日誌瞭解任務阻塞或鎖死情況
首先我們看如何通過DT10的測試日誌幫我們查找到任務鎖死的問題。如下圖,我們看到DT10的獲取到的測試日誌報告:
結論:通過DT10測試日誌中的FuncIn, FuncOut測試點,很容易找到目的程式運行過程中是否存在某個任務或者函數被阻塞,這對於同時啟動很多個task的程式而言,可以瞭解哪些任務是否存在阻塞情況。
2. 通過覆蓋率資訊查看任務函數執行完整情況
另外通過DT10的覆蓋率資訊,也可以從側面瞭解某個函數或任務是否被執行完整,是否發生阻塞導致任務函數未退出。
結論:通過覆蓋率測試,一方面,使得在軟體測試過程中,可以幫助我們瞭解測試是否完整,測試用例是否存在遺漏,被測試代碼是否存在冗餘;另外一方面,覆蓋率的資訊對於我們調試代碼也有一定的幫助;
3. 通過DT10的函數執行時間瞭解更多資訊
通過DT10的函數執行時間報告,可以知道每個函數的執行時間,並且該執行時間精確到納秒級,同時可以知道每個函數執行的次數。如下圖:
我們看到該常式中,vxmain和taskB函數執行次數為1次,執行時間為883us和1116us,而taskA的執行次數為0,執行時間為0。這樣對於程式師,即可重點關注taskA是否存在問題。除了本常式中這種情況,在實際程式中,程式中的任務可能會執行成千上萬次,如果在DT10的函數執行時間報告中,發現某函數或者任務的某次執行時間特別長,舉例,比如某個TaskC,執行次數為9999次,其中9998次的執行時間都為1ms左右,另外有一次執行時間卻為30s,那麼就需要仔細查看這一次30s函數執行過程是什麼邏輯路徑。通過DT10可以看到每次代碼執行路徑,從而精確查看為什麼本次執行時間為30s,是否存在問題。這種情況在多工程式中經常碰到,比如某個低優先順序的任務可能被其它高優先順序的任務阻塞,從而導致該任務執行時間變長。
結論:通過DT10瞭解每個函數執行時間,執行次數,以及每次執行過程中代碼執行邏輯路徑,從而説明使用者更細緻的瞭解代碼執行情況,説明使用者定位和分析代碼中隱藏的bug。
上面重點對dead_lock.c的結果重點進行分析了,對於multi_task.c的分析類似。有興趣試用並瞭解DT10的朋友可以聯繫我們申請試用。