strace问题定位

问题:

进程CPU占用率100%,用strace查看进程系统调用情况,发现madvise调用占90%的时间(正常情况下应以clockgettimeepoll_waitepoll_ctl为主)。系统日志中有channel overflow错误,状态日志中显示channelwrite调用有大量返回失败。

代码走读:

基础库代码中将数据传输通道,如socketfifoshm等抽象成channelchannel通过文件描述符读取数据,每个进程中所有的channel由统一的event loop维护。

Channel上有数据写发生时,并不直接在fd上调用write,而是先将数据写到channel中的buffer,然后根据某种规则将buffer中的数据通过fd上的write调用写出:

strace问题定位_第1张图片

Buffer是堆上动态分配的存储空间,由起始地址、读位置和写位置(read indexwrite index,读和写相对于起始地址的偏移量,不是指针)来维护,当读写位置重合时,buffer不可读,当写空间不够时,重新分配更大的空间(2倍),将已有的数据拷贝至新位置,然后再写:

strace问题定位_第2张图片

两个buffer维护操作:

DiscardReadedBytes:内存搬移,腾出更大的写空间

strace问题定位_第3张图片

Compact:释放多余的空间,只保留buffer中没有读的数据

strace问题定位_第4张图片

Channel写数据流程:

strace问题定位_第5张图片

Flush流程:

strace问题定位_第6张图片

流程优化:

Channel overflow时,可以先尝试将channel buffer中的数据调用C库的write,减少buffer中可读数据大小,再返回错误。

Flush流程中channel buffer数据通过C库调用系统调用写入内核,可读数据减少后,连续调用DiscardReadedBytesCompact,造成对大块数据进行memmovememcpycompact操作可以加条件判断。

内存分配库的影响:

通过jemalloc分配内存时,连续memmovememcpy会造成大量madvise系统调用,用C库默认的内存分配器不会出现这个问题。

修改:

Flush调用中的Compact加条件判断,buffer空间大于某个值才进行compact

你可能感兴趣的:(c/c++)