背景
在基于英創(chuàng)工控主板的智能整機(jī)設(shè)備的開發(fā)過程中,客戶應(yīng)用程序的開發(fā)通常都是最為關(guān)鍵性的工作,其工作量往往也是最大的。一個(gè)高質(zhì)量的應(yīng)用程序,首先表現(xiàn)在較少的現(xiàn)場維護(hù),不僅大幅度降低了設(shè)備開發(fā)費(fèi)用,同時(shí)也為客戶贏得后續(xù)的市場聲譽(yù)。因此如何在設(shè)備出廠之前就能確定應(yīng)用程序的基本質(zhì)量,就變得至關(guān)重要了。
基于我們十多年長期不斷地對(duì)客戶應(yīng)用程序的技術(shù)支持的經(jīng)驗(yàn),一般來說,如果一個(gè)應(yīng)用程序在完成基本的應(yīng)用功能的基礎(chǔ)上,整個(gè)應(yīng)用進(jìn)程(包括進(jìn)程的所有活動(dòng)線程)的CPU負(fù)載率保持在一個(gè)合理的水平,比如低于70%,那么我們就可以認(rèn)為運(yùn)行于英創(chuàng)工控主板上的這個(gè)應(yīng)用程序其質(zhì)量是有基本保證的。為了方便客戶隨時(shí)了解應(yīng)用程序的運(yùn)行狀況,我們計(jì)劃在主板中嵌入一款稱為應(yīng)用程序助手(AppHelper)的監(jiān)測程序。AppHelper僅使用很少的CPU資源,就可為客戶提供系統(tǒng)各個(gè)進(jìn)程的CPU開銷情況,對(duì)客戶的應(yīng)用進(jìn)程,還將提供進(jìn)程中各個(gè)活動(dòng)線程的運(yùn)行狀況??蛻舾鶕?jù)這些信息及可方便及時(shí)的了解程序運(yùn)行的總體情況,快速確定程序代碼需要優(yōu)化的地方。
本文的后續(xù)部分主要介紹AppHelper的使用方法及信息輸出的格式。
AppHelper的輸出接口
CE應(yīng)用程序助手AppHelper的主要功能是提供系統(tǒng)運(yùn)行狀況的基本信息。這些基本信息可支持多種通訊接口輸出,這些接口包括調(diào)試串口、USB OTG接口、應(yīng)用串口COM2 – COM9、以太網(wǎng)接口。客戶可根據(jù)自身設(shè)備的特點(diǎn),方便地選擇輸出接口。調(diào)試串口是AppHelper的缺省輸出接口。
AppHelper輸出信息的基本格式都是標(biāo)準(zhǔn)的ASCII碼字符串,客戶通過PC上的一款串口終端窗口程序(推薦使用開源的Tara Term),就可看到輸出的信息。
若客戶希望使用USB或應(yīng)用串口來觀察AppHelper的輸出信息,需要通過執(zhí)行主板上的AppHelperConfig進(jìn)行端口配置:
\> AppHelperConfig p1 [p2]
上式中p1 = 1, 2, .. 9;其中 = 1表示使用COM1端口,在英創(chuàng)主板中COM1端口是基于USB OTG的虛擬串口,英創(chuàng)公司的EM335x產(chǎn)品線和EM928x產(chǎn)品線的所有產(chǎn)品均支持USB OTG虛擬串口功能,虛擬串口的使用方法與實(shí)際物理串口完全一致。參數(shù)p1 = 2 – 9分別對(duì)應(yīng)物理串口COM2 – COM9。注意在選擇物理串口時(shí),應(yīng)避免使用低速串口。參數(shù)p2為串口的波特率,缺省配置為115200bps。除非特別的需求,一般不設(shè)置該參數(shù),即推薦使用115200波特率。
用戶只需在輸出串口上輸入3個(gè)以上的字符(鍵盤連按3次以上),就會(huì)激活A(yù)ppHelper。AppHelper將按2秒間隔輸出系統(tǒng)運(yùn)行狀態(tài)信息。
若用戶希望通過以太網(wǎng)口來觀察AppHelper的輸出信息,則可通過telnet登錄系統(tǒng)后,直接運(yùn)行SysInfo.exe,就可在CMD窗口看到系統(tǒng)的運(yùn)行信息。SysInfo可帶一個(gè)輸入?yún)?shù),來確定輸出信息的時(shí)間,缺省的時(shí)間為10s。AppHelper每2秒輸出一次系統(tǒng)運(yùn)行參數(shù)。
AppHelper信息輸出格式
AppHelper的輸出格式如下:
AppHelper v0.1 Oct 18 2015 17:36:33 Emtronix(c)
CPU:2% FreeMemory=148.59MiB FreeNand=123.99MiB
….
第一行是AppHelper的版本信息,第二行是系統(tǒng)總的CPU負(fù)載、程序內(nèi)存的剩余空間,以及NandFlash的剩余空間。之后的每一行是一個(gè)進(jìn)程或線程的CPU占用率。其中每個(gè)進(jìn)程的名稱就是對(duì)應(yīng)的exe文件名,而對(duì)線程來說,系統(tǒng)只提供有線程ID??蛻粢话阏f來很難根據(jù)線程ID來辨識(shí)具體是應(yīng)用程序中哪個(gè)線程,例如串口接收線程。
應(yīng)用線程命名
為了客戶更容易識(shí)別應(yīng)用線程,AppHelper為應(yīng)用程序提供了2個(gè)API函數(shù)。應(yīng)用程序在創(chuàng)建線程后,通過API函數(shù)來為該線程注冊(cè)一個(gè)希望字符串名;當(dāng)線程退出時(shí),則通過API函數(shù)注銷該字符串。AppHelper提供的這兩個(gè)API函數(shù)為:
BOOL RegisterThreadName(DWORD dwThreadID, TCHAR* sThreadName);
BOOL UnRegisterThreadName(DWORD dwThreadID);
注冊(cè)操作一般直接跟在線程創(chuàng)建之后,其代碼如下:
DWORD dwThreadID = 0;
TCHAR sThreadName[] = L” ReceiveThread”;//注意32個(gè)字符!
// create rx thread
m_hRxThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)ReceiveThread,
(LPVOID)pPara,
0,
&dwThreadID);
RegisterThreadName(dwThreadID, sThreadName);
線程名注銷操作則更簡單,直接放在線程退出之前即可。
以下是AppHelper提供的這兩個(gè)API函數(shù)的具體實(shí)現(xiàn),該代碼應(yīng)包含在應(yīng)用程序之中。
struct _THREAD_INDEX
{
DWORD dwSize; // struct size in byte
DWORD dwThreadID; // a thread id
TCHAR szThreadName[32]; // user-defined name associated with the
// thread id above
struct _THREAD_INDEX *pNext; // = NULL
};
typedef struct _THREAD_INDEX THREAD_INDEX, *PTHREAD_INDEX;
BOOL RegisterThreadName(DWORD dwThreadID, TCHAR* sThreadName)
{
BOOL bRet = TRUE;
THREAD_INDEX ThreadNode;
PTHREAD_INDEX pNode = &ThreadNode;
DWORD dwLen;
HANDLE hDevFile = NULL;
memset(&ThreadNode, 0, sizeof(THREAD_INDEX));
pNode->dwSize = sizeof(THREAD_INDEX);
dwLen = wcslen(sThreadName);
if(!dwThreadID || (dwLen >= 32))
{
bRet = FALSE;
goto cleanup;
}
pNode->dwThreadID = dwThreadID;
wcscpy(pNode->szThreadName, sThreadName);
hDevFile = CreateFile(L"HLP1:", // name of device
GENERIC_READ|GENERIC_WRITE, // desired access
0, // sharing mode
NULL, // security attributes
OPEN_EXISTING, // creation disposition
0, // flags/attributes
NULL); // template file
if(hDevFile == INVALID_HANDLE_VALUE)
{
hDevFile = NULL;
bRet = FALSE;
goto cleanup;
}
dwLen = 0;
if(!WriteFile(hDevFile, pNode, sizeof(THREAD_INDEX), &dwLen, NULL))
{
bRet = FALSE;
}
CloseHandle(hDevFile);
cleanup:
return bRet;
}
BOOL UnRegisterThreadName(DWORD dwThreadID)
{
BOOL bRet = TRUE;
THREAD_INDEX ThreadNode;
PTHREAD_INDEX pNode = &ThreadNode;
DWORD dwLen;
HANDLE hDevFile = NULL;
memset(&ThreadNode, 0, sizeof(THREAD_INDEX));
pNode->dwSize = sizeof(THREAD_INDEX);
if(!dwThreadID)
{
bRet = FALSE;
goto cleanup;
}
pNode->dwThreadID = dwThreadID;
hDevFile = CreateFile(L"HLP1:", // name of device
GENERIC_READ|GENERIC_WRITE, // desired access
0, // sharing mode
NULL, // security attributes
OPEN_EXISTING, // creation disposition
0, // flags/attributes
NULL); // template file
if(hDevFile == INVALID_HANDLE_VALUE)
{
hDevFile = NULL;
bRet = FALSE;
goto cleanup;
}
dwLen = 0;
if(!WriteFile(hDevFile, pNode, sizeof(THREAD_INDEX), &dwLen, NULL))
{
bRet = FALSE;
}
CloseHandle(hDevFile);
cleanup:
return bRet;
}
預(yù)計(jì)在2015年10月底前,AppHelper將首先安裝到EM335x產(chǎn)品線的所有主板,并在11月份部署到EM928x產(chǎn)品線。歡迎新老客戶評(píng)估測試CE應(yīng)用程序助手。
-
嵌入式主板
+關(guān)注
關(guān)注
7文章
6085瀏覽量
35345
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論