- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我编写了一个简单的 epoll 驱动的服务器来测试网络/io 性能。服务器仅接收请求并立即发送响应。 它比 redis-server 'get' 慢,38k/s vs 40k/s。两者都使用 redis-benchmark 作为负载运行器,并且都使用了 cpu (>99%)。
bench redis-server: redis-benchmark -n 1000000 -c 20 -t get -p 6379
bench myserver:redis-benchmark -n 1000000 -c 20 -t get -p 6399
我已经使用 linux perf 对它们进行了分析,消除了 myserver 中的 epoll_ctl(就像 redis-server 所做的那样)。现在的问题是函数 finish_task_switch() 占用太多 cpu 时间,大约 10%-15%(redis-server 和 redis-benchmark 是 3%,在同一台机器上)。
调用流程(自上而下阅读)是
-> epoll_wait(25%)
-> entry_SYSCALL_64_after_hwframe(23.56%)
-> do_syscall_64(23.23%)
-> sys_epoll_wait(22.36%)
-> ep_poll(21.88%)
-> schedule_hrtimeout_range(12.98%)
-> schedule_hrtimeout_range_clock(12.74%)
-> schedule(11.30) %)
-> _schedule(11.30%)
-> finish_task_switch(10.82%)
我已经尝试使用原始 epoll api 编写服务器,并在 redis/src/ae.c 中使用 redis 的 api,没有任何改变。
我检查了 redis-server 和 redis-benchmark 如何使用 epoll,没有发现任何技巧。
redis CFLAGS 用于 myserver,与 redis-benchmark 相同。
CPU使用率与level/edge-triggered、block或nonblock client fd无关,无论是否设置了epoll_wait超时。
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> // exit
#include <string.h> // memset
#include "anet.h"
#define MAX_EVENTS 32
typedef struct {
int fd;
char querybuf[256];
} client;
client *clients;
char err[256];
#define RESPONSE_REDIS "$128\r\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
static int do_use_fd(client *c)
{
int n = read(c->fd, c->querybuf, sizeof(c->querybuf));
if (n == 0) { printf("Client Closed\n"); return n; }
n = write(c->fd, RESPONSE_REDIS, sizeof(RESPONSE_REDIS)-1);
return n;
}
int main()
{
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;
epollfd = epoll_create(MAX_EVENTS);
listen_sock = anetTcpServer(err, 6399, NULL, MAX_EVENTS);
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev);
clients = (client *)malloc(sizeof(client) * MAX_EVENTS);
memset(clients, 0, sizeof(client) * MAX_EVENTS);
for (;;) {
int n;
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100);
for (n = 0; n < nfds; ++n) {
if (events[n].data.fd == listen_sock) {
conn_sock = accept(listen_sock,
(struct sockaddr *) &addr, &addrlen);
anetNonBlock(err, conn_sock);
ev.events = EPOLLIN;
//ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,&ev);
clients[conn_sock].fd = conn_sock;
} else {
client *c = &clients[events[n].data.fd];
int ret = do_use_fd(c);
if (ret == 0) {
epoll_ctl(epollfd, EPOLL_CTL_DEL, c->fd, &ev);
}
}
}
}
}
最佳答案
服务器的 listen fd 被阻塞。将其设置为非阻塞会将 finish_task_switch 的使用率降低到 <2%。
关于redis - 如何降低 epoll_wait 调用的 finish_task_switch() 的 CPU 使用率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55744195/
我正在考虑基于 epoll 编写一个 tcp 服务器. 为了获得最佳性能,我也想实现多核支持。但在我的研究过程中,出现了以下问题: 叫两个更快吗epoll_wait() - 来自两个不同线程的调用,每
使用epoll_wait时,它似乎会“吃掉”写入stdout的所有内容,并延迟打印,直到epoll_wait收到事件之后,即使我尝试在调用与 epoll 相关的任何内容之前进行打印(它甚至可能位于我的
我有一个 Connection 对象,代表一个由 epoll 管理的连接。在发生事件时,调用 Connection::eventWrite() 或 Connection::eventRead()。连接
epoll_wait() 的第二个参数是大小为 sizeof (struct epoll_event) * 调用者期望(或监视)的事件总数(文件描述符)的缓冲区。在第一次传递给 epoll_wait(
我的应用程序在 epoll_wait 中等待的时间比我在超时中指定的时间长得多: 22578 09:33:46.959791 epoll_wait(5, 22578 09:33:50.010794
我已经编写了一个简单的 TCP 服务器套接字并将 fd 添加到 epoll_cntl。客户端连接后,accept fd也被添加到epoll_cntl中。 当客户端关闭时,我通过 epoll_wait
请原谅我的长篇文章。我会发布代码,以便更容易理解我面临的问题。似乎如果将信号套接字添加到 epoll 实例,则 epoll 实例上的 epoll_wait 不会阻塞。下面的例子让我相信了这一点: #i
我的应用程序使用 epoll_wait 来执行定时等待 IO 事件。如果没有事件发生,epoll_wait 应该在超时后返回并且我的应用程序继续。 在测试期间,有人将系统时钟调慢了一天,我的应用程序中
我正在使用一个多线程嵌入式应用程序,其中 epoll 用于其中一个线程中的 IO。我依赖于 epoll 的一个特定功能,该功能指定关闭文件描述符会自动将其从 epoll 集中删除(man 7 epol
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 我对 maxevents 参数有点困
When successful, epoll_wait(2) returns the number of file descriptors ready for the requested I/O, o
所以我有一些看起来像这样的代码: for (;;) { errno=0; epoll_event e = {}; auto wait_r = epoll
我有两次调用 event_wait。 线程 1:监听来自子进程的管道 struct epoll_event *ev; struct EpollStub stub[poo
所以....我很困惑为什么我的基于 epoll 的 tcp 服务器随机挂起 epoll_wait,然后在我用 SIGINT 终止时向某些连接发送一个空数组。 事实证明,我的软件中有一个随机错误,导致我
1) 我有 epoll_wait(..., events, ...) 循环,我需要在每次迭代前重新初始化 events 数组吗? 2) 根据epoll() 手册例子没有必要,是不是搞错了? 3) 我还
我无法从 epoll 文档中理解这一点:假设我有 pipe(fd) 所以我们有 fd[0] 用于读取和 fd[ 1] 用于书写。我们向 fd[1] 写入一些内容,然后将其关闭: write(fd[1]
当我使用此命令检查页面执行时,我面临着较长的 epoll_wait 时间。 strace -o output.txt -f -r -s4096 -p 21605 输出是一个很大的txt文件,但
我有一个线程负责轮询各种fds。我正在使用设置了超时的 epoll_wait。以下是代码片段: do { n = epoll_wait(epollFd, eventsList, eventsT
我正在使用 C++ 和 pthreads 进行一些事件处理。我有一个从我定义的事件队列中读取的主线程,以及一个填充事件队列的工作线程。队列当然是线程安全的。 工作线程有一个文件描述符列表,并创建一个
如果 epoll_wait 被任何原因(例如 SIGINT)中断,我想处理 while ( true ) { n = epoll_wait ( epoll_fd, events, max_ev
我是一名优秀的程序员,十分优秀!