Don't free the memory malloc with rte_malloc in most commonly used socket API, to improve proformance.

The performance of single instance from 200,000 QPS improve to 260,000QPS.
NOTE:May cause memory leak.
This commit is contained in:
fengbojiang 2023-04-12 18:57:59 +08:00
parent dfb462caa7
commit e45925dd79
1 changed files with 303 additions and 124 deletions

View File

@ -55,6 +55,32 @@
return ret; \
}
/* Always use __thread, but no __FF_THREAD */
static __thread struct ff_shutdown_args *shutdown_args = NULL;
static __thread struct ff_accept_args *accept_args = NULL;
static __thread struct ff_connect_args *connect_args = NULL;
static __thread struct ff_recvfrom_args *recvfrom_args = NULL;
static __thread struct ff_read_args *read_args = NULL;
static __thread struct ff_sendto_args *sendto_args = NULL;
static __thread struct ff_write_args *write_args = NULL;
static __thread struct ff_close_args *close_args = NULL;
static __thread struct ff_epoll_ctl_args *epoll_ctl_args = NULL;
static __thread struct ff_epoll_wait_args *epoll_wait_args = NULL;
static __thread struct ff_kevent_args *kevent_args = NULL;
#define DEFINE_REQ_ARGS_STATIC(name) \
int ret = -1; \
struct ff_##name##_args *args = NULL; \
if (name##_args == NULL) { \
size_t size = sizeof(struct ff_##name##_args); \
name##_args = share_mem_alloc(size); \
if (name##_args == NULL) { \
errno = ENOMEM; \
return ret; \
} \
} \
args = name##_args;
#define ACQUIRE_ZONE_LOCK(exp) do { \
while (1) { \
rte_spinlock_lock(&sc->lock); \
@ -85,6 +111,15 @@
RELEASE_ZONE_LOCK(FF_SC_IDLE); \
} while (0)
#define RETURN_NOFREE() do { \
return ret; \
} while (0)
#define RETURN_ERROR_NOFREE(err) do { \
errno = err; \
return ret; \
} while (0)
#define RETURN() do { \
share_mem_free(args); \
return ret; \
@ -99,13 +134,7 @@
static __FF_THREAD int inited = 0;
static __FF_THREAD struct ff_so_context *sc;
/*
* Use pthread_key_create/pthread_setspecific/pthread_key_delete in FF_THREAD_SOCKET mode,
* because ff_so_zone is thread level.
*/
#ifdef FF_THREAD_SOCKET
static pthread_key_t key;
#endif
/* process-level initialization flag */
static int proc_inited = 0;
@ -257,14 +286,14 @@ ff_hook_shutdown(int fd, int how)
{
CHECK_FD_OWNERSHIP(shutdown, (fd, how));
DEFINE_REQ_ARGS(shutdown);
DEFINE_REQ_ARGS_STATIC(shutdown);
args->fd = fd;
args->how = how;
SYSCALL(FF_SO_SHUTDOWN, args);
RETURN();
RETURN_NOFREE();
}
int
@ -458,27 +487,41 @@ ff_hook_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
CHECK_FD_OWNERSHIP(accept, (fd, addr, addrlen));
DEFINE_REQ_ARGS(accept);
struct sockaddr *sh_addr = NULL;
socklen_t *sh_addrlen = NULL;
DEFINE_REQ_ARGS_STATIC(accept);
static __thread struct sockaddr *sh_addr = NULL;
static __thread socklen_t sh_addr_len = 0;
static __thread socklen_t *sh_addrlen = NULL;
if (addr != NULL) {
sh_addr = share_mem_alloc(*addrlen);
if (sh_addr == NULL) {
RETURN_ERROR(ENOMEM);
if (sh_addr == NULL || sh_addr_len < *addrlen) {
if(sh_addr) {
share_mem_free(sh_addr);
}
sh_addr_len = *addrlen;
sh_addr = share_mem_alloc(sh_addr_len);
if (sh_addr == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
sh_addrlen = share_mem_alloc(sizeof(socklen_t));
if (sh_addrlen == NULL) {
share_mem_free(sh_addr);
RETURN_ERROR(ENOMEM);
sh_addrlen = share_mem_alloc(sizeof(socklen_t));
if (sh_addrlen == NULL) {
//share_mem_free(sh_addr); // Don't free
RETURN_ERROR_NOFREE(ENOMEM);
}
}
*sh_addrlen = *addrlen;
args->addr = sh_addr;
args->addrlen = sh_addrlen;
}else {
args->addr = NULL;
args->addrlen = NULL;
}
args->fd = fd;
args->addr = sh_addr;
args->addrlen = sh_addrlen;
SYSCALL(FF_SO_ACCEPT, args);
@ -493,11 +536,11 @@ ff_hook_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
rte_memcpy(addr, sh_addr, cplen);
*addrlen = *sh_addrlen;
}
share_mem_free(sh_addr);
share_mem_free(sh_addrlen);
//share_mem_free(sh_addr); // Don't free
//share_mem_free(sh_addrlen);
}
RETURN();
RETURN_NOFREE();
}
int
@ -521,12 +564,20 @@ ff_hook_connect(int fd, const struct sockaddr *addr,
CHECK_FD_OWNERSHIP(connect, (fd, addr, addrlen));
DEFINE_REQ_ARGS(connect);
struct sockaddr *sh_addr;
DEFINE_REQ_ARGS_STATIC(connect);
static __thread struct sockaddr *sh_addr = NULL;
static __thread socklen_t sh_addr_len = 0;
sh_addr = share_mem_alloc(addrlen);
if (sh_addr == NULL) {
RETURN_ERROR(ENOMEM);
if (sh_addr == NULL || sh_addr_len < addrlen) {
if(sh_addr) {
share_mem_free(sh_addr);
}
sh_addr_len = addrlen;
sh_addr = share_mem_alloc(sh_addr_len);
if (sh_addr == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_addr, addr, addrlen);
@ -536,8 +587,8 @@ ff_hook_connect(int fd, const struct sockaddr *addr,
SYSCALL(FF_SO_CONNECT, args);
share_mem_free(sh_addr);
RETURN();
//share_mem_free(sh_addr);
RETURN_NOFREE();
}
ssize_t
@ -563,41 +614,57 @@ ff_hook_recvfrom(int fd, void *buf, size_t len, int flags,
CHECK_FD_OWNERSHIP(recvfrom, (fd, buf, len, flags, from, fromlen));
DEFINE_REQ_ARGS(recvfrom);
void *sh_buf;
struct sockaddr *sh_from = NULL;
socklen_t *sh_fromlen = NULL;
DEFINE_REQ_ARGS_STATIC(recvfrom);
static __thread void *sh_buf;
static __thread size_t sh_buf_len = 0;
static __thread struct sockaddr *sh_from = NULL;
static __thread socklen_t sh_from_len = 0;
static __thread socklen_t *sh_fromlen = NULL;
if (from != NULL) {
sh_from = share_mem_alloc(*fromlen);
if (sh_from == NULL) {
RETURN_ERROR(ENOMEM);
if (sh_from == NULL || sh_from_len < *fromlen) {
if (sh_from) {
share_mem_free(sh_from);
}
sh_from_len = *fromlen;
sh_from = share_mem_alloc(sh_from_len);
if (sh_from == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
sh_fromlen = share_mem_alloc(sizeof(socklen_t));
if (sh_fromlen == NULL) {
share_mem_free(sh_from);
RETURN_ERROR(ENOMEM);
sh_fromlen = share_mem_alloc(sizeof(socklen_t));
if (sh_fromlen == NULL) {
//share_mem_free(sh_from);
RETURN_ERROR_NOFREE(ENOMEM);
}
}
args->from = sh_from;
args->fromlen = sh_fromlen;
} else {
args->from = NULL;
args->fromlen = NULL;
}
sh_buf = share_mem_alloc(len);
if (sh_buf == NULL) {
if (sh_from) {
share_mem_free(sh_from);
if (sh_buf == NULL || sh_buf_len < (len * 4)) {
if (sh_buf) {
share_mem_free(sh_buf);
}
if (sh_fromlen) {
share_mem_free(sh_fromlen);
sh_buf_len = len * 4;
sh_buf = share_mem_alloc(sh_buf_len);
if (sh_buf == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
RETURN_ERROR(ENOMEM);
}
args->fd = fd;
args->buf = sh_buf;
args->len = len;
args->flags = flags;
args->from = sh_from;
args->fromlen = sh_fromlen;
SYSCALL(FF_SO_RECVFROM, args);
@ -611,13 +678,14 @@ ff_hook_recvfrom(int fd, void *buf, size_t len, int flags,
}
}
if (from) {
/*if (from) {
share_mem_free(sh_from);
share_mem_free(sh_fromlen);
}
share_mem_free(sh_buf);
RETURN();
share_mem_free(sh_buf);*/
RETURN_NOFREE();
}
static void
@ -858,12 +926,22 @@ ff_hook_read(int fd, void *buf, size_t len)
CHECK_FD_OWNERSHIP(read, (fd, buf, len));
DEFINE_REQ_ARGS(read);
void *sh_buf;
DEFINE_REQ_ARGS_STATIC(read);
static __thread void *sh_buf = NULL;
static __thread size_t sh_buf_len = 0;
sh_buf = share_mem_alloc(len);
if (sh_buf == NULL) {
RETURN_ERROR(ENOMEM);
/* alloc or realloc sh_buf */
if (sh_buf == NULL || sh_buf_len < (len * 4)) {
if (sh_buf) {
share_mem_free(sh_buf);;
}
/* alloc 4 times buf space */
sh_buf_len = len * 4;
sh_buf = share_mem_alloc(sh_buf_len);
if (sh_buf == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
args->fd = fd;
@ -876,8 +954,9 @@ ff_hook_read(int fd, void *buf, size_t len)
rte_memcpy(buf, sh_buf, ret);
}
share_mem_free(sh_buf);
RETURN();
//share_mem_free(sh_buf);
RETURN_NOFREE();
}
ssize_t
@ -923,39 +1002,60 @@ ff_hook_sendto(int fd, const void *buf, size_t len, int flags,
CHECK_FD_OWNERSHIP(sendto, (fd, buf, len, flags, to, tolen));
DEFINE_REQ_ARGS(sendto);
void *sh_buf;
void *sh_to = NULL;
DEFINE_REQ_ARGS_STATIC(sendto);
static __thread void *sh_buf = NULL;
static __thread size_t sh_buf_len = 0;
static __thread void *sh_to = NULL;
static __thread socklen_t sh_to_len = 0;
sh_buf = share_mem_alloc(len);
if (sh_buf == NULL) {
RETURN_ERROR(ENOMEM);
if (sh_buf == NULL || sh_buf_len < (len * 4)) {
if (sh_buf) {
share_mem_free(sh_buf);;
}
/* alloc 4 times buf space */
sh_buf_len = len * 4;
sh_buf = share_mem_alloc(sh_buf_len);
if (sh_buf == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_buf, buf, len);
if (to) {
sh_to = share_mem_alloc(tolen);
if (sh_to == NULL) {
share_mem_free(sh_buf);
RETURN_ERROR(ENOMEM);
if (sh_to == NULL || sh_to_len < tolen) {
if (sh_to) {
share_mem_free(sh_to);
}
sh_to_len = tolen;
sh_to = share_mem_alloc(sh_to_len);
if (sh_to == NULL) {
//share_mem_free(sh_buf);
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_to, to, tolen);
args->to = sh_to;
args->tolen = tolen;
} else {
args->to = NULL;
args->tolen = 0;
}
args->fd = fd;
args->buf = sh_buf;
args->len = len;
args->flags = flags;
args->to = sh_to;
args->tolen = tolen;
SYSCALL(FF_SO_SENDTO, args);
share_mem_free(sh_buf);
/*share_mem_free(sh_buf);
if (sh_to) {
share_mem_free(sh_to);
}
RETURN();
}*/
RETURN_NOFREE();
}
ssize_t
@ -1014,12 +1114,20 @@ ff_hook_write(int fd, const void *buf, size_t len)
CHECK_FD_OWNERSHIP(write, (fd, buf, len));
DEFINE_REQ_ARGS(write);
void *sh_buf;
DEFINE_REQ_ARGS_STATIC(write);
static __thread void *sh_buf = NULL;
static __thread size_t sh_buf_len = 0;
sh_buf = share_mem_alloc(len);
if (sh_buf == NULL) {
RETURN_ERROR(ENOMEM);
if (sh_buf == NULL || sh_buf_len < (len * 4)) {
if (sh_buf) {
share_mem_free(sh_buf);
}
sh_buf_len = len * 4;
sh_buf = share_mem_alloc(sh_buf_len);
if (sh_buf == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_buf, buf, len);
@ -1029,8 +1137,9 @@ ff_hook_write(int fd, const void *buf, size_t len)
SYSCALL(FF_SO_WRITE, args);
share_mem_free(sh_buf);
RETURN();
//share_mem_free(sh_buf);
RETURN_NOFREE();
}
ssize_t
@ -1073,13 +1182,13 @@ ff_hook_close(int fd)
CHECK_FD_OWNERSHIP(close, (fd));
DEFINE_REQ_ARGS(close);
DEFINE_REQ_ARGS_STATIC(close);
args->fd = fd;
SYSCALL(FF_SO_CLOSE, args);
RETURN();
RETURN_NOFREE();
}
int
@ -1174,8 +1283,8 @@ ff_hook_epoll_ctl(int epfd, int op, int fd,
DEBUG_LOG("ff_hook_epoll_ctl, epfd:%d, op:%d, fd:%d\n", epfd, op, fd);
CHECK_FD_OWNERSHIP(epoll_ctl, (epfd, op, fd, event));
DEFINE_REQ_ARGS(epoll_ctl);
struct epoll_event *sh_event = NULL;
DEFINE_REQ_ARGS_STATIC(epoll_ctl);
static __thread struct epoll_event *sh_event = NULL;
if ((!event && op != EPOLL_CTL_DEL) ||
(op != EPOLL_CTL_ADD &&
@ -1186,25 +1295,29 @@ ff_hook_epoll_ctl(int epfd, int op, int fd,
}
if (event) {
sh_event = share_mem_alloc(sizeof(struct epoll_event));
if (sh_event == NULL) {
RETURN_ERROR(ENOMEM);
sh_event = share_mem_alloc(sizeof(struct epoll_event));
if (sh_event == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_event, event, sizeof(struct epoll_event));
args->event = sh_event;
} else {
args->event = NULL;
}
args->epfd = restore_fstack_fd(epfd);
args->op = op;
args->fd = fd;
args->event = sh_event;
SYSCALL(FF_SO_EPOLL_CTL, args);
if (sh_event) {
/*if (sh_event) {
share_mem_free(sh_event);
}
}*/
RETURN();
RETURN_NOFREE();
}
int
@ -1215,12 +1328,14 @@ ff_hook_epoll_wait(int epfd, struct epoll_event *events,
int fd = epfd;
CHECK_FD_OWNERSHIP(epoll_wait, (epfd, events, maxevents, timeout));
DEFINE_REQ_ARGS(epoll_wait);
struct epoll_event *sh_events;
DEFINE_REQ_ARGS_STATIC(epoll_wait);
static __thread struct epoll_event *sh_events = NULL;
sh_events = share_mem_alloc(sizeof(struct epoll_event) * maxevents);
if (sh_events == NULL) {
RETURN_ERROR(ENOMEM);
sh_events = share_mem_alloc(sizeof(struct epoll_event) * maxevents);
if (sh_events == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
args->epfd = fd;
@ -1296,11 +1411,17 @@ ff_hook_epoll_wait(int epfd, struct epoll_event *events,
rte_memcpy(events, sh_events, sizeof(struct epoll_event) * ret);
}
if (sh_events) {
/*
* Don't free, to improve proformance.
* Will cause memory leak while APP exit , but fstack adapter not exit.
* May set them as gloabl variable and free in thread_destructor.
*/
/*if (sh_events) {
share_mem_free(sh_events);
}
sh_events = NULL;
}*/
RETURN();
RETURN_NOFREE();
}
pid_t
@ -1350,16 +1471,24 @@ kevent(int kq, const struct kevent *changelist, int nchanges,
kq = restore_fstack_fd(kq);
DEFINE_REQ_ARGS(kevent);
struct kevent *sh_changelist = NULL;
struct kevent *sh_eventlist = NULL;
DEFINE_REQ_ARGS_STATIC(kevent);
static __thread struct kevent *sh_changelist = NULL;
static __thread int sh_changelist_len = 0;
static __thread struct kevent *sh_eventlist = NULL;
static __thread int sh_eventlist_len = 0;
if (changelist != NULL && nchanges > 0) {
sh_changelist = share_mem_alloc(sizeof(struct kevent) * nchanges);
if (sh_changelist == NULL) {
RETURN_ERROR(ENOMEM);
}
if (sh_changelist == NULL || sh_changelist_len < nchanges) {
if (sh_changelist) {
share_mem_free(sh_changelist);
}
sh_changelist_len = nchanges;
sh_changelist = share_mem_alloc(sizeof(struct kevent) * sh_changelist_len);
if (sh_changelist == NULL) {
RETURN_ERROR_NOFREE(ENOMEM);
}
}
rte_memcpy(sh_changelist, changelist, sizeof(struct kevent) * nchanges);
for(i = 0; i < nchanges; i++) {
@ -1374,22 +1503,35 @@ kevent(int kq, const struct kevent *changelist, int nchanges,
break;
}
}
args->changelist = sh_changelist;
args->nchanges = nchanges;
} else {
args->changelist = NULL;
args->nchanges = 0;
}
if (eventlist != NULL && nevents > 0) {
sh_eventlist = share_mem_alloc(sizeof(struct kevent) * nevents);
if (sh_eventlist == NULL) {
share_mem_free(sh_changelist);
RETURN_ERROR(ENOMEM);
if (sh_eventlist == NULL || sh_eventlist_len < nevents) {
if (sh_eventlist) {
share_mem_free(sh_eventlist);
}
sh_eventlist_len = nevents;
sh_eventlist = share_mem_alloc(sizeof(struct kevent) * sh_eventlist_len);
if (sh_eventlist == NULL) {
//share_mem_free(sh_changelist); // don't free
RETURN_ERROR_NOFREE(ENOMEM);
}
}
args->eventlist = sh_eventlist;
args->nevents = nevents;
} else {
args->eventlist = NULL;
args->nevents = 0;
}
args->kq = kq;
args->changelist = sh_changelist;
args->nchanges = nchanges;
args->eventlist = sh_eventlist;
args->nevents = nevents;
args->timeout = NULL;
args->timeout = (struct timespec *)timeout;
if (timeout == NULL) {
need_alarm_sem = 1;
@ -1462,26 +1604,67 @@ kevent(int kq, const struct kevent *changelist, int nchanges,
}
}
if (sh_changelist) {
/*
* Don't free, to improve performance.
* Will cause memory leak while APP exit , but fstack adapter not exit.
* May set them as gloabl variable and free in thread_destructor.
*/
/*if (sh_changelist) {
share_mem_free(sh_changelist);
sh_changelist = NULL;
}
if (sh_eventlist) {
share_mem_free(sh_eventlist);
}
sh_eventlist = NULL;
}*/
RETURN();
RETURN_NOFREE();
}
#ifdef FF_THREAD_SOCKET
static void
thread_destructor(void *sc)
{
#ifdef FF_THREAD_SOCKET
DEBUG_LOG("pthread self tid:%lu, detach sc:%p\n", pthread_self(), sc);
ff_detach_so_context(sc);
}
#endif
if (shutdown_args) {
share_mem_free(shutdown_args);
}
if (accept_args) {
share_mem_free(accept_args);
}
if (connect_args) {
share_mem_free(connect_args);
}
if (recvfrom_args) {
share_mem_free(recvfrom_args);
}
if (read_args) {
share_mem_free(read_args);
}
if (sendto_args) {
share_mem_free(sendto_args);
}
if (write_args) {
share_mem_free(write_args);
}
if (close_args) {
share_mem_free(close_args);
}
if (epoll_ctl_args) {
share_mem_free(epoll_ctl_args);
}
if (epoll_wait_args) {
share_mem_free(epoll_wait_args);
}
if (kevent_args) {
share_mem_free(kevent_args);
}
}
int
ff_adapter_init()
//int __attribute__((constructor))
@ -1498,10 +1681,8 @@ ff_adapter_init()
rte_spinlock_init(&worker_id_lock);
rte_spinlock_lock(&worker_id_lock);
#ifdef FF_THREAD_SOCKET
pthread_key_create(&key, thread_destructor);
DEBUG_LOG("pthread key:%d\n", key);
#endif
/*
* get ulimit -n to distinguish fd between kernel and F-Stack
@ -1615,9 +1796,7 @@ ff_adapter_init()
return -1;
}
#ifdef FF_THREAD_SOCKET
pthread_setspecific(key, sc);
#endif
worker_id++;
inited = 1;
@ -1632,9 +1811,9 @@ ff_adapter_init()
void __attribute__((destructor))
ff_adapter_exit()
{
#ifdef FF_THREAD_SOCKET
pthread_key_delete(key);
#else
#ifndef FF_THREAD_SOCKET
ERR_LOG("pthread self tid:%lu, detach sc:%p\n", pthread_self(), sc);
ff_detach_so_context(sc);
#endif