针对自己写的一个服务器网络引擎Engine 文章后面附上源码
使用epoll 刚刚开始时候发现占用CPU 特别高,但是网络引擎里面基本没干什么事,不应该有这么高的CPU,一直不解,
于是自己慢慢的分析服务器工作线程,发现主要的性能消耗应该是处理IO 时候,
int nEventNum = epoll_wait(m_nEpId, arrEvents, default_epoll_size, );
原来是 epoll_wait的最后一个参数的问题
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的产生,类似于select()调用。
参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,
这个 maxevents的值不能大于创建epoll_create()时的size,
参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。
该函数返回需要处理的事件数目,如返回0表示已超时。
于是我把参数timeout改成 1 毫秒,CPU 就降下来了,
int nEventNum = epoll_wait(m_nEpId, arrEvents, default_epoll_size, 1);
体会:
如果超时时间为0,必然导致内核不停的调用epoll_wait函数,频率应该是内核的最小时间粒度,其结果是
相当于一个死循环调用了,所以导致CPU消耗过高,
/*---------------------------------------------------
Date: Feb 22, 2016
Author: fangjunmin
Modify:
Description: IO基类
----------------------------------------------------*/ #ifndef CBASEIO_H_
#define CBASEIO_H_
#include "cLink.h"
#include <queue> class cCommAIO;
class CommMsgArgs; class cBaseIO
{
public:
cBaseIO();
virtual ~cBaseIO(); bool start();
bool stop(); bool startEpoll();
bool stopEopll(); void processIOEvent(); virtual EF_EVENT_RESULT on_io_read(cLink * pLink){return EF_EVR_NORMAL;};
virtual EF_EVENT_RESULT on_io_write(cLink * pLink){return EF_EVR_NORMAL;};
void on_io_error(int fd, int32 sn); public: bool AddIoHandle(int32 fd, int32 sn, uint32 nEventType);
bool DelIoHandle(int32 fd, int32 sn);
bool ModIoHandle(int32 fd, int32 sn, uint32 nEventType); //bool request_message_send(CommMsgArgs & args);
bool request_connection_close(int fd, int32 sn);
bool request_connection_open(int fd, int32 sn); bool bind_comm_user(cCommAIO* pAIO); void fill_epoll_t(struct epoll_event & ep_t, int32 ev_type, cLink * pLink); protected:
//void process_internal_command();
void process_io_event();
//void process_timer(int64 now_time/*ms*/, TIMER_QUEUE & timer_q, TIMER_INDEX_MAP & timer_index_map);
//void process_g_send_q(); protected:
cCommAIO* m_pAIO;
vecLink m_vecLink;//所有的客户端链接
int32 m_nEpId; //epoll id mapLink m_mapLink;
int32 m_nExistIONum; }; #endif /* CCOMMMOUDLE_H_ */
/*---------------------------------------------------
Date: Feb 22, 2016
Author: fangjunmin
Modify:
Description:
----------------------------------------------------*/ #include "cBaseIO.h"
#include "sys/epoll.h"
#include <queue>
#include "../thread/simple_lock.h"
#include "../Frame/cCommAIO.h"
#include "../inlc/globalConfig.h" cBaseIO::cBaseIO()
{
// TODO Auto-generated constructor stub
m_pAIO = NULL;
m_nEpId = ;
m_nExistIONum = ;
} cBaseIO::~cBaseIO()
{
// TODO Auto-generated destructor stub
} bool cBaseIO::start()
{
startEpoll();
return true;
} bool cBaseIO::stop()
{
stopEopll();
return true;
} bool cBaseIO::startEpoll()
{
m_nEpId = epoll_create(default_epoll_size);
if(m_nEpId == -)
{
pthread_exit(NULL);
return false;
}
return true;
} bool cBaseIO::stopEopll()
{
return true;
} void cBaseIO::processIOEvent()
{
epoll_event arrEvents[default_epoll_size + ];
int nEventNum = epoll_wait(m_nEpId, arrEvents, default_epoll_size, );
for(int i=; i<nEventNum; ++i)
{
printf("event num is: %d\n", nEventNum);
cLink * pLink = (cLink *)arrEvents[i].data.ptr;
if( == pLink)
{
continue;
} if( arrEvents[i].events & EPOLLIN ) //接收到数据,读socket
{
if(on_io_read(pLink) == EF_EVR_DEL_IO)
{
pLink->m_eStat = EF_IO_ERROR;
on_io_error(pLink->_fd, pLink->_sn);
DelIoHandle(pLink->_fd, pLink->_sn);
continue;
}
}
else if(arrEvents[i].events & EPOLLOUT) //有数据待发送,写socket
{
switch(on_io_write(pLink))
{
case EF_EVR_DEL_IO:
{
pLink->m_eStat = EF_IO_ERROR;
on_io_error(pLink->_fd, pLink->_sn);
DelIoHandle(pLink->_fd, pLink->_sn); continue;
}
break;
case EF_EVR_TX_EAGAIN:
{
continue;
}
break;
default:
{
pLink->m_eStat = EF_IO_NORMAL;
uint32 type = EF_EVT_READ;
ModIoHandle(pLink->_fd, pLink->_sn, type);
}
break;
}
}
else if(arrEvents[i].events & EPOLLHUP) //socket disconnect
{
printf("EPOLLHUP\n");
}
else if(arrEvents[i].events & EPOLLERR) //socket disconnect
{
printf("EPOLLERR\n");
}
else
{
//其他的处理
printf("EPOLL NUKNOW MSG \n");
}
}
} //void cBaseIO::process_internal_command()
//{
// int32 nLoopSize = 0;
// {
// SimpleLock lock;;
// nLoopSize = m_queueInterCmd.size();
// }
//
// for(int32 i = 0; i < nLoopSize; ++i)
// {
// EF_INTER_CMD * cmd(NULL);
// {
// SimpleLock lock;;
// cmd = m_queueInterCmd.front();
// m_queueInterCmd.pop();
// }
//
// if(!cmd)
// {
// continue;
// }
//
// switch(cmd->_type)
// {
//// case EF_IC_ADD_TIMER:
//// {
//// timer_add(ic, now_time, timer_q, timer_index_map);
//// }
//// break;
//// case EF_IC_DEL_TIMER:
//// {
//// timer_del(ic, now_time, timer_q, timer_index_map);
//// }
// break;
// case EF_IC_ADD_IO:
// {
// io_add(cmd);
// }
// break;
// case EF_IC_DEL_IO:
// {
// io_del(cmd);
// }
// break;
// case EF_IC_MOD_IO:
// {
// io_mod(cmd);
// }
// break;
//// case EF_IC_CHK_IO:
//// {
//// io_chk(ic, epfd, ioevent_index_map);
//// }
// break;
// default:
// break;
// }
//
// delete cmd;
// }
//} bool cBaseIO::AddIoHandle(int32 fd, int32 sn, uint32 nEventType)
{
if(!(nEventType & EF_EVT_READ) && !(nEventType & EF_EVT_WRITE))
{
return false;
} itmapLink it = m_mapLink.find( fd);
if(it != m_mapLink.end())
{
return false;
}
cLink *pLink = new cLink();
if(!pLink)
{
on_io_error(pLink->_fd, pLink->_sn);
return false;
}
pLink->_fd = fd;
pLink->_sn = sn; struct epoll_event ep_t;
fill_epoll_t(ep_t, nEventType, pLink); if(epoll_ctl(m_nEpId, EPOLL_CTL_ADD, pLink->_fd, &ep_t) == -)
{
on_io_error(pLink->_fd, pLink->_sn);
delete pLink;
}
else
{
std::cout << "[FD] ADD " << pLink->_fd << ":" << pLink->_sn << std::endl; m_mapLink[pLink->_fd] = pLink;
__sync_add_and_fetch(&m_nExistIONum, );
} return true;
} void cBaseIO::fill_epoll_t(struct epoll_event & ep_t, int32 ev_type, cLink * pLink)
{
ep_t.data.ptr = pLink;
ep_t.events = EPOLLET | EPOLLHUP | EPOLLERR; if(ev_type & EF_EVT_READ)
{
ep_t.events |= EPOLLIN;
} if(ev_type & EF_EVT_WRITE)
{
ep_t.events |= EPOLLOUT;
}
} bool cBaseIO::DelIoHandle(int32 fd, int32 sn)
{
itmapLink it = m_mapLink.find( fd);
if(it == m_mapLink.end())
{
return false;
}
cLink *pLink = it->second;
if(!pLink)
{
return false;
}
if(epoll_ctl(m_nEpId, EPOLL_CTL_DEL, pLink->_fd, NULL) == -)
{
return false;
}
m_mapLink.erase(pLink->_fd);
close(fd); __sync_sub_and_fetch(&m_nExistIONum, );
std::cout << "[FD] DEL " << pLink->_fd << ":" << pLink->_sn << std::endl; return true;
} bool cBaseIO::ModIoHandle(int32 fd, int32 sn, uint32 nEventType)
{
itmapLink it = m_mapLink.find(fd);
if(it != m_mapLink.end())
{
return false;
}
cLink *pLink = it->second;
if(!pLink)
{
return false;
}
struct epoll_event ep_t;
fill_epoll_t(ep_t, nEventType, pLink); if(epoll_ctl(m_nEpId, EPOLL_CTL_MOD, pLink->_fd, &ep_t) == -)
{
on_io_error(pLink->_fd, pLink->_sn);
DelIoHandle(pLink->_fd, pLink->_sn);
return false;
}
std::cout << "[FD] MOD " << pLink->_fd << ":" << pLink->_sn << std::endl;
return true;
} //
//bool cBaseIO::io_add(EF_INTER_CMD * ic)
//{
// if(!ic)
// {
// return false;
// }
//
// itmapLink it = m_mapLink.find(ic->_info.fd);
// if(it != m_mapLink.end())
// {
// return false;
// }
// cLink *pLink = new cLink();
// if(pLink)
// {
// on_io_error(pLink->_fd, pLink->_sn);
// return false;
// }
// pLink->_fd = ic->_info.fd;
// pLink->_sn = ic->_info.sn;
//
//
// struct epoll_event ep_t;
// //fill_epoll_t(ep_t, n->_type, n);
//
// if(epoll_ctl(m_nEpId, EPOLL_CTL_ADD, pLink->_fd, &ep_t) == -1)
// {
// on_io_error(pLink->_fd, pLink->_sn);
// delete pLink;
// }
// else
// {
// std::cout << "[FD] ADD " << pLink->_fd << ":" << pLink->_sn << std::endl;
//
// m_mapLink[pLink->_fd] = pLink;
// __sync_add_and_fetch(&m_nExistIONum, 1);
// }
//
//
// return true;
//} //bool cBaseIO::request_message_send(CommMsgArgs & args)
//{
// send_message_process(&args);
// return true;
//} bool cBaseIO::request_connection_close(int fd, int32 sn)
{
return DelIoHandle(fd, sn);
} bool cBaseIO::request_connection_open(int fd, int32 sn)
{
AddIoHandle(fd, sn ,EF_EVT_READ);
return true;
} bool cBaseIO::bind_comm_user(cCommAIO* pAIO)
{
m_pAIO = pAIO;
return true;
} void cBaseIO::on_io_error(int fd, int32 sn)
{
m_pAIO->notice_connection_close(fd, sn);
}