共3条
1/1 1 跳转至页
请教gem2000版主PPPoE的定时器问题
我自己编了程序测试过了,对这个定时器的效率一个字:赞。
下面贡献我对PPPoE定时器的一些理解。
1.PPPoE定时器设计思想
PPPoE实现了对特定框架的定时器管理器。这个定时器管理器支持几个时间单元(PFW_100_MILLISECOND, PFW_SECOND 和PFW_MINUTE)。每个时间单元是独立管理的。
每个定时器的请求由一个定时器对象来表示。而定时器对象由定时器管理器创建和删除。管理器提供一个基于软件定时器功能的系统时钟。这种专用的定时器单元类型在定时器启动时定义了定时器的时间粒度。举例如:一个超时时间为N的PFW_SECOND定时器启动后,会在N+-0.5秒后超时。如果需要更精确的时间粒度,那么相同的请求应该用PFW_100_MILLISECOND定时器,这比前者精确了十倍。
每个定时器管理器中分为多个组,组元素中保存与前一个组超时时间的差值。最前面的组超时时间为该组的实际超时时间。每个组中保存所有超时时间为(N+-0.5)×unit的定时器节点。当定时器管理器中一旦有组存在时,其对应的watchDog便开始启动,watchDog每过一个定时器管理器的时间单位便将管理器的当前时间加1,并检查是否有定时器节点超时,如果有定时器节点超时则将该节点从队列中提取出并执行其回调函数,然后继续检查是否还有节点超时并处理,直到所有超时节点全部处理完才继续按以前步骤定期的检查是否有定时器节点超时。当某个定时器管理器中没有组存在时,其对应的watchDog便取消掉,不再定期的将管理器的时间加1和检查节点的超时情况。
超时处理函数是在frameWork的控制程序中执行的(修改后在新生成的PPPoETimer任务中执行超时函数)。相比之下,VxWorks的watchDog定时器所调用的处理函数是在中断级处理的,而POSIX的定时器处理函数是在程序异常中处理的。定时器管理器将plug-in对象状态传递进定时器处理程序。这运行开发者可以立即处理超时事件。例如:如果这是一个超时重传事件,那么处理函数可以通过使用plug-in对象取得上次发送的报文并使用相同的发包程序重传这个报文。
时间管理器同时也提供一种时间戳的功能。时间戳是一种被动的超时事件机制。使用者通过调用pfwTimeStampStar()函数得到一个时间戳,这记录了系统当前的时间和使用者指定的持续时间。在某段时间后(可能是在某个事件的发生后),使用者使用pfwTimeStampExpired()函数查询时间戳是否超时。
2.定时器性能测试及评价
测试方法:
针对实际的应用,2000个用户时,设备大概负载8000个左右的定时器节点。编写测试函数往定时器队列中添加定时器节点。随机的将8000的定时器分散在3个定时器管理器中,超时时间选择1分钟之内的随机时间。定时器节点的回调函数中运行100次减法操作。同时启动另外一个任务以每秒20个的速度添加新的定时器节点。
测试结果:
定时器任务CPU利用率在2%~3%左右,IDLE平均为74%左右。而且可以在1分钟内完成8000个定时器的超时任务。定时器任务运行良好,按上面的测试方法没有发现性能上的瓶颈。
该测试方法仅对定时器算法本身进行了简单的测试,实际的运行结果还需要编写多客户端程序来测试。
测试用代码:
/*******************************************************************************
*
* pfwTimerTickShow - show timer tick
*
* RETURNS : OK or ERROR
*
* NOMANUAL
*/
STATUS pfwTimerShow
(
)
{
PFW_TIMER_MANAGER *timerManager;
PFW_TIME_UNIT_MANAGER *timeUnitManager;
FAST lockKey;
unsigned int i, ticks, deadline;
DL_LIST *timerGroupList, *timerObjList;
PFW_TIMER_GROUP *group;
PFW_TIMER_OBJ *timerObj;
int groupCnt;
int timerObjCnt;
char name[100];
int value = 0;
SYM_TYPE type;
if (pppSysFramework == NULL)
{
pfwPrintError (__FILE__, "pfwTimerShow", __LINE__, NULL,
NULL, "Invalid argument: Null framework object pointer");
return (ERROR);
}
if ((timerManager = pppSysFramework->timerManager) == NULL)
{
pfwPrintError (__FILE__, "pfwTimerShow", __LINE__, NULL,
NULL, "Null timer manager object pointer");
return (ERROR);
}
for (i = 0; i < PFW_TIME_UNIT_NUM; i++)
{
timeUnitManager = timerManager->timeUnitManager[i];
if (timeUnitManager == NULL)
continue;
lockKey = intLock ();
ticks = timeUnitManager->ticks;
deadline = timeUnitManager->deadline;
intUnlock (lockKey);
printf ("\nTime Unit : ");
switch (i)
{
case PFW_100_MILLISECOND :
printf ("100_MILLISECOND\n");
break;
case PFW_SECOND :
printf ("SECOND\n");
break;
case PFW_MINUTE :
printf ("MINUTE\n");
break;
default :
printf ("UNKNOWN\n");
}
printf ("----------------------------\n");
printf ("Current Tick : %u\n", ticks);
printf ("Current Deadline : %u\n", deadline);
/* printf group infomation */
timerGroupList = &timeUnitManager->timerGroupList;
if (DLL_EMPTY (timerGroupList))
{
printf(" Empty group.\n");
continue;
}
group = (PFW_TIMER_GROUP *) DLL_FIRST (&timeUnitManager->timerGroupList);
if(NULL == group)
{
printf(" link list error, it should be empty group.\n");
continue;
}
/* print all group in this unit manage */
groupCnt = 0;
while(NULL != group)
{
printf(" Group%d %d/%s\n", groupCnt++, group->relativeTime, (group->expired) ? "Expired":"notExpired");
timerObjList = &group->timerObjList;
if (DLL_EMPTY (timerObjList))
{
printf(" Empty timer objlist.\n");
continue;
}
timerObj = (PFW_TIMER_OBJ *) DLL_FIRST(&group->timerObjList);
if(NULL == timerObj)
{
printf(" link list error, it should be empty timerObj.\n");
continue;
}
/* print all timer object in this group */
timerObjCnt = 0;
while(NULL != timerObj)
{
symFindByValue(sysSymTbl, (uint_t)timerObj->handler, name, &value, &type);
if(value != (int)timerObj->handler)
sprintf(name, "%#x (local)", (uint_t)timerObj->handler);
printf(" Callback handler %d: %s, unit %d\n", timerObjCnt++, name, timerObj->unit);
/* goto next timer object */
timerObj = (PFW_TIMER_OBJ *) DLL_NEXT(timerObj);
}
/* goto next group */
group = (PFW_TIMER_GROUP *) DLL_NEXT(group);
}
}
return (OK);
}
#if 1
int totalTimerObjs = 0;
int timerinfoOut = 1;
void consumeTime()
{
int x = 200;
while(x > 0)
{
x -= 2;
}
}
STATUS timerInfo()
{
if(timerinfoOut)
printf(".");
consumeTime();
totalTimerObjs--;
return OK;
}
STATUS pfwTimerAdd(PFW_TIME_UNIT unit, unsigned int timeoutValue)
{
PFW_TIMER_OBJ *timerObj;
PFW_PLUGIN_OBJ_STATE state;
PFW_PLUGIN_OBJ pluginObj;
PFW_OBJ pfwObj;
/* borrow memoryManager & timerManager for pppSysFramework */
pfwObj.memoryManager = pppSysFramework->memoryManager;
pfwObj.timerManager = pppSysFramework->timerManager;
pluginObj.pfwObj = &pfwObj;
state.pluginObj = &pluginObj;
if ((timerObj = pfwTimerCreate(&state)) == NULL)
{
printf(" Failed to create pfwTimer!\n");
return ERROR;
}
if(pfwTimerStart(timerObj, unit, timeoutValue, timerInfo, 0) == ERROR)
{
printf(" Failed to process pfwTimerStart!\n");
return ERROR;
}
totalTimerObjs++;
return OK;
}
void pfwTest(int n)
{
int i = 0;
srand(tickGet());
while(n--)
{
i = rand() % 3;
switch(i){
case PFW_100_MILLISECOND:
pfwTimerAdd(PFW_100_MILLISECOND, rand() % 600 + 1);
break;
case PFW_SECOND:
pfwTimerAdd(PFW_SECOND, rand() % 60 + 1);
break;
case PFW_MINUTE:
pfwTimerAdd(PFW_MINUTE, 1);
break;
default:
printf(" Shit, it's impossible!\n");
break;
}
}
}
void pfwRandTest()
{
int i = 0;
srand(tickGet());
while(1)
{
taskDelay(sysClkRateGet() / 20);
if(totalTimerObjs > 8000)
continue;
i = rand() % 3;
switch(i){
case PFW_100_MILLISECOND:
pfwTimerAdd(PFW_100_MILLISECOND, rand() % 3000 + 1);
break;
case PFW_SECOND:
pfwTimerAdd(PFW_SECOND, rand() % 300 + 1);
break;
case PFW_MINUTE:
pfwTimerAdd(PFW_MINUTE, rand() % 5 + 1);
break;
default:
printf(" Shit, it's impossible!\n");
break;
}
}
}
#endif
[align=right][color=#000066][此贴子已经被作者于2003-10-29 18:33:14编辑过][/color][/align]
共3条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |